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