24#include "XrdVersion.hh"
48#include <openssl/err.h>
49#include <openssl/ssl.h>
58#define XRHTTP_TK_GRACETIME 600
99BIO *XrdHttpProtocol::sslbio_err = 0;
101bool XrdHttpProtocol::isRequiredXtractor =
false;
103int XrdHttpProtocol::exthandlercnt = 0;
106bool XrdHttpProtocol::usingEC = false;
124const char *TraceID =
"Protocol";
150 "xrootd protocol anchor");
156#if OPENSSL_VERSION_NUMBER < 0x10100000L
163#if OPENSSL_VERSION_NUMBER < 0x1000105fL
178 bio->shutdown = shut;
181 return bio->shutdown;
193:
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
194SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
219 char mybuf[16], mybuf2[1024];
222 bool myishttps =
false;
226 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
227 if (dlen <= 0) lp->
setEtext(
"handshake not received");
230 mybuf[dlen - 1] =
'\0';
238 for (
int i = 0; i < dlen; i++) {
240 sprintf(mybuf3,
"%.02d ", mybuf[i]);
241 strcat(mybuf2, mybuf3);
248 for (
int i = 0; i < dlen - 1; i++)
249 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
251 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
256 if ((!ismine) && (dlen >= 4)) {
257 char check[4] = {00, 00, 00, 00};
258 if (memcmp(mybuf, check, 4)) {
265 TRACEI(ALL,
"This may look like https, but https is not configured");
272 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
280 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
283 hp->ishttps = myishttps;
298 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
306char *XrdHttpProtocol::GetClientIPStr() {
309 if (!
Link)
return strdup(
"unknown");
311 if (!ai)
return strdup(
"unknown");
319#if OPENSSL_VERSION_NUMBER < 0x1000105fL
330 int ret = lp->
Send(data, datal);
331 BIO_clear_retry_flags(bio);
334 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
335 BIO_set_retry_write(bio);
351 int ret = lp->
Send(data, datal);
352 BIO_clear_retry_flags(bio);
354 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
355 BIO_set_retry_write(bio);
362#if OPENSSL_VERSION_NUMBER < 0x1000105fL
373 int ret = lp->
Recv(data, datal);
374 BIO_clear_retry_flags(bio);
377 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
378 BIO_set_retry_read(bio);
393 int ret = lp->
Recv(data, datal);
394 BIO_clear_retry_flags(bio);
396 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
397 BIO_set_retry_read(bio);
413#if OPENSSL_VERSION_NUMBER < 0x10100000L
425 if (bio == NULL)
return 0;
441 case BIO_CTRL_GET_CLOSE:
444 case BIO_CTRL_SET_CLOSE:
459BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
478#define TRACELINK Link
486 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
487 TRACE(ALL,
" Process. No buffer available. Internal error.");
493 char *nfo = GetClientIPStr();
495 TRACEI(REQ,
" Setting host: " << nfo);
504 if (ishttps && !ssldone) {
507 sbio = CreateBIO(
Link);
508 BIO_set_nbio(sbio, 1);
514 ERR_print_errors(sslbio_err);
523 SSL_set_bio(ssl, sbio, sbio);
530 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
531 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
534 int res = SSL_accept(ssl);
536 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
537 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
542 ERR_print_errors(sslbio_err);
551 BIO_set_nbio(sbio, 0);
556 if (HandleAuthentication(
Link)) {
577 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
583 if (BuffUsed() < ResumeBytes)
return 1;
591 if (mon_info.size() >= 1024) {
592 TRACEI(ALL,
"User agent string too long");
594 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
603 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
618 while ((rc = BuffgetLine(tmpline)) > 0) {
620 std::string traceLine{tmpline.
c_str()};
622 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
624 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
626 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
635 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
641 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
642 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
653 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
658 if ((rc <= 0) && (BuffUsed() >= 16384)) {
659 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
678 time_t timenow = time(0);
696 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
703 struct sockaddr_storage sa;
704 socklen_t sl =
sizeof(sa);
711 switch (sa.ss_family) {
713 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
720 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
722 Addr_str = (
char *)malloc(strlen(buf)+3);
730 TRACEI(REQ,
" Can't recognize the address family of the local host.");
738 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
739 << dest.
c_str() <<
"'");
743 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
748 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
752 TRACEI(ALL,
" Could not calculate self-redirection hash");
758 if (!ishttps && !ssldone) {
768 if (t) tim = atoi(t);
770 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
774 TRACEI(REQ,
" Token expired. Authentication failed.");
859 TRACEI(REQ,
" Invalid tk '" << tk <<
"' != '" << hash <<
"'(calculated). Authentication failed.");
866 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
874 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
894 TRACEI(REQ,
" Authorization failed.");
910 TRACEI(REQ,
"Process is exiting rc:" << rc);
918#define TRACELINK Link
972#define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
974#define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
976#define HTTPS_ALERT(x,y,z) httpsspec = true;\
977 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
978 eDest.Say("Config http." x " overrides the xrd." y " directive.")
980int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
983 std::vector<extHInfo> extHIVec;
985 int cfgFD, GoNo, NoGo = 0, ismine;
995 if(nonIanaChecksums.size()) {
996 std::stringstream warningMsgSS;
997 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
998 std::string unknownCksumString;
999 for(
auto unknownCksum: nonIanaChecksums) {
1000 unknownCksumString += unknownCksum +
",";
1002 unknownCksumString.erase(unknownCksumString.size() - 1);
1003 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1004 eDest.
Say(warningMsgSS.str().c_str());
1010 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1012 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1047 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1048 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1049 Config.Attach(cfgFD);
1050 static const char *cvec[] = {
"*** http protocol config:", 0 };
1051 Config.Capture(cvec);
1055 while ((var = Config.GetMyFirstWord())) {
1056 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1059 if TS_Xeq(
"trace", xtrace);
1060 else if TS_Xeq(
"cert", xsslcert);
1061 else if TS_Xeq(
"key", xsslkey);
1062 else if TS_Xeq(
"cadir", xsslcadir);
1063 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1064 else if TS_Xeq(
"gridmap", xgmap);
1065 else if TS_Xeq(
"cafile", xsslcafile);
1066 else if TS_Xeq(
"secretkey", xsecretkey);
1067 else if TS_Xeq(
"desthttps", xdesthttps);
1068 else if TS_Xeq(
"secxtractor", xsecxtractor);
1069 else if TS_Xeq3(
"exthandler", xexthandler);
1070 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1071 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1072 else if TS_Xeq(
"listingredir", xlistredir);
1073 else if TS_Xeq(
"staticredir", xstaticredir);
1074 else if TS_Xeq(
"staticpreload", xstaticpreload);
1075 else if TS_Xeq(
"listingdeny", xlistdeny);
1076 else if TS_Xeq(
"header2cgi", xheader2cgi);
1077 else if TS_Xeq(
"httpsmode", xhttpsmode);
1078 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1079 else if TS_Xeq(
"auth", xauth);
1081 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1096 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1102 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1105 if (getenv(
"XRDCL_EC")) usingEC =
true;
1114 :
"was not configured.");
1115 const char *what = Configed();
1117 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1120 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1122 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1132 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1133 "is meaningless; ignoring key!");
1141 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1142 "a cert specification!");
1153 const char *what1 = 0, *what2 = 0, *what3 = 0;
1158 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1162 what2 =
"xrd.tlsca to supply 'cadir'.";
1166 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1167 :
"xrd.tlsca to supply 'cafile'.");
1171 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1181 {
const char *what = Configed();
1182 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1183 :
"'xrd.tlsca noverify' was specified!");
1185 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1193 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1198 const char *how =
"completed.";
1199 eDest.
Say(
"++++++ HTTPS initialization started.");
1200 if (!InitTLS()) {NoGo = 1; how =
"failed.";}
1201 eDest.
Say(
"------ HTTPS initialization ", how);
1202 if (NoGo)
return NoGo;
1206 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1210 return (InitSecurity() ? NoGo : 1);
1217const char *XrdHttpProtocol::Configed()
1219 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1220 if (secxtractor)
return "secxtractor requires";
1221 if (
gridmap)
return "gridmap requires";
1237 if (myBuffEnd >= myBuffStart) {
1239 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1244 dest.
assign(myBuffStart, 0, l-1);
1263 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1265 if ((*p ==
'\n') || (*p ==
'\0')) {
1268 dest.
assign(myBuffStart, 0, l-1);
1284 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1286 if ((*p ==
'\n') || (*p ==
'\0')) {
1290 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1292 dest.
assign(myBuffStart, 0, l1-1);
1296 dest.
insert(myBuffStart, l1, l-1);
1320int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1335 maxread = std::min(blen, BuffAvailable());
1336 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1342 int sslavail = maxread;
1345 int l = SSL_pending(ssl);
1347 sslavail = std::min(maxread, SSL_pending(ssl));
1352 ERR_print_errors(sslbio_err);
1356 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1357 if (sslavail <= 0)
return 0;
1359 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1361 myBuffEnd = myBuff->
buff;
1364 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1367 ERR_print_errors(sslbio_err);
1374 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1376 myBuffEnd = myBuff->
buff;
1382 rlen =
Link->
Recv(myBuffEnd, maxread);
1398 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1405int XrdHttpProtocol::BuffAvailable() {
1408 if (myBuffEnd >= myBuffStart)
1409 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1411 r = myBuffStart - myBuffEnd;
1413 if ((r < 0) || (r > myBuff->
bsize)) {
1414 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1427int XrdHttpProtocol::BuffUsed() {
1430 if (myBuffEnd >= myBuffStart)
1431 r = myBuffEnd - myBuffStart;
1434 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1436 if ((r < 0) || (r > myBuff->
bsize)) {
1437 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1450int XrdHttpProtocol::BuffFree() {
1451 return (myBuff->
bsize - BuffUsed());
1458void XrdHttpProtocol::BuffConsume(
int blen) {
1460 if (blen > myBuff->
bsize) {
1461 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1465 if (blen > BuffUsed()) {
1466 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1470 myBuffStart = myBuffStart + blen;
1472 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1473 myBuffStart -= myBuff->
bsize;
1475 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1476 myBuffEnd -= myBuff->
bsize;
1478 if (BuffUsed() == 0)
1479 myBuffStart = myBuffEnd = myBuff->
buff;
1494int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1497 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1502 if (blen > BuffUsed()) {
1503 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1504 if ( getDataOneShot(blen - BuffUsed(),
true) )
1510 if ( !BuffUsed() ) {
1511 if ( getDataOneShot(blen,
false) )
1519 if (myBuffStart <= myBuffEnd) {
1520 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1523 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1525 *data = myBuffStart;
1536int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1540 if (body && bodylen) {
1541 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1543 r = SSL_write(ssl, body, bodylen);
1545 ERR_print_errors(sslbio_err);
1551 if (r <= 0)
return -1;
1562int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1563 std::stringstream ss;
1564 const std::string crlf =
"\r\n";
1566 ss <<
"HTTP/1.1 " << code <<
" ";
1570 if (code == 200) ss <<
"OK";
1571 else if (code == 100) ss <<
"Continue";
1572 else if (code == 206) ss <<
"Partial Content";
1573 else if (code == 302) ss <<
"Redirect";
1574 else if (code == 307) ss <<
"Temporary Redirect";
1575 else if (code == 400) ss <<
"Bad Request";
1576 else if (code == 403) ss <<
"Forbidden";
1577 else if (code == 404) ss <<
"Not Found";
1578 else if (code == 405) ss <<
"Method Not Allowed";
1579 else if (code == 416) ss <<
"Range Not Satisfiable";
1580 else if (code == 500) ss <<
"Internal Server Error";
1581 else if (code == 504) ss <<
"Gateway Timeout";
1582 else ss <<
"Unknown";
1585 if (keepalive && (code != 100))
1586 ss <<
"Connection: Keep-Alive" << crlf;
1588 ss <<
"Connection: Close" << crlf;
1590 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1592 if ((bodylen >= 0) && (code != 100))
1593 ss <<
"Content-Length: " << bodylen << crlf;
1595 if (header_to_add && (header_to_add[0] !=
'\0'))
1596 ss << header_to_add << crlf;
1600 const std::string &outhdr = ss.str();
1601 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1602 if (SendData(outhdr.c_str(), outhdr.size()))
1612int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1613 const std::string crlf =
"\r\n";
1614 std::stringstream ss;
1616 if (header_to_add && (header_to_add[0] !=
'\0')) {
1617 ss << header_to_add << crlf;
1620 ss <<
"Transfer-Encoding: chunked";
1621 TRACEI(RSP,
"Starting chunked response");
1622 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1629int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1630 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1631 if (ChunkRespHeader(content_length))
1634 if (body && SendData(body, content_length))
1637 return ChunkRespFooter();
1644int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1645 const std::string crlf =
"\r\n";
1646 std::stringstream ss;
1648 ss << std::hex << bodylen << std::dec << crlf;
1650 const std::string &chunkhdr = ss.str();
1651 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1652 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1659int XrdHttpProtocol::ChunkRespFooter() {
1660 const std::string crlf =
"\r\n";
1661 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1672int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1674 long long content_length = bodylen;
1676 content_length = body ? strlen(body) : 0;
1679 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1686 return SendData(body, content_length);
1723 sprintf(buf,
"%d",
Port);
1729 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1730 if (rdf && Config(rdf, pi->
theEnv))
return 0;
1735 if ((rdf = getenv(
"XRDROLE"))) {
1738 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1740 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1743 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1747 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1766 char *val, keybuf[1024], parmbuf[1024];
1770 val = Config.GetWord();
1771 if (!val || !val[0]) {
1772 err.
Emsg(
"Config",
"No headerkey specified.");
1777 while ( *val && !isalnum(*val) ) val++;
1778 strcpy(keybuf, val);
1782 pp = keybuf + strlen(keybuf) - 1;
1783 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1788 parm = Config.GetWord();
1791 if(!parm || !parm[0]) {
1792 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1797 while ( *parm && !isalnum(*parm) ) parm++;
1798 strcpy(parmbuf, parm);
1801 pp = parmbuf + strlen(parmbuf) - 1;
1802 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1809 header2cgi[keybuf] = parmbuf;
1811 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1824bool XrdHttpProtocol::InitTLS() {
1849 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1850 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1856 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1869void XrdHttpProtocol::Cleanup() {
1871 TRACE(ALL,
" Cleanup");
1873 if (
BPool && myBuff) {
1874 BuffConsume(BuffUsed());
1888 int ret = SSL_shutdown(ssl);
1892 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1893 ERR_remove_thread_state(
nullptr);
1897 TRACE(ALL,
" SSL_shutdown failed");
1898 ERR_print_errors(sslbio_err);
1932void XrdHttpProtocol::Reset() {
1934 TRACE(ALL,
" Reset");
1943 myBuffStart = myBuffEnd = 0;
1946 DoneSetInfo =
false;
1990int XrdHttpProtocol::xhttpsmode(
XrdOucStream & Config) {
1996 if (!val || !val[0]) {
1997 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2006 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2025int XrdHttpProtocol::xsslverifydepth(
XrdOucStream & Config) {
2031 if (!val || !val[0]) {
2032 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2063 if (!val || !val[0]) {
2064 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2098 if (!val || !val[0]) {
2099 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2135 if (!val || !val[0]) {
2136 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2142 if (!strncmp(val,
"required", 8)) {
2146 if (!val || !val[0]) {
2147 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2155 if (!strcmp(val,
"compatNameGeneration")) {
2158 if (!val || !val[0]) {
2159 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2160 "[compatNameGeneration] parameter");
2186int XrdHttpProtocol::xsslcafile(
XrdOucStream & Config) {
2192 if (!val || !val[0]) {
2193 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2219int XrdHttpProtocol::xsecretkey(
XrdOucStream & Config) {
2221 bool inFile =
false;
2226 if (!val || !val[0]) {
2227 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2235 if (val[0] ==
'/') {
2238 if (
stat(val, &st) ) {
2239 eDest.
Emsg(
"Config", errno,
"stat shared secret key file", val);
2243 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2244 eDest.
Emsg(
"Config",
"For your own security, the shared secret key file cannot be world readable or group writable'", val,
"'");
2248 FILE *fp =
fopen(val,
"r");
2251 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2256 while( fgets(line, 1024, fp) ) {
2260 pp = line + strlen(line) - 1;
2261 while ( (pp >= line) && (!isalnum(*pp)) ) {
2268 while ( *pp && !isalnum(*pp) ) pp++;
2270 if ( strlen(pp) >= 32 ) {
2271 eDest.
Say(
"Config",
"Secret key loaded.");
2283 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2288 if ( strlen(val) < 32 ) {
2289 eDest.
Emsg(
"Config",
"Secret key is too short");
2296 if (!inFile)
Config.noEcho();
2320 if (!val || !val[0]) {
2321 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2327 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2346int XrdHttpProtocol::xlistredir(
XrdOucStream & Config) {
2352 if (!val || !val[0]) {
2353 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2379int XrdHttpProtocol::xdesthttps(
XrdOucStream & Config) {
2385 if (!val || !val[0]) {
2386 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2392 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2411int XrdHttpProtocol::xembeddedstatic(
XrdOucStream & Config) {
2417 if (!val || !val[0]) {
2418 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2424 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2443int XrdHttpProtocol::xstaticredir(
XrdOucStream & Config) {
2449 if (!val || !val[0]) {
2450 eDest.
Emsg(
"Config",
"staticredir url not specified");
2478int XrdHttpProtocol::xstaticpreload(
XrdOucStream & Config) {
2479 char *val, *k, key[1024];
2485 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2494 if (!val || !val[0]) {
2495 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2500 int fp =
open(val, O_RDONLY);
2502 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2506 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2508 nfo->data = (
char *)malloc(65536);
2509 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2512 if (nfo->len <= 0) {
2513 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2517 if (nfo->len >= 65536) {
2518 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2544int XrdHttpProtocol::xselfhttps2http(
XrdOucStream & Config) {
2550 if (!val || !val[0]) {
2551 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2557 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2579int XrdHttpProtocol::xsecxtractor(
XrdOucStream& Config) {
2585 if (!val || !val[0]) {
2586 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2591 if (!strncmp(val,
"required", 8)) {
2592 isRequiredXtractor =
true;
2595 if (!val || !val[0]) {
2596 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2603 strlcpy(libName, val,
sizeof(libName));
2604 libName[
sizeof(libName) - 1] =
'\0';
2605 char libParms[4096];
2607 if (!
Config.GetRest(libParms, 4095)) {
2608 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2614 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2640 std::vector<extHInfo> &hiVec) {
2641 char *val, path[1024], namebuf[1024];
2644 bool noTlsOK =
false;
2649 if (!val || !val[0]) {
2650 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2653 if (strlen(val) >= 16) {
2654 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2657 strncpy(namebuf, val,
sizeof(namebuf));
2658 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2663 if(val && !strcmp(
"+notls",val)) {
2670 if (!val || !val[0]) {
2671 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2674 if (strlen(val) >= (int)
sizeof(path)) {
2675 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2687 for (
int i = 0; i < (int)hiVec.size(); i++)
2688 {
if (hiVec[i].extHName == namebuf) {
2689 eDest.
Emsg(
"Config",
"Instance name already present for "
2690 "http external handler plugin",
2691 hiVec[i].extHPath.c_str());
2699 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2705 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2726int XrdHttpProtocol::xheader2cgi(
XrdOucStream & Config) {
2749 if (!val || !val[0]) {
2750 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2777int XrdHttpProtocol::xsslcipherfilter(
XrdOucStream & Config) {
2783 if (!val || !val[0]) {
2784 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2814 if (!val || !val[0])
2815 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2819 if (!strcmp(val,
"off"))
2826 if (!strcmp(val,
"on"))
2833 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2838 char *val =
Config.GetWord();
2840 if(!strcmp(
"tpc",val)) {
2841 if(!(val =
Config.GetWord())) {
2842 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2844 if(!strcmp(
"fcreds",val)) {
2847 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2851 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
2875 static struct traceopts {
2887 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
2889 if (!(val =
Config.GetWord())) {
2890 eDest.
Emsg(
"config",
"trace option not specified");
2894 if (!strcmp(val,
"off")) trval = 0;
2896 if ((neg = (val[0] ==
'-' && val[1]))) val++;
2897 for (i = 0; i < numopts; i++) {
2898 if (!strcmp(val, tropts[i].opname)) {
2899 if (neg) trval &= ~tropts[i].opval;
2900 else trval |= tropts[i].opval;
2905 eDest.
Emsg(
"config",
"invalid trace option", val);
2924 l = strlen(fname) + 1;
2949 length = fname.
length() + 1;
2961int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
2962 const char *libParms) {
2966 if (secxtractor)
return 1;
2968 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
2974 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
2982int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
2983 for (
int i = 0; i < (int) hiVec.size(); i++) {
2984 if(hiVec[i].extHNoTlsOK) {
2986 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
2987 hiVec[i].extHParm.c_str(), &myEnv,
2988 hiVec[i].extHName.c_str()))
2995int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3007 for (
int i = 0; i < (int)hiVec.size(); i++) {
3010 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3011 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3012 hiVec[i].extHParm.c_str(), &myEnv,
3013 hiVec[i].extHName.c_str()))
return 1;
3020int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3021 const char *configFN,
const char *libParms,
3022 XrdOucEnv *myEnv,
const char *instName) {
3026 if (ExtHandlerLoaded(instName)) {
3027 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3031 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3035 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3043 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3046 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3047 exthandler[exthandlercnt].name[15] =
'\0';
3048 exthandler[exthandlercnt++].ptr = newhandler;
3061bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3062 for (
int i = 0; i < exthandlercnt; i++) {
3063 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3074 for (
int i = 0; i < exthandlercnt; i++) {
3076 return exthandler[i].ptr;
struct ClientSetRequest set
struct ClientQueryRequest query
struct ClientStatRequest stat
#define XrdHttpExtHandlerArgs
int BIO_get_init(BIO *bio)
int BIO_get_shutdown(BIO *bio)
int BIO_get_flags(BIO *bio)
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
void BIO_set_init(BIO *bio, int init)
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
void BIO_set_shutdown(BIO *bio, int shut)
XrdSysTrace XrdHttpTrace("http")
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
void BIO_set_data(BIO *bio, void *ptr)
static int BIO_XrdLink_destroy(BIO *bio)
#define XRHTTP_TK_GRACETIME
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
void * BIO_get_data(BIO *bio)
void BIO_set_flags(BIO *bio, int flags)
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
int compareHash(const char *h1, const char *h2)
char * unquote(char *str)
void calcHashes(char *hash, const char *fn, kXR_int16 request, XrdSecEntity *secent, time_t tim, const char *key)
Utility functions for XrdHTTP.
std::string obfuscateAuth(const std::string &input)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
void Release(XrdBuffer *bp)
XrdBuffer * Obtain(int bsz)
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static bool isRequiredGridmap
static char * listredir
Url to redirect to in the case a listing is requested.
int Stats(char *buff, int blen, int do_sync=0)
Get activity stats.
static int crlRefIntervalSec
CRL thread refresh interval.
static XrdHttpReadRangeHandler::Configuration ReadRangeConfig
configuration for the read range handler
static XrdSecService * CIA
static XrdBuffManager * BPool
static bool tpcForwardCreds
If set to true, the HTTP TPC transfers will forward the credentials to redirected hosts.
int Process(XrdLink *lp)
Process data incoming from the socket.
XrdHttpProtocol(const XrdHttpProtocol &)=default
Ctor, dtors and copy ctor.
static bool listdeny
If true, any form of listing is denied.
static int parseHeader2CGI(XrdOucStream &Config, XrdSysError &err, std::map< std::string, std::string > &header2cgi)
Use this function to parse header2cgi configurations.
XrdSecEntity SecEntity
Authentication area.
static bool embeddedstatic
If true, use the embedded css and icons.
static int sslverifydepth
Depth of verification of a certificate chain.
static int Configure(char *parms, XrdProtocol_Config *pi)
Read and apply the configuration.
static int Configure(XrdSysError &Eroute, const char *const parms, Configuration &cfg)
int reqstate
State machine to talk to the bridge.
XrdOucString resource
The resource specified by the request, stripped of opaque data.
bool headerok
Tells if we have finished reading the header.
const std::string & userAgent() const
ReqType request
The request we got.
XrdOucEnv * opaque
The opaque data, after parsing.
int parseFirstLine(char *line, int len)
Parse the first line of the header.
int parseLine(char *line, int len)
Parse the header.
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
ClientRequest xrdreq
The last issued xrd request, often pending.
virtual int InitSSL(SSL *, char *)
virtual int FreeSSL(SSL *)
int setEtext(const char *text)
int Peek(char *buff, int blen, int timeout=-1)
int Recv(char *buff, int blen)
const XrdNetAddr * NetAddr() const
XrdNetAddrInfo * AddrInfo()
int Send(const char *buff, int blen)
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
void SetDialect(const char *dP)
void Set(int inQMax, time_t agemax=1800)
void Push(XrdObject< T > *Node)
static bool Import(const char *var, char *&val)
char * Get(const char *varname)
void * GetPtr(const char *varname)
void Put(const char *varname, const char *value)
T * Rep(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
void insert(const int i, int start=-1)
void assign(const char *s, int j, int k=-1)
const char * c_str() const
char * vorg
Entity's virtual organization(s)
int credslen
Length of the 'creds' data.
XrdNetAddrInfo * addrInfo
Entity's connection details.
const char * tident
Trace identifier always preset.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * caps
Entity's capabilities.
char * creds
Raw entity credentials or cert.
char * grps
Entity's group name(s)
void Reset(const char *spV=0)
char * name
Entity's name.
char * role
Entity's role(s)
char * endorsements
Protocol specific endorsements.
void Display(XrdSysError &mDest)
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
XrdSysLogger * logger(XrdSysLogger *lp=0)
void SetLogger(XrdSysLogger *logp)
int SessionCache(int opts=scNone, const char *id=0, int idlen=0)
static const int DEFAULT_CRL_REF_INT_SEC
Default CRL refresh interval in seconds.
static const uint64_t servr
This is a server context.
static const uint64_t rfCRL
Turn on the CRL refresh thread.
static const uint64_t logVF
Log verify failures.
static const uint64_t artON
Auto retry Handshake.
const CTX_Params * GetParams()
static const int scOff
Turn off cache.
bool SetContextCiphers(const char *ciphers)
static const int scSrvr
Turn on cache server mode (default)
static Bridge * Login(Result *rsltP, XrdLink *linkP, XrdSecEntity *seceP, const char *nameP, const char *protP)
virtual bool Run(const char *xreqP, char *xdataP=0, int xdataL=0)=0
std::string cafile
-> ca cert file.
std::string cadir
-> ca cert directory.
int crlRT
crl refresh interval time in seconds
std::string pkey
-> private key path.
std::string cert
-> certificate path.