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  return -1;
872  }
873 
874  } else {
875  // Client is plain http. If we have a secret key then we reject it
876  if (secretkey) {
877  TRACEI(ALL, " Rejecting plain http with no valid token as we have a secretkey.");
878  return -1;
879  }
880  }
881 
882  } else {
883  // Client is plain http. If we have a secret key then we reject it
884  if (secretkey) {
885  TRACEI(ALL, " Rejecting plain http with no valid token as we have a secretkey.");
886  return -1;
887  }
888  }
889 
890  ssldone = true;
891  }
892 
893 
894 
895  // Now we have everything that is needed to try the login
896  // Remember that if there is an exthandler then it has the responsibility
897  // for authorization in the paths that it manages
898  if (!Bridge && !FindMatchingExtHandler(CurrentReq)) {
899  if (SecEntity.name)
900  Bridge = XrdXrootd::Bridge::Login(&CurrentReq, Link, &SecEntity, SecEntity.name, ishttps ? "https" : "http");
901  else
902  Bridge = XrdXrootd::Bridge::Login(&CurrentReq, Link, &SecEntity, "unknown", ishttps ? "https" : "http");
903 
904  if (!Bridge) {
905  TRACEI(REQ, " Authorization failed.");
906  return -1;
907  }
908  if (m_maxdelay > 0) Bridge->SetWait(m_maxdelay, false);
909 
910  // Let the bridge process the login, and then reinvoke us
911  DoingLogin = true;
912  return 0;
913  }
914 
915  // Compute and send the response. This may involve further reading from the socket
916  rc = CurrentReq.ProcessHTTPReq();
917  if (rc < 0)
918  CurrentReq.reset();
919 
920 
921 
922  TRACEI(REQ, "Process is exiting rc:" << rc);
923  return rc;
924 }
925 /******************************************************************************/
926 /* R e c y c l e */
927 /******************************************************************************/
928 
929 #undef TRACELINK
930 #define TRACELINK Link
931 
932 void XrdHttpProtocol::Recycle(XrdLink *lp, int csec, const char *reason) {
933 
934  // Release all appendages
935  //
936 
937  Cleanup();
938 
939 
940  // Set fields to starting point (debugging mostly)
941  //
942  Reset();
943 
944  // Push ourselves on the stack
945  //
947 }
948 
949 int XrdHttpProtocol::Stats(char *buff, int blen, int do_sync) {
950  // Synchronize statistics if need be
951  //
952  // if (do_sync) {
953  //
954  // SI->statsMutex.Lock();
955  // SI->readCnt += numReads;
956  // cumReads += numReads;
957  // numReads = 0;
958  // SI->prerCnt += numReadP;
959  // cumReadP += numReadP;
960  // numReadP = 0;
961  // SI->rvecCnt += numReadV;
962  // cumReadV += numReadV;
963  // numReadV = 0;
964  // SI->rsegCnt += numSegsV;
965  // cumSegsV += numSegsV;
966  // numSegsV = 0;
967  // SI->writeCnt += numWrites;
968  // cumWrites += numWrites;
969  // numWrites = 0;
970  // SI->statsMutex.UnLock();
971  // }
972  //
973  // // Now return the statistics
974  // //
975  // return SI->Stats(buff, blen, do_sync);
976 
977  return 0;
978 }
979 
980 /******************************************************************************/
981 /* C o n f i g */
982 /******************************************************************************/
983 
984 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
985 //#define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, ConfigFN, myEnv)
986 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
987 
988 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
989  if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
990  eDest.Say("Config http." x " overrides the xrd." y " directive.")
991 
992 int XrdHttpProtocol::Config(const char *ConfigFN, XrdOucEnv *myEnv) {
993  XrdOucEnv cfgEnv;
994  XrdOucStream Config(&eDest, getenv("XRDINSTANCE"), &cfgEnv, "=====> ");
995  std::vector<extHInfo> extHIVec;
996  char *var;
997  int cfgFD, GoNo, NoGo = 0, ismine;
998 
999  var = nullptr;
1000  XrdOucEnv::Import("XRD_READV_LIMITS", var);
1002 
1003  pmarkHandle = (XrdNetPMark* ) myEnv->GetPtr("XrdNetPMark*");
1004 
1006  auto nonIanaChecksums = cksumHandler.getNonIANAConfiguredCksums();
1007  if(nonIanaChecksums.size()) {
1008  std::stringstream warningMsgSS;
1009  warningMsgSS << "Config warning: the following checksum algorithms are not IANA compliant: [";
1010  std::string unknownCksumString;
1011  for(auto unknownCksum: nonIanaChecksums) {
1012  unknownCksumString += unknownCksum + ",";
1013  }
1014  unknownCksumString.erase(unknownCksumString.size() - 1);
1015  warningMsgSS << unknownCksumString << "]" << ". They therefore cannot be queried by a user via HTTP." ;
1016  eDest.Say(warningMsgSS.str().c_str());
1017  }
1018 
1019  // Initialize our custom BIO type.
1020  if (!m_bio_type) {
1021 
1022  #if OPENSSL_VERSION_NUMBER < 0x10100000L
1023  m_bio_type = (26|0x0400|0x0100);
1024  m_bio_method = static_cast<BIO_METHOD*>(OPENSSL_malloc(sizeof(BIO_METHOD)));
1025 
1026  if (m_bio_method) {
1027  memset(m_bio_method, '\0', sizeof(BIO_METHOD));
1028  m_bio_method->type = m_bio_type;
1029  m_bio_method->bwrite = BIO_XrdLink_write;
1030  m_bio_method->bread = BIO_XrdLink_read;
1031  m_bio_method->create = BIO_XrdLink_create;
1032  m_bio_method->destroy = BIO_XrdLink_destroy;
1034  }
1035  #else
1036  // OpenSSL 1.1 has an internal counter for generating unique types.
1037  // We'll switch to that when widely available.
1038  m_bio_type = BIO_get_new_index();
1039  m_bio_method = BIO_meth_new(m_bio_type, "xrdhttp-bio-method");
1040 
1041  if (m_bio_method) {
1042  BIO_meth_set_write(m_bio_method, BIO_XrdLink_write);
1043  BIO_meth_set_read(m_bio_method, BIO_XrdLink_read);
1044  BIO_meth_set_create(m_bio_method, BIO_XrdLink_create);
1045  BIO_meth_set_destroy(m_bio_method, BIO_XrdLink_destroy);
1046  BIO_meth_set_ctrl(m_bio_method, BIO_XrdLink_ctrl);
1047  }
1048 
1049  #endif
1050  }
1051 
1052  // If we have a tls context record whether it configured for verification
1053  // so that we can provide meaningful error and warning messages.
1054  //
1056 
1057  // Open and attach the config file
1058  //
1059  if ((cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
1060  return eDest.Emsg("Config", errno, "open config file", ConfigFN);
1061  Config.Attach(cfgFD);
1062  static const char *cvec[] = { "*** http protocol config:", 0 };
1063  Config.Capture(cvec);
1064 
1065  // Process items
1066  //
1067  while ((var = Config.GetMyFirstWord())) {
1068  if ((ismine = !strncmp("http.", var, 5)) && var[5]) var += 5;
1069 
1070  if (ismine) {
1071  if TS_Xeq("trace", xtrace);
1072  else if TS_Xeq("cert", xsslcert);
1073  else if TS_Xeq("key", xsslkey);
1074  else if TS_Xeq("cadir", xsslcadir);
1075  else if TS_Xeq("cipherfilter", xsslcipherfilter);
1076  else if TS_Xeq("gridmap", xgmap);
1077  else if TS_Xeq("cafile", xsslcafile);
1078  else if TS_Xeq("secretkey", xsecretkey);
1079  else if TS_Xeq("desthttps", xdesthttps);
1080  else if TS_Xeq("secxtractor", xsecxtractor);
1081  else if TS_Xeq("cors", xcors);
1082  else if TS_Xeq3("exthandler", xexthandler);
1083  else if TS_Xeq("selfhttps2http", xselfhttps2http);
1084  else if TS_Xeq("embeddedstatic", xembeddedstatic);
1085  else if TS_Xeq("listingredir", xlistredir);
1086  else if TS_Xeq("staticredir", xstaticredir);
1087  else if TS_Xeq("staticpreload", xstaticpreload);
1088  else if TS_Xeq("staticheader", xstaticheader);
1089  else if TS_Xeq("listingdeny", xlistdeny);
1090  else if TS_Xeq("header2cgi", xheader2cgi);
1091  else if TS_Xeq("httpsmode", xhttpsmode);
1092  else if TS_Xeq("tlsreuse", xtlsreuse);
1093  else if TS_Xeq("auth", xauth);
1094  else if TS_Xeq("tlsclientauth", xtlsclientauth);
1095  else if TS_Xeq("maxdelay", xmaxdelay);
1096  else {
1097  eDest.Say("Config warning: ignoring unknown directive '", var, "'.");
1098  Config.Echo();
1099  continue;
1100  }
1101  if (GoNo) {
1102  Config.Echo();
1103  NoGo = 1;
1104  }
1105  }
1106  }
1107 
1108 // To minimize message confusion down, if an error occurred during config
1109 // parsing, just bail out now with a confirming message.
1110 //
1111  if (NoGo)
1112  {eDest.Say("Config failure: one or more directives are flawed!");
1113  return 1;
1114  }
1115 
1116 // Some headers must always be converted to CGI key=value pairs
1117 //
1118  hdr2cgimap["Cache-Control"] = "cache-control";
1119 
1120 // Test if XrdEC is loaded
1121  if (getenv("XRDCL_EC")) usingEC = true;
1122 
1123 // Pre-compute the static headers
1124 //
1125  const auto default_verb = m_staticheader_map.find("");
1126  std::string default_static_headers;
1127  if (default_verb != m_staticheader_map.end()) {
1128  for (const auto &header_entry : default_verb->second) {
1129  default_static_headers += header_entry.first + ": " + header_entry.second + "\r\n";
1130  }
1131  }
1132  m_staticheaders[""] = default_static_headers;
1133  for (const auto &item : m_staticheader_map) {
1134  if (item.first.empty()) {
1135  continue; // Skip default case; already handled
1136  }
1137  auto headers = default_static_headers;
1138  for (const auto &header_entry : item.second) {
1139  headers += header_entry.first + ": " + header_entry.second + "\r\n";
1140  }
1141 
1142  m_staticheaders[item.first] = headers;
1143  }
1144 
1145 // Test if this is a caching server
1146 //
1147  if (myEnv->Get("XrdCache")) hasCache = true;
1148 
1149  // Load CORS plugin if configured
1150  if(xrdcorsLibPath.size()) {
1151  if(LoadCorsHandler(&eDest, xrdcorsLibPath.c_str()) != 0) {
1152  return 1;
1153  }
1154  if (xrdcors->Configure(ConfigFN, &eDest) != 0) {
1155  return 1;
1156  }
1157  }
1158 
1159 // If https was disabled, then issue a warning message if xrdtls configured
1160 // of it's disabled because httpsmode was auto and xrdtls was not configured.
1161 // If we get past this point then we know https is a plausible option but we
1162 // can still fail if we cannot supply any missing but required options.
1163 //
1164  if (httpsmode == hsmOff || (httpsmode == hsmAuto && !xrdctx && !httpsspec))
1165  {const char *why = (httpsmode == hsmOff ? "has been disabled!"
1166  : "was not configured.");
1167  const char *what = Configed();
1168 
1169  eDest.Say("Config warning: HTTPS functionality ", why);
1170  httpsmode = hsmOff;
1171 
1172  LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1173  if (what)
1174  {eDest.Say("Config failure: ", what, " HTTPS but it ", why);
1175  NoGo = 1;
1176  }
1177  return NoGo;
1178  }
1179 
1180 // Warn if a private key was specified without a cert as this has no meaning
1181 // even as an auto overide as they must be paired.
1182 //
1183  if (sslkey && !sslcert)
1184  {eDest.Say("Config warning: specifying http.key without http.cert "
1185  "is meaningless; ignoring key!");
1186  free(sslkey); sslkey = 0;
1187  }
1188 
1189 // If the mode is manual then we need to have at least a cert.
1190 //
1191  if (httpsmode == hsmMan)
1192  {if (!sslcert)
1193  {eDest.Say("Config failure: 'httpsmode manual' requires atleast a "
1194  "a cert specification!");
1195  return 1;
1196  }
1197  }
1198 
1199 // If it's auto d through all possibilities. It's either auto with xrdtls
1200 // configured or manual which needs at least a cert specification. For auto
1201 // configuration we will only issue a warning if overrides were specified.
1202 //
1203  if (httpsmode == hsmAuto && xrdctx)
1204  {const XrdTlsContext::CTX_Params *cP = xrdctx->GetParams();
1205  const char *what1 = 0, *what2 = 0, *what3 = 0;
1206 
1207  if (!sslcert && cP->cert.size())
1208  {sslcert = strdup(cP->cert.c_str());
1209  if (cP->pkey.size()) sslkey = strdup(cP->pkey.c_str());
1210  what1 = "xrd.tls to supply 'cert' and 'key'.";
1211  }
1212  if (!sslcadir && cP->cadir.size())
1213  {sslcadir = strdup(cP->cadir.c_str());
1214  what2 = "xrd.tlsca to supply 'cadir'.";
1215  }
1216  if (!sslcafile && cP->cafile.size())
1217  {sslcafile = strdup(cP->cafile.c_str());
1218  what2 = (what2 ? "xrd.tlsca to supply 'cadir' and 'cafile'."
1219  : "xrd.tlsca to supply 'cafile'.");
1220  }
1222  crlRefIntervalSec = cP->crlRT;
1223  what3 = "xrd.tlsca to supply 'refresh' interval.";
1224  }
1225  if (!httpsspec && what1) eDest.Say("Config Using ", what1);
1226  if (!httpsspec && what2) eDest.Say("Config Using ", what2);
1227  if (!httpsspec && what3) eDest.Say("Config Using ", what3);
1228  }
1229 
1230 // If a gridmap or secxtractor is present then we must be able to verify certs
1231 //
1232  if (!(sslcadir || sslcafile))
1233  {const char *what = Configed();
1234  const char *why = (httpsspec ? "a cadir or cafile was not specified!"
1235  : "'xrd.tlsca noverify' was specified!");
1236  if (what)
1237  {eDest.Say("Config failure: ", what, " cert verification but ", why);
1238  return 1;
1239  }
1240  }
1241  httpsmode = hsmOn;
1242 
1243 // Oddly we need to create an error bio at this point
1244 //
1245  sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1246 
1247 // Now we can configure HTTPS. We will not reuse the passed context as we will
1248 // be setting our own options specific to out implementation. One day we will.
1249 //
1250  const char *how = "completed.";
1251  eDest.Say("++++++ HTTPS initialization started.");
1252  if (!InitTLS()) {NoGo = 1; how = "failed.";}
1253  eDest.Say("------ HTTPS initialization ", how);
1254  if (NoGo) return NoGo;
1255 
1256 // We can now load all the external handlers
1257 //
1258  if (LoadExtHandler(extHIVec, ConfigFN, *myEnv)) return 1;
1259 
1260 // At this point, we can actually initialize security plugins
1261 //
1262  return (InitSecurity() ? NoGo : 1);
1263 }
1264 
1265 /******************************************************************************/
1266 /* C o n f i g e d */
1267 /******************************************************************************/
1268 
1269 const char *XrdHttpProtocol::Configed()
1270 {
1271  if (secxtractor && gridmap) return "gridmap and secxtractor require";
1272  if (secxtractor) return "secxtractor requires";
1273  if (gridmap) return "gridmap requires";
1274  return 0;
1275 }
1276 
1277 /******************************************************************************/
1278 /* B u f f g e t L i n e */
1279 /******************************************************************************/
1280 
1282 
1283 int XrdHttpProtocol::BuffgetLine(XrdOucString &dest) {
1284 
1285  dest = "";
1286  char save;
1287 
1288  // Easy case
1289  if (myBuffEnd >= myBuffStart) {
1290  int l = 0;
1291  for (char *p = myBuffStart; p < myBuffEnd; p++) {
1292  l++;
1293  if (*p == '\n') {
1294  save = *(p+1);
1295  *(p+1) = '\0';
1296  dest.assign(myBuffStart, 0, l-1);
1297  *(p+1) = save;
1298 
1299  //strncpy(dest, myBuffStart, l);
1300  //dest[l] = '\0';
1301  BuffConsume(l);
1302 
1303  //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1304  return l;
1305  }
1306 
1307  }
1308 
1309  return 0;
1310  } else {
1311  // More complex case... we have to do it in two segments
1312 
1313  // Segment 1: myBuffStart->myBuff->buff+myBuff->bsize
1314  int l = 0;
1315  for (char *p = myBuffStart; p < myBuff->buff + myBuff->bsize; p++) {
1316  l++;
1317  if ((*p == '\n') || (*p == '\0')) {
1318  save = *(p+1);
1319  *(p+1) = '\0';
1320  dest.assign(myBuffStart, 0, l-1);
1321  *(p+1) = save;
1322 
1323  //strncpy(dest, myBuffStart, l);
1324 
1325  BuffConsume(l);
1326 
1327  //if (dest[l-1] == '\n') dest[l - 1] = '\0';
1328  return l;
1329  }
1330 
1331  }
1332 
1333  // We did not find the \n, let's keep on searching in the 2nd segment
1334  // Segment 2: myBuff->buff --> myBuffEnd
1335  l = 0;
1336  for (char *p = myBuff->buff; p < myBuffEnd; p++) {
1337  l++;
1338  if ((*p == '\n') || (*p == '\0')) {
1339  save = *(p+1);
1340  *(p+1) = '\0';
1341  // Remember the 1st segment
1342  int l1 = myBuff->buff + myBuff->bsize - myBuffStart;
1343 
1344  dest.assign(myBuffStart, 0, l1-1);
1345  //strncpy(dest, myBuffStart, l1);
1346  BuffConsume(l1);
1347 
1348  dest.insert(myBuffStart, l1, l-1);
1349  //strncpy(dest + l1, myBuffStart, l);
1350  //dest[l + l1] = '\0';
1351  BuffConsume(l);
1352 
1353  *(p+1) = save;
1354 
1355  //if (dest[l + l1 - 1] == '\n') dest[l + l1 - 1] = '\0';
1356  return l + l1;
1357  }
1358 
1359  }
1360 
1361 
1362 
1363  }
1364 
1365  return 0;
1366 }
1367 
1368 /******************************************************************************/
1369 /* g e t D a t a O n e S h o t */
1370 /******************************************************************************/
1371 
1372 int XrdHttpProtocol::getDataOneShot(int blen, bool wait) {
1373  int rlen, maxread;
1374 
1375  // Get up to blen bytes from the connection. Put them into mybuff.
1376  // This primitive, for the way it is used, is not supposed to block if wait=false
1377 
1378  // Returns:
1379  // 2: no space left in buffer
1380  // 1: timeout
1381  // -1: error
1382  // 0: everything read correctly
1383 
1384 
1385 
1386  // Check for buffer overflow first
1387  maxread = std::min(blen, BuffAvailable());
1388  TRACE(DEBUG, "getDataOneShot BuffAvailable: " << BuffAvailable() << " maxread: " << maxread);
1389 
1390  if (!maxread)
1391  return 2;
1392 
1393  if (ishttps) {
1394  int sslavail = maxread;
1395 
1396  if (!wait) {
1397  int l = SSL_pending(ssl);
1398  if (l > 0)
1399  sslavail = std::min(maxread, SSL_pending(ssl));
1400  }
1401 
1402  if (sslavail < 0) {
1403  Link->setEtext("link SSL_pending error");
1404  ERR_print_errors(sslbio_err);
1405  return -1;
1406  }
1407 
1408  TRACE(DEBUG, "getDataOneShot sslavail: " << sslavail);
1409  if (sslavail <= 0) return 0;
1410 
1411  if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1412  TRACE(DEBUG, "getDataOneShot Buffer panic");
1413  myBuffEnd = myBuff->buff;
1414  }
1415 
1416  rlen = SSL_read(ssl, myBuffEnd, sslavail);
1417  if (rlen <= 0) {
1418  Link->setEtext("link SSL read error");
1419  ERR_print_errors(sslbio_err);
1420  return -1;
1421  }
1422 
1423 
1424  } else {
1425 
1426  if (myBuffEnd - myBuff->buff >= myBuff->bsize) {
1427  TRACE(DEBUG, "getDataOneShot Buffer panic");
1428  myBuffEnd = myBuff->buff;
1429  }
1430 
1431  if (wait)
1432  rlen = Link->Recv(myBuffEnd, maxread, readWait);
1433  else
1434  rlen = Link->Recv(myBuffEnd, maxread);
1435 
1436 
1437  if (rlen == 0) {
1438  Link->setEtext("link read error or closed");
1439  return -1;
1440  }
1441 
1442  if (rlen < 0) {
1443  Link->setEtext("link timeout or other error");
1444  return -1;
1445  }
1446  }
1447 
1448  myBuffEnd += rlen;
1449 
1450  TRACE(REQ, "read " << rlen << " of " << blen << " bytes");
1451 
1452  return 0;
1453 }
1454 
1456 
1457 int XrdHttpProtocol::BuffAvailable() {
1458  int r;
1459 
1460  if (myBuffEnd >= myBuffStart)
1461  r = myBuff->buff + myBuff->bsize - myBuffEnd;
1462  else
1463  r = myBuffStart - myBuffEnd;
1464 
1465  if ((r < 0) || (r > myBuff->bsize)) {
1466  TRACE(REQ, "internal error, myBuffAvailable: " << r << " myBuff->bsize " << myBuff->bsize);
1467  abort();
1468  }
1469 
1470  return r;
1471 }
1472 
1473 /******************************************************************************/
1474 /* B u f f U s e d */
1475 /******************************************************************************/
1476 
1478 
1479 int XrdHttpProtocol::BuffUsed() {
1480  int r;
1481 
1482  if (myBuffEnd >= myBuffStart)
1483  r = myBuffEnd - myBuffStart;
1484  else
1485 
1486  r = myBuff->bsize - (myBuffStart - myBuffEnd);
1487 
1488  if ((r < 0) || (r > myBuff->bsize)) {
1489  TRACE(REQ, "internal error, myBuffUsed: " << r << " myBuff->bsize " << myBuff->bsize);
1490  abort();
1491  }
1492 
1493  return r;
1494 }
1495 
1496 /******************************************************************************/
1497 /* B u f f F r e e */
1498 /******************************************************************************/
1499 
1501 
1502 int XrdHttpProtocol::BuffFree() {
1503  return (myBuff->bsize - BuffUsed());
1504 }
1505 
1506 /******************************************************************************/
1507 /* B u f f C o n s u m e */
1508 /******************************************************************************/
1509 
1510 void XrdHttpProtocol::BuffConsume(int blen) {
1511 
1512  if (blen > myBuff->bsize) {
1513  TRACE(REQ, "internal error, BuffConsume(" << blen << ") smaller than buffsize");
1514  abort();
1515  }
1516 
1517  if (blen > BuffUsed()) {
1518  TRACE(REQ, "internal error, BuffConsume(" << blen << ") larger than BuffUsed:" << BuffUsed());
1519  abort();
1520  }
1521 
1522  myBuffStart = myBuffStart + blen;
1523 
1524  if (myBuffStart >= myBuff->buff + myBuff->bsize)
1525  myBuffStart -= myBuff->bsize;
1526 
1527  if (myBuffEnd >= myBuff->buff + myBuff->bsize)
1528  myBuffEnd -= myBuff->bsize;
1529 
1530  if (BuffUsed() == 0)
1531  myBuffStart = myBuffEnd = myBuff->buff;
1532 }
1533 
1534 /******************************************************************************/
1535 /* B u f f g e t D a t a */
1536 /******************************************************************************/
1537 
1546 int XrdHttpProtocol::BuffgetData(int blen, char **data, bool wait) {
1547  int rlen;
1548 
1549  TRACE(DEBUG, "BuffgetData: requested " << blen << " bytes");
1550 
1551 
1552  if (wait) {
1553  // If there's not enough data in the buffer then wait on the socket until it comes
1554  if (blen > BuffUsed()) {
1555  TRACE(REQ, "BuffgetData: need to read " << blen - BuffUsed() << " bytes");
1556  if ( getDataOneShot(blen - BuffUsed(), true) )
1557  // The wanted data could not be read. Either timeout of connection closed
1558  return 0;
1559  }
1560  } else {
1561  // Get a peek at the socket, without waiting, if we have no data in the buffer
1562  if ( !BuffUsed() ) {
1563  if ( getDataOneShot(blen, false) )
1564  // The wanted data could not be read. Either timeout of connection closed
1565  return -1;
1566  }
1567  }
1568 
1569  // And now make available the data taken from the buffer. Note that the buffer
1570  // may be empty...
1571  if (myBuffStart <= myBuffEnd) {
1572  rlen = std::min( (long) blen, (long)(myBuffEnd - myBuffStart) );
1573 
1574  } else
1575  rlen = std::min( (long) blen, (long)(myBuff->buff + myBuff->bsize - myBuffStart) );
1576 
1577  *data = myBuffStart;
1578  BuffConsume(rlen);
1579  return rlen;
1580 }
1581 
1582 /******************************************************************************/
1583 /* S e n d D a t a */
1584 /******************************************************************************/
1585 
1587 
1588 int XrdHttpProtocol::SendData(const char *body, int bodylen) {
1589 
1590  int r;
1591 
1592  if (body && bodylen) {
1593  TRACE(REQ, "Sending " << bodylen << " bytes");
1594  if (ishttps) {
1595  r = SSL_write(ssl, body, bodylen);
1596  if (r <= 0) {
1597  ERR_print_errors(sslbio_err);
1598  return -1;
1599  }
1600 
1601  } else {
1602  r = Link->Send(body, bodylen);
1603  if (r <= 0) return -1;
1604  }
1605  }
1606 
1607  return 0;
1608 }
1609 
1610 /******************************************************************************/
1611 /* S t a r t S i m p l e R e s p */
1612 /******************************************************************************/
1613 
1614 int XrdHttpProtocol::StartSimpleResp(int code, const char *desc,
1615  const char *header_to_add,
1616  long long bodylen, bool keepalive) {
1617  std::stringstream ss;
1618  const std::string crlf = "\r\n";
1619 
1620  ss << "HTTP/1.1 " << code << " ";
1621 
1622  if (desc) {
1623  ss << desc;
1624  } else {
1625  ss << httpStatusToString(code);
1626  }
1627  ss << crlf;
1628 
1629  if (keepalive && (code != 100))
1630  ss << "Connection: Keep-Alive" << crlf;
1631  else
1632  ss << "Connection: Close" << crlf;
1633 
1634  ss << "Server: XrootD/" << XrdVSTRING << crlf;
1635 
1636  const auto iter = m_staticheaders.find(CurrentReq.requestverb);
1637  if (iter != m_staticheaders.end()) {
1638  ss << iter->second;
1639  } else {
1640  ss << m_staticheaders[""];
1641  }
1642 
1643  if(xrdcors) {
1644  auto corsAllowOrigin = xrdcors->getCORSAllowOriginHeader(CurrentReq.m_origin);
1645  if(corsAllowOrigin) {
1646  ss << *corsAllowOrigin << crlf;
1647  }
1648  }
1649 
1650  if ((bodylen >= 0) && (code != 100))
1651  ss << "Content-Length: " << bodylen << crlf;
1652 
1653  if (header_to_add && (header_to_add[0] != '\0')) ss << header_to_add << crlf;
1654 
1655  ss << crlf;
1656 
1657  const std::string &outhdr = ss.str();
1658  TRACEI(RSP, "Sending resp: " << code << " header len:" << outhdr.size());
1659  if (SendData(outhdr.c_str(), outhdr.size()))
1660  return -1;
1661 
1662  return 0;
1663 }
1664 
1665 /******************************************************************************/
1666 /* S t a r t C h u n k e d R e s p */
1667 /******************************************************************************/
1668 
1669 int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1670  const std::string crlf = "\r\n";
1671  std::stringstream ss;
1672 
1673  if (header_to_add && (header_to_add[0] != '\0')) {
1674  ss << header_to_add << crlf;
1675  }
1676 
1677  ss << "Transfer-Encoding: chunked";
1678  TRACEI(RSP, "Starting chunked response");
1679  return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1680 }
1681 
1682 /******************************************************************************/
1683 /* C h u n k R e s p */
1684 /******************************************************************************/
1685 
1686 int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1687  long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1688  if (ChunkRespHeader(content_length))
1689  return -1;
1690 
1691  if (body && SendData(body, content_length))
1692  return -1;
1693 
1694  return ChunkRespFooter();
1695 }
1696 
1697 /******************************************************************************/
1698 /* C h u n k R e s p H e a d e r */
1699 /******************************************************************************/
1700 
1701 int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1702  const std::string crlf = "\r\n";
1703  std::stringstream ss;
1704 
1705  ss << std::hex << bodylen << std::dec << crlf;
1706 
1707  const std::string &chunkhdr = ss.str();
1708  TRACEI(RSP, "Sending encoded chunk of size " << bodylen);
1709  return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1710 }
1711 
1712 /******************************************************************************/
1713 /* C h u n k R e s p F o o t e r */
1714 /******************************************************************************/
1715 
1716 int XrdHttpProtocol::ChunkRespFooter() {
1717  const std::string crlf = "\r\n";
1718  return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1719 }
1720 
1721 /******************************************************************************/
1722 /* S e n d S i m p l e R e s p */
1723 /******************************************************************************/
1724 
1728 
1729 int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1730 
1731  long long content_length = bodylen;
1732  if (bodylen <= 0) {
1733  content_length = body ? strlen(body) : 0;
1734  }
1735 
1736  if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1737  return -1;
1738 
1739  //
1740  // Send the data
1741  //
1742  if (body)
1743  return SendData(body, content_length);
1744 
1745  return 0;
1746 }
1747 
1748 /******************************************************************************/
1749 /* C o n f i g u r e */
1750 /******************************************************************************/
1751 
1753  /*
1754  Function: Establish configuration at load time.
1755 
1756  Input: None.
1757 
1758  Output: 0 upon success or !0 otherwise.
1759  */
1760 
1761  char *rdf;
1762 
1763  // Copy out the special info we want to use at top level
1764  //
1765  eDest.logger(pi->eDest->logger());
1767  // SI = new XrdXrootdStats(pi->Stats);
1768  Sched = pi->Sched;
1769  BPool = pi->BPool;
1770  xrd_cslist = getenv("XRD_CSLIST");
1771 
1772  Port = pi->Port;
1773 
1774  // Copy out the current TLS context
1775  //
1776  xrdctx = pi->tlsCtx;
1777 
1778  {
1779  char buf[16];
1780  sprintf(buf, "%d", Port);
1781  Port_str = strdup(buf);
1782  }
1783 
1784  // Now process and configuration parameters
1785  //
1786  rdf = (parms && *parms ? parms : pi->ConfigFN);
1787  if (rdf && Config(rdf, pi->theEnv)) return 0;
1788  if (pi->DebugON) XrdHttpTrace.What = TRACE_ALL;
1789 
1790  // Set the redirect flag if we are a pure redirector
1791  myRole = kXR_isServer;
1792  if ((rdf = getenv("XRDROLE"))) {
1793  eDest.Emsg("Config", "XRDROLE: ", rdf);
1794 
1795  if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1797  eDest.Emsg("Config", "Configured as HTTP(s) redirector.");
1798  } else {
1799 
1800  eDest.Emsg("Config", "Configured as HTTP(s) data server.");
1801  }
1802 
1803  } else {
1804  eDest.Emsg("Config", "No XRDROLE specified.");
1805  }
1806 
1807  // Schedule protocol object cleanup
1808  //
1810  (XrdHttpTrace.What & TRACE_MEM ? TRACE_MEM : 0));
1811  ProtStack.Set((pi->ConnMax / 3 ? pi->ConnMax / 3 : 30), 60 * 60);
1812 
1813  // Return success
1814  //
1815 
1816  return 1;
1817 }
1818 
1819 /******************************************************************************/
1820 /* p a r s e H e a d e r 2 C G I */
1821 /******************************************************************************/
1822 int XrdHttpProtocol::parseHeader2CGI(XrdOucStream &Config, XrdSysError & err,std::map<std::string, std::string> &header2cgi) {
1823  char *val, keybuf[1024], parmbuf[1024];
1824  char *parm;
1825 
1826  // Get the header key
1827  val = Config.GetWord();
1828  if (!val || !val[0]) {
1829  err.Emsg("Config", "No headerkey specified.");
1830  return 1;
1831  } else {
1832 
1833  // Trim the beginning, in place
1834  while ( *val && !isalnum(*val) ) val++;
1835  strcpy(keybuf, val);
1836 
1837  // Trim the end, in place
1838  char *pp;
1839  pp = keybuf + strlen(keybuf) - 1;
1840  while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1841  *pp = '\0';
1842  pp--;
1843  }
1844 
1845  parm = Config.GetWord();
1846 
1847  // Avoids segfault in case a key is given without value
1848  if(!parm || !parm[0]) {
1849  err.Emsg("Config", "No header2cgi value specified. key: '", keybuf, "'");
1850  return 1;
1851  }
1852 
1853  // Trim the beginning, in place
1854  while ( *parm && !isalnum(*parm) ) parm++;
1855  strcpy(parmbuf, parm);
1856 
1857  // Trim the end, in place
1858  pp = parmbuf + strlen(parmbuf) - 1;
1859  while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1860  *pp = '\0';
1861  pp--;
1862  }
1863 
1864  // Add this mapping to the map that will be used
1865  try {
1866  header2cgi[keybuf] = parmbuf;
1867  } catch ( ... ) {
1868  err.Emsg("Config", "Can't insert new header2cgi rule. key: '", keybuf, "'");
1869  return 1;
1870  }
1871 
1872  }
1873  return 0;
1874 }
1875 
1876 
1877 /******************************************************************************/
1878 /* I n i t T L S */
1879 /******************************************************************************/
1880 
1881 bool XrdHttpProtocol::InitTLS() {
1882 
1883  std::string eMsg;
1886 
1887 // Create a new TLS context
1888 //
1889  if (sslverifydepth > 255) sslverifydepth = 255;
1891  //TLS_SET_REFINT will set the refresh interval in minutes, hence the division by 60
1894 
1895 // Make sure the context was created
1896 //
1897  if (!xrdctx->isOK())
1898  {eDest.Say("Config failure: ", eMsg.c_str());
1899  return false;
1900  }
1901 
1902 // Setup session cache (this is controversial). The default is off but many
1903 // programs expect it being enabled and break when it is disabled. In such
1904 // cases it should be enabled. This is, of course, a big OpenSSL mess.
1905 //
1906  static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1907  unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1908  xrdctx->SessionCache(tlsCache, sess_ctx_id, n);
1909 
1910 // Set special ciphers if so specified.
1911 //
1913  {eDest.Say("Config failure: ", "Unable to set allowable https ciphers!");
1914  return false;
1915  }
1916 
1917 // Enable or disable the config in the context
1919 
1920 // All done
1921 //
1922  return true;
1923 }
1924 
1925 /******************************************************************************/
1926 /* C l e a n u p */
1927 /******************************************************************************/
1928 
1929 void XrdHttpProtocol::Cleanup() {
1930 
1931  TRACE(ALL, " Cleanup");
1932 
1933  if (BPool && myBuff) {
1934  BuffConsume(BuffUsed());
1935  BPool->Release(myBuff);
1936  myBuff = 0;
1937  }
1938 
1939  if (ssl) {
1940  // Shutdown the SSL/TLS connection
1941  // This triggers a bidirectional shutdown of the connection; the bidirectional
1942  // shutdown is useful to ensure that the client receives the server response;
1943  // a one-sided shutdown can result in the server sending a TCP reset packet, zapping
1944  // the contents of the TCP socket buffer on the client side. The HTTP 1.1 RFC has a
1945  // description of why this is important:
1946  // https://datatracker.ietf.org/doc/html/rfc9112#name-tls-connection-closure
1947  // Once we get the clean SSL shutdown message back from the client, we know that
1948  // the client has received the response and we can safely close the connection.
1949  int ret = SSL_shutdown(ssl);
1950  if (ret != 1) {
1951  if(ret == 0) {
1952  // ret == 0, the unidirectional shutdown was successful; wait for the acknowledgement.
1953  ret = SSL_shutdown(ssl);
1954  if (ret != 1) {
1955  TRACE(ALL, "SSL server failed to receive the SSL shutdown message from the client");
1956  ERR_print_errors(sslbio_err);
1957  }
1958  } else {
1959  //ret < 0, an error really happened.
1960  TRACE(ALL, "SSL server failed to send the shutdown message to the client");
1961  ERR_print_errors(sslbio_err);
1962  }
1963  }
1964 
1965  if (secxtractor)
1966  secxtractor->FreeSSL(ssl);
1967 
1968  SSL_free(ssl);
1969 
1970  }
1971 
1972 
1973  ssl = 0;
1974  sbio = 0;
1975 
1976  if (SecEntity.caps) free(SecEntity.caps);
1977  if (SecEntity.grps) free(SecEntity.grps);
1979  if (SecEntity.vorg) free(SecEntity.vorg);
1980  if (SecEntity.role) free(SecEntity.role);
1981  if (SecEntity.name) free(SecEntity.name);
1982  if (SecEntity.host) free(SecEntity.host);
1983  if (SecEntity.moninfo) free(SecEntity.moninfo);
1984 
1985  SecEntity.Reset();
1986 
1987  if (Addr_str) free(Addr_str);
1988  Addr_str = 0;
1989 }
1990 
1991 /******************************************************************************/
1992 /* R e s e t */
1993 /******************************************************************************/
1994 
1995 void XrdHttpProtocol::Reset() {
1996 
1997  TRACE(ALL, " Reset");
1998  Link = 0;
1999  CurrentReq.reset();
2000  CurrentReq.reqstate = 0;
2001 
2002  if (myBuff) {
2003  BPool->Release(myBuff);
2004  myBuff = 0;
2005  }
2006  myBuffStart = myBuffEnd = 0;
2007 
2008  DoingLogin = false;
2009  DoneSetInfo = false;
2010 
2011  ResumeBytes = 0;
2012  Resume = 0;
2013 
2014  //
2015  // numReads = 0;
2016  // numReadP = 0;
2017  // numReadV = 0;
2018  // numSegsV = 0;
2019  // numWrites = 0;
2020  // numFiles = 0;
2021  // cumReads = 0;
2022  // cumReadV = 0;
2023  // cumSegsV = 0;
2024  // cumWrites = 0;
2025  // totReadP = 0;
2026 
2027  SecEntity.Reset();
2029  ishttps = false;
2030  ssldone = false;
2031 
2032  Bridge = 0;
2033  ssl = 0;
2034  sbio = 0;
2035 
2036 }
2037 
2038 /******************************************************************************/
2039 /* x h t t p s m o d e */
2040 /******************************************************************************/
2041 
2042 /* Function: xhttpsmode
2043 
2044  Purpose: To parse the directive: httpsmode {auto | disable | manual}
2045 
2046  auto configure https if configured in xrd framework.
2047  disable do not configure https no matter what
2048  manual configure https and ignore the xrd framework
2049 
2050  Output: 0 upon success or !0 upon failure.
2051  */
2052 
2053 int XrdHttpProtocol::xhttpsmode(XrdOucStream & Config) {
2054  char *val;
2055 
2056  // Get the val
2057  //
2058  val = Config.GetWord();
2059  if (!val || !val[0]) {
2060  eDest.Emsg("Config", "httpsmode parameter not specified");
2061  return 1;
2062  }
2063 
2064  // Record the val
2065  //
2066  if (!strcmp(val, "auto")) httpsmode = hsmAuto;
2067  else if (!strcmp(val, "disable")) httpsmode = hsmOff;
2068  else if (!strcmp(val, "manual")) httpsmode = hsmMan;
2069  else {eDest.Emsg("Config", "invalid httpsmode parameter - ", val);
2070  return 1;
2071  }
2072  return 0;
2073 }
2074 
2075 /******************************************************************************/
2076 /* x s s l v e r i f y d e p t h */
2077 /******************************************************************************/
2078 
2079 /* Function: xsslverifydepth
2080 
2081  Purpose: To parse the directive: sslverifydepth <depth>
2082 
2083  <depth> the max depth of the ssl cert verification
2084 
2085  Output: 0 upon success or !0 upon failure.
2086  */
2087 
2088 int XrdHttpProtocol::xsslverifydepth(XrdOucStream & Config) {
2089  char *val;
2090 
2091  // Get the val
2092  //
2093  val = Config.GetWord();
2094  if (!val || !val[0]) {
2095  eDest.Emsg("Config", "sslverifydepth value not specified");
2096  return 1;
2097  }
2098 
2099  // Record the val
2100  //
2101  sslverifydepth = atoi(val);
2102 
2103  if (xrdctxVer){ HTTPS_ALERT("verifydepth","tlsca",false); }
2104  return 0;
2105 }
2106 
2107 /******************************************************************************/
2108 /* x s s l c e r t */
2109 /******************************************************************************/
2110 
2111 /* Function: xsslcert
2112 
2113  Purpose: To parse the directive: sslcert <path>
2114 
2115  <path> the path of the server certificate to be used.
2116 
2117  Output: 0 upon success or !0 upon failure.
2118  */
2119 
2120 int XrdHttpProtocol::xsslcert(XrdOucStream & Config) {
2121  char *val;
2122 
2123  // Get the path
2124  //
2125  val = Config.GetWord();
2126  if (!val || !val[0]) {
2127  eDest.Emsg("Config", "HTTP X509 certificate not specified");
2128  return 1;
2129  }
2130 
2131  // Record the path
2132  //
2133  if (sslcert) free(sslcert);
2134  sslcert = strdup(val);
2135 
2136  // If we have an xrd context issue reminder
2137  //
2138  HTTPS_ALERT("cert","tls",true);
2139  return 0;
2140 }
2141 
2142 /******************************************************************************/
2143 /* x s s l k e y */
2144 /******************************************************************************/
2145 
2146 /* Function: xsslkey
2147 
2148  Purpose: To parse the directive: sslkey <path>
2149 
2150  <path> the path of the server key to be used.
2151 
2152  Output: 0 upon success or !0 upon failure.
2153  */
2154 
2155 int XrdHttpProtocol::xsslkey(XrdOucStream & Config) {
2156  char *val;
2157 
2158  // Get the path
2159  //
2160  val = Config.GetWord();
2161  if (!val || !val[0]) {
2162  eDest.Emsg("Config", "HTTP X509 key not specified");
2163  return 1;
2164  }
2165 
2166  // Record the path
2167  //
2168  if (sslkey) free(sslkey);
2169  sslkey = strdup(val);
2170 
2171  HTTPS_ALERT("key","tls",true);
2172  return 0;
2173 }
2174 
2175 /******************************************************************************/
2176 /* x g m a p */
2177 /******************************************************************************/
2178 
2179 /* Function: xgmap
2180 
2181  Purpose: To parse the directive: gridmap [required] [compatNameGeneration] <path>
2182 
2183  required optional parameter which if present treats any grimap errors
2184  as fatal.
2185  <path> the path of the gridmap file to be used. Normally it's
2186  /etc/grid-security/gridmap. No mapfile means no translation
2187  required. Pointing to a non existing mapfile is an error.
2188 
2189  Output: 0 upon success or !0 upon failure.
2190  */
2191 
2192 int XrdHttpProtocol::xgmap(XrdOucStream & Config) {
2193  char *val;
2194 
2195  // Get the path
2196  //
2197  val = Config.GetWord();
2198  if (!val || !val[0]) {
2199  eDest.Emsg("Config", "HTTP X509 gridmap file location not specified");
2200  return 1;
2201  }
2202 
2203  // Handle optional parameter "required"
2204  //
2205  if (!strncmp(val, "required", 8)) {
2206  isRequiredGridmap = true;
2207  val = Config.GetWord();
2208 
2209  if (!val || !val[0]) {
2210  eDest.Emsg("Config", "HTTP X509 gridmap file missing after [required] "
2211  "parameter");
2212  return 1;
2213  }
2214  }
2215 
2216  // Handle optional parameter "compatNameGeneration"
2217  //
2218  if (!strcmp(val, "compatNameGeneration")) {
2219  compatNameGeneration = true;
2220  val = Config.GetWord();
2221  if (!val || !val[0]) {
2222  eDest.Emsg("Config", "HTTP X509 gridmap file missing after "
2223  "[compatNameGeneration] parameter");
2224  return 1;
2225  }
2226  }
2227 
2228 
2229  // Record the path
2230  //
2231  if (gridmap) free(gridmap);
2232  gridmap = strdup(val);
2233  return 0;
2234 }
2235 
2236 /******************************************************************************/
2237 /* x s s l c a f i l e */
2238 /******************************************************************************/
2239 
2240 /* Function: xsslcafile
2241 
2242  Purpose: To parse the directive: sslcafile <path>
2243 
2244  <path> the path of the server key to be used.
2245 
2246  Output: 0 upon success or !0 upon failure.
2247  */
2248 
2249 int XrdHttpProtocol::xsslcafile(XrdOucStream & Config) {
2250  char *val;
2251 
2252  // Get the path
2253  //
2254  val = Config.GetWord();
2255  if (!val || !val[0]) {
2256  eDest.Emsg("Config", "HTTP X509 CAfile not specified");
2257  return 1;
2258  }
2259 
2260  // Record the path
2261  //
2262  if (sslcafile) free(sslcafile);
2263  sslcafile = strdup(val);
2264 
2265  if (xrdctxVer){ HTTPS_ALERT("cafile","tlsca",false); }
2266  return 0;
2267 }
2268 
2269 /******************************************************************************/
2270 /* x s e c r e t k e y */
2271 /******************************************************************************/
2272 
2273 /* Function: xsecretkey
2274 
2275  Purpose: To parse the directive: xsecretkey <key>
2276 
2277  <key> the key to be used
2278 
2279  Output: 0 upon success or !0 upon failure.
2280  */
2281 
2282 int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2283  char *val;
2284  bool inFile = false;
2285 
2286  // Get the path
2287  //
2288  val = Config.GetWord();
2289  if (!val || !val[0]) {
2290  eDest.Emsg("Config", "Shared secret key not specified");
2291  return 1;
2292  }
2293 
2294 
2295  // If the token starts with a slash, then we interpret it as
2296  // the path to a file that contains the secretkey
2297  // otherwise, the token itself is the secretkey
2298  if (val[0] == '/') {
2299  struct stat st;
2300  inFile = true;
2301  int fd = open(val, O_RDONLY);
2302 
2303  if ( fd == -1 ) {
2304  eDest.Emsg("Config", errno, "open shared secret key file", val);
2305  return 1;
2306  }
2307 
2308  if ( fstat(fd, &st) != 0 ) {
2309  eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2310  close(fd);
2311  return 1;
2312  }
2313 
2314  if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2315  eDest.Emsg("Config",
2316  "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2317  close(fd);
2318  return 1;
2319  }
2320 
2321  FILE *fp = fdopen(fd, "r");
2322 
2323  if ( fp == nullptr ) {
2324  eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2325  close(fd);
2326  return 1;
2327  }
2328 
2329  char line[1024];
2330  while( fgets(line, 1024, fp) ) {
2331  char *pp;
2332 
2333  // Trim the end
2334  pp = line + strlen(line) - 1;
2335  while ( (pp >= line) && (!isalnum(*pp)) ) {
2336  *pp = '\0';
2337  pp--;
2338  }
2339 
2340  // Trim the beginning
2341  pp = line;
2342  while ( *pp && !isalnum(*pp) ) pp++;
2343 
2344  if ( strlen(pp) >= 32 ) {
2345  eDest.Say("Config", "Secret key loaded.");
2346  // Record the path
2347  if (secretkey) free(secretkey);
2348  secretkey = strdup(pp);
2349 
2350  fclose(fp);
2351  return 0;
2352  }
2353 
2354  }
2355 
2356  fclose(fp);
2357  eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2358  return 1;
2359 
2360  }
2361 
2362  if ( strlen(val) < 32 ) {
2363  eDest.Emsg("Config", "Secret key is too short");
2364  return 1;
2365  }
2366 
2367  // Record the path
2368  if (secretkey) free(secretkey);
2369  secretkey = strdup(val);
2370  if (!inFile) Config.noEcho();
2371 
2372  return 0;
2373 }
2374 
2375 /******************************************************************************/
2376 /* x l i s t d e n y */
2377 /******************************************************************************/
2378 
2379 /* Function: xlistdeny
2380 
2381  Purpose: To parse the directive: listingdeny <yes|no|0|1>
2382 
2383  <val> makes this redirector deny listings with an error
2384 
2385  Output: 0 upon success or !0 upon failure.
2386  */
2387 
2388 int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2389  char *val;
2390 
2391  // Get the path
2392  //
2393  val = Config.GetWord();
2394  if (!val || !val[0]) {
2395  eDest.Emsg("Config", "listingdeny flag not specified");
2396  return 1;
2397  }
2398 
2399  // Record the value
2400  //
2401  listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2402 
2403 
2404  return 0;
2405 }
2406 
2407 /******************************************************************************/
2408 /* x l i s t r e d i r */
2409 /******************************************************************************/
2410 
2411 /* Function: xlistredir
2412 
2413  Purpose: To parse the directive: listingredir <Url>
2414 
2415  <Url> http/https server to redirect to in the case of listing
2416 
2417  Output: 0 upon success or !0 upon failure.
2418  */
2419 
2420 int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2421  char *val;
2422 
2423  // Get the path
2424  //
2425  val = Config.GetWord();
2426  if (!val || !val[0]) {
2427  eDest.Emsg("Config", "listingredir flag not specified");
2428  return 1;
2429  }
2430 
2431  // Record the value
2432  //
2433  if (listredir) free(listredir);
2434  listredir = strdup(val);
2435 
2436 
2437  return 0;
2438 }
2439 
2440 /******************************************************************************/
2441 /* x s s l d e s t h t t p s */
2442 /******************************************************************************/
2443 
2444 /* Function: xdesthttps
2445 
2446  Purpose: To parse the directive: desthttps <yes|no|0|1>
2447 
2448  <val> makes this redirector produce http or https redirection targets
2449 
2450  Output: 0 upon success or !0 upon failure.
2451  */
2452 
2453 int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2454  char *val;
2455 
2456  // Get the path
2457  //
2458  val = Config.GetWord();
2459  if (!val || !val[0]) {
2460  eDest.Emsg("Config", "desthttps flag not specified");
2461  return 1;
2462  }
2463 
2464  // Record the value
2465  //
2466  isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2467 
2468 
2469  return 0;
2470 }
2471 
2472 /******************************************************************************/
2473 /* x e m b e d d e d s t a t i c */
2474 /******************************************************************************/
2475 
2476 /* Function: xembeddedstatic
2477 
2478  Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2479 
2480  <val> this server will redirect HTTPS to itself using HTTP+token
2481 
2482  Output: 0 upon success or !0 upon failure.
2483  */
2484 
2485 int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2486  char *val;
2487 
2488  // Get the path
2489  //
2490  val = Config.GetWord();
2491  if (!val || !val[0]) {
2492  eDest.Emsg("Config", "embeddedstatic flag not specified");
2493  return 1;
2494  }
2495 
2496  // Record the value
2497  //
2498  embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2499 
2500 
2501  return 0;
2502 }
2503 
2504 /******************************************************************************/
2505 /* x r e d i r s t a t i c */
2506 /******************************************************************************/
2507 
2508 /* Function: xstaticredir
2509 
2510  Purpose: To parse the directive: staticredir <Url>
2511 
2512  <Url> http/https server to redirect to in the case of /static
2513 
2514  Output: 0 upon success or !0 upon failure.
2515  */
2516 
2517 int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2518  char *val;
2519 
2520  // Get the path
2521  //
2522  val = Config.GetWord();
2523  if (!val || !val[0]) {
2524  eDest.Emsg("Config", "staticredir url not specified");
2525  return 1;
2526  }
2527 
2528  // Record the value
2529  //
2530  if (staticredir) free(staticredir);
2531  staticredir = strdup(val);
2532 
2533  return 0;
2534 }
2535 
2536 /******************************************************************************/
2537 /* x p r e l o a d s t a t i c */
2538 /******************************************************************************/
2539 
2540 /* Function: xpreloadstatic
2541 
2542  Purpose: To parse the directive: preloadstatic <http url path> <local file>
2543 
2544  <http url path> http/http path whose response we are preloading
2545  e.g. /static/mycss.css
2546  NOTE: this must start with /static
2547 
2548 
2549  Output: 0 upon success or !0 upon failure.
2550  */
2551 
2552 int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2553  char *val, *k, key[1024];
2554 
2555  // Get the key
2556  //
2557  k = Config.GetWord();
2558  if (!k || !k[0]) {
2559  eDest.Emsg("Config", "preloadstatic urlpath not specified");
2560  return 1;
2561  }
2562 
2563  strcpy(key, k);
2564 
2565  // Get the val
2566  //
2567  val = Config.GetWord();
2568  if (!val || !val[0]) {
2569  eDest.Emsg("Config", "preloadstatic filename not specified");
2570  return 1;
2571  }
2572 
2573  // Try to load the file into memory
2574  int fp = open(val, O_RDONLY);
2575  if( fp < 0 ) {
2576  eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2577  return 1;
2578  }
2579 
2580  StaticPreloadInfo *nfo = new StaticPreloadInfo;
2581  // Max 64Kb ok?
2582  nfo->data = (char *)malloc(65536);
2583  nfo->len = read(fp, (void *)nfo->data, 65536);
2584  close(fp);
2585 
2586  if (nfo->len <= 0) {
2587  eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2588  return 1;
2589  }
2590 
2591  if (nfo->len >= 65536) {
2592  eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2593  return 1;
2594  }
2595 
2596  // Record the value
2597  //
2598  if (!staticpreload)
2600 
2601  staticpreload->Rep((const char *)key, nfo);
2602  return 0;
2603 }
2604 
2605 /******************************************************************************/
2606 /* x s t a t i c h e a d e r */
2607 /******************************************************************************/
2608 
2609 //
2610 // xstaticheader parses the http.staticheader director with the following syntax:
2611 //
2612 // http.staticheader [-verb=[GET|HEAD|...]]* header [value]
2613 //
2614 // When set, this will cause XrdHttp to always return the specified header and
2615 // value.
2616 //
2617 // Setting this option multiple times is additive (multiple headers may be set).
2618 // Omitting the value will cause the static header setting to be unset.
2619 //
2620 // Omitting the -verb argument will cause it the header to be set unconditionally
2621 // for all requests.
2622 int XrdHttpProtocol::xstaticheader(XrdOucStream & Config) {
2623  auto val = Config.GetWord();
2624  std::vector<std::string> verbs;
2625  while (true) {
2626  if (!val || !val[0]) {
2627  eDest.Emsg("Config", "http.staticheader requires the header to be specified");
2628  return 1;
2629  }
2630 
2631  std::string match_verb;
2632  std::string_view val_str(val);
2633  if (val_str.substr(0, 6) == "-verb=") {
2634  verbs.emplace_back(val_str.substr(6));
2635  } else if (val_str == "-") {
2636  eDest.Emsg("Config", "http.staticheader is ignoring unknown flag: ", val_str.data());
2637  } else {
2638  break;
2639  }
2640 
2641  val = Config.GetWord();
2642  }
2643  if (verbs.empty()) {
2644  verbs.emplace_back();
2645  }
2646 
2647  std::string header = val;
2648 
2649  val = Config.GetWord();
2650  std::string header_value;
2651  if (val && val[0]) {
2652  header_value = val;
2653  }
2654 
2655  for (const auto &verb : verbs) {
2656  auto iter = m_staticheader_map.find(verb);
2657  if (iter == m_staticheader_map.end()) {
2658  if (!header_value.empty())
2659  m_staticheader_map.insert(iter, {verb, {{header, header_value}}});
2660  } else if (header_value.empty()) {
2661  iter->second.clear();
2662  } else {
2663  iter->second.emplace_back(header, header_value);
2664  }
2665  }
2666 
2667  return 0;
2668 }
2669 
2670 
2671 /******************************************************************************/
2672 /* x s e l f h t t p s 2 h t t p */
2673 /******************************************************************************/
2674 
2675 /* Function: selfhttps2http
2676 
2677  Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2678 
2679  <val> this server will redirect HTTPS to itself using HTTP+token
2680 
2681  Output: 0 upon success or !0 upon failure.
2682  */
2683 
2684 int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2685  char *val;
2686 
2687  // Get the path
2688  //
2689  val = Config.GetWord();
2690  if (!val || !val[0]) {
2691  eDest.Emsg("Config", "selfhttps2http flag not specified");
2692  return 1;
2693  }
2694 
2695  // Record the value
2696  //
2697  selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2698 
2699 
2700  return 0;
2701 }
2702 
2703 /******************************************************************************/
2704 /* x s e c x t r a c t o r */
2705 /******************************************************************************/
2706 
2707 /* Function: xsecxtractor
2708 
2709  Purpose: To parse the directive: secxtractor [required] <path> <params>
2710 
2711  required optional parameter which if present treats any secxtractor
2712  errors as fatal.
2713  <path> the path of the plugin to be loaded
2714  <params> parameters passed to the secxtractor library
2715 
2716  Output: 0 upon success or !0 upon failure.
2717  */
2718 
2719 int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2720  char *val;
2721 
2722  // Get the path
2723  //
2724  val = Config.GetWord();
2725  if (!val || !val[0]) {
2726  eDest.Emsg("Config", "No security extractor plugin specified.");
2727  return 1;
2728  } else {
2729  // Handle optional parameter [required]
2730  //
2731  if (!strncmp(val, "required", 8)) {
2732  isRequiredXtractor = true;
2733  val = Config.GetWord();
2734 
2735  if (!val || !val[0]) {
2736  eDest.Emsg("Config", "No security extractor plugin after [required] "
2737  "parameter");
2738  return 1;
2739  }
2740  }
2741 
2742  char libName[4096];
2743  strlcpy(libName, val, sizeof(libName));
2744  libName[sizeof(libName) - 1] = '\0';
2745  char libParms[4096];
2746 
2747  if (!Config.GetRest(libParms, 4095)) {
2748  eDest.Emsg("Config", "secxtractor config params longer than 4k");
2749  return 1;
2750  }
2751 
2752  // Try to load the plugin (if available) that extracts info from the
2753  // user cert/proxy
2754  if (LoadSecXtractor(&eDest, libName, libParms)) {
2755  return 1;
2756  }
2757  }
2758 
2759  return 0;
2760 }
2761 
2762 int XrdHttpProtocol::xcors(XrdOucStream& Config) {
2763  char * val;
2764  // Get the path
2765  val = Config.GetWord();
2766  if (!val || !val[0]) {
2767  eDest.Emsg("Config", "No CORS plugin specified.");
2768  return 1;
2769  }
2770  xrdcorsLibPath = val;
2771  return 0;
2772 }
2773 
2774 /******************************************************************************/
2775 /* x e x t h a n d l e r */
2776 /******************************************************************************/
2777 
2778 /* Function: xexthandler
2779  *
2780  * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2781  *
2782  * <name> a unique name (max 16chars) to be given to this
2783  * instance, e.g 'myhandler1'
2784  * <path> the path of the plugin to be loaded
2785  * <initparm> a string parameter (e.g. a config file) that is
2786  * passed to the initialization of the plugin
2787  *
2788  * Output: 0 upon success or !0 upon failure.
2789  */
2790 
2791 int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2792  std::vector<extHInfo> &hiVec) {
2793  char *val, path[1024], namebuf[1024];
2794  char *parm;
2795  // By default, every external handler need TLS configured to be loaded
2796  bool noTlsOK = false;
2797 
2798  // Get the name
2799  //
2800  val = Config.GetWord();
2801  if (!val || !val[0]) {
2802  eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2803  return 1;
2804  }
2805  if (strlen(val) >= 16) {
2806  eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2807  return 1;
2808  }
2809  strncpy(namebuf, val, sizeof(namebuf));
2810  namebuf[ sizeof(namebuf)-1 ] = '\0';
2811 
2812  // Get the +notls option if it was provided
2813  val = Config.GetWord();
2814 
2815  if(val && !strcmp("+notls",val)) {
2816  noTlsOK = true;
2817  val = Config.GetWord();
2818  }
2819 
2820  // Get the path
2821  //
2822  if (!val || !val[0]) {
2823  eDest.Emsg("Config", "No http external handler plugin specified.");
2824  return 1;
2825  }
2826  if (strlen(val) >= (int)sizeof(path)) {
2827  eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2828  return 1;
2829  }
2830 
2831  strcpy(path, val);
2832 
2833  // Everything else is a free string
2834  //
2835  parm = Config.GetWord();
2836 
2837  // Verify whether this is a duplicate (we never supported replacements)
2838  //
2839  for (int i = 0; i < (int)hiVec.size(); i++)
2840  {if (hiVec[i].extHName == namebuf) {
2841  eDest.Emsg("Config", "Instance name already present for "
2842  "http external handler plugin",
2843  hiVec[i].extHPath.c_str());
2844  return 1;
2845  }
2846  }
2847 
2848  // Verify that we don't have more already than we are allowed to have
2849  //
2850  if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2851  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2852  return 1;
2853  }
2854 
2855  // Create an info struct and push it on the list of ext handlers to load
2856  //
2857  hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2858 
2859  return 0;
2860 }
2861 
2862 /******************************************************************************/
2863 /* x h e a d e r 2 c g i */
2864 /******************************************************************************/
2865 
2866 /* Function: xheader2cgi
2867  *
2868  * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2869  *
2870  * <headerkey> the name of an incoming HTTP header
2871  * to be transformed
2872  * <cgikey> the name to be given when adding it to the cgi info
2873  * that is kept only internally
2874  *
2875  * Output: 0 upon success or !0 upon failure.
2876  */
2877 
2878 int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2880 }
2881 
2882 /******************************************************************************/
2883 /* x s s l c a d i r */
2884 /******************************************************************************/
2885 
2886 /* Function: xsslcadir
2887 
2888  Purpose: To parse the directive: sslcadir <path>
2889 
2890  <path> the path of the server key to be used.
2891 
2892  Output: 0 upon success or !0 upon failure.
2893  */
2894 
2895 int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2896  char *val;
2897 
2898  // Get the path
2899  //
2900  val = Config.GetWord();
2901  if (!val || !val[0]) {
2902  eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2903  return 1;
2904  }
2905 
2906  // Record the path
2907  //
2908  if (sslcadir) free(sslcadir);
2909  sslcadir = strdup(val);
2910 
2911  if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2912  return 0;
2913 }
2914 
2915 /******************************************************************************/
2916 /* x s s l c i p h e r f i l t e r */
2917 /******************************************************************************/
2918 
2919 /* Function: xsslcipherfilter
2920 
2921  Purpose: To parse the directive: cipherfilter <filter>
2922 
2923  <filter> the filter string to be used when generating
2924  the SSL cipher list
2925 
2926  Output: 0 upon success or !0 upon failure.
2927  */
2928 
2929 int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2930  char *val;
2931 
2932  // Get the filter string
2933  //
2934  val = Config.GetWord();
2935  if (!val || !val[0]) {
2936  eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2937  return 1;
2938  }
2939 
2940  // Record the filter string
2941  //
2942  if (sslcipherfilter) free(sslcipherfilter);
2943  sslcipherfilter = strdup(val);
2944 
2945  return 0;
2946 }
2947 
2948 /******************************************************************************/
2949 /* x t l s r e u s e */
2950 /******************************************************************************/
2951 
2952 /* Function: xtlsreuse
2953 
2954  Purpose: To parse the directive: tlsreuse {on | off}
2955 
2956  Output: 0 upon success or 1 upon failure.
2957  */
2958 
2959 int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2960 
2961  char *val;
2962 
2963 // Get the argument
2964 //
2965  val = Config.GetWord();
2966  if (!val || !val[0])
2967  {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2968 
2969 // If it's off, we set it off
2970 //
2971  if (!strcmp(val, "off"))
2973  return 0;
2974  }
2975 
2976 // If it's on we set it on.
2977 //
2978  if (!strcmp(val, "on"))
2980  return 0;
2981  }
2982 
2983 // Bad argument
2984 //
2985  eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2986  return 1;
2987 }
2988 
2989 int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) {
2990  auto val = Config.GetWord();
2991  if (!val || !val[0])
2992  {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;}
2993 
2994  if (!strcmp(val, "off"))
2995  {tlsClientAuth = false;
2996  return 0;
2997  }
2998  if (!strcmp(val, "on"))
2999  {tlsClientAuth = true;
3000  return 0;
3001  }
3002 
3003  eDest.Emsg("config", "invalid tlsclientauth parameter -", val);
3004  return 1;
3005 }
3006 
3007 int XrdHttpProtocol::xauth(XrdOucStream &Config) {
3008  char *val = Config.GetWord();
3009  if(val) {
3010  if(!strcmp("tpc",val)) {
3011  if(!(val = Config.GetWord())) {
3012  eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
3013  } else {
3014  if(!strcmp("fcreds",val)) {
3015  tpcForwardCreds = true;
3016  } else {
3017  eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
3018  }
3019  }
3020  } else {
3021  eDest.Emsg("Config", "http.auth value is invalid"); return 1;
3022  }
3023  }
3024  return 0;
3025 }
3026 
3027 int XrdHttpProtocol::xmaxdelay(XrdOucStream &Config) {
3028  char *val = Config.GetWord();
3029  if(val) {
3030  int maxdelay;
3031  if (XrdOuca2x::a2tm(eDest, "http.maxdelay", val, &maxdelay, 1)) return 1;
3032  m_maxdelay = maxdelay;
3033  } else {
3034  eDest.Emsg("Config", "http.maxdelay requires an argument in seconds (default is 30). Example: http.maxdelay 30");
3035  return 1;
3036  }
3037  return 0;
3038 }
3039 
3040 /******************************************************************************/
3041 /* x t r a c e */
3042 /******************************************************************************/
3043 
3044 /* Function: xtrace
3045 
3046  Purpose: To parse the directive: trace <events>
3047 
3048  <events> the blank separated list of events to trace. Trace
3049  directives are cumulative.
3050 
3051  Output: 0 upon success or 1 upon failure.
3052  */
3053 
3054 int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
3055 
3056  char *val;
3057 
3058  static struct traceopts {
3059  const char *opname;
3060  int opval;
3061  } tropts[] = {
3062  {"all", TRACE_ALL},
3063  {"auth", TRACE_AUTH},
3064  {"debug", TRACE_DEBUG},
3065  {"mem", TRACE_MEM},
3066  {"redirect", TRACE_REDIR},
3067  {"request", TRACE_REQ},
3068  {"response", TRACE_RSP}
3069  };
3070  int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3071 
3072  if (!(val = Config.GetWord())) {
3073  eDest.Emsg("config", "trace option not specified");
3074  return 1;
3075  }
3076  while (val) {
3077  if (!strcmp(val, "off")) trval = 0;
3078  else {
3079  if ((neg = (val[0] == '-' && val[1]))) val++;
3080  for (i = 0; i < numopts; i++) {
3081  if (!strcmp(val, tropts[i].opname)) {
3082  if (neg) trval &= ~tropts[i].opval;
3083  else trval |= tropts[i].opval;
3084  break;
3085  }
3086  }
3087  if (i >= numopts)
3088  eDest.Emsg("config", "invalid trace option", val);
3089  }
3090  val = Config.GetWord();
3091  }
3092  XrdHttpTrace.What = trval;
3093  return 0;
3094 }
3095 
3096 int XrdHttpProtocol::doStat(char *fname) {
3097  int l;
3098  bool b;
3099  CurrentReq.filesize = 0;
3100  CurrentReq.fileflags = 0;
3101  CurrentReq.filemodtime = 0;
3102 
3103  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3105  memset(CurrentReq.xrdreq.stat.reserved, 0,
3106  sizeof (CurrentReq.xrdreq.stat.reserved));
3107  l = strlen(fname) + 1;
3108  CurrentReq.xrdreq.stat.dlen = htonl(l);
3109 
3110  if (!Bridge) return -1;
3111  b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3112  if (!b) {
3113  return -1;
3114  }
3115 
3116 
3117  return 0;
3118 }
3119 
3120 /******************************************************************************/
3121 /* d o C h k s u m */
3122 /******************************************************************************/
3123 
3125  size_t length;
3126  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3130  memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
3132  length = fname.length() + 1;
3133  CurrentReq.xrdreq.query.dlen = htonl(length);
3134 
3135  if (!Bridge) return -1;
3136 
3137  return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3138 }
3139 
3140 
3141 static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3142 
3143 // Loads the SecXtractor plugin, if available
3144 int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3145  const char *libParms) {
3146 
3147 
3148  // We don't want to load it more than once
3149  if (secxtractor) return 1;
3150 
3151  XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3153 
3154  // Get the entry point of the object creator
3155  //
3156  ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3157  if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3158  myLib.Unload();
3159  return 1;
3160 }
3161 /******************************************************************************/
3162 /* L o a d E x t H a n d l e r */
3163 /******************************************************************************/
3164 
3165 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3166  for (int i = 0; i < (int) hiVec.size(); i++) {
3167  if(hiVec[i].extHNoTlsOK) {
3168  // The external plugin does not need TLS to be loaded
3169  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3170  hiVec[i].extHParm.c_str(), &myEnv,
3171  hiVec[i].extHName.c_str()))
3172  return 1;
3173  }
3174  }
3175  return 0;
3176 }
3177 
3178 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3179  const char *cFN, XrdOucEnv &myEnv) {
3180 
3181  // Add the pointer to the cadir and the cakey to the environment.
3182  //
3183  if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3184  if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3185  if (sslcert) myEnv.Put("http.cert", sslcert);
3186  if (sslkey) myEnv.Put("http.key" , sslkey);
3187 
3188  // Load all of the specified external handlers.
3189  //
3190  for (int i = 0; i < (int)hiVec.size(); i++) {
3191  // Only load the external handlers that were not already loaded
3192  // by LoadExtHandlerNoTls(...)
3193  if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3194  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3195  hiVec[i].extHParm.c_str(), &myEnv,
3196  hiVec[i].extHName.c_str())) return 1;
3197  }
3198  }
3199  return 0;
3200 }
3201 
3202 // Loads the external handler plugin, if available
3203 int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3204  const char *configFN, const char *libParms,
3205  XrdOucEnv *myEnv, const char *instName) {
3206 
3207 
3208  // This function will avoid loading doubles. No idea why this happens
3209  if (ExtHandlerLoaded(instName)) {
3210  eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3211  return 1;
3212  }
3213  if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3214  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3215  return 1;
3216  }
3217 
3218  XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3220 
3221  // Get the entry point of the object creator
3222  //
3223  ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3224 
3225  XrdHttpExtHandler *newhandler;
3226  if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3227 
3228  // Handler has been loaded, it's the last one in the list
3229  strncpy( exthandler[exthandlercnt].name, instName, 16 );
3230  exthandler[exthandlercnt].name[15] = '\0';
3231  exthandler[exthandlercnt++].ptr = newhandler;
3232 
3233  return 0;
3234  }
3235 
3236  myLib.Unload();
3237  return 1;
3238 }
3239 
3240 
3241 int XrdHttpProtocol::LoadCorsHandler(XrdSysError *eDest, const char *libname) {
3242  if(xrdcors) return 1;
3243  XrdOucPinLoader corsLib(eDest, &compiledVer, "corslib",libname);
3245  ep = (XrdHttpCors *(*)(XrdHttpCorsGetHandlerArgs))(corsLib.Resolve("XrdHttpCorsGetHandler"));
3246  if(ep && (xrdcors = ep())) return 0;
3247  corsLib.Unload();
3248  return 1;
3249 }
3250 
3251 // Tells if we have already loaded a certain exthandler. Try to
3252 // privilege speed, as this func may be invoked pretty often
3253 bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3254  for (int i = 0; i < exthandlercnt; i++) {
3255  if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3256  return true;
3257  }
3258  }
3259  return false;
3260 }
3261 
3262 // Locates a matching external handler for a given request, if available. Try to
3263 // privilege speed, as this func is invoked for every incoming request
3264 XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3265 
3266  for (int i = 0; i < exthandlercnt; i++) {
3267  if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3268  return exthandler[i].ptr;
3269  }
3270  }
3271  return NULL;
3272 }
#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:839
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:639
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:2700
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:204
void * GetPtr(const char *varname)
Definition: XrdOucEnv.cc:263
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.
void * Session()
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.