XRootD
XrdHttpProtocol.cc
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // This file is part of XrdHTTP: A pragmatic implementation of the
3 // HTTP/WebDAV protocol for the Xrootd framework
4 //
5 // Copyright (c) 2013 by European Organization for Nuclear Research (CERN)
6 // Author: Fabrizio Furano <furano@cern.ch>
7 // File Date: Nov 2012
8 //------------------------------------------------------------------------------
9 // XRootD is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Lesser General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // XRootD is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public License
20 // along with XRootD. If not, see <http://www.gnu.org/licenses/>.
21 //------------------------------------------------------------------------------
22 
23 
24 #include "XrdVersion.hh"
25 
26 #include "Xrd/XrdBuffer.hh"
27 #include "Xrd/XrdLink.hh"
28 #include "XProtocol/XProtocol.hh"
29 #include "XrdOuc/XrdOuca2x.hh"
30 #include "XrdOuc/XrdOucStream.hh"
31 #include "XrdOuc/XrdOucEnv.hh"
32 #include "XrdOuc/XrdOucGMap.hh"
33 #include "XrdSys/XrdSysE2T.hh"
34 #include "XrdSys/XrdSysTimer.hh"
36 #include "XrdHttpTrace.hh"
37 #include "XrdHttpProtocol.hh"
38 
39 #include <sys/stat.h>
40 #include "XrdHttpUtils.hh"
41 #include "XrdHttpSecXtractor.hh"
42 #include "XrdHttpExtHandler.hh"
43 
44 #include "XrdTls/XrdTls.hh"
45 #include "XrdTls/XrdTlsContext.hh"
46 #include "XrdOuc/XrdOucUtils.hh"
49 
50 #include <charconv>
51 #include <openssl/err.h>
52 #include <openssl/ssl.h>
53 #include <vector>
54 #include <arpa/inet.h>
55 #include <sstream>
56 #include <cctype>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <algorithm>
60 
61 #define XRHTTP_TK_GRACETIME 600
62 
63 
64 /******************************************************************************/
65 /* G l o b a l s */
66 /******************************************************************************/
67 
68 // It seems that eos needs this to be present
69 const char *XrdHttpSecEntityTident = "http";
70 
71 //
72 // Static stuff
73 //
74 
75 int XrdHttpProtocol::hailWait = 60000;
76 int XrdHttpProtocol::readWait = 300000;
77 int XrdHttpProtocol::Port = 1094;
79 
80 //XrdXrootdStats *XrdHttpProtocol::SI = 0;
81 char *XrdHttpProtocol::sslcert = 0;
82 char *XrdHttpProtocol::sslkey = 0;
88 bool XrdHttpProtocol::listdeny = false;
93 
96 bool XrdHttpProtocol::isdesthttps = false;
99 
100 char *XrdHttpProtocol::gridmap = 0;
104 BIO *XrdHttpProtocol::sslbio_err = 0;
105 XrdHttpSecXtractor *XrdHttpProtocol::secxtractor = 0;
106 bool XrdHttpProtocol::isRequiredXtractor = false;
107 struct XrdHttpProtocol::XrdHttpExtHandlerInfo XrdHttpProtocol::exthandler[MAX_XRDHTTPEXTHANDLERS];
110 int XrdHttpProtocol::exthandlercnt = 0;
111 std::map< std::string, std::string > XrdHttpProtocol::hdr2cgimap;
112 
113 bool XrdHttpProtocol::usingEC = false;
114 bool XrdHttpProtocol::hasCache= false;
115 
116 XrdScheduler *XrdHttpProtocol::Sched = 0; // System scheduler
117 XrdBuffManager *XrdHttpProtocol::BPool = 0; // Buffer manager
118 XrdSysError XrdHttpProtocol::eDest = 0; // Error message handler
119 XrdSecService *XrdHttpProtocol::CIA = 0; // Authentication Server
120 int XrdHttpProtocol::m_bio_type = 0; // BIO type identifier for our custom BIO.
121 BIO_METHOD *XrdHttpProtocol::m_bio_method = NULL; // BIO method constructor.
122 char *XrdHttpProtocol::xrd_cslist = nullptr;
127 
128 decltype(XrdHttpProtocol::m_staticheader_map) XrdHttpProtocol::m_staticheader_map;
129 decltype(XrdHttpProtocol::m_staticheaders) XrdHttpProtocol::m_staticheaders;
130 
132 
133 namespace
134 {
135 const char *TraceID = "Protocol";
136 }
137 
139 {
141 
142 static const int hsmAuto = -1;
143 static const int hsmOff = 0;
144 static const int hsmMan = 1;
145 static const int hsmOn = 1; // Dual purpose but use a meaningful varname
146 
149 bool tlsClientAuth = true;
150 bool httpsspec = false;
151 bool xrdctxVer = false;
152 }
153 
154 using namespace XrdHttpProtoInfo;
155 
156 /******************************************************************************/
157 /* P r o t o c o l M a n a g e m e n t S t a c k s */
158 /******************************************************************************/
159 
161 XrdHttpProtocol::ProtStack("ProtStack",
162  "xrootd protocol anchor");
163 
164 
165 /******************************************************************************/
166 /* U g l y O p e n S S L w o r k a r o u n d s */
167 /******************************************************************************/
168 #if OPENSSL_VERSION_NUMBER < 0x10100000L
169 void *BIO_get_data(BIO *bio) {
170  return bio->ptr;
171 }
172 void BIO_set_data(BIO *bio, void *ptr) {
173  bio->ptr = ptr;
174 }
175 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
176 int BIO_get_flags(BIO *bio) {
177  return bio->flags;
178 }
179 #endif
180 void BIO_set_flags(BIO *bio, int flags) {
181  bio->flags = flags;
182 }
183 int BIO_get_init(BIO *bio) {
184  return bio->init;
185 }
186 void BIO_set_init(BIO *bio, int init) {
187  bio->init = init;
188 }
189 void BIO_set_shutdown(BIO *bio, int shut) {
190  bio->shutdown = shut;
191 }
192 int BIO_get_shutdown(BIO *bio) {
193  return bio->shutdown;
194 }
195 
196 #endif
197 /******************************************************************************/
198 /* X r d H T T P P r o t o c o l C l a s s */
199 /******************************************************************************/
200 /******************************************************************************/
201 /* C o n s t r u c t o r */
202 /******************************************************************************/
203 
205 : XrdProtocol("HTTP protocol handler"), ProtLink(this),
206 SecEntity(""), CurrentReq(this, ReadRangeConfig) {
207  myBuff = 0;
208  Addr_str = 0;
209  Reset();
210  ishttps = imhttps;
211 
212 }
213 
214 /******************************************************************************/
215 /* A s s i g n m e n t O p e r a t o r */
216 
217 /******************************************************************************/
218 
220 
221  return *this;
222 }
223 
224 /******************************************************************************/
225 /* M a t c h */
226 /******************************************************************************/
227 
228 #define TRACELINK lp
229 
231  char mybuf[16], mybuf2[1024];
232  XrdHttpProtocol *hp;
233  int dlen;
234  bool myishttps = false;
235 
236  // Peek at the first 20 bytes of data
237  //
238  if ((dlen = lp->Peek(mybuf, (int) sizeof (mybuf), hailWait)) < (int) sizeof (mybuf)) {
239  if (dlen <= 0) lp->setEtext("handshake not received");
240  return (XrdProtocol *) 0;
241  }
242  mybuf[dlen - 1] = '\0';
243 
244  // Trace the data
245  //
246 
247  TRACEI(DEBUG, "received dlen: " << dlen);
248  //TRACEI(REQ, "received buf: " << mybuf);
249  mybuf2[0] = '\0';
250  for (int i = 0; i < dlen; i++) {
251  char mybuf3[16];
252  sprintf(mybuf3, "%.02d ", mybuf[i]);
253  strcat(mybuf2, mybuf3);
254 
255  }
256  TRACEI(DEBUG, "received dump: " << mybuf2);
257 
258  // Decide if it looks http or not. For now we are happy if all the received characters are alphanumeric
259  bool ismine = true;
260  for (int i = 0; i < dlen - 1; i++)
261  if (!isprint(mybuf[i]) && (mybuf[i] != '\r') && (mybuf[i] != '\n')) {
262  ismine = false;
263  TRACEI(DEBUG, "This does not look like http at pos " << i);
264  break;
265  }
266 
267  // If it does not look http then look if it looks like https
268  if ((!ismine) && (dlen >= 4)) {
269  char check[4] = {00, 00, 00, 00};
270  if (memcmp(mybuf, check, 4)) {
271 
272  if (httpsmode) {
273  ismine = true;
274  myishttps = true;
275  TRACEI(DEBUG, "This may look like https");
276  } else {
277  TRACEI(ALL, "This may look like https, but https is not configured");
278  }
279 
280  }
281  }
282 
283  if (!ismine) {
284  TRACEI(DEBUG, "This does not look like https. Protocol not matched.");
285  return (XrdProtocol *) 0;
286  }
287 
288  // It does look http or https...
289  // Get a protocol object off the stack (if none, allocate a new one)
290  //
291 
292  TRACEI(REQ, "Protocol matched. https: " << myishttps);
293  if (!(hp = ProtStack.Pop())) hp = new XrdHttpProtocol(myishttps);
294  else
295  hp->ishttps = myishttps;
296 
297  // We now have to do some work arounds to tell the underlying framework
298  // that is is https without invoking TLS on the actual link. Eventually,
299  // we should just use the link's TLS native implementation.
300  //
301  hp->SecEntity.addrInfo = lp->AddrInfo();
302  XrdNetAddr *netP = const_cast<XrdNetAddr*>(lp->NetAddr());
303  netP->SetDialect("https");
304  netP->SetTLS(true);
305 
306  // Allocate 1MB buffer from pool
307  if (!hp->myBuff) {
308  hp->myBuff = BPool->Obtain(1024 * 1024);
309  }
310  hp->myBuffStart = hp->myBuffEnd = hp->myBuff->buff;
311 
312  // Bind the protocol to the link and return the protocol
313  //
314  hp->Link = lp;
315  return (XrdProtocol *) hp;
316 }
317 
318 char *XrdHttpProtocol::GetClientIPStr() {
319  char buf[256];
320  buf[0] = '\0';
321  if (!Link) return strdup("unknown");
322  XrdNetAddrInfo *ai = Link->AddrInfo();
323  if (!ai) return strdup("unknown");
324 
325  if (!Link->AddrInfo()->Format(buf, 255, XrdNetAddrInfo::fmtAddr, XrdNetAddrInfo::noPort)) return strdup("unknown");
326 
327  return strdup(buf);
328 }
329 
330 // Various routines for handling XrdLink as BIO objects within OpenSSL.
331 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
332 int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
333 {
334  if (!data || !bio) {
335  *written = 0;
336  return 0;
337  }
338 
339  XrdLink *lp=static_cast<XrdLink *>(BIO_get_data(bio));
340 
341  errno = 0;
342  int ret = lp->Send(data, datal);
343  BIO_clear_retry_flags(bio);
344  if (ret <= 0) {
345  *written = 0;
346  if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
347  BIO_set_retry_write(bio);
348  return ret;
349  }
350  *written = ret;
351  return 1;
352 }
353 #else
354 int BIO_XrdLink_write(BIO *bio, const char *data, int datal)
355 {
356  if (!data || !bio) {
357  errno = ENOMEM;
358  return -1;
359  }
360 
361  errno = 0;
362  XrdLink *lp = static_cast<XrdLink *>(BIO_get_data(bio));
363  int ret = lp->Send(data, datal);
364  BIO_clear_retry_flags(bio);
365  if (ret <= 0) {
366  if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
367  BIO_set_retry_write(bio);
368  }
369  return ret;
370 }
371 #endif
372 
373 
374 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
375 static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
376 {
377  if (!data || !bio) {
378  *read = 0;
379  return 0;
380  }
381 
382  errno = 0;
383 
384  XrdLink *lp = static_cast<XrdLink *>(BIO_get_data(bio));
385  int ret = lp->Recv(data, datal);
386  BIO_clear_retry_flags(bio);
387  if (ret <= 0) {
388  *read = 0;
389  if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
390  BIO_set_retry_read(bio);
391  return ret;
392  }
393  *read = ret;
394 }
395 #else
396 static int BIO_XrdLink_read(BIO *bio, char *data, int datal)
397 {
398  if (!data || !bio) {
399  errno = ENOMEM;
400  return -1;
401  }
402 
403  errno = 0;
404  XrdLink *lp = static_cast<XrdLink *>(BIO_get_data(bio));
405  int ret = lp->Recv(data, datal);
406  BIO_clear_retry_flags(bio);
407  if (ret <= 0) {
408  if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
409  BIO_set_retry_read(bio);
410  }
411  return ret;
412 }
413 #endif
414 
415 
416 static int BIO_XrdLink_create(BIO *bio)
417 {
418 
419 
420  BIO_set_init(bio, 0);
421  //BIO_set_next(bio, 0);
422  BIO_set_data(bio, NULL);
423  BIO_set_flags(bio, 0);
424 
425 #if OPENSSL_VERSION_NUMBER < 0x10100000L
426 
427  bio->num = 0;
428 
429 #endif
430 
431  return 1;
432 }
433 
434 
435 static int BIO_XrdLink_destroy(BIO *bio)
436 {
437  if (bio == NULL) return 0;
438  if (BIO_get_shutdown(bio)) {
439  if (BIO_get_data(bio)) {
440  static_cast<XrdLink*>(BIO_get_data(bio))->Close();
441  }
442  BIO_set_init(bio, 0);
443  BIO_set_flags(bio, 0);
444  }
445  return 1;
446 }
447 
448 
449 static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void * ptr)
450 {
451  long ret = 1;
452  switch (cmd) {
453  case BIO_CTRL_GET_CLOSE:
454  ret = BIO_get_shutdown(bio);
455  break;
456  case BIO_CTRL_SET_CLOSE:
457  BIO_set_shutdown(bio, (int)num);
458  break;
459  case BIO_CTRL_DUP:
460  case BIO_CTRL_FLUSH:
461  ret = 1;
462  break;
463  default:
464  ret = 0;
465  break;
466  }
467  return ret;
468 }
469 
470 
471 BIO *XrdHttpProtocol::CreateBIO(XrdLink *lp)
472 {
473  if (m_bio_method == NULL)
474  return NULL;
475 
476  BIO *ret = BIO_new(m_bio_method);
477 
478  BIO_set_shutdown(ret, 0);
479  BIO_set_data(ret, lp);
480  BIO_set_init(ret, 1);
481  return ret;
482 }
483 
484 
485 /******************************************************************************/
486 /* P r o c e s s */
487 /******************************************************************************/
488 
489 #undef TRACELINK
490 #define TRACELINK Link
491 
492 int XrdHttpProtocol::Process(XrdLink *lp) // We ignore the argument here
493 {
494  int rc = 0;
495 
496  TRACEI(DEBUG, " Process. lp:"<<(void *)lp<<" reqstate: "<<CurrentReq.reqstate);
497 
498  if (!myBuff || !myBuff->buff || !myBuff->bsize) {
499  TRACE(ALL, " Process. No buffer available. Internal error.");
500  return -1;
501  }
502 
503 
504  if (!SecEntity.host) {
505  char *nfo = GetClientIPStr();
506  if (nfo) {
507  TRACEI(REQ, " Setting host: " << nfo);
508  SecEntity.host = nfo;
509  strcpy(SecEntity.prot, "http");
510  }
511  }
512 
513 
514 
515  // If https then check independently for the ssl handshake
516  if (ishttps && !ssldone) {
517 
518  if (!ssl) {
519  sbio = CreateBIO(Link);
520  BIO_set_nbio(sbio, 1);
521  ssl = (SSL*)xrdctx->Session();
522  }
523 
524  if (!ssl) {
525  TRACEI(DEBUG, " SSL_new returned NULL");
526  ERR_print_errors(sslbio_err);
527  return -1;
528  }
529 
530  // If a secxtractor has been loaded
531  // maybe it wants to add its own initialization bits
532  if (secxtractor)
533  secxtractor->InitSSL(ssl, sslcadir);
534 
535  SSL_set_bio(ssl, sbio, sbio);
536  //SSL_set_connect_state(ssl);
537 
538  //SSL_set_fd(ssl, Link->FDnum());
539  struct timeval tv;
540  tv.tv_sec = 10;
541  tv.tv_usec = 0;
542  setsockopt(Link->FDnum(), SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
543  setsockopt(Link->FDnum(), SOL_SOCKET, SO_SNDTIMEO, (struct timeval *)&tv, sizeof(struct timeval));
544 
545  TRACEI(DEBUG, " Entering SSL_accept...");
546  int res = SSL_accept(ssl);
547  TRACEI(DEBUG, " SSL_accept returned :" << res);
548  if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
549  TRACEI(DEBUG, " SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
550  return 1;
551  }
552 
553  if(res <= 0) {
554  ERR_print_errors(sslbio_err);
555  if (res < 0) {
556 
557  SSL_free(ssl);
558  ssl = 0;
559  return -1;
560  }
561  }
562 
563  BIO_set_nbio(sbio, 0);
564 
565  strcpy(SecEntity.prot, "https");
566 
567  // Get the voms string and auth information
568  if (tlsClientAuth && HandleAuthentication(Link)) {
569  SSL_free(ssl);
570  ssl = 0;
571  return -1;
572  }
573 
574  ssldone = true;
575  if (TRACING(TRACE_AUTH)) {
577  }
578  }
579 
580 
581 
582  if (!DoingLogin) {
583  // Re-invocations triggered by the bridge have lp==0
584  // In this case we keep track of a different request state
585  if (lp) {
586 
587  // This is an invocation that was triggered by a socket event
588  // Read all the data that is available, throw it into the buffer
589  if ((rc = getDataOneShot(BuffAvailable())) < 0) {
590  // Error -> exit
591  return -1;
592  }
593 
594  // If we need more bytes, let's wait for another invokation
595  if (BuffUsed() < ResumeBytes) return 1;
596 
597 
598  } else
600  } else if (!DoneSetInfo && !CurrentReq.userAgent().empty()) { // DoingLogin is true, meaning the login finished.
601  std::string mon_info = "monitor info " + CurrentReq.userAgent();
602  DoneSetInfo = true;
603  if (mon_info.size() >= 1024) {
604  TRACEI(ALL, "User agent string too long");
605  } else if (!Bridge) {
606  TRACEI(ALL, "Internal logic error: Bridge is null after login");
607  } else {
608  TRACEI(DEBUG, "Setting " << mon_info);
609  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
611  CurrentReq.xrdreq.set.modifier = '\0';
612  memset(CurrentReq.xrdreq.set.reserved, '\0', sizeof(CurrentReq.xrdreq.set.reserved));
613  CurrentReq.xrdreq.set.dlen = htonl(mon_info.size());
614  if (!Bridge->Run((char *) &CurrentReq.xrdreq, (char *) mon_info.c_str(), mon_info.size())) {
615  SendSimpleResp(500, nullptr, nullptr, "Could not set user agent.", 0, false);
616  return -1;
617  }
618  return 0;
619  }
620  } else {
621  DoingLogin = false;
622  }
623 
624  // Read the next request header, that is, read until a double CRLF is found
625 
626 
627  if (!CurrentReq.headerok) {
628 
629  // Read as many lines as possible into the buffer. An empty line breaks
630  while ((rc = BuffgetLine(tmpline)) > 0) {
631  std::string traceLine = tmpline.c_str();
632  if (TRACING(TRACE_DEBUG)) {
633  traceLine = obfuscateAuth(traceLine);
634  }
635  TRACE(DEBUG, " rc:" << rc << " got hdr line: " << traceLine);
636  if ((rc == 2) && (tmpline.length() > 1) && (tmpline[rc - 1] == '\n')) {
637  CurrentReq.headerok = true;
638  TRACE(DEBUG, " rc:" << rc << " detected header end.");
639  break;
640  }
641 
642 
644  TRACE(DEBUG, " Parsing first line: " << traceLine.c_str());
645  int result = CurrentReq.parseFirstLine((char *)tmpline.c_str(), tmpline.length());
646  if (result < 0) {
647  TRACE(DEBUG, " Parsing of first line failed with " << result);
648  return -1;
649  }
650  } else {
651  int result = CurrentReq.parseLine((char *) tmpline.c_str(), tmpline.length());
652  if(result < 0) {
653  TRACE(DEBUG, " Parsing of header line failed with " << result)
654  SendSimpleResp(400,NULL,NULL,"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0, false);
655  return -1;
656  }
657  }
658 
659 
660  }
661 
662  // Here we have CurrentReq loaded with the header, or its relevant fields
663 
664  if (!CurrentReq.headerok) {
665  TRACEI(REQ, " rc:" << rc << "Header not yet complete.");
666 
667  // Here a subtle error condition. IF we failed reading a line AND the buffer
668  // has a reasonable amount of data available THEN we consider the header
669  // as corrupted and shutdown the client
670  if ((rc <= 0) && (BuffUsed() >= 16384)) {
671  TRACEI(ALL, "Corrupted header detected, or line too long. Disconnecting client.");
672  return -1;
673  }
674 
675 
676  if (CurrentReq.reqstate > 0)
678  // Waiting for more data
679  return 1;
680  }
681 
682  }
683 
684  // If we are in self-redirect mode, then let's do it
685  // Do selfredirect only with 'simple' requests, otherwise poor clients may misbehave
686  if (ishttps && ssldone && selfhttps2http &&
689  char hash[512];
690  time_t timenow = time(0);
691 
692 
694  &SecEntity,
695  timenow,
696  secretkey);
697 
698 
699 
700  if (hash[0]) {
701 
702  // Workaround... delete the previous opaque information
703  if (CurrentReq.opaque) {
704  delete CurrentReq.opaque;
705  CurrentReq.opaque = 0;
706  }
707 
708  TRACEI(REQ, " rc:" << rc << " self-redirecting to http with security token.");
709 
710  XrdOucString dest = "Location: http://";
711  // Here I should put the IP addr of the server
712 
713  // We have to recompute it here because we don't know to which
714  // interface the client had connected to
715  struct sockaddr_storage sa;
716  socklen_t sl = sizeof(sa);
717  getsockname(this->Link->AddrInfo()->SockFD(), (struct sockaddr*)&sa, &sl);
718 
719  // now get it back and print it
720  char buf[256];
721  bool ok = false;
722 
723  switch (sa.ss_family) {
724  case AF_INET:
725  if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
726  if (Addr_str) free(Addr_str);
727  Addr_str = strdup(buf);
728  ok = true;
729  }
730  break;
731  case AF_INET6:
732  if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
733  if (Addr_str) free(Addr_str);
734  Addr_str = (char *)malloc(strlen(buf)+3);
735  strcpy(Addr_str, "[");
736  strcat(Addr_str, buf);
737  strcat(Addr_str, "]");
738  ok = true;
739  }
740  break;
741  default:
742  TRACEI(REQ, " Can't recognize the address family of the local host.");
743  }
744 
745  if (ok) {
746  dest += Addr_str;
747  dest += ":";
748  dest += Port_str;
749  dest += CurrentReq.resource.c_str();
750  TRACEI(REQ," rc:"<<rc<<" self-redirecting to http with security token: '"
751  << dest.c_str() << "'");
752 
753 
754  CurrentReq.appendOpaque(dest, &SecEntity, hash, timenow);
755  SendSimpleResp(302, NULL, (char *) dest.c_str(), 0, 0, true);
756  CurrentReq.reset();
757  return -1;
758  }
759 
760  TRACEI(REQ, " rc:" << rc << " Can't perform self-redirection.");
761 
762  }
763  else {
764  TRACEI(ALL, " Could not calculate self-redirection hash");
765  }
766  }
767 
768  // If this is not https, then extract the signed information from the url
769  // and fill the SecEntity structure as if we were using https
770  if (!ishttps && !ssldone) {
771 
772 
773  if (CurrentReq.opaque) {
774  char * tk = CurrentReq.opaque->Get("xrdhttptk");
775  // If there is a hash then we use it as authn info
776  if (tk) {
777 
778  time_t tim = 0;
779  char * t = CurrentReq.opaque->Get("xrdhttptime");
780  if (t) tim = atoi(t);
781  if (!t) {
782  TRACEI(REQ, " xrdhttptime not specified. Authentication failed.");
783  return -1;
784  }
785  if (abs(time(0) - tim) > XRHTTP_TK_GRACETIME) {
786  TRACEI(REQ, " Token expired. Authentication failed.");
787  return -1;
788  }
789 
790  // Fill the Secentity from the fields in the URL:name, vo, host
791  char *nfo;
792 
793  nfo = CurrentReq.opaque->Get("xrdhttpvorg");
794  if (nfo) {
795  TRACEI(DEBUG, " Setting vorg: " << nfo);
796  SecEntity.vorg = strdup(nfo);
797  TRACEI(REQ, " Setting vorg: " << SecEntity.vorg);
798  }
799 
800  nfo = CurrentReq.opaque->Get("xrdhttpname");
801  if (nfo) {
802  TRACEI(DEBUG, " Setting name: " << nfo);
803  SecEntity.name = strdup(decode_str(nfo).c_str());
804  TRACEI(REQ, " Setting name: " << SecEntity.name);
805  }
806 
807  nfo = CurrentReq.opaque->Get("xrdhttphost");
808  if (nfo) {
809  TRACEI(DEBUG, " Setting host: " << nfo);
810  if (SecEntity.host) free(SecEntity.host);
811  SecEntity.host = strdup(decode_str(nfo).c_str());
812  TRACEI(REQ, " Setting host: " << SecEntity.host);
813  }
814 
815  nfo = CurrentReq.opaque->Get("xrdhttpdn");
816  if (nfo) {
817  TRACEI(DEBUG, " Setting dn: " << nfo);
818  SecEntity.moninfo = strdup(decode_str(nfo).c_str());
819  TRACEI(REQ, " Setting dn: " << SecEntity.moninfo);
820  }
821 
822  nfo = CurrentReq.opaque->Get("xrdhttprole");
823  if (nfo) {
824  TRACEI(DEBUG, " Setting role: " << nfo);
825  SecEntity.role = strdup(decode_str(nfo).c_str());
826  TRACEI(REQ, " Setting role: " << SecEntity.role);
827  }
828 
829  nfo = CurrentReq.opaque->Get("xrdhttpgrps");
830  if (nfo) {
831  TRACEI(DEBUG, " Setting grps: " << nfo);
832  SecEntity.grps = strdup(decode_str(nfo).c_str());
833  TRACEI(REQ, " Setting grps: " << SecEntity.grps);
834  }
835 
836  nfo = CurrentReq.opaque->Get("xrdhttpendorsements");
837  if (nfo) {
838  TRACEI(DEBUG, " Setting endorsements: " << nfo);
839  SecEntity.endorsements = strdup(decode_str(nfo).c_str());
840  TRACEI(REQ, " Setting endorsements: " << SecEntity.endorsements);
841  }
842 
843  nfo = CurrentReq.opaque->Get("xrdhttpcredslen");
844  if (nfo) {
845  TRACEI(DEBUG, " Setting credslen: " << nfo);
846  char *s1 = strdup(decode_str(nfo).c_str());
847  if (s1 && s1[0]) {
848  SecEntity.credslen = atoi(s1);
849  TRACEI(REQ, " Setting credslen: " << SecEntity.credslen);
850  }
851  if (s1) free(s1);
852  }
853 
854  if (SecEntity.credslen) {
855  nfo = CurrentReq.opaque->Get("xrdhttpcreds");
856  if (nfo) {
857  TRACEI(DEBUG, " Setting creds: " << nfo);
858  SecEntity.creds = strdup(decode_str(nfo).c_str());
859  TRACEI(REQ, " Setting creds: " << SecEntity.creds);
860  }
861  }
862 
863  char hash[512];
864 
866  &SecEntity,
867  tim,
868  secretkey);
869 
870  if (compareHash(hash, tk)) {
871  TRACEI(REQ, "Invalid tk '" << tk << "' != '" << hash << "' (calculated). Authentication failed.");
872  SendSimpleResp(400, nullptr, nullptr, "Authentication failed: invalid token", 0, false);
873  return -1;
874  }
875 
876  } else {
877  // Client is plain http. If we have a secret key then we reject it
878  if (secretkey) {
879  TRACEI(ALL, " Rejecting plain http with no valid token as we have a secretkey.");
880  return -1;
881  }
882  }
883 
884  } else {
885  // Client is plain http. If we have a secret key then we reject it
886  if (secretkey) {
887  TRACEI(ALL, " Rejecting plain http with no valid token as we have a secretkey.");
888  return -1;
889  }
890  }
891 
892  ssldone = true;
893  }
894 
895 
896 
897  // Now we have everything that is needed to try the login
898  // Remember that if there is an exthandler then it has the responsibility
899  // for authorization in the paths that it manages
900  if (!Bridge && !FindMatchingExtHandler(CurrentReq)) {
901  if (SecEntity.name)
902  Bridge = XrdXrootd::Bridge::Login(&CurrentReq, Link, &SecEntity, SecEntity.name, ishttps ? "https" : "http");
903  else
904  Bridge = XrdXrootd::Bridge::Login(&CurrentReq, Link, &SecEntity, "unknown", ishttps ? "https" : "http");
905 
906  if (!Bridge) {
907  TRACEI(REQ, " Authorization failed.");
908  return -1;
909  }
910  if (m_maxdelay > 0) Bridge->SetWait(m_maxdelay, false);
911 
912  // Let the bridge process the login, and then reinvoke us
913  DoingLogin = true;
914  return 0;
915  }
916 
917  // Compute and send the response. This may involve further reading from the socket
918  rc = CurrentReq.ProcessHTTPReq();
919  if (rc < 0)
920  CurrentReq.reset();
921 
922 
923 
924  TRACEI(REQ, "Process is exiting rc:" << rc);
925  return rc;
926 }
927 /******************************************************************************/
928 /* R e c y c l e */
929 /******************************************************************************/
930 
931 #undef TRACELINK
932 #define TRACELINK Link
933 
934 void XrdHttpProtocol::Recycle(XrdLink *lp, int csec, const char *reason) {
935 
936  // Release all appendages
937  //
938 
939  Cleanup();
940 
941 
942  // Set fields to starting point (debugging mostly)
943  //
944  Reset();
945 
946  // Push ourselves on the stack
947  //
949 }
950 
951 int XrdHttpProtocol::Stats(char *buff, int blen, int do_sync) {
952  // Synchronize statistics if need be
953  //
954  // if (do_sync) {
955  //
956  // SI->statsMutex.Lock();
957  // SI->readCnt += numReads;
958  // cumReads += numReads;
959  // numReads = 0;
960  // SI->prerCnt += numReadP;
961  // cumReadP += numReadP;
962  // numReadP = 0;
963  // SI->rvecCnt += numReadV;
964  // cumReadV += numReadV;
965  // numReadV = 0;
966  // SI->rsegCnt += numSegsV;
967  // cumSegsV += numSegsV;
968  // numSegsV = 0;
969  // SI->writeCnt += numWrites;
970  // cumWrites += numWrites;
971  // numWrites = 0;
972  // SI->statsMutex.UnLock();
973  // }
974  //
975  // // Now return the statistics
976  // //
977  // return SI->Stats(buff, blen, do_sync);
978 
979  return 0;
980 }
981 
982 /******************************************************************************/
983 /* C o n f i g */
984 /******************************************************************************/
985 
986 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
987 //#define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, ConfigFN, myEnv)
988 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
989 
990 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
991  if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
992  eDest.Say("Config http." x " overrides the xrd." y " directive.")
993 
994 int XrdHttpProtocol::Config(const char *ConfigFN, XrdOucEnv *myEnv) {
995  XrdOucEnv cfgEnv;
996  XrdOucStream Config(&eDest, getenv("XRDINSTANCE"), &cfgEnv, "=====> ");
997  std::vector<extHInfo> extHIVec;
998  char *var;
999  int cfgFD, GoNo, NoGo = 0, ismine;
1000 
1001  var = nullptr;
1002  XrdOucEnv::Import("XRD_READV_LIMITS", var);
1004 
1005  pmarkHandle = (XrdNetPMark* ) myEnv->GetPtr("XrdNetPMark*");
1006 
1008  auto nonIanaChecksums = cksumHandler.getNonIANAConfiguredCksums();
1009  if(nonIanaChecksums.size()) {
1010  std::stringstream warningMsgSS;
1011  warningMsgSS << "Config warning: the following checksum algorithms are not IANA compliant: [";
1012  std::string unknownCksumString;
1013  for(auto unknownCksum: nonIanaChecksums) {
1014  unknownCksumString += unknownCksum + ",";
1015  }
1016  unknownCksumString.erase(unknownCksumString.size() - 1);
1017  warningMsgSS << unknownCksumString << "]" << ". They therefore cannot be queried by a user via HTTP." ;
1018  eDest.Say(warningMsgSS.str().c_str());
1019  }
1020 
1021  // Initialize our custom BIO type.
1022  if (!m_bio_type) {
1023 
1024  #if OPENSSL_VERSION_NUMBER < 0x10100000L
1025  m_bio_type = (26|0x0400|0x0100);
1026  m_bio_method = static_cast<BIO_METHOD*>(OPENSSL_malloc(sizeof(BIO_METHOD)));
1027 
1028  if (m_bio_method) {
1029  memset(m_bio_method, '\0', sizeof(BIO_METHOD));
1030  m_bio_method->type = m_bio_type;
1031  m_bio_method->bwrite = BIO_XrdLink_write;
1032  m_bio_method->bread = BIO_XrdLink_read;
1033  m_bio_method->create = BIO_XrdLink_create;
1034  m_bio_method->destroy = BIO_XrdLink_destroy;
1036  }
1037  #else
1038  // OpenSSL 1.1 has an internal counter for generating unique types.
1039  // We'll switch to that when widely available.
1040  m_bio_type = BIO_get_new_index();
1041  m_bio_method = BIO_meth_new(m_bio_type, "xrdhttp-bio-method");
1042 
1043  if (m_bio_method) {
1044  BIO_meth_set_write(m_bio_method, BIO_XrdLink_write);
1045  BIO_meth_set_read(m_bio_method, BIO_XrdLink_read);
1046  BIO_meth_set_create(m_bio_method, BIO_XrdLink_create);
1047  BIO_meth_set_destroy(m_bio_method, BIO_XrdLink_destroy);
1048  BIO_meth_set_ctrl(m_bio_method, BIO_XrdLink_ctrl);
1049  }
1050 
1051  #endif
1052  }
1053 
1054  // If we have a tls context record whether it configured for verification
1055  // so that we can provide meaningful error and warning messages.
1056  //
1058 
1059  // Open and attach the config file
1060  //
1061  if ((cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
1062  return eDest.Emsg("Config", errno, "open config file", ConfigFN);
1063  Config.Attach(cfgFD);
1064  static const char *cvec[] = { "*** http protocol config:", 0 };
1065  Config.Capture(cvec);
1066 
1067  // Process items
1068  //
1069  while ((var = Config.GetMyFirstWord())) {
1070  if ((ismine = !strncmp("http.", var, 5)) && var[5]) var += 5;
1071 
1072  if (ismine) {
1073  if TS_Xeq("trace", xtrace);
1074  else if TS_Xeq("cert", xsslcert);
1075  else if TS_Xeq("key", xsslkey);
1076  else if TS_Xeq("cadir", xsslcadir);
1077  else if TS_Xeq("cipherfilter", xsslcipherfilter);
1078  else if TS_Xeq("gridmap", xgmap);
1079  else if TS_Xeq("cafile", xsslcafile);
1080  else if TS_Xeq("secretkey", xsecretkey);
1081  else if TS_Xeq("desthttps", xdesthttps);
1082  else if TS_Xeq("secxtractor", xsecxtractor);
1083  else if TS_Xeq("cors", xcors);
1084  else if TS_Xeq3("exthandler", xexthandler);
1085  else if TS_Xeq("selfhttps2http", xselfhttps2http);
1086  else if TS_Xeq("embeddedstatic", xembeddedstatic);
1087  else if TS_Xeq("listingredir", xlistredir);
1088  else if TS_Xeq("staticredir", xstaticredir);
1089  else if TS_Xeq("staticpreload", xstaticpreload);
1090  else if TS_Xeq("staticheader", xstaticheader);
1091  else if TS_Xeq("listingdeny", xlistdeny);
1092  else if TS_Xeq("header2cgi", xheader2cgi);
1093  else if TS_Xeq("httpsmode", xhttpsmode);
1094  else if TS_Xeq("tlsreuse", xtlsreuse);
1095  else if TS_Xeq("auth", xauth);
1096  else if TS_Xeq("tlsclientauth", xtlsclientauth);
1097  else if TS_Xeq("maxdelay", xmaxdelay);
1098  else {
1099  eDest.Say("Config warning: ignoring unknown directive '", var, "'.");
1100  Config.Echo();
1101  continue;
1102  }
1103  if (GoNo) {
1104  Config.Echo();
1105  NoGo = 1;
1106  }
1107  }
1108  }
1109 
1110 // To minimize message confusion down, if an error occurred during config
1111 // parsing, just bail out now with a confirming message.
1112 //
1113  if (NoGo)
1114  {eDest.Say("Config failure: one or more directives are flawed!");
1115  return 1;
1116  }
1117 
1118 // Some headers must always be converted to CGI key=value pairs
1119 //
1120  hdr2cgimap["Cache-Control"] = "cache-control";
1121 
1122 // Test if XrdEC is loaded
1123  if (getenv("XRDCL_EC")) usingEC = true;
1124 
1125 // Pre-compute the static headers
1126 //
1127  const auto default_verb = m_staticheader_map.find("");
1128  std::string default_static_headers;
1129  if (default_verb != m_staticheader_map.end()) {
1130  for (const auto &header_entry : default_verb->second) {
1131  default_static_headers += header_entry.first + ": " + header_entry.second + "\r\n";
1132  }
1133  }
1134  m_staticheaders[""] = default_static_headers;
1135  for (const auto &item : m_staticheader_map) {
1136  if (item.first.empty()) {
1137  continue; // Skip default case; already handled
1138  }
1139  auto headers = default_static_headers;
1140  for (const auto &header_entry : item.second) {
1141  headers += header_entry.first + ": " + header_entry.second + "\r\n";
1142  }
1143 
1144  m_staticheaders[item.first] = headers;
1145  }
1146 
1147 // Test if this is a caching server
1148 //
1149  if (myEnv->Get("XrdCache")) hasCache = true;
1150 
1151  // Load CORS plugin if configured
1152  if(xrdcorsLibPath.size()) {
1153  if(LoadCorsHandler(&eDest, xrdcorsLibPath.c_str()) != 0) {
1154  return 1;
1155  }
1156  if (xrdcors->Configure(ConfigFN, &eDest) != 0) {
1157  return 1;
1158  }
1159  }
1160 
1161 // If https was disabled, then issue a warning message if xrdtls configured
1162 // of it's disabled because httpsmode was auto and xrdtls was not configured.
1163 // If we get past this point then we know https is a plausible option but we
1164 // can still fail if we cannot supply any missing but required options.
1165 //
1166  if (httpsmode == hsmOff || (httpsmode == hsmAuto && !xrdctx && !httpsspec))
1167  {const char *why = (httpsmode == hsmOff ? "has been disabled!"
1168  : "was not configured.");
1169  const char *what = Configed();
1170 
1171  eDest.Say("Config warning: HTTPS functionality ", why);
1172  httpsmode = hsmOff;
1173 
1174  LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1175  if (what)
1176  {eDest.Say("Config failure: ", what, " HTTPS but it ", why);
1177  NoGo = 1;
1178  }
1179  return NoGo;
1180  }
1181 
1182 // Warn if a private key was specified without a cert as this has no meaning
1183 // even as an auto overide as they must be paired.
1184 //
1185  if (sslkey && !sslcert)
1186  {eDest.Say("Config warning: specifying http.key without http.cert "
1187  "is meaningless; ignoring key!");
1188  free(sslkey); sslkey = 0;
1189  }
1190 
1191 // If the mode is manual then we need to have at least a cert.
1192 //
1193  if (httpsmode == hsmMan)
1194  {if (!sslcert)
1195  {eDest.Say("Config failure: 'httpsmode manual' requires atleast a "
1196  "a cert specification!");
1197  return 1;
1198  }
1199  }
1200 
1201 // If it's auto d through all possibilities. It's either auto with xrdtls
1202 // configured or manual which needs at least a cert specification. For auto
1203 // configuration we will only issue a warning if overrides were specified.
1204 //
1205  if (httpsmode == hsmAuto && xrdctx)
1206  {const XrdTlsContext::CTX_Params *cP = xrdctx->GetParams();
1207  const char *what1 = 0, *what2 = 0, *what3 = 0;
1208 
1209  if (!sslcert && cP->cert.size())
1210  {sslcert = strdup(cP->cert.c_str());
1211  if (cP->pkey.size()) sslkey = strdup(cP->pkey.c_str());
1212  what1 = "xrd.tls to supply 'cert' and 'key'.";
1213  }
1214  if (!sslcadir && cP->cadir.size())
1215  {sslcadir = strdup(cP->cadir.c_str());
1216  what2 = "xrd.tlsca to supply 'cadir'.";
1217  }
1218  if (!sslcafile && cP->cafile.size())
1219  {sslcafile = strdup(cP->cafile.c_str());
1220  what2 = (what2 ? "xrd.tlsca to supply 'cadir' and 'cafile'."
1221  : "xrd.tlsca to supply 'cafile'.");
1222  }
1224  crlRefIntervalSec = cP->crlRT;
1225  what3 = "xrd.tlsca to supply 'refresh' interval.";
1226  }
1227  if (!httpsspec && what1) eDest.Say("Config Using ", what1);
1228  if (!httpsspec && what2) eDest.Say("Config Using ", what2);
1229  if (!httpsspec && what3) eDest.Say("Config Using ", what3);
1230 
1231  if (cP->opts & XrdTlsContext::crlAM) {
1232  allowMissingCRL = true;
1233  }
1234  }
1235 
1236 // If a gridmap or secxtractor is present then we must be able to verify certs
1237 //
1238  if (!(sslcadir || sslcafile))
1239  {const char *what = Configed();
1240  const char *why = (httpsspec ? "a cadir or cafile was not specified!"
1241  : "'xrd.tlsca noverify' was specified!");
1242  if (what)
1243  {eDest.Say("Config failure: ", what, " cert verification but ", why);
1244  return 1;
1245  }
1246  }
1247  httpsmode = hsmOn;
1248 
1249 // Oddly we need to create an error bio at this point
1250 //
1251  sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1252 
1253 // Now we can configure HTTPS. We will not reuse the passed context as we will
1254 // be setting our own options specific to out implementation. One day we will.
1255 //
1256  const char *how = "completed.";
1257  eDest.Say("++++++ HTTPS initialization started.");
1258  if (!InitTLS()) {NoGo = 1; how = "failed.";}
1259  eDest.Say("------ HTTPS initialization ", how);
1260  if (NoGo) return NoGo;
1261 
1262 // We can now load all the external handlers
1263 //
1264  if (LoadExtHandler(extHIVec, ConfigFN, *myEnv)) return 1;
1265 
1266 // At this point, we can actually initialize security plugins
1267 //
1268  return (InitSecurity() ? NoGo : 1);
1269 }
1270 
1271 /******************************************************************************/
1272 /* C o n f i g e d */
1273 /******************************************************************************/
1274 
1275 const char *XrdHttpProtocol::Configed()
1276 {
1277  if (secxtractor && gridmap) return "gridmap and secxtractor require";
1278  if (secxtractor) return "secxtractor requires";
1279  if (gridmap) return "gridmap requires";
1280  return 0;
1281 }
1282 
1283 /******************************************************************************/
1284 /* B u f f g e t L i n e */
1285 /******************************************************************************/
1286 
1288 
1289 int XrdHttpProtocol::BuffgetLine(XrdOucString &dest) {
1290 
1291  dest = "";
1292  char save;
1293 
1294  // Easy case
1295  if (myBuffEnd >= myBuffStart) {
1296  int l = 0;
1297  for (char *p = myBuffStart; p < myBuffEnd; p++) {
1298  l++;
1299  if (*p == '\n') {
1300  save = *(p+1);
1301  *(p+1) = '\0';
1302  dest.assign(myBuffStart, 0, l-1);
1303  *(p+1) = save;
1304 
1305  //strncpy(dest, myBuffStart, l);
1306  //dest[l] = '\0';
1307  BuffConsume(l);
1308 
1309  //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1310  return l;
1311  }
1312 
1313  }
1314 
1315  return 0;
1316  } else {
1317  // More complex case... we have to do it in two segments
1318 
1319  // Segment 1: myBuffStart->myBuff->buff+myBuff->bsize
1320  int l = 0;
1321  for (char *p = myBuffStart; p < myBuff->buff + myBuff->bsize; p++) {
1322  l++;
1323  if ((*p == '\n') || (*p == '\0')) {
1324  save = *(p+1);
1325  *(p+1) = '\0';
1326  dest.assign(myBuffStart, 0, l-1);
1327  *(p+1) = save;
1328 
1329  //strncpy(dest, myBuffStart, l);
1330 
1331  BuffConsume(l);
1332 
1333  //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1334  return l;
1335  }
1336 
1337  }
1338 
1339  // We did not find the \n, let's keep on searching in the 2nd segment
1340  // Segment 2: myBuff->buff --> myBuffEnd
1341  l = 0;
1342  for (char *p = myBuff->buff; p < myBuffEnd; p++) {
1343  l++;
1344  if ((*p == '\n') || (*p == '\0')) {
1345  save = *(p+1);
1346  *(p+1) = '\0';
1347  // Remember the 1st segment
1348  int l1 = myBuff->buff + myBuff->bsize - myBuffStart;
1349 
1350  dest.assign(myBuffStart, 0, l1-1);
1351  //strncpy(dest, myBuffStart, l1);
1352  BuffConsume(l1);
1353 
1354  dest.insert(myBuffStart, l1, l-1);
1355  //strncpy(dest + l1, myBuffStart, l);
1356  //dest[l + l1] = '\0';
1357  BuffConsume(l);
1358 
1359  *(p+1) = save;
1360 
1361  //if (dest[l + l1 - 1] == '\n') dest[l + l1 - 1] = '\0';
1362  return l + l1;
1363  }
1364 
1365  }
1366 
1367 
1368 
1369  }
1370 
1371  return 0;
1372 }
1373 
1374 /******************************************************************************/
1375 /* g e t D a t a O n e S h o t */
1376 /******************************************************************************/
1377 
1378 int XrdHttpProtocol::getDataOneShot(int blen, bool wait) {
1379  int rlen, maxread;
1380 
1381  // Get up to blen bytes from the connection. Put them into mybuff.
1382  // This primitive, for the way it is used, is not supposed to block if wait=false
1383 
1384  // Returns:
1385  // 2: no space left in buffer
1386  // 1: timeout
1387  // -1: error
1388  // 0: everything read correctly
1389 
1390 
1391 
1392  // Check for buffer overflow first
1393  maxread = std::min(blen, BuffAvailable());
1394  TRACE(DEBUG, "getDataOneShot BuffAvailable: " << BuffAvailable() << " maxread: " << maxread);
1395 
1396  if (!maxread)
1397  return 2;
1398 
1399  if (ishttps) {
1400  int sslavail = maxread;
1401 
1402  if (!wait) {
1403  int l = SSL_pending(ssl);
1404  if (l > 0)
1405  sslavail = std::min(maxread, SSL_pending(ssl));
1406  }
1407 
1408  if (sslavail < 0) {
1409  Link->setEtext("link SSL_pending error");
1410  ERR_print_errors(sslbio_err);
1411  return -1;
1412  }
1413 
1414  TRACE(DEBUG, "getDataOneShot sslavail: " << sslavail);
1415  if (sslavail <= 0) return 0;
1416 
1417  if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1418  TRACE(DEBUG, "getDataOneShot Buffer panic");
1419  myBuffEnd = myBuff->buff;
1420  }
1421 
1422  rlen = SSL_read(ssl, myBuffEnd, sslavail);
1423  if (rlen <= 0) {
1424  Link->setEtext("link SSL read error");
1425  ERR_print_errors(sslbio_err);
1426  return -1;
1427  }
1428 
1429 
1430  } else {
1431 
1432  if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1433  TRACE(DEBUG, "getDataOneShot Buffer panic");
1434  myBuffEnd = myBuff->buff;
1435  }
1436 
1437  if (wait)
1438  rlen = Link->Recv(myBuffEnd, maxread, readWait);
1439  else
1440  rlen = Link->Recv(myBuffEnd, maxread);
1441 
1442 
1443  if (rlen == 0) {
1444  Link->setEtext("link read error or closed");
1445  return -1;
1446  }
1447 
1448  if (rlen < 0) {
1449  Link->setEtext("link timeout or other error");
1450  return -1;
1451  }
1452  }
1453 
1454  myBuffEnd += rlen;
1455 
1456  TRACE(REQ, "read " << rlen << " of " << blen << " bytes");
1457 
1458  return 0;
1459 }
1460 
1462 
1463 int XrdHttpProtocol::BuffAvailable() {
1464  int r;
1465 
1466  if (myBuffEnd >= myBuffStart)
1467  r = myBuff->buff + myBuff->bsize - myBuffEnd;
1468  else
1469  r = myBuffStart - myBuffEnd;
1470 
1471  if ((r < 0) || (r > myBuff->bsize)) {
1472  TRACE(REQ, "internal error, myBuffAvailable: " << r << " myBuff->bsize " << myBuff->bsize);
1473  abort();
1474  }
1475 
1476  return r;
1477 }
1478 
1479 /******************************************************************************/
1480 /* B u f f U s e d */
1481 /******************************************************************************/
1482 
1484 
1485 int XrdHttpProtocol::BuffUsed() {
1486  int r;
1487 
1488  if (myBuffEnd >= myBuffStart)
1489  r = myBuffEnd - myBuffStart;
1490  else
1491 
1492  r = myBuff->bsize - (myBuffStart - myBuffEnd);
1493 
1494  if ((r < 0) || (r > myBuff->bsize)) {
1495  TRACE(REQ, "internal error, myBuffUsed: " << r << " myBuff->bsize " << myBuff->bsize);
1496  abort();
1497  }
1498 
1499  return r;
1500 }
1501 
1502 /******************************************************************************/
1503 /* B u f f F r e e */
1504 /******************************************************************************/
1505 
1507 
1508 int XrdHttpProtocol::BuffFree() {
1509  return (myBuff->bsize - BuffUsed());
1510 }
1511 
1512 /******************************************************************************/
1513 /* B u f f C o n s u m e */
1514 /******************************************************************************/
1515 
1516 void XrdHttpProtocol::BuffConsume(int blen) {
1517 
1518  if (blen > myBuff->bsize) {
1519  TRACE(REQ, "internal error, BuffConsume(" << blen << ") smaller than buffsize");
1520  abort();
1521  }
1522 
1523  if (blen > BuffUsed()) {
1524  TRACE(REQ, "internal error, BuffConsume(" << blen << ") larger than BuffUsed:" << BuffUsed());
1525  abort();
1526  }
1527 
1528  myBuffStart = myBuffStart + blen;
1529 
1530  if (myBuffStart >= myBuff->buff + myBuff->bsize)
1531  myBuffStart -= myBuff->bsize;
1532 
1533  if (myBuffEnd >= myBuff->buff + myBuff->bsize)
1534  myBuffEnd -= myBuff->bsize;
1535 
1536  if (BuffUsed() == 0)
1537  myBuffStart = myBuffEnd = myBuff->buff;
1538 }
1539 
1540 /******************************************************************************/
1541 /* B u f f g e t D a t a */
1542 /******************************************************************************/
1543 
1552 int XrdHttpProtocol::BuffgetData(int blen, char **data, bool wait) {
1553  int rlen;
1554 
1555  TRACE(DEBUG, "BuffgetData: requested " << blen << " bytes");
1556 
1557 
1558  if (wait) {
1559  // If there's not enough data in the buffer then wait on the socket until it comes
1560  if (blen > BuffUsed()) {
1561  TRACE(REQ, "BuffgetData: need to read " << blen - BuffUsed() << " bytes");
1562  if ( getDataOneShot(blen - BuffUsed(), true) )
1563  // The wanted data could not be read. Either timeout of connection closed
1564  return 0;
1565  }
1566  } else {
1567  // Get a peek at the socket, without waiting, if we have no data in the buffer
1568  if ( !BuffUsed() ) {
1569  if ( getDataOneShot(blen, false) )
1570  // The wanted data could not be read. Either timeout of connection closed
1571  return -1;
1572  }
1573  }
1574 
1575  // And now make available the data taken from the buffer. Note that the buffer
1576  // may be empty...
1577  if (myBuffStart <= myBuffEnd) {
1578  rlen = std::min( (long) blen, (long)(myBuffEnd - myBuffStart) );
1579 
1580  } else
1581  rlen = std::min( (long) blen, (long)(myBuff->buff + myBuff->bsize - myBuffStart) );
1582 
1583  *data = myBuffStart;
1584  BuffConsume(rlen);
1585  return rlen;
1586 }
1587 
1588 /******************************************************************************/
1589 /* S e n d D a t a */
1590 /******************************************************************************/
1591 
1593 
1594 int XrdHttpProtocol::SendData(const char *body, int bodylen) {
1595 
1596  int r;
1597 
1598  if (body && bodylen) {
1599  TRACE(REQ, "Sending " << bodylen << " bytes");
1600  if (ishttps) {
1601  r = SSL_write(ssl, body, bodylen);
1602  if (r <= 0) {
1603  ERR_print_errors(sslbio_err);
1604  return -1;
1605  }
1606 
1607  } else {
1608  r = Link->Send(body, bodylen);
1609  if (r <= 0) return -1;
1610  }
1611  }
1612 
1613  return 0;
1614 }
1615 
1616 /******************************************************************************/
1617 /* S t a r t S i m p l e R e s p */
1618 /******************************************************************************/
1619 
1620 int XrdHttpProtocol::StartSimpleResp(int code, const char *desc,
1621  const char *header_to_add,
1622  long long bodylen, bool keepalive) {
1623  std::stringstream ss;
1624  const std::string crlf = "\r\n";
1625 
1626  ss << "HTTP/1.1 " << code << " ";
1627 
1628  if (desc) {
1629  ss << desc;
1630  } else {
1631  ss << httpStatusToString(code);
1632  }
1633  ss << crlf;
1634 
1635  if (keepalive && (code != 100))
1636  ss << "Connection: Keep-Alive" << crlf;
1637  else
1638  ss << "Connection: Close" << crlf;
1639 
1640  ss << "Server: XrootD/" << XrdVSTRING << crlf;
1641 
1642  const auto iter = m_staticheaders.find(CurrentReq.requestverb);
1643  if (iter != m_staticheaders.end()) {
1644  ss << iter->second;
1645  } else {
1646  ss << m_staticheaders[""];
1647  }
1648 
1649  if(xrdcors) {
1650  auto corsAllowOrigin = xrdcors->getCORSAllowOriginHeader(CurrentReq.m_origin);
1651  if(corsAllowOrigin) {
1652  ss << *corsAllowOrigin << crlf;
1653  }
1654  }
1655 
1656  if ((bodylen >= 0) && (code != 100))
1657  ss << "Content-Length: " << bodylen << crlf;
1658 
1659  if (header_to_add && (header_to_add[0] != '\0')) ss << header_to_add << crlf;
1660 
1661  ss << crlf;
1662 
1663  const std::string &outhdr = ss.str();
1664  TRACEI(RSP, "Sending resp: " << code << " header len:" << outhdr.size());
1665  if (SendData(outhdr.c_str(), outhdr.size()))
1666  return -1;
1667 
1668  return 0;
1669 }
1670 
1671 /******************************************************************************/
1672 /* S t a r t C h u n k e d R e s p */
1673 /******************************************************************************/
1674 
1675 int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1676  const std::string crlf = "\r\n";
1677  std::stringstream ss;
1678 
1679  if (header_to_add && (header_to_add[0] != '\0')) {
1680  ss << header_to_add << crlf;
1681  }
1682 
1683  ss << "Transfer-Encoding: chunked";
1684  TRACEI(RSP, "Starting chunked response");
1685  return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1686 }
1687 
1688 /******************************************************************************/
1689 /* C h u n k R e s p */
1690 /******************************************************************************/
1691 
1692 int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1693  long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1694  if (ChunkRespHeader(content_length))
1695  return -1;
1696 
1697  if (body && SendData(body, content_length))
1698  return -1;
1699 
1700  return ChunkRespFooter();
1701 }
1702 
1703 /******************************************************************************/
1704 /* C h u n k R e s p H e a d e r */
1705 /******************************************************************************/
1706 
1707 int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1708  const std::string crlf = "\r\n";
1709  std::stringstream ss;
1710 
1711  ss << std::hex << bodylen << std::dec << crlf;
1712 
1713  const std::string &chunkhdr = ss.str();
1714  TRACEI(RSP, "Sending encoded chunk of size " << bodylen);
1715  return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1716 }
1717 
1718 /******************************************************************************/
1719 /* C h u n k R e s p F o o t e r */
1720 /******************************************************************************/
1721 
1722 int XrdHttpProtocol::ChunkRespFooter() {
1723  const std::string crlf = "\r\n";
1724  return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1725 }
1726 
1727 /******************************************************************************/
1728 /* S e n d S i m p l e R e s p */
1729 /******************************************************************************/
1730 
1734 
1735 int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1736 
1737  long long content_length = bodylen;
1738  if (bodylen <= 0) {
1739  content_length = body ? strlen(body) : 0;
1740  }
1741 
1742  if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1743  return -1;
1744 
1745  //
1746  // Send the data
1747  //
1748  if (body)
1749  return SendData(body, content_length);
1750 
1751  return 0;
1752 }
1753 
1754 /******************************************************************************/
1755 /* C o n f i g u r e */
1756 /******************************************************************************/
1757 
1759  /*
1760  Function: Establish configuration at load time.
1761 
1762  Input: None.
1763 
1764  Output: 0 upon success or !0 otherwise.
1765  */
1766 
1767  char *rdf;
1768 
1769  // Copy out the special info we want to use at top level
1770  //
1771  eDest.logger(pi->eDest->logger());
1773  // SI = new XrdXrootdStats(pi->Stats);
1774  Sched = pi->Sched;
1775  BPool = pi->BPool;
1776  xrd_cslist = getenv("XRD_CSLIST");
1777 
1778  Port = pi->Port;
1779 
1780  // Copy out the current TLS context
1781  //
1782  xrdctx = pi->tlsCtx;
1783 
1784  {
1785  char buf[16];
1786  sprintf(buf, "%d", Port);
1787  Port_str = strdup(buf);
1788  }
1789 
1790  // Now process and configuration parameters
1791  //
1792  rdf = (parms && *parms ? parms : pi->ConfigFN);
1793  if (rdf && Config(rdf, pi->theEnv)) return 0;
1794  if (pi->DebugON) XrdHttpTrace.What = TRACE_ALL;
1795 
1796  // Set the redirect flag if we are a pure redirector
1797  myRole = kXR_isServer;
1798  if ((rdf = getenv("XRDROLE"))) {
1799  eDest.Emsg("Config", "XRDROLE: ", rdf);
1800 
1801  if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1803  eDest.Emsg("Config", "Configured as HTTP(s) redirector.");
1804  } else {
1805 
1806  eDest.Emsg("Config", "Configured as HTTP(s) data server.");
1807  }
1808 
1809  } else {
1810  eDest.Emsg("Config", "No XRDROLE specified.");
1811  }
1812 
1813  // Schedule protocol object cleanup
1814  //
1816  (XrdHttpTrace.What & TRACE_MEM ? TRACE_MEM : 0));
1817  ProtStack.Set((pi->ConnMax / 3 ? pi->ConnMax / 3 : 30), 60 * 60);
1818 
1819  // Return success
1820  //
1821 
1822  return 1;
1823 }
1824 
1825 /******************************************************************************/
1826 /* p a r s e H e a d e r 2 C G I */
1827 /******************************************************************************/
1828 int XrdHttpProtocol::parseHeader2CGI(XrdOucStream &Config, XrdSysError & err,std::map<std::string, std::string> &header2cgi) {
1829  char *val, keybuf[1024], parmbuf[1024];
1830  char *parm;
1831 
1832  // Get the header key
1833  val = Config.GetWord();
1834  if (!val || !val[0]) {
1835  err.Emsg("Config", "No headerkey specified.");
1836  return 1;
1837  } else {
1838 
1839  // Trim the beginning, in place
1840  while ( *val && !isalnum(*val) ) val++;
1841  strcpy(keybuf, val);
1842 
1843  // Trim the end, in place
1844  char *pp;
1845  pp = keybuf + strlen(keybuf) - 1;
1846  while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1847  *pp = '\0';
1848  pp--;
1849  }
1850 
1851  parm = Config.GetWord();
1852 
1853  // Avoids segfault in case a key is given without value
1854  if(!parm || !parm[0]) {
1855  err.Emsg("Config", "No header2cgi value specified. key: '", keybuf, "'");
1856  return 1;
1857  }
1858 
1859  // Trim the beginning, in place
1860  while ( *parm && !isalnum(*parm) ) parm++;
1861  strcpy(parmbuf, parm);
1862 
1863  // Trim the end, in place
1864  pp = parmbuf + strlen(parmbuf) - 1;
1865  while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1866  *pp = '\0';
1867  pp--;
1868  }
1869 
1870  // Add this mapping to the map that will be used
1871  try {
1872  header2cgi[keybuf] = parmbuf;
1873  } catch ( ... ) {
1874  err.Emsg("Config", "Can't insert new header2cgi rule. key: '", keybuf, "'");
1875  return 1;
1876  }
1877 
1878  }
1879  return 0;
1880 }
1881 
1882 
1883 /******************************************************************************/
1884 /* I n i t T L S */
1885 /******************************************************************************/
1886 
1887 bool XrdHttpProtocol::InitTLS() {
1888 
1889  std::string eMsg;
1892 
1893  if (allowMissingCRL) {
1895  }
1896 
1897 // Create a new TLS context
1898 //
1899  if (sslverifydepth > 255) sslverifydepth = 255;
1901  //TLS_SET_REFINT will set the refresh interval in minutes, hence the division by 60
1904 
1905 // Make sure the context was created
1906 //
1907  if (!xrdctx->isOK())
1908  {eDest.Say("Config failure: ", eMsg.c_str());
1909  return false;
1910  }
1911 
1912 // Setup session cache (this is controversial). The default is off but many
1913 // programs expect it being enabled and break when it is disabled. In such
1914 // cases it should be enabled. This is, of course, a big OpenSSL mess.
1915 //
1916  static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1917  unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1918  xrdctx->SessionCache(tlsCache, sess_ctx_id, n);
1919 
1920 // Set special ciphers if so specified.
1921 //
1923  {eDest.Say("Config failure: ", "Unable to set allowable https ciphers!");
1924  return false;
1925  }
1926 
1927 // Enable or disable the config in the context
1929 
1930 // All done
1931 //
1932  return true;
1933 }
1934 
1935 /******************************************************************************/
1936 /* C l e a n u p */
1937 /******************************************************************************/
1938 
1939 void XrdHttpProtocol::Cleanup() {
1940 
1941  TRACE(ALL, " Cleanup");
1942 
1943  if (BPool && myBuff) {
1944  BuffConsume(BuffUsed());
1945  BPool->Release(myBuff);
1946  myBuff = 0;
1947  }
1948 
1949  if (ssl) {
1950  // Shutdown the SSL/TLS connection
1951  // This triggers a bidirectional shutdown of the connection; the bidirectional
1952  // shutdown is useful to ensure that the client receives the server response;
1953  // a one-sided shutdown can result in the server sending a TCP reset packet, zapping
1954  // the contents of the TCP socket buffer on the client side. The HTTP 1.1 RFC has a
1955  // description of why this is important:
1956  // https://datatracker.ietf.org/doc/html/rfc9112#name-tls-connection-closure
1957  // Once we get the clean SSL shutdown message back from the client, we know that
1958  // the client has received the response and we can safely close the connection.
1959  int ret = SSL_shutdown(ssl);
1960  if (ret != 1) {
1961  if(ret == 0) {
1962  // ret == 0, the unidirectional shutdown was successful; wait for the acknowledgement.
1963  ret = SSL_shutdown(ssl);
1964  if (ret != 1) {
1965  TRACE(ALL, "SSL server failed to receive the SSL shutdown message from the client");
1966  ERR_print_errors(sslbio_err);
1967  }
1968  } else {
1969  //ret < 0, an error really happened.
1970  TRACE(ALL, "SSL server failed to send the shutdown message to the client");
1971  ERR_print_errors(sslbio_err);
1972  }
1973  }
1974 
1975  if (secxtractor)
1976  secxtractor->FreeSSL(ssl);
1977 
1978  SSL_free(ssl);
1979 
1980  }
1981 
1982 
1983  ssl = 0;
1984  sbio = 0;
1985 
1986  if (SecEntity.caps) free(SecEntity.caps);
1987  if (SecEntity.grps) free(SecEntity.grps);
1989  if (SecEntity.vorg) free(SecEntity.vorg);
1990  if (SecEntity.role) free(SecEntity.role);
1991  if (SecEntity.name) free(SecEntity.name);
1992  if (SecEntity.host) free(SecEntity.host);
1993  if (SecEntity.moninfo) free(SecEntity.moninfo);
1994 
1995  SecEntity.Reset();
1996 
1997  if (Addr_str) free(Addr_str);
1998  Addr_str = 0;
1999 }
2000 
2001 /******************************************************************************/
2002 /* R e s e t */
2003 /******************************************************************************/
2004 
2005 void XrdHttpProtocol::Reset() {
2006 
2007  TRACE(ALL, " Reset");
2008  Link = 0;
2009  CurrentReq.reset();
2010  CurrentReq.reqstate = 0;
2011 
2012  if (myBuff) {
2013  BPool->Release(myBuff);
2014  myBuff = 0;
2015  }
2016  myBuffStart = myBuffEnd = 0;
2017 
2018  DoingLogin = false;
2019  DoneSetInfo = false;
2020 
2021  ResumeBytes = 0;
2022  Resume = 0;
2023 
2024  //
2025  // numReads = 0;
2026  // numReadP = 0;
2027  // numReadV = 0;
2028  // numSegsV = 0;
2029  // numWrites = 0;
2030  // numFiles = 0;
2031  // cumReads = 0;
2032  // cumReadV = 0;
2033  // cumSegsV = 0;
2034  // cumWrites = 0;
2035  // totReadP = 0;
2036 
2037  SecEntity.Reset();
2039  ishttps = false;
2040  ssldone = false;
2041 
2042  Bridge = 0;
2043  ssl = 0;
2044  sbio = 0;
2045 
2046 }
2047 
2048 /******************************************************************************/
2049 /* x h t t p s m o d e */
2050 /******************************************************************************/
2051 
2052 /* Function: xhttpsmode
2053 
2054  Purpose: To parse the directive: httpsmode {auto | disable | manual}
2055 
2056  auto configure https if configured in xrd framework.
2057  disable do not configure https no matter what
2058  manual configure https and ignore the xrd framework
2059 
2060  Output: 0 upon success or !0 upon failure.
2061  */
2062 
2063 int XrdHttpProtocol::xhttpsmode(XrdOucStream & Config) {
2064  char *val;
2065 
2066  // Get the val
2067  //
2068  val = Config.GetWord();
2069  if (!val || !val[0]) {
2070  eDest.Emsg("Config", "httpsmode parameter not specified");
2071  return 1;
2072  }
2073 
2074  // Record the val
2075  //
2076  if (!strcmp(val, "auto")) httpsmode = hsmAuto;
2077  else if (!strcmp(val, "disable")) httpsmode = hsmOff;
2078  else if (!strcmp(val, "manual")) httpsmode = hsmMan;
2079  else {eDest.Emsg("Config", "invalid httpsmode parameter - ", val);
2080  return 1;
2081  }
2082  return 0;
2083 }
2084 
2085 /******************************************************************************/
2086 /* x s s l v e r i f y d e p t h */
2087 /******************************************************************************/
2088 
2089 /* Function: xsslverifydepth
2090 
2091  Purpose: To parse the directive: sslverifydepth <depth>
2092 
2093  <depth> the max depth of the ssl cert verification
2094 
2095  Output: 0 upon success or !0 upon failure.
2096  */
2097 
2098 int XrdHttpProtocol::xsslverifydepth(XrdOucStream & Config) {
2099  char *val;
2100 
2101  // Get the val
2102  //
2103  val = Config.GetWord();
2104  if (!val || !val[0]) {
2105  eDest.Emsg("Config", "sslverifydepth value not specified");
2106  return 1;
2107  }
2108 
2109  // Record the val
2110  //
2111  sslverifydepth = atoi(val);
2112 
2113  if (xrdctxVer){ HTTPS_ALERT("verifydepth","tlsca",false); }
2114  return 0;
2115 }
2116 
2117 /******************************************************************************/
2118 /* x s s l c e r t */
2119 /******************************************************************************/
2120 
2121 /* Function: xsslcert
2122 
2123  Purpose: To parse the directive: sslcert <path>
2124 
2125  <path> the path of the server certificate to be used.
2126 
2127  Output: 0 upon success or !0 upon failure.
2128  */
2129 
2130 int XrdHttpProtocol::xsslcert(XrdOucStream & Config) {
2131  char *val;
2132 
2133  // Get the path
2134  //
2135  val = Config.GetWord();
2136  if (!val || !val[0]) {
2137  eDest.Emsg("Config", "HTTP X509 certificate not specified");
2138  return 1;
2139  }
2140 
2141  // Record the path
2142  //
2143  if (sslcert) free(sslcert);
2144  sslcert = strdup(val);
2145 
2146  // If we have an xrd context issue reminder
2147  //
2148  HTTPS_ALERT("cert","tls",true);
2149  return 0;
2150 }
2151 
2152 /******************************************************************************/
2153 /* x s s l k e y */
2154 /******************************************************************************/
2155 
2156 /* Function: xsslkey
2157 
2158  Purpose: To parse the directive: sslkey <path>
2159 
2160  <path> the path of the server key to be used.
2161 
2162  Output: 0 upon success or !0 upon failure.
2163  */
2164 
2165 int XrdHttpProtocol::xsslkey(XrdOucStream & Config) {
2166  char *val;
2167 
2168  // Get the path
2169  //
2170  val = Config.GetWord();
2171  if (!val || !val[0]) {
2172  eDest.Emsg("Config", "HTTP X509 key not specified");
2173  return 1;
2174  }
2175 
2176  // Record the path
2177  //
2178  if (sslkey) free(sslkey);
2179  sslkey = strdup(val);
2180 
2181  HTTPS_ALERT("key","tls",true);
2182  return 0;
2183 }
2184 
2185 /******************************************************************************/
2186 /* x g m a p */
2187 /******************************************************************************/
2188 
2189 /* Function: xgmap
2190 
2191  Purpose: To parse the directive: gridmap [required] [compatNameGeneration] <path>
2192 
2193  required optional parameter which if present treats any grimap errors
2194  as fatal.
2195  <path> the path of the gridmap file to be used. Normally it's
2196  /etc/grid-security/gridmap. No mapfile means no translation
2197  required. Pointing to a non existing mapfile is an error.
2198 
2199  Output: 0 upon success or !0 upon failure.
2200  */
2201 
2202 int XrdHttpProtocol::xgmap(XrdOucStream & Config) {
2203  char *val;
2204 
2205  // Get the path
2206  //
2207  val = Config.GetWord();
2208  if (!val || !val[0]) {
2209  eDest.Emsg("Config", "HTTP X509 gridmap file location not specified");
2210  return 1;
2211  }
2212 
2213  // Handle optional parameter "required"
2214  //
2215  if (!strncmp(val, "required", 8)) {
2216  isRequiredGridmap = true;
2217  val = Config.GetWord();
2218 
2219  if (!val || !val[0]) {
2220  eDest.Emsg("Config", "HTTP X509 gridmap file missing after [required] "
2221  "parameter");
2222  return 1;
2223  }
2224  }
2225 
2226  // Handle optional parameter "compatNameGeneration"
2227  //
2228  if (!strcmp(val, "compatNameGeneration")) {
2229  compatNameGeneration = true;
2230  val = Config.GetWord();
2231  if (!val || !val[0]) {
2232  eDest.Emsg("Config", "HTTP X509 gridmap file missing after "
2233  "[compatNameGeneration] parameter");
2234  return 1;
2235  }
2236  }
2237 
2238 
2239  // Record the path
2240  //
2241  if (gridmap) free(gridmap);
2242  gridmap = strdup(val);
2243  return 0;
2244 }
2245 
2246 /******************************************************************************/
2247 /* x s s l c a f i l e */
2248 /******************************************************************************/
2249 
2250 /* Function: xsslcafile
2251 
2252  Purpose: To parse the directive: sslcafile <path>
2253 
2254  <path> the path of the server key to be used.
2255 
2256  Output: 0 upon success or !0 upon failure.
2257  */
2258 
2259 int XrdHttpProtocol::xsslcafile(XrdOucStream & Config) {
2260  char *val;
2261 
2262  // Get the path
2263  //
2264  val = Config.GetWord();
2265  if (!val || !val[0]) {
2266  eDest.Emsg("Config", "HTTP X509 CAfile not specified");
2267  return 1;
2268  }
2269 
2270  // Record the path
2271  //
2272  if (sslcafile) free(sslcafile);
2273  sslcafile = strdup(val);
2274 
2275  if (xrdctxVer){ HTTPS_ALERT("cafile","tlsca",false); }
2276  return 0;
2277 }
2278 
2279 /******************************************************************************/
2280 /* x s e c r e t k e y */
2281 /******************************************************************************/
2282 
2283 /* Function: xsecretkey
2284 
2285  Purpose: To parse the directive: xsecretkey <key>
2286 
2287  <key> the key to be used
2288 
2289  Output: 0 upon success or !0 upon failure.
2290  */
2291 
2292 int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2293  char *val;
2294  bool inFile = false;
2295 
2296  // Get the path
2297  //
2298  val = Config.GetWord();
2299  if (!val || !val[0]) {
2300  eDest.Emsg("Config", "Shared secret key not specified");
2301  return 1;
2302  }
2303 
2304 
2305  // If the token starts with a slash, then we interpret it as
2306  // the path to a file that contains the secretkey
2307  // otherwise, the token itself is the secretkey
2308  if (val[0] == '/') {
2309  struct stat st;
2310  inFile = true;
2311  int fd = open(val, O_RDONLY);
2312 
2313  if ( fd == -1 ) {
2314  eDest.Emsg("Config", errno, "open shared secret key file", val);
2315  return 1;
2316  }
2317 
2318  if ( fstat(fd, &st) != 0 ) {
2319  eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2320  close(fd);
2321  return 1;
2322  }
2323 
2324  if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2325  eDest.Emsg("Config",
2326  "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2327  close(fd);
2328  return 1;
2329  }
2330 
2331  FILE *fp = fdopen(fd, "r");
2332 
2333  if ( fp == nullptr ) {
2334  eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2335  close(fd);
2336  return 1;
2337  }
2338 
2339  char line[1024];
2340  while( fgets(line, 1024, fp) ) {
2341  char *pp;
2342 
2343  // Trim the end
2344  pp = line + strlen(line) - 1;
2345  while ( (pp >= line) && (!isalnum(*pp)) ) {
2346  *pp = '\0';
2347  pp--;
2348  }
2349 
2350  // Trim the beginning
2351  pp = line;
2352  while ( *pp && !isalnum(*pp) ) pp++;
2353 
2354  if ( strlen(pp) >= 32 ) {
2355  eDest.Say("Config", "Secret key loaded.");
2356  // Record the path
2357  if (secretkey) free(secretkey);
2358  secretkey = strdup(pp);
2359 
2360  fclose(fp);
2361  return 0;
2362  }
2363 
2364  }
2365 
2366  fclose(fp);
2367  eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2368  return 1;
2369 
2370  }
2371 
2372  if ( strlen(val) < 32 ) {
2373  eDest.Emsg("Config", "Secret key is too short");
2374  return 1;
2375  }
2376 
2377  // Record the path
2378  if (secretkey) free(secretkey);
2379  secretkey = strdup(val);
2380  if (!inFile) Config.noEcho();
2381 
2382  return 0;
2383 }
2384 
2385 /******************************************************************************/
2386 /* x l i s t d e n y */
2387 /******************************************************************************/
2388 
2389 /* Function: xlistdeny
2390 
2391  Purpose: To parse the directive: listingdeny <yes|no|0|1>
2392 
2393  <val> makes this redirector deny listings with an error
2394 
2395  Output: 0 upon success or !0 upon failure.
2396  */
2397 
2398 int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2399  char *val;
2400 
2401  // Get the path
2402  //
2403  val = Config.GetWord();
2404  if (!val || !val[0]) {
2405  eDest.Emsg("Config", "listingdeny flag not specified");
2406  return 1;
2407  }
2408 
2409  // Record the value
2410  //
2411  listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2412 
2413 
2414  return 0;
2415 }
2416 
2417 /******************************************************************************/
2418 /* x l i s t r e d i r */
2419 /******************************************************************************/
2420 
2421 /* Function: xlistredir
2422 
2423  Purpose: To parse the directive: listingredir <Url>
2424 
2425  <Url> http/https server to redirect to in the case of listing
2426 
2427  Output: 0 upon success or !0 upon failure.
2428  */
2429 
2430 int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2431  char *val;
2432 
2433  // Get the path
2434  //
2435  val = Config.GetWord();
2436  if (!val || !val[0]) {
2437  eDest.Emsg("Config", "listingredir flag not specified");
2438  return 1;
2439  }
2440 
2441  // Record the value
2442  //
2443  if (listredir) free(listredir);
2444  listredir = strdup(val);
2445 
2446 
2447  return 0;
2448 }
2449 
2450 /******************************************************************************/
2451 /* x s s l d e s t h t t p s */
2452 /******************************************************************************/
2453 
2454 /* Function: xdesthttps
2455 
2456  Purpose: To parse the directive: desthttps <yes|no|0|1>
2457 
2458  <val> makes this redirector produce http or https redirection targets
2459 
2460  Output: 0 upon success or !0 upon failure.
2461  */
2462 
2463 int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2464  char *val;
2465 
2466  // Get the path
2467  //
2468  val = Config.GetWord();
2469  if (!val || !val[0]) {
2470  eDest.Emsg("Config", "desthttps flag not specified");
2471  return 1;
2472  }
2473 
2474  // Record the value
2475  //
2476  isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2477 
2478 
2479  return 0;
2480 }
2481 
2482 /******************************************************************************/
2483 /* x e m b e d d e d s t a t i c */
2484 /******************************************************************************/
2485 
2486 /* Function: xembeddedstatic
2487 
2488  Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2489 
2490  <val> this server will redirect HTTPS to itself using HTTP+token
2491 
2492  Output: 0 upon success or !0 upon failure.
2493  */
2494 
2495 int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2496  char *val;
2497 
2498  // Get the path
2499  //
2500  val = Config.GetWord();
2501  if (!val || !val[0]) {
2502  eDest.Emsg("Config", "embeddedstatic flag not specified");
2503  return 1;
2504  }
2505 
2506  // Record the value
2507  //
2508  embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2509 
2510 
2511  return 0;
2512 }
2513 
2514 /******************************************************************************/
2515 /* x r e d i r s t a t i c */
2516 /******************************************************************************/
2517 
2518 /* Function: xstaticredir
2519 
2520  Purpose: To parse the directive: staticredir <Url>
2521 
2522  <Url> http/https server to redirect to in the case of /static
2523 
2524  Output: 0 upon success or !0 upon failure.
2525  */
2526 
2527 int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2528  char *val;
2529 
2530  // Get the path
2531  //
2532  val = Config.GetWord();
2533  if (!val || !val[0]) {
2534  eDest.Emsg("Config", "staticredir url not specified");
2535  return 1;
2536  }
2537 
2538  // Record the value
2539  //
2540  if (staticredir) free(staticredir);
2541  staticredir = strdup(val);
2542 
2543  return 0;
2544 }
2545 
2546 /******************************************************************************/
2547 /* x p r e l o a d s t a t i c */
2548 /******************************************************************************/
2549 
2550 /* Function: xpreloadstatic
2551 
2552  Purpose: To parse the directive: preloadstatic <http url path> <local file>
2553 
2554  <http url path> http/http path whose response we are preloading
2555  e.g. /static/mycss.css
2556  NOTE: this must start with /static
2557 
2558 
2559  Output: 0 upon success or !0 upon failure.
2560  */
2561 
2562 int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2563  char *val, *k, key[1024];
2564 
2565  // Get the key
2566  //
2567  k = Config.GetWord();
2568  if (!k || !k[0]) {
2569  eDest.Emsg("Config", "preloadstatic urlpath not specified");
2570  return 1;
2571  }
2572 
2573  strcpy(key, k);
2574 
2575  // Get the val
2576  //
2577  val = Config.GetWord();
2578  if (!val || !val[0]) {
2579  eDest.Emsg("Config", "preloadstatic filename not specified");
2580  return 1;
2581  }
2582 
2583  // Try to load the file into memory
2584  int fp = open(val, O_RDONLY);
2585  if( fp < 0 ) {
2586  eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2587  return 1;
2588  }
2589 
2590  StaticPreloadInfo *nfo = new StaticPreloadInfo;
2591  // Max 64Kb ok?
2592  nfo->data = (char *)malloc(65536);
2593  nfo->len = read(fp, (void *)nfo->data, 65536);
2594  close(fp);
2595 
2596  if (nfo->len <= 0) {
2597  eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2598  return 1;
2599  }
2600 
2601  if (nfo->len >= 65536) {
2602  eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2603  return 1;
2604  }
2605 
2606  // Record the value
2607  //
2608  if (!staticpreload)
2610 
2611  staticpreload->Rep((const char *)key, nfo);
2612  return 0;
2613 }
2614 
2615 /******************************************************************************/
2616 /* x s t a t i c h e a d e r */
2617 /******************************************************************************/
2618 
2619 //
2620 // xstaticheader parses the http.staticheader director with the following syntax:
2621 //
2622 // http.staticheader [-verb=[GET|HEAD|...]]* header [value]
2623 //
2624 // When set, this will cause XrdHttp to always return the specified header and
2625 // value.
2626 //
2627 // Setting this option multiple times is additive (multiple headers may be set).
2628 // Omitting the value will cause the static header setting to be unset.
2629 //
2630 // Omitting the -verb argument will cause it the header to be set unconditionally
2631 // for all requests.
2632 int XrdHttpProtocol::xstaticheader(XrdOucStream & Config) {
2633  auto val = Config.GetWord();
2634  std::vector<std::string> verbs;
2635  while (true) {
2636  if (!val || !val[0]) {
2637  eDest.Emsg("Config", "http.staticheader requires the header to be specified");
2638  return 1;
2639  }
2640 
2641  std::string match_verb;
2642  std::string_view val_str(val);
2643  if (val_str.substr(0, 6) == "-verb=") {
2644  verbs.emplace_back(val_str.substr(6));
2645  } else if (val_str == "-") {
2646  eDest.Emsg("Config", "http.staticheader is ignoring unknown flag: ", val_str.data());
2647  } else {
2648  break;
2649  }
2650 
2651  val = Config.GetWord();
2652  }
2653  if (verbs.empty()) {
2654  verbs.emplace_back();
2655  }
2656 
2657  std::string header = val;
2658 
2659  val = Config.GetWord();
2660  std::string header_value;
2661  if (val && val[0]) {
2662  header_value = val;
2663  }
2664 
2665  for (const auto &verb : verbs) {
2666  auto iter = m_staticheader_map.find(verb);
2667  if (iter == m_staticheader_map.end()) {
2668  if (!header_value.empty())
2669  m_staticheader_map.insert(iter, {verb, {{header, header_value}}});
2670  } else if (header_value.empty()) {
2671  iter->second.clear();
2672  } else {
2673  iter->second.emplace_back(header, header_value);
2674  }
2675  }
2676 
2677  return 0;
2678 }
2679 
2680 
2681 /******************************************************************************/
2682 /* x s e l f h t t p s 2 h t t p */
2683 /******************************************************************************/
2684 
2685 /* Function: selfhttps2http
2686 
2687  Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2688 
2689  <val> this server will redirect HTTPS to itself using HTTP+token
2690 
2691  Output: 0 upon success or !0 upon failure.
2692  */
2693 
2694 int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2695  char *val;
2696 
2697  // Get the path
2698  //
2699  val = Config.GetWord();
2700  if (!val || !val[0]) {
2701  eDest.Emsg("Config", "selfhttps2http flag not specified");
2702  return 1;
2703  }
2704 
2705  // Record the value
2706  //
2707  selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2708 
2709 
2710  return 0;
2711 }
2712 
2713 /******************************************************************************/
2714 /* x s e c x t r a c t o r */
2715 /******************************************************************************/
2716 
2717 /* Function: xsecxtractor
2718 
2719  Purpose: To parse the directive: secxtractor [required] <path> <params>
2720 
2721  required optional parameter which if present treats any secxtractor
2722  errors as fatal.
2723  <path> the path of the plugin to be loaded
2724  <params> parameters passed to the secxtractor library
2725 
2726  Output: 0 upon success or !0 upon failure.
2727  */
2728 
2729 int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2730  char *val;
2731 
2732  // Get the path
2733  //
2734  val = Config.GetWord();
2735  if (!val || !val[0]) {
2736  eDest.Emsg("Config", "No security extractor plugin specified.");
2737  return 1;
2738  } else {
2739  // Handle optional parameter [required]
2740  //
2741  if (!strncmp(val, "required", 8)) {
2742  isRequiredXtractor = true;
2743  val = Config.GetWord();
2744 
2745  if (!val || !val[0]) {
2746  eDest.Emsg("Config", "No security extractor plugin after [required] "
2747  "parameter");
2748  return 1;
2749  }
2750  }
2751 
2752  char libName[4096];
2753  strlcpy(libName, val, sizeof(libName));
2754  libName[sizeof(libName) - 1] = '\0';
2755  char libParms[4096];
2756 
2757  if (!Config.GetRest(libParms, 4095)) {
2758  eDest.Emsg("Config", "secxtractor config params longer than 4k");
2759  return 1;
2760  }
2761 
2762  // Try to load the plugin (if available) that extracts info from the
2763  // user cert/proxy
2764  if (LoadSecXtractor(&eDest, libName, libParms)) {
2765  return 1;
2766  }
2767  }
2768 
2769  return 0;
2770 }
2771 
2772 int XrdHttpProtocol::xcors(XrdOucStream& Config) {
2773  char * val;
2774  // Get the path
2775  val = Config.GetWord();
2776  if (!val || !val[0]) {
2777  eDest.Emsg("Config", "No CORS plugin specified.");
2778  return 1;
2779  }
2780  xrdcorsLibPath = val;
2781  return 0;
2782 }
2783 
2784 /******************************************************************************/
2785 /* x e x t h a n d l e r */
2786 /******************************************************************************/
2787 
2788 /* Function: xexthandler
2789  *
2790  * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2791  *
2792  * <name> a unique name (max 16chars) to be given to this
2793  * instance, e.g 'myhandler1'
2794  * <path> the path of the plugin to be loaded
2795  * <initparm> a string parameter (e.g. a config file) that is
2796  * passed to the initialization of the plugin
2797  *
2798  * Output: 0 upon success or !0 upon failure.
2799  */
2800 
2801 int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2802  std::vector<extHInfo> &hiVec) {
2803  char *val, path[1024], namebuf[1024];
2804  char *parm;
2805  // By default, every external handler need TLS configured to be loaded
2806  bool noTlsOK = false;
2807 
2808  // Get the name
2809  //
2810  val = Config.GetWord();
2811  if (!val || !val[0]) {
2812  eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2813  return 1;
2814  }
2815  if (strlen(val) >= 16) {
2816  eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2817  return 1;
2818  }
2819  strncpy(namebuf, val, sizeof(namebuf));
2820  namebuf[ sizeof(namebuf)-1 ] = '\0';
2821 
2822  // Get the +notls option if it was provided
2823  val = Config.GetWord();
2824 
2825  if(val && !strcmp("+notls",val)) {
2826  noTlsOK = true;
2827  val = Config.GetWord();
2828  }
2829 
2830  // Get the path
2831  //
2832  if (!val || !val[0]) {
2833  eDest.Emsg("Config", "No http external handler plugin specified.");
2834  return 1;
2835  }
2836  if (strlen(val) >= (int)sizeof(path)) {
2837  eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2838  return 1;
2839  }
2840 
2841  strcpy(path, val);
2842 
2843  // Everything else is a free string
2844  //
2845  parm = Config.GetWord();
2846 
2847  // Verify whether this is a duplicate (we never supported replacements)
2848  //
2849  for (int i = 0; i < (int)hiVec.size(); i++)
2850  {if (hiVec[i].extHName == namebuf) {
2851  eDest.Emsg("Config", "Instance name already present for "
2852  "http external handler plugin",
2853  hiVec[i].extHPath.c_str());
2854  return 1;
2855  }
2856  }
2857 
2858  // Verify that we don't have more already than we are allowed to have
2859  //
2860  if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2861  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2862  return 1;
2863  }
2864 
2865  // Create an info struct and push it on the list of ext handlers to load
2866  //
2867  hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2868 
2869  return 0;
2870 }
2871 
2872 /******************************************************************************/
2873 /* x h e a d e r 2 c g i */
2874 /******************************************************************************/
2875 
2876 /* Function: xheader2cgi
2877  *
2878  * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2879  *
2880  * <headerkey> the name of an incoming HTTP header
2881  * to be transformed
2882  * <cgikey> the name to be given when adding it to the cgi info
2883  * that is kept only internally
2884  *
2885  * Output: 0 upon success or !0 upon failure.
2886  */
2887 
2888 int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2890 }
2891 
2892 /******************************************************************************/
2893 /* x s s l c a d i r */
2894 /******************************************************************************/
2895 
2896 /* Function: xsslcadir
2897 
2898  Purpose: To parse the directive: sslcadir <path>
2899 
2900  <path> the path of the server key to be used.
2901 
2902  Output: 0 upon success or !0 upon failure.
2903  */
2904 
2905 int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2906  char *val;
2907 
2908  // Get the path
2909  //
2910  val = Config.GetWord();
2911  if (!val || !val[0]) {
2912  eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2913  return 1;
2914  }
2915 
2916  // Record the path
2917  //
2918  if (sslcadir) free(sslcadir);
2919  sslcadir = strdup(val);
2920 
2921  if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2922  return 0;
2923 }
2924 
2925 /******************************************************************************/
2926 /* x s s l c i p h e r f i l t e r */
2927 /******************************************************************************/
2928 
2929 /* Function: xsslcipherfilter
2930 
2931  Purpose: To parse the directive: cipherfilter <filter>
2932 
2933  <filter> the filter string to be used when generating
2934  the SSL cipher list
2935 
2936  Output: 0 upon success or !0 upon failure.
2937  */
2938 
2939 int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2940  char *val;
2941 
2942  // Get the filter string
2943  //
2944  val = Config.GetWord();
2945  if (!val || !val[0]) {
2946  eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2947  return 1;
2948  }
2949 
2950  // Record the filter string
2951  //
2952  if (sslcipherfilter) free(sslcipherfilter);
2953  sslcipherfilter = strdup(val);
2954 
2955  return 0;
2956 }
2957 
2958 /******************************************************************************/
2959 /* x t l s r e u s e */
2960 /******************************************************************************/
2961 
2962 /* Function: xtlsreuse
2963 
2964  Purpose: To parse the directive: tlsreuse {on | off}
2965 
2966  Output: 0 upon success or 1 upon failure.
2967  */
2968 
2969 int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2970 
2971  char *val;
2972 
2973 // Get the argument
2974 //
2975  val = Config.GetWord();
2976  if (!val || !val[0])
2977  {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2978 
2979 // If it's off, we set it off
2980 //
2981  if (!strcmp(val, "off"))
2983  return 0;
2984  }
2985 
2986 // If it's on we set it on.
2987 //
2988  if (!strcmp(val, "on"))
2990  return 0;
2991  }
2992 
2993 // Bad argument
2994 //
2995  eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2996  return 1;
2997 }
2998 
2999 int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) {
3000  auto val = Config.GetWord();
3001  if (!val || !val[0])
3002  {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;}
3003 
3004  if (!strcmp(val, "off"))
3005  {tlsClientAuth = false;
3006  return 0;
3007  }
3008  if (!strcmp(val, "on"))
3009  {tlsClientAuth = true;
3010  return 0;
3011  }
3012 
3013  eDest.Emsg("config", "invalid tlsclientauth parameter -", val);
3014  return 1;
3015 }
3016 
3017 int XrdHttpProtocol::xauth(XrdOucStream &Config) {
3018  char *val = Config.GetWord();
3019  if(val) {
3020  if(!strcmp("tpc",val)) {
3021  if(!(val = Config.GetWord())) {
3022  eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
3023  } else {
3024  if(!strcmp("fcreds",val)) {
3025  tpcForwardCreds = true;
3026  } else {
3027  eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
3028  }
3029  }
3030  } else {
3031  eDest.Emsg("Config", "http.auth value is invalid"); return 1;
3032  }
3033  }
3034  return 0;
3035 }
3036 
3037 int XrdHttpProtocol::xmaxdelay(XrdOucStream &Config) {
3038  char *val = Config.GetWord();
3039  if(val) {
3040  int maxdelay;
3041  if (XrdOuca2x::a2tm(eDest, "http.maxdelay", val, &maxdelay, 1)) return 1;
3042  m_maxdelay = maxdelay;
3043  } else {
3044  eDest.Emsg("Config", "http.maxdelay requires an argument in seconds (default is 30). Example: http.maxdelay 30");
3045  return 1;
3046  }
3047  return 0;
3048 }
3049 
3050 /******************************************************************************/
3051 /* x t r a c e */
3052 /******************************************************************************/
3053 
3054 /* Function: xtrace
3055 
3056  Purpose: To parse the directive: trace <events>
3057 
3058  <events> the blank separated list of events to trace. Trace
3059  directives are cumulative.
3060 
3061  Output: 0 upon success or 1 upon failure.
3062  */
3063 
3064 int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
3065 
3066  char *val;
3067 
3068  static struct traceopts {
3069  const char *opname;
3070  int opval;
3071  } tropts[] = {
3072  {"all", TRACE_ALL},
3073  {"auth", TRACE_AUTH},
3074  {"debug", TRACE_DEBUG},
3075  {"mem", TRACE_MEM},
3076  {"redirect", TRACE_REDIR},
3077  {"request", TRACE_REQ},
3078  {"response", TRACE_RSP}
3079  };
3080  int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3081 
3082  if (!(val = Config.GetWord())) {
3083  eDest.Emsg("config", "trace option not specified");
3084  return 1;
3085  }
3086  while (val) {
3087  if (!strcmp(val, "off")) trval = 0;
3088  else {
3089  if ((neg = (val[0] == '-' && val[1]))) val++;
3090  for (i = 0; i < numopts; i++) {
3091  if (!strcmp(val, tropts[i].opname)) {
3092  if (neg) trval &= ~tropts[i].opval;
3093  else trval |= tropts[i].opval;
3094  break;
3095  }
3096  }
3097  if (i >= numopts)
3098  eDest.Emsg("config", "invalid trace option", val);
3099  }
3100  val = Config.GetWord();
3101  }
3102  XrdHttpTrace.What = trval;
3103  return 0;
3104 }
3105 
3106 int XrdHttpProtocol::doStat(char *fname) {
3107  int l;
3108  bool b;
3109  CurrentReq.filesize = 0;
3110  CurrentReq.fileflags = 0;
3111  CurrentReq.filemodtime = 0;
3112 
3113  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3115  memset(CurrentReq.xrdreq.stat.reserved, 0,
3116  sizeof (CurrentReq.xrdreq.stat.reserved));
3117  l = strlen(fname) + 1;
3118  CurrentReq.xrdreq.stat.dlen = htonl(l);
3119 
3120  if (!Bridge) return -1;
3121  b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3122  if (!b) {
3123  return -1;
3124  }
3125 
3126 
3127  return 0;
3128 }
3129 
3130 /******************************************************************************/
3131 /* d o C h k s u m */
3132 /******************************************************************************/
3133 
3135  size_t length;
3136  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3140  memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
3142  length = fname.length() + 1;
3143  CurrentReq.xrdreq.query.dlen = htonl(length);
3144 
3145  if (!Bridge) return -1;
3146 
3147  return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3148 }
3149 
3150 
3151 static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3152 
3153 // Loads the SecXtractor plugin, if available
3154 int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3155  const char *libParms) {
3156 
3157 
3158  // We don't want to load it more than once
3159  if (secxtractor) return 1;
3160 
3161  XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3163 
3164  // Get the entry point of the object creator
3165  //
3166  ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3167  if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3168  myLib.Unload();
3169  return 1;
3170 }
3171 /******************************************************************************/
3172 /* L o a d E x t H a n d l e r */
3173 /******************************************************************************/
3174 
3175 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3176  for (int i = 0; i < (int) hiVec.size(); i++) {
3177  if(hiVec[i].extHNoTlsOK) {
3178  // The external plugin does not need TLS to be loaded
3179  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3180  hiVec[i].extHParm.c_str(), &myEnv,
3181  hiVec[i].extHName.c_str()))
3182  return 1;
3183  }
3184  }
3185  return 0;
3186 }
3187 
3188 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3189  const char *cFN, XrdOucEnv &myEnv) {
3190 
3191  // Add the pointer to the cadir and the cakey to the environment.
3192  //
3193  if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3194  if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3195  if (sslcert) myEnv.Put("http.cert", sslcert);
3196  if (sslkey) myEnv.Put("http.key" , sslkey);
3197  // Add the allowMissingCRL configuration to the environment
3198  myEnv.PutInt("http.allowmissingcrl",allowMissingCRL ? 1 : 0);
3199 
3200  // Load all of the specified external handlers.
3201  //
3202  for (int i = 0; i < (int)hiVec.size(); i++) {
3203  // Only load the external handlers that were not already loaded
3204  // by LoadExtHandlerNoTls(...)
3205  if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3206  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3207  hiVec[i].extHParm.c_str(), &myEnv,
3208  hiVec[i].extHName.c_str())) return 1;
3209  }
3210  }
3211  return 0;
3212 }
3213 
3214 // Loads the external handler plugin, if available
3215 int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3216  const char *configFN, const char *libParms,
3217  XrdOucEnv *myEnv, const char *instName) {
3218 
3219 
3220  // This function will avoid loading doubles. No idea why this happens
3221  if (ExtHandlerLoaded(instName)) {
3222  eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3223  return 1;
3224  }
3225  if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3226  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3227  return 1;
3228  }
3229 
3230  XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3232 
3233  // Get the entry point of the object creator
3234  //
3235  ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3236 
3237  XrdHttpExtHandler *newhandler;
3238  if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3239 
3240  // Handler has been loaded, it's the last one in the list
3241  strncpy( exthandler[exthandlercnt].name, instName, 16 );
3242  exthandler[exthandlercnt].name[15] = '\0';
3243  exthandler[exthandlercnt++].ptr = newhandler;
3244 
3245  return 0;
3246  }
3247 
3248  myLib.Unload();
3249  return 1;
3250 }
3251 
3252 
3253 int XrdHttpProtocol::LoadCorsHandler(XrdSysError *eDest, const char *libname) {
3254  if(xrdcors) return 1;
3255  XrdOucPinLoader corsLib(eDest, &compiledVer, "corslib",libname);
3257  ep = (XrdHttpCors *(*)(XrdHttpCorsGetHandlerArgs))(corsLib.Resolve("XrdHttpCorsGetHandler"));
3258  if(ep && (xrdcors = ep())) return 0;
3259  corsLib.Unload();
3260  return 1;
3261 }
3262 
3263 // Tells if we have already loaded a certain exthandler. Try to
3264 // privilege speed, as this func may be invoked pretty often
3265 bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3266  for (int i = 0; i < exthandlercnt; i++) {
3267  if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3268  return true;
3269  }
3270  }
3271  return false;
3272 }
3273 
3274 // Locates a matching external handler for a given request, if available. Try to
3275 // privilege speed, as this func is invoked for every incoming request
3276 XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3277 
3278  for (int i = 0; i < exthandlercnt; i++) {
3279  if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3280  return exthandler[i].ptr;
3281  }
3282  }
3283  return NULL;
3284 }
#define kXR_isManager
Definition: XProtocol.hh:1156
kXR_unt16 requestid
Definition: XProtocol.hh:630
kXR_char reserved1[2]
Definition: XProtocol.hh:632
struct ClientSetRequest set
Definition: XProtocol.hh:871
kXR_char reserved[11]
Definition: XProtocol.hh:770
kXR_unt16 infotype
Definition: XProtocol.hh:631
kXR_char reserved2[8]
Definition: XProtocol.hh:634
kXR_char fhandle[4]
Definition: XProtocol.hh:633
@ kXR_query
Definition: XProtocol.hh:113
@ kXR_set
Definition: XProtocol.hh:130
@ kXR_stat
Definition: XProtocol.hh:129
kXR_unt16 requestid
Definition: XProtocol.hh:719
#define kXR_isServer
Definition: XProtocol.hh:1157
struct ClientQueryRequest query
Definition: XProtocol.hh:866
kXR_unt16 requestid
Definition: XProtocol.hh:768
struct ClientStatRequest stat
Definition: XProtocol.hh:873
kXR_int32 dlen
Definition: XProtocol.hh:722
kXR_int32 dlen
Definition: XProtocol.hh:772
kXR_char modifier
Definition: XProtocol.hh:721
@ kXR_Qcksum
Definition: XProtocol.hh:617
kXR_char reserved[15]
Definition: XProtocol.hh:720
int kXR_int32
Definition: XPtypes.hh:89
short kXR_int16
Definition: XPtypes.hh:66
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
static XrdSysError eDest(0,"crypto_")
bool usingEC
#define XrdHttpCorsGetHandlerArgs
Definition: XrdHttpCors.hh:70
#define XrdHttpExtHandlerArgs
int BIO_get_init(BIO *bio)
int BIO_get_shutdown(BIO *bio)
int BIO_get_flags(BIO *bio)
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
void BIO_set_init(BIO *bio, int init)
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
void BIO_set_shutdown(BIO *bio, int shut)
#define TS_Xeq(x, m)
XrdSysTrace XrdHttpTrace("http")
void * BIO_get_data(BIO *bio)
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
void BIO_set_data(BIO *bio, void *ptr)
#define TS_Xeq3(x, m)
static int BIO_XrdLink_destroy(BIO *bio)
#define XRHTTP_TK_GRACETIME
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
void BIO_set_flags(BIO *bio, int flags)
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
Trace definitions.
#define TRACE_AUTH
Definition: XrdHttpTrace.hh:48
#define TRACE_REQ
Definition: XrdHttpTrace.hh:51
#define TRACE_RSP
Definition: XrdHttpTrace.hh:53
#define TRACE_REDIR
Definition: XrdHttpTrace.hh:52
int compareHash(const char *h1, const char *h2)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
std::string httpStatusToString(int status)
Utility functions for XrdHTTP.
std::string decode_str(const std::string &str)
std::string obfuscateAuth(const std::string &input)
int fclose(FILE *stream)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:48
#define fstat(a, b)
Definition: XrdPosix.hh:62
#define open
Definition: XrdPosix.hh:76
#define stat(a, b)
Definition: XrdPosix.hh:101
#define eMsg(x)
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
#define TRACE_DEBUG
Definition: XrdTrace.hh:36
#define TRACE_MEM
Definition: XrdTrace.hh:38
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
void Release(XrdBuffer *bp)
Definition: XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition: XrdBuffer.cc:140
int bsize
Definition: XrdBuffer.hh:46
char * buff
Definition: XrdBuffer.hh:45
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
virtual std::optional< std::string > getCORSAllowOriginHeader(const std::string &origin)=0
virtual int Configure(const char *configFN, XrdSysError *errP)=0
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static char * sslcafile
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static XrdSysError eDest
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static int m_maxdelay
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
static char * sslkey
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
static char * sslcadir
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static XrdHttpCors * xrdcors
static bool compatNameGeneration
static std::string xrdcorsLibPath
static bool allowMissingCRL
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static std::unordered_map< std::string, std::vector< std::pair< std::string, std::string > > > m_staticheader_map
The static headers to always return; map is from verb to a list of (header, val) pairs.
static bool isRequiredGridmap
static char * listredir
Url to redirect to in the case a listing is requested.
int Stats(char *buff, int blen, int do_sync=0)
Get activity stats.
static std::unordered_map< std::string, std::string > m_staticheaders
XrdHttpReq CurrentReq
static int crlRefIntervalSec
CRL thread refresh interval.
static int Port
Our port.
static XrdHttpReadRangeHandler::Configuration ReadRangeConfig
configuration for the read range handler
static XrdSecService * CIA
static XrdBuffManager * BPool
static bool tpcForwardCreds
If set to true, the HTTP TPC transfers will forward the credentials to redirected hosts.
int Process(XrdLink *lp)
Process data incoming from the socket.
XrdHttpProtocol(const XrdHttpProtocol &)=default
Ctor, dtors and copy ctor.
static bool listdeny
If true, any form of listing is denied.
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
XrdSecEntity SecEntity
Authentication area.
static bool embeddedstatic
If true, use the embedded css and icons.
static int sslverifydepth
Depth of verification of a certificate chain.
static int Configure(char *parms, XrdProtocol_Config *pi)
Read and apply the configuration.
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
int reqstate
State machine to talk to the bridge.
Definition: XrdHttpReq.hh:348
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:266
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:274
std::string requestverb
Definition: XrdHttpReq.hh:259
ReqType request
The request we got.
Definition: XrdHttpReq.hh:258
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:854
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:268
long fileflags
Definition: XrdHttpReq.hh:338
long filemodtime
Definition: XrdHttpReq.hh:339
int parseFirstLine(char *line, int len)
Parse the first line of the header.
Definition: XrdHttpReq.cc:265
std::string m_origin
Definition: XrdHttpReq.hh:355
int parseLine(char *line, int len)
Parse the header.
Definition: XrdHttpReq.cc:117
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
Definition: XrdHttpReq.cc:654
long long filesize
Definition: XrdHttpReq.hh:337
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:322
const std::string & userAgent() const
Definition: XrdHttpReq.hh:254
virtual void reset()
Definition: XrdHttpReq.cc:2716
virtual int InitSSL(SSL *, char *)
virtual int FreeSSL(SSL *)
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
void SetDialect(const char *dP)
Definition: XrdNetAddr.hh:205
void SetTLS(bool val)
Definition: XrdNetAddr.cc:590
void Set(int inQMax, time_t agemax=1800)
Definition: XrdObject.icc:90
void Push(XrdObject< T > *Node)
Definition: XrdObject.hh:101
T * Pop()
Definition: XrdObject.hh:93
void PutInt(const char *varname, long value)
Definition: XrdOucEnv.cc:268
static bool Import(const char *var, char *&val)
Definition: XrdOucEnv.cc:222
void * GetPtr(const char *varname)
Definition: XrdOucEnv.cc:281
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
int length() const
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition: XrdOuca2x.cc:288
XrdBuffManager * BPool
Definition: XrdProtocol.hh:63
XrdScheduler * Sched
Definition: XrdProtocol.hh:64
XrdTlsContext * tlsCtx
Definition: XrdProtocol.hh:99
XrdSysError * eDest
Definition: XrdProtocol.hh:61
XrdOucEnv * theEnv
Definition: XrdProtocol.hh:66
char * vorg
Entity's virtual organization(s)
Definition: XrdSecEntity.hh:71
int credslen
Length of the 'creds' data.
Definition: XrdSecEntity.hh:78
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
const char * tident
Trace identifier always preset.
Definition: XrdSecEntity.hh:81
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * caps
Entity's capabilities.
Definition: XrdSecEntity.hh:74
char * creds
Raw entity credentials or cert.
Definition: XrdSecEntity.hh:77
char * grps
Entity's group name(s)
Definition: XrdSecEntity.hh:73
void Reset(const char *spV=0)
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * role
Entity's role(s)
Definition: XrdSecEntity.hh:72
char * endorsements
Protocol specific endorsements.
Definition: XrdSecEntity.hh:75
void Display(XrdSysError &mDest)
Definition: XrdSecEntity.cc:58
char * moninfo
Information for monitoring.
Definition: XrdSecEntity.hh:76
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
void SetLogger(XrdSysLogger *logp)
Definition: XrdSysTrace.cc:65
int SessionCache(int opts=scNone, const char *id=0, int idlen=0)
static const int DEFAULT_CRL_REF_INT_SEC
Default CRL refresh interval in seconds.
static const uint64_t servr
This is a server context.
static const uint64_t rfCRL
Turn on the CRL refresh thread.
static const uint64_t logVF
Log verify failures.
static const uint64_t artON
Auto retry Handshake.
const CTX_Params * GetParams()
static const int scOff
Turn off cache.
bool SetContextCiphers(const char *ciphers)
static const uint64_t crlAM
Allow CA validation when CRL is missing (CRL soft-fail)
static const int scSrvr
Turn on cache server mode (default)
void SetTlsClientAuth(bool setting)
static Bridge * Login(Result *rsltP, XrdLink *linkP, XrdSecEntity *seceP, const char *nameP, const char *protP)
virtual bool Run(const char *xreqP, char *xdataP=0, int xdataL=0)=0
virtual void SetWait(int wtime, bool notify=false)=0
bool InitTLS()
Definition: XrdClTls.cc:96
CloseImpl< false > Close(Ctx< File > file, uint16_t timeout=0)
Factory for creating CloseImpl objects.
XrdCmsConfig Config
static const int hsmOff
static const int hsmMan
static const int hsmOn
static const int hsmAuto
XrdTlsContext * xrdctx
@ dec
Definition: XrdSysTrace.hh:42
@ hex
Definition: XrdSysTrace.hh:42
std::string cafile
-> ca cert file.
uint64_t opts
Options as passed to the constructor.
std::string cadir
-> ca cert directory.
int crlRT
crl refresh interval time in seconds
std::string pkey
-> private key path.
std::string cert
-> certificate path.