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