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