24 #include "XrdVersion.hh"
51 #include <openssl/err.h>
52 #include <openssl/ssl.h>
54 #include <arpa/inet.h>
61 #define XRHTTP_TK_GRACETIME 600
103 BIO *XrdHttpProtocol::sslbio_err = 0;
105 bool XrdHttpProtocol::isRequiredXtractor =
false;
109 int XrdHttpProtocol::exthandlercnt = 0;
112 bool XrdHttpProtocol::usingEC = false;
113 bool XrdHttpProtocol::hasCache= false;
134 const char *TraceID =
"Protocol";
161 "xrootd protocol anchor");
167 #if OPENSSL_VERSION_NUMBER < 0x10100000L
174 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
189 bio->shutdown = shut;
192 return bio->shutdown;
204 :
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
205 SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
230 char mybuf[16], mybuf2[1024];
233 bool myishttps =
false;
237 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
238 if (dlen <= 0) lp->
setEtext(
"handshake not received");
241 mybuf[dlen - 1] =
'\0';
249 for (
int i = 0; i < dlen; i++) {
251 sprintf(mybuf3,
"%.02d ", mybuf[i]);
252 strcat(mybuf2, mybuf3);
259 for (
int i = 0; i < dlen - 1; i++)
260 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
262 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
267 if ((!ismine) && (dlen >= 4)) {
268 char check[4] = {00, 00, 00, 00};
269 if (memcmp(mybuf, check, 4)) {
276 TRACEI(ALL,
"This may look like https, but https is not configured");
283 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
291 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
294 hp->ishttps = myishttps;
309 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
317 char *XrdHttpProtocol::GetClientIPStr() {
320 if (!
Link)
return strdup(
"unknown");
322 if (!ai)
return strdup(
"unknown");
330 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
341 int ret = lp->
Send(data, datal);
342 BIO_clear_retry_flags(bio);
345 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
346 BIO_set_retry_write(bio);
362 int ret = lp->
Send(data, datal);
363 BIO_clear_retry_flags(bio);
365 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
366 BIO_set_retry_write(bio);
373 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
384 int ret = lp->
Recv(data, datal);
385 BIO_clear_retry_flags(bio);
388 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
389 BIO_set_retry_read(bio);
404 int ret = lp->
Recv(data, datal);
405 BIO_clear_retry_flags(bio);
407 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
408 BIO_set_retry_read(bio);
424 #if OPENSSL_VERSION_NUMBER < 0x10100000L
436 if (bio == NULL)
return 0;
452 case BIO_CTRL_GET_CLOSE:
455 case BIO_CTRL_SET_CLOSE:
470 BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
489 #define TRACELINK Link
497 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
498 TRACE(ALL,
" Process. No buffer available. Internal error.");
504 char *nfo = GetClientIPStr();
506 TRACEI(REQ,
" Setting host: " << nfo);
515 if (ishttps && !ssldone) {
518 sbio = CreateBIO(
Link);
519 BIO_set_nbio(sbio, 1);
525 ERR_print_errors(sslbio_err);
534 SSL_set_bio(ssl, sbio, sbio);
541 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
542 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
545 int res = SSL_accept(ssl);
547 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
548 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
553 ERR_print_errors(sslbio_err);
562 BIO_set_nbio(sbio, 0);
588 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
594 if (BuffUsed() < ResumeBytes)
return 1;
602 if (mon_info.size() >= 1024) {
603 TRACEI(ALL,
"User agent string too long");
605 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
614 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
629 while ((rc = BuffgetLine(tmpline)) > 0) {
630 std::string traceLine = tmpline.
c_str();
634 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
635 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
637 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
643 TRACE(
DEBUG,
" Parsing first line: " << traceLine.c_str());
646 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
652 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
653 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
664 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
669 if ((rc <= 0) && (BuffUsed() >= 16384)) {
670 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
689 time_t timenow = time(0);
707 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
714 struct sockaddr_storage sa;
715 socklen_t sl =
sizeof(sa);
722 switch (sa.ss_family) {
724 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
731 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
733 Addr_str = (
char *)malloc(strlen(buf)+3);
741 TRACEI(REQ,
" Can't recognize the address family of the local host.");
749 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
750 << dest.
c_str() <<
"'");
754 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
759 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
763 TRACEI(ALL,
" Could not calculate self-redirection hash");
769 if (!ishttps && !ssldone) {
779 if (t) tim = atoi(t);
781 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
785 TRACEI(REQ,
" Token expired. Authentication failed.");
870 TRACEI(REQ,
" Invalid tk '" << tk <<
"' != '" << hash <<
"'(calculated). Authentication failed.");
877 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
885 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
905 TRACEI(REQ,
" Authorization failed.");
922 TRACEI(REQ,
"Process is exiting rc:" << rc);
930 #define TRACELINK Link
984 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
986 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
988 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
989 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
990 eDest.Say("Config http." x " overrides the xrd." y " directive.")
992 int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
995 std::vector<extHInfo> extHIVec;
997 int cfgFD, GoNo, NoGo = 0, ismine;
1007 if(nonIanaChecksums.size()) {
1008 std::stringstream warningMsgSS;
1009 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
1010 std::string unknownCksumString;
1011 for(
auto unknownCksum: nonIanaChecksums) {
1012 unknownCksumString += unknownCksum +
",";
1014 unknownCksumString.erase(unknownCksumString.size() - 1);
1015 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1016 eDest.
Say(warningMsgSS.str().c_str());
1022 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1024 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1059 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1060 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1062 static const char *cvec[] = {
"*** http protocol config:", 0 };
1067 while ((var =
Config.GetMyFirstWord())) {
1068 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1071 if TS_Xeq(
"trace", xtrace);
1072 else if TS_Xeq(
"cert", xsslcert);
1073 else if TS_Xeq(
"key", xsslkey);
1074 else if TS_Xeq(
"cadir", xsslcadir);
1075 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1076 else if TS_Xeq(
"gridmap", xgmap);
1077 else if TS_Xeq(
"cafile", xsslcafile);
1078 else if TS_Xeq(
"secretkey", xsecretkey);
1079 else if TS_Xeq(
"desthttps", xdesthttps);
1080 else if TS_Xeq(
"secxtractor", xsecxtractor);
1081 else if TS_Xeq(
"cors", xcors);
1082 else if TS_Xeq3(
"exthandler", xexthandler);
1083 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1084 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1085 else if TS_Xeq(
"listingredir", xlistredir);
1086 else if TS_Xeq(
"staticredir", xstaticredir);
1087 else if TS_Xeq(
"staticpreload", xstaticpreload);
1088 else if TS_Xeq(
"staticheader", xstaticheader);
1089 else if TS_Xeq(
"listingdeny", xlistdeny);
1090 else if TS_Xeq(
"header2cgi", xheader2cgi);
1091 else if TS_Xeq(
"httpsmode", xhttpsmode);
1092 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1093 else if TS_Xeq(
"auth", xauth);
1094 else if TS_Xeq(
"tlsclientauth", xtlsclientauth);
1095 else if TS_Xeq(
"maxdelay", xmaxdelay);
1097 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1112 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1118 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1121 if (getenv(
"XRDCL_EC"))
usingEC =
true;
1126 std::string default_static_headers;
1128 for (
const auto &header_entry : default_verb->second) {
1129 default_static_headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1134 if (item.first.empty()) {
1137 auto headers = default_static_headers;
1138 for (
const auto &header_entry : item.second) {
1139 headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1147 if (myEnv->
Get(
"XrdCache")) hasCache =
true;
1166 :
"was not configured.");
1167 const char *what = Configed();
1169 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1172 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1174 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1184 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1185 "is meaningless; ignoring key!");
1193 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1194 "a cert specification!");
1205 const char *what1 = 0, *what2 = 0, *what3 = 0;
1210 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1214 what2 =
"xrd.tlsca to supply 'cadir'.";
1218 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1219 :
"xrd.tlsca to supply 'cafile'.");
1223 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1233 {
const char *what = Configed();
1234 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1235 :
"'xrd.tlsca noverify' was specified!");
1237 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1245 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1250 const char *how =
"completed.";
1251 eDest.
Say(
"++++++ HTTPS initialization started.");
1252 if (!
InitTLS()) {NoGo = 1; how =
"failed.";}
1253 eDest.
Say(
"------ HTTPS initialization ", how);
1254 if (NoGo)
return NoGo;
1258 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1262 return (InitSecurity() ? NoGo : 1);
1269 const char *XrdHttpProtocol::Configed()
1271 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1272 if (secxtractor)
return "secxtractor requires";
1273 if (
gridmap)
return "gridmap requires";
1289 if (myBuffEnd >= myBuffStart) {
1291 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1296 dest.
assign(myBuffStart, 0, l-1);
1315 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1317 if ((*p ==
'\n') || (*p ==
'\0')) {
1320 dest.
assign(myBuffStart, 0, l-1);
1336 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1338 if ((*p ==
'\n') || (*p ==
'\0')) {
1342 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1344 dest.
assign(myBuffStart, 0, l1-1);
1348 dest.
insert(myBuffStart, l1, l-1);
1372 int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1387 maxread = std::min(blen, BuffAvailable());
1388 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1394 int sslavail = maxread;
1397 int l = SSL_pending(ssl);
1399 sslavail = std::min(maxread, SSL_pending(ssl));
1404 ERR_print_errors(sslbio_err);
1408 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1409 if (sslavail <= 0)
return 0;
1411 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1413 myBuffEnd = myBuff->
buff;
1416 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1419 ERR_print_errors(sslbio_err);
1426 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1428 myBuffEnd = myBuff->
buff;
1434 rlen =
Link->
Recv(myBuffEnd, maxread);
1450 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1457 int XrdHttpProtocol::BuffAvailable() {
1460 if (myBuffEnd >= myBuffStart)
1461 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1463 r = myBuffStart - myBuffEnd;
1465 if ((r < 0) || (r > myBuff->
bsize)) {
1466 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1479 int XrdHttpProtocol::BuffUsed() {
1482 if (myBuffEnd >= myBuffStart)
1483 r = myBuffEnd - myBuffStart;
1486 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1488 if ((r < 0) || (r > myBuff->
bsize)) {
1489 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1502 int XrdHttpProtocol::BuffFree() {
1503 return (myBuff->
bsize - BuffUsed());
1510 void XrdHttpProtocol::BuffConsume(
int blen) {
1512 if (blen > myBuff->
bsize) {
1513 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1517 if (blen > BuffUsed()) {
1518 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1522 myBuffStart = myBuffStart + blen;
1524 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1525 myBuffStart -= myBuff->
bsize;
1527 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1528 myBuffEnd -= myBuff->
bsize;
1530 if (BuffUsed() == 0)
1531 myBuffStart = myBuffEnd = myBuff->
buff;
1546 int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1549 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1554 if (blen > BuffUsed()) {
1555 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1556 if ( getDataOneShot(blen - BuffUsed(),
true) )
1562 if ( !BuffUsed() ) {
1563 if ( getDataOneShot(blen,
false) )
1571 if (myBuffStart <= myBuffEnd) {
1572 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1575 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1577 *data = myBuffStart;
1588 int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1592 if (body && bodylen) {
1593 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1595 r = SSL_write(ssl, body, bodylen);
1597 ERR_print_errors(sslbio_err);
1603 if (r <= 0)
return -1;
1614 int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
1615 const char *header_to_add,
1616 long long bodylen,
bool keepalive) {
1617 std::stringstream ss;
1618 const std::string crlf =
"\r\n";
1620 ss <<
"HTTP/1.1 " << code <<
" ";
1629 if (keepalive && (code != 100))
1630 ss <<
"Connection: Keep-Alive" << crlf;
1632 ss <<
"Connection: Close" << crlf;
1634 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1645 if(corsAllowOrigin) {
1646 ss << *corsAllowOrigin << crlf;
1650 if ((bodylen >= 0) && (code != 100))
1651 ss <<
"Content-Length: " << bodylen << crlf;
1653 if (header_to_add && (header_to_add[0] !=
'\0')) ss << header_to_add << crlf;
1657 const std::string &outhdr = ss.str();
1658 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1659 if (SendData(outhdr.c_str(), outhdr.size()))
1669 int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1670 const std::string crlf =
"\r\n";
1671 std::stringstream ss;
1673 if (header_to_add && (header_to_add[0] !=
'\0')) {
1674 ss << header_to_add << crlf;
1677 ss <<
"Transfer-Encoding: chunked";
1678 TRACEI(RSP,
"Starting chunked response");
1679 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1686 int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1687 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1688 if (ChunkRespHeader(content_length))
1691 if (body && SendData(body, content_length))
1694 return ChunkRespFooter();
1701 int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1702 const std::string crlf =
"\r\n";
1703 std::stringstream ss;
1707 const std::string &chunkhdr = ss.str();
1708 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1709 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1716 int XrdHttpProtocol::ChunkRespFooter() {
1717 const std::string crlf =
"\r\n";
1718 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1729 int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1731 long long content_length = bodylen;
1733 content_length = body ? strlen(body) : 0;
1736 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1743 return SendData(body, content_length);
1780 sprintf(buf,
"%d",
Port);
1786 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1792 if ((rdf = getenv(
"XRDROLE"))) {
1795 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1797 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1800 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1804 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1823 char *val, keybuf[1024], parmbuf[1024];
1828 if (!val || !val[0]) {
1829 err.
Emsg(
"Config",
"No headerkey specified.");
1834 while ( *val && !isalnum(*val) ) val++;
1835 strcpy(keybuf, val);
1839 pp = keybuf + strlen(keybuf) - 1;
1840 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1848 if(!parm || !parm[0]) {
1849 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1854 while ( *parm && !isalnum(*parm) ) parm++;
1855 strcpy(parmbuf, parm);
1858 pp = parmbuf + strlen(parmbuf) - 1;
1859 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1866 header2cgi[keybuf] = parmbuf;
1868 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1881 bool XrdHttpProtocol::InitTLS() {
1906 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1907 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1913 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1929 void XrdHttpProtocol::Cleanup() {
1931 TRACE(ALL,
" Cleanup");
1933 if (
BPool && myBuff) {
1934 BuffConsume(BuffUsed());
1949 int ret = SSL_shutdown(ssl);
1953 ret = SSL_shutdown(ssl);
1955 TRACE(ALL,
"SSL server failed to receive the SSL shutdown message from the client");
1956 ERR_print_errors(sslbio_err);
1960 TRACE(ALL,
"SSL server failed to send the shutdown message to the client");
1961 ERR_print_errors(sslbio_err);
1995 void XrdHttpProtocol::Reset() {
1997 TRACE(ALL,
" Reset");
2006 myBuffStart = myBuffEnd = 0;
2009 DoneSetInfo =
false;
2059 if (!val || !val[0]) {
2060 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2069 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2094 if (!val || !val[0]) {
2095 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2126 if (!val || !val[0]) {
2127 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2161 if (!val || !val[0]) {
2162 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2198 if (!val || !val[0]) {
2199 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2205 if (!strncmp(val,
"required", 8)) {
2209 if (!val || !val[0]) {
2210 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2218 if (!strcmp(val,
"compatNameGeneration")) {
2221 if (!val || !val[0]) {
2222 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2223 "[compatNameGeneration] parameter");
2255 if (!val || !val[0]) {
2256 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2284 bool inFile =
false;
2289 if (!val || !val[0]) {
2290 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2298 if (val[0] ==
'/') {
2301 int fd =
open(val, O_RDONLY);
2304 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2308 if (
fstat(fd, &st) != 0 ) {
2309 eDest.
Emsg(
"Config", errno,
"fstat shared secret key file", val);
2314 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2316 "For your own security, the shared secret key file cannot be world readable or group writable '", val,
"'");
2321 FILE *fp = fdopen(fd,
"r");
2323 if ( fp ==
nullptr ) {
2324 eDest.
Emsg(
"Config", errno,
"fdopen shared secret key file", val);
2330 while( fgets(line, 1024, fp) ) {
2334 pp = line + strlen(line) - 1;
2335 while ( (pp >= line) && (!isalnum(*pp)) ) {
2342 while ( *pp && !isalnum(*pp) ) pp++;
2344 if ( strlen(pp) >= 32 ) {
2345 eDest.
Say(
"Config",
"Secret key loaded.");
2357 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2362 if ( strlen(val) < 32 ) {
2363 eDest.
Emsg(
"Config",
"Secret key is too short");
2370 if (!inFile)
Config.noEcho();
2394 if (!val || !val[0]) {
2395 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2401 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2426 if (!val || !val[0]) {
2427 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2459 if (!val || !val[0]) {
2460 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2466 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2491 if (!val || !val[0]) {
2492 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2498 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2523 if (!val || !val[0]) {
2524 eDest.
Emsg(
"Config",
"staticredir url not specified");
2553 char *val, *k, key[1024];
2559 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2568 if (!val || !val[0]) {
2569 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2574 int fp =
open(val, O_RDONLY);
2576 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2580 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2582 nfo->data = (
char *)malloc(65536);
2583 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2586 if (nfo->len <= 0) {
2587 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2591 if (nfo->len >= 65536) {
2592 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2623 auto val =
Config.GetWord();
2624 std::vector<std::string> verbs;
2626 if (!val || !val[0]) {
2627 eDest.
Emsg(
"Config",
"http.staticheader requires the header to be specified");
2631 std::string match_verb;
2632 std::string_view val_str(val);
2633 if (val_str.substr(0, 6) ==
"-verb=") {
2634 verbs.emplace_back(val_str.substr(6));
2635 }
else if (val_str ==
"-") {
2636 eDest.
Emsg(
"Config",
"http.staticheader is ignoring unknown flag: ", val_str.data());
2643 if (verbs.empty()) {
2644 verbs.emplace_back();
2647 std::string header = val;
2650 std::string header_value;
2651 if (val && val[0]) {
2655 for (
const auto &verb : verbs) {
2658 if (!header_value.empty())
2660 }
else if (header_value.empty()) {
2661 iter->second.clear();
2663 iter->second.emplace_back(header, header_value);
2690 if (!val || !val[0]) {
2691 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2697 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2725 if (!val || !val[0]) {
2726 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2731 if (!strncmp(val,
"required", 8)) {
2732 isRequiredXtractor =
true;
2735 if (!val || !val[0]) {
2736 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2743 strlcpy(libName, val,
sizeof(libName));
2744 libName[
sizeof(libName) - 1] =
'\0';
2745 char libParms[4096];
2747 if (!
Config.GetRest(libParms, 4095)) {
2748 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2754 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2766 if (!val || !val[0]) {
2767 eDest.
Emsg(
"Config",
"No CORS plugin specified.");
2792 std::vector<extHInfo> &hiVec) {
2793 char *val, path[1024], namebuf[1024];
2796 bool noTlsOK =
false;
2801 if (!val || !val[0]) {
2802 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2805 if (strlen(val) >= 16) {
2806 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2809 strncpy(namebuf, val,
sizeof(namebuf));
2810 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2815 if(val && !strcmp(
"+notls",val)) {
2822 if (!val || !val[0]) {
2823 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2826 if (strlen(val) >= (int)
sizeof(path)) {
2827 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2839 for (
int i = 0; i < (int)hiVec.size(); i++)
2840 {
if (hiVec[i].extHName == namebuf) {
2841 eDest.
Emsg(
"Config",
"Instance name already present for "
2842 "http external handler plugin",
2843 hiVec[i].extHPath.c_str());
2851 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2857 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2901 if (!val || !val[0]) {
2902 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2935 if (!val || !val[0]) {
2936 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2966 if (!val || !val[0])
2967 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2971 if (!strcmp(val,
"off"))
2978 if (!strcmp(val,
"on"))
2985 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2990 auto val =
Config.GetWord();
2991 if (!val || !val[0])
2992 {
eDest.
Emsg(
"Config",
"tlsclientauth argument not specified");
return 1;}
2994 if (!strcmp(val,
"off"))
2998 if (!strcmp(val,
"on"))
3003 eDest.
Emsg(
"config",
"invalid tlsclientauth parameter -", val);
3008 char *val =
Config.GetWord();
3010 if(!strcmp(
"tpc",val)) {
3011 if(!(val =
Config.GetWord())) {
3012 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
3014 if(!strcmp(
"fcreds",val)) {
3017 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
3021 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
3028 char *val =
Config.GetWord();
3034 eDest.
Emsg(
"Config",
"http.maxdelay requires an argument in seconds (default is 30). Example: http.maxdelay 30");
3058 static struct traceopts {
3070 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
3072 if (!(val =
Config.GetWord())) {
3073 eDest.
Emsg(
"config",
"trace option not specified");
3077 if (!strcmp(val,
"off")) trval = 0;
3079 if ((neg = (val[0] ==
'-' && val[1]))) val++;
3080 for (i = 0; i < numopts; i++) {
3081 if (!strcmp(val, tropts[i].opname)) {
3082 if (neg) trval &= ~tropts[i].opval;
3083 else trval |= tropts[i].opval;
3088 eDest.
Emsg(
"config",
"invalid trace option", val);
3107 l = strlen(fname) + 1;
3132 length = fname.
length() + 1;
3144 int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
3145 const char *libParms) {
3149 if (secxtractor)
return 1;
3151 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
3157 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
3165 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
3166 for (
int i = 0; i < (int) hiVec.size(); i++) {
3167 if(hiVec[i].extHNoTlsOK) {
3169 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3170 hiVec[i].extHParm.c_str(), &myEnv,
3171 hiVec[i].extHName.c_str()))
3178 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3190 for (
int i = 0; i < (int)hiVec.size(); i++) {
3193 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3194 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3195 hiVec[i].extHParm.c_str(), &myEnv,
3196 hiVec[i].extHName.c_str()))
return 1;
3203 int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3204 const char *configFN,
const char *libParms,
3205 XrdOucEnv *myEnv,
const char *instName) {
3209 if (ExtHandlerLoaded(instName)) {
3210 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3214 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3218 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3226 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3229 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3230 exthandler[exthandlercnt].name[15] =
'\0';
3231 exthandler[exthandlercnt++].ptr = newhandler;
3241 int XrdHttpProtocol::LoadCorsHandler(
XrdSysError *
eDest,
const char *libname) {
3246 if(ep && (
xrdcors = ep()))
return 0;
3253 bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3254 for (
int i = 0; i < exthandlercnt; i++) {
3255 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3266 for (
int i = 0; i < exthandlercnt; i++) {
3268 return exthandler[i].ptr;
struct ClientSetRequest set
struct ClientQueryRequest query
struct ClientStatRequest stat
static XrdSysError eDest(0,"crypto_")
#define XrdHttpCorsGetHandlerArgs
#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)
std::string httpStatusToString(int status)
Utility functions for XrdHTTP.
std::string decode_str(const std::string &str)
std::string obfuscateAuth(const std::string &input)
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)
virtual std::optional< std::string > getCORSAllowOriginHeader(const std::string &origin)=0
virtual int Configure(const char *configFN, XrdSysError *errP)=0
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 XrdHttpCors * xrdcors
static bool compatNameGeneration
static std::string xrdcorsLibPath
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)
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-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.
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)
void SetTlsClientAuth(bool setting)
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
virtual void SetWait(int wtime, bool notify=false)=0
CloseImpl< false > Close(Ctx< File > file, uint16_t timeout=0)
Factory for creating CloseImpl objects.
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.