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