Squid Proxy Professional: fixes to Squid's Windows SSPI sign-on helpers.
Applies to Squid 7.8 (the same code is in upstream master as of 2026-11-02).

1. negotiate_sspi_auth: SEND/SEND2/SEND3 were two statements, and debug() is
   an if/else, so "} else SEND(\"BH can't obtain server blob\");" sent the BH
   line after every YR, successful ones included. Squid then read an
   unrequested reply, killed the helper mid-reservation and died on
   "assertion failed: auth/negotiate/UserRequest.cc:286". The macros are
   now single statements (do { } while (0)).
2. ntlm_sspi_auth: credentials[] was DNLEN+UNLEN+2 (273) bytes, but
   SSP_ValidateNTLMCredentials() strncpy()s SSP_MAX_CRED_LEN (848) bytes into
   it, overrunning the stack on every successful login. Now sized
   SSP_MAX_CRED_LEN + 1.
3. ntlm_sspi_auth: for a local call (client on the proxy machine) user and
   domain were never filled in, so the reply was user="\" and Squid logged
   the user as a double quote. They now come from the name Windows
   authenticated.
4. ntlm_sspi_auth: OK user="domain\user" lost its backslash, because Squid
   unescapes quoted values ("domainuser"). The backslash is now sent escaped.

--- a/src/auth/negotiate/SSPI/negotiate_sspi_auth.cc
+++ b/src/auth/negotiate/SSPI/negotiate_sspi_auth.cc
@@ -59,15 +59,16 @@
 int Negotiate_packet_debug_enabled = 0;
 static int have_serverblob;
 
-/* A couple of harmless helper macros */
-#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
+/* A couple of harmless helper macros. Each is one statement, so that an
+ * unbraced "else SEND(...)" sends the reply only on that branch. */
+#define SEND(X) do { debug("sending '%s' to squid\n",X); printf(X "\n"); } while (0)
 #ifdef __GNUC__
-#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#define SEND2(X,Y...) do { debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); } while (0)
+#define SEND3(X,Y...) do { debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); } while (0)
 #else
 /* no gcc, no debugging. varargs macros are a gcc extension */
-#define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
+#define SEND2(X,Y) do { debug("sending '" X "' to squid\n",Y); printf(X "\n",Y); } while (0)
+#define SEND3(X,Y,Z) do { debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z); } while (0)
 #endif
 
 /*
--- a/src/auth/ntlm/SSPI/ntlm_sspi_auth.cc
+++ b/src/auth/ntlm/SSPI/ntlm_sspi_auth.cc
@@ -173,7 +173,8 @@
 static NtlmError
 ntlm_check_auth(ntlm_authenticate * auth, char *user, char *domain, int auth_length)
 {
-    char credentials[DNLEN+UNLEN+2];    /* we can afford to waste */
+    /* SSP_ValidateNTLMCredentials() writes SSP_MAX_CRED_LEN bytes here */
+    char credentials[SSP_MAX_CRED_LEN + 1];
 
     user[0] = '\0';
     domain[0] = '\0';
@@ -198,7 +199,7 @@
         debug("checking local user\n");
     }
 
-    snprintf(credentials, DNLEN+UNLEN+2, "%s\\%s", domain, user);
+    snprintf(credentials, sizeof(credentials), "%s\\%s", domain, user);
 
     const auto rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials);
 
@@ -208,6 +209,20 @@
         return NtlmError::SspiError;
     }
 
+    if (NTLM_LocalCall) {
+        /* A local call carries no names in the packet; use the ones
+         * Windows authenticated ("DOMAIN\user") instead. */
+        const char *sep = strchr(credentials, '\\');
+        const size_t domainLen = sep ? static_cast<size_t>(sep - credentials) : 0;
+        if (!domainLen || domainLen > DNLEN || !sep[1] || strlen(sep + 1) > UNLEN) {
+            debug("Unexpected name '%s' for a local call. Returning no-auth\n", credentials);
+            return NtlmError::BadRequest;
+        }
+        xstrncpy(domain, credentials, domainLen + 1);
+        xstrncpy(user, sep + 1, UNLEN + 1);
+        debug("local call authenticated as domain: '%s', user: '%s'\n", domain, user);
+    }
+
     if (UseAllowedGroup) {
         if (!Valid_Group(credentials, NTAllowedGroup)) {
             debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup);
@@ -498,7 +513,9 @@
             /* let's lowercase them for our convenience */
             lc(domain);
             lc(user);
-            fprintf(stdout, "OK user=\"%s\\%s\"\n", domain, user);
+            /* Squid unescapes a quoted value, so the backslash between
+             * domain and user must be sent as "\\" to survive. */
+            fprintf(stdout, "OK user=\"%s\\\\%s\"\n", domain, user);
             return 1;
         }
         default:
