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,
1600  const char *header_to_add,
1601  long long bodylen, bool keepalive) {
1602  static const std::unordered_map<int, std::string> statusTexts = {
1603  {100, "Continue"},
1604  {200, "OK"},
1605  {201, "Created"},
1606  {206, "Partial Content"},
1607  {302, "Redirect"},
1608  {307, "Temporary Redirect"},
1609  {400, "Bad Request"},
1610  {401, "Unauthorized"},
1611  {403, "Forbidden"},
1612  {404, "Not Found"},
1613  {405, "Method Not Allowed"},
1614  {409, "Conflict"},
1615  {416, "Range Not Satisfiable"},
1616  {423, "Locked"},
1617  {500, "Internal Server Error"},
1618  {502, "Bad Gateway"},
1619  {504, "Gateway Timeout"},
1620  {507, "Insufficient Storage"}};
1621 
1622  std::stringstream ss;
1623  const std::string crlf = "\r\n";
1624 
1625  ss << "HTTP/1.1 " << code << " ";
1626 
1627  if (desc) {
1628  ss << desc;
1629  } else {
1630  auto it = statusTexts.find(code);
1631  if (it != statusTexts.end()) {
1632  ss << it->second;
1633  } else {
1634  ss << "Unknown";
1635  }
1636  }
1637  ss << crlf;
1638 
1639  if (keepalive && (code != 100))
1640  ss << "Connection: Keep-Alive" << crlf;
1641  else
1642  ss << "Connection: Close" << crlf;
1643 
1644  ss << "Server: XrootD/" << XrdVSTRING << crlf;
1645 
1646  const auto iter = m_staticheaders.find(CurrentReq.requestverb);
1647  if (iter != m_staticheaders.end()) {
1648  ss << iter->second;
1649  } else {
1650  ss << m_staticheaders[""];
1651  }
1652 
1653  if ((bodylen >= 0) && (code != 100))
1654  ss << "Content-Length: " << bodylen << crlf;
1655 
1656  if (header_to_add && (header_to_add[0] != '\0')) ss << header_to_add << crlf;
1657 
1658  ss << crlf;
1659 
1660  const std::string &outhdr = ss.str();
1661  TRACEI(RSP, "Sending resp: " << code << " header len:" << outhdr.size());
1662  if (SendData(outhdr.c_str(), outhdr.size()))
1663  return -1;
1664 
1665  return 0;
1666 }
1667 
1668 /******************************************************************************/
1669 /* S t a r t C h u n k e d R e s p */
1670 /******************************************************************************/
1671 
1672 int XrdHttpProtocol::StartChunkedResp(int code, const char *desc, const char *header_to_add, long long bodylen, bool keepalive) {
1673  const std::string crlf = "\r\n";
1674  std::stringstream ss;
1675 
1676  if (header_to_add && (header_to_add[0] != '\0')) {
1677  ss << header_to_add << crlf;
1678  }
1679 
1680  ss << "Transfer-Encoding: chunked";
1681  TRACEI(RSP, "Starting chunked response");
1682  return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1683 }
1684 
1685 /******************************************************************************/
1686 /* C h u n k R e s p */
1687 /******************************************************************************/
1688 
1689 int XrdHttpProtocol::ChunkResp(const char *body, long long bodylen) {
1690  long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1691  if (ChunkRespHeader(content_length))
1692  return -1;
1693 
1694  if (body && SendData(body, content_length))
1695  return -1;
1696 
1697  return ChunkRespFooter();
1698 }
1699 
1700 /******************************************************************************/
1701 /* C h u n k R e s p H e a d e r */
1702 /******************************************************************************/
1703 
1704 int XrdHttpProtocol::ChunkRespHeader(long long bodylen) {
1705  const std::string crlf = "\r\n";
1706  std::stringstream ss;
1707 
1708  ss << std::hex << bodylen << std::dec << crlf;
1709 
1710  const std::string &chunkhdr = ss.str();
1711  TRACEI(RSP, "Sending encoded chunk of size " << bodylen);
1712  return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1713 }
1714 
1715 /******************************************************************************/
1716 /* C h u n k R e s p F o o t e r */
1717 /******************************************************************************/
1718 
1719 int XrdHttpProtocol::ChunkRespFooter() {
1720  const std::string crlf = "\r\n";
1721  return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1722 }
1723 
1724 /******************************************************************************/
1725 /* S e n d S i m p l e R e s p */
1726 /******************************************************************************/
1727 
1731 
1732 int XrdHttpProtocol::SendSimpleResp(int code, const char *desc, const char *header_to_add, const char *body, long long bodylen, bool keepalive) {
1733 
1734  long long content_length = bodylen;
1735  if (bodylen <= 0) {
1736  content_length = body ? strlen(body) : 0;
1737  }
1738 
1739  if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1740  return -1;
1741 
1742  //
1743  // Send the data
1744  //
1745  if (body)
1746  return SendData(body, content_length);
1747 
1748  return 0;
1749 }
1750 
1751 /******************************************************************************/
1752 /* C o n f i g u r e */
1753 /******************************************************************************/
1754 
1756  /*
1757  Function: Establish configuration at load time.
1758 
1759  Input: None.
1760 
1761  Output: 0 upon success or !0 otherwise.
1762  */
1763 
1764  char *rdf;
1765 
1766  // Copy out the special info we want to use at top level
1767  //
1768  eDest.logger(pi->eDest->logger());
1770  // SI = new XrdXrootdStats(pi->Stats);
1771  Sched = pi->Sched;
1772  BPool = pi->BPool;
1773  xrd_cslist = getenv("XRD_CSLIST");
1774 
1775  Port = pi->Port;
1776 
1777  // Copy out the current TLS context
1778  //
1779  xrdctx = pi->tlsCtx;
1780 
1781  {
1782  char buf[16];
1783  sprintf(buf, "%d", Port);
1784  Port_str = strdup(buf);
1785  }
1786 
1787  // Now process and configuration parameters
1788  //
1789  rdf = (parms && *parms ? parms : pi->ConfigFN);
1790  if (rdf && Config(rdf, pi->theEnv)) return 0;
1791  if (pi->DebugON) XrdHttpTrace.What = TRACE_ALL;
1792 
1793  // Set the redirect flag if we are a pure redirector
1794  myRole = kXR_isServer;
1795  if ((rdf = getenv("XRDROLE"))) {
1796  eDest.Emsg("Config", "XRDROLE: ", rdf);
1797 
1798  if (!strcasecmp(rdf, "manager") || !strcasecmp(rdf, "supervisor")) {
1800  eDest.Emsg("Config", "Configured as HTTP(s) redirector.");
1801  } else {
1802 
1803  eDest.Emsg("Config", "Configured as HTTP(s) data server.");
1804  }
1805 
1806  } else {
1807  eDest.Emsg("Config", "No XRDROLE specified.");
1808  }
1809 
1810  // Schedule protocol object cleanup
1811  //
1813  (XrdHttpTrace.What & TRACE_MEM ? TRACE_MEM : 0));
1814  ProtStack.Set((pi->ConnMax / 3 ? pi->ConnMax / 3 : 30), 60 * 60);
1815 
1816  // Return success
1817  //
1818 
1819  return 1;
1820 }
1821 
1822 /******************************************************************************/
1823 /* p a r s e H e a d e r 2 C G I */
1824 /******************************************************************************/
1825 int XrdHttpProtocol::parseHeader2CGI(XrdOucStream &Config, XrdSysError & err,std::map<std::string, std::string> &header2cgi) {
1826  char *val, keybuf[1024], parmbuf[1024];
1827  char *parm;
1828 
1829  // Get the header key
1830  val = Config.GetWord();
1831  if (!val || !val[0]) {
1832  err.Emsg("Config", "No headerkey specified.");
1833  return 1;
1834  } else {
1835 
1836  // Trim the beginning, in place
1837  while ( *val && !isalnum(*val) ) val++;
1838  strcpy(keybuf, val);
1839 
1840  // Trim the end, in place
1841  char *pp;
1842  pp = keybuf + strlen(keybuf) - 1;
1843  while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1844  *pp = '\0';
1845  pp--;
1846  }
1847 
1848  parm = Config.GetWord();
1849 
1850  // Avoids segfault in case a key is given without value
1851  if(!parm || !parm[0]) {
1852  err.Emsg("Config", "No header2cgi value specified. key: '", keybuf, "'");
1853  return 1;
1854  }
1855 
1856  // Trim the beginning, in place
1857  while ( *parm && !isalnum(*parm) ) parm++;
1858  strcpy(parmbuf, parm);
1859 
1860  // Trim the end, in place
1861  pp = parmbuf + strlen(parmbuf) - 1;
1862  while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1863  *pp = '\0';
1864  pp--;
1865  }
1866 
1867  // Add this mapping to the map that will be used
1868  try {
1869  header2cgi[keybuf] = parmbuf;
1870  } catch ( ... ) {
1871  err.Emsg("Config", "Can't insert new header2cgi rule. key: '", keybuf, "'");
1872  return 1;
1873  }
1874 
1875  }
1876  return 0;
1877 }
1878 
1879 
1880 /******************************************************************************/
1881 /* I n i t T L S */
1882 /******************************************************************************/
1883 
1884 bool XrdHttpProtocol::InitTLS() {
1885 
1886  std::string eMsg;
1889 
1890 // Create a new TLS context
1891 //
1892  if (sslverifydepth > 255) sslverifydepth = 255;
1894  //TLS_SET_REFINT will set the refresh interval in minutes, hence the division by 60
1897 
1898 // Make sure the context was created
1899 //
1900  if (!xrdctx->isOK())
1901  {eDest.Say("Config failure: ", eMsg.c_str());
1902  return false;
1903  }
1904 
1905 // Setup session cache (this is controversial). The default is off but many
1906 // programs expect it being enabled and break when it is disabled. In such
1907 // cases it should be enabled. This is, of course, a big OpenSSL mess.
1908 //
1909  static const char *sess_ctx_id = "XrdHTTPSessionCtx";
1910  unsigned int n =(unsigned int)(strlen(sess_ctx_id)+1);
1911  xrdctx->SessionCache(tlsCache, sess_ctx_id, n);
1912 
1913 // Set special ciphers if so specified.
1914 //
1916  {eDest.Say("Config failure: ", "Unable to set allowable https ciphers!");
1917  return false;
1918  }
1919 
1920 // All done
1921 //
1922  return true;
1923 }
1924 
1925 /******************************************************************************/
1926 /* C l e a n u p */
1927 /******************************************************************************/
1928 
1929 void XrdHttpProtocol::Cleanup() {
1930 
1931  TRACE(ALL, " Cleanup");
1932 
1933  if (BPool && myBuff) {
1934  BuffConsume(BuffUsed());
1935  BPool->Release(myBuff);
1936  myBuff = 0;
1937  }
1938 
1939  if (ssl) {
1940  // Shutdown the SSL/TLS connection
1941  // https://www.openssl.org/docs/man1.0.2/man3/SSL_shutdown.html
1942  // We don't need a bidirectional shutdown as
1943  // when we are here, the connection will not be re-used.
1944  // In the case SSL_shutdown returns 0,
1945  // "the output of SSL_get_error(3) may be misleading, as an erroneous SSL_ERROR_SYSCALL may be flagged even though no error occurred."
1946  // we will then just flush the thread's queue.
1947  // In the case an error really happened, we print the error that happened
1948  int ret = SSL_shutdown(ssl);
1949  if (ret != 1) {
1950  if(ret == 0) {
1951  // Clean this thread's error queue for the old openssl versions
1952  #if OPENSSL_VERSION_NUMBER < 0x10100000L
1953  ERR_remove_thread_state(nullptr);
1954  #endif
1955  } else {
1956  //ret < 0, an error really happened.
1957  TRACE(ALL, " SSL_shutdown failed");
1958  ERR_print_errors(sslbio_err);
1959  }
1960  }
1961 
1962  if (secxtractor)
1963  secxtractor->FreeSSL(ssl);
1964 
1965  SSL_free(ssl);
1966 
1967  }
1968 
1969 
1970  ssl = 0;
1971  sbio = 0;
1972 
1973  if (SecEntity.caps) free(SecEntity.caps);
1974  if (SecEntity.grps) free(SecEntity.grps);
1976  if (SecEntity.vorg) free(SecEntity.vorg);
1977  if (SecEntity.role) free(SecEntity.role);
1978  if (SecEntity.name) free(SecEntity.name);
1979  if (SecEntity.host) free(SecEntity.host);
1980  if (SecEntity.moninfo) free(SecEntity.moninfo);
1981 
1982  SecEntity.Reset();
1983 
1984  if (Addr_str) free(Addr_str);
1985  Addr_str = 0;
1986 }
1987 
1988 /******************************************************************************/
1989 /* R e s e t */
1990 /******************************************************************************/
1991 
1992 void XrdHttpProtocol::Reset() {
1993 
1994  TRACE(ALL, " Reset");
1995  Link = 0;
1996  CurrentReq.reset();
1997  CurrentReq.reqstate = 0;
1998 
1999  if (myBuff) {
2000  BPool->Release(myBuff);
2001  myBuff = 0;
2002  }
2003  myBuffStart = myBuffEnd = 0;
2004 
2005  DoingLogin = false;
2006  DoneSetInfo = false;
2007 
2008  ResumeBytes = 0;
2009  Resume = 0;
2010 
2011  //
2012  // numReads = 0;
2013  // numReadP = 0;
2014  // numReadV = 0;
2015  // numSegsV = 0;
2016  // numWrites = 0;
2017  // numFiles = 0;
2018  // cumReads = 0;
2019  // cumReadV = 0;
2020  // cumSegsV = 0;
2021  // cumWrites = 0;
2022  // totReadP = 0;
2023 
2024  SecEntity.Reset();
2026  ishttps = false;
2027  ssldone = false;
2028 
2029  Bridge = 0;
2030  ssl = 0;
2031  sbio = 0;
2032 
2033 }
2034 
2035 /******************************************************************************/
2036 /* x h t t p s m o d e */
2037 /******************************************************************************/
2038 
2039 /* Function: xhttpsmode
2040 
2041  Purpose: To parse the directive: httpsmode {auto | disable | manual}
2042 
2043  auto configure https if configured in xrd framework.
2044  disable do not configure https no matter what
2045  manual configure https and ignore the xrd framework
2046 
2047  Output: 0 upon success or !0 upon failure.
2048  */
2049 
2050 int XrdHttpProtocol::xhttpsmode(XrdOucStream & Config) {
2051  char *val;
2052 
2053  // Get the val
2054  //
2055  val = Config.GetWord();
2056  if (!val || !val[0]) {
2057  eDest.Emsg("Config", "httpsmode parameter not specified");
2058  return 1;
2059  }
2060 
2061  // Record the val
2062  //
2063  if (!strcmp(val, "auto")) httpsmode = hsmAuto;
2064  else if (!strcmp(val, "disable")) httpsmode = hsmOff;
2065  else if (!strcmp(val, "manual")) httpsmode = hsmMan;
2066  else {eDest.Emsg("Config", "invalid httpsmode parameter - ", val);
2067  return 1;
2068  }
2069  return 0;
2070 }
2071 
2072 /******************************************************************************/
2073 /* x s s l v e r i f y d e p t h */
2074 /******************************************************************************/
2075 
2076 /* Function: xsslverifydepth
2077 
2078  Purpose: To parse the directive: sslverifydepth <depth>
2079 
2080  <depth> the max depth of the ssl cert verification
2081 
2082  Output: 0 upon success or !0 upon failure.
2083  */
2084 
2085 int XrdHttpProtocol::xsslverifydepth(XrdOucStream & Config) {
2086  char *val;
2087 
2088  // Get the val
2089  //
2090  val = Config.GetWord();
2091  if (!val || !val[0]) {
2092  eDest.Emsg("Config", "sslverifydepth value not specified");
2093  return 1;
2094  }
2095 
2096  // Record the val
2097  //
2098  sslverifydepth = atoi(val);
2099 
2100  if (xrdctxVer){ HTTPS_ALERT("verifydepth","tlsca",false); }
2101  return 0;
2102 }
2103 
2104 /******************************************************************************/
2105 /* x s s l c e r t */
2106 /******************************************************************************/
2107 
2108 /* Function: xsslcert
2109 
2110  Purpose: To parse the directive: sslcert <path>
2111 
2112  <path> the path of the server certificate to be used.
2113 
2114  Output: 0 upon success or !0 upon failure.
2115  */
2116 
2117 int XrdHttpProtocol::xsslcert(XrdOucStream & Config) {
2118  char *val;
2119 
2120  // Get the path
2121  //
2122  val = Config.GetWord();
2123  if (!val || !val[0]) {
2124  eDest.Emsg("Config", "HTTP X509 certificate not specified");
2125  return 1;
2126  }
2127 
2128  // Record the path
2129  //
2130  if (sslcert) free(sslcert);
2131  sslcert = strdup(val);
2132 
2133  // If we have an xrd context issue reminder
2134  //
2135  HTTPS_ALERT("cert","tls",true);
2136  return 0;
2137 }
2138 
2139 /******************************************************************************/
2140 /* x s s l k e y */
2141 /******************************************************************************/
2142 
2143 /* Function: xsslkey
2144 
2145  Purpose: To parse the directive: sslkey <path>
2146 
2147  <path> the path of the server key to be used.
2148 
2149  Output: 0 upon success or !0 upon failure.
2150  */
2151 
2152 int XrdHttpProtocol::xsslkey(XrdOucStream & Config) {
2153  char *val;
2154 
2155  // Get the path
2156  //
2157  val = Config.GetWord();
2158  if (!val || !val[0]) {
2159  eDest.Emsg("Config", "HTTP X509 key not specified");
2160  return 1;
2161  }
2162 
2163  // Record the path
2164  //
2165  if (sslkey) free(sslkey);
2166  sslkey = strdup(val);
2167 
2168  HTTPS_ALERT("key","tls",true);
2169  return 0;
2170 }
2171 
2172 /******************************************************************************/
2173 /* x g m a p */
2174 /******************************************************************************/
2175 
2176 /* Function: xgmap
2177 
2178  Purpose: To parse the directive: gridmap [required] [compatNameGeneration] <path>
2179 
2180  required optional parameter which if present treats any grimap errors
2181  as fatal.
2182  <path> the path of the gridmap file to be used. Normally it's
2183  /etc/grid-security/gridmap. No mapfile means no translation
2184  required. Pointing to a non existing mapfile is an error.
2185 
2186  Output: 0 upon success or !0 upon failure.
2187  */
2188 
2189 int XrdHttpProtocol::xgmap(XrdOucStream & Config) {
2190  char *val;
2191 
2192  // Get the path
2193  //
2194  val = Config.GetWord();
2195  if (!val || !val[0]) {
2196  eDest.Emsg("Config", "HTTP X509 gridmap file location not specified");
2197  return 1;
2198  }
2199 
2200  // Handle optional parameter "required"
2201  //
2202  if (!strncmp(val, "required", 8)) {
2203  isRequiredGridmap = true;
2204  val = Config.GetWord();
2205 
2206  if (!val || !val[0]) {
2207  eDest.Emsg("Config", "HTTP X509 gridmap file missing after [required] "
2208  "parameter");
2209  return 1;
2210  }
2211  }
2212 
2213  // Handle optional parameter "compatNameGeneration"
2214  //
2215  if (!strcmp(val, "compatNameGeneration")) {
2216  compatNameGeneration = true;
2217  val = Config.GetWord();
2218  if (!val || !val[0]) {
2219  eDest.Emsg("Config", "HTTP X509 gridmap file missing after "
2220  "[compatNameGeneration] parameter");
2221  return 1;
2222  }
2223  }
2224 
2225 
2226  // Record the path
2227  //
2228  if (gridmap) free(gridmap);
2229  gridmap = strdup(val);
2230  return 0;
2231 }
2232 
2233 /******************************************************************************/
2234 /* x s s l c a f i l e */
2235 /******************************************************************************/
2236 
2237 /* Function: xsslcafile
2238 
2239  Purpose: To parse the directive: sslcafile <path>
2240 
2241  <path> the path of the server key to be used.
2242 
2243  Output: 0 upon success or !0 upon failure.
2244  */
2245 
2246 int XrdHttpProtocol::xsslcafile(XrdOucStream & Config) {
2247  char *val;
2248 
2249  // Get the path
2250  //
2251  val = Config.GetWord();
2252  if (!val || !val[0]) {
2253  eDest.Emsg("Config", "HTTP X509 CAfile not specified");
2254  return 1;
2255  }
2256 
2257  // Record the path
2258  //
2259  if (sslcafile) free(sslcafile);
2260  sslcafile = strdup(val);
2261 
2262  if (xrdctxVer){ HTTPS_ALERT("cafile","tlsca",false); }
2263  return 0;
2264 }
2265 
2266 /******************************************************************************/
2267 /* x s e c r e t k e y */
2268 /******************************************************************************/
2269 
2270 /* Function: xsecretkey
2271 
2272  Purpose: To parse the directive: xsecretkey <key>
2273 
2274  <key> the key to be used
2275 
2276  Output: 0 upon success or !0 upon failure.
2277  */
2278 
2279 int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2280  char *val;
2281  bool inFile = false;
2282 
2283  // Get the path
2284  //
2285  val = Config.GetWord();
2286  if (!val || !val[0]) {
2287  eDest.Emsg("Config", "Shared secret key not specified");
2288  return 1;
2289  }
2290 
2291 
2292  // If the token starts with a slash, then we interpret it as
2293  // the path to a file that contains the secretkey
2294  // otherwise, the token itself is the secretkey
2295  if (val[0] == '/') {
2296  struct stat st;
2297  inFile = true;
2298  int fd = open(val, O_RDONLY);
2299 
2300  if ( fd == -1 ) {
2301  eDest.Emsg("Config", errno, "open shared secret key file", val);
2302  return 1;
2303  }
2304 
2305  if ( fstat(fd, &st) != 0 ) {
2306  eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2307  close(fd);
2308  return 1;
2309  }
2310 
2311  if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2312  eDest.Emsg("Config",
2313  "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2314  close(fd);
2315  return 1;
2316  }
2317 
2318  FILE *fp = fdopen(fd, "r");
2319 
2320  if ( fp == nullptr ) {
2321  eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2322  close(fd);
2323  return 1;
2324  }
2325 
2326  char line[1024];
2327  while( fgets(line, 1024, fp) ) {
2328  char *pp;
2329 
2330  // Trim the end
2331  pp = line + strlen(line) - 1;
2332  while ( (pp >= line) && (!isalnum(*pp)) ) {
2333  *pp = '\0';
2334  pp--;
2335  }
2336 
2337  // Trim the beginning
2338  pp = line;
2339  while ( *pp && !isalnum(*pp) ) pp++;
2340 
2341  if ( strlen(pp) >= 32 ) {
2342  eDest.Say("Config", "Secret key loaded.");
2343  // Record the path
2344  if (secretkey) free(secretkey);
2345  secretkey = strdup(pp);
2346 
2347  fclose(fp);
2348  return 0;
2349  }
2350 
2351  }
2352 
2353  fclose(fp);
2354  eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2355  return 1;
2356 
2357  }
2358 
2359  if ( strlen(val) < 32 ) {
2360  eDest.Emsg("Config", "Secret key is too short");
2361  return 1;
2362  }
2363 
2364  // Record the path
2365  if (secretkey) free(secretkey);
2366  secretkey = strdup(val);
2367  if (!inFile) Config.noEcho();
2368 
2369  return 0;
2370 }
2371 
2372 /******************************************************************************/
2373 /* x l i s t d e n y */
2374 /******************************************************************************/
2375 
2376 /* Function: xlistdeny
2377 
2378  Purpose: To parse the directive: listingdeny <yes|no|0|1>
2379 
2380  <val> makes this redirector deny listings with an error
2381 
2382  Output: 0 upon success or !0 upon failure.
2383  */
2384 
2385 int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2386  char *val;
2387 
2388  // Get the path
2389  //
2390  val = Config.GetWord();
2391  if (!val || !val[0]) {
2392  eDest.Emsg("Config", "listingdeny flag not specified");
2393  return 1;
2394  }
2395 
2396  // Record the value
2397  //
2398  listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2399 
2400 
2401  return 0;
2402 }
2403 
2404 /******************************************************************************/
2405 /* x l i s t r e d i r */
2406 /******************************************************************************/
2407 
2408 /* Function: xlistredir
2409 
2410  Purpose: To parse the directive: listingredir <Url>
2411 
2412  <Url> http/https server to redirect to in the case of listing
2413 
2414  Output: 0 upon success or !0 upon failure.
2415  */
2416 
2417 int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2418  char *val;
2419 
2420  // Get the path
2421  //
2422  val = Config.GetWord();
2423  if (!val || !val[0]) {
2424  eDest.Emsg("Config", "listingredir flag not specified");
2425  return 1;
2426  }
2427 
2428  // Record the value
2429  //
2430  if (listredir) free(listredir);
2431  listredir = strdup(val);
2432 
2433 
2434  return 0;
2435 }
2436 
2437 /******************************************************************************/
2438 /* x s s l d e s t h t t p s */
2439 /******************************************************************************/
2440 
2441 /* Function: xdesthttps
2442 
2443  Purpose: To parse the directive: desthttps <yes|no|0|1>
2444 
2445  <val> makes this redirector produce http or https redirection targets
2446 
2447  Output: 0 upon success or !0 upon failure.
2448  */
2449 
2450 int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2451  char *val;
2452 
2453  // Get the path
2454  //
2455  val = Config.GetWord();
2456  if (!val || !val[0]) {
2457  eDest.Emsg("Config", "desthttps flag not specified");
2458  return 1;
2459  }
2460 
2461  // Record the value
2462  //
2463  isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2464 
2465 
2466  return 0;
2467 }
2468 
2469 /******************************************************************************/
2470 /* x e m b e d d e d s t a t i c */
2471 /******************************************************************************/
2472 
2473 /* Function: xembeddedstatic
2474 
2475  Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2476 
2477  <val> this server will redirect HTTPS to itself using HTTP+token
2478 
2479  Output: 0 upon success or !0 upon failure.
2480  */
2481 
2482 int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2483  char *val;
2484 
2485  // Get the path
2486  //
2487  val = Config.GetWord();
2488  if (!val || !val[0]) {
2489  eDest.Emsg("Config", "embeddedstatic flag not specified");
2490  return 1;
2491  }
2492 
2493  // Record the value
2494  //
2495  embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2496 
2497 
2498  return 0;
2499 }
2500 
2501 /******************************************************************************/
2502 /* x r e d i r s t a t i c */
2503 /******************************************************************************/
2504 
2505 /* Function: xstaticredir
2506 
2507  Purpose: To parse the directive: staticredir <Url>
2508 
2509  <Url> http/https server to redirect to in the case of /static
2510 
2511  Output: 0 upon success or !0 upon failure.
2512  */
2513 
2514 int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2515  char *val;
2516 
2517  // Get the path
2518  //
2519  val = Config.GetWord();
2520  if (!val || !val[0]) {
2521  eDest.Emsg("Config", "staticredir url not specified");
2522  return 1;
2523  }
2524 
2525  // Record the value
2526  //
2527  if (staticredir) free(staticredir);
2528  staticredir = strdup(val);
2529 
2530  return 0;
2531 }
2532 
2533 /******************************************************************************/
2534 /* x p r e l o a d s t a t i c */
2535 /******************************************************************************/
2536 
2537 /* Function: xpreloadstatic
2538 
2539  Purpose: To parse the directive: preloadstatic <http url path> <local file>
2540 
2541  <http url path> http/http path whose response we are preloading
2542  e.g. /static/mycss.css
2543  NOTE: this must start with /static
2544 
2545 
2546  Output: 0 upon success or !0 upon failure.
2547  */
2548 
2549 int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2550  char *val, *k, key[1024];
2551 
2552  // Get the key
2553  //
2554  k = Config.GetWord();
2555  if (!k || !k[0]) {
2556  eDest.Emsg("Config", "preloadstatic urlpath not specified");
2557  return 1;
2558  }
2559 
2560  strcpy(key, k);
2561 
2562  // Get the val
2563  //
2564  val = Config.GetWord();
2565  if (!val || !val[0]) {
2566  eDest.Emsg("Config", "preloadstatic filename not specified");
2567  return 1;
2568  }
2569 
2570  // Try to load the file into memory
2571  int fp = open(val, O_RDONLY);
2572  if( fp < 0 ) {
2573  eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2574  return 1;
2575  }
2576 
2577  StaticPreloadInfo *nfo = new StaticPreloadInfo;
2578  // Max 64Kb ok?
2579  nfo->data = (char *)malloc(65536);
2580  nfo->len = read(fp, (void *)nfo->data, 65536);
2581  close(fp);
2582 
2583  if (nfo->len <= 0) {
2584  eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2585  return 1;
2586  }
2587 
2588  if (nfo->len >= 65536) {
2589  eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2590  return 1;
2591  }
2592 
2593  // Record the value
2594  //
2595  if (!staticpreload)
2597 
2598  staticpreload->Rep((const char *)key, nfo);
2599  return 0;
2600 }
2601 
2602 /******************************************************************************/
2603 /* x s t a t i c h e a d e r */
2604 /******************************************************************************/
2605 
2606 //
2607 // xstaticheader parses the http.staticheader director with the following syntax:
2608 //
2609 // http.staticheader [-verb=[GET|HEAD|...]]* header [value]
2610 //
2611 // When set, this will cause XrdHttp to always return the specified header and
2612 // value.
2613 //
2614 // Setting this option multiple times is additive (multiple headers may be set).
2615 // Omitting the value will cause the static header setting to be unset.
2616 //
2617 // Omitting the -verb argument will cause it the header to be set unconditionally
2618 // for all requests.
2619 int XrdHttpProtocol::xstaticheader(XrdOucStream & Config) {
2620  auto val = Config.GetWord();
2621  std::vector<std::string> verbs;
2622  while (true) {
2623  if (!val || !val[0]) {
2624  eDest.Emsg("Config", "http.staticheader requires the header to be specified");
2625  return 1;
2626  }
2627 
2628  std::string match_verb;
2629  std::string_view val_str(val);
2630  if (val_str.substr(0, 6) == "-verb=") {
2631  verbs.emplace_back(val_str.substr(6));
2632  } else if (val_str == "-") {
2633  eDest.Emsg("Config", "http.staticheader is ignoring unknown flag: ", val_str.data());
2634  } else {
2635  break;
2636  }
2637 
2638  val = Config.GetWord();
2639  }
2640  if (verbs.empty()) {
2641  verbs.emplace_back();
2642  }
2643 
2644  std::string header = val;
2645 
2646  val = Config.GetWord();
2647  std::string header_value;
2648  if (val && val[0]) {
2649  header_value = val;
2650  }
2651 
2652  for (const auto &verb : verbs) {
2653  auto iter = m_staticheader_map.find(verb);
2654  if (iter == m_staticheader_map.end()) {
2655  if (!header_value.empty())
2656  m_staticheader_map.insert(iter, {verb, {{header, header_value}}});
2657  } else if (header_value.empty()) {
2658  iter->second.clear();
2659  } else {
2660  iter->second.emplace_back(header, header_value);
2661  }
2662  }
2663 
2664  return 0;
2665 }
2666 
2667 
2668 /******************************************************************************/
2669 /* x s e l f h t t p s 2 h t t p */
2670 /******************************************************************************/
2671 
2672 /* Function: selfhttps2http
2673 
2674  Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2675 
2676  <val> this server will redirect HTTPS to itself using HTTP+token
2677 
2678  Output: 0 upon success or !0 upon failure.
2679  */
2680 
2681 int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2682  char *val;
2683 
2684  // Get the path
2685  //
2686  val = Config.GetWord();
2687  if (!val || !val[0]) {
2688  eDest.Emsg("Config", "selfhttps2http flag not specified");
2689  return 1;
2690  }
2691 
2692  // Record the value
2693  //
2694  selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2695 
2696 
2697  return 0;
2698 }
2699 
2700 /******************************************************************************/
2701 /* x s e c x t r a c t o r */
2702 /******************************************************************************/
2703 
2704 /* Function: xsecxtractor
2705 
2706  Purpose: To parse the directive: secxtractor [required] <path> <params>
2707 
2708  required optional parameter which if present treats any secxtractor
2709  errors as fatal.
2710  <path> the path of the plugin to be loaded
2711  <params> parameters passed to the secxtractor library
2712 
2713  Output: 0 upon success or !0 upon failure.
2714  */
2715 
2716 int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2717  char *val;
2718 
2719  // Get the path
2720  //
2721  val = Config.GetWord();
2722  if (!val || !val[0]) {
2723  eDest.Emsg("Config", "No security extractor plugin specified.");
2724  return 1;
2725  } else {
2726  // Handle optional parameter [required]
2727  //
2728  if (!strncmp(val, "required", 8)) {
2729  isRequiredXtractor = true;
2730  val = Config.GetWord();
2731 
2732  if (!val || !val[0]) {
2733  eDest.Emsg("Config", "No security extractor plugin after [required] "
2734  "parameter");
2735  return 1;
2736  }
2737  }
2738 
2739  char libName[4096];
2740  strlcpy(libName, val, sizeof(libName));
2741  libName[sizeof(libName) - 1] = '\0';
2742  char libParms[4096];
2743 
2744  if (!Config.GetRest(libParms, 4095)) {
2745  eDest.Emsg("Config", "secxtractor config params longer than 4k");
2746  return 1;
2747  }
2748 
2749  // Try to load the plugin (if available) that extracts info from the
2750  // user cert/proxy
2751  if (LoadSecXtractor(&eDest, libName, libParms)) {
2752  return 1;
2753  }
2754  }
2755 
2756  return 0;
2757 }
2758 
2759 /******************************************************************************/
2760 /* x e x t h a n d l e r */
2761 /******************************************************************************/
2762 
2763 /* Function: xexthandler
2764  *
2765  * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2766  *
2767  * <name> a unique name (max 16chars) to be given to this
2768  * instance, e.g 'myhandler1'
2769  * <path> the path of the plugin to be loaded
2770  * <initparm> a string parameter (e.g. a config file) that is
2771  * passed to the initialization of the plugin
2772  *
2773  * Output: 0 upon success or !0 upon failure.
2774  */
2775 
2776 int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2777  std::vector<extHInfo> &hiVec) {
2778  char *val, path[1024], namebuf[1024];
2779  char *parm;
2780  // By default, every external handler need TLS configured to be loaded
2781  bool noTlsOK = false;
2782 
2783  // Get the name
2784  //
2785  val = Config.GetWord();
2786  if (!val || !val[0]) {
2787  eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2788  return 1;
2789  }
2790  if (strlen(val) >= 16) {
2791  eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2792  return 1;
2793  }
2794  strncpy(namebuf, val, sizeof(namebuf));
2795  namebuf[ sizeof(namebuf)-1 ] = '\0';
2796 
2797  // Get the +notls option if it was provided
2798  val = Config.GetWord();
2799 
2800  if(val && !strcmp("+notls",val)) {
2801  noTlsOK = true;
2802  val = Config.GetWord();
2803  }
2804 
2805  // Get the path
2806  //
2807  if (!val || !val[0]) {
2808  eDest.Emsg("Config", "No http external handler plugin specified.");
2809  return 1;
2810  }
2811  if (strlen(val) >= (int)sizeof(path)) {
2812  eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2813  return 1;
2814  }
2815 
2816  strcpy(path, val);
2817 
2818  // Everything else is a free string
2819  //
2820  parm = Config.GetWord();
2821 
2822  // Verify whether this is a duplicate (we never supported replacements)
2823  //
2824  for (int i = 0; i < (int)hiVec.size(); i++)
2825  {if (hiVec[i].extHName == namebuf) {
2826  eDest.Emsg("Config", "Instance name already present for "
2827  "http external handler plugin",
2828  hiVec[i].extHPath.c_str());
2829  return 1;
2830  }
2831  }
2832 
2833  // Verify that we don't have more already than we are allowed to have
2834  //
2835  if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2836  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2837  return 1;
2838  }
2839 
2840  // Create an info struct and push it on the list of ext handlers to load
2841  //
2842  hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2843 
2844  return 0;
2845 }
2846 
2847 /******************************************************************************/
2848 /* x h e a d e r 2 c g i */
2849 /******************************************************************************/
2850 
2851 /* Function: xheader2cgi
2852  *
2853  * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2854  *
2855  * <headerkey> the name of an incoming HTTP header
2856  * to be transformed
2857  * <cgikey> the name to be given when adding it to the cgi info
2858  * that is kept only internally
2859  *
2860  * Output: 0 upon success or !0 upon failure.
2861  */
2862 
2863 int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2865 }
2866 
2867 /******************************************************************************/
2868 /* x s s l c a d i r */
2869 /******************************************************************************/
2870 
2871 /* Function: xsslcadir
2872 
2873  Purpose: To parse the directive: sslcadir <path>
2874 
2875  <path> the path of the server key to be used.
2876 
2877  Output: 0 upon success or !0 upon failure.
2878  */
2879 
2880 int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2881  char *val;
2882 
2883  // Get the path
2884  //
2885  val = Config.GetWord();
2886  if (!val || !val[0]) {
2887  eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2888  return 1;
2889  }
2890 
2891  // Record the path
2892  //
2893  if (sslcadir) free(sslcadir);
2894  sslcadir = strdup(val);
2895 
2896  if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2897  return 0;
2898 }
2899 
2900 /******************************************************************************/
2901 /* x s s l c i p h e r f i l t e r */
2902 /******************************************************************************/
2903 
2904 /* Function: xsslcipherfilter
2905 
2906  Purpose: To parse the directive: cipherfilter <filter>
2907 
2908  <filter> the filter string to be used when generating
2909  the SSL cipher list
2910 
2911  Output: 0 upon success or !0 upon failure.
2912  */
2913 
2914 int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2915  char *val;
2916 
2917  // Get the filter string
2918  //
2919  val = Config.GetWord();
2920  if (!val || !val[0]) {
2921  eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2922  return 1;
2923  }
2924 
2925  // Record the filter string
2926  //
2927  if (sslcipherfilter) free(sslcipherfilter);
2928  sslcipherfilter = strdup(val);
2929 
2930  return 0;
2931 }
2932 
2933 /******************************************************************************/
2934 /* x t l s r e u s e */
2935 /******************************************************************************/
2936 
2937 /* Function: xtlsreuse
2938 
2939  Purpose: To parse the directive: tlsreuse {on | off}
2940 
2941  Output: 0 upon success or 1 upon failure.
2942  */
2943 
2944 int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2945 
2946  char *val;
2947 
2948 // Get the argument
2949 //
2950  val = Config.GetWord();
2951  if (!val || !val[0])
2952  {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2953 
2954 // If it's off, we set it off
2955 //
2956  if (!strcmp(val, "off"))
2958  return 0;
2959  }
2960 
2961 // If it's on we set it on.
2962 //
2963  if (!strcmp(val, "on"))
2965  return 0;
2966  }
2967 
2968 // Bad argument
2969 //
2970  eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2971  return 1;
2972 }
2973 
2974 int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) {
2975  auto val = Config.GetWord();
2976  if (!val || !val[0])
2977  {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;}
2978 
2979  if (!strcmp(val, "off"))
2980  {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOff;
2981  return 0;
2982  }
2983  if (!strcmp(val, "on"))
2984  {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOn;
2985  return 0;
2986  }
2987 
2988  eDest.Emsg("config", "invalid tlsclientauth parameter -", val);
2989  return 1;
2990 }
2991 
2992 int XrdHttpProtocol::xauth(XrdOucStream &Config) {
2993  char *val = Config.GetWord();
2994  if(val) {
2995  if(!strcmp("tpc",val)) {
2996  if(!(val = Config.GetWord())) {
2997  eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
2998  } else {
2999  if(!strcmp("fcreds",val)) {
3000  tpcForwardCreds = true;
3001  } else {
3002  eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
3003  }
3004  }
3005  } else {
3006  eDest.Emsg("Config", "http.auth value is invalid"); return 1;
3007  }
3008  }
3009  return 0;
3010 }
3011 
3012 /******************************************************************************/
3013 /* x t r a c e */
3014 /******************************************************************************/
3015 
3016 /* Function: xtrace
3017 
3018  Purpose: To parse the directive: trace <events>
3019 
3020  <events> the blank separated list of events to trace. Trace
3021  directives are cumulative.
3022 
3023  Output: 0 upon success or 1 upon failure.
3024  */
3025 
3026 int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
3027 
3028  char *val;
3029 
3030  static struct traceopts {
3031  const char *opname;
3032  int opval;
3033  } tropts[] = {
3034  {"all", TRACE_ALL},
3035  {"auth", TRACE_AUTH},
3036  {"debug", TRACE_DEBUG},
3037  {"mem", TRACE_MEM},
3038  {"redirect", TRACE_REDIR},
3039  {"request", TRACE_REQ},
3040  {"response", TRACE_RSP}
3041  };
3042  int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3043 
3044  if (!(val = Config.GetWord())) {
3045  eDest.Emsg("config", "trace option not specified");
3046  return 1;
3047  }
3048  while (val) {
3049  if (!strcmp(val, "off")) trval = 0;
3050  else {
3051  if ((neg = (val[0] == '-' && val[1]))) val++;
3052  for (i = 0; i < numopts; i++) {
3053  if (!strcmp(val, tropts[i].opname)) {
3054  if (neg) trval &= ~tropts[i].opval;
3055  else trval |= tropts[i].opval;
3056  break;
3057  }
3058  }
3059  if (i >= numopts)
3060  eDest.Emsg("config", "invalid trace option", val);
3061  }
3062  val = Config.GetWord();
3063  }
3064  XrdHttpTrace.What = trval;
3065  return 0;
3066 }
3067 
3068 int XrdHttpProtocol::doStat(char *fname) {
3069  int l;
3070  bool b;
3071  CurrentReq.filesize = 0;
3072  CurrentReq.fileflags = 0;
3073  CurrentReq.filemodtime = 0;
3074 
3075  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3077  memset(CurrentReq.xrdreq.stat.reserved, 0,
3078  sizeof (CurrentReq.xrdreq.stat.reserved));
3079  l = strlen(fname) + 1;
3080  CurrentReq.xrdreq.stat.dlen = htonl(l);
3081 
3082  if (!Bridge) return -1;
3083  b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3084  if (!b) {
3085  return -1;
3086  }
3087 
3088 
3089  return 0;
3090 }
3091 
3092 /******************************************************************************/
3093 /* d o C h k s u m */
3094 /******************************************************************************/
3095 
3097  size_t length;
3098  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3102  memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
3104  length = fname.length() + 1;
3105  CurrentReq.xrdreq.query.dlen = htonl(length);
3106 
3107  if (!Bridge) return -1;
3108 
3109  return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3110 }
3111 
3112 
3113 static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3114 
3115 // Loads the SecXtractor plugin, if available
3116 int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3117  const char *libParms) {
3118 
3119 
3120  // We don't want to load it more than once
3121  if (secxtractor) return 1;
3122 
3123  XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3125 
3126  // Get the entry point of the object creator
3127  //
3128  ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3129  if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3130  myLib.Unload();
3131  return 1;
3132 }
3133 /******************************************************************************/
3134 /* L o a d E x t H a n d l e r */
3135 /******************************************************************************/
3136 
3137 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3138  for (int i = 0; i < (int) hiVec.size(); i++) {
3139  if(hiVec[i].extHNoTlsOK) {
3140  // The external plugin does not need TLS to be loaded
3141  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3142  hiVec[i].extHParm.c_str(), &myEnv,
3143  hiVec[i].extHName.c_str()))
3144  return 1;
3145  }
3146  }
3147  return 0;
3148 }
3149 
3150 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3151  const char *cFN, XrdOucEnv &myEnv) {
3152 
3153  // Add the pointer to the cadir and the cakey to the environment.
3154  //
3155  if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3156  if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3157  if (sslcert) myEnv.Put("http.cert", sslcert);
3158  if (sslkey) myEnv.Put("http.key" , sslkey);
3159 
3160  // Load all of the specified external handlers.
3161  //
3162  for (int i = 0; i < (int)hiVec.size(); i++) {
3163  // Only load the external handlers that were not already loaded
3164  // by LoadExtHandlerNoTls(...)
3165  if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3166  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3167  hiVec[i].extHParm.c_str(), &myEnv,
3168  hiVec[i].extHName.c_str())) return 1;
3169  }
3170  }
3171  return 0;
3172 }
3173 
3174 // Loads the external handler plugin, if available
3175 int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3176  const char *configFN, const char *libParms,
3177  XrdOucEnv *myEnv, const char *instName) {
3178 
3179 
3180  // This function will avoid loading doubles. No idea why this happens
3181  if (ExtHandlerLoaded(instName)) {
3182  eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3183  return 1;
3184  }
3185  if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3186  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3187  return 1;
3188  }
3189 
3190  XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3192 
3193  // Get the entry point of the object creator
3194  //
3195  ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3196 
3197  XrdHttpExtHandler *newhandler;
3198  if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3199 
3200  // Handler has been loaded, it's the last one in the list
3201  strncpy( exthandler[exthandlercnt].name, instName, 16 );
3202  exthandler[exthandlercnt].name[15] = '\0';
3203  exthandler[exthandlercnt++].ptr = newhandler;
3204 
3205  return 0;
3206  }
3207 
3208  myLib.Unload();
3209  return 1;
3210 }
3211 
3212 
3213 
3214 // Tells if we have already loaded a certain exthandler. Try to
3215 // privilege speed, as this func may be invoked pretty often
3216 bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3217  for (int i = 0; i < exthandlercnt; i++) {
3218  if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3219  return true;
3220  }
3221  }
3222  return false;
3223 }
3224 
3225 // Locates a matching external handler for a given request, if available. Try to
3226 // privilege speed, as this func is invoked for every incoming request
3227 XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3228 
3229  for (int i = 0; i < exthandlercnt; i++) {
3230  if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3231  return exthandler[i].ptr;
3232  }
3233  }
3234  return NULL;
3235 }
#define kXR_isManager
Definition: XProtocol.hh:1156
kXR_unt16 requestid
Definition: XProtocol.hh:630
kXR_char reserved1[2]
Definition: XProtocol.hh:632
struct ClientSetRequest set
Definition: XProtocol.hh:871
kXR_char reserved[11]
Definition: XProtocol.hh:770
kXR_unt16 infotype
Definition: XProtocol.hh:631
kXR_char reserved2[8]
Definition: XProtocol.hh:634
kXR_char fhandle[4]
Definition: XProtocol.hh:633
@ kXR_query
Definition: XProtocol.hh:113
@ kXR_set
Definition: XProtocol.hh:130
@ kXR_stat
Definition: XProtocol.hh:129
kXR_unt16 requestid
Definition: XProtocol.hh:719
#define kXR_isServer
Definition: XProtocol.hh:1157
struct ClientQueryRequest query
Definition: XProtocol.hh:866
kXR_unt16 requestid
Definition: XProtocol.hh:768
struct ClientStatRequest stat
Definition: XProtocol.hh:873
kXR_int32 dlen
Definition: XProtocol.hh:722
kXR_int32 dlen
Definition: XProtocol.hh:772
kXR_char modifier
Definition: XProtocol.hh:721
@ kXR_Qcksum
Definition: XProtocol.hh:617
kXR_char reserved[15]
Definition: XProtocol.hh:720
int kXR_int32
Definition: XPtypes.hh:89
short kXR_int16
Definition: XPtypes.hh:66
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
bool usingEC
#define XrdHttpExtHandlerArgs
int BIO_get_init(BIO *bio)
int BIO_get_shutdown(BIO *bio)
int BIO_get_flags(BIO *bio)
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
void BIO_set_init(BIO *bio, int init)
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
void BIO_set_shutdown(BIO *bio, int shut)
#define TS_Xeq(x, m)
XrdSysTrace XrdHttpTrace("http")
void * BIO_get_data(BIO *bio)
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
void BIO_set_data(BIO *bio, void *ptr)
#define TS_Xeq3(x, m)
static int BIO_XrdLink_destroy(BIO *bio)
#define XRHTTP_TK_GRACETIME
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
void BIO_set_flags(BIO *bio, int flags)
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
Trace definitions.
#define TRACE_AUTH
Definition: XrdHttpTrace.hh:48
#define TRACE_REQ
Definition: XrdHttpTrace.hh:51
#define TRACE_RSP
Definition: XrdHttpTrace.hh:53
#define TRACE_REDIR
Definition: XrdHttpTrace.hh:52
int compareHash(const char *h1, const char *h2)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
Utility functions for XrdHTTP.
std::string decode_str(const std::string &str)
std::string obfuscateAuth(const std::string &input)
int fclose(FILE *stream)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:48
#define fstat(a, b)
Definition: XrdPosix.hh:62
#define open
Definition: XrdPosix.hh:76
#define stat(a, b)
Definition: XrdPosix.hh:101
#define eMsg(x)
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
#define TRACE_DEBUG
Definition: XrdTrace.hh:36
#define TRACE_MEM
Definition: XrdTrace.hh:38
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
void Release(XrdBuffer *bp)
Definition: XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition: XrdBuffer.cc:140
int bsize
Definition: XrdBuffer.hh:46
char * buff
Definition: XrdBuffer.hh:45
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static char * sslcafile
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static XrdSysError eDest
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
static char * sslkey
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
static char * sslcadir
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static std::unordered_map< std::string, std::vector< std::pair< std::string, std::string > > > m_staticheader_map
The static headers to always return; map is from verb to a list of (header, val) pairs.
static bool isRequiredGridmap
static char * listredir
Url to redirect to in the case a listing is requested.
int Stats(char *buff, int blen, int do_sync=0)
Get activity stats.
static std::unordered_map< std::string, std::string > m_staticheaders
XrdHttpReq CurrentReq
static int crlRefIntervalSec
CRL thread refresh interval.
static int Port
Our port.
static XrdHttpReadRangeHandler::Configuration ReadRangeConfig
configuration for the read range handler
static XrdSecService * CIA
static XrdBuffManager * BPool
static bool tpcForwardCreds
If set to true, the HTTP TPC transfers will forward the credentials to redirected hosts.
int Process(XrdLink *lp)
Process data incoming from the socket.
XrdHttpProtocol(const XrdHttpProtocol &)=default
Ctor, dtors and copy ctor.
static bool listdeny
If true, any form of listing is denied.
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
XrdSecEntity SecEntity
Authentication area.
static bool embeddedstatic
If true, use the embedded css and icons.
static int sslverifydepth
Depth of verification of a certificate chain.
static int Configure(char *parms, XrdProtocol_Config *pi)
Read and apply the configuration.
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
int reqstate
State machine to talk to the bridge.
Definition: XrdHttpReq.hh:353
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:271
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:279
std::string requestverb
Definition: XrdHttpReq.hh:264
ReqType request
The request we got.
Definition: XrdHttpReq.hh:263
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:936
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:273
long fileflags
Definition: XrdHttpReq.hh:343
long filemodtime
Definition: XrdHttpReq.hh:344
int parseFirstLine(char *line, int len)
Parse the first line of the header.
Definition: XrdHttpReq.cc:261
int parseLine(char *line, int len)
Parse the header.
Definition: XrdHttpReq.cc:116
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
Definition: XrdHttpReq.cc:635
long long filesize
Definition: XrdHttpReq.hh:342
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:327
const std::string & userAgent() const
Definition: XrdHttpReq.hh:259
virtual void reset()
Definition: XrdHttpReq.cc:2813
virtual int InitSSL(SSL *, char *)
virtual int FreeSSL(SSL *)
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
void SetDialect(const char *dP)
Definition: XrdNetAddr.hh:205
void SetTLS(bool val)
Definition: XrdNetAddr.cc:590
void Set(int inQMax, time_t agemax=1800)
Definition: XrdObject.icc:90
void Push(XrdObject< T > *Node)
Definition: XrdObject.hh:101
T * Pop()
Definition: XrdObject.hh:93
static bool Import(const char *var, char *&val)
Definition: XrdOucEnv.cc:222
void * GetPtr(const char *varname)
Definition: XrdOucEnv.cc:281
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
int length() const
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.