Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/adaptation/icap/ModXact.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1399,12 +1399,20 @@ void Adaptation::Icap::ModXact::makeRequestHeaders(MemBuf &buf)
String vh=virgin.header->header.getById(Http::HdrType::PROXY_AUTHORIZATION);
buf.appendf("Proxy-Authorization: " SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(vh));
} else if (request->extacl_user.size() > 0 && request->extacl_passwd.size() > 0) {
const auto userLen = request->extacl_user.size();
const auto passwdLen = request->extacl_passwd.size();
// +1 for the ':' separator between user and passwd
const auto plainLen = userLen + 1 + passwdLen;
if (plainLen > MAX_LOGIN_SZ)
throw TexcHere("extacl credentials too long for Proxy-Authorization");
Comment thread
rousskov marked this conversation as resolved.
Outdated
// plainLen <= MAX_LOGIN_SZ, so base64_encode_len(plainLen) fits
// within the base64_encode_len(MAX_LOGIN_SZ) stack buffer.
Comment on lines +1408 to +1409

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we need to add this comment -- this code is quite self-documenting/clear.

Suggested change
// plainLen <= MAX_LOGIN_SZ, so base64_encode_len(plainLen) fits
// within the base64_encode_len(MAX_LOGIN_SZ) stack buffer.

I do not insist on this change.

char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
Comment on lines +1406 to +1410

@yadij yadij Jun 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (plainLen > MAX_LOGIN_SZ)
throw TextException("extacl credentials too long for Proxy-Authorization", Here());
// plainLen <= MAX_LOGIN_SZ, so base64_encode_len(plainLen) fits
// within the base64_encode_len(MAX_LOGIN_SZ) stack buffer.
char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
SBuf encoded; // TODO: when 'buf' is an SBuf we can write directly to it.
auto base64buf = encoded.rawAppendStart(base64_encode_len(plainLen));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to be particularly pedantic, you can also verify that the final output will fit into the allocated MemBuf output parameter as well as within the temporary buffer allocation:

Suggested change
if (plainLen > MAX_LOGIN_SZ)
throw TextException("extacl credentials too long for Proxy-Authorization", Here());
// plainLen <= MAX_LOGIN_SZ, so base64_encode_len(plainLen) fits
// within the base64_encode_len(MAX_LOGIN_SZ) stack buffer.
char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
const auto expectedSize = base64_encode_len(plainLen)
+ 28 /* HTTP Syntax: "Proxy-Authorization: Basic " */
+ 30 /* HTTP Syntax: CRLF */;
Assure(buf.potentialSpaceSize() > expectedSize);
SBuf encoded; // TODO: when 'buf' is an SBuf we can write directly to it.
auto base64buf = encoded.rawAppendStart(base64_encode_len(plainLen));

That TODO could technically be implemented today with buf.rawSpace(). Provided its space was resized first to ensure the buffer existed before being passed to the encoder. Currently it may not exist and appendf() after encoder does any needed allocation as a repeat allocation. My suggested SBuf use avoids that extra code being part of this patch.

struct base64_encode_ctx ctx;
base64_encode_init(&ctx);
char base64buf[base64_encode_len(MAX_LOGIN_SZ)];
size_t resultLen = base64_encode_update(&ctx, base64buf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
auto resultLen = base64_encode_update(&ctx, base64buf, userLen, reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
resultLen += base64_encode_update(&ctx, base64buf+resultLen, 1, reinterpret_cast<const uint8_t*>(":"));
resultLen += base64_encode_update(&ctx, base64buf+resultLen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
resultLen += base64_encode_update(&ctx, base64buf+resultLen, passwdLen, reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
resultLen += base64_encode_final(&ctx, base64buf+resultLen);
buf.appendf("Proxy-Authorization: Basic %.*s\r\n", (int)resultLen, base64buf);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
buf.appendf("Proxy-Authorization: Basic %.*s\r\n", (int)resultLen, base64buf);
encoded.rawAppendFinish(base64buf, resultLen);
buf.appendf("Proxy-Authorization: Basic " SQUIDSBUFPH "\r\n", SQUIDSBUFPRINT(encoded));

}
Expand Down
22 changes: 17 additions & 5 deletions src/http.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,12 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
username = request->auth_user_request->username();
#endif

blen = base64_encode_update(&ctx, loginbuf, strlen(username), reinterpret_cast<const uint8_t*>(username));
blen += base64_encode_update(&ctx, loginbuf+blen, strlen(request->peer_login +1), reinterpret_cast<const uint8_t*>(request->peer_login +1));
const auto usernameLen = strlen(username);
const auto suffixLen = strlen(request->peer_login + 1);
if (usernameLen + suffixLen > MAX_LOGIN_SZ)
throw TexcHere("peer login credentials too long");
blen = base64_encode_update(&ctx, loginbuf, usernameLen, reinterpret_cast<const uint8_t*>(username));
blen += base64_encode_update(&ctx, loginbuf+blen, suffixLen, reinterpret_cast<const uint8_t*>(request->peer_login +1));
blen += base64_encode_final(&ctx, loginbuf+blen);
httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
return;
Expand All @@ -1862,9 +1866,14 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
(strcmp(request->peer_login, "PASS") == 0 ||
strcmp(request->peer_login, "PROXYPASS") == 0)) {

blen = base64_encode_update(&ctx, loginbuf, request->extacl_user.size(), reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
const auto userLen = request->extacl_user.size();
const auto passwdLen = request->extacl_passwd.size();
// +1 for the ':' separator between user and passwd
if (userLen + 1 + passwdLen > MAX_LOGIN_SZ)
throw TexcHere("extacl credentials too long for peer login");
blen = base64_encode_update(&ctx, loginbuf, userLen, reinterpret_cast<const uint8_t*>(request->extacl_user.rawBuf()));
blen += base64_encode_update(&ctx, loginbuf+blen, 1, reinterpret_cast<const uint8_t*>(":"));
blen += base64_encode_update(&ctx, loginbuf+blen, request->extacl_passwd.size(), reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
blen += base64_encode_update(&ctx, loginbuf+blen, passwdLen, reinterpret_cast<const uint8_t*>(request->extacl_passwd.rawBuf()));
blen += base64_encode_final(&ctx, loginbuf+blen);
httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);
return;
Expand Down Expand Up @@ -1894,7 +1903,10 @@ httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHe
}
#endif /* HAVE_KRB5 && HAVE_GSSAPI */

blen = base64_encode_update(&ctx, loginbuf, strlen(request->peer_login), reinterpret_cast<const uint8_t*>(request->peer_login));
const auto loginLen = strlen(request->peer_login);
if (loginLen > MAX_LOGIN_SZ)
throw TexcHere("peer_login too long");
blen = base64_encode_update(&ctx, loginbuf, loginLen, reinterpret_cast<const uint8_t*>(request->peer_login));
blen += base64_encode_final(&ctx, loginbuf+blen);
httpHeaderPutStrf(hdr_out, header, "Basic %.*s", (int)blen, loginbuf);

@rousskov rousskov Jun 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add Assure(request->url.userInfo().length() < MAX_URL*2) or a similar assertion to HttpStateData::httpBuildRequestHeader().

Please also adjust SSP_MakeChallenge() and peer_proxy_negotiate_auth() cases.

@yadij yadij Jun 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot, however those cases should be restricted by MAX_AUTHTOKEN_SZ which is the SSPI buffer size for encoded credential tokens.

So Assure(base64_encode_len(loginLen) <= MAX_AUTHTOKEN_LEN);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot, however those cases should be restricted by MAX_AUTHTOKEN_SZ which is the SSPI buffer size for encoded credential tokens.

I do not recommend changing the size of the existing assembly buffer in this PR. The current size is MAX_URL*2, not MAX_AUTHTOKEN_SZ (which is presumably a typo for MAX_AUTHTOKEN_LEN).

If you do increase that size despite my recommendation, please update or remove the corresponding "should be big enough for a single URI segment" comment as well: MAX_AUTHTOKEN_LEN is much bigger than MAX_URL or even MAX_URL*2, so the comment would become even more wrong/misleading (and you become responsible for updating or removing it if you change the size).

return;
Expand Down
Loading