From: Joshua Rogers Date: Sun, 19 Oct 2025 17:33:18 +0000 (+0000) Subject: Fix libntlmauth string parsing on big-endian machines (#2242) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=346ff7bbc7e89ff8abdbc80fb7a2e6638162e359;p=thirdparty%2Fsquid.git Fix libntlmauth string parsing on big-endian machines (#2242) Prevent off-by-one reads in ntlm_fetch_string(); clamp copies too. Convert flags with le32toh; validate lengths; ensure NUL-terminate. cast ntlm string characters to unsigned char explicitly. Return BlobError on oversized fields to avoid UB. Combined these changes affect Big-Endian CPU architectures which will fail to detect ASCII vs UTF encoding properly and produce invalid strings (including user/password to compare). --- diff --git a/lib/ntlmauth/ntlmauth.cc b/lib/ntlmauth/ntlmauth.cc index b5f5838eb3..4f194aa82e 100644 --- a/lib/ntlmauth/ntlmauth.cc +++ b/lib/ntlmauth/ntlmauth.cc @@ -142,9 +142,10 @@ ntlm_fetch_string(const ntlmhdr *packet, const int32_t packet_size, const strhdr /* ASCII/OEM string */ char *sc = rv.str; - for (; l>=0; ++sc, --l) { - if (*sc == '\0' || !xisprint(*sc)) { - fprintf(stderr, "ntlmssp: bad ascii: %04x\n", *sc); + for (; l>0; ++sc, --l) { + const auto c = static_cast(*sc); + if (c == '\0' || !xisprint(c)) { + fprintf(stderr, "ntlmssp: bad ascii: %04x\n", c); return rv; } ++rv.l; @@ -252,7 +253,7 @@ ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const return NtlmError::ProtocolError; } debug("ntlm_unpack_auth: size of %d\n", size); - debug("ntlm_unpack_auth: flg %08x\n", auth->flags); + debug("ntlm_unpack_auth: flg %08x\n", le32toh(auth->flags)); debug("ntlm_unpack_auth: lmr o(%d) l(%d)\n", le32toh(auth->lmresponse.offset), auth->lmresponse.len); debug("ntlm_unpack_auth: ntr o(%d) l(%d)\n", le32toh(auth->ntresponse.offset), auth->ntresponse.len); debug("ntlm_unpack_auth: dom o(%d) l(%d)\n", le32toh(auth->domain.offset), auth->domain.len); @@ -260,24 +261,30 @@ ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const debug("ntlm_unpack_auth: wst o(%d) l(%d)\n", le32toh(auth->workstation.offset), auth->workstation.len); debug("ntlm_unpack_auth: key o(%d) l(%d)\n", le32toh(auth->sessionkey.offset), auth->sessionkey.len); - rv = ntlm_fetch_string(&auth->hdr, size, &auth->domain, auth->flags); - if (rv.l > 0) { - memcpy(domain, rv.str, rv.l); - domain[rv.l] = '\0'; - debug("ntlm_unpack_auth: Domain '%s' (len=%d).\n", domain, rv.l); - } + rv = ntlm_fetch_string(&auth->hdr, size, &auth->domain, le32toh(auth->flags)); if (rv.l >= size) { debug("ntlm_unpack_auth: Domain length %d too big for %d byte packet.\n", rv.l, size); return NtlmError::BlobError; } - - rv = ntlm_fetch_string(&auth->hdr, size, &auth->user, auth->flags); if (rv.l > 0) { - memcpy(user, rv.str, rv.l); - user[rv.l] = '\0'; - debug("ntlm_unpack_auth: Username '%s' (len=%d).\n", user, rv.l); - } else + const size_t dcopy = rv.l > (NTLM_MAX_FIELD_LENGTH - 1) ? (NTLM_MAX_FIELD_LENGTH - 1) : static_cast(rv.l); + memcpy(domain, rv.str, dcopy); + domain[dcopy] = '\0'; + debug("ntlm_unpack_auth: Domain '%s' (len=%zu).\n", domain, dcopy); + } + + rv = ntlm_fetch_string(&auth->hdr, size, &auth->user, le32toh(auth->flags)); + if (rv.l <= 0) return NtlmError::LoginEror; + if (rv.l >= size) { + debug("ntlm_unpack_auth: Username length %d too big for %d byte packet.\n", rv.l, size); + return NtlmError::BlobError; + } + + const size_t ucopy = rv.l > (NTLM_MAX_FIELD_LENGTH - 1) ? (NTLM_MAX_FIELD_LENGTH - 1) : static_cast(rv.l); + memcpy(user, rv.str, ucopy); + user[ucopy] = '\0'; + debug("ntlm_unpack_auth: Username '%s' (len=%zu).\n", user, ucopy); return NtlmError::None; }