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";
152 "xrootd protocol anchor");
158 #if OPENSSL_VERSION_NUMBER < 0x10100000L
165 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
180 bio->shutdown = shut;
183 return bio->shutdown;
195 :
XrdProtocol(
"HTTP protocol handler"), ProtLink(this),
196 SecEntity(
""), CurrentReq(this, ReadRangeConfig) {
221 char mybuf[16], mybuf2[1024];
224 bool myishttps =
false;
228 if ((dlen = lp->
Peek(mybuf, (
int) sizeof (mybuf),
hailWait)) < (
int)
sizeof (mybuf)) {
229 if (dlen <= 0) lp->
setEtext(
"handshake not received");
232 mybuf[dlen - 1] =
'\0';
240 for (
int i = 0; i < dlen; i++) {
242 sprintf(mybuf3,
"%.02d ", mybuf[i]);
243 strcat(mybuf2, mybuf3);
250 for (
int i = 0; i < dlen - 1; i++)
251 if (!isprint(mybuf[i]) && (mybuf[i] !=
'\r') && (mybuf[i] !=
'\n')) {
253 TRACEI(
DEBUG,
"This does not look like http at pos " << i);
258 if ((!ismine) && (dlen >= 4)) {
259 char check[4] = {00, 00, 00, 00};
260 if (memcmp(mybuf, check, 4)) {
267 TRACEI(ALL,
"This may look like https, but https is not configured");
274 TRACEI(
DEBUG,
"This does not look like https. Protocol not matched.");
282 TRACEI(REQ,
"Protocol matched. https: " << myishttps);
285 hp->ishttps = myishttps;
300 hp->myBuffStart = hp->myBuffEnd = hp->myBuff->
buff;
308 char *XrdHttpProtocol::GetClientIPStr() {
311 if (!
Link)
return strdup(
"unknown");
313 if (!ai)
return strdup(
"unknown");
321 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
332 int ret = lp->
Send(data, datal);
333 BIO_clear_retry_flags(bio);
336 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
337 BIO_set_retry_write(bio);
353 int ret = lp->
Send(data, datal);
354 BIO_clear_retry_flags(bio);
356 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
357 BIO_set_retry_write(bio);
364 #if OPENSSL_VERSION_NUMBER < 0x1000105fL
375 int ret = lp->
Recv(data, datal);
376 BIO_clear_retry_flags(bio);
379 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
380 BIO_set_retry_read(bio);
395 int ret = lp->
Recv(data, datal);
396 BIO_clear_retry_flags(bio);
398 if ((errno == EINTR) || (errno == EINPROGRESS) || (errno == EAGAIN) || (errno == EWOULDBLOCK))
399 BIO_set_retry_read(bio);
415 #if OPENSSL_VERSION_NUMBER < 0x10100000L
427 if (bio == NULL)
return 0;
443 case BIO_CTRL_GET_CLOSE:
446 case BIO_CTRL_SET_CLOSE:
464 setsockopt(link->FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
465 setsockopt(link->FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
478 BIO *XrdHttpProtocol::CreateBIO(
XrdLink *lp)
497 #define TRACELINK Link
505 if (!myBuff || !myBuff->
buff || !myBuff->
bsize) {
506 TRACE(ALL,
" Process. No buffer available. Internal error.");
512 char *nfo = GetClientIPStr();
514 TRACEI(REQ,
" Setting host: " << nfo);
523 if (ishttps && !ssldone) {
526 sbio = CreateBIO(
Link);
527 BIO_set_nbio(sbio, 1);
530 postheaderauth =
false;
531 postheaderwait =
false;
532 postheaderauthdone =
false;
537 ERR_print_errors(sslbio_err);
546 SSL_set_bio(ssl, sbio, sbio);
553 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_RCVTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
554 setsockopt(
Link->
FDnum(), SOL_SOCKET, SO_SNDTIMEO, (
struct timeval *)&tv,
sizeof(
struct timeval));
557 int res = SSL_accept(ssl);
559 if ((res == -1) && (SSL_get_error(ssl, res) == SSL_ERROR_WANT_READ)) {
560 TRACEI(
DEBUG,
" SSL_accept wants to read more bytes... err:" << SSL_get_error(ssl, res));
565 ERR_print_errors(sslbio_err);
574 BIO_set_nbio(sbio, 0);
579 if (
tlsClientAuth == XrdTlsContext::ClientAuthSetting::kOn && HandleAuthentication(
Link)) {
600 if ((rc = getDataOneShot(BuffAvailable())) < 0) {
606 if (BuffUsed() < ResumeBytes)
return 1;
611 }
else if (!DoneSetInfo && !postheaderwait && !postheaderauth && !
CurrentReq.
userAgent().empty()) {
614 if (mon_info.size() >= 1024) {
615 TRACEI(ALL,
"User agent string too long");
617 TRACEI(ALL,
"Internal logic error: Bridge is null after login");
626 SendSimpleResp(500,
nullptr,
nullptr,
"Could not set user agent.", 0,
false);
631 }
else if (!postheaderwait) {
641 while ((rc = BuffgetLine(tmpline)) > 0) {
643 std::string traceLine{tmpline.
c_str()};
645 TRACE(
DEBUG,
" rc:" << rc <<
" got hdr line: " << traceLine);
647 if ((rc == 2) && (tmpline.
length() > 1) && (tmpline[rc - 1] ==
'\n')) {
649 TRACE(
DEBUG,
" rc:" << rc <<
" detected header end.");
658 TRACE(
DEBUG,
" Parsing of first line failed with " << result);
662 #if OPENSSL_VERSION_NUMBER >= 0x10100010L
665 if (!postheaderauthdone &&
tlsClientAuth == XrdTlsContext::ClientAuthSetting::kDefer)
668 {postheaderwait =
true;
679 TRACE(
DEBUG,
" Parsing of header line failed with " << result)
680 SendSimpleResp(400,NULL,NULL,
"Malformed header line. Hint: ensure the line finishes with \"\\r\\n\"", 0,
false);
691 TRACEI(REQ,
" rc:" << rc <<
"Header not yet complete.");
696 if ((rc <= 0) && (BuffUsed() >= 16384)) {
697 TRACEI(ALL,
"Corrupted header detected, or line too long. Disconnecting client.");
711 #if OPENSSL_VERSION_NUMBER >= 0x10100010L
712 if (postheaderwait) {
713 postheaderwait =
false;
714 if (SSL_verify_client_post_handshake(ssl) != 1) {
717 TRACEI(ALL,
"Unable to request client X.509 authentication");
718 ERR_print_errors(sslbio_err);
722 auto res = SSL_write_ex(ssl,
nullptr, 0, &write_size);
724 TRACEI(
DEBUG,
" SSL post-handshake auth failed; err:" << SSL_get_error(ssl, res));
725 ERR_print_errors(sslbio_err);
726 SendSimpleResp(500,
nullptr,
nullptr,
"Failed post-handshake authentication", 0,
false);
729 TRACEI(
DEBUG,
" SSL post-handshake auth finished successfully");
730 postheaderauth =
true;
735 if (postheaderauth) {
736 postheaderauth =
false;
737 postheaderauthdone =
true;
739 TRACEI(REQ,
"Reading out response to post-handshake authentication");
740 BIO_set_nbio(sbio, 1);
741 auto res = SSL_peek_ex(ssl,
nullptr, 0, &readbytes);
742 if ((res <= 0) && SSL_get_error(ssl, res) != SSL_ERROR_WANT_READ) {
743 SendSimpleResp(500,
nullptr,
nullptr,
"Failed to process authentication frames", 0,
false);
746 BIO_set_nbio(sbio, 0);
747 if (HandleAuthentication(
Link)) {
748 SendSimpleResp(500,
nullptr,
nullptr,
"Failed to extract authentication information from handshake", 0,
false);
760 time_t timenow = time(0);
778 TRACEI(REQ,
" rc:" << rc <<
" self-redirecting to http with security token.");
785 struct sockaddr_storage sa;
786 socklen_t sl =
sizeof(sa);
793 switch (sa.ss_family) {
795 if (inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), buf, INET_ADDRSTRLEN)) {
802 if (inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), buf, INET6_ADDRSTRLEN)) {
804 Addr_str = (
char *)malloc(strlen(buf)+3);
812 TRACEI(REQ,
" Can't recognize the address family of the local host.");
820 TRACEI(REQ,
" rc:"<<rc<<
" self-redirecting to http with security token: '"
821 << dest.
c_str() <<
"'");
825 SendSimpleResp(302, NULL, (
char *) dest.
c_str(), 0, 0,
true);
830 TRACEI(REQ,
" rc:" << rc <<
" Can't perform self-redirection.");
834 TRACEI(ALL,
" Could not calculate self-redirection hash");
840 if (!ishttps && !ssldone) {
850 if (t) tim = atoi(t);
852 TRACEI(REQ,
" xrdhttptime not specified. Authentication failed.");
856 TRACEI(REQ,
" Token expired. Authentication failed.");
941 TRACEI(REQ,
" Invalid tk '" << tk <<
"' != '" << hash <<
"'(calculated). Authentication failed.");
948 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
956 TRACEI(ALL,
" Rejecting plain http with no valid token as we have a secretkey.");
976 TRACEI(REQ,
" Authorization failed.");
992 TRACEI(REQ,
"Process is exiting rc:" << rc);
1000 #define TRACELINK Link
1054 #define TS_Xeq(x,m) (!strcmp(x,var)) GoNo = m(Config)
1056 #define TS_Xeq3(x,m) (!strcmp(x,var)) GoNo = m(Config, extHIVec)
1058 #define HTTPS_ALERT(x,y,z) httpsspec = true;\
1059 if (xrdctx && httpsmode == hsmAuto && (z || xrdctx->x509Verify())) \
1060 eDest.Say("Config http." x " overrides the xrd." y " directive.")
1062 int XrdHttpProtocol::Config(
const char *ConfigFN,
XrdOucEnv *myEnv) {
1065 std::vector<extHInfo> extHIVec;
1067 int cfgFD, GoNo, NoGo = 0, ismine;
1077 if(nonIanaChecksums.size()) {
1078 std::stringstream warningMsgSS;
1079 warningMsgSS <<
"Config warning: the following checksum algorithms are not IANA compliant: [";
1080 std::string unknownCksumString;
1081 for(
auto unknownCksum: nonIanaChecksums) {
1082 unknownCksumString += unknownCksum +
",";
1084 unknownCksumString.erase(unknownCksumString.size() - 1);
1085 warningMsgSS << unknownCksumString <<
"]" <<
". They therefore cannot be queried by a user via HTTP." ;
1086 eDest.
Say(warningMsgSS.str().c_str());
1092 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1094 m_bio_method =
static_cast<BIO_METHOD*
>(OPENSSL_malloc(
sizeof(BIO_METHOD)));
1129 if ((cfgFD =
open(ConfigFN, O_RDONLY, 0)) < 0)
1130 return eDest.
Emsg(
"Config", errno,
"open config file", ConfigFN);
1132 static const char *cvec[] = {
"*** http protocol config:", 0 };
1137 while ((var =
Config.GetMyFirstWord())) {
1138 if ((ismine = !strncmp(
"http.", var, 5)) && var[5]) var += 5;
1141 if TS_Xeq(
"trace", xtrace);
1142 else if TS_Xeq(
"cert", xsslcert);
1143 else if TS_Xeq(
"key", xsslkey);
1144 else if TS_Xeq(
"cadir", xsslcadir);
1145 else if TS_Xeq(
"cipherfilter", xsslcipherfilter);
1146 else if TS_Xeq(
"gridmap", xgmap);
1147 else if TS_Xeq(
"cafile", xsslcafile);
1148 else if TS_Xeq(
"secretkey", xsecretkey);
1149 else if TS_Xeq(
"desthttps", xdesthttps);
1150 else if TS_Xeq(
"secxtractor", xsecxtractor);
1151 else if TS_Xeq3(
"exthandler", xexthandler);
1152 else if TS_Xeq(
"selfhttps2http", xselfhttps2http);
1153 else if TS_Xeq(
"embeddedstatic", xembeddedstatic);
1154 else if TS_Xeq(
"listingredir", xlistredir);
1155 else if TS_Xeq(
"staticredir", xstaticredir);
1156 else if TS_Xeq(
"staticpreload", xstaticpreload);
1157 else if TS_Xeq(
"listingdeny", xlistdeny);
1158 else if TS_Xeq(
"header2cgi", xheader2cgi);
1159 else if TS_Xeq(
"httpsmode", xhttpsmode);
1160 else if TS_Xeq(
"tlsreuse", xtlsreuse);
1161 else if TS_Xeq(
"auth", xauth);
1162 else if TS_Xeq(
"tlsclientauth", xtlsclientauth);
1163 else if TS_Xeq(
"tlsrequiredprefix", xtlsrequiredprefix);
1165 eDest.
Say(
"Config warning: ignoring unknown directive '", var,
"'.");
1180 {
eDest.
Say(
"Config failure: one or more directives are flawed!");
1186 hdr2cgimap[
"Cache-Control"] =
"cache-control";
1189 if (getenv(
"XRDCL_EC"))
usingEC =
true;
1198 :
"was not configured.");
1199 const char *what = Configed();
1201 eDest.
Say(
"Config warning: HTTPS functionality ", why);
1204 LoadExtHandlerNoTls(extHIVec, ConfigFN, *myEnv);
1206 {
eDest.
Say(
"Config failure: ", what,
" HTTPS but it ", why);
1216 {
eDest.
Say(
"Config warning: specifying http.key without http.cert "
1217 "is meaningless; ignoring key!");
1225 {
eDest.
Say(
"Config failure: 'httpsmode manual' requires atleast a "
1226 "a cert specification!");
1237 const char *what1 = 0, *what2 = 0, *what3 = 0;
1242 what1 =
"xrd.tls to supply 'cert' and 'key'.";
1246 what2 =
"xrd.tlsca to supply 'cadir'.";
1250 what2 = (what2 ?
"xrd.tlsca to supply 'cadir' and 'cafile'."
1251 :
"xrd.tlsca to supply 'cafile'.");
1255 what3 =
"xrd.tlsca to supply 'refresh' interval.";
1265 {
const char *what = Configed();
1266 const char *why = (
httpsspec ?
"a cadir or cafile was not specified!"
1267 :
"'xrd.tlsca noverify' was specified!");
1269 {
eDest.
Say(
"Config failure: ", what,
" cert verification but ", why);
1277 sslbio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
1282 const char *how =
"completed.";
1283 eDest.
Say(
"++++++ HTTPS initialization started.");
1284 if (!
InitTLS()) {NoGo = 1; how =
"failed.";}
1285 eDest.
Say(
"------ HTTPS initialization ", how);
1286 if (NoGo)
return NoGo;
1290 if (LoadExtHandler(extHIVec, ConfigFN, *myEnv))
return 1;
1294 return (InitSecurity() ? NoGo : 1);
1301 const char *XrdHttpProtocol::Configed()
1303 if (secxtractor &&
gridmap)
return "gridmap and secxtractor require";
1304 if (secxtractor)
return "secxtractor requires";
1305 if (
gridmap)
return "gridmap requires";
1321 if (myBuffEnd >= myBuffStart) {
1323 for (
char *p = myBuffStart; p < myBuffEnd; p++) {
1328 dest.
assign(myBuffStart, 0, l-1);
1347 for (
char *p = myBuffStart; p < myBuff->
buff + myBuff->
bsize; p++) {
1349 if ((*p ==
'\n') || (*p ==
'\0')) {
1352 dest.
assign(myBuffStart, 0, l-1);
1368 for (
char *p = myBuff->
buff; p < myBuffEnd; p++) {
1370 if ((*p ==
'\n') || (*p ==
'\0')) {
1374 int l1 = myBuff->
buff + myBuff->
bsize - myBuffStart;
1376 dest.
assign(myBuffStart, 0, l1-1);
1380 dest.
insert(myBuffStart, l1, l-1);
1404 int XrdHttpProtocol::getDataOneShot(
int blen,
bool wait) {
1419 maxread = std::min(blen, BuffAvailable());
1420 TRACE(
DEBUG,
"getDataOneShot BuffAvailable: " << BuffAvailable() <<
" maxread: " << maxread);
1426 int sslavail = maxread;
1429 int l = SSL_pending(ssl);
1431 sslavail = std::min(maxread, SSL_pending(ssl));
1436 ERR_print_errors(sslbio_err);
1440 TRACE(
DEBUG,
"getDataOneShot sslavail: " << sslavail);
1441 if (sslavail <= 0)
return 0;
1443 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1445 myBuffEnd = myBuff->
buff;
1448 rlen = SSL_read(ssl, myBuffEnd, sslavail);
1451 ERR_print_errors(sslbio_err);
1458 if (myBuffEnd - myBuff->
buff >= myBuff->
bsize) {
1460 myBuffEnd = myBuff->
buff;
1466 rlen =
Link->
Recv(myBuffEnd, maxread);
1482 TRACE(REQ,
"read " << rlen <<
" of " << blen <<
" bytes");
1489 int XrdHttpProtocol::BuffAvailable() {
1492 if (myBuffEnd >= myBuffStart)
1493 r = myBuff->
buff + myBuff->
bsize - myBuffEnd;
1495 r = myBuffStart - myBuffEnd;
1497 if ((r < 0) || (r > myBuff->
bsize)) {
1498 TRACE(REQ,
"internal error, myBuffAvailable: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1511 int XrdHttpProtocol::BuffUsed() {
1514 if (myBuffEnd >= myBuffStart)
1515 r = myBuffEnd - myBuffStart;
1518 r = myBuff->
bsize - (myBuffStart - myBuffEnd);
1520 if ((r < 0) || (r > myBuff->
bsize)) {
1521 TRACE(REQ,
"internal error, myBuffUsed: " << r <<
" myBuff->bsize " << myBuff->
bsize);
1534 int XrdHttpProtocol::BuffFree() {
1535 return (myBuff->
bsize - BuffUsed());
1542 void XrdHttpProtocol::BuffConsume(
int blen) {
1544 if (blen > myBuff->
bsize) {
1545 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") smaller than buffsize");
1549 if (blen > BuffUsed()) {
1550 TRACE(REQ,
"internal error, BuffConsume(" << blen <<
") larger than BuffUsed:" << BuffUsed());
1554 myBuffStart = myBuffStart + blen;
1556 if (myBuffStart >= myBuff->
buff + myBuff->
bsize)
1557 myBuffStart -= myBuff->
bsize;
1559 if (myBuffEnd >= myBuff->
buff + myBuff->
bsize)
1560 myBuffEnd -= myBuff->
bsize;
1562 if (BuffUsed() == 0)
1563 myBuffStart = myBuffEnd = myBuff->
buff;
1578 int XrdHttpProtocol::BuffgetData(
int blen,
char **data,
bool wait) {
1581 TRACE(
DEBUG,
"BuffgetData: requested " << blen <<
" bytes");
1586 if (blen > BuffUsed()) {
1587 TRACE(REQ,
"BuffgetData: need to read " << blen - BuffUsed() <<
" bytes");
1588 if ( getDataOneShot(blen - BuffUsed(),
true) )
1594 if ( !BuffUsed() ) {
1595 if ( getDataOneShot(blen,
false) )
1603 if (myBuffStart <= myBuffEnd) {
1604 rlen = std::min( (
long) blen, (
long)(myBuffEnd - myBuffStart) );
1607 rlen = std::min( (
long) blen, (
long)(myBuff->
buff + myBuff->
bsize - myBuffStart) );
1609 *data = myBuffStart;
1620 int XrdHttpProtocol::SendData(
const char *body,
int bodylen) {
1624 if (body && bodylen) {
1625 TRACE(REQ,
"Sending " << bodylen <<
" bytes");
1627 r = SSL_write(ssl, body, bodylen);
1629 ERR_print_errors(sslbio_err);
1635 if (r <= 0)
return -1;
1646 int XrdHttpProtocol::StartSimpleResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1647 std::stringstream ss;
1648 const std::string crlf =
"\r\n";
1650 ss <<
"HTTP/1.1 " << code <<
" ";
1654 if (code == 200) ss <<
"OK";
1655 else if (code == 100) ss <<
"Continue";
1656 else if (code == 206) ss <<
"Partial Content";
1657 else if (code == 302) ss <<
"Redirect";
1658 else if (code == 307) ss <<
"Temporary Redirect";
1659 else if (code == 400) ss <<
"Bad Request";
1660 else if (code == 403) ss <<
"Forbidden";
1661 else if (code == 404) ss <<
"Not Found";
1662 else if (code == 405) ss <<
"Method Not Allowed";
1663 else if (code == 416) ss <<
"Range Not Satisfiable";
1664 else if (code == 500) ss <<
"Internal Server Error";
1665 else if (code == 504) ss <<
"Gateway Timeout";
1666 else ss <<
"Unknown";
1669 if (keepalive && (code != 100))
1670 ss <<
"Connection: Keep-Alive" << crlf;
1672 ss <<
"Connection: Close" << crlf;
1674 ss <<
"Server: XrootD/" << XrdVSTRING << crlf;
1676 if ((bodylen >= 0) && (code != 100))
1677 ss <<
"Content-Length: " << bodylen << crlf;
1679 if (header_to_add && (header_to_add[0] !=
'\0'))
1680 ss << header_to_add << crlf;
1684 const std::string &outhdr = ss.str();
1685 TRACEI(RSP,
"Sending resp: " << code <<
" header len:" << outhdr.size());
1686 if (SendData(outhdr.c_str(), outhdr.size()))
1696 int XrdHttpProtocol::StartChunkedResp(
int code,
const char *desc,
const char *header_to_add,
long long bodylen,
bool keepalive) {
1697 const std::string crlf =
"\r\n";
1698 std::stringstream ss;
1700 if (header_to_add && (header_to_add[0] !=
'\0')) {
1701 ss << header_to_add << crlf;
1704 ss <<
"Transfer-Encoding: chunked";
1705 TRACEI(RSP,
"Starting chunked response");
1706 return StartSimpleResp(code, desc, ss.str().c_str(), bodylen, keepalive);
1713 int XrdHttpProtocol::ChunkResp(
const char *body,
long long bodylen) {
1714 long long content_length = (bodylen <= 0) ? (body ? strlen(body) : 0) : bodylen;
1715 if (ChunkRespHeader(content_length))
1718 if (body && SendData(body, content_length))
1721 return ChunkRespFooter();
1728 int XrdHttpProtocol::ChunkRespHeader(
long long bodylen) {
1729 const std::string crlf =
"\r\n";
1730 std::stringstream ss;
1734 const std::string &chunkhdr = ss.str();
1735 TRACEI(RSP,
"Sending encoded chunk of size " << bodylen);
1736 return (SendData(chunkhdr.c_str(), chunkhdr.size())) ? -1 : 0;
1743 int XrdHttpProtocol::ChunkRespFooter() {
1744 const std::string crlf =
"\r\n";
1745 return (SendData(crlf.c_str(), crlf.size())) ? -1 : 0;
1756 int XrdHttpProtocol::SendSimpleResp(
int code,
const char *desc,
const char *header_to_add,
const char *body,
long long bodylen,
bool keepalive) {
1758 long long content_length = bodylen;
1760 content_length = body ? strlen(body) : 0;
1763 if (StartSimpleResp(code, desc, header_to_add, content_length, keepalive) < 0)
1770 return SendData(body, content_length);
1807 sprintf(buf,
"%d",
Port);
1813 rdf = (parms && *parms ? parms : pi->
ConfigFN);
1819 if ((rdf = getenv(
"XRDROLE"))) {
1822 if (!strcasecmp(rdf,
"manager") || !strcasecmp(rdf,
"supervisor")) {
1824 eDest.
Emsg(
"Config",
"Configured as HTTP(s) redirector.");
1827 eDest.
Emsg(
"Config",
"Configured as HTTP(s) data server.");
1831 eDest.
Emsg(
"Config",
"No XRDROLE specified.");
1850 char *val, keybuf[1024], parmbuf[1024];
1855 if (!val || !val[0]) {
1856 err.
Emsg(
"Config",
"No headerkey specified.");
1861 while ( *val && !isalnum(*val) ) val++;
1862 strcpy(keybuf, val);
1866 pp = keybuf + strlen(keybuf) - 1;
1867 while ( (pp >= keybuf) && (!isalnum(*pp)) ) {
1875 if(!parm || !parm[0]) {
1876 err.
Emsg(
"Config",
"No header2cgi value specified. key: '", keybuf,
"'");
1881 while ( *parm && !isalnum(*parm) ) parm++;
1882 strcpy(parmbuf, parm);
1885 pp = parmbuf + strlen(parmbuf) - 1;
1886 while ( (pp >= parmbuf) && (!isalnum(*pp)) ) {
1893 header2cgi[keybuf] = parmbuf;
1895 err.
Emsg(
"Config",
"Can't insert new header2cgi rule. key: '", keybuf,
"'");
1908 bool XrdHttpProtocol::InitTLS() {
1933 static const char *sess_ctx_id =
"XrdHTTPSessionCtx";
1934 unsigned int n =(
unsigned int)(strlen(sess_ctx_id)+1);
1940 {
eDest.
Say(
"Config failure: ",
"Unable to set allowable https ciphers!");
1953 void XrdHttpProtocol::Cleanup() {
1955 TRACE(ALL,
" Cleanup");
1957 if (
BPool && myBuff) {
1958 BuffConsume(BuffUsed());
1972 int ret = SSL_shutdown(ssl);
1976 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1977 ERR_remove_thread_state(
nullptr);
1981 TRACE(ALL,
" SSL_shutdown failed");
1982 ERR_print_errors(sslbio_err);
2016 void XrdHttpProtocol::Reset() {
2018 TRACE(ALL,
" Reset");
2027 myBuffStart = myBuffEnd = 0;
2030 DoneSetInfo =
false;
2031 postheaderauth =
false;
2032 postheaderwait =
false;
2082 if (!val || !val[0]) {
2083 eDest.
Emsg(
"Config",
"httpsmode parameter not specified");
2092 else {
eDest.
Emsg(
"Config",
"invalid httpsmode parameter - ", val);
2117 if (!val || !val[0]) {
2118 eDest.
Emsg(
"Config",
"sslverifydepth value not specified");
2149 if (!val || !val[0]) {
2150 eDest.
Emsg(
"Config",
"HTTP X509 certificate not specified");
2184 if (!val || !val[0]) {
2185 eDest.
Emsg(
"Config",
"HTTP X509 key not specified");
2221 if (!val || !val[0]) {
2222 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file location not specified");
2228 if (!strncmp(val,
"required", 8)) {
2232 if (!val || !val[0]) {
2233 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after [required] "
2241 if (!strcmp(val,
"compatNameGeneration")) {
2244 if (!val || !val[0]) {
2245 eDest.
Emsg(
"Config",
"HTTP X509 gridmap file missing after "
2246 "[compatNameGeneration] parameter");
2278 if (!val || !val[0]) {
2279 eDest.
Emsg(
"Config",
"HTTP X509 CAfile not specified");
2307 bool inFile =
false;
2312 if (!val || !val[0]) {
2313 eDest.
Emsg(
"Config",
"Shared secret key not specified");
2321 if (val[0] ==
'/') {
2324 if (
stat(val, &st) ) {
2325 eDest.
Emsg(
"Config", errno,
"stat shared secret key file", val);
2329 if ( st.st_mode & S_IWOTH & S_IWGRP & S_IROTH) {
2330 eDest.
Emsg(
"Config",
"For your own security, the shared secret key file cannot be world readable or group writable'", val,
"'");
2334 FILE *fp =
fopen(val,
"r");
2337 eDest.
Emsg(
"Config", errno,
"open shared secret key file", val);
2342 while( fgets(line, 1024, fp) ) {
2346 pp = line + strlen(line) - 1;
2347 while ( (pp >= line) && (!isalnum(*pp)) ) {
2354 while ( *pp && !isalnum(*pp) ) pp++;
2356 if ( strlen(pp) >= 32 ) {
2357 eDest.
Say(
"Config",
"Secret key loaded.");
2369 eDest.
Emsg(
"Config",
"Cannot find useful secretkey in file '", val,
"'");
2374 if ( strlen(val) < 32 ) {
2375 eDest.
Emsg(
"Config",
"Secret key is too short");
2382 if (!inFile)
Config.noEcho();
2406 if (!val || !val[0]) {
2407 eDest.
Emsg(
"Config",
"listingdeny flag not specified");
2413 listdeny = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2438 if (!val || !val[0]) {
2439 eDest.
Emsg(
"Config",
"listingredir flag not specified");
2471 if (!val || !val[0]) {
2472 eDest.
Emsg(
"Config",
"desthttps flag not specified");
2478 isdesthttps = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2503 if (!val || !val[0]) {
2504 eDest.
Emsg(
"Config",
"embeddedstatic flag not specified");
2510 embeddedstatic = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2535 if (!val || !val[0]) {
2536 eDest.
Emsg(
"Config",
"staticredir url not specified");
2565 char *val, *k, key[1024];
2571 eDest.
Emsg(
"Config",
"preloadstatic urlpath not specified");
2580 if (!val || !val[0]) {
2581 eDest.
Emsg(
"Config",
"preloadstatic filename not specified");
2586 int fp =
open(val, O_RDONLY);
2588 eDest.
Emsg(
"Config", errno,
"open preloadstatic filename", val);
2592 StaticPreloadInfo *nfo =
new StaticPreloadInfo;
2594 nfo->data = (
char *)malloc(65536);
2595 nfo->len =
read(fp, (
void *)nfo->data, 65536);
2598 if (nfo->len <= 0) {
2599 eDest.
Emsg(
"Config", errno,
"read from preloadstatic filename", val);
2603 if (nfo->len >= 65536) {
2604 eDest.
Emsg(
"Config",
"Truncated preloadstatic filename. Max is 64 KB '", val,
"'");
2636 if (!val || !val[0]) {
2637 eDest.
Emsg(
"Config",
"selfhttps2http flag not specified");
2643 selfhttps2http = (!strcasecmp(val,
"true") || !strcasecmp(val,
"yes") || !strcmp(val,
"1"));
2671 if (!val || !val[0]) {
2672 eDest.
Emsg(
"Config",
"No security extractor plugin specified.");
2677 if (!strncmp(val,
"required", 8)) {
2678 isRequiredXtractor =
true;
2681 if (!val || !val[0]) {
2682 eDest.
Emsg(
"Config",
"No security extractor plugin after [required] "
2689 strlcpy(libName, val,
sizeof(libName));
2690 libName[
sizeof(libName) - 1] =
'\0';
2691 char libParms[4096];
2693 if (!
Config.GetRest(libParms, 4095)) {
2694 eDest.
Emsg(
"Config",
"secxtractor config params longer than 4k");
2700 if (LoadSecXtractor(&
eDest, libName, libParms)) {
2726 std::vector<extHInfo> &hiVec) {
2727 char *val, path[1024], namebuf[1024];
2730 bool noTlsOK =
false;
2735 if (!val || !val[0]) {
2736 eDest.
Emsg(
"Config",
"No instance name specified for an http external handler plugin.");
2739 if (strlen(val) >= 16) {
2740 eDest.
Emsg(
"Config",
"Instance name too long for an http external handler plugin.");
2743 strncpy(namebuf, val,
sizeof(namebuf));
2744 namebuf[
sizeof(namebuf)-1 ] =
'\0';
2749 if(val && !strcmp(
"+notls",val)) {
2756 if (!val || !val[0]) {
2757 eDest.
Emsg(
"Config",
"No http external handler plugin specified.");
2760 if (strlen(val) >= (int)
sizeof(path)) {
2761 eDest.
Emsg(
"Config",
"Path too long for an http external handler plugin.");
2773 for (
int i = 0; i < (int)hiVec.size(); i++)
2774 {
if (hiVec[i].extHName == namebuf) {
2775 eDest.
Emsg(
"Config",
"Instance name already present for "
2776 "http external handler plugin",
2777 hiVec[i].extHPath.c_str());
2785 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
2791 hiVec.push_back(extHInfo(namebuf, path, (parm ? parm :
""), noTlsOK));
2835 if (!val || !val[0]) {
2836 eDest.
Emsg(
"Config",
"HTTP X509 CAdir not specified");
2869 if (!val || !val[0]) {
2870 eDest.
Emsg(
"Config",
"SSL cipherlist filter string not specified");
2900 if (!val || !val[0])
2901 {
eDest.
Emsg(
"Config",
"tlsreuse argument not specified");
return 1;}
2905 if (!strcmp(val,
"off"))
2912 if (!strcmp(val,
"on"))
2919 eDest.
Emsg(
"config",
"invalid tlsreuse parameter -", val);
2924 auto val =
Config.GetWord();
2925 if (!val || !val[0])
2926 {
eDest.
Emsg(
"Config",
"tlsclientauth argument not specified");
return 1;}
2928 if (!strcmp(val,
"off"))
2932 if (!strcmp(val,
"on"))
2936 if (!strcmp(val,
"defer"))
2938 #if OPENSSL_VERSION_NUMBER >= 0x10100010L
2942 eDest.
Emsg(
"config",
"http.tlsclientauth defer is not supported on this platform");
2947 eDest.
Emsg(
"config",
"invalid tlsclientauth parameter -", val);
2952 auto val =
Config.GetWord();
2953 if (!val || !val[0])
2954 {
eDest.
Emsg(
"Config",
"tlsrequiredprefix argument not specified");
return 1;}
2957 {
eDest.
Emsg(
"Config",
"http.tlsrequiredprefix argument must be an absolute path");
return 1;}
2964 char *val =
Config.GetWord();
2966 if(!strcmp(
"tpc",val)) {
2967 if(!(val =
Config.GetWord())) {
2968 eDest.
Emsg(
"Config",
"http.auth tpc value not specified.");
return 1;
2970 if(!strcmp(
"fcreds",val)) {
2973 eDest.
Emsg(
"Config",
"http.auth tpc value is invalid");
return 1;
2977 eDest.
Emsg(
"Config",
"http.auth value is invalid");
return 1;
3001 static struct traceopts {
3013 int i, neg, trval = 0, numopts =
sizeof (tropts) /
sizeof (
struct traceopts);
3015 if (!(val =
Config.GetWord())) {
3016 eDest.
Emsg(
"config",
"trace option not specified");
3020 if (!strcmp(val,
"off")) trval = 0;
3022 if ((neg = (val[0] ==
'-' && val[1]))) val++;
3023 for (i = 0; i < numopts; i++) {
3024 if (!strcmp(val, tropts[i].opname)) {
3025 if (neg) trval &= ~tropts[i].opval;
3026 else trval |= tropts[i].opval;
3031 eDest.
Emsg(
"config",
"invalid trace option", val);
3050 l = strlen(fname) + 1;
3075 length = fname.
length() + 1;
3087 int XrdHttpProtocol::LoadSecXtractor(
XrdSysError *myeDest,
const char *libName,
3088 const char *libParms) {
3092 if (secxtractor)
return 1;
3094 XrdOucPinLoader myLib(myeDest, &compiledVer,
"secxtractorlib", libName);
3100 if (ep && (secxtractor = ep(myeDest, NULL, libParms)))
return 0;
3108 int XrdHttpProtocol::LoadExtHandlerNoTls(std::vector<extHInfo> &hiVec,
const char *cFN,
XrdOucEnv &myEnv) {
3109 for (
int i = 0; i < (int) hiVec.size(); i++) {
3110 if(hiVec[i].extHNoTlsOK) {
3112 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3113 hiVec[i].extHParm.c_str(), &myEnv,
3114 hiVec[i].extHName.c_str()))
3121 int XrdHttpProtocol::LoadExtHandler(std::vector<extHInfo> &hiVec,
3133 for (
int i = 0; i < (int)hiVec.size(); i++) {
3136 if(!ExtHandlerLoaded(hiVec[i].extHName.c_str())) {
3137 if (LoadExtHandler(&
eDest, hiVec[i].extHPath.c_str(), cFN,
3138 hiVec[i].extHParm.c_str(), &myEnv,
3139 hiVec[i].extHName.c_str()))
return 1;
3146 int XrdHttpProtocol::LoadExtHandler(
XrdSysError *myeDest,
const char *libName,
3147 const char *configFN,
const char *libParms,
3148 XrdOucEnv *myEnv,
const char *instName) {
3152 if (ExtHandlerLoaded(instName)) {
3153 eDest.
Emsg(
"Config",
"Instance name already present for an http external handler plugin.");
3157 eDest.
Emsg(
"Config",
"Cannot load one more exthandler. Max is 4");
3161 XrdOucPinLoader myLib(myeDest, &compiledVer,
"exthandlerlib", libName);
3169 if (ep && (newhandler = ep(myeDest, configFN, libParms, myEnv))) {
3172 strncpy( exthandler[exthandlercnt].name, instName, 16 );
3173 exthandler[exthandlercnt].name[15] =
'\0';
3174 exthandler[exthandlercnt++].ptr = newhandler;
3187 bool XrdHttpProtocol::ExtHandlerLoaded(
const char *handlername) {
3188 for (
int i = 0; i < exthandlercnt; i++) {
3189 if ( !strncmp(exthandler[i].name, handlername, 15) ) {
3200 for (
int i = 0; i < exthandlercnt; i++) {
3202 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,...)
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)
void SetTlsClientAuth(ClientAuthSetting setting)
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::vector< std::string > tlsAuthRequestPrefixes
XrdTlsContext::ClientAuthSetting tlsClientAuth
std::string cafile
-> ca cert file.
std::string cadir
-> ca cert directory.
int crlRT
crl refresh interval time in seconds
std::string pkey
-> private key path.
std::string cert
-> certificate path.