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