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