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