Bug Report: proxy_auth -i case-insensitive matching broken in Squid 6.x

Andre Bolinhas <[email protected]> Wed, 4 Mar 2026 22:44:04 +0000
Newsgroups gmane.comp.web.squid.general
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--===============6740450480782051361==
Content-Type: multipart/alternative;
 boundary="------------HdounchMQzQSYPHiu001XZWf"
Content-Language: pt_PT

This is a multi-part message in MIME format.
--------------HdounchMQzQSYPHiu001XZWf
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit


    Summary

The |proxy_auth -i| ACL (case-insensitive user matching) is broken in 
Squid 6.x. The |-i| flag causes entries to be lowercased during parse, 
but the internal set container retains a case-sensitive comparator, so 
lookups with mixed-case usernames always fail. |proxy_auth_regex -i| and 
|proxy_auth| (without |-i|) work correctly.


    Squid Version

  * *Affected*: Squid 6.14-VCS (likely all Squid 6.x versions)
  * *Working*: Squid 5.x (tested, |-i| works correctly)


    Operating System

  * Debian-based Linux (Artica Proxy appliance)


    Steps to Reproduce

 1.

    Configure a negotiate (SPNEGO/NTLM) authentication helper that
    returns usernames in mixed case (e.g., |DOMAIN/Username|)

 2.

    Create an ACL user list file |/etc/squid3/acls/userlist.txt|:

    |DOMAIN/username DOMAIN/Username |

 3.

    Configure |proxy_auth -i| ACL:

    |acl BlockedUsers proxy_auth -i "/etc/squid3/acls/userlist.txt"
    http_access deny BlockedUsers |

 4.

    Authenticate via negotiate helper. The helper returns: |AF
    oQcwBaADCgEA DOMAIN/Username|

 5.

    *Expected*: |proxy_auth -i| matches |DOMAIN/Username| against
    |domain/username| (case-insensitive) → access denied

 6.

    *Actual*: |proxy_auth -i| does NOT match → access allowed


    Workarounds

Any of these work:

  * Use |proxy_auth| *without* |-i|, ensuring the ACL file contains
    usernames in the exact case returned by the helper
  * Use |proxy_auth_regex -i| instead (regex matching handles
    case-insensitivity correctly)


    Root Cause Analysis

The bug is in |src/acl/UserData.cc|. In Squid 6.x, the |-i| flag was 
refactored into an ACL “line option” (handled by 
|lineOptions()|/|Acl::BooleanOptionValue|). The |-i| token is consumed 
by the line options parser *before* |parse()| is called. However, the 
|parse()| function only recreates the internal |std::set| with a 
case-insensitive comparator when it sees |-i| as a *token* — which never 
happens in Squid 6.x because the token was already consumed.


      Code trace in |UserData.cc|:

*Constructor* — set defaults to case-sensitive:

|ACLUserData::ACLUserData() : userDataNames(CaseSensitiveSBufCompare) // 
case-SENSITIVE by default { ... } |

*parse()* — the set is never recreated:

|void ACLUserData::parse() { // Step 1: flag is set correctly from the 
line option flags.case_insensitive = bool(CaseInsensitive_); // TRUE 
(from -i line option) char *t = nullptr; if ((t = 
ConfigParser::strtokFile())) { SBuf s(t); // Step 2: this check NEVER 
matches in Squid 6.x because // "-i" was already consumed by the line 
options parser if (s.cmp("-i",2) == 0) { flags.case_insensitive = true; 
// THIS BLOCK NEVER EXECUTES — the set is never recreated 
UserDataNames_t newUdn(CaseInsensitveSBufCompare); 
newUdn.insert(userDataNames.begin(), userDataNames.end()); 
swap(userDataNames, newUdn); } else { // Step 3: entries ARE correctly 
lowercased... if (flags.case_insensitive) s.toLower(); // ...but 
inserted into a case-SENSITIVE set! userDataNames.insert(s); } } // ... 
(remaining entries also lowercased and inserted into case-sensitive set) } |

*match()* — lookup uses case-sensitive comparison on lowercase entries:

|bool ACLUserData::match(char const *user) { // user = "DOMAIN/Username" 
(original case from auth helper) // userDataNames contains 
"domain/username" (lowercased during parse) // userDataNames comparator 
= CaseSensitiveSBufCompare (never changed!) bool result = 
(userDataNames.find(SBuf(user)) != userDataNames.end()); // 
find("DOMAIN/Username") in set{"domain/username"} with CASE-SENSITIVE 
compare // → NOT FOUND (because "DOMAIN/Username" != "domain/username") 
return result; // returns false — BUG } |


      In Squid 5.x (working correctly):

In Squid 5.x, |-i| was passed through to |parse()| as a regular token. 
So the |if (s.cmp("-i",2) == 0)| block DID execute, and the set was 
properly recreated with |CaseInsensitveSBufCompare|. The 
case-insensitive comparator made |find()| work regardless of case.

In Squid 6.x, |-i| was refactored into a generic ACL “line option” — it 
is now consumed by the line options parser *before* |parse()| is called. 
The flag value is correctly propagated to |CaseInsensitive_| (and then 
to |flags.case_insensitive|), and entries are correctly lowercased 
during insertion. However, the set comparator is never switched from 
case-sensitive to case-insensitive because the code path that does this 
(|if (s.cmp("-i",2) == 0)|) is never reached.


    Debug Evidence


      Squid 6.14-VCS debug output (|debug_options ALL,1 28,9 29,9 84,9|):

*ACL parsing* — entries correctly lowercased, 2 unique users:

|UserData.cc(93) parse: parsing user list UserData.cc(99) parse: first 
token is CHILD01/administrator UserData.cc(116) parse: Adding user 
child01/administrator UserData.cc(121) parse: Case-insensitive-switch is 
1 UserData.cc(124) parse: parsing following tokens UserData.cc(128) 
parse: Got token: [email protected] UserData.cc(133) parse: 
Adding user [email protected] UserData.cc(128) parse: Got 
token: [email protected] UserData.cc(133) parse: Adding user 
[email protected] UserData.cc(128) parse: Got token: 
CHILD01/Administrator UserData.cc(133) parse: Adding user 
child01/administrator UserData.cc(142) parse: ACL contains 2 users |

*Helper response* — username correctly extracted:

|helper.cc(1122) helperStatefulHandleRead: accumulated[38]=AF 
oQcwBaADCgEA CHILD01/Administrator Reply.cc(43) finalize: Parsing helper 
buffer UserRequest.cc(267) HandleReply: got reply={result=OK, 
notes={token: oQcwBaADCgEA; user: CHILD01/Administrator; }} 
UserRequest.cc(338) HandleReply: authenticated user 
CHILD01/Administrator UserRequest.cc(357) HandleReply: Successfully 
validated user via Negotiate. Username 'CHILD01/Administrator' |

*Match with |-i| — FAILS (BUG):*

|UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive 
is 1 UserData.cc(37) match: returning 0 |

*Match without |-i| — WORKS (proves the issue is with |-i|):*

|UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive 
is 0 UserData.cc(37) match: returning 1 |


    Proof of Concept — Full Debug Session

Below is the complete step-by-step debug session performed on a live 
Squid 6.14-VCS instance
to isolate and confirm the bug.


      Environment

  * *Squid server*: 192.168.60.58, Squid 6.14-VCS on Debian-based Linux
    (Artica Proxy)
  * *Client machine*: 192.168.60.31, Windows 10 domain-joined to
    |CHILD01| (child domain of |ARTICATECH|)
  * *Authentication*: Negotiate (SPNEGO with NTLM fallback) via external
    helper
  * *Auth helper*: Returns |AF <blob> CHILD01/Administrator| on
    successful authenticate


      Step 1 — Baseline configuration (broken)

ACL user list file (|/etc/squid3/acls/container_963.1.txt|):

|CHILD01/administrator [email protected] 
[email protected] CHILD01/Administrator |

File verified clean with |xxd| — Unix line endings (0x0A), no BOM, no 
hidden characters:

|00000000: 4348 494c 4430 312f 6164 6d69 6e69 7374 CHILD01/administ 
00000010: 7261 746f 720a 6164 6d69 6e69 7374 7261 rator.administra 
00000020: 746f 7240 6162 6f6c 696e 6861 732e 6c61 [email protected] 
00000030: 620a 4164 6d69 6e69 7374 7261 746f 7240 b.Administrator@ 
00000040: 6162 6f6c 696e 6861 732e 6c61 620a 4348 abolinhas.lab.CH 
00000050: 494c 4430 312f 4164 6d69 6e69 7374 7261 ILD01/Administra 
00000060: 746f 720a tor. |

squid.conf ACL (in |/etc/squid3/http_access.conf|):

|acl AnnotateRule587 annotate_transaction accessrule=Rule587 acl 
Group953 proxy_auth -i "/etc/squid3/acls/container_963.1.txt" 
http_access deny Group953 AnnotateRule587 all |


      Step 2 — Enable debug logging

|# Set debug options in /etc/squid3/logging.conf debug_options ALL,1 
28,9 29,9 84,9 # Section 28 = Access Control (ACL matching, UserData) # 
Section 29 = Authenticator (negotiate helper handling) # Section 84 = 
Helper I/O (helper stdin/stdout) squid -k reconfigure |


      Step 3 — Observe ACL parsing (cache.log)

Squid parses the ACL file with |-i| enabled. Entries are lowercased 
during insertion.
After case-insensitive deduplication, the ACL contains 2 unique users:

|2026/03/04 18:23:57.734 kid1| 28,2| UserData.cc(93) parse: parsing user 
list 2026/03/04 18:23:57.734 kid1| 28,5| UserData.cc(99) parse: first 
token is CHILD01/administrator 2026/03/04 18:23:57.734 kid1| 28,6| 
UserData.cc(116) parse: Adding user child01/administrator 2026/03/04 
18:23:57.734 kid1| 28,3| UserData.cc(121) parse: Case-insensitive-switch 
is 1 2026/03/04 18:23:57.734 kid1| 28,4| UserData.cc(124) parse: parsing 
following tokens 2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(128) 
parse: Got token: [email protected] 2026/03/04 18:23:57.734 
kid1| 28,6| UserData.cc(133) parse: Adding user 
[email protected] 2026/03/04 18:23:57.734 kid1| 28,6| 
UserData.cc(128) parse: Got token: [email protected] 
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(133) parse: Adding user 
[email protected] 2026/03/04 18:23:57.734 kid1| 28,6| 
UserData.cc(128) parse: Got token: CHILD01/Administrator 2026/03/04 
18:23:57.734 kid1| 28,6| UserData.cc(133) parse: Adding user 
child01/administrator 2026/03/04 18:23:57.734 kid1| 28,4| 
UserData.cc(142) parse: ACL contains 2 users |

Observation: |Case-insensitive-switch is 1| (flag is set correctly), 
entries are lowercased
(|child01/administrator|, |[email protected]|). Parsing looks 
correct.


      Step 4 — Client authenticates via Negotiate (NTLM-in-SPNEGO)

Client on 192.168.60.31 sends CONNECT through the proxy. The negotiate 
helper performs
two-step NTLM-in-SPNEGO authentication:

*Step 4a — NTLM Type 2 challenge (TT response):*
```
2026/03/04 18:29:02.696 kid1| 84,5| helper.cc(1112) 
helperStatefulHandleRead: helperStatefulHandleRead: 376 bytes from 
negotiateauthenticator #Hlpr91
2026/03/04 18:29:02.696 kid1| 84,3| Reply.cc(43) finalize: Parsing 
helper buffer
2026/03/04 18:29:02.696 kid1| 29,8| UserRequest.cc(267) HandleReply: 
hlpRes693 got reply={result=TT, notes={token: TlRMTVNTUA…AAAA=; }}
2026/03/04 18:29:02.696 kid1| 29,4| UserRequest.cc(313) HandleReply: 
Need to challenge the client with a server token

|**Step 4b — NTLM Type 3 validation (AF response):** |

2026/03/04 18:29:02.724 kid1| 84,9| helper.cc(1447) 
helperStatefulDispatch: helperStatefulDispatch busying helper 
negotiateauthenticator #Hlpr91
2026/03/04 18:29:02.724 kid1| 84,5| helper.cc(1476) 
helperStatefulDispatch: helperStatefulDispatch: Request sent to 
negotiateauthenticator #Hlpr91, 764 bytes
2026/03/04 18:29:02.731 kid1| 84,5| helper.cc(1112) 
helperStatefulHandleRead: helperStatefulHandleRead: 38 bytes from 
negotiateauthenticator #Hlpr91
2026/03/04 18:29:02.732 kid1| 84,9| helper.cc(1122) 
helperStatefulHandleRead: accumulated[38]=AF oQcwBaADCgEA 
CHILD01/Administrator
2026/03/04 18:29:02.732 kid1| 84,3| helper.cc(1134) 
helperStatefulHandleRead: helperStatefulHandleRead: end of reply found
2026/03/04 18:29:02.732 kid1| 84,3| Reply.cc(43) finalize: Parsing 
helper buffer
2026/03/04 18:29:02.732 kid1| 84,3| Reply.cc(61) finalize: Buff length 
is larger than 2
2026/03/04 18:29:02.732 kid1| 29,8| UserRequest.cc(267) HandleReply: 
hlpRes693 got reply={result=OK, notes={token: oQcwBaADCgEA; user: 
CHILD01/Administrator; }}
2026/03/04 18:29:02.732 kid1| 29,4| UserRequest.cc(338) HandleReply: 
authenticated user CHILD01/Administrator
2026/03/04 18:29:02.732 kid1| 29,4| UserRequest.cc(357) HandleReply: 
Successfully validated user via Negotiate. Username ‘CHILD01/Administrator’

|Observation: The helper returns exactly `AF oQcwBaADCgEA 
CHILD01/Administrator` (38 bytes including newline). Squid correctly 
parses the reply, extracts the token and username. The authenticated 
username is set to `CHILD01/Administrator`. ### Step 5 — ACL match with 
`-i` FAILS (the bug) When Squid evaluates `http_access deny Group953`, 
it checks the `proxy_auth -i` ACL: |

2026/03/04 18:27:58.119 kid1| 28,7| UserData.cc(26) match: user is 
CHILD01/Administrator, case_insensitive is 1
2026/03/04 18:27:58.119 kid1| 28,7| UserData.cc(37) match: returning 0

|**Result: `returning 0` — NO MATCH.** The ACL check for Group953 
returns 0 (no match), so the deny rule does not trigger. Access is 
allowed through the final allow rule: |

2026/03/04 18:29:02.732 kid1| 28,5| Acl.cc(145) matches: checking Group953
2026/03/04 18:29:02.732 kid1| 28,3| Acl.cc(172) matches: checked: 
Group953 = 0

|Access log confirms user is NOT denied (note `accessrule: final_allow`): |

1772648820.870 75169 192.168.60.31 TCP_TUNNEL/200 5123 CONNECT 
sapo.pt:443 CHILD01/Administrator HIER_DIRECT/213.13.145.114:443 - 
accessrule:%20final_allow

|### Step 6 — Remove `-i` flag, ACL match SUCCEEDS Changed the ACL 
definition to remove the `-i` flag: ```bash # Before: acl Group953 
proxy_auth -i "/etc/squid3/acls/container_963.1.txt" # After: acl 
Group953 proxy_auth "/etc/squid3/acls/container_963.1.txt" squid -k 
reconfigure |

After the next authentication from the same client:

|2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(26) match: user is 
CHILD01/Administrator, case_insensitive is 0 2026/03/04 18:34:11.740 
kid1| 28,7| UserData.cc(37) match: returning 1 |

*Result: |returning 1| — MATCH!*

Without |-i|, entries are stored in original case from the file. The 
file contains
|CHILD01/Administrator| (line 4) which exactly matches the helper’s 
username. The deny
rule triggers.

Access log confirms user IS now denied (note |accessrule: Rule587| and 
|ERR_ACCESS_DENIED|):

|1772649291.245 12 192.168.60.31 TCP_DENIED/200 0 CONNECT 
static.foxnews.com:443 CHILD01/Administrator HIER_NONE/-:- - 
accessrule:%20Rule587 ERR_ACCESS_DENIED 1772649291.188 2 192.168.60.31 
NONE_NONE_ABORTED/403 65843 GET 
https://static.foxnews.com/.../favicon-96x96.png CHILD01/Administrator 
HIER_NONE/-:- text/html ERR_ACCESS_DENIED |


      Step 7 — Additional confirmation: |proxy_auth_regex -i| also works

Changing the ACL to use |proxy_auth_regex -i| with the same file:

|acl Group953 proxy_auth_regex -i "/etc/squid3/acls/container_963.1.txt" |

This also correctly matches and denies the user. |proxy_auth_regex| is 
unaffected
because it uses |ACLRegexData| (regex matching) instead of |ACLUserData| 
(set-based matching).


      Step 8 — Downgrade to Squid 5.x confirms fix

After downgrading from Squid 6.14-VCS to Squid 5.x on the same machine, 
the original
configuration with |proxy_auth -i| works correctly — the deny rule 
matches and blocks
the user as expected.

|acl Group953 proxy_auth -i "/etc/squid3/acls/container_963.1.txt" squid 
-k reconfigure |

After the next authentication from the same client:

|2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(26) match: user is 
CHILD01/Administrator, case_insensitive is 1 2026/03/04 18:34:11.740 
kid1| 28,7| UserData.cc(37) match: returning 1 |

*Result: |returning 1| — MATCH!*

On Squd5.X With |-i|, entries are stored in original case from the file. 
The file contains
|CHILD01/Administrator| (line 4) which exactly matches the helper’s 
username. The deny
rule triggers.

Access log confirms user IS now denied (note |accessrule: Rule587| and 
|ERR_ACCESS_DENIED|):

|1772649291.245 12 192.168.60.31 TCP_DENIED/200 0 CONNECT 
static.foxnews.com:443 CHILD01/Administrator HIER_NONE/-:- - 
accessrule:%20Rule587 ERR_ACCESS_DENIED 1772649291.188 2 192.168.60.31 
NONE_NONE_ABORTED/403 65843 GET 
https://static.foxnews.com/.../favicon-96x96.png CHILD01/Administrator 
HIER_NONE/-:- text/html ERR_ACCESS_DENIED |


      PoC Summary Table

Configuration 	Squid 6.14-VCS 	Squid 5.x
|proxy_auth -i| (file) 	BROKEN 	Works
|proxy_auth| (no |-i|, file) 	Works 	Works
|proxy_auth_regex -i| (file) 	Works 	Works


    Suggested Fix

Either of these approaches would fix the bug:


      Option A: Recreate the set when |CaseInsensitive_| is set (in
      |parse()|)

Add set recreation at the beginning of |parse()| when the flag comes 
from the line option:

|void ACLUserData::parse() { flags.case_insensitive = 
bool(CaseInsensitive_); // If case-insensitive was set via line option, 
ensure the set // uses the case-insensitive comparator if 
(flags.case_insensitive) { UserDataNames_t 
newUdn(CaseInsensitveSBufCompare); newUdn.insert(userDataNames.begin(), 
userDataNames.end()); std::swap(userDataNames, newUdn); } // ... rest of 
parse() unchanged } |


      Option B: Lowercase the search key in |match()|

|bool ACLUserData::match(char const *user) { debugs(28, 7, "user is " << 
user << ", case_insensitive is " << flags.case_insensitive); if (user == 
nullptr || strcmp(user, "-") == 0) return 0; if (flags.required) { 
debugs(28, 7, "aclMatchUser: user REQUIRED and auth-info present."); 
return 1; } SBuf key(user); if (flags.case_insensitive) key.toLower(); 
bool result = (userDataNames.find(key) != userDataNames.end()); 
debugs(28, 7, "returning " << result); return result; } |

Option A is more correct because it also fixes the set comparator for 
any future operations. Option B is simpler but relies on both sides 
being lowercased rather than using a proper case-insensitive comparator.


    Configuration Context

This was observed with a negotiate (SPNEGO/Kerberos with NTLM fallback) 
authentication helper. The helper returns usernames in mixed case as 
received from Active Directory SSPI (e.g., |DOMAIN/Username|). The 
|proxy_auth -i| ACL should match these usernames case-insensitively 
against the ACL file entries, but fails to do so in Squid 6.x.

|auth_param negotiate program /path/to/negotiate-helper acl BlockedUsers 
proxy_auth -i "/path/to/userlist.txt" http_access deny BlockedUsers |

--------------HdounchMQzQSYPHiu001XZWf
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit

<!DOCTYPE html>
<html data-lt-installed="true">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body style="padding-bottom: 1px;">
    <div class="markdown-here-wrapper">
      <h2>Summary</h2>
      <p>The <code>proxy_auth -i</code> ACL (case-insensitive user
        matching) is broken in Squid 6.x. The <code>-i</code> flag
        causes entries to be lowercased during parse, but the internal
        set container retains a case-sensitive comparator, so lookups
        with mixed-case usernames always fail. <code>proxy_auth_regex
          -i</code> and <code>proxy_auth</code> (without <code>-i</code>)
        work correctly.</p>
      <h2>Squid Version</h2>
      <ul>
        <li><strong>Affected</strong>: Squid 6.14-VCS (likely all Squid
          6.x versions)</li>
        <li><strong>Working</strong>: Squid 5.x (tested, <code>-i</code>
          works correctly)</li>
      </ul>
      <h2>Operating System</h2>
      <ul>
        <li>Debian-based Linux (Artica Proxy appliance)</li>
      </ul>
      <h2>Steps to Reproduce</h2>
      <ol>
        <li>
          <p>Configure a negotiate (SPNEGO/NTLM) authentication helper
            that returns usernames in mixed case (e.g., <code>DOMAIN/Username</code>)</p>
        </li>
        <li>
          <p>Create an ACL user list file <code>/etc/squid3/acls/userlist.txt</code>:</p>
          <pre><code>DOMAIN/username
DOMAIN/Username
</code></pre>
        </li>
        <li>
          <p>Configure <code>proxy_auth -i</code> ACL:</p>
          <pre><code>acl BlockedUsers proxy_auth -i "/etc/squid3/acls/userlist.txt"
http_access deny BlockedUsers
</code></pre>
        </li>
        <li>
          <p>Authenticate via negotiate helper. The helper returns: <code>AF
              oQcwBaADCgEA DOMAIN/Username</code></p>
        </li>
        <li>
          <p><strong>Expected</strong>: <code>proxy_auth -i</code>
            matches <code>DOMAIN/Username</code> against <code>domain/username</code>
            (case-insensitive) → access denied</p>
        </li>
        <li>
          <p><strong>Actual</strong>: <code>proxy_auth -i</code> does
            NOT match → access allowed</p>
        </li>
      </ol>
      <h2>Workarounds</h2>
      <p>Any of these work:</p>
      <ul>
        <li>Use <code>proxy_auth</code> <strong>without</strong> <code>-i</code>,
          ensuring the ACL file contains usernames in the exact case
          returned by the helper</li>
        <li>Use <code>proxy_auth_regex -i</code> instead (regex
          matching handles case-insensitivity correctly)</li>
      </ul>
      <h2>Root Cause Analysis</h2>
      <p>The bug is in <code>src/acl/UserData.cc</code>. In Squid 6.x,
        the <code>-i</code> flag was refactored into an ACL “line
        option” (handled by <code>lineOptions()</code>/<code>Acl::BooleanOptionValue</code>).
        The <code>-i</code> token is consumed by the line options
        parser <strong>before</strong> <code>parse()</code> is called.
        However, the <code>parse()</code> function only recreates the
        internal <code>std::set</code> with a case-insensitive
        comparator when it sees <code>-i</code> as a <strong>token</strong>
        — which never happens in Squid 6.x because the token was already
        consumed.</p>
      <h3>Code trace in <code>UserData.cc</code>:</h3>
      <p><strong>Constructor</strong> — set defaults to case-sensitive:</p>
      <pre><code class="hljs language-cpp">ACLUserData::<span
      class="hljs-built_in">ACLUserData</span>() :
    <span class="hljs-built_in">userDataNames</span>(CaseSensitiveSBufCompare)  <span
      class="hljs-comment">// case-SENSITIVE by default</span>
{ ... }
</code></pre>
      <p><strong>parse()</strong> — the set is never recreated:</p>
      <pre><code class="hljs language-cpp"><span class="hljs-function"><span
      class="hljs-type">void</span> <span class="hljs-title">ACLUserData::parse</span><span
      class="hljs-params">()</span>
</span>{
    <span class="hljs-comment">// Step 1: flag is set correctly from the line option</span>
    flags.case_insensitive = <span class="hljs-built_in">bool</span>(CaseInsensitive_);  <span
      class="hljs-comment">// TRUE (from -i line option)</span>

    <span class="hljs-type">char</span> *t = <span class="hljs-literal">nullptr</span>;
    <span class="hljs-keyword">if</span> ((t = ConfigParser::<span
      class="hljs-built_in">strtokFile</span>())) {
        <span class="hljs-function">SBuf <span class="hljs-title">s</span><span
      class="hljs-params">(t)</span></span>;

        <span class="hljs-comment">// Step 2: this check NEVER matches in Squid 6.x because</span>
        <span class="hljs-comment">//         "-i" was already consumed by the line options parser</span>
        <span class="hljs-keyword">if</span> (s.<span
      class="hljs-built_in">cmp</span>(<span class="hljs-string">"-i"</span>,<span
      class="hljs-number">2</span>) == <span class="hljs-number">0</span>) {
            flags.case_insensitive = <span class="hljs-literal">true</span>;
            <span class="hljs-comment">// THIS BLOCK NEVER EXECUTES — the set is never recreated</span>
            <span class="hljs-function">UserDataNames_t <span
      class="hljs-title">newUdn</span><span class="hljs-params">(CaseInsensitveSBufCompare)</span></span>;
            newUdn.<span class="hljs-built_in">insert</span>(userDataNames.<span
      class="hljs-built_in">begin</span>(), userDataNames.<span
      class="hljs-built_in">end</span>());
            <span class="hljs-built_in">swap</span>(userDataNames, newUdn);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Step 3: entries ARE correctly lowercased...</span>
            <span class="hljs-keyword">if</span> (flags.case_insensitive)
                s.<span class="hljs-built_in">toLower</span>();
            <span class="hljs-comment">// ...but inserted into a case-SENSITIVE set!</span>
            userDataNames.<span class="hljs-built_in">insert</span>(s);
        }
    }
    <span class="hljs-comment">// ... (remaining entries also lowercased and inserted into case-sensitive set)</span>
}
</code></pre>
      <p><strong>match()</strong> — lookup uses case-sensitive
        comparison on lowercase entries:</p>
      <pre><code class="hljs language-cpp"><span class="hljs-function"><span
      class="hljs-type">bool</span> <span class="hljs-title">ACLUserData::match</span><span
      class="hljs-params">(<span class="hljs-type">char</span> <span
      class="hljs-type">const</span> *user)</span>
</span>{
    <span class="hljs-comment">// user = "DOMAIN/Username" (original case from auth helper)</span>
    <span class="hljs-comment">// userDataNames contains "domain/username" (lowercased during parse)</span>
    <span class="hljs-comment">// userDataNames comparator = CaseSensitiveSBufCompare (never changed!)</span>

    <span class="hljs-type">bool</span> result = (userDataNames.<span
      class="hljs-built_in">find</span>(<span class="hljs-built_in">SBuf</span>(user)) != userDataNames.<span
      class="hljs-built_in">end</span>());
    <span class="hljs-comment">// find("DOMAIN/Username") in set{"domain/username"} with CASE-SENSITIVE compare</span>
    <span class="hljs-comment">// → NOT FOUND (because "DOMAIN/Username" != "domain/username")</span>

    <span class="hljs-keyword">return</span> result;  <span
      class="hljs-comment">// returns false — BUG</span>
}
</code></pre>
      <h3>In Squid 5.x (working correctly):</h3>
      <p>In Squid 5.x, <code>-i</code> was passed through to <code>parse()</code>
        as a regular token. So the <code>if (s.cmp("-i",2) == 0)</code>
        block DID execute, and the set was properly recreated with <code>CaseInsensitveSBufCompare</code>.
        The case-insensitive comparator made <code>find()</code> work
        regardless of case.</p>
      <p>In Squid 6.x, <code>-i</code> was refactored into a generic
        ACL “line option” — it is now consumed by the line options
        parser <strong>before</strong> <code>parse()</code> is called.
        The flag value is correctly propagated to <code>CaseInsensitive_</code>
        (and then to <code>flags.case_insensitive</code>), and entries
        are correctly lowercased during insertion. However, the set
        comparator is never switched from case-sensitive to
        case-insensitive because the code path that does this (<code>if
          (s.cmp("-i",2) == 0)</code>) is never reached.</p>
      <h2>Debug Evidence</h2>
      <h3>Squid 6.14-VCS debug output (<code>debug_options ALL,1 28,9
          29,9 84,9</code>):</h3>
      <p><strong>ACL parsing</strong> — entries correctly lowercased, 2
        unique users:</p>
      <pre><code>UserData.cc(93)  parse: parsing user list
UserData.cc(99)  parse: first token is CHILD01/administrator
UserData.cc(116) parse: Adding user child01/administrator
UserData.cc(121) parse: Case-insensitive-switch is 1
UserData.cc(124) parse: parsing following tokens
UserData.cc(128) parse: Got token: <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
UserData.cc(133) parse: Adding user <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
UserData.cc(128) parse: Got token: <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
UserData.cc(133) parse: Adding user <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
UserData.cc(128) parse: Got token: CHILD01/Administrator
UserData.cc(133) parse: Adding user child01/administrator
UserData.cc(142) parse: ACL contains 2 users
</code></pre>
      <p><strong>Helper response</strong> — username correctly
        extracted:</p>
      <pre><code>helper.cc(1122)      helperStatefulHandleRead: accumulated[38]=AF oQcwBaADCgEA CHILD01/Administrator
Reply.cc(43)         finalize: Parsing helper buffer
UserRequest.cc(267)  HandleReply: got reply={result=OK, notes={token: oQcwBaADCgEA; user: CHILD01/Administrator; }}
UserRequest.cc(338)  HandleReply: authenticated user CHILD01/Administrator
UserRequest.cc(357)  HandleReply: Successfully validated user via Negotiate. Username 'CHILD01/Administrator'
</code></pre>
      <p><strong>Match with <code>-i</code> — FAILS (BUG):</strong></p>
      <pre><code>UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive is 1
UserData.cc(37) match: returning 0
</code></pre>
      <p><strong>Match without <code>-i</code> — WORKS (proves the
          issue is with <code>-i</code>):</strong></p>
      <pre><code>UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive is 0
UserData.cc(37) match: returning 1
</code></pre>
      <h2>Proof of Concept — Full Debug Session</h2>
      <p>Below is the complete step-by-step debug session performed on a
        live Squid 6.14-VCS instance<br>
        to isolate and confirm the bug.</p>
      <h3>Environment</h3>
      <ul>
        <li><strong>Squid server</strong>: 192.168.60.58, Squid 6.14-VCS
          on Debian-based Linux (Artica Proxy)</li>
        <li><strong>Client machine</strong>: 192.168.60.31, Windows 10
          domain-joined to <code>CHILD01</code> (child domain of <code>ARTICATECH</code>)</li>
        <li><strong>Authentication</strong>: Negotiate (SPNEGO with NTLM
          fallback) via external helper</li>
        <li><strong>Auth helper</strong>: Returns <code>AF &lt;blob&gt;
            CHILD01/Administrator</code> on successful authenticate</li>
      </ul>
      <h3>Step 1 — Baseline configuration (broken)</h3>
      <p>ACL user list file (<code>/etc/squid3/acls/container_963.1.txt</code>):</p>
      <pre><code>CHILD01/administrator
<a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
<a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
CHILD01/Administrator
</code></pre>
      <p>File verified clean with <code>xxd</code> — Unix line endings
        (0x0A), no BOM, no hidden characters:</p>
      <pre><code>00000000: 4348 494c 4430 312f 6164 6d69 6e69 7374  CHILD01/administ
00000010: 7261 746f 720a 6164 6d69 6e69 7374 7261  rator.administra
00000020: 746f 7240 6162 6f6c 696e 6861 732e 6c61  <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
00000030: 620a 4164 6d69 6e69 7374 7261 746f 7240  b.Administrator@
00000040: 6162 6f6c 696e 6861 732e 6c61 620a 4348  abolinhas.lab.CH
00000050: 494c 4430 312f 4164 6d69 6e69 7374 7261  ILD01/Administra
00000060: 746f 720a                                tor.
</code></pre>
      <p>squid.conf ACL (in <code>/etc/squid3/http_access.conf</code>):</p>
      <pre><code>acl AnnotateRule587 annotate_transaction accessrule=Rule587
acl Group953 proxy_auth  -i "/etc/squid3/acls/container_963.1.txt"
http_access deny Group953 AnnotateRule587 all
</code></pre>
      <h3>Step 2 — Enable debug logging</h3>
      <pre><code class="hljs language-bash"><span class="hljs-comment"># Set debug options in /etc/squid3/logging.conf</span>
debug_options ALL,1 28,9 29,9 84,9
<span class="hljs-comment"># Section 28 = Access Control (ACL matching, UserData)</span>
<span class="hljs-comment"># Section 29 = Authenticator (negotiate helper handling)</span>
<span class="hljs-comment"># Section 84 = Helper I/O (helper stdin/stdout)</span>

squid -k reconfigure
</code></pre>
      <h3>Step 3 — Observe ACL parsing (cache.log)</h3>
      <p>Squid parses the ACL file with <code>-i</code> enabled.
        Entries are lowercased during insertion.<br>
        After case-insensitive deduplication, the ACL contains 2 unique
        users:</p>
      <pre><code>2026/03/04 18:23:57.734 kid1| 28,2| UserData.cc(93)  parse: parsing user list
2026/03/04 18:23:57.734 kid1| 28,5| UserData.cc(99)  parse: first token is CHILD01/administrator
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(116) parse: Adding user child01/administrator
2026/03/04 18:23:57.734 kid1| 28,3| UserData.cc(121) parse: Case-insensitive-switch is 1
2026/03/04 18:23:57.734 kid1| 28,4| UserData.cc(124) parse: parsing following tokens
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(128) parse: Got token: <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(133) parse: Adding user <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(128) parse: Got token: <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(133) parse: Adding user <a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a>
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(128) parse: Got token: CHILD01/Administrator
2026/03/04 18:23:57.734 kid1| 28,6| UserData.cc(133) parse: Adding user child01/administrator
2026/03/04 18:23:57.734 kid1| 28,4| UserData.cc(142) parse: ACL contains 2 users
</code></pre>
      <p>Observation: <code>Case-insensitive-switch is 1</code> (flag
        is set correctly), entries are lowercased<br>
        (<code>child01/administrator</code>, <code><a class="moz-txt-link-abbreviated" href="mailto:[email protected]">[email protected]</a></code>).
        Parsing looks correct.</p>
      <h3>Step 4 — Client authenticates via Negotiate (NTLM-in-SPNEGO)</h3>
      <p>Client on 192.168.60.31 sends CONNECT through the proxy. The
        negotiate helper performs<br>
        two-step NTLM-in-SPNEGO authentication:</p>
      <p><strong>Step 4a — NTLM Type 2 challenge (TT response):</strong><br>
        ```<br>
        2026/03/04 18:29:02.696 kid1| 84,5| helper.cc(1112)
        helperStatefulHandleRead: helperStatefulHandleRead: 376 bytes
        from negotiateauthenticator #Hlpr91<br>
        2026/03/04 18:29:02.696 kid1| 84,3| Reply.cc(43) finalize:
        Parsing helper buffer<br>
        2026/03/04 18:29:02.696 kid1| 29,8| UserRequest.cc(267)
        HandleReply: hlpRes693 got reply={result=TT, notes={token:
        TlRMTVNTUA…AAAA=; }}<br>
        2026/03/04 18:29:02.696 kid1| 29,4| UserRequest.cc(313)
        HandleReply: Need to challenge the client with a server token</p>
      <pre><code>
**Step 4b — NTLM Type 3 validation (AF response):**
</code></pre>
      <p>2026/03/04 18:29:02.724 kid1| 84,9| helper.cc(1447)
        helperStatefulDispatch: helperStatefulDispatch busying helper
        negotiateauthenticator #Hlpr91<br>
        2026/03/04 18:29:02.724 kid1| 84,5| helper.cc(1476)
        helperStatefulDispatch: helperStatefulDispatch: Request sent to
        negotiateauthenticator #Hlpr91, 764 bytes<br>
        2026/03/04 18:29:02.731 kid1| 84,5| helper.cc(1112)
        helperStatefulHandleRead: helperStatefulHandleRead: 38 bytes
        from negotiateauthenticator #Hlpr91<br>
        2026/03/04 18:29:02.732 kid1| 84,9| helper.cc(1122)
        helperStatefulHandleRead: accumulated[38]=AF oQcwBaADCgEA
        CHILD01/Administrator<br>
        2026/03/04 18:29:02.732 kid1| 84,3| helper.cc(1134)
        helperStatefulHandleRead: helperStatefulHandleRead: end of reply
        found<br>
        2026/03/04 18:29:02.732 kid1| 84,3| Reply.cc(43) finalize:
        Parsing helper buffer<br>
        2026/03/04 18:29:02.732 kid1| 84,3| Reply.cc(61) finalize: Buff
        length is larger than 2<br>
        2026/03/04 18:29:02.732 kid1| 29,8| UserRequest.cc(267)
        HandleReply: hlpRes693 got reply={result=OK, notes={token:
        oQcwBaADCgEA; user: CHILD01/Administrator; }}<br>
        2026/03/04 18:29:02.732 kid1| 29,4| UserRequest.cc(338)
        HandleReply: authenticated user CHILD01/Administrator<br>
        2026/03/04 18:29:02.732 kid1| 29,4| UserRequest.cc(357)
        HandleReply: Successfully validated user via Negotiate. Username
        ‘CHILD01/Administrator’</p>
      <pre><code>
Observation: The helper returns exactly `AF oQcwBaADCgEA CHILD01/Administrator` (38 bytes
including newline). Squid correctly parses the reply, extracts the token and username. The
authenticated username is set to `CHILD01/Administrator`.

### Step 5 — ACL match with `-i` FAILS (the bug)

When Squid evaluates `http_access deny Group953`, it checks the `proxy_auth -i` ACL:
</code></pre>
      <p>2026/03/04 18:27:58.119 kid1| 28,7| UserData.cc(26) match: user
        is CHILD01/Administrator, case_insensitive is 1<br>
        2026/03/04 18:27:58.119 kid1| 28,7| UserData.cc(37) match:
        returning 0</p>
      <pre><code>
**Result: `returning 0` — NO MATCH.**

The ACL check for Group953 returns 0 (no match), so the deny rule does not trigger.
Access is allowed through the final allow rule:
</code></pre>
      <p>2026/03/04 18:29:02.732 kid1| 28,5| Acl.cc(145) matches:
        checking Group953<br>
        2026/03/04 18:29:02.732 kid1| 28,3| Acl.cc(172) matches:
        checked: Group953 = 0</p>
      <pre><code>
Access log confirms user is NOT denied (note `accessrule: final_allow`):
</code></pre>
      <p>1772648820.870 75169 192.168.60.31 TCP_TUNNEL/200 5123 CONNECT
        sapo.pt:443 CHILD01/Administrator HIER_DIRECT/213.13.145.114:443
        - accessrule:%20final_allow</p>
      <pre><code>
### Step 6 — Remove `-i` flag, ACL match SUCCEEDS

Changed the ACL definition to remove the `-i` flag:
```bash
# Before:
acl Group953 proxy_auth  -i "/etc/squid3/acls/container_963.1.txt"
# After:
acl Group953 proxy_auth "/etc/squid3/acls/container_963.1.txt"

squid -k reconfigure
</code></pre>
      <p>After the next authentication from the same client:</p>
      <pre><code>2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive is 0
2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(37) match: returning 1
</code></pre>
      <p><strong>Result: <code>returning 1</code> — MATCH!</strong></p>
      <p>Without <code>-i</code>, entries are stored in original case
        from the file. The file contains<br>
        <code>CHILD01/Administrator</code> (line 4) which exactly
        matches the helper’s username. The deny<br>
        rule triggers.</p>
      <p>Access log confirms user IS now denied (note <code>accessrule:
          Rule587</code> and <code>ERR_ACCESS_DENIED</code>):</p>
      <pre><code>1772649291.245     12 192.168.60.31 TCP_DENIED/200 0 CONNECT static.foxnews.com:443 CHILD01/Administrator HIER_NONE/-:- - accessrule:%20Rule587 ERR_ACCESS_DENIED
1772649291.188      2 192.168.60.31 NONE_NONE_ABORTED/403 65843 GET <a class="moz-txt-link-freetext" href="https://static.foxnews.com/.../favicon-96x96.png">https://static.foxnews.com/.../favicon-96x96.png</a> CHILD01/Administrator HIER_NONE/-:- text/html ERR_ACCESS_DENIED
</code></pre>
      <h3>Step 7 — Additional confirmation: <code>proxy_auth_regex -i</code>
        also works</h3>
      <p>Changing the ACL to use <code>proxy_auth_regex -i</code> with
        the same file:</p>
      <pre><code>acl Group953 proxy_auth_regex  -i "/etc/squid3/acls/container_963.1.txt"
</code></pre>
      <p>This also correctly matches and denies the user. <code>proxy_auth_regex</code>
        is unaffected<br>
        because it uses <code>ACLRegexData</code> (regex matching)
        instead of <code>ACLUserData</code> (set-based matching).</p>
      <h3>Step 8 — Downgrade to Squid 5.x confirms fix</h3>
      <p>After downgrading from Squid 6.14-VCS to Squid 5.x on the same
        machine, the original<br>
        configuration with <code>proxy_auth -i</code> works correctly —
        the deny rule matches and blocks<br>
        the user as expected.</p>
      <pre><code class="hljs language-bash">
acl Group953 proxy_auth -i <span class="hljs-string">"/etc/squid3/acls/container_963.1.txt"</span>

squid -k reconfigure
</code></pre>
      <p>After the next authentication from the same client:</p>
      <pre><code>2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(26) match: user is CHILD01/Administrator, case_insensitive is 1
2026/03/04 18:34:11.740 kid1| 28,7| UserData.cc(37) match: returning 1
</code></pre>
      <p><strong>Result: <code>returning 1</code> — MATCH!</strong></p>
      <p>On Squd5.X With <code>-i</code>, entries are stored in
        original case from the file. The file contains<br>
        <code>CHILD01/Administrator</code> (line 4) which exactly
        matches the helper’s username. The deny<br>
        rule triggers.</p>
      <p>Access log confirms user IS now denied (note <code>accessrule:
          Rule587</code> and <code>ERR_ACCESS_DENIED</code>):</p>
      <pre><code>1772649291.245     12 192.168.60.31 TCP_DENIED/200 0 CONNECT static.foxnews.com:443 CHILD01/Administrator HIER_NONE/-:- - accessrule:%20Rule587 ERR_ACCESS_DENIED
1772649291.188      2 192.168.60.31 NONE_NONE_ABORTED/403 65843 GET <a class="moz-txt-link-freetext" href="https://static.foxnews.com/.../favicon-96x96.png">https://static.foxnews.com/.../favicon-96x96.png</a> CHILD01/Administrator HIER_NONE/-:- text/html ERR_ACCESS_DENIED
</code></pre>
      <h3>PoC Summary Table</h3>
      <table>
        <thead><tr>
            <th>Configuration</th>
            <th align="center">Squid 6.14-VCS</th>
            <th align="center">Squid 5.x</th>
          </tr>
        </thead><tbody>
          <tr>
            <td><code>proxy_auth -i</code> (file)</td>
            <td align="center">BROKEN</td>
            <td align="center">Works</td>
          </tr>
          <tr>
            <td><code>proxy_auth</code> (no <code>-i</code>, file)</td>
            <td align="center">Works</td>
            <td align="center">Works</td>
          </tr>
          <tr>
            <td><code>proxy_auth_regex -i</code> (file)</td>
            <td align="center">Works</td>
            <td align="center">Works</td>
          </tr>
        </tbody>
      </table>
      <h2>Suggested Fix</h2>
      <p>Either of these approaches would fix the bug:</p>
      <h3>Option A: Recreate the set when <code>CaseInsensitive_</code>
        is set (in <code>parse()</code>)</h3>
      <p>Add set recreation at the beginning of <code>parse()</code>
        when the flag comes from the line option:</p>
      <pre><code class="hljs language-cpp"><span class="hljs-function"><span
      class="hljs-type">void</span> <span class="hljs-title">ACLUserData::parse</span><span
      class="hljs-params">()</span>
</span>{
    flags.case_insensitive = <span class="hljs-built_in">bool</span>(CaseInsensitive_);

    <span class="hljs-comment">// If case-insensitive was set via line option, ensure the set</span>
    <span class="hljs-comment">// uses the case-insensitive comparator</span>
    <span class="hljs-keyword">if</span> (flags.case_insensitive) {
        <span class="hljs-function">UserDataNames_t <span
      class="hljs-title">newUdn</span><span class="hljs-params">(CaseInsensitveSBufCompare)</span></span>;
        newUdn.<span class="hljs-built_in">insert</span>(userDataNames.<span
      class="hljs-built_in">begin</span>(), userDataNames.<span
      class="hljs-built_in">end</span>());
        std::<span class="hljs-built_in">swap</span>(userDataNames, newUdn);
    }

    <span class="hljs-comment">// ... rest of parse() unchanged</span>
}
</code></pre>
      <h3>Option B: Lowercase the search key in <code>match()</code></h3>
      <pre><code class="hljs language-cpp"><span class="hljs-function"><span
      class="hljs-type">bool</span> <span class="hljs-title">ACLUserData::match</span><span
      class="hljs-params">(<span class="hljs-type">char</span> <span
      class="hljs-type">const</span> *user)</span>
</span>{
    <span class="hljs-built_in">debugs</span>(<span class="hljs-number">28</span>, <span
      class="hljs-number">7</span>, <span class="hljs-string">"user is "</span> &lt;&lt; user &lt;&lt; <span
      class="hljs-string">", case_insensitive is "</span> &lt;&lt; flags.case_insensitive);

    <span class="hljs-keyword">if</span> (user == <span
      class="hljs-literal">nullptr</span> || <span class="hljs-built_in">strcmp</span>(user, <span
      class="hljs-string">"-"</span>) == <span class="hljs-number">0</span>)
        <span class="hljs-keyword">return</span> <span
      class="hljs-number">0</span>;

    <span class="hljs-keyword">if</span> (flags.required) {
        <span class="hljs-built_in">debugs</span>(<span
      class="hljs-number">28</span>, <span class="hljs-number">7</span>, <span
      class="hljs-string">"aclMatchUser: user REQUIRED and auth-info present."</span>);
        <span class="hljs-keyword">return</span> <span
      class="hljs-number">1</span>;
    }

    <span class="hljs-function">SBuf <span class="hljs-title">key</span><span
      class="hljs-params">(user)</span></span>;
    <span class="hljs-keyword">if</span> (flags.case_insensitive)
        key.<span class="hljs-built_in">toLower</span>();

    <span class="hljs-type">bool</span> result = (userDataNames.<span
      class="hljs-built_in">find</span>(key) != userDataNames.<span
      class="hljs-built_in">end</span>());
    <span class="hljs-built_in">debugs</span>(<span class="hljs-number">28</span>, <span
      class="hljs-number">7</span>, <span class="hljs-string">"returning "</span> &lt;&lt; result);
    <span class="hljs-keyword">return</span> result;
}
</code></pre>
      <p>Option A is more correct because it also fixes the set
        comparator for any future operations. Option B is simpler but
        relies on both sides being lowercased rather than using a proper
        case-insensitive comparator.</p>
      <h2>Configuration Context</h2>
      <p>This was observed with a negotiate (SPNEGO/Kerberos with NTLM
        fallback) authentication helper. The helper returns usernames in
        mixed case as received from Active Directory SSPI (e.g., <code>DOMAIN/Username</code>).
        The <code>proxy_auth -i</code> ACL should match these usernames
        case-insensitively against the ACL file entries, but fails to do
        so in Squid 6.x.</p>
      <pre><code>auth_param negotiate program /path/to/negotiate-helper
acl BlockedUsers proxy_auth -i "/path/to/userlist.txt"
http_access deny BlockedUsers
</code></pre>
    </div>
  </body>
</html>

--------------HdounchMQzQSYPHiu001XZWf--

--===============6740450480782051361==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
squid-users mailing list
[email protected]
https://lists.squid-cache.org/listinfo/squid-users

--===============6740450480782051361==--