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