24#include "XrdVersion.hh"
47#include <openssl/err.h>
48#include <openssl/ssl.h>
57#define XRHTTP_TK_GRACETIME 600
98BIO *XrdHttpProtocol::sslbio_err = 0;
100bool XrdHttpProtocol::isRequiredXtractor =
false;
102int XrdHttpProtocol::exthandlercnt = 0;
105bool XrdHttpProtocol::usingEC = false;
123const char *TraceID =
"Protocol";
149 "xrootd protocol anchor");
155#if OPENSSL_VERSION_NUMBER < 0x10100000L
162#if OPENSSL_VERSION_NUMBER < 0x1000105fL
177 bio->shutdown = shut;
180 return bio->shutdown;
192:
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
193SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
218 char mybuf[16], mybuf2[1024];
221 bool myishttps =
false;
225 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
226 if (dlen <= 0) lp->
setEtext(
"handshake not received");
229 mybuf[dlen - 1] =
'\0';
237 for (
int i = 0; i < dlen; i++) {
239 sprintf(mybuf3,
"%.02d ", mybuf[i]);
240 strcat(mybuf2, mybuf3);
247 for (
int i = 0; i < dlen - 1; i++)
248 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
250 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
255 if ((!ismine) && (dlen >= 4)) {
256 char check[4] = {00, 00, 00, 00};
257 if (memcmp(mybuf, check, 4)) {
264 TRACEI(ALL,
"This may look like https, but https is not configured");
271 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
279 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
282 hp->ishttps = myishttps;
297 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
305char *XrdHttpProtocol::GetClientIPStr() {
308 if (!
Link)
return strdup(
"unknown");
310 if (!ai)
return strdup(
"unknown");
318#if OPENSSL_VERSION_NUMBER < 0x1000105fL
329 int ret = lp->
Send(data, datal);
330 BIO_clear_retry_flags(bio);
333 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
334 BIO_set_retry_write(bio);
350 int ret = lp->
Send(data, datal);
351 BIO_clear_retry_flags(bio);
353 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
354 BIO_set_retry_write(bio);
361#if OPENSSL_VERSION_NUMBER < 0x1000105fL
372 int ret = lp->
Recv(data, datal);
373 BIO_clear_retry_flags(bio);
376 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
377 BIO_set_retry_read(bio);
392 int ret = lp->
Recv(data, datal);
393 BIO_clear_retry_flags(bio);
395 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
396 BIO_set_retry_read(bio);
412#if OPENSSL_VERSION_NUMBER < 0x10100000L
424 if (bio == NULL)
return 0;
440 case BIO_CTRL_GET_CLOSE:
443 case BIO_CTRL_SET_CLOSE:
458BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
477#define TRACELINK Link
485 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
486 TRACE(ALL,
" Process. No buffer available. Internal error.");
492 char *nfo = GetClientIPStr();
494 TRACEI(REQ,
" Setting host: " << nfo);
503 if (ishttps && !ssldone) {
506 sbio = CreateBIO(
Link);
507 BIO_set_nbio(sbio, 1);
513 ERR_print_errors(sslbio_err);
522 SSL_set_bio(ssl, sbio, sbio);
529 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
530 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
533 int res = SSL_accept(ssl);
535 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
536 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
541 ERR_print_errors(sslbio_err);
550 BIO_set_nbio(sbio, 0);
555 if (HandleAuthentication(
Link)) {
576 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
582 if (BuffUsed() < ResumeBytes)
return 1;
590 if (mon_info.size() >= 1024) {
591 TRACEI(ALL,
"User agent string too long");
593 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
602 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
617 while ((rc = BuffgetLine(tmpline)) > 0) {
619 std::string traceLine{tmpline.
c_str()};
620 traceLine =
XrdOucUtils::obfuscate(traceLine, {
"authorization",
"transferheaderauthorization"},
':',
'\n');
621 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
623 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
625 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
634 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
640 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
641 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
652 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
657 if ((rc <= 0) && (BuffUsed() >= 16384)) {
658 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
677 time_t timenow = time(0);
695 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
702 struct sockaddr_storage sa;
703 socklen_t sl =
sizeof(sa);
710 switch (sa.ss_family) {
712 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
719 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
721 Addr_str = (
char *)malloc(strlen(buf)+3);
729 TRACEI(REQ,
" Can't recognize the address family of the local host.");
737 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
738 << dest.
c_str() <<
"'");
742 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
747 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
751 TRACEI(ALL,
" Could not calculate self-redirection hash");
757 if (!ishttps && !ssldone) {
767 if (t) tim = atoi(t);
769 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
773 TRACEI(REQ,
" Token expired. Authentication failed.");
858 TRACEI(REQ,
" Invalid tk '" << tk <<
"' != '" << hash <<
"'(calculated). Authentication failed.");
865 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
873 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
893 TRACEI(REQ,
" Authorization failed.");
909 TRACEI(REQ,
"Process is exiting rc:" << rc);
917#define TRACELINK Link
971#define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
973#define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
975#define HTTPS_ALERT(x,y,z) httpsspec = true;\
976 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
977 eDest.Say("Config http." x " overrides the xrd." y " directive.")
979int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
982 std::vector<extHInfo> extHIVec;
984 int cfgFD, GoNo, NoGo = 0, ismine;
994 if(nonIanaChecksums.size()) {
995 std::stringstream warningMsgSS;
996 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
997 std::string unknownCksumString;
998 for(
auto unknownCksum: nonIanaChecksums) {
999 unknownCksumString += unknownCksum +
",";
1001 unknownCksumString.erase(unknownCksumString.size() - 1);
1002 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1003 eDest.
Say(warningMsgSS.str().c_str());
1009 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1011 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1046 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1047 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1048 Config.Attach(cfgFD);
1049 static const char *cvec[] = {
"*** http protocol config:", 0 };
1050 Config.Capture(cvec);
1054 while ((var = Config.GetMyFirstWord())) {
1055 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1058 if TS_Xeq(
"trace", xtrace);
1059 else if TS_Xeq(
"cert", xsslcert);
1060 else if TS_Xeq(
"key", xsslkey);
1061 else if TS_Xeq(
"cadir", xsslcadir);
1062 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1063 else if TS_Xeq(
"gridmap", xgmap);
1064 else if TS_Xeq(
"cafile", xsslcafile);
1065 else if TS_Xeq(
"secretkey", xsecretkey);
1066 else if TS_Xeq(
"desthttps", xdesthttps);
1067 else if TS_Xeq(
"secxtractor", xsecxtractor);
1068 else if TS_Xeq3(
"exthandler", xexthandler);
1069 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1070 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1071 else if TS_Xeq(
"listingredir", xlistredir);
1072 else if TS_Xeq(
"staticredir", xstaticredir);
1073 else if TS_Xeq(
"staticpreload", xstaticpreload);
1074 else if TS_Xeq(
"listingdeny", xlistdeny);
1075 else if TS_Xeq(
"header2cgi", xheader2cgi);
1076 else if TS_Xeq(
"httpsmode", xhttpsmode);
1077 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1078 else if TS_Xeq(
"auth", xauth);
1080 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1095 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1101 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1104 if (getenv(
"XRDCL_EC")) usingEC =
true;
1113 :
"was not configured.");
1114 const char *what = Configed();
1116 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1119 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1121 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1131 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1132 "is meaningless; ignoring key!");
1140 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1141 "a cert specification!");
1152 const char *what1 = 0, *what2 = 0, *what3 = 0;
1157 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1161 what2 =
"xrd.tlsca to supply 'cadir'.";
1165 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1166 :
"xrd.tlsca to supply 'cafile'.");
1170 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1180 {
const char *what = Configed();
1181 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1182 :
"'xrd.tlsca noverify' was specified!");
1184 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1192 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1197 const char *how =
"completed.";
1198 eDest.
Say(
"++++++ HTTPS initialization started.");
1199 if (!InitTLS()) {NoGo = 1; how =
"failed.";}
1200 eDest.
Say(
"------ HTTPS initialization ", how);
1201 if (NoGo)
return NoGo;
1205 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1209 return (InitSecurity() ? NoGo : 1);
1216const char *XrdHttpProtocol::Configed()
1218 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1219 if (secxtractor)
return "secxtractor requires";
1220 if (
gridmap)
return "gridmap requires";
1236 if (myBuffEnd >= myBuffStart) {
1238 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1243 dest.
assign(myBuffStart, 0, l-1);
1262 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1264 if ((*p ==
'\n') || (*p ==
'\0')) {
1267 dest.
assign(myBuffStart, 0, l-1);
1283 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1285 if ((*p ==
'\n') || (*p ==
'\0')) {
1289 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1291 dest.
assign(myBuffStart, 0, l1-1);
1295 dest.
insert(myBuffStart, l1, l-1);
1319int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1334 maxread = std::min(blen, BuffAvailable());
1335 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1341 int sslavail = maxread;
1344 int l = SSL_pending(ssl);
1346 sslavail = std::min(maxread, SSL_pending(ssl));
1351 ERR_print_errors(sslbio_err);
1355 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1356 if (sslavail <= 0)
return 0;
1358 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1360 myBuffEnd = myBuff->
buff;
1363 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1366 ERR_print_errors(sslbio_err);
1373 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1375 myBuffEnd = myBuff->
buff;
1381 rlen =
Link->
Recv(myBuffEnd, maxread);
1397 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1404int XrdHttpProtocol::BuffAvailable() {
1407 if (myBuffEnd >= myBuffStart)
1408 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1410 r = myBuffStart - myBuffEnd;
1412 if ((r < 0) || (r > myBuff->
bsize)) {
1413 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1426int XrdHttpProtocol::BuffUsed() {
1429 if (myBuffEnd >= myBuffStart)
1430 r = myBuffEnd - myBuffStart;
1433 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1435 if ((r < 0) || (r > myBuff->
bsize)) {
1436 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1449int XrdHttpProtocol::BuffFree() {
1450 return (myBuff->
bsize - BuffUsed());
1457void XrdHttpProtocol::BuffConsume(
int blen) {
1459 if (blen > myBuff->
bsize) {
1460 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1464 if (blen > BuffUsed()) {
1465 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1469 myBuffStart = myBuffStart + blen;
1471 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1472 myBuffStart -= myBuff->
bsize;
1474 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1475 myBuffEnd -= myBuff->
bsize;
1477 if (BuffUsed() == 0)
1478 myBuffStart = myBuffEnd = myBuff->
buff;
1493int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1496 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1501 if (blen > BuffUsed()) {
1502 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1503 if ( getDataOneShot(blen - BuffUsed(),
true) )
1509 if ( !BuffUsed() ) {
1510 if ( getDataOneShot(blen,
false) )
1518 if (myBuffStart <= myBuffEnd) {
1519 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1522 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1524 *data = myBuffStart;
1535int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1539 if (body && bodylen) {
1540 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1542 r = SSL_write(ssl, body, bodylen);
1544 ERR_print_errors(sslbio_err);
1550 if (r <= 0)
return -1;
1561int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1562 std::stringstream ss;
1563 const std::string crlf =
"\r\n";
1565 ss <<
"HTTP/1.1 " << code <<
" ";
1569 if (code == 200) ss <<
"OK";
1570 else if (code == 100) ss <<
"Continue";
1571 else if (code == 206) ss <<
"Partial Content";
1572 else if (code == 302) ss <<
"Redirect";
1573 else if (code == 307) ss <<
"Temporary Redirect";
1574 else if (code == 400) ss <<
"Bad Request";
1575 else if (code == 403) ss <<
"Forbidden";
1576 else if (code == 404) ss <<
"Not Found";
1577 else if (code == 405) ss <<
"Method Not Allowed";
1578 else if (code == 416) ss <<
"Range Not Satisfiable";
1579 else if (code == 500) ss <<
"Internal Server Error";
1580 else if (code == 504) ss <<
"Gateway Timeout";
1581 else ss <<
"Unknown";
1584 if (keepalive && (code != 100))
1585 ss <<
"Connection: Keep-Alive" << crlf;
1587 ss <<
"Connection: Close" << crlf;
1589 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1591 if ((bodylen >= 0) && (code != 100))
1592 ss <<
"Content-Length: " << bodylen << crlf;
1594 if (header_to_add && (header_to_add[0] !=
'\0'))
1595 ss << header_to_add << crlf;
1599 const std::string &outhdr = ss.str();
1600 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1601 if (SendData(outhdr.c_str(), outhdr.size()))
1611int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1612 const std::string crlf =
"\r\n";
1613 std::stringstream ss;
1615 if (header_to_add && (header_to_add[0] !=
'\0')) {
1616 ss << header_to_add << crlf;
1619 ss <<
"Transfer-Encoding: chunked";
1620 TRACEI(RSP,
"Starting chunked response");
1621 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1628int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1629 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1630 if (ChunkRespHeader(content_length))
1633 if (body && SendData(body, content_length))
1636 return ChunkRespFooter();
1643int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1644 const std::string crlf =
"\r\n";
1645 std::stringstream ss;
1647 ss << std::hex << bodylen << std::dec << crlf;
1649 const std::string &chunkhdr = ss.str();
1650 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1651 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1658int XrdHttpProtocol::ChunkRespFooter() {
1659 const std::string crlf =
"\r\n";
1660 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1671int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1673 long long content_length = bodylen;
1675 content_length = body ? strlen(body) : 0;
1678 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1685 return SendData(body, content_length);
1722 sprintf(buf,
"%d",
Port);
1728 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1729 if (rdf && Config(rdf, pi->
theEnv))
return 0;
1734 if ((rdf = getenv(
"XRDROLE"))) {
1737 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1739 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1742 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1746 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1765 char *val, keybuf[1024], parmbuf[1024];
1769 val = Config.GetWord();
1770 if (!val || !val[0]) {
1771 err.
Emsg(
"Config",
"No headerkey specified.");
1776 while ( *val && !isalnum(*val) ) val++;
1777 strcpy(keybuf, val);
1781 pp = keybuf + strlen(keybuf) - 1;
1782 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1787 parm = Config.GetWord();
1790 if(!parm || !parm[0]) {
1791 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1796 while ( *parm && !isalnum(*parm) ) parm++;
1797 strcpy(parmbuf, parm);
1800 pp = parmbuf + strlen(parmbuf) - 1;
1801 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1808 header2cgi[keybuf] = parmbuf;
1810 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1823bool XrdHttpProtocol::InitTLS() {
1848 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1849 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1855 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1868void XrdHttpProtocol::Cleanup() {
1870 TRACE(ALL,
" Cleanup");
1872 if (
BPool && myBuff) {
1873 BuffConsume(BuffUsed());
1887 int ret = SSL_shutdown(ssl);
1891 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1892 ERR_remove_thread_state(
nullptr);
1896 TRACE(ALL,
" SSL_shutdown failed");
1897 ERR_print_errors(sslbio_err);
1931void XrdHttpProtocol::Reset() {
1933 TRACE(ALL,
" Reset");
1942 myBuffStart = myBuffEnd = 0;
1945 DoneSetInfo =
false;
1989int XrdHttpProtocol::xhttpsmode(
XrdOucStream & Config) {
1995 if (!val || !val[0]) {
1996 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2005 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2024int XrdHttpProtocol::xsslverifydepth(
XrdOucStream & Config) {
2030 if (!val || !val[0]) {
2031 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2062 if (!val || !val[0]) {
2063 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2097 if (!val || !val[0]) {
2098 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2134 if (!val || !val[0]) {
2135 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2141 if (!strncmp(val,
"required", 8)) {
2145 if (!val || !val[0]) {
2146 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2154 if (!strcmp(val,
"compatNameGeneration")) {
2157 if (!val || !val[0]) {
2158 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2159 "[compatNameGeneration] parameter");
2185int XrdHttpProtocol::xsslcafile(
XrdOucStream & Config) {
2191 if (!val || !val[0]) {
2192 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2218int XrdHttpProtocol::xsecretkey(
XrdOucStream & Config) {
2220 bool inFile =
false;
2225 if (!val || !val[0]) {
2226 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2234 if (val[0] ==
'/') {
2237 if (
stat(val, &st) ) {
2238 eDest.
Emsg(
"Config", errno,
"stat shared secret key file", val);
2242 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2243 eDest.
Emsg(
"Config",
"For your own security, the shared secret key file cannot be world readable or group writable'", val,
"'");
2247 FILE *fp =
fopen(val,
"r");
2250 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2255 while( fgets(line, 1024, fp) ) {
2259 pp = line + strlen(line) - 1;
2260 while ( (pp >= line) && (!isalnum(*pp)) ) {
2267 while ( *pp && !isalnum(*pp) ) pp++;
2269 if ( strlen(pp) >= 32 ) {
2270 eDest.
Say(
"Config",
"Secret key loaded.");
2282 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2287 if ( strlen(val) < 32 ) {
2288 eDest.
Emsg(
"Config",
"Secret key is too short");
2295 if (!inFile)
Config.noEcho();
2319 if (!val || !val[0]) {
2320 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2326 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2345int XrdHttpProtocol::xlistredir(
XrdOucStream & Config) {
2351 if (!val || !val[0]) {
2352 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2378int XrdHttpProtocol::xdesthttps(
XrdOucStream & Config) {
2384 if (!val || !val[0]) {
2385 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2391 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2410int XrdHttpProtocol::xembeddedstatic(
XrdOucStream & Config) {
2416 if (!val || !val[0]) {
2417 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2423 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2442int XrdHttpProtocol::xstaticredir(
XrdOucStream & Config) {
2448 if (!val || !val[0]) {
2449 eDest.
Emsg(
"Config",
"staticredir url not specified");
2477int XrdHttpProtocol::xstaticpreload(
XrdOucStream & Config) {
2478 char *val, *k, key[1024];
2484 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2493 if (!val || !val[0]) {
2494 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2499 int fp =
open(val, O_RDONLY);
2501 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2505 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2507 nfo->data = (
char *)malloc(65536);
2508 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2511 if (nfo->len <= 0) {
2512 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2516 if (nfo->len >= 65536) {
2517 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2543int XrdHttpProtocol::xselfhttps2http(
XrdOucStream & Config) {
2549 if (!val || !val[0]) {
2550 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2556 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2578int XrdHttpProtocol::xsecxtractor(
XrdOucStream& Config) {
2584 if (!val || !val[0]) {
2585 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2590 if (!strncmp(val,
"required", 8)) {
2591 isRequiredXtractor =
true;
2594 if (!val || !val[0]) {
2595 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2602 strlcpy(libName, val,
sizeof(libName));
2603 libName[
sizeof(libName) - 1] =
'\0';
2604 char libParms[4096];
2606 if (!
Config.GetRest(libParms, 4095)) {
2607 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2613 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2639 std::vector<extHInfo> &hiVec) {
2640 char *val, path[1024], namebuf[1024];
2643 bool noTlsOK =
false;
2648 if (!val || !val[0]) {
2649 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2652 if (strlen(val) >= 16) {
2653 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2656 strncpy(namebuf, val,
sizeof(namebuf));
2657 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2662 if(val && !strcmp(
"+notls",val)) {
2669 if (!val || !val[0]) {
2670 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2673 if (strlen(val) >= (
int)
sizeof(path)) {
2674 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2686 for (
int i = 0; i < (int)hiVec.size(); i++)
2687 {
if (hiVec[i].extHName == namebuf) {
2688 eDest.
Emsg(
"Config",
"Instance name already present for "
2689 "http external handler plugin",
2690 hiVec[i].extHPath.c_str());
2698 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2704 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2725int XrdHttpProtocol::xheader2cgi(
XrdOucStream & Config) {
2748 if (!val || !val[0]) {
2749 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2776int XrdHttpProtocol::xsslcipherfilter(
XrdOucStream & Config) {
2782 if (!val || !val[0]) {
2783 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2813 if (!val || !val[0])
2814 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2818 if (!strcmp(val,
"off"))
2825 if (!strcmp(val,
"on"))
2832 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2837 char *val =
Config.GetWord();
2839 if(!strcmp(
"tpc",val)) {
2840 if(!(val =
Config.GetWord())) {
2841 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2843 if(!strcmp(
"fcreds",val)) {
2846 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2850 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
2874 static struct traceopts {
2886 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
2888 if (!(val =
Config.GetWord())) {
2889 eDest.
Emsg(
"config",
"trace option not specified");
2893 if (!strcmp(val,
"off")) trval = 0;
2895 if ((neg = (val[0] ==
'-' && val[1]))) val++;
2896 for (i = 0; i < numopts; i++) {
2897 if (!strcmp(val, tropts[i].opname)) {
2898 if (neg) trval &= ~tropts[i].opval;
2899 else trval |= tropts[i].opval;
2904 eDest.
Emsg(
"config",
"invalid trace option", val);
2923 l = strlen(fname) + 1;
2948 length = fname.
length() + 1;
2960int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
2961 const char *libParms) {
2965 if (secxtractor)
return 1;
2967 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
2973 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
2981int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
2982 for (
int i = 0; i < (int) hiVec.size(); i++) {
2983 if(hiVec[i].extHNoTlsOK) {
2985 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
2986 hiVec[i].extHParm.c_str(), &myEnv,
2987 hiVec[i].extHName.c_str()))
2994int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3006 for (
int i = 0; i < (int)hiVec.size(); i++) {
3009 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3010 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3011 hiVec[i].extHParm.c_str(), &myEnv,
3012 hiVec[i].extHName.c_str()))
return 1;
3019int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3020 const char *configFN,
const char *libParms,
3021 XrdOucEnv *myEnv,
const char *instName) {
3025 if (ExtHandlerLoaded(instName)) {
3026 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3030 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3034 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3042 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3045 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3046 exthandler[exthandlercnt].name[15] =
'\0';
3047 exthandler[exthandlercnt++].ptr = newhandler;
3060bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3061 for (
int i = 0; i < exthandlercnt; i++) {
3062 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3073 for (
int i = 0; i < exthandlercnt; i++) {
3075 return exthandler[i].ptr;
struct ClientSetRequest set
struct ClientQueryRequest query
struct ClientStatRequest stat
#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)
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
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.
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
void Release(XrdBuffer *bp)
XrdBuffer * Obtain(int bsz)
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 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 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.
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.
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 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
ReqType request
The request we got.
XrdOucEnv * opaque
The opaque data, after parsing.
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)
ClientRequest xrdreq
The last issued xrd request, often pending.
virtual int InitSSL(SSL *, char *)
virtual int FreeSSL(SSL *)
int setEtext(const char *text)
int Peek(char *buff, int blen, int timeout=-1)
int Recv(char *buff, int blen)
const XrdNetAddr * NetAddr() const
XrdNetAddrInfo * AddrInfo()
int Send(const char *buff, int blen)
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 Set(int inQMax, time_t agemax=1800)
void Push(XrdObject< T > *Node)
static bool Import(const char *var, char *&val)
char * Get(const char *varname)
void * GetPtr(const char *varname)
void Put(const char *varname, const char *value)
T * Rep(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
void insert(const int i, int start=-1)
void assign(const char *s, int j, int k=-1)
const char * c_str() const
static std::string obfuscate(const std::string &input, const std::unordered_set< std::string > &keysToObfuscate, const char keyValueDelimiter, const char listDelimiter)
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
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.