24 #include "XrdVersion.hh"
48 #include <openssl/err.h>
49 #include <openssl/ssl.h>
51 #include <arpa/inet.h>
58 #define XRHTTP_TK_GRACETIME 600
99 BIO *XrdHttpProtocol::sslbio_err = 0;
101 bool XrdHttpProtocol::isRequiredXtractor =
false;
103 int XrdHttpProtocol::exthandlercnt = 0;
106 bool XrdHttpProtocol::usingEC = false;
124 const 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),
194 SecEntity(
""), 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;
306 char *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:
459 BIO *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) {
619 std::string traceLine = tmpline.
c_str();
623 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.");
632 TRACE(
DEBUG,
" Parsing first line: " << traceLine.c_str());
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.")
980 int 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);
1050 static const char *cvec[] = {
"*** http protocol config:", 0 };
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);
1217 const 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);
1320 int 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");
1405 int 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);
1427 int 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);
1450 int XrdHttpProtocol::BuffFree() {
1451 return (myBuff->
bsize - BuffUsed());
1458 void 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;
1494 int 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;
1536 int 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;
1562 int 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()))
1612 int 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);
1629 int 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();
1644 int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1645 const std::string crlf =
"\r\n";
1646 std::stringstream ss;
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;
1659 int XrdHttpProtocol::ChunkRespFooter() {
1660 const std::string crlf =
"\r\n";
1661 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1672 int 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);
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];
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)) ) {
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,
"'");
1824 bool 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!");
1869 void 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);
1932 void XrdHttpProtocol::Reset() {
1934 TRACE(ALL,
" Reset");
1943 myBuffStart = myBuffEnd = 0;
1946 DoneSetInfo =
false;
1996 if (!val || !val[0]) {
1997 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2006 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
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");
2192 if (!val || !val[0]) {
2193 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2221 bool inFile =
false;
2226 if (!val || !val[0]) {
2227 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2235 if (val[0] ==
'/') {
2238 int fd =
open(val, O_RDONLY);
2241 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2245 if (
fstat(fd, &st) != 0 ) {
2246 eDest.
Emsg(
"Config", errno,
"fstat shared secret key file", val);
2251 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2253 "For your own security, the shared secret key file cannot be world readable or group writable '", val,
"'");
2258 FILE *fp = fdopen(fd,
"r");
2260 if ( fp ==
nullptr ) {
2261 eDest.
Emsg(
"Config", errno,
"fdopen shared secret key file", val);
2267 while( fgets(line, 1024, fp) ) {
2271 pp = line + strlen(line) - 1;
2272 while ( (pp >= line) && (!isalnum(*pp)) ) {
2279 while ( *pp && !isalnum(*pp) ) pp++;
2281 if ( strlen(pp) >= 32 ) {
2282 eDest.
Say(
"Config",
"Secret key loaded.");
2294 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2299 if ( strlen(val) < 32 ) {
2300 eDest.
Emsg(
"Config",
"Secret key is too short");
2307 if (!inFile)
Config.noEcho();
2331 if (!val || !val[0]) {
2332 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2338 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2363 if (!val || !val[0]) {
2364 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2396 if (!val || !val[0]) {
2397 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2403 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2428 if (!val || !val[0]) {
2429 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2435 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2460 if (!val || !val[0]) {
2461 eDest.
Emsg(
"Config",
"staticredir url not specified");
2490 char *val, *k, key[1024];
2496 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2505 if (!val || !val[0]) {
2506 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2511 int fp =
open(val, O_RDONLY);
2513 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2517 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2519 nfo->data = (
char *)malloc(65536);
2520 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2523 if (nfo->len <= 0) {
2524 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2528 if (nfo->len >= 65536) {
2529 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2561 if (!val || !val[0]) {
2562 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2568 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2596 if (!val || !val[0]) {
2597 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2602 if (!strncmp(val,
"required", 8)) {
2603 isRequiredXtractor =
true;
2606 if (!val || !val[0]) {
2607 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2614 strlcpy(libName, val,
sizeof(libName));
2615 libName[
sizeof(libName) - 1] =
'\0';
2616 char libParms[4096];
2618 if (!
Config.GetRest(libParms, 4095)) {
2619 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2625 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2651 std::vector<extHInfo> &hiVec) {
2652 char *val, path[1024], namebuf[1024];
2655 bool noTlsOK =
false;
2660 if (!val || !val[0]) {
2661 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2664 if (strlen(val) >= 16) {
2665 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2668 strncpy(namebuf, val,
sizeof(namebuf));
2669 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2674 if(val && !strcmp(
"+notls",val)) {
2681 if (!val || !val[0]) {
2682 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2685 if (strlen(val) >= (int)
sizeof(path)) {
2686 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2698 for (
int i = 0; i < (int)hiVec.size(); i++)
2699 {
if (hiVec[i].extHName == namebuf) {
2700 eDest.
Emsg(
"Config",
"Instance name already present for "
2701 "http external handler plugin",
2702 hiVec[i].extHPath.c_str());
2710 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2716 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2760 if (!val || !val[0]) {
2761 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2794 if (!val || !val[0]) {
2795 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2825 if (!val || !val[0])
2826 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2830 if (!strcmp(val,
"off"))
2837 if (!strcmp(val,
"on"))
2844 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2849 char *val =
Config.GetWord();
2851 if(!strcmp(
"tpc",val)) {
2852 if(!(val =
Config.GetWord())) {
2853 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2855 if(!strcmp(
"fcreds",val)) {
2858 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2862 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
2886 static struct traceopts {
2898 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
2900 if (!(val =
Config.GetWord())) {
2901 eDest.
Emsg(
"config",
"trace option not specified");
2905 if (!strcmp(val,
"off")) trval = 0;
2907 if ((neg = (val[0] ==
'-' && val[1]))) val++;
2908 for (i = 0; i < numopts; i++) {
2909 if (!strcmp(val, tropts[i].opname)) {
2910 if (neg) trval &= ~tropts[i].opval;
2911 else trval |= tropts[i].opval;
2916 eDest.
Emsg(
"config",
"invalid trace option", val);
2935 l = strlen(fname) + 1;
2960 length = fname.
length() + 1;
2972 int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
2973 const char *libParms) {
2977 if (secxtractor)
return 1;
2979 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
2985 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
2993 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
2994 for (
int i = 0; i < (int) hiVec.size(); i++) {
2995 if(hiVec[i].extHNoTlsOK) {
2997 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
2998 hiVec[i].extHParm.c_str(), &myEnv,
2999 hiVec[i].extHName.c_str()))
3006 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3018 for (
int i = 0; i < (int)hiVec.size(); i++) {
3021 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3022 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3023 hiVec[i].extHParm.c_str(), &myEnv,
3024 hiVec[i].extHName.c_str()))
return 1;
3031 int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3032 const char *configFN,
const char *libParms,
3033 XrdOucEnv *myEnv,
const char *instName) {
3037 if (ExtHandlerLoaded(instName)) {
3038 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3042 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3046 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3054 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3057 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3058 exthandler[exthandlercnt].name[15] =
'\0';
3059 exthandler[exthandlercnt++].ptr = newhandler;
3072 bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3073 for (
int i = 0; i < exthandlercnt; i++) {
3074 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3085 for (
int i = 0; i < exthandlercnt; i++) {
3087 return exthandler[i].ptr;
struct ClientSetRequest set
struct ClientQueryRequest query
struct ClientStatRequest stat
#define XrdHttpExtHandlerArgs
int BIO_get_init(BIO *bio)
int BIO_get_shutdown(BIO *bio)
int BIO_get_flags(BIO *bio)
static int BIO_XrdLink_create(BIO *bio)
const char * XrdHttpSecEntityTident
void BIO_set_init(BIO *bio, int init)
int BIO_XrdLink_write(BIO *bio, const char *data, size_t datal, size_t *written)
#define HTTPS_ALERT(x, y, z)
static long BIO_XrdLink_ctrl(BIO *bio, int cmd, long num, void *ptr)
void BIO_set_shutdown(BIO *bio, int shut)
XrdSysTrace XrdHttpTrace("http")
void * BIO_get_data(BIO *bio)
static int BIO_XrdLink_read(BIO *bio, char *data, size_t datal, size_t *read)
void BIO_set_data(BIO *bio, void *ptr)
static int BIO_XrdLink_destroy(BIO *bio)
#define XRHTTP_TK_GRACETIME
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
void BIO_set_flags(BIO *bio, int flags)
A pragmatic implementation of the HTTP/DAV protocol for the Xrd framework.
#define MAX_XRDHTTPEXTHANDLERS
#define XrdHttpSecXtractorArgs
int compareHash(const char *h1, const char *h2)
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)
int stat(const char *path, struct stat *buf)
int open(const char *path, int oflag,...)
int fstat(int fildes, struct stat *buf)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define TLS_SET_VDEPTH(cOpts, vdv)
#define TLS_SET_REFINT(cOpts, refi)
void Release(XrdBuffer *bp)
XrdBuffer * Obtain(int bsz)
const std::vector< std::string > & getNonIANAConfiguredCksums() const
void configure(const char *csList)
static char * secretkey
The key used to calculate the url hashes.
static BIO_METHOD * m_bio_method
C-style vptr table for our custom BIO objects.
static char * gridmap
Gridmap file location. The same used by XrdSecGsi.
static XrdScheduler * Sched
static kXR_int32 myRole
Our role.
static XrdNetPMark * pmarkHandle
Packet marking handler pointer (assigned from the environment during the Config() call)
static char * Port_str
Our port, as a string.
XrdXrootd::Bridge * Bridge
The Bridge that we use to exercise the xrootd internals.
static char * staticredir
static bool selfhttps2http
If client is HTTPS, self-redirect with HTTP+token.
static XrdHttpChecksumHandler cksumHandler
static int hailWait
Timeout for reading the handshake.
int doChksum(const XrdOucString &fname)
Perform a checksum request.
static XrdOucHash< StaticPreloadInfo > * staticpreload
static char * xrd_cslist
The list of checksums that were configured via the xrd.cksum parameter on the server config file.
static char * sslcipherfilter
static int m_bio_type
Type identifier for our custom BIO objects.
static std::map< std::string, std::string > hdr2cgimap
Rules that turn HTTP headers to cgi tokens in the URL, for internal comsumption.
static char * sslcert
OpenSSL stuff.
XrdLink * Link
The link we are bound to.
int doStat(char *fname)
Perform a Stat request.
XrdObject< XrdHttpProtocol > ProtLink
static int readWait
Timeout for reading data.
void Recycle(XrdLink *lp, int consec, const char *reason)
Recycle this instance.
XrdHttpProtocol operator=(const XrdHttpProtocol &rhs)
static bool compatNameGeneration
static bool isdesthttps
True if the redirections must be towards https targets.
static XrdObjectQ< XrdHttpProtocol > ProtStack
XrdProtocol * Match(XrdLink *lp)
Tells if the oustanding bytes on the socket match this protocol implementation.
static 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.
ReqType request
The request we got.
XrdOucEnv * opaque
The opaque data, after parsing.
int parseFirstLine(char *line, int len)
Parse the first line of the header.
int parseLine(char *line, int len)
Parse the header.
void appendOpaque(XrdOucString &s, XrdSecEntity *secent, char *hash, time_t tnow)
ClientRequest xrdreq
The last issued xrd request, often pending.
const std::string & userAgent() const
virtual int InitSSL(SSL *, char *)
virtual int FreeSSL(SSL *)
int setEtext(const char *text)
int Peek(char *buff, int blen, int timeout=-1)
int Recv(char *buff, int blen)
const XrdNetAddr * NetAddr() const
XrdNetAddrInfo * AddrInfo()
int Send(const char *buff, int blen)
static const int noPort
Do not add port number.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtAddr
Address using suitable ipv4 or ipv6 format.
void SetDialect(const char *dP)
void Set(int inQMax, time_t agemax=1800)
void Push(XrdObject< T > *Node)
static bool Import(const char *var, char *&val)
void * GetPtr(const char *varname)
char * Get(const char *varname)
void Put(const char *varname, const char *value)
void insert(const int i, int start=-1)
const char * c_str() const
void assign(const char *s, int j, int k=-1)
char * vorg
Entity's virtual organization(s)
int credslen
Length of the 'creds' data.
XrdNetAddrInfo * addrInfo
Entity's connection details.
const char * tident
Trace identifier always preset.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * caps
Entity's capabilities.
char * creds
Raw entity credentials or cert.
char * grps
Entity's group name(s)
void Reset(const char *spV=0)
char * name
Entity's name.
char * role
Entity's role(s)
char * endorsements
Protocol specific endorsements.
void Display(XrdSysError &mDest)
char * moninfo
Information for monitoring.
char * host
Entity's host name dnr dependent.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
XrdSysLogger * logger(XrdSysLogger *lp=0)
void SetLogger(XrdSysLogger *logp)
int SessionCache(int opts=scNone, const char *id=0, int idlen=0)
static const int DEFAULT_CRL_REF_INT_SEC
Default CRL refresh interval in seconds.
static const uint64_t servr
This is a server context.
static const uint64_t rfCRL
Turn on the CRL refresh thread.
static const uint64_t logVF
Log verify failures.
static const uint64_t artON
Auto retry Handshake.
const CTX_Params * GetParams()
static const int scOff
Turn off cache.
bool SetContextCiphers(const char *ciphers)
static const int scSrvr
Turn on cache server mode (default)
static Bridge * Login(Result *rsltP, XrdLink *linkP, XrdSecEntity *seceP, const char *nameP, const char *protP)
virtual bool Run(const char *xreqP, char *xdataP=0, int xdataL=0)=0
CloseImpl< false > Close(Ctx< File > file, uint16_t timeout=0)
Factory for creating CloseImpl objects.
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.