24 #include "XrdVersion.hh"
48 #include <openssl/err.h>
49 #include <openssl/ssl.h>
51 #include <arpa/inet.h>
58 #define XRHTTP_TK_GRACETIME 600
99 BIO *XrdHttpProtocol::sslbio_err = 0;
101 bool XrdHttpProtocol::isRequiredXtractor =
false;
103 int XrdHttpProtocol::exthandlercnt = 0;
106 bool XrdHttpProtocol::usingEC = false;
107 bool XrdHttpProtocol::hasCache= false;
128 const char *TraceID =
"Protocol";
155 "xrootd protocol anchor");
161 #if OPENSSL_VERSION_NUMBER < 0x10100000L
168 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
183 bio->shutdown = shut;
186 return bio->shutdown;
198 :
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
199 SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
224 char mybuf[16], mybuf2[1024];
227 bool myishttps =
false;
231 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
232 if (dlen <= 0) lp->
setEtext(
"handshake not received");
235 mybuf[dlen - 1] =
'\0';
243 for (
int i = 0; i < dlen; i++) {
245 sprintf(mybuf3,
"%.02d ", mybuf[i]);
246 strcat(mybuf2, mybuf3);
253 for (
int i = 0; i < dlen - 1; i++)
254 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
256 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
261 if ((!ismine) && (dlen >= 4)) {
262 char check[4] = {00, 00, 00, 00};
263 if (memcmp(mybuf, check, 4)) {
270 TRACEI(ALL,
"This may look like https, but https is not configured");
277 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
285 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
288 hp->ishttps = myishttps;
303 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
311 char *XrdHttpProtocol::GetClientIPStr() {
314 if (!
Link)
return strdup(
"unknown");
316 if (!ai)
return strdup(
"unknown");
324 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
335 int ret = lp->
Send(data, datal);
336 BIO_clear_retry_flags(bio);
339 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
340 BIO_set_retry_write(bio);
356 int ret = lp->
Send(data, datal);
357 BIO_clear_retry_flags(bio);
359 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
360 BIO_set_retry_write(bio);
367 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
378 int ret = lp->
Recv(data, datal);
379 BIO_clear_retry_flags(bio);
382 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
383 BIO_set_retry_read(bio);
398 int ret = lp->
Recv(data, datal);
399 BIO_clear_retry_flags(bio);
401 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
402 BIO_set_retry_read(bio);
418 #if OPENSSL_VERSION_NUMBER < 0x10100000L
430 if (bio == NULL)
return 0;
446 case BIO_CTRL_GET_CLOSE:
449 case BIO_CTRL_SET_CLOSE:
464 BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
483 #define TRACELINK Link
491 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
492 TRACE(ALL,
" Process. No buffer available. Internal error.");
498 char *nfo = GetClientIPStr();
500 TRACEI(REQ,
" Setting host: " << nfo);
509 if (ishttps && !ssldone) {
512 sbio = CreateBIO(
Link);
513 BIO_set_nbio(sbio, 1);
515 TRACE(ALL,
"Failed to configure the TLS client authentication; invalid configuration");
523 ERR_print_errors(sslbio_err);
532 SSL_set_bio(ssl, sbio, sbio);
539 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
540 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
543 int res = SSL_accept(ssl);
545 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
546 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
551 ERR_print_errors(sslbio_err);
560 BIO_set_nbio(sbio, 0);
565 if (
tlsClientAuth == XrdTlsContext::ClientAuthSetting::kOn && HandleAuthentication(
Link)) {
586 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
592 if (BuffUsed() < ResumeBytes)
return 1;
600 if (mon_info.size() >= 1024) {
601 TRACEI(ALL,
"User agent string too long");
603 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
612 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
627 while ((rc = BuffgetLine(tmpline)) > 0) {
628 std::string traceLine = tmpline.
c_str();
632 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
633 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
635 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
641 TRACE(
DEBUG,
" Parsing first line: " << traceLine.c_str());
644 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
650 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
651 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
662 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
667 if ((rc <= 0) && (BuffUsed() >= 16384)) {
668 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
687 time_t timenow = time(0);
705 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
712 struct sockaddr_storage sa;
713 socklen_t sl =
sizeof(sa);
720 switch (sa.ss_family) {
722 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
729 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
731 Addr_str = (
char *)malloc(strlen(buf)+3);
739 TRACEI(REQ,
" Can't recognize the address family of the local host.");
747 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
748 << dest.
c_str() <<
"'");
752 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
757 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
761 TRACEI(ALL,
" Could not calculate self-redirection hash");
767 if (!ishttps && !ssldone) {
777 if (t) tim = atoi(t);
779 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
783 TRACEI(REQ,
" Token expired. Authentication failed.");
868 TRACEI(REQ,
" Invalid tk '" << tk <<
"' != '" << hash <<
"'(calculated). Authentication failed.");
875 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
883 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
903 TRACEI(REQ,
" Authorization failed.");
919 TRACEI(REQ,
"Process is exiting rc:" << rc);
927 #define TRACELINK Link
981 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
983 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
985 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
986 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
987 eDest.Say("Config http." x " overrides the xrd." y " directive.")
989 int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
992 std::vector<extHInfo> extHIVec;
994 int cfgFD, GoNo, NoGo = 0, ismine;
1004 if(nonIanaChecksums.size()) {
1005 std::stringstream warningMsgSS;
1006 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
1007 std::string unknownCksumString;
1008 for(
auto unknownCksum: nonIanaChecksums) {
1009 unknownCksumString += unknownCksum +
",";
1011 unknownCksumString.erase(unknownCksumString.size() - 1);
1012 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1013 eDest.
Say(warningMsgSS.str().c_str());
1019 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1021 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1056 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1057 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1059 static const char *cvec[] = {
"*** http protocol config:", 0 };
1064 while ((var =
Config.GetMyFirstWord())) {
1065 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1068 if TS_Xeq(
"trace", xtrace);
1069 else if TS_Xeq(
"cert", xsslcert);
1070 else if TS_Xeq(
"key", xsslkey);
1071 else if TS_Xeq(
"cadir", xsslcadir);
1072 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1073 else if TS_Xeq(
"gridmap", xgmap);
1074 else if TS_Xeq(
"cafile", xsslcafile);
1075 else if TS_Xeq(
"secretkey", xsecretkey);
1076 else if TS_Xeq(
"desthttps", xdesthttps);
1077 else if TS_Xeq(
"secxtractor", xsecxtractor);
1078 else if TS_Xeq3(
"exthandler", xexthandler);
1079 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1080 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1081 else if TS_Xeq(
"listingredir", xlistredir);
1082 else if TS_Xeq(
"staticredir", xstaticredir);
1083 else if TS_Xeq(
"staticpreload", xstaticpreload);
1084 else if TS_Xeq(
"staticheader", xstaticheader);
1085 else if TS_Xeq(
"listingdeny", xlistdeny);
1086 else if TS_Xeq(
"header2cgi", xheader2cgi);
1087 else if TS_Xeq(
"httpsmode", xhttpsmode);
1088 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1089 else if TS_Xeq(
"auth", xauth);
1090 else if TS_Xeq(
"tlsclientauth", xtlsclientauth);
1092 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1107 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1113 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1116 if (getenv(
"XRDCL_EC"))
usingEC =
true;
1121 std::string default_static_headers;
1123 for (
const auto &header_entry : default_verb->second) {
1124 default_static_headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1129 if (item.first.empty()) {
1132 auto headers = default_static_headers;
1133 for (
const auto &header_entry : item.second) {
1134 headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1142 if (myEnv->
Get(
"XrdCache")) hasCache =
true;
1151 :
"was not configured.");
1152 const char *what = Configed();
1154 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1157 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1159 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1169 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1170 "is meaningless; ignoring key!");
1178 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1179 "a cert specification!");
1190 const char *what1 = 0, *what2 = 0, *what3 = 0;
1195 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1199 what2 =
"xrd.tlsca to supply 'cadir'.";
1203 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1204 :
"xrd.tlsca to supply 'cafile'.");
1208 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1218 {
const char *what = Configed();
1219 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1220 :
"'xrd.tlsca noverify' was specified!");
1222 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1230 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1235 const char *how =
"completed.";
1236 eDest.
Say(
"++++++ HTTPS initialization started.");
1237 if (!
InitTLS()) {NoGo = 1; how =
"failed.";}
1238 eDest.
Say(
"------ HTTPS initialization ", how);
1239 if (NoGo)
return NoGo;
1243 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1247 return (InitSecurity() ? NoGo : 1);
1254 const char *XrdHttpProtocol::Configed()
1256 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1257 if (secxtractor)
return "secxtractor requires";
1258 if (
gridmap)
return "gridmap requires";
1274 if (myBuffEnd >= myBuffStart) {
1276 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1281 dest.
assign(myBuffStart, 0, l-1);
1300 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1302 if ((*p ==
'\n') || (*p ==
'\0')) {
1305 dest.
assign(myBuffStart, 0, l-1);
1321 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1323 if ((*p ==
'\n') || (*p ==
'\0')) {
1327 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1329 dest.
assign(myBuffStart, 0, l1-1);
1333 dest.
insert(myBuffStart, l1, l-1);
1357 int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1372 maxread = std::min(blen, BuffAvailable());
1373 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1379 int sslavail = maxread;
1382 int l = SSL_pending(ssl);
1384 sslavail = std::min(maxread, SSL_pending(ssl));
1389 ERR_print_errors(sslbio_err);
1393 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1394 if (sslavail <= 0)
return 0;
1396 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1398 myBuffEnd = myBuff->
buff;
1401 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1404 ERR_print_errors(sslbio_err);
1411 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1413 myBuffEnd = myBuff->
buff;
1419 rlen =
Link->
Recv(myBuffEnd, maxread);
1435 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1442 int XrdHttpProtocol::BuffAvailable() {
1445 if (myBuffEnd >= myBuffStart)
1446 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1448 r = myBuffStart - myBuffEnd;
1450 if ((r < 0) || (r > myBuff->
bsize)) {
1451 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1464 int XrdHttpProtocol::BuffUsed() {
1467 if (myBuffEnd >= myBuffStart)
1468 r = myBuffEnd - myBuffStart;
1471 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1473 if ((r < 0) || (r > myBuff->
bsize)) {
1474 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1487 int XrdHttpProtocol::BuffFree() {
1488 return (myBuff->
bsize - BuffUsed());
1495 void XrdHttpProtocol::BuffConsume(
int blen) {
1497 if (blen > myBuff->
bsize) {
1498 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1502 if (blen > BuffUsed()) {
1503 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1507 myBuffStart = myBuffStart + blen;
1509 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1510 myBuffStart -= myBuff->
bsize;
1512 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1513 myBuffEnd -= myBuff->
bsize;
1515 if (BuffUsed() == 0)
1516 myBuffStart = myBuffEnd = myBuff->
buff;
1531 int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1534 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1539 if (blen > BuffUsed()) {
1540 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1541 if ( getDataOneShot(blen - BuffUsed(),
true) )
1547 if ( !BuffUsed() ) {
1548 if ( getDataOneShot(blen,
false) )
1556 if (myBuffStart <= myBuffEnd) {
1557 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1560 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1562 *data = myBuffStart;
1573 int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1577 if (body && bodylen) {
1578 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1580 r = SSL_write(ssl, body, bodylen);
1582 ERR_print_errors(sslbio_err);
1588 if (r <= 0)
return -1;
1599 int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1600 std::stringstream ss;
1601 const std::string crlf =
"\r\n";
1603 ss <<
"HTTP/1.1 " << code <<
" ";
1607 if (code == 200) ss <<
"OK";
1608 else if (code == 100) ss <<
"Continue";
1609 else if (code == 201) ss <<
"Created";
1610 else if (code == 206) ss <<
"Partial Content";
1611 else if (code == 302) ss <<
"Redirect";
1612 else if (code == 307) ss <<
"Temporary Redirect";
1613 else if (code == 400) ss <<
"Bad Request";
1614 else if (code == 401) ss <<
"Unauthorized";
1615 else if (code == 403) ss <<
"Forbidden";
1616 else if (code == 404) ss <<
"Not Found";
1617 else if (code == 405) ss <<
"Method Not Allowed";
1618 else if (code == 409) ss <<
"Conflict";
1619 else if (code == 416) ss <<
"Range Not Satisfiable";
1620 else if (code == 423) ss <<
"Locked";
1621 else if (code == 500) ss <<
"Internal Server Error";
1622 else if (code == 502) ss <<
"Bad Gateway";
1623 else if (code == 504) ss <<
"Gateway Timeout";
1624 else ss <<
"Unknown";
1627 if (keepalive && (code != 100))
1628 ss <<
"Connection: Keep-Alive" << crlf;
1630 ss <<
"Connection: Close" << crlf;
1632 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1641 if ((bodylen >= 0) && (code != 100))
1642 ss <<
"Content-Length: " << bodylen << crlf;
1644 if (header_to_add && (header_to_add[0] !=
'\0'))
1645 ss << header_to_add << crlf;
1649 const std::string &outhdr = ss.str();
1650 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1651 if (SendData(outhdr.c_str(), outhdr.size()))
1661 int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1662 const std::string crlf =
"\r\n";
1663 std::stringstream ss;
1665 if (header_to_add && (header_to_add[0] !=
'\0')) {
1666 ss << header_to_add << crlf;
1669 ss <<
"Transfer-Encoding: chunked";
1670 TRACEI(RSP,
"Starting chunked response");
1671 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1678 int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1679 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1680 if (ChunkRespHeader(content_length))
1683 if (body && SendData(body, content_length))
1686 return ChunkRespFooter();
1693 int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1694 const std::string crlf =
"\r\n";
1695 std::stringstream ss;
1699 const std::string &chunkhdr = ss.str();
1700 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1701 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1708 int XrdHttpProtocol::ChunkRespFooter() {
1709 const std::string crlf =
"\r\n";
1710 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1721 int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1723 long long content_length = bodylen;
1725 content_length = body ? strlen(body) : 0;
1728 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1735 return SendData(body, content_length);
1772 sprintf(buf,
"%d",
Port);
1778 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1784 if ((rdf = getenv(
"XRDROLE"))) {
1787 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1789 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1792 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1796 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1815 char *val, keybuf[1024], parmbuf[1024];
1820 if (!val || !val[0]) {
1821 err.
Emsg(
"Config",
"No headerkey specified.");
1826 while ( *val && !isalnum(*val) ) val++;
1827 strcpy(keybuf, val);
1831 pp = keybuf + strlen(keybuf) - 1;
1832 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1840 if(!parm || !parm[0]) {
1841 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1846 while ( *parm && !isalnum(*parm) ) parm++;
1847 strcpy(parmbuf, parm);
1850 pp = parmbuf + strlen(parmbuf) - 1;
1851 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1858 header2cgi[keybuf] = parmbuf;
1860 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1873 bool XrdHttpProtocol::InitTLS() {
1898 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1899 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1905 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1918 void XrdHttpProtocol::Cleanup() {
1920 TRACE(ALL,
" Cleanup");
1922 if (
BPool && myBuff) {
1923 BuffConsume(BuffUsed());
1937 int ret = SSL_shutdown(ssl);
1941 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1942 ERR_remove_thread_state(
nullptr);
1946 TRACE(ALL,
" SSL_shutdown failed");
1947 ERR_print_errors(sslbio_err);
1981 void XrdHttpProtocol::Reset() {
1983 TRACE(ALL,
" Reset");
1992 myBuffStart = myBuffEnd = 0;
1995 DoneSetInfo =
false;
2045 if (!val || !val[0]) {
2046 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2055 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2080 if (!val || !val[0]) {
2081 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2112 if (!val || !val[0]) {
2113 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2147 if (!val || !val[0]) {
2148 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2184 if (!val || !val[0]) {
2185 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2191 if (!strncmp(val,
"required", 8)) {
2195 if (!val || !val[0]) {
2196 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2204 if (!strcmp(val,
"compatNameGeneration")) {
2207 if (!val || !val[0]) {
2208 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2209 "[compatNameGeneration] parameter");
2241 if (!val || !val[0]) {
2242 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2270 bool inFile =
false;
2275 if (!val || !val[0]) {
2276 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2284 if (val[0] ==
'/') {
2287 int fd =
open(val, O_RDONLY);
2290 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2294 if (
fstat(fd, &st) != 0 ) {
2295 eDest.
Emsg(
"Config", errno,
"fstat shared secret key file", val);
2300 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2302 "For your own security, the shared secret key file cannot be world readable or group writable '", val,
"'");
2307 FILE *fp = fdopen(fd,
"r");
2309 if ( fp ==
nullptr ) {
2310 eDest.
Emsg(
"Config", errno,
"fdopen shared secret key file", val);
2316 while( fgets(line, 1024, fp) ) {
2320 pp = line + strlen(line) - 1;
2321 while ( (pp >= line) && (!isalnum(*pp)) ) {
2328 while ( *pp && !isalnum(*pp) ) pp++;
2330 if ( strlen(pp) >= 32 ) {
2331 eDest.
Say(
"Config",
"Secret key loaded.");
2343 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2348 if ( strlen(val) < 32 ) {
2349 eDest.
Emsg(
"Config",
"Secret key is too short");
2356 if (!inFile)
Config.noEcho();
2380 if (!val || !val[0]) {
2381 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2387 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2412 if (!val || !val[0]) {
2413 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2445 if (!val || !val[0]) {
2446 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2452 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2477 if (!val || !val[0]) {
2478 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2484 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2509 if (!val || !val[0]) {
2510 eDest.
Emsg(
"Config",
"staticredir url not specified");
2539 char *val, *k, key[1024];
2545 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2554 if (!val || !val[0]) {
2555 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2560 int fp =
open(val, O_RDONLY);
2562 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2566 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2568 nfo->data = (
char *)malloc(65536);
2569 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2572 if (nfo->len <= 0) {
2573 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2577 if (nfo->len >= 65536) {
2578 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2609 auto val =
Config.GetWord();
2610 std::vector<std::string> verbs;
2612 if (!val || !val[0]) {
2613 eDest.
Emsg(
"Config",
"http.staticheader requires the header to be specified");
2617 std::string match_verb;
2618 std::string_view val_str(val);
2619 if (val_str.substr(0, 6) ==
"-verb=") {
2620 verbs.emplace_back(val_str.substr(6));
2621 }
else if (val_str ==
"-") {
2622 eDest.
Emsg(
"Config",
"http.staticheader is ignoring unknown flag: ", val_str.data());
2629 if (verbs.empty()) {
2630 verbs.emplace_back();
2633 std::string header = val;
2636 std::string header_value;
2637 if (val && val[0]) {
2641 for (
const auto &verb : verbs) {
2644 if (!header_value.empty())
2646 }
else if (header_value.empty()) {
2647 iter->second.clear();
2649 iter->second.emplace_back(header, header_value);
2676 if (!val || !val[0]) {
2677 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2683 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2711 if (!val || !val[0]) {
2712 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2717 if (!strncmp(val,
"required", 8)) {
2718 isRequiredXtractor =
true;
2721 if (!val || !val[0]) {
2722 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2729 strlcpy(libName, val,
sizeof(libName));
2730 libName[
sizeof(libName) - 1] =
'\0';
2731 char libParms[4096];
2733 if (!
Config.GetRest(libParms, 4095)) {
2734 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2740 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2766 std::vector<extHInfo> &hiVec) {
2767 char *val, path[1024], namebuf[1024];
2770 bool noTlsOK =
false;
2775 if (!val || !val[0]) {
2776 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2779 if (strlen(val) >= 16) {
2780 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2783 strncpy(namebuf, val,
sizeof(namebuf));
2784 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2789 if(val && !strcmp(
"+notls",val)) {
2796 if (!val || !val[0]) {
2797 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2800 if (strlen(val) >= (int)
sizeof(path)) {
2801 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2813 for (
int i = 0; i < (int)hiVec.size(); i++)
2814 {
if (hiVec[i].extHName == namebuf) {
2815 eDest.
Emsg(
"Config",
"Instance name already present for "
2816 "http external handler plugin",
2817 hiVec[i].extHPath.c_str());
2825 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2831 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2875 if (!val || !val[0]) {
2876 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2909 if (!val || !val[0]) {
2910 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2940 if (!val || !val[0])
2941 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2945 if (!strcmp(val,
"off"))
2952 if (!strcmp(val,
"on"))
2959 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2964 auto val =
Config.GetWord();
2965 if (!val || !val[0])
2966 {
eDest.
Emsg(
"Config",
"tlsclientauth argument not specified");
return 1;}
2968 if (!strcmp(val,
"off"))
2972 if (!strcmp(val,
"on"))
2977 eDest.
Emsg(
"config",
"invalid tlsclientauth parameter -", val);
2982 char *val =
Config.GetWord();
2984 if(!strcmp(
"tpc",val)) {
2985 if(!(val =
Config.GetWord())) {
2986 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2988 if(!strcmp(
"fcreds",val)) {
2991 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2995 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
3019 static struct traceopts {
3031 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
3033 if (!(val =
Config.GetWord())) {
3034 eDest.
Emsg(
"config",
"trace option not specified");
3038 if (!strcmp(val,
"off")) trval = 0;
3040 if ((neg = (val[0] ==
'-' && val[1]))) val++;
3041 for (i = 0; i < numopts; i++) {
3042 if (!strcmp(val, tropts[i].opname)) {
3043 if (neg) trval &= ~tropts[i].opval;
3044 else trval |= tropts[i].opval;
3049 eDest.
Emsg(
"config",
"invalid trace option", val);
3068 l = strlen(fname) + 1;
3093 length = fname.
length() + 1;
3105 int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
3106 const char *libParms) {
3110 if (secxtractor)
return 1;
3112 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
3118 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
3126 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
3127 for (
int i = 0; i < (int) hiVec.size(); i++) {
3128 if(hiVec[i].extHNoTlsOK) {
3130 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3131 hiVec[i].extHParm.c_str(), &myEnv,
3132 hiVec[i].extHName.c_str()))
3139 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3151 for (
int i = 0; i < (int)hiVec.size(); i++) {
3154 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3155 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3156 hiVec[i].extHParm.c_str(), &myEnv,
3157 hiVec[i].extHName.c_str()))
return 1;
3164 int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3165 const char *configFN,
const char *libParms,
3166 XrdOucEnv *myEnv,
const char *instName) {
3170 if (ExtHandlerLoaded(instName)) {
3171 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3175 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3179 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3187 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3190 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3191 exthandler[exthandlercnt].name[15] =
'\0';
3192 exthandler[exthandlercnt++].ptr = newhandler;
3205 bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3206 for (
int i = 0; i < exthandlercnt; i++) {
3207 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3218 for (
int i = 0; i < exthandlercnt; i++) {
3220 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")
void * BIO_get_data(BIO *bio)
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_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)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
Utility functions for XrdHTTP.
std::string decode_str(const std::string &str)
std::string obfuscateAuth(const std::string &input)
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int fstat(int fildes, struct stat *buf)
ssize_t read(int fildes, void *buf, size_t nbyte)
#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 std::unordered_map< std::string, std::vector< std::pair< std::string, std::string > > > m_staticheader_map
The static headers to always return; map is from verb to a list of (header, val) pairs.
static 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 std::unordered_map< std::string, std::string > m_staticheaders
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.
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.
const std::string & userAgent() const
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)
void * GetPtr(const char *varname)
char * Get(const char *varname)
void Put(const char *varname, const char *value)
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
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.
bool SetTlsClientAuth(ClientAuthSetting setting)
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
CloseImpl< false > Close(Ctx< File > file, uint16_t timeout=0)
Factory for creating CloseImpl objects.
XrdTlsContext::ClientAuthSetting tlsClientAuth
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.