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