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