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