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