XRootD
Loading...
Searching...
No Matches
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"
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"
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
66const char *XrdHttpSecEntityTident = "http";
67
68//
69// Static stuff
70//
71
73int XrdHttpProtocol::readWait = 300000;
74int XrdHttpProtocol::Port = 1094;
76
77//XrdXrootdStats *XrdHttpProtocol::SI = 0;
84bool XrdHttpProtocol::listdeny = false;
88
94
99BIO *XrdHttpProtocol::sslbio_err = 0;
100XrdHttpSecXtractor *XrdHttpProtocol::secxtractor = 0;
101bool XrdHttpProtocol::isRequiredXtractor = false;
102struct XrdHttpProtocol::XrdHttpExtHandlerInfo XrdHttpProtocol::exthandler[MAX_XRDHTTPEXTHANDLERS];
103int XrdHttpProtocol::exthandlercnt = 0;
104std::map< std::string, std::string > XrdHttpProtocol::hdr2cgimap;
105
106bool XrdHttpProtocol::usingEC = false;
107
108XrdScheduler *XrdHttpProtocol::Sched = 0; // System scheduler
109XrdBuffManager *XrdHttpProtocol::BPool = 0; // Buffer manager
110XrdSysError XrdHttpProtocol::eDest = 0; // Error message handler
111XrdSecService *XrdHttpProtocol::CIA = 0; // Authentication Server
112int XrdHttpProtocol::m_bio_type = 0; // BIO type identifier for our custom BIO.
113BIO_METHOD *XrdHttpProtocol::m_bio_method = NULL; // BIO method constructor.
114char *XrdHttpProtocol::xrd_cslist = nullptr;
119
121
122namespace
123{
124const char *TraceID = "Protocol";
125}
126
128{
130
131static const int hsmAuto = -1;
132static const int hsmOff = 0;
133static const int hsmMan = 1;
134static const int hsmOn = 1; // Dual purpose but use a meaningful varname
135
138bool httpsspec = false;
139bool xrdctxVer = false;
140}
141
142using 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
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
157void *BIO_get_data(BIO *bio) {
158 return bio->ptr;
159}
160void BIO_set_data(BIO *bio, void *ptr) {
161 bio->ptr = ptr;
162}
163#if OPENSSL_VERSION_NUMBER < 0x1000105fL
164int BIO_get_flags(BIO *bio) {
165 return bio->flags;
166}
167#endif
168void BIO_set_flags(BIO *bio, int flags) {
169 bio->flags = flags;
170}
171int BIO_get_init(BIO *bio) {
172 return bio->init;
173}
174void BIO_set_init(BIO *bio, int init) {
175 bio->init = init;
176}
177void BIO_set_shutdown(BIO *bio, int shut) {
178 bio->shutdown = shut;
179}
180int 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),
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
306char *XrdHttpProtocol::GetClientIPStr() {
307 char buf[256];
308 buf[0] = '\0';
309 if (!Link) return strdup("unknown");
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
320int 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
342int 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
363static 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
384static 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
404static 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
423static 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
437static 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
459BIO *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
480int 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)) {
564 SecEntity.Display(eDest);
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
587 CurrentReq.reqstate++;
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));
598 CurrentReq.xrdreq.set.requestid = htons(kXR_set);
599 CurrentReq.xrdreq.set.modifier = '\0';
600 memset(CurrentReq.xrdreq.set.reserved, '\0', sizeof(CurrentReq.xrdreq.set.reserved));
601 CurrentReq.xrdreq.set.dlen = htonl(mon_info.size());
602 if (!Bridge->Run((char *) &CurrentReq.xrdreq, (char *) mon_info.c_str(), mon_info.size())) {
603 SendSimpleResp(500, nullptr, nullptr, "Could not set user agent.", 0, false);
604 return -1;
605 }
606 return 0;
607 }
608 } else {
609 DoingLogin = false;
610 }
611
612 // Read the next request header, that is, read until a double CRLF is found
613
614
615 if (!CurrentReq.headerok) {
616
617 // Read as many lines as possible into the buffer. An empty line breaks
618 while ((rc = BuffgetLine(tmpline)) > 0) {
619 std::string traceLine = tmpline.c_str();
620 if (TRACING(TRACE_DEBUG)) {
621 traceLine = obfuscateAuth(traceLine);
622 }
623 TRACE(DEBUG, " rc:" << rc << " got hdr line: " << traceLine);
624 if ((rc == 2) && (tmpline.length() > 1) && (tmpline[rc - 1] == '\n')) {
625 CurrentReq.headerok = true;
626 TRACE(DEBUG, " rc:" << rc << " detected header end.");
627 break;
628 }
629
630
631 if (CurrentReq.request == CurrentReq.rtUnset) {
632 TRACE(DEBUG, " Parsing first line: " << traceLine.c_str());
633 int result = CurrentReq.parseFirstLine((char *)tmpline.c_str(), rc);
634 if (result < 0) {
635 TRACE(DEBUG, " Parsing of first line failed with " << result);
636 return -1;
637 }
638 } else {
639 int result = CurrentReq.parseLine((char *) tmpline.c_str(), rc);
640 if(result < 0) {
641 TRACE(DEBUG, " Parsing of header line failed with " << result)
642 SendSimpleResp(400,NULL,NULL,"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0, false);
643 return -1;
644 }
645 }
646
647
648 }
649
650 // Here we have CurrentReq loaded with the header, or its relevant fields
651
652 if (!CurrentReq.headerok) {
653 TRACEI(REQ, " rc:" << rc << "Header not yet complete.");
654
655 // Here a subtle error condition. IF we failed reading a line AND the buffer
656 // has a reasonable amount of data available THEN we consider the header
657 // as corrupted and shutdown the client
658 if ((rc <= 0) && (BuffUsed() >= 16384)) {
659 TRACEI(ALL, "Corrupted header detected, or line too long. Disconnecting client.");
660 return -1;
661 }
662
663
664 if (CurrentReq.reqstate > 0)
665 CurrentReq.reqstate--;
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 &&
675 ( (CurrentReq.request == XrdHttpReq::rtGET) || (CurrentReq.request == XrdHttpReq::rtPUT) ||
676 (CurrentReq.request == XrdHttpReq::rtPROPFIND)) ) {
677 char hash[512];
678 time_t timenow = time(0);
679
680
681 calcHashes(hash, CurrentReq.resource.c_str(), (kXR_int16) CurrentReq.request,
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);
827 SecEntity.endorsements = unquote(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
853 calcHashes(hash, CurrentReq.resource.c_str(), (kXR_int16) CurrentReq.request,
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
920void 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 //
934 ProtStack.Push(&ProtLink);
935}
936
937int 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
980int 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;
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 //
1043 xrdctxVer = xrdctx && xrdctx->x509Verify();
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 }
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
1217const 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
1231int 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
1320int 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
1405int 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
1427int 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
1450int XrdHttpProtocol::BuffFree() {
1451 return (myBuff->bsize - BuffUsed());
1452}
1453
1454/******************************************************************************/
1455/* B u f f C o n s u m e */
1456/******************************************************************************/
1457
1458void 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
1494int 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
1536int 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
1562int 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
1612int 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
1629int 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
1644int 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
1659int 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
1672int 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());
1709 XrdHttpTrace.SetLogger(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
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 //
1752 ProtStack.Set(pi->Sched, &XrdHttpTrace,
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/******************************************************************************/
1765int 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
1824bool 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
1869void 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);
1915 if (SecEntity.endorsements) free(SecEntity.endorsements);
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
1932void 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
1990int 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
2025int 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
2057int 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
2092int 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
2129int 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
2186int 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
2219int XrdHttpProtocol::xsecretkey(XrdOucStream & Config) {
2220 char *val;
2221 bool inFile = false;
2222
2223 // Get the path
2224 //
2225 val = Config.GetWord();
2226 if (!val || !val[0]) {
2227 eDest.Emsg("Config", "Shared secret key not specified");
2228 return 1;
2229 }
2230
2231
2232 // If the token starts with a slash, then we interpret it as
2233 // the path to a file that contains the secretkey
2234 // otherwise, the token itself is the secretkey
2235 if (val[0] == '/') {
2236 struct stat st;
2237 inFile = true;
2238 int fd = open(val, O_RDONLY);
2239
2240 if ( fd == -1 ) {
2241 eDest.Emsg("Config", errno, "open shared secret key file", val);
2242 return 1;
2243 }
2244
2245 if ( fstat(fd, &st) != 0 ) {
2246 eDest.Emsg("Config", errno, "fstat shared secret key file", val);
2247 close(fd);
2248 return 1;
2249 }
2250
2251 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2252 eDest.Emsg("Config",
2253 "For your own security, the shared secret key file cannot be world readable or group writable '", val, "'");
2254 close(fd);
2255 return 1;
2256 }
2257
2258 FILE *fp = fdopen(fd, "r");
2259
2260 if ( fp == nullptr ) {
2261 eDest.Emsg("Config", errno, "fdopen shared secret key file", val);
2262 close(fd);
2263 return 1;
2264 }
2265
2266 char line[1024];
2267 while( fgets(line, 1024, fp) ) {
2268 char *pp;
2269
2270 // Trim the end
2271 pp = line + strlen(line) - 1;
2272 while ( (pp >= line) && (!isalnum(*pp)) ) {
2273 *pp = '\0';
2274 pp--;
2275 }
2276
2277 // Trim the beginning
2278 pp = line;
2279 while ( *pp && !isalnum(*pp) ) pp++;
2280
2281 if ( strlen(pp) >= 32 ) {
2282 eDest.Say("Config", "Secret key loaded.");
2283 // Record the path
2284 if (secretkey) free(secretkey);
2285 secretkey = strdup(pp);
2286
2287 fclose(fp);
2288 return 0;
2289 }
2290
2291 }
2292
2293 fclose(fp);
2294 eDest.Emsg("Config", "Cannot find useful secretkey in file '", val, "'");
2295 return 1;
2296
2297 }
2298
2299 if ( strlen(val) < 32 ) {
2300 eDest.Emsg("Config", "Secret key is too short");
2301 return 1;
2302 }
2303
2304 // Record the path
2305 if (secretkey) free(secretkey);
2306 secretkey = strdup(val);
2307 if (!inFile) Config.noEcho();
2308
2309 return 0;
2310}
2311
2312/******************************************************************************/
2313/* x l i s t d e n y */
2314/******************************************************************************/
2315
2316/* Function: xlistdeny
2317
2318 Purpose: To parse the directive: listingdeny <yes|no|0|1>
2319
2320 <val> makes this redirector deny listings with an error
2321
2322 Output: 0 upon success or !0 upon failure.
2323 */
2324
2325int XrdHttpProtocol::xlistdeny(XrdOucStream & Config) {
2326 char *val;
2327
2328 // Get the path
2329 //
2330 val = Config.GetWord();
2331 if (!val || !val[0]) {
2332 eDest.Emsg("Config", "listingdeny flag not specified");
2333 return 1;
2334 }
2335
2336 // Record the value
2337 //
2338 listdeny = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2339
2340
2341 return 0;
2342}
2343
2344/******************************************************************************/
2345/* x l i s t r e d i r */
2346/******************************************************************************/
2347
2348/* Function: xlistredir
2349
2350 Purpose: To parse the directive: listingredir <Url>
2351
2352 <Url> http/https server to redirect to in the case of listing
2353
2354 Output: 0 upon success or !0 upon failure.
2355 */
2356
2357int XrdHttpProtocol::xlistredir(XrdOucStream & Config) {
2358 char *val;
2359
2360 // Get the path
2361 //
2362 val = Config.GetWord();
2363 if (!val || !val[0]) {
2364 eDest.Emsg("Config", "listingredir flag not specified");
2365 return 1;
2366 }
2367
2368 // Record the value
2369 //
2370 if (listredir) free(listredir);
2371 listredir = strdup(val);
2372
2373
2374 return 0;
2375}
2376
2377/******************************************************************************/
2378/* x s s l d e s t h t t p s */
2379/******************************************************************************/
2380
2381/* Function: xdesthttps
2382
2383 Purpose: To parse the directive: desthttps <yes|no|0|1>
2384
2385 <val> makes this redirector produce http or https redirection targets
2386
2387 Output: 0 upon success or !0 upon failure.
2388 */
2389
2390int XrdHttpProtocol::xdesthttps(XrdOucStream & Config) {
2391 char *val;
2392
2393 // Get the path
2394 //
2395 val = Config.GetWord();
2396 if (!val || !val[0]) {
2397 eDest.Emsg("Config", "desthttps flag not specified");
2398 return 1;
2399 }
2400
2401 // Record the value
2402 //
2403 isdesthttps = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2404
2405
2406 return 0;
2407}
2408
2409/******************************************************************************/
2410/* x e m b e d d e d s t a t i c */
2411/******************************************************************************/
2412
2413/* Function: xembeddedstatic
2414
2415 Purpose: To parse the directive: embeddedstatic <yes|no|0|1|true|false>
2416
2417 <val> this server will redirect HTTPS to itself using HTTP+token
2418
2419 Output: 0 upon success or !0 upon failure.
2420 */
2421
2422int XrdHttpProtocol::xembeddedstatic(XrdOucStream & Config) {
2423 char *val;
2424
2425 // Get the path
2426 //
2427 val = Config.GetWord();
2428 if (!val || !val[0]) {
2429 eDest.Emsg("Config", "embeddedstatic flag not specified");
2430 return 1;
2431 }
2432
2433 // Record the value
2434 //
2435 embeddedstatic = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2436
2437
2438 return 0;
2439}
2440
2441/******************************************************************************/
2442/* x r e d i r s t a t i c */
2443/******************************************************************************/
2444
2445/* Function: xstaticredir
2446
2447 Purpose: To parse the directive: staticredir <Url>
2448
2449 <Url> http/https server to redirect to in the case of /static
2450
2451 Output: 0 upon success or !0 upon failure.
2452 */
2453
2454int XrdHttpProtocol::xstaticredir(XrdOucStream & Config) {
2455 char *val;
2456
2457 // Get the path
2458 //
2459 val = Config.GetWord();
2460 if (!val || !val[0]) {
2461 eDest.Emsg("Config", "staticredir url not specified");
2462 return 1;
2463 }
2464
2465 // Record the value
2466 //
2467 if (staticredir) free(staticredir);
2468 staticredir = strdup(val);
2469
2470 return 0;
2471}
2472
2473/******************************************************************************/
2474/* x p r e l o a d s t a t i c */
2475/******************************************************************************/
2476
2477/* Function: xpreloadstatic
2478
2479 Purpose: To parse the directive: preloadstatic <http url path> <local file>
2480
2481 <http url path> http/http path whose response we are preloading
2482 e.g. /static/mycss.css
2483 NOTE: this must start with /static
2484
2485
2486 Output: 0 upon success or !0 upon failure.
2487 */
2488
2489int XrdHttpProtocol::xstaticpreload(XrdOucStream & Config) {
2490 char *val, *k, key[1024];
2491
2492 // Get the key
2493 //
2494 k = Config.GetWord();
2495 if (!k || !k[0]) {
2496 eDest.Emsg("Config", "preloadstatic urlpath not specified");
2497 return 1;
2498 }
2499
2500 strcpy(key, k);
2501
2502 // Get the val
2503 //
2504 val = Config.GetWord();
2505 if (!val || !val[0]) {
2506 eDest.Emsg("Config", "preloadstatic filename not specified");
2507 return 1;
2508 }
2509
2510 // Try to load the file into memory
2511 int fp = open(val, O_RDONLY);
2512 if( fp < 0 ) {
2513 eDest.Emsg("Config", errno, "open preloadstatic filename", val);
2514 return 1;
2515 }
2516
2518 // Max 64Kb ok?
2519 nfo->data = (char *)malloc(65536);
2520 nfo->len = read(fp, (void *)nfo->data, 65536);
2521 close(fp);
2522
2523 if (nfo->len <= 0) {
2524 eDest.Emsg("Config", errno, "read from preloadstatic filename", val);
2525 return 1;
2526 }
2527
2528 if (nfo->len >= 65536) {
2529 eDest.Emsg("Config", "Truncated preloadstatic filename. Max is 64 KB '", val, "'");
2530 return 1;
2531 }
2532
2533 // Record the value
2534 //
2535 if (!staticpreload)
2536 staticpreload = new XrdOucHash<StaticPreloadInfo>;
2537
2538 staticpreload->Rep((const char *)key, nfo);
2539 return 0;
2540}
2541
2542/******************************************************************************/
2543/* x s e l f h t t p s 2 h t t p */
2544/******************************************************************************/
2545
2546/* Function: selfhttps2http
2547
2548 Purpose: To parse the directive: selfhttps2http <yes|no|0|1>
2549
2550 <val> this server will redirect HTTPS to itself using HTTP+token
2551
2552 Output: 0 upon success or !0 upon failure.
2553 */
2554
2555int XrdHttpProtocol::xselfhttps2http(XrdOucStream & Config) {
2556 char *val;
2557
2558 // Get the path
2559 //
2560 val = Config.GetWord();
2561 if (!val || !val[0]) {
2562 eDest.Emsg("Config", "selfhttps2http flag not specified");
2563 return 1;
2564 }
2565
2566 // Record the value
2567 //
2568 selfhttps2http = (!strcasecmp(val, "true") || !strcasecmp(val, "yes") || !strcmp(val, "1"));
2569
2570
2571 return 0;
2572}
2573
2574/******************************************************************************/
2575/* x s e c x t r a c t o r */
2576/******************************************************************************/
2577
2578/* Function: xsecxtractor
2579
2580 Purpose: To parse the directive: secxtractor [required] <path> <params>
2581
2582 required optional parameter which if present treats any secxtractor
2583 errors as fatal.
2584 <path> the path of the plugin to be loaded
2585 <params> parameters passed to the secxtractor library
2586
2587 Output: 0 upon success or !0 upon failure.
2588 */
2589
2590int XrdHttpProtocol::xsecxtractor(XrdOucStream& Config) {
2591 char *val;
2592
2593 // Get the path
2594 //
2595 val = Config.GetWord();
2596 if (!val || !val[0]) {
2597 eDest.Emsg("Config", "No security extractor plugin specified.");
2598 return 1;
2599 } else {
2600 // Handle optional parameter [required]
2601 //
2602 if (!strncmp(val, "required", 8)) {
2603 isRequiredXtractor = true;
2604 val = Config.GetWord();
2605
2606 if (!val || !val[0]) {
2607 eDest.Emsg("Config", "No security extractor plugin after [required] "
2608 "parameter");
2609 return 1;
2610 }
2611 }
2612
2613 char libName[4096];
2614 strlcpy(libName, val, sizeof(libName));
2615 libName[sizeof(libName) - 1] = '\0';
2616 char libParms[4096];
2617
2618 if (!Config.GetRest(libParms, 4095)) {
2619 eDest.Emsg("Config", "secxtractor config params longer than 4k");
2620 return 1;
2621 }
2622
2623 // Try to load the plugin (if available) that extracts info from the
2624 // user cert/proxy
2625 if (LoadSecXtractor(&eDest, libName, libParms)) {
2626 return 1;
2627 }
2628 }
2629
2630 return 0;
2631}
2632
2633/******************************************************************************/
2634/* x e x t h a n d l e r */
2635/******************************************************************************/
2636
2637/* Function: xexthandler
2638 *
2639 * Purpose: To parse the directive: exthandler <name> <path> <initparm>
2640 *
2641 * <name> a unique name (max 16chars) to be given to this
2642 * instance, e.g 'myhandler1'
2643 * <path> the path of the plugin to be loaded
2644 * <initparm> a string parameter (e.g. a config file) that is
2645 * passed to the initialization of the plugin
2646 *
2647 * Output: 0 upon success or !0 upon failure.
2648 */
2649
2650int XrdHttpProtocol::xexthandler(XrdOucStream &Config,
2651 std::vector<extHInfo> &hiVec) {
2652 char *val, path[1024], namebuf[1024];
2653 char *parm;
2654 // By default, every external handler need TLS configured to be loaded
2655 bool noTlsOK = false;
2656
2657 // Get the name
2658 //
2659 val = Config.GetWord();
2660 if (!val || !val[0]) {
2661 eDest.Emsg("Config", "No instance name specified for an http external handler plugin.");
2662 return 1;
2663 }
2664 if (strlen(val) >= 16) {
2665 eDest.Emsg("Config", "Instance name too long for an http external handler plugin.");
2666 return 1;
2667 }
2668 strncpy(namebuf, val, sizeof(namebuf));
2669 namebuf[ sizeof(namebuf)-1 ] = '\0';
2670
2671 // Get the +notls option if it was provided
2672 val = Config.GetWord();
2673
2674 if(val && !strcmp("+notls",val)) {
2675 noTlsOK = true;
2676 val = Config.GetWord();
2677 }
2678
2679 // Get the path
2680 //
2681 if (!val || !val[0]) {
2682 eDest.Emsg("Config", "No http external handler plugin specified.");
2683 return 1;
2684 }
2685 if (strlen(val) >= (int)sizeof(path)) {
2686 eDest.Emsg("Config", "Path too long for an http external handler plugin.");
2687 return 1;
2688 }
2689
2690 strcpy(path, val);
2691
2692 // Everything else is a free string
2693 //
2694 parm = Config.GetWord();
2695
2696 // Verify whether this is a duplicate (we never supported replacements)
2697 //
2698 for (int i = 0; i < (int)hiVec.size(); i++)
2699 {if (hiVec[i].extHName == namebuf) {
2700 eDest.Emsg("Config", "Instance name already present for "
2701 "http external handler plugin",
2702 hiVec[i].extHPath.c_str());
2703 return 1;
2704 }
2705 }
2706
2707 // Verify that we don't have more already than we are allowed to have
2708 //
2709 if (hiVec.size() >= MAX_XRDHTTPEXTHANDLERS) {
2710 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
2711 return 1;
2712 }
2713
2714 // Create an info struct and push it on the list of ext handlers to load
2715 //
2716 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm : ""), noTlsOK));
2717
2718 return 0;
2719}
2720
2721/******************************************************************************/
2722/* x h e a d e r 2 c g i */
2723/******************************************************************************/
2724
2725/* Function: xheader2cgi
2726 *
2727 * Purpose: To parse the directive: header2cgi <headerkey> <cgikey>
2728 *
2729 * <headerkey> the name of an incoming HTTP header
2730 * to be transformed
2731 * <cgikey> the name to be given when adding it to the cgi info
2732 * that is kept only internally
2733 *
2734 * Output: 0 upon success or !0 upon failure.
2735 */
2736
2737int XrdHttpProtocol::xheader2cgi(XrdOucStream & Config) {
2738 return parseHeader2CGI(Config,eDest,hdr2cgimap);
2739}
2740
2741/******************************************************************************/
2742/* x s s l c a d i r */
2743/******************************************************************************/
2744
2745/* Function: xsslcadir
2746
2747 Purpose: To parse the directive: sslcadir <path>
2748
2749 <path> the path of the server key to be used.
2750
2751 Output: 0 upon success or !0 upon failure.
2752 */
2753
2754int XrdHttpProtocol::xsslcadir(XrdOucStream & Config) {
2755 char *val;
2756
2757 // Get the path
2758 //
2759 val = Config.GetWord();
2760 if (!val || !val[0]) {
2761 eDest.Emsg("Config", "HTTP X509 CAdir not specified");
2762 return 1;
2763 }
2764
2765 // Record the path
2766 //
2767 if (sslcadir) free(sslcadir);
2768 sslcadir = strdup(val);
2769
2770 if (xrdctxVer){ HTTPS_ALERT("cadir","tlsca",false); }
2771 return 0;
2772}
2773
2774/******************************************************************************/
2775/* x s s l c i p h e r f i l t e r */
2776/******************************************************************************/
2777
2778/* Function: xsslcipherfilter
2779
2780 Purpose: To parse the directive: cipherfilter <filter>
2781
2782 <filter> the filter string to be used when generating
2783 the SSL cipher list
2784
2785 Output: 0 upon success or !0 upon failure.
2786 */
2787
2788int XrdHttpProtocol::xsslcipherfilter(XrdOucStream & Config) {
2789 char *val;
2790
2791 // Get the filter string
2792 //
2793 val = Config.GetWord();
2794 if (!val || !val[0]) {
2795 eDest.Emsg("Config", "SSL cipherlist filter string not specified");
2796 return 1;
2797 }
2798
2799 // Record the filter string
2800 //
2802 sslcipherfilter = strdup(val);
2803
2804 return 0;
2805}
2806
2807/******************************************************************************/
2808/* x t l s r e u s e */
2809/******************************************************************************/
2810
2811/* Function: xtlsreuse
2812
2813 Purpose: To parse the directive: tlsreuse {on | off}
2814
2815 Output: 0 upon success or 1 upon failure.
2816 */
2817
2818int XrdHttpProtocol::xtlsreuse(XrdOucStream & Config) {
2819
2820 char *val;
2821
2822// Get the argument
2823//
2824 val = Config.GetWord();
2825 if (!val || !val[0])
2826 {eDest.Emsg("Config", "tlsreuse argument not specified"); return 1;}
2827
2828// If it's off, we set it off
2829//
2830 if (!strcmp(val, "off"))
2832 return 0;
2833 }
2834
2835// If it's on we set it on.
2836//
2837 if (!strcmp(val, "on"))
2839 return 0;
2840 }
2841
2842// Bad argument
2843//
2844 eDest.Emsg("config", "invalid tlsreuse parameter -", val);
2845 return 1;
2846}
2847
2848int XrdHttpProtocol::xauth(XrdOucStream &Config) {
2849 char *val = Config.GetWord();
2850 if(val) {
2851 if(!strcmp("tpc",val)) {
2852 if(!(val = Config.GetWord())) {
2853 eDest.Emsg("Config", "http.auth tpc value not specified."); return 1;
2854 } else {
2855 if(!strcmp("fcreds",val)) {
2856 tpcForwardCreds = true;
2857 } else {
2858 eDest.Emsg("Config", "http.auth tpc value is invalid"); return 1;
2859 }
2860 }
2861 } else {
2862 eDest.Emsg("Config", "http.auth value is invalid"); return 1;
2863 }
2864 }
2865 return 0;
2866}
2867
2868/******************************************************************************/
2869/* x t r a c e */
2870/******************************************************************************/
2871
2872/* Function: xtrace
2873
2874 Purpose: To parse the directive: trace <events>
2875
2876 <events> the blank separated list of events to trace. Trace
2877 directives are cumulative.
2878
2879 Output: 0 upon success or 1 upon failure.
2880 */
2881
2882int XrdHttpProtocol::xtrace(XrdOucStream & Config) {
2883
2884 char *val;
2885
2886 static struct traceopts {
2887 const char *opname;
2888 int opval;
2889 } tropts[] = {
2890 {"all", TRACE_ALL},
2891 {"auth", TRACE_AUTH},
2892 {"debug", TRACE_DEBUG},
2893 {"mem", TRACE_MEM},
2894 {"redirect", TRACE_REDIR},
2895 {"request", TRACE_REQ},
2896 {"response", TRACE_RSP}
2897 };
2898 int i, neg, trval = 0, numopts = sizeof (tropts) / sizeof (struct traceopts);
2899
2900 if (!(val = Config.GetWord())) {
2901 eDest.Emsg("config", "trace option not specified");
2902 return 1;
2903 }
2904 while (val) {
2905 if (!strcmp(val, "off")) trval = 0;
2906 else {
2907 if ((neg = (val[0] == '-' && val[1]))) val++;
2908 for (i = 0; i < numopts; i++) {
2909 if (!strcmp(val, tropts[i].opname)) {
2910 if (neg) trval &= ~tropts[i].opval;
2911 else trval |= tropts[i].opval;
2912 break;
2913 }
2914 }
2915 if (i >= numopts)
2916 eDest.Emsg("config", "invalid trace option", val);
2917 }
2918 val = Config.GetWord();
2919 }
2920 XrdHttpTrace.What = trval;
2921 return 0;
2922}
2923
2924int XrdHttpProtocol::doStat(char *fname) {
2925 int l;
2926 bool b;
2927 CurrentReq.filesize = 0;
2928 CurrentReq.fileflags = 0;
2929 CurrentReq.filemodtime = 0;
2930
2931 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
2932 CurrentReq.xrdreq.stat.requestid = htons(kXR_stat);
2933 memset(CurrentReq.xrdreq.stat.reserved, 0,
2934 sizeof (CurrentReq.xrdreq.stat.reserved));
2935 l = strlen(fname) + 1;
2936 CurrentReq.xrdreq.stat.dlen = htonl(l);
2937
2938 if (!Bridge) return -1;
2939 b = Bridge->Run((char *) &CurrentReq.xrdreq, fname, l);
2940 if (!b) {
2941 return -1;
2942 }
2943
2944
2945 return 0;
2946}
2947
2948/******************************************************************************/
2949/* d o C h k s u m */
2950/******************************************************************************/
2951
2953 size_t length;
2954 memset(&CurrentReq.xrdreq, 0, sizeof (ClientRequest));
2955 CurrentReq.xrdreq.query.requestid = htons(kXR_query);
2956 CurrentReq.xrdreq.query.infotype = htons(kXR_Qcksum);
2957 memset(CurrentReq.xrdreq.query.reserved1, '\0', sizeof(CurrentReq.xrdreq.query.reserved1));
2958 memset(CurrentReq.xrdreq.query.fhandle, '\0', sizeof(CurrentReq.xrdreq.query.fhandle));
2959 memset(CurrentReq.xrdreq.query.reserved2, '\0', sizeof(CurrentReq.xrdreq.query.reserved2));
2960 length = fname.length() + 1;
2961 CurrentReq.xrdreq.query.dlen = htonl(length);
2962
2963 if (!Bridge) return -1;
2964
2965 return Bridge->Run(reinterpret_cast<char *>(&CurrentReq.xrdreq), const_cast<char *>(fname.c_str()), length) ? 0 : -1;
2966}
2967
2968
2969static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION);
2970
2971// Loads the SecXtractor plugin, if available
2972int XrdHttpProtocol::LoadSecXtractor(XrdSysError *myeDest, const char *libName,
2973 const char *libParms) {
2974
2975
2976 // We don't want to load it more than once
2977 if (secxtractor) return 1;
2978
2979 XrdOucPinLoader myLib(myeDest, &compiledVer, "secxtractorlib", libName);
2981
2982 // Get the entry point of the object creator
2983 //
2984 ep = (XrdHttpSecXtractor *(*)(XrdHttpSecXtractorArgs))(myLib.Resolve("XrdHttpGetSecXtractor"));
2985 if (ep && (secxtractor = ep(myeDest, NULL, libParms))) return 0;
2986 myLib.Unload();
2987 return 1;
2988}
2989/******************************************************************************/
2990/* L o a d E x t H a n d l e r */
2991/******************************************************************************/
2992
2993int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec, const char *cFN, XrdOucEnv &myEnv) {
2994 for (int i = 0; i < (int) hiVec.size(); i++) {
2995 if(hiVec[i].extHNoTlsOK) {
2996 // The external plugin does not need TLS to be loaded
2997 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
2998 hiVec[i].extHParm.c_str(), &myEnv,
2999 hiVec[i].extHName.c_str()))
3000 return 1;
3001 }
3002 }
3003 return 0;
3004}
3005
3006int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3007 const char *cFN, XrdOucEnv &myEnv) {
3008
3009 // Add the pointer to the cadir and the cakey to the environment.
3010 //
3011 if (sslcadir) myEnv.Put("http.cadir", sslcadir);
3012 if (sslcafile) myEnv.Put("http.cafile", sslcafile);
3013 if (sslcert) myEnv.Put("http.cert", sslcert);
3014 if (sslkey) myEnv.Put("http.key" , sslkey);
3015
3016 // Load all of the specified external handlers.
3017 //
3018 for (int i = 0; i < (int)hiVec.size(); i++) {
3019 // Only load the external handlers that were not already loaded
3020 // by LoadExtHandlerNoTls(...)
3021 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3022 if (LoadExtHandler(&eDest, hiVec[i].extHPath.c_str(), cFN,
3023 hiVec[i].extHParm.c_str(), &myEnv,
3024 hiVec[i].extHName.c_str())) return 1;
3025 }
3026 }
3027 return 0;
3028}
3029
3030// Loads the external handler plugin, if available
3031int XrdHttpProtocol::LoadExtHandler(XrdSysError *myeDest, const char *libName,
3032 const char *configFN, const char *libParms,
3033 XrdOucEnv *myEnv, const char *instName) {
3034
3035
3036 // This function will avoid loading doubles. No idea why this happens
3037 if (ExtHandlerLoaded(instName)) {
3038 eDest.Emsg("Config", "Instance name already present for an http external handler plugin.");
3039 return 1;
3040 }
3041 if (exthandlercnt >= MAX_XRDHTTPEXTHANDLERS) {
3042 eDest.Emsg("Config", "Cannot load one more exthandler. Max is 4");
3043 return 1;
3044 }
3045
3046 XrdOucPinLoader myLib(myeDest, &compiledVer, "exthandlerlib", libName);
3047 XrdHttpExtHandler *(*ep)(XrdHttpExtHandlerArgs);
3048
3049 // Get the entry point of the object creator
3050 //
3051 ep = (XrdHttpExtHandler *(*)(XrdHttpExtHandlerArgs))(myLib.Resolve("XrdHttpGetExtHandler"));
3052
3053 XrdHttpExtHandler *newhandler;
3054 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3055
3056 // Handler has been loaded, it's the last one in the list
3057 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3058 exthandler[exthandlercnt].name[15] = '\0';
3059 exthandler[exthandlercnt++].ptr = newhandler;
3060
3061 return 0;
3062 }
3063
3064 myLib.Unload();
3065 return 1;
3066}
3067
3068
3069
3070// Tells if we have already loaded a certain exthandler. Try to
3071// privilege speed, as this func may be invoked pretty often
3072bool XrdHttpProtocol::ExtHandlerLoaded(const char *handlername) {
3073 for (int i = 0; i < exthandlercnt; i++) {
3074 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3075 return true;
3076 }
3077 }
3078 return false;
3079}
3080
3081// Locates a matching external handler for a given request, if available. Try to
3082// privilege speed, as this func is invoked for every incoming request
3083XrdHttpExtHandler * XrdHttpProtocol::FindMatchingExtHandler(const XrdHttpReq &req) {
3084
3085 for (int i = 0; i < exthandlercnt; i++) {
3086 if (exthandler[i].ptr->MatchesPath(req.requestverb.c_str(), req.resource.c_str())) {
3087 return exthandler[i].ptr;
3088 }
3089 }
3090 return NULL;
3091}
#define kXR_isManager
@ kXR_query
Definition XProtocol.hh:113
@ kXR_set
Definition XProtocol.hh:130
@ kXR_stat
Definition XProtocol.hh:129
#define kXR_isServer
@ kXR_Qcksum
Definition XProtocol.hh:617
int kXR_int32
Definition XPtypes.hh:89
short kXR_int16
Definition XPtypes.hh:66
#define DEBUG(x)
#define TS_Xeq(x, m)
Definition XrdConfig.cc:156
static XrdSysError eDest(0,"crypto_")
#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)
XrdSysTrace XrdHttpTrace("http")
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_get_data(BIO *bio)
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
#define TRACE_REQ
#define TRACE_RSP
#define TRACE_REDIR
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 fclose(FILE *stream)
#define close(a)
Definition XrdPosix.hh:43
#define fstat(a, b)
Definition XrdPosix.hh:57
#define open
Definition XrdPosix.hh:71
#define stat(a, b)
Definition XrdPosix.hh:96
#define read(a, b, c)
Definition XrdPosix.hh:77
#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
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.
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)
XrdOucString resource
The resource specified by the request, stripped of opaque data.
std::string requestverb
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)
void SetTLS(bool val)
static bool Import(const char *var, char *&val)
Definition XrdOucEnv.cc:204
void * GetPtr(const char *varname)
Definition XrdOucEnv.cc:263
void Put(const char *varname, const char *value)
Definition XrdOucEnv.hh:85
void insert(const int i, int start=-1)
void assign(const char *s, int j, int k=-1)
int length() const
const char * c_str() const
XrdBuffManager * BPool
XrdScheduler * Sched
XrdTlsContext * tlsCtx
XrdSysError * eDest
XrdOucEnv * theEnv
XrdProtocol(const char *jname)
XrdNetAddrInfo * addrInfo
Entity's connection details.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
XrdSysLogger * logger(XrdSysLogger *lp=0)
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.
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)
static const int hsmOff
static const int hsmMan
static const int hsmOn
static const int hsmAuto
XrdTlsContext * xrdctx
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.