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  std::string traceLine = tmpline.c_str();
643  if (TRACING(TRACE_DEBUG)) {
644  traceLine = obfuscateAuth(traceLine);
645  }
646  TRACE(DEBUG, " rc:" << rc << " got hdr line: " << traceLine);
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: " << traceLine.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  int fd = open(val, O_RDONLY);
2325 
2326  if ( fd == -1 ) {
2327  eDest.Emsg("Config", errno, "open shared secret key file", val);
2328  return 1;
2329  }
2330 
2331  if ( fstat(fd, &st) != 0 ) {
2332  eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2333  close(fd);
2334  return 1;
2335  }
2336 
2337  if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2338  eDest.Emsg("Config",
2339  "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2340  close(fd);
2341  return 1;
2342  }
2343 
2344  FILE *fp = fdopen(fd, "r");
2345 
2346  if ( fp == nullptr ) {
2347  eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2348  close(fd);
2349  return 1;
2350  }
2351 
2352  char line[1024];
2353  while( fgets(line, 1024, fp) ) {
2354  char *pp;
2355 
2356  // Trim the end
2357  pp = line + strlen(line) - 1;
2358  while ( (pp >= line) && (!isalnum(*pp)) ) {
2359  *pp = '\0';
2360  pp--;
2361  }
2362 
2363  // Trim the beginning
2364  pp = line;
2365  while ( *pp && !isalnum(*pp) ) pp++;
2366 
2367  if ( strlen(pp) >= 32 ) {
2368  eDest.Say("Config", "Secret key loaded.");
2369  // Record the path
2370  if (secretkey) free(secretkey);
2371  secretkey = strdup(pp);
2372 
2373  fclose(fp);
2374  return 0;
2375  }
2376 
2377  }
2378 
2379  fclose(fp);
2380  eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2381  return 1;
2382 
2383  }
2384 
2385  if ( strlen(val) < 32 ) {
2386  eDest.Emsg("Config", "Secret key is too short");
2387  return 1;
2388  }
2389 
2390  // Record the path
2391  if (secretkey) free(secretkey);
2392  secretkey = strdup(val);
2393  if (!inFile) Config.noEcho();
2394 
2395  return 0;
2396 }
2397 
2398 /******************************************************************************/
2399 /* x l i s t d e n y */
2400 /******************************************************************************/
2401 
2402 /* Function: xlistdeny
2403 
2404  Purpose: To parse the directive: listingdeny <yes|no|0|1>
2405 
2406  <val> makes this redirector deny listings with an error
2407 
2408  Output: 0 upon success or !0 upon failure.
2409  */
2410 
2411 int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2412  char *val;
2413 
2414  // Get the path
2415  //
2416  val = Config.GetWord();
2417  if (!val || !val[0]) {
2418  eDest.Emsg("Config", "listingdeny flag not specified");
2419  return 1;
2420  }
2421 
2422  // Record the value
2423  //
2424  listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2425 
2426 
2427  return 0;
2428 }
2429 
2430 /******************************************************************************/
2431 /* x l i s t r e d i r */
2432 /******************************************************************************/
2433 
2434 /* Function: xlistredir
2435 
2436  Purpose: To parse the directive: listingredir <Url>
2437 
2438  <Url> http/https server to redirect to in the case of listing
2439 
2440  Output: 0 upon success or !0 upon failure.
2441  */
2442 
2443 int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2444  char *val;
2445 
2446  // Get the path
2447  //
2448  val = Config.GetWord();
2449  if (!val || !val[0]) {
2450  eDest.Emsg("Config", "listingredir flag not specified");
2451  return 1;
2452  }
2453 
2454  // Record the value
2455  //
2456  if (listredir) free(listredir);
2457  listredir = strdup(val);
2458 
2459 
2460  return 0;
2461 }
2462 
2463 /******************************************************************************/
2464 /* x s s l d e s t h t t p s */
2465 /******************************************************************************/
2466 
2467 /* Function: xdesthttps
2468 
2469  Purpose: To parse the directive: desthttps <yes|no|0|1>
2470 
2471  <val> makes this redirector produce http or https redirection targets
2472 
2473  Output: 0 upon success or !0 upon failure.
2474  */
2475 
2476 int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2477  char *val;
2478 
2479  // Get the path
2480  //
2481  val = Config.GetWord();
2482  if (!val || !val[0]) {
2483  eDest.Emsg("Config", "desthttps flag not specified");
2484  return 1;
2485  }
2486 
2487  // Record the value
2488  //
2489  isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2490 
2491 
2492  return 0;
2493 }
2494 
2495 /******************************************************************************/
2496 /* x e m b e d d e d s t a t i c */
2497 /******************************************************************************/
2498 
2499 /* Function: xembeddedstatic
2500 
2501  Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2502 
2503  <val> this server will redirect HTTPS to itself using HTTP+token
2504 
2505  Output: 0 upon success or !0 upon failure.
2506  */
2507 
2508 int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2509  char *val;
2510 
2511  // Get the path
2512  //
2513  val = Config.GetWord();
2514  if (!val || !val[0]) {
2515  eDest.Emsg("Config", "embeddedstatic flag not specified");
2516  return 1;
2517  }
2518 
2519  // Record the value
2520  //
2521  embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2522 
2523 
2524  return 0;
2525 }
2526 
2527 /******************************************************************************/
2528 /* x r e d i r s t a t i c */
2529 /******************************************************************************/
2530 
2531 /* Function: xstaticredir
2532 
2533  Purpose: To parse the directive: staticredir <Url>
2534 
2535  <Url> http/https server to redirect to in the case of /static
2536 
2537  Output: 0 upon success or !0 upon failure.
2538  */
2539 
2540 int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2541  char *val;
2542 
2543  // Get the path
2544  //
2545  val = Config.GetWord();
2546  if (!val || !val[0]) {
2547  eDest.Emsg("Config", "staticredir url not specified");
2548  return 1;
2549  }
2550 
2551  // Record the value
2552  //
2553  if (staticredir) free(staticredir);
2554  staticredir = strdup(val);
2555 
2556  return 0;
2557 }
2558 
2559 /******************************************************************************/
2560 /* x p r e l o a d s t a t i c */
2561 /******************************************************************************/
2562 
2563 /* Function: xpreloadstatic
2564 
2565  Purpose: To parse the directive: preloadstatic <http url path> <local file>
2566 
2567  <http url path> http/http path whose response we are preloading
2568  e.g. /static/mycss.css
2569  NOTE: this must start with /static
2570 
2571 
2572  Output: 0 upon success or !0 upon failure.
2573  */
2574 
2575 int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2576  char *val, *k, key[1024];
2577 
2578  // Get the key
2579  //
2580  k = Config.GetWord();
2581  if (!k || !k[0]) {
2582  eDest.Emsg("Config", "preloadstatic urlpath not specified");
2583  return 1;
2584  }
2585 
2586  strcpy(key, k);
2587 
2588  // Get the val
2589  //
2590  val = Config.GetWord();
2591  if (!val || !val[0]) {
2592  eDest.Emsg("Config", "preloadstatic filename not specified");
2593  return 1;
2594  }
2595 
2596  // Try to load the file into memory
2597  int fp = open(val, O_RDONLY);
2598  if( fp < 0 ) {
2599  eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2600  return 1;
2601  }
2602 
2603  StaticPreloadInfo *nfo = new StaticPreloadInfo;
2604  // Max 64Kb ok?
2605  nfo->data = (char *)malloc(65536);
2606  nfo->len = read(fp, (void *)nfo->data, 65536);
2607  close(fp);
2608 
2609  if (nfo->len <= 0) {
2610  eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2611  return 1;
2612  }
2613 
2614  if (nfo->len >= 65536) {
2615  eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2616  return 1;
2617  }
2618 
2619  // Record the value
2620  //
2621  if (!staticpreload)
2623 
2624  staticpreload->Rep((const char *)key, nfo);
2625  return 0;
2626 }
2627 
2628 /******************************************************************************/
2629 /* x s e l f h t t p s 2 h t t p */
2630 /******************************************************************************/
2631 
2632 /* Function: selfhttps2http
2633 
2634  Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2635 
2636  <val> this server will redirect HTTPS to itself using HTTP+token
2637 
2638  Output: 0 upon success or !0 upon failure.
2639  */
2640 
2641 int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2642  char *val;
2643 
2644  // Get the path
2645  //
2646  val = Config.GetWord();
2647  if (!val || !val[0]) {
2648  eDest.Emsg("Config", "selfhttps2http flag not specified");
2649  return 1;
2650  }
2651 
2652  // Record the value
2653  //
2654  selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2655 
2656 
2657  return 0;
2658 }
2659 
2660 /******************************************************************************/
2661 /* x s e c x t r a c t o r */
2662 /******************************************************************************/
2663 
2664 /* Function: xsecxtractor
2665 
2666  Purpose: To parse the directive: secxtractor [required] <path> <params>
2667 
2668  required optional parameter which if present treats any secxtractor
2669  errors as fatal.
2670  <path> the path of the plugin to be loaded
2671  <params> parameters passed to the secxtractor library
2672 
2673  Output: 0 upon success or !0 upon failure.
2674  */
2675 
2676 int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2677  char *val;
2678 
2679  // Get the path
2680  //
2681  val = Config.GetWord();
2682  if (!val || !val[0]) {
2683  eDest.Emsg("Config", "No security extractor plugin specified.");
2684  return 1;
2685  } else {
2686  // Handle optional parameter [required]
2687  //
2688  if (!strncmp(val, "required", 8)) {
2689  isRequiredXtractor = true;
2690  val = Config.GetWord();
2691 
2692  if (!val || !val[0]) {
2693  eDest.Emsg("Config", "No security extractor plugin after [required] "
2694  "parameter");
2695  return 1;
2696  }
2697  }
2698 
2699  char libName[4096];
2700  strlcpy(libName, val, sizeof(libName));
2701  libName[sizeof(libName) - 1] = '\0';
2702  char libParms[4096];
2703 
2704  if (!Config.GetRest(libParms, 4095)) {
2705  eDest.Emsg("Config", "secxtractor config params longer than 4k");
2706  return 1;
2707  }
2708 
2709  // Try to load the plugin (if available) that extracts info from the
2710  // user cert/proxy
2711  if (LoadSecXtractor(&eDest, libName, libParms)) {
2712  return 1;
2713  }
2714  }
2715 
2716  return 0;
2717 }
2718 
2719 /******************************************************************************/
2720 /* x e x t h a n d l e r */
2721 /******************************************************************************/
2722 
2723 /* Function: xexthandler
2724  *
2725  * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2726  *
2727  * <name> a unique name (max 16chars) to be given to this
2728  * instance, e.g 'myhandler1'
2729  * <path> the path of the plugin to be loaded
2730  * <initparm> a string parameter (e.g. a config file) that is
2731  * passed to the initialization of the plugin
2732  *
2733  * Output: 0 upon success or !0 upon failure.
2734  */
2735 
2736 int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2737  std::vector<extHInfo> &hiVec) {
2738  char *val, path[1024], namebuf[1024];
2739  char *parm;
2740  // By default, every external handler need TLS configured to be loaded
2741  bool noTlsOK = false;
2742 
2743  // Get the name
2744  //
2745  val = Config.GetWord();
2746  if (!val || !val[0]) {
2747  eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2748  return 1;
2749  }
2750  if (strlen(val) >= 16) {
2751  eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2752  return 1;
2753  }
2754  strncpy(namebuf, val, sizeof(namebuf));
2755  namebuf[ sizeof(namebuf)-1 ] = '\0';
2756 
2757  // Get the +notls option if it was provided
2758  val = Config.GetWord();
2759 
2760  if(val && !strcmp("+notls",val)) {
2761  noTlsOK = true;
2762  val = Config.GetWord();
2763  }
2764 
2765  // Get the path
2766  //
2767  if (!val || !val[0]) {
2768  eDest.Emsg("Config", "No http external handler plugin specified.");
2769  return 1;
2770  }
2771  if (strlen(val) >= (int)sizeof(path)) {
2772  eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2773  return 1;
2774  }
2775 
2776  strcpy(path, val);
2777 
2778  // Everything else is a free string
2779  //
2780  parm = Config.GetWord();
2781 
2782  // Verify whether this is a duplicate (we never supported replacements)
2783  //
2784  for (int i = 0; i < (int)hiVec.size(); i++)
2785  {if (hiVec[i].extHName == namebuf) {
2786  eDest.Emsg("Config", "Instance name already present for "
2787  "http external handler plugin",
2788  hiVec[i].extHPath.c_str());
2789  return 1;
2790  }
2791  }
2792 
2793  // Verify that we don't have more already than we are allowed to have
2794  //
2795  if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2796  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2797  return 1;
2798  }
2799 
2800  // Create an info struct and push it on the list of ext handlers to load
2801  //
2802  hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2803 
2804  return 0;
2805 }
2806 
2807 /******************************************************************************/
2808 /* x h e a d e r 2 c g i */
2809 /******************************************************************************/
2810 
2811 /* Function: xheader2cgi
2812  *
2813  * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2814  *
2815  * <headerkey> the name of an incoming HTTP header
2816  * to be transformed
2817  * <cgikey> the name to be given when adding it to the cgi info
2818  * that is kept only internally
2819  *
2820  * Output: 0 upon success or !0 upon failure.
2821  */
2822 
2823 int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2825 }
2826 
2827 /******************************************************************************/
2828 /* x s s l c a d i r */
2829 /******************************************************************************/
2830 
2831 /* Function: xsslcadir
2832 
2833  Purpose: To parse the directive: sslcadir <path>
2834 
2835  <path> the path of the server key to be used.
2836 
2837  Output: 0 upon success or !0 upon failure.
2838  */
2839 
2840 int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2841  char *val;
2842 
2843  // Get the path
2844  //
2845  val = Config.GetWord();
2846  if (!val || !val[0]) {
2847  eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2848  return 1;
2849  }
2850 
2851  // Record the path
2852  //
2853  if (sslcadir) free(sslcadir);
2854  sslcadir = strdup(val);
2855 
2856  if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2857  return 0;
2858 }
2859 
2860 /******************************************************************************/
2861 /* x s s l c i p h e r f i l t e r */
2862 /******************************************************************************/
2863 
2864 /* Function: xsslcipherfilter
2865 
2866  Purpose: To parse the directive: cipherfilter <filter>
2867 
2868  <filter> the filter string to be used when generating
2869  the SSL cipher list
2870 
2871  Output: 0 upon success or !0 upon failure.
2872  */
2873 
2874 int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2875  char *val;
2876 
2877  // Get the filter string
2878  //
2879  val = Config.GetWord();
2880  if (!val || !val[0]) {
2881  eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2882  return 1;
2883  }
2884 
2885  // Record the filter string
2886  //
2887  if (sslcipherfilter) free(sslcipherfilter);
2888  sslcipherfilter = strdup(val);
2889 
2890  return 0;
2891 }
2892 
2893 /******************************************************************************/
2894 /* x t l s r e u s e */
2895 /******************************************************************************/
2896 
2897 /* Function: xtlsreuse
2898 
2899  Purpose: To parse the directive: tlsreuse {on | off}
2900 
2901  Output: 0 upon success or 1 upon failure.
2902  */
2903 
2904 int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2905 
2906  char *val;
2907 
2908 // Get the argument
2909 //
2910  val = Config.GetWord();
2911  if (!val || !val[0])
2912  {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2913 
2914 // If it's off, we set it off
2915 //
2916  if (!strcmp(val, "off"))
2918  return 0;
2919  }
2920 
2921 // If it's on we set it on.
2922 //
2923  if (!strcmp(val, "on"))
2925  return 0;
2926  }
2927 
2928 // Bad argument
2929 //
2930  eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2931  return 1;
2932 }
2933 
2934 int XrdHttpProtocol::xtlsclientauth(XrdOucStream &Config) {
2935  auto val = Config.GetWord();
2936  if (!val || !val[0])
2937  {eDest.Emsg("Config", "tlsclientauth argument not specified"); return 1;}
2938 
2939  if (!strcmp(val, "off"))
2940  {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOff;
2941  return 0;
2942  }
2943  if (!strcmp(val, "on"))
2944  {tlsClientAuth = XrdTlsContext::ClientAuthSetting::kOn;
2945  return 0;
2946  }
2947  if (!strcmp(val, "defer"))
2948  {
2949 #if OPENSSL_VERSION_NUMBER >= 0x10100010L
2950  tlsClientAuth = XrdTlsContext::ClientAuthSetting::kDefer;
2951  return 0;
2952 #else
2953  eDest.Emsg("config", "http.tlsclientauth defer is not supported on this platform");
2954  return 1;
2955 #endif
2956  }
2957 
2958  eDest.Emsg("config", "invalid tlsclientauth parameter -", val);
2959  return 1;
2960 }
2961 
2962 int XrdHttpProtocol::xtlsrequiredprefix(XrdOucStream &Config) {
2963  auto val = Config.GetWord();
2964  if (!val || !val[0])
2965  {eDest.Emsg("Config", "tlsrequiredprefix argument not specified"); return 1;}
2966 
2967  if (val[0] != '/')
2968  {eDest.Emsg("Config", "http.tlsrequiredprefix argument must be an absolute path"); return 1;}
2969 
2970  tlsAuthRequestPrefixes.push_back(val);
2971  return 0;
2972 }
2973 
2974 int XrdHttpProtocol::xauth(XrdOucStream &Config) {
2975  char *val = Config.GetWord();
2976  if(val) {
2977  if(!strcmp("tpc",val)) {
2978  if(!(val = Config.GetWord())) {
2979  eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
2980  } else {
2981  if(!strcmp("fcreds",val)) {
2982  tpcForwardCreds = true;
2983  } else {
2984  eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
2985  }
2986  }
2987  } else {
2988  eDest.Emsg("Config", "http.auth value is invalid"); return 1;
2989  }
2990  }
2991  return 0;
2992 }
2993 
2994 /******************************************************************************/
2995 /* x t r a c e */
2996 /******************************************************************************/
2997 
2998 /* Function: xtrace
2999 
3000  Purpose: To parse the directive: trace <events>
3001 
3002  <events> the blank separated list of events to trace. Trace
3003  directives are cumulative.
3004 
3005  Output: 0 upon success or 1 upon failure.
3006  */
3007 
3008 int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
3009 
3010  char *val;
3011 
3012  static struct traceopts {
3013  const char *opname;
3014  int opval;
3015  } tropts[] = {
3016  {"all", TRACE_ALL},
3017  {"auth", TRACE_AUTH},
3018  {"debug", TRACE_DEBUG},
3019  {"mem", TRACE_MEM},
3020  {"redirect", TRACE_REDIR},
3021  {"request", TRACE_REQ},
3022  {"response", TRACE_RSP}
3023  };
3024  int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
3025 
3026  if (!(val = Config.GetWord())) {
3027  eDest.Emsg("config", "trace option not specified");
3028  return 1;
3029  }
3030  while (val) {
3031  if (!strcmp(val, "off")) trval = 0;
3032  else {
3033  if ((neg = (val[0] == '-' && val[1]))) val++;
3034  for (i = 0; i < numopts; i++) {
3035  if (!strcmp(val, tropts[i].opname)) {
3036  if (neg) trval &= ~tropts[i].opval;
3037  else trval |= tropts[i].opval;
3038  break;
3039  }
3040  }
3041  if (i >= numopts)
3042  eDest.Emsg("config", "invalid trace option", val);
3043  }
3044  val = Config.GetWord();
3045  }
3046  XrdHttpTrace.What = trval;
3047  return 0;
3048 }
3049 
3050 int XrdHttpProtocol::doStat(char *fname) {
3051  int l;
3052  bool b;
3053  CurrentReq.filesize = 0;
3054  CurrentReq.fileflags = 0;
3055  CurrentReq.filemodtime = 0;
3056 
3057  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3059  memset(CurrentReq.xrdreq.stat.reserved, 0,
3060  sizeof (CurrentReq.xrdreq.stat.reserved));
3061  l = strlen(fname) + 1;
3062  CurrentReq.xrdreq.stat.dlen = htonl(l);
3063 
3064  if (!Bridge) return -1;
3065  b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
3066  if (!b) {
3067  return -1;
3068  }
3069 
3070 
3071  return 0;
3072 }
3073 
3074 /******************************************************************************/
3075 /* d o C h k s u m */
3076 /******************************************************************************/
3077 
3079  size_t length;
3080  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
3084  memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
3086  length = fname.length() + 1;
3087  CurrentReq.xrdreq.query.dlen = htonl(length);
3088 
3089  if (!Bridge) return -1;
3090 
3091  return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
3092 }
3093 
3094 
3095 static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
3096 
3097 // Loads the SecXtractor plugin, if available
3098 int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
3099  const char *libParms) {
3100 
3101 
3102  // We don't want to load it more than once
3103  if (secxtractor) return 1;
3104 
3105  XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
3107 
3108  // Get the entry point of the object creator
3109  //
3110  ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
3111  if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
3112  myLib.Unload();
3113  return 1;
3114 }
3115 /******************************************************************************/
3116 /* L o a d E x t H a n d l e r */
3117 /******************************************************************************/
3118 
3119 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
3120  for (int i = 0; i < (int) hiVec.size(); i++) {
3121  if(hiVec[i].extHNoTlsOK) {
3122  // The external plugin does not need TLS to be loaded
3123  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3124  hiVec[i].extHParm.c_str(), &myEnv,
3125  hiVec[i].extHName.c_str()))
3126  return 1;
3127  }
3128  }
3129  return 0;
3130 }
3131 
3132 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3133  const char *cFN, XrdOucEnv &myEnv) {
3134 
3135  // Add the pointer to the cadir and the cakey to the environment.
3136  //
3137  if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3138  if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3139  if (sslcert) myEnv.Put("http.cert", sslcert);
3140  if (sslkey) myEnv.Put("http.key" , sslkey);
3141 
3142  // Load all of the specified external handlers.
3143  //
3144  for (int i = 0; i < (int)hiVec.size(); i++) {
3145  // Only load the external handlers that were not already loaded
3146  // by LoadExtHandlerNoTls(...)
3147  if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3148  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3149  hiVec[i].extHParm.c_str(), &myEnv,
3150  hiVec[i].extHName.c_str())) return 1;
3151  }
3152  }
3153  return 0;
3154 }
3155 
3156 // Loads the external handler plugin, if available
3157 int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3158  const char *configFN, const char *libParms,
3159  XrdOucEnv *myEnv, const char *instName) {
3160 
3161 
3162  // This function will avoid loading doubles. No idea why this happens
3163  if (ExtHandlerLoaded(instName)) {
3164  eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3165  return 1;
3166  }
3167  if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3168  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3169  return 1;
3170  }
3171 
3172  XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3174 
3175  // Get the entry point of the object creator
3176  //
3177  ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3178 
3179  XrdHttpExtHandler *newhandler;
3180  if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3181 
3182  // Handler has been loaded, it's the last one in the list
3183  strncpy( exthandler[exthandlercnt].name, instName, 16 );
3184  exthandler[exthandlercnt].name[15] = '\0';
3185  exthandler[exthandlercnt++].ptr = newhandler;
3186 
3187  return 0;
3188  }
3189 
3190  myLib.Unload();
3191  return 1;
3192 }
3193 
3194 
3195 
3196 // Tells if we have already loaded a certain exthandler. Try to
3197 // privilege speed, as this func may be invoked pretty often
3198 bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3199  for (int i = 0; i < exthandlercnt; i++) {
3200  if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3201  return true;
3202  }
3203  }
3204  return false;
3205 }
3206 
3207 // Locates a matching external handler for a given request, if available. Try to
3208 // privilege speed, as this func is invoked for every incoming request
3209 XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3210 
3211  for (int i = 0; i < exthandlercnt; i++) {
3212  if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3213  return exthandler[i].ptr;
3214  }
3215  }
3216  return NULL;
3217 }
#define kXR_isManager
Definition: XProtocol.hh:1156
kXR_unt16 requestid
Definition: XProtocol.hh:630
kXR_char reserved1[2]
Definition: XProtocol.hh:632
struct ClientSetRequest set
Definition: XProtocol.hh:871
kXR_char reserved[11]
Definition: XProtocol.hh:770
kXR_unt16 infotype
Definition: XProtocol.hh:631
kXR_char reserved2[8]
Definition: XProtocol.hh:634
kXR_char fhandle[4]
Definition: XProtocol.hh:633
@ kXR_query
Definition: XProtocol.hh:113
@ kXR_set
Definition: XProtocol.hh:130
@ kXR_stat
Definition: XProtocol.hh:129
kXR_unt16 requestid
Definition: XProtocol.hh:719
#define kXR_isServer
Definition: XProtocol.hh:1157
struct ClientQueryRequest query
Definition: XProtocol.hh:866
kXR_unt16 requestid
Definition: XProtocol.hh:768
struct ClientStatRequest stat
Definition: XProtocol.hh:873
kXR_int32 dlen
Definition: XProtocol.hh:722
kXR_int32 dlen
Definition: XProtocol.hh:772
kXR_char modifier
Definition: XProtocol.hh:721
@ kXR_Qcksum
Definition: XProtocol.hh:617
kXR_char reserved[15]
Definition: XProtocol.hh:720
int kXR_int32
Definition: XPtypes.hh:89
short kXR_int16
Definition: XPtypes.hh:66
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define XrdHttpExtHandlerArgs
int BIO_get_init(BIO *bio)
int BIO_get_shutdown(BIO *bio)
int BIO_get_flags(BIO *bio)
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
void BIO_set_init(BIO *bio, int init)
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
void BIO_set_shutdown(BIO *bio, int shut)
#define TS_Xeq(x, m)
XrdSysTrace XrdHttpTrace("http")
void * BIO_get_data(BIO *bio)
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
void BIO_set_data(BIO *bio, void *ptr)
#define TS_Xeq3(x, m)
static int BIO_XrdLink_destroy(BIO *bio)
#define XRHTTP_TK_GRACETIME
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
void BIO_set_flags(BIO *bio, int flags)
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
Trace definitions.
#define TRACE_AUTH
Definition: XrdHttpTrace.hh:48
#define TRACE_REQ
Definition: XrdHttpTrace.hh:51
#define TRACE_RSP
Definition: XrdHttpTrace.hh:53
#define TRACE_REDIR
Definition: XrdHttpTrace.hh:52
int compareHash(const char *h1, const char *h2)
char * unquote(char *str)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
Utility functions for XrdHTTP.
std::string obfuscateAuth(const std::string &input)
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int fstat(int fildes, struct stat *buf)
int fclose(FILE *stream)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:43
#define eMsg(x)
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
#define TRACE_DEBUG
Definition: XrdTrace.hh:36
#define TRACE_MEM
Definition: XrdTrace.hh:38
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
void Release(XrdBuffer *bp)
Definition: XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition: XrdBuffer.cc:140
int bsize
Definition: XrdBuffer.hh:46
char * buff
Definition: XrdBuffer.hh:45
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static char * sslcafile
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static XrdSysError eDest
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
static char * sslkey
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
static char * sslcadir
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static 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:320
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:244
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:252
std::string requestverb
Definition: XrdHttpReq.hh:237
ReqType request
The request we got.
Definition: XrdHttpReq.hh:236
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:928
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:246
long fileflags
Definition: XrdHttpReq.hh:310
long filemodtime
Definition: XrdHttpReq.hh:311
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:309
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:294
const std::string & userAgent() const
Definition: XrdHttpReq.hh:210
virtual void reset()
Definition: XrdHttpReq.cc:2735
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.