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