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
104 BIO *XrdHttpProtocol::sslbio_err = 0;
106 bool XrdHttpProtocol::isRequiredXtractor =
false;
110 int XrdHttpProtocol::exthandlercnt = 0;
113 bool XrdHttpProtocol::usingEC = false;
114 bool XrdHttpProtocol::hasCache= false;
135 const char *TraceID =
"Protocol";
162 "xrootd protocol anchor");
168 #if OPENSSL_VERSION_NUMBER < 0x10100000L
175 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
190 bio->shutdown = shut;
193 return bio->shutdown;
205 :
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
206 SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
231 char mybuf[16], mybuf2[1024];
234 bool myishttps =
false;
238 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
239 if (dlen <= 0) lp->
setEtext(
"handshake not received");
242 mybuf[dlen - 1] =
'\0';
250 for (
int i = 0; i < dlen; i++) {
252 sprintf(mybuf3,
"%.02d ", mybuf[i]);
253 strcat(mybuf2, mybuf3);
260 for (
int i = 0; i < dlen - 1; i++)
261 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
263 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
268 if ((!ismine) && (dlen >= 4)) {
269 char check[4] = {00, 00, 00, 00};
270 if (memcmp(mybuf, check, 4)) {
277 TRACEI(ALL,
"This may look like https, but https is not configured");
284 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
292 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
295 hp->ishttps = myishttps;
310 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
318 char *XrdHttpProtocol::GetClientIPStr() {
321 if (!
Link)
return strdup(
"unknown");
323 if (!ai)
return strdup(
"unknown");
331 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
342 int ret = lp->
Send(data, datal);
343 BIO_clear_retry_flags(bio);
346 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
347 BIO_set_retry_write(bio);
363 int ret = lp->
Send(data, datal);
364 BIO_clear_retry_flags(bio);
366 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
367 BIO_set_retry_write(bio);
374 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
385 int ret = lp->
Recv(data, datal);
386 BIO_clear_retry_flags(bio);
389 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
390 BIO_set_retry_read(bio);
405 int ret = lp->
Recv(data, datal);
406 BIO_clear_retry_flags(bio);
408 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
409 BIO_set_retry_read(bio);
425 #if OPENSSL_VERSION_NUMBER < 0x10100000L
437 if (bio == NULL)
return 0;
453 case BIO_CTRL_GET_CLOSE:
456 case BIO_CTRL_SET_CLOSE:
471 BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
490 #define TRACELINK Link
498 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
499 TRACE(ALL,
" Process. No buffer available. Internal error.");
505 char *nfo = GetClientIPStr();
507 TRACEI(REQ,
" Setting host: " << nfo);
516 if (ishttps && !ssldone) {
519 sbio = CreateBIO(
Link);
520 BIO_set_nbio(sbio, 1);
526 ERR_print_errors(sslbio_err);
535 SSL_set_bio(ssl, sbio, sbio);
542 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
543 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
546 int res = SSL_accept(ssl);
548 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
549 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
554 ERR_print_errors(sslbio_err);
563 BIO_set_nbio(sbio, 0);
589 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
595 if (BuffUsed() < ResumeBytes)
return 1;
603 if (mon_info.size() >= 1024) {
604 TRACEI(ALL,
"User agent string too long");
606 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
615 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
630 while ((rc = BuffgetLine(tmpline)) > 0) {
631 std::string traceLine = tmpline.
c_str();
635 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
636 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
638 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
644 TRACE(
DEBUG,
" Parsing first line: " << traceLine.c_str());
647 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
653 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
654 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
665 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
670 if ((rc <= 0) && (BuffUsed() >= 16384)) {
671 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
690 time_t timenow = time(0);
708 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
715 struct sockaddr_storage sa;
716 socklen_t sl =
sizeof(sa);
723 switch (sa.ss_family) {
725 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
732 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
734 Addr_str = (
char *)malloc(strlen(buf)+3);
742 TRACEI(REQ,
" Can't recognize the address family of the local host.");
750 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
751 << dest.
c_str() <<
"'");
755 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
760 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
764 TRACEI(ALL,
" Could not calculate self-redirection hash");
770 if (!ishttps && !ssldone) {
780 if (t) tim = atoi(t);
782 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
786 TRACEI(REQ,
" Token expired. Authentication failed.");
871 TRACEI(REQ,
"Invalid tk '" << tk <<
"' != '" << hash <<
"' (calculated). Authentication failed.");
872 SendSimpleResp(400,
nullptr,
nullptr,
"Authentication failed: invalid token", 0,
false);
879 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
887 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
907 TRACEI(REQ,
" Authorization failed.");
924 TRACEI(REQ,
"Process is exiting rc:" << rc);
932 #define TRACELINK Link
986 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
988 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
990 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
991 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
992 eDest.Say("Config http." x " overrides the xrd." y " directive.")
994 int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
997 std::vector<extHInfo> extHIVec;
999 int cfgFD, GoNo, NoGo = 0, ismine;
1009 if(nonIanaChecksums.size()) {
1010 std::stringstream warningMsgSS;
1011 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
1012 std::string unknownCksumString;
1013 for(
auto unknownCksum: nonIanaChecksums) {
1014 unknownCksumString += unknownCksum +
",";
1016 unknownCksumString.erase(unknownCksumString.size() - 1);
1017 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1018 eDest.
Say(warningMsgSS.str().c_str());
1024 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1026 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1061 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1062 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1064 static const char *cvec[] = {
"*** http protocol config:", 0 };
1069 while ((var =
Config.GetMyFirstWord())) {
1070 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1073 if TS_Xeq(
"trace", xtrace);
1074 else if TS_Xeq(
"cert", xsslcert);
1075 else if TS_Xeq(
"key", xsslkey);
1076 else if TS_Xeq(
"cadir", xsslcadir);
1077 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1078 else if TS_Xeq(
"gridmap", xgmap);
1079 else if TS_Xeq(
"cafile", xsslcafile);
1080 else if TS_Xeq(
"secretkey", xsecretkey);
1081 else if TS_Xeq(
"desthttps", xdesthttps);
1082 else if TS_Xeq(
"secxtractor", xsecxtractor);
1083 else if TS_Xeq(
"cors", xcors);
1084 else if TS_Xeq3(
"exthandler", xexthandler);
1085 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1086 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1087 else if TS_Xeq(
"listingredir", xlistredir);
1088 else if TS_Xeq(
"staticredir", xstaticredir);
1089 else if TS_Xeq(
"staticpreload", xstaticpreload);
1090 else if TS_Xeq(
"staticheader", xstaticheader);
1091 else if TS_Xeq(
"listingdeny", xlistdeny);
1092 else if TS_Xeq(
"header2cgi", xheader2cgi);
1093 else if TS_Xeq(
"httpsmode", xhttpsmode);
1094 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1095 else if TS_Xeq(
"auth", xauth);
1096 else if TS_Xeq(
"tlsclientauth", xtlsclientauth);
1097 else if TS_Xeq(
"maxdelay", xmaxdelay);
1099 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1114 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1120 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1123 if (getenv(
"XRDCL_EC"))
usingEC =
true;
1128 std::string default_static_headers;
1130 for (
const auto &header_entry : default_verb->second) {
1131 default_static_headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1136 if (item.first.empty()) {
1139 auto headers = default_static_headers;
1140 for (
const auto &header_entry : item.second) {
1141 headers += header_entry.first +
": " + header_entry.second +
"\r\n";
1149 if (myEnv->
Get(
"XrdCache")) hasCache =
true;
1168 :
"was not configured.");
1169 const char *what = Configed();
1171 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1174 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1176 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1186 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1187 "is meaningless; ignoring key!");
1195 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1196 "a cert specification!");
1207 const char *what1 = 0, *what2 = 0, *what3 = 0;
1212 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1216 what2 =
"xrd.tlsca to supply 'cadir'.";
1220 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1221 :
"xrd.tlsca to supply 'cafile'.");
1225 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1239 {
const char *what = Configed();
1240 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1241 :
"'xrd.tlsca noverify' was specified!");
1243 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1251 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1256 const char *how =
"completed.";
1257 eDest.
Say(
"++++++ HTTPS initialization started.");
1258 if (!
InitTLS()) {NoGo = 1; how =
"failed.";}
1259 eDest.
Say(
"------ HTTPS initialization ", how);
1260 if (NoGo)
return NoGo;
1264 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1268 return (InitSecurity() ? NoGo : 1);
1275 const char *XrdHttpProtocol::Configed()
1277 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1278 if (secxtractor)
return "secxtractor requires";
1279 if (
gridmap)
return "gridmap requires";
1295 if (myBuffEnd >= myBuffStart) {
1297 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1302 dest.
assign(myBuffStart, 0, l-1);
1321 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1323 if ((*p ==
'\n') || (*p ==
'\0')) {
1326 dest.
assign(myBuffStart, 0, l-1);
1342 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1344 if ((*p ==
'\n') || (*p ==
'\0')) {
1348 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1350 dest.
assign(myBuffStart, 0, l1-1);
1354 dest.
insert(myBuffStart, l1, l-1);
1378 int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1393 maxread = std::min(blen, BuffAvailable());
1394 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1400 int sslavail = maxread;
1403 int l = SSL_pending(ssl);
1405 sslavail = std::min(maxread, SSL_pending(ssl));
1410 ERR_print_errors(sslbio_err);
1414 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1415 if (sslavail <= 0)
return 0;
1417 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1419 myBuffEnd = myBuff->
buff;
1422 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1425 ERR_print_errors(sslbio_err);
1432 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1434 myBuffEnd = myBuff->
buff;
1440 rlen =
Link->
Recv(myBuffEnd, maxread);
1456 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1463 int XrdHttpProtocol::BuffAvailable() {
1466 if (myBuffEnd >= myBuffStart)
1467 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1469 r = myBuffStart - myBuffEnd;
1471 if ((r < 0) || (r > myBuff->
bsize)) {
1472 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1485 int XrdHttpProtocol::BuffUsed() {
1488 if (myBuffEnd >= myBuffStart)
1489 r = myBuffEnd - myBuffStart;
1492 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1494 if ((r < 0) || (r > myBuff->
bsize)) {
1495 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1508 int XrdHttpProtocol::BuffFree() {
1509 return (myBuff->
bsize - BuffUsed());
1516 void XrdHttpProtocol::BuffConsume(
int blen) {
1518 if (blen > myBuff->
bsize) {
1519 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1523 if (blen > BuffUsed()) {
1524 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1528 myBuffStart = myBuffStart + blen;
1530 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1531 myBuffStart -= myBuff->
bsize;
1533 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1534 myBuffEnd -= myBuff->
bsize;
1536 if (BuffUsed() == 0)
1537 myBuffStart = myBuffEnd = myBuff->
buff;
1552 int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1555 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1560 if (blen > BuffUsed()) {
1561 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1562 if ( getDataOneShot(blen - BuffUsed(),
true) )
1568 if ( !BuffUsed() ) {
1569 if ( getDataOneShot(blen,
false) )
1577 if (myBuffStart <= myBuffEnd) {
1578 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1581 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1583 *data = myBuffStart;
1594 int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1598 if (body && bodylen) {
1599 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1601 r = SSL_write(ssl, body, bodylen);
1603 ERR_print_errors(sslbio_err);
1609 if (r <= 0)
return -1;
1620 int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
1621 const char *header_to_add,
1622 long long bodylen,
bool keepalive) {
1623 std::stringstream ss;
1624 const std::string crlf =
"\r\n";
1626 ss <<
"HTTP/1.1 " << code <<
" ";
1635 if (keepalive && (code != 100))
1636 ss <<
"Connection: Keep-Alive" << crlf;
1638 ss <<
"Connection: Close" << crlf;
1640 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1651 if(corsAllowOrigin) {
1652 ss << *corsAllowOrigin << crlf;
1656 if ((bodylen >= 0) && (code != 100))
1657 ss <<
"Content-Length: " << bodylen << crlf;
1659 if (header_to_add && (header_to_add[0] !=
'\0')) ss << header_to_add << crlf;
1663 const std::string &outhdr = ss.str();
1664 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1665 if (SendData(outhdr.c_str(), outhdr.size()))
1675 int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1676 const std::string crlf =
"\r\n";
1677 std::stringstream ss;
1679 if (header_to_add && (header_to_add[0] !=
'\0')) {
1680 ss << header_to_add << crlf;
1683 ss <<
"Transfer-Encoding: chunked";
1684 TRACEI(RSP,
"Starting chunked response");
1685 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1692 int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1693 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1694 if (ChunkRespHeader(content_length))
1697 if (body && SendData(body, content_length))
1700 return ChunkRespFooter();
1707 int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1708 const std::string crlf =
"\r\n";
1709 std::stringstream ss;
1713 const std::string &chunkhdr = ss.str();
1714 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1715 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1722 int XrdHttpProtocol::ChunkRespFooter() {
1723 const std::string crlf =
"\r\n";
1724 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1735 int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1737 long long content_length = bodylen;
1739 content_length = body ? strlen(body) : 0;
1742 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1749 return SendData(body, content_length);
1786 sprintf(buf,
"%d",
Port);
1792 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1798 if ((rdf = getenv(
"XRDROLE"))) {
1801 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1803 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1806 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1810 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1829 char *val, keybuf[1024], parmbuf[1024];
1834 if (!val || !val[0]) {
1835 err.
Emsg(
"Config",
"No headerkey specified.");
1840 while ( *val && !isalnum(*val) ) val++;
1841 strcpy(keybuf, val);
1845 pp = keybuf + strlen(keybuf) - 1;
1846 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1854 if(!parm || !parm[0]) {
1855 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1860 while ( *parm && !isalnum(*parm) ) parm++;
1861 strcpy(parmbuf, parm);
1864 pp = parmbuf + strlen(parmbuf) - 1;
1865 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1872 header2cgi[keybuf] = parmbuf;
1874 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1887 bool XrdHttpProtocol::InitTLS() {
1916 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1917 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1923 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1939 void XrdHttpProtocol::Cleanup() {
1941 TRACE(ALL,
" Cleanup");
1943 if (
BPool && myBuff) {
1944 BuffConsume(BuffUsed());
1959 int ret = SSL_shutdown(ssl);
1963 ret = SSL_shutdown(ssl);
1965 TRACE(ALL,
"SSL server failed to receive the SSL shutdown message from the client");
1966 ERR_print_errors(sslbio_err);
1970 TRACE(ALL,
"SSL server failed to send the shutdown message to the client");
1971 ERR_print_errors(sslbio_err);
2005 void XrdHttpProtocol::Reset() {
2007 TRACE(ALL,
" Reset");
2016 myBuffStart = myBuffEnd = 0;
2019 DoneSetInfo =
false;
2069 if (!val || !val[0]) {
2070 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2079 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2104 if (!val || !val[0]) {
2105 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2136 if (!val || !val[0]) {
2137 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2171 if (!val || !val[0]) {
2172 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2208 if (!val || !val[0]) {
2209 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2215 if (!strncmp(val,
"required", 8)) {
2219 if (!val || !val[0]) {
2220 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2228 if (!strcmp(val,
"compatNameGeneration")) {
2231 if (!val || !val[0]) {
2232 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2233 "[compatNameGeneration] parameter");
2265 if (!val || !val[0]) {
2266 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2294 bool inFile =
false;
2299 if (!val || !val[0]) {
2300 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2308 if (val[0] ==
'/') {
2311 int fd =
open(val, O_RDONLY);
2314 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2318 if (
fstat(fd, &st) != 0 ) {
2319 eDest.
Emsg(
"Config", errno,
"fstat shared secret key file", val);
2324 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2326 "For your own security, the shared secret key file cannot be world readable or group writable '", val,
"'");
2331 FILE *fp = fdopen(fd,
"r");
2333 if ( fp ==
nullptr ) {
2334 eDest.
Emsg(
"Config", errno,
"fdopen shared secret key file", val);
2340 while( fgets(line, 1024, fp) ) {
2344 pp = line + strlen(line) - 1;
2345 while ( (pp >= line) && (!isalnum(*pp)) ) {
2352 while ( *pp && !isalnum(*pp) ) pp++;
2354 if ( strlen(pp) >= 32 ) {
2355 eDest.
Say(
"Config",
"Secret key loaded.");
2367 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2372 if ( strlen(val) < 32 ) {
2373 eDest.
Emsg(
"Config",
"Secret key is too short");
2380 if (!inFile)
Config.noEcho();
2404 if (!val || !val[0]) {
2405 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2411 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2436 if (!val || !val[0]) {
2437 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2469 if (!val || !val[0]) {
2470 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2476 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2501 if (!val || !val[0]) {
2502 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2508 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2533 if (!val || !val[0]) {
2534 eDest.
Emsg(
"Config",
"staticredir url not specified");
2563 char *val, *k, key[1024];
2569 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2578 if (!val || !val[0]) {
2579 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2584 int fp =
open(val, O_RDONLY);
2586 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2590 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2592 nfo->data = (
char *)malloc(65536);
2593 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2596 if (nfo->len <= 0) {
2597 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2601 if (nfo->len >= 65536) {
2602 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2633 auto val =
Config.GetWord();
2634 std::vector<std::string> verbs;
2636 if (!val || !val[0]) {
2637 eDest.
Emsg(
"Config",
"http.staticheader requires the header to be specified");
2641 std::string match_verb;
2642 std::string_view val_str(val);
2643 if (val_str.substr(0, 6) ==
"-verb=") {
2644 verbs.emplace_back(val_str.substr(6));
2645 }
else if (val_str ==
"-") {
2646 eDest.
Emsg(
"Config",
"http.staticheader is ignoring unknown flag: ", val_str.data());
2653 if (verbs.empty()) {
2654 verbs.emplace_back();
2657 std::string header = val;
2660 std::string header_value;
2661 if (val && val[0]) {
2665 for (
const auto &verb : verbs) {
2668 if (!header_value.empty())
2670 }
else if (header_value.empty()) {
2671 iter->second.clear();
2673 iter->second.emplace_back(header, header_value);
2700 if (!val || !val[0]) {
2701 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2707 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2735 if (!val || !val[0]) {
2736 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2741 if (!strncmp(val,
"required", 8)) {
2742 isRequiredXtractor =
true;
2745 if (!val || !val[0]) {
2746 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2753 strlcpy(libName, val,
sizeof(libName));
2754 libName[
sizeof(libName) - 1] =
'\0';
2755 char libParms[4096];
2757 if (!
Config.GetRest(libParms, 4095)) {
2758 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2764 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2776 if (!val || !val[0]) {
2777 eDest.
Emsg(
"Config",
"No CORS plugin specified.");
2802 std::vector<extHInfo> &hiVec) {
2803 char *val, path[1024], namebuf[1024];
2806 bool noTlsOK =
false;
2811 if (!val || !val[0]) {
2812 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2815 if (strlen(val) >= 16) {
2816 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2819 strncpy(namebuf, val,
sizeof(namebuf));
2820 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2825 if(val && !strcmp(
"+notls",val)) {
2832 if (!val || !val[0]) {
2833 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2836 if (strlen(val) >= (int)
sizeof(path)) {
2837 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2849 for (
int i = 0; i < (int)hiVec.size(); i++)
2850 {
if (hiVec[i].extHName == namebuf) {
2851 eDest.
Emsg(
"Config",
"Instance name already present for "
2852 "http external handler plugin",
2853 hiVec[i].extHPath.c_str());
2861 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2867 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2911 if (!val || !val[0]) {
2912 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2945 if (!val || !val[0]) {
2946 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2976 if (!val || !val[0])
2977 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2981 if (!strcmp(val,
"off"))
2988 if (!strcmp(val,
"on"))
2995 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
3000 auto val =
Config.GetWord();
3001 if (!val || !val[0])
3002 {
eDest.
Emsg(
"Config",
"tlsclientauth argument not specified");
return 1;}
3004 if (!strcmp(val,
"off"))
3008 if (!strcmp(val,
"on"))
3013 eDest.
Emsg(
"config",
"invalid tlsclientauth parameter -", val);
3018 char *val =
Config.GetWord();
3020 if(!strcmp(
"tpc",val)) {
3021 if(!(val =
Config.GetWord())) {
3022 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
3024 if(!strcmp(
"fcreds",val)) {
3027 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
3031 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
3038 char *val =
Config.GetWord();
3044 eDest.
Emsg(
"Config",
"http.maxdelay requires an argument in seconds (default is 30). Example: http.maxdelay 30");
3068 static struct traceopts {
3080 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
3082 if (!(val =
Config.GetWord())) {
3083 eDest.
Emsg(
"config",
"trace option not specified");
3087 if (!strcmp(val,
"off")) trval = 0;
3089 if ((neg = (val[0] ==
'-' && val[1]))) val++;
3090 for (i = 0; i < numopts; i++) {
3091 if (!strcmp(val, tropts[i].opname)) {
3092 if (neg) trval &= ~tropts[i].opval;
3093 else trval |= tropts[i].opval;
3098 eDest.
Emsg(
"config",
"invalid trace option", val);
3117 l = strlen(fname) + 1;
3142 length = fname.
length() + 1;
3154 int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
3155 const char *libParms) {
3159 if (secxtractor)
return 1;
3161 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
3167 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
3175 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
3176 for (
int i = 0; i < (int) hiVec.size(); i++) {
3177 if(hiVec[i].extHNoTlsOK) {
3179 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3180 hiVec[i].extHParm.c_str(), &myEnv,
3181 hiVec[i].extHName.c_str()))
3188 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3202 for (
int i = 0; i < (int)hiVec.size(); i++) {
3205 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3206 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3207 hiVec[i].extHParm.c_str(), &myEnv,
3208 hiVec[i].extHName.c_str()))
return 1;
3215 int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3216 const char *configFN,
const char *libParms,
3217 XrdOucEnv *myEnv,
const char *instName) {
3221 if (ExtHandlerLoaded(instName)) {
3222 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3226 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3230 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3238 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3241 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3242 exthandler[exthandlercnt].name[15] =
'\0';
3243 exthandler[exthandlercnt++].ptr = newhandler;
3253 int XrdHttpProtocol::LoadCorsHandler(
XrdSysError *
eDest,
const char *libname) {
3258 if(ep && (
xrdcors = ep()))
return 0;
3265 bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3266 for (
int i = 0; i < exthandlercnt; i++) {
3267 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3278 for (
int i = 0; i < exthandlercnt; i++) {
3280 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 allowMissingCRL
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)
void PutInt(const char *varname, long value)
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 uint64_t crlAM
Allow CA validation when CRL is missing (CRL soft-fail)
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.
uint64_t opts
Options as passed to the constructor.
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.