Honor the "deny" part of "foobar deny ACL" options. When AuthenticateAcl() and aclMatchExternal() were converted to use extended authentication ACL states (r11644 and r11645 dated 2011-08-14), the result of those function calls was set as the current checklist answer. This was incorrect because those functions do not make allow/deny decisions. They only tell us whether the ACL part of the allow/deny rule matches. If there is a match, the ACCESS_ALLOWED/ACCESS_DENIED answer depends on whether it is an allow or deny rule. For example, "http_access deny BadGuys" should deny access when the BadGuys ACL matches, but it was allowing access instead. === modified file 'src/auth/AclMaxUserIp.cc' --- src/auth/AclMaxUserIp.cc 2012-01-20 18:55:04 +0000 +++ src/auth/AclMaxUserIp.cc 2012-03-09 19:43:34 +0000 @@ -134,41 +134,40 @@ /* remove _this_ ip, as it is the culprit for going over the limit */ authenticateAuthUserRequestRemoveIp(auth_user_request, src_addr); debugs(28, 4, "aclMatchUserMaxIP: Denying access in strict mode"); } else { /* * non-strict - remove some/all of the cached entries * ie to allow the user to move machines easily */ authenticateAuthUserRequestClearIp(auth_user_request); debugs(28, 4, "aclMatchUserMaxIP: Denying access in non-strict mode - flushing the user ip cache"); } return 1; } int ACLMaxUserIP::match(ACLChecklist *cl) { ACLFilledChecklist *checklist = Filled(cl); allow_t answer = AuthenticateAcl(checklist); - checklist->currentAnswer(answer); int ti; // convert to tri-state ACL match 1,0,-1 switch (answer) { case ACCESS_ALLOWED: case ACCESS_AUTH_EXPIRED_OK: // check for a match ti = match(checklist->auth_user_request, checklist->src_addr); checklist->auth_user_request = NULL; return ti; case ACCESS_DENIED: case ACCESS_AUTH_EXPIRED_BAD: return 0; // non-match case ACCESS_DUNNO: case ACCESS_AUTH_REQUIRED: default: return -1; // other } === modified file 'src/auth/AclProxyAuth.cc' --- src/auth/AclProxyAuth.cc 2012-01-20 18:55:04 +0000 +++ src/auth/AclProxyAuth.cc 2012-03-09 19:31:12 +0000 @@ -63,41 +63,40 @@ type_ = rhs.type_; return *this; } char const * ACLProxyAuth::typeString() const { return type_; } void ACLProxyAuth::parse() { data->parse(); } int ACLProxyAuth::match(ACLChecklist *checklist) { allow_t answer = AuthenticateAcl(checklist); - checklist->currentAnswer(answer); // convert to tri-state ACL match 1,0,-1 switch (answer) { case ACCESS_ALLOWED: case ACCESS_AUTH_EXPIRED_OK: // check for a match return matchProxyAuth(checklist); case ACCESS_DENIED: case ACCESS_AUTH_EXPIRED_BAD: return 0; // non-match case ACCESS_DUNNO: case ACCESS_AUTH_REQUIRED: default: return -1; // other } } wordlist * === modified file 'src/external_acl.cc' --- src/external_acl.cc 2012-01-20 18:55:04 +0000 +++ src/external_acl.cc 2012-03-09 19:42:42 +0000 @@ -844,41 +844,40 @@ debugs(82, DBG_IMPORTANT, "WARNING: external ACL '" << acl->def->name << "' queue overload. Using stale result. '" << key << "'."); /* Fall thru to processing below */ } } } } external_acl_cache_touch(acl->def, entry); external_acl_message = entry->message.termedBuf(); debugs(82, 2, HERE << acl->def->name << " = " << entry->result); copyResultsFromEntry(ch->request, entry); return entry->result; } int ACLExternal::match(ACLChecklist *checklist) { allow_t answer = aclMatchExternal(data, Filled(checklist)); - checklist->currentAnswer(answer); // convert to tri-state ACL match 1,0,-1 switch (answer) { case ACCESS_ALLOWED: case ACCESS_AUTH_EXPIRED_OK: return 1; // match case ACCESS_DENIED: case ACCESS_AUTH_EXPIRED_BAD: return 0; // non-match case ACCESS_DUNNO: case ACCESS_AUTH_REQUIRED: default: return -1; // other } } wordlist * ACLExternal::dump() const