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