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