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  if (TRACING(TRACE_DEBUG)) {
620  std::string traceLine{tmpline.c_str()};
621  traceLine = obfuscateAuth(traceLine);
622  TRACE(DEBUG, " rc:" << rc << " got hdr line: " << traceLine);
623  }
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: " << tmpline.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  if ( stat(val, &st) ) {
2239  eDest.Emsg("Config", errno, "stat shared secret key file", val);
2240  return 1;
2241  }
2242 
2243  if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2244  eDest.Emsg("Config", "For your own security, the shared secret key file cannot be world readable or group writable'", val, "'");
2245  return 1;
2246  }
2247 
2248  FILE *fp = fopen(val,"r");
2249 
2250  if( fp == NULL ) {
2251  eDest.Emsg("Config", errno, "open shared secret key file", val);
2252  return 1;
2253  }
2254 
2255  char line[1024];
2256  while( fgets(line, 1024, fp) ) {
2257  char *pp;
2258 
2259  // Trim the end
2260  pp = line + strlen(line) - 1;
2261  while ( (pp >= line) && (!isalnum(*pp)) ) {
2262  *pp = '\0';
2263  pp--;
2264  }
2265 
2266  // Trim the beginning
2267  pp = line;
2268  while ( *pp && !isalnum(*pp) ) pp++;
2269 
2270  if ( strlen(pp) >= 32 ) {
2271  eDest.Say("Config", "Secret key loaded.");
2272  // Record the path
2273  if (secretkey) free(secretkey);
2274  secretkey = strdup(pp);
2275 
2276  fclose(fp);
2277  return 0;
2278  }
2279 
2280  }
2281 
2282  fclose(fp);
2283  eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2284  return 1;
2285 
2286  }
2287 
2288  if ( strlen(val) < 32 ) {
2289  eDest.Emsg("Config", "Secret key is too short");
2290  return 1;
2291  }
2292 
2293  // Record the path
2294  if (secretkey) free(secretkey);
2295  secretkey = strdup(val);
2296  if (!inFile) Config.noEcho();
2297 
2298  return 0;
2299 }
2300 
2301 /******************************************************************************/
2302 /* x l i s t d e n y */
2303 /******************************************************************************/
2304 
2305 /* Function: xlistdeny
2306 
2307  Purpose: To parse the directive: listingdeny <yes|no|0|1>
2308 
2309  <val> makes this redirector deny listings with an error
2310 
2311  Output: 0 upon success or !0 upon failure.
2312  */
2313 
2314 int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2315  char *val;
2316 
2317  // Get the path
2318  //
2319  val = Config.GetWord();
2320  if (!val || !val[0]) {
2321  eDest.Emsg("Config", "listingdeny flag not specified");
2322  return 1;
2323  }
2324 
2325  // Record the value
2326  //
2327  listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2328 
2329 
2330  return 0;
2331 }
2332 
2333 /******************************************************************************/
2334 /* x l i s t r e d i r */
2335 /******************************************************************************/
2336 
2337 /* Function: xlistredir
2338 
2339  Purpose: To parse the directive: listingredir <Url>
2340 
2341  <Url> http/https server to redirect to in the case of listing
2342 
2343  Output: 0 upon success or !0 upon failure.
2344  */
2345 
2346 int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2347  char *val;
2348 
2349  // Get the path
2350  //
2351  val = Config.GetWord();
2352  if (!val || !val[0]) {
2353  eDest.Emsg("Config", "listingredir flag not specified");
2354  return 1;
2355  }
2356 
2357  // Record the value
2358  //
2359  if (listredir) free(listredir);
2360  listredir = strdup(val);
2361 
2362 
2363  return 0;
2364 }
2365 
2366 /******************************************************************************/
2367 /* x s s l d e s t h t t p s */
2368 /******************************************************************************/
2369 
2370 /* Function: xdesthttps
2371 
2372  Purpose: To parse the directive: desthttps <yes|no|0|1>
2373 
2374  <val> makes this redirector produce http or https redirection targets
2375 
2376  Output: 0 upon success or !0 upon failure.
2377  */
2378 
2379 int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2380  char *val;
2381 
2382  // Get the path
2383  //
2384  val = Config.GetWord();
2385  if (!val || !val[0]) {
2386  eDest.Emsg("Config", "desthttps flag not specified");
2387  return 1;
2388  }
2389 
2390  // Record the value
2391  //
2392  isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2393 
2394 
2395  return 0;
2396 }
2397 
2398 /******************************************************************************/
2399 /* x e m b e d d e d s t a t i c */
2400 /******************************************************************************/
2401 
2402 /* Function: xembeddedstatic
2403 
2404  Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2405 
2406  <val> this server will redirect HTTPS to itself using HTTP+token
2407 
2408  Output: 0 upon success or !0 upon failure.
2409  */
2410 
2411 int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2412  char *val;
2413 
2414  // Get the path
2415  //
2416  val = Config.GetWord();
2417  if (!val || !val[0]) {
2418  eDest.Emsg("Config", "embeddedstatic flag not specified");
2419  return 1;
2420  }
2421 
2422  // Record the value
2423  //
2424  embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2425 
2426 
2427  return 0;
2428 }
2429 
2430 /******************************************************************************/
2431 /* x r e d i r s t a t i c */
2432 /******************************************************************************/
2433 
2434 /* Function: xstaticredir
2435 
2436  Purpose: To parse the directive: staticredir <Url>
2437 
2438  <Url> http/https server to redirect to in the case of /static
2439 
2440  Output: 0 upon success or !0 upon failure.
2441  */
2442 
2443 int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2444  char *val;
2445 
2446  // Get the path
2447  //
2448  val = Config.GetWord();
2449  if (!val || !val[0]) {
2450  eDest.Emsg("Config", "staticredir url not specified");
2451  return 1;
2452  }
2453 
2454  // Record the value
2455  //
2456  if (staticredir) free(staticredir);
2457  staticredir = strdup(val);
2458 
2459  return 0;
2460 }
2461 
2462 /******************************************************************************/
2463 /* x p r e l o a d s t a t i c */
2464 /******************************************************************************/
2465 
2466 /* Function: xpreloadstatic
2467 
2468  Purpose: To parse the directive: preloadstatic <http url path> <local file>
2469 
2470  <http url path> http/http path whose response we are preloading
2471  e.g. /static/mycss.css
2472  NOTE: this must start with /static
2473 
2474 
2475  Output: 0 upon success or !0 upon failure.
2476  */
2477 
2478 int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2479  char *val, *k, key[1024];
2480 
2481  // Get the key
2482  //
2483  k = Config.GetWord();
2484  if (!k || !k[0]) {
2485  eDest.Emsg("Config", "preloadstatic urlpath not specified");
2486  return 1;
2487  }
2488 
2489  strcpy(key, k);
2490 
2491  // Get the val
2492  //
2493  val = Config.GetWord();
2494  if (!val || !val[0]) {
2495  eDest.Emsg("Config", "preloadstatic filename not specified");
2496  return 1;
2497  }
2498 
2499  // Try to load the file into memory
2500  int fp = open(val, O_RDONLY);
2501  if( fp < 0 ) {
2502  eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2503  return 1;
2504  }
2505 
2506  StaticPreloadInfo *nfo = new StaticPreloadInfo;
2507  // Max 64Kb ok?
2508  nfo->data = (char *)malloc(65536);
2509  nfo->len = read(fp, (void *)nfo->data, 65536);
2510  close(fp);
2511 
2512  if (nfo->len <= 0) {
2513  eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2514  return 1;
2515  }
2516 
2517  if (nfo->len >= 65536) {
2518  eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2519  return 1;
2520  }
2521 
2522  // Record the value
2523  //
2524  if (!staticpreload)
2526 
2527  staticpreload->Rep((const char *)key, nfo);
2528  return 0;
2529 }
2530 
2531 /******************************************************************************/
2532 /* x s e l f h t t p s 2 h t t p */
2533 /******************************************************************************/
2534 
2535 /* Function: selfhttps2http
2536 
2537  Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2538 
2539  <val> this server will redirect HTTPS to itself using HTTP+token
2540 
2541  Output: 0 upon success or !0 upon failure.
2542  */
2543 
2544 int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2545  char *val;
2546 
2547  // Get the path
2548  //
2549  val = Config.GetWord();
2550  if (!val || !val[0]) {
2551  eDest.Emsg("Config", "selfhttps2http flag not specified");
2552  return 1;
2553  }
2554 
2555  // Record the value
2556  //
2557  selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2558 
2559 
2560  return 0;
2561 }
2562 
2563 /******************************************************************************/
2564 /* x s e c x t r a c t o r */
2565 /******************************************************************************/
2566 
2567 /* Function: xsecxtractor
2568 
2569  Purpose: To parse the directive: secxtractor [required] <path> <params>
2570 
2571  required optional parameter which if present treats any secxtractor
2572  errors as fatal.
2573  <path> the path of the plugin to be loaded
2574  <params> parameters passed to the secxtractor library
2575 
2576  Output: 0 upon success or !0 upon failure.
2577  */
2578 
2579 int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2580  char *val;
2581 
2582  // Get the path
2583  //
2584  val = Config.GetWord();
2585  if (!val || !val[0]) {
2586  eDest.Emsg("Config", "No security extractor plugin specified.");
2587  return 1;
2588  } else {
2589  // Handle optional parameter [required]
2590  //
2591  if (!strncmp(val, "required", 8)) {
2592  isRequiredXtractor = true;
2593  val = Config.GetWord();
2594 
2595  if (!val || !val[0]) {
2596  eDest.Emsg("Config", "No security extractor plugin after [required] "
2597  "parameter");
2598  return 1;
2599  }
2600  }
2601 
2602  char libName[4096];
2603  strlcpy(libName, val, sizeof(libName));
2604  libName[sizeof(libName) - 1] = '\0';
2605  char libParms[4096];
2606 
2607  if (!Config.GetRest(libParms, 4095)) {
2608  eDest.Emsg("Config", "secxtractor config params longer than 4k");
2609  return 1;
2610  }
2611 
2612  // Try to load the plugin (if available) that extracts info from the
2613  // user cert/proxy
2614  if (LoadSecXtractor(&eDest, libName, libParms)) {
2615  return 1;
2616  }
2617  }
2618 
2619  return 0;
2620 }
2621 
2622 /******************************************************************************/
2623 /* x e x t h a n d l e r */
2624 /******************************************************************************/
2625 
2626 /* Function: xexthandler
2627  *
2628  * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2629  *
2630  * <name> a unique name (max 16chars) to be given to this
2631  * instance, e.g 'myhandler1'
2632  * <path> the path of the plugin to be loaded
2633  * <initparm> a string parameter (e.g. a config file) that is
2634  * passed to the initialization of the plugin
2635  *
2636  * Output: 0 upon success or !0 upon failure.
2637  */
2638 
2639 int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2640  std::vector<extHInfo> &hiVec) {
2641  char *val, path[1024], namebuf[1024];
2642  char *parm;
2643  // By default, every external handler need TLS configured to be loaded
2644  bool noTlsOK = false;
2645 
2646  // Get the name
2647  //
2648  val = Config.GetWord();
2649  if (!val || !val[0]) {
2650  eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2651  return 1;
2652  }
2653  if (strlen(val) >= 16) {
2654  eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2655  return 1;
2656  }
2657  strncpy(namebuf, val, sizeof(namebuf));
2658  namebuf[ sizeof(namebuf)-1 ] = '\0';
2659 
2660  // Get the +notls option if it was provided
2661  val = Config.GetWord();
2662 
2663  if(val && !strcmp("+notls",val)) {
2664  noTlsOK = true;
2665  val = Config.GetWord();
2666  }
2667 
2668  // Get the path
2669  //
2670  if (!val || !val[0]) {
2671  eDest.Emsg("Config", "No http external handler plugin specified.");
2672  return 1;
2673  }
2674  if (strlen(val) >= (int)sizeof(path)) {
2675  eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2676  return 1;
2677  }
2678 
2679  strcpy(path, val);
2680 
2681  // Everything else is a free string
2682  //
2683  parm = Config.GetWord();
2684 
2685  // Verify whether this is a duplicate (we never supported replacements)
2686  //
2687  for (int i = 0; i < (int)hiVec.size(); i++)
2688  {if (hiVec[i].extHName == namebuf) {
2689  eDest.Emsg("Config", "Instance name already present for "
2690  "http external handler plugin",
2691  hiVec[i].extHPath.c_str());
2692  return 1;
2693  }
2694  }
2695 
2696  // Verify that we don't have more already than we are allowed to have
2697  //
2698  if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2699  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2700  return 1;
2701  }
2702 
2703  // Create an info struct and push it on the list of ext handlers to load
2704  //
2705  hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2706 
2707  return 0;
2708 }
2709 
2710 /******************************************************************************/
2711 /* x h e a d e r 2 c g i */
2712 /******************************************************************************/
2713 
2714 /* Function: xheader2cgi
2715  *
2716  * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2717  *
2718  * <headerkey> the name of an incoming HTTP header
2719  * to be transformed
2720  * <cgikey> the name to be given when adding it to the cgi info
2721  * that is kept only internally
2722  *
2723  * Output: 0 upon success or !0 upon failure.
2724  */
2725 
2726 int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2728 }
2729 
2730 /******************************************************************************/
2731 /* x s s l c a d i r */
2732 /******************************************************************************/
2733 
2734 /* Function: xsslcadir
2735 
2736  Purpose: To parse the directive: sslcadir <path>
2737 
2738  <path> the path of the server key to be used.
2739 
2740  Output: 0 upon success or !0 upon failure.
2741  */
2742 
2743 int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2744  char *val;
2745 
2746  // Get the path
2747  //
2748  val = Config.GetWord();
2749  if (!val || !val[0]) {
2750  eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2751  return 1;
2752  }
2753 
2754  // Record the path
2755  //
2756  if (sslcadir) free(sslcadir);
2757  sslcadir = strdup(val);
2758 
2759  if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2760  return 0;
2761 }
2762 
2763 /******************************************************************************/
2764 /* x s s l c i p h e r f i l t e r */
2765 /******************************************************************************/
2766 
2767 /* Function: xsslcipherfilter
2768 
2769  Purpose: To parse the directive: cipherfilter <filter>
2770 
2771  <filter> the filter string to be used when generating
2772  the SSL cipher list
2773 
2774  Output: 0 upon success or !0 upon failure.
2775  */
2776 
2777 int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2778  char *val;
2779 
2780  // Get the filter string
2781  //
2782  val = Config.GetWord();
2783  if (!val || !val[0]) {
2784  eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2785  return 1;
2786  }
2787 
2788  // Record the filter string
2789  //
2790  if (sslcipherfilter) free(sslcipherfilter);
2791  sslcipherfilter = strdup(val);
2792 
2793  return 0;
2794 }
2795 
2796 /******************************************************************************/
2797 /* x t l s r e u s e */
2798 /******************************************************************************/
2799 
2800 /* Function: xtlsreuse
2801 
2802  Purpose: To parse the directive: tlsreuse {on | off}
2803 
2804  Output: 0 upon success or 1 upon failure.
2805  */
2806 
2807 int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2808 
2809  char *val;
2810 
2811 // Get the argument
2812 //
2813  val = Config.GetWord();
2814  if (!val || !val[0])
2815  {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2816 
2817 // If it's off, we set it off
2818 //
2819  if (!strcmp(val, "off"))
2821  return 0;
2822  }
2823 
2824 // If it's on we set it on.
2825 //
2826  if (!strcmp(val, "on"))
2828  return 0;
2829  }
2830 
2831 // Bad argument
2832 //
2833  eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2834  return 1;
2835 }
2836 
2837 int XrdHttpProtocol::xauth(XrdOucStream &Config) {
2838  char *val = Config.GetWord();
2839  if(val) {
2840  if(!strcmp("tpc",val)) {
2841  if(!(val = Config.GetWord())) {
2842  eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
2843  } else {
2844  if(!strcmp("fcreds",val)) {
2845  tpcForwardCreds = true;
2846  } else {
2847  eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
2848  }
2849  }
2850  } else {
2851  eDest.Emsg("Config", "http.auth value is invalid"); return 1;
2852  }
2853  }
2854  return 0;
2855 }
2856 
2857 /******************************************************************************/
2858 /* x t r a c e */
2859 /******************************************************************************/
2860 
2861 /* Function: xtrace
2862 
2863  Purpose: To parse the directive: trace <events>
2864 
2865  <events> the blank separated list of events to trace. Trace
2866  directives are cumulative.
2867 
2868  Output: 0 upon success or 1 upon failure.
2869  */
2870 
2871 int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
2872 
2873  char *val;
2874 
2875  static struct traceopts {
2876  const char *opname;
2877  int opval;
2878  } tropts[] = {
2879  {"all", TRACE_ALL},
2880  {"auth", TRACE_AUTH},
2881  {"debug", TRACE_DEBUG},
2882  {"mem", TRACE_MEM},
2883  {"redirect", TRACE_REDIR},
2884  {"request", TRACE_REQ},
2885  {"response", TRACE_RSP}
2886  };
2887  int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
2888 
2889  if (!(val = Config.GetWord())) {
2890  eDest.Emsg("config", "trace option not specified");
2891  return 1;
2892  }
2893  while (val) {
2894  if (!strcmp(val, "off")) trval = 0;
2895  else {
2896  if ((neg = (val[0] == '-' && val[1]))) val++;
2897  for (i = 0; i < numopts; i++) {
2898  if (!strcmp(val, tropts[i].opname)) {
2899  if (neg) trval &= ~tropts[i].opval;
2900  else trval |= tropts[i].opval;
2901  break;
2902  }
2903  }
2904  if (i >= numopts)
2905  eDest.Emsg("config", "invalid trace option", val);
2906  }
2907  val = Config.GetWord();
2908  }
2909  XrdHttpTrace.What = trval;
2910  return 0;
2911 }
2912 
2913 int XrdHttpProtocol::doStat(char *fname) {
2914  int l;
2915  bool b;
2916  CurrentReq.filesize = 0;
2917  CurrentReq.fileflags = 0;
2918  CurrentReq.filemodtime = 0;
2919 
2920  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
2922  memset(CurrentReq.xrdreq.stat.reserved, 0,
2923  sizeof (CurrentReq.xrdreq.stat.reserved));
2924  l = strlen(fname) + 1;
2925  CurrentReq.xrdreq.stat.dlen = htonl(l);
2926 
2927  if (!Bridge) return -1;
2928  b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
2929  if (!b) {
2930  return -1;
2931  }
2932 
2933 
2934  return 0;
2935 }
2936 
2937 /******************************************************************************/
2938 /* d o C h k s u m */
2939 /******************************************************************************/
2940 
2942  size_t length;
2943  memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
2947  memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
2949  length = fname.length() + 1;
2950  CurrentReq.xrdreq.query.dlen = htonl(length);
2951 
2952  if (!Bridge) return -1;
2953 
2954  return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
2955 }
2956 
2957 
2958 static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
2959 
2960 // Loads the SecXtractor plugin, if available
2961 int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
2962  const char *libParms) {
2963 
2964 
2965  // We don't want to load it more than once
2966  if (secxtractor) return 1;
2967 
2968  XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
2970 
2971  // Get the entry point of the object creator
2972  //
2973  ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
2974  if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
2975  myLib.Unload();
2976  return 1;
2977 }
2978 /******************************************************************************/
2979 /* L o a d E x t H a n d l e r */
2980 /******************************************************************************/
2981 
2982 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
2983  for (int i = 0; i < (int) hiVec.size(); i++) {
2984  if(hiVec[i].extHNoTlsOK) {
2985  // The external plugin does not need TLS to be loaded
2986  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
2987  hiVec[i].extHParm.c_str(), &myEnv,
2988  hiVec[i].extHName.c_str()))
2989  return 1;
2990  }
2991  }
2992  return 0;
2993 }
2994 
2995 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
2996  const char *cFN, XrdOucEnv &myEnv) {
2997 
2998  // Add the pointer to the cadir and the cakey to the environment.
2999  //
3000  if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3001  if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3002  if (sslcert) myEnv.Put("http.cert", sslcert);
3003  if (sslkey) myEnv.Put("http.key" , sslkey);
3004 
3005  // Load all of the specified external handlers.
3006  //
3007  for (int i = 0; i < (int)hiVec.size(); i++) {
3008  // Only load the external handlers that were not already loaded
3009  // by LoadExtHandlerNoTls(...)
3010  if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3011  if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3012  hiVec[i].extHParm.c_str(), &myEnv,
3013  hiVec[i].extHName.c_str())) return 1;
3014  }
3015  }
3016  return 0;
3017 }
3018 
3019 // Loads the external handler plugin, if available
3020 int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3021  const char *configFN, const char *libParms,
3022  XrdOucEnv *myEnv, const char *instName) {
3023 
3024 
3025  // This function will avoid loading doubles. No idea why this happens
3026  if (ExtHandlerLoaded(instName)) {
3027  eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3028  return 1;
3029  }
3030  if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3031  eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3032  return 1;
3033  }
3034 
3035  XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3037 
3038  // Get the entry point of the object creator
3039  //
3040  ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3041 
3042  XrdHttpExtHandler *newhandler;
3043  if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3044 
3045  // Handler has been loaded, it's the last one in the list
3046  strncpy( exthandler[exthandlercnt].name, instName, 16 );
3047  exthandler[exthandlercnt].name[15] = '\0';
3048  exthandler[exthandlercnt++].ptr = newhandler;
3049 
3050  return 0;
3051  }
3052 
3053  myLib.Unload();
3054  return 1;
3055 }
3056 
3057 
3058 
3059 // Tells if we have already loaded a certain exthandler. Try to
3060 // privilege speed, as this func may be invoked pretty often
3061 bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3062  for (int i = 0; i < exthandlercnt; i++) {
3063  if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3064  return true;
3065  }
3066  }
3067  return false;
3068 }
3069 
3070 // Locates a matching external handler for a given request, if available. Try to
3071 // privilege speed, as this func is invoked for every incoming request
3072 XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3073 
3074  for (int i = 0; i < exthandlercnt; i++) {
3075  if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3076  return exthandler[i].ptr;
3077  }
3078  }
3079  return NULL;
3080 }
#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 fclose(FILE *stream)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:43
#define fopen(a, b)
Definition: XrdPosix.hh:49
#define eMsg(x)
struct myOpts opts
size_t strlcpy(char *dst, const char *src, size_t sz)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
#define TRACE_DEBUG
Definition: XrdTrace.hh:36
#define TRACE_MEM
Definition: XrdTrace.hh:38
#define TRACE(act, x)
Definition: XrdTrace.hh:63
#define TRACE_ALL
Definition: XrdTrace.hh:35
#define TRACING(x)
Definition: XrdTrace.hh:70
#define TRACEI(act, x)
Definition: XrdTrace.hh:66
void Release(XrdBuffer *bp)
Definition: XrdBuffer.cc:221
XrdBuffer * Obtain(int bsz)
Definition: XrdBuffer.cc:140
int bsize
Definition: XrdBuffer.hh:46
char * buff
Definition: XrdBuffer.hh:45
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static char * sslcafile
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static XrdSysError eDest
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
static char * sslkey
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
static char * sslcadir
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static bool isRequiredGridmap
static char * listredir
Url to redirect to in the case a listing is requested.
int Stats(char *buff, int blen, int do_sync=0)
Get activity stats.
XrdHttpReq CurrentReq
static int crlRefIntervalSec
CRL thread refresh interval.
static int Port
Our port.
static XrdHttpReadRangeHandler::Configuration ReadRangeConfig
configuration for the read range handler
static XrdSecService * CIA
static XrdBuffManager * BPool
static bool tpcForwardCreds
If set to true, the HTTP TPC transfers will forward the credentials to redirected hosts.
int Process(XrdLink *lp)
Process data incoming from the socket.
XrdHttpProtocol(const XrdHttpProtocol &)=default
Ctor, dtors and copy ctor.
static bool listdeny
If true, any form of listing is denied.
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
XrdSecEntity SecEntity
Authentication area.
static bool embeddedstatic
If true, use the embedded css and icons.
static int sslverifydepth
Depth of verification of a certificate chain.
static int Configure(char *parms, XrdProtocol_Config *pi)
Read and apply the configuration.
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
int reqstate
State machine to talk to the bridge.
Definition: XrdHttpReq.hh:308
XrdOucString resource
The resource specified by the request, stripped of opaque data.
Definition: XrdHttpReq.hh:232
bool headerok
Tells if we have finished reading the header.
Definition: XrdHttpReq.hh:240
std::string requestverb
Definition: XrdHttpReq.hh:225
ReqType request
The request we got.
Definition: XrdHttpReq.hh:224
int ProcessHTTPReq()
Definition: XrdHttpReq.cc:926
XrdOucEnv * opaque
The opaque data, after parsing.
Definition: XrdHttpReq.hh:234
long fileflags
Definition: XrdHttpReq.hh:298
long filemodtime
Definition: XrdHttpReq.hh:299
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:627
long long filesize
Definition: XrdHttpReq.hh:297
ClientRequest xrdreq
The last issued xrd request, often pending.
Definition: XrdHttpReq.hh:282
const std::string & userAgent() const
Definition: XrdHttpReq.hh:198
virtual void reset()
Definition: XrdHttpReq.cc:2750
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.