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