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