From: wessels <> Date: Tue, 12 Jan 1999 05:54:15 +0000 (+0000) Subject: This patch fully transforms proxy_auth into a ACL type, allowing both X-Git-Tag: SQUID_3_0_PRE1~2428 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1cfdbcf0;p=thirdparty%2Fsquid.git This patch fully transforms proxy_auth into a ACL type, allowing both allow and deny in any order suitable. Authentication is requested from the user if: * proxy_auth is used and no valid authentication header is present. * wrong password is used * denied by a proxy_auth ACL A positive sideeffect is that is is also possible to use deny_info on proxy_auth ACLs to change the message returned. It also fixes the problem where proxy_auth user wasn't logged if the proxy_auth user info wasn't cached. This patch fully replaces my previous attemt. There is a small collision with one of my other changes in proto.h, but I assume that you know how to resolve this. --- diff --git a/src/acl.cc b/src/acl.cc index 96c6b0b3a1..11b4f1a3c7 100644 --- a/src/acl.cc +++ b/src/acl.cc @@ -1,6 +1,6 @@ /* - * $Id: acl.cc,v 1.191 1998/12/05 00:54:13 wessels Exp $ + * $Id: acl.cc,v 1.192 1999/01/11 22:54:15 wessels Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -53,6 +53,7 @@ static void aclDestroyAclList(acl_list * list); static void aclDestroyTimeList(acl_time_data * data); static void aclDestroyIntRange(intrange *); static FREE aclFreeProxyAuthUser; +static struct _acl *aclFindByName(const char *name); static int aclMatchAcl(struct _acl *, aclCheck_t *); static int aclMatchIntegerRange(intrange * data, int i); static int aclMatchTime(acl_time_data * data, time_t when); @@ -246,7 +247,7 @@ aclTypeToStr(squid_acl type) return "ERROR"; } -acl * +static acl * aclFindByName(const char *name) { acl *a; @@ -761,6 +762,17 @@ aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name) return -1; } +/* does name lookup, returns if it is a proxy_auth acl */ +int +aclIsProxyAuth(const char *name) +{ + acl *a = aclFindByName(name); + if (a) + return a->type == ACL_PROXY_AUTH; + return 0; +} + + /* maex@space.net (05.09.96) * get the info for redirecting "access denied" to info pages * TODO (probably ;-) @@ -989,14 +1001,15 @@ aclDecodeProxyAuth(const char *proxy_auth, char **user, char **password, char *b } /* aclMatchProxyAuth can return three exit codes: - * 0 : No such user; invalid Proxy-authorization: header; - * ask for Proxy-Authorization: header + * 0 : user denied access * 1 : user validated OK * -1 : check the password for this user via an external authenticator + * -2 : invalid Proxy-authorization: header; + * ask for Proxy-Authorization: header */ static int -aclMatchProxyAuth(const char *proxy_auth, acl_proxy_auth_user * auth_user, aclCheck_t * checklist) +aclMatchProxyAuth(wordlist * data, const char * proxy_auth, acl_proxy_auth_user * auth_user, aclCheck_t * checklist) { /* checklist is used to register user name when identified, nothing else */ LOCAL_ARRAY(char, login_buf, USER_IDENT_SZ); @@ -1004,56 +1017,66 @@ aclMatchProxyAuth(const char *proxy_auth, acl_proxy_auth_user * auth_user, aclCh if (!aclDecodeProxyAuth(proxy_auth, &user, &password, login_buf, sizeof(login_buf))) /* No or invalid Proxy-Auth header */ - return 0; + return -2; debug(28, 5) ("aclMatchProxyAuth: checking user '%s'\n", user); - if (!auth_user) { - /* see if we already know this user */ - auth_user = hash_lookup(proxy_auth_cache, user); - if (!auth_user) { - /* user not yet known, ask external authenticator */ - debug(28, 4) ("aclMatchProxyAuth: user '%s' not yet known\n", user); - return -1; - } else if ((0 == strcmp(auth_user->passwd, password)) && - (auth_user->expiretime > current_time.tv_sec)) { - /* user already known and valid */ - debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n", - user); - /* copy username to request for logging on client-side */ - xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ); - return 1; - } else { - /* password mismatch/timeout */ - debug(28, 4) ("aclMatchProxyAuth: user '%s' password mismatch/timeout\n", + if (auth_user) { + /* This should be optimized to a boolean argument indicating that the + * password is invalid, instead of passing full acl_proxy_auth_user + * structures, and all messing with checklist->proxy_auth should + * be restricted the functions that deal with the authenticator. + */ + assert(auth_user == checklist->auth_user); + checklist->auth_user = NULL; /* get rid of that special reference */ + /* Check result from external validation */ + if (auth_user->passwd_ok != 1) { + /* password was checked but did not match */ + assert(auth_user->passwd_ok == 0); + debug(28, 4) ("aclMatchProxyAuth: authentication failed for user '%s'\n", user); - /* remove this user from the hash, making him unknown */ - hash_remove_link(proxy_auth_cache, (hash_link *) auth_user); aclFreeProxyAuthUser(auth_user); /* copy username to request for logging on client-side unless ident * is known (do not override ident with false proxy auth names) */ if (!*checklist->request->user_ident) xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ); - return -1; - } - /* NOTREACHED */ - } else { - /* Check result from external validation */ - if (checklist->auth_user->passwd_ok != 1) { - /* password was checked but did not match */ - assert(checklist->auth_user->passwd_ok == 0); - debug(28, 4) ("aclMatchProxyAuth: authentication failed for user '%s'\n", - user); - return 0; + return -2; + } else { + /* password was checked and did match */ + debug(28, 4) ("aclMatchProxyAuth: user '%s' validated OK\n", user); + /* store validated user in hash, after filling in expiretime */ + auth_user->expiretime = current_time.tv_sec + Config.authenticateTTL; + hash_join(proxy_auth_cache, (hash_link *) auth_user); + /* Continue checking below, as normal */ } - debug(28, 4) ("aclMatchProxyAuth: user '%s' validated OK\n", user); - /* store validated user in hash, after filling in expiretime */ - checklist->auth_user->expiretime = current_time.tv_sec + Config.authenticateTTL; - hash_join(proxy_auth_cache, (hash_link *) checklist->auth_user); - - return 1; } + /* see if we already know this user */ + auth_user = hash_lookup(proxy_auth_cache, user); + + if (!auth_user) { + /* user not yet known, ask external authenticator */ + debug(28, 4) ("aclMatchProxyAuth: user '%s' not yet known\n", user); + return -1; + } else if ((0 == strcmp(auth_user->passwd, password)) && + (auth_user->expiretime > current_time.tv_sec)) { + /* user already known and valid */ + debug(28, 5) ("aclMatchProxyAuth: user '%s' previously validated\n", + user); + /* copy username to request for logging on client-side */ + xstrncpy(checklist->request->user_ident, user, USER_IDENT_SZ); + return aclMatchUser(data, user); + } else { + /* password mismatch/timeout */ + debug(28, 4) ("aclMatchProxyAuth: user '%s' password mismatch/timeout\n", + user); + /* remove this user from the hash, making him unknown */ + hash_remove_link(proxy_auth_cache, (hash_link *) auth_user); + aclFreeProxyAuthUser(auth_user); + /* ask the external authenticator in case the password is changed */ + /* wrong password will be trapped above so this does not loop */ + return -1; + } /* NOTREACHED */ } @@ -1188,6 +1211,7 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist) const ipcache_addrs *ia = NULL; const char *fqdn = NULL; char *esc_buf; + const char *header; int k; if (!ae) return 0; @@ -1300,29 +1324,39 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist) case ACL_PROXY_AUTH: if (!r->flags.accelerated) { /* Proxy authorization on proxy requests */ - k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header, - HDR_PROXY_AUTHORIZATION), - checklist->auth_user, - checklist); + header = httpHeaderGetStr(&checklist->request->header, + HDR_PROXY_AUTHORIZATION); } else if (r->flags.internal) { /* WWW authorization on accelerated internal requests */ - k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header, - HDR_AUTHORIZATION), - checklist->auth_user, - checklist); + header = httpHeaderGetStr(&checklist->request->header, + HDR_AUTHORIZATION); } else { #if AUTH_ON_ACCELERATION /* WWW authorization on accelerated requests */ - k = aclMatchProxyAuth(httpHeaderGetStr(&checklist->request->header, - HDR_AUTHORIZATION), - checklist->auth_user, - checklist); + header = httpHeaderGetStr(&checklist->request->header, + HDR_AUTHORIZATION); #else debug(28, 1) ("aclMatchAcl: proxy_auth %s not applicable on accelerated requests.\n", ae->name); return -1; #endif } - if (k == 0) { + /* + * Register that we used the proxy authentication header so that + * it is not forwarded to the next proxy + */ + r->flags.used_proxy_auth = 1; + /* Check the password */ + switch (aclMatchProxyAuth(ae->data, + header, + checklist->auth_user, + checklist)) { + case 0: + /* Correct password, but was not allowed in this ACL */ + return 0; + case 1: + /* user validated OK */ + return 1; + case -2: /* no such user OR we need a proxy authentication header */ checklist->state[ACL_PROXY_AUTH] = ACL_PROXY_AUTH_NEEDED; /* @@ -1330,15 +1364,7 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist) * return codes here */ return 0; - } else if (k == 1) { - /* - * Authentication successful. Register that we used the proxy - * authentication header so that it is not forwarded to the - * next proxy - */ - r->flags.used_proxy_auth = 1; - return 1; - } else if (k == -1) { + case -1: /* * we need to validate the password */ diff --git a/src/client_side.cc b/src/client_side.cc index f79f9ee6b3..8519af5011 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.428 1999/01/11 20:16:04 wessels Exp $ + * $Id: client_side.cc,v 1.429 1999/01/11 22:54:17 wessels Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -53,7 +53,6 @@ #endif static const char *const crlf = "\r\n"; -static const char *const proxy_auth_challenge_fmt = "Basic realm=\"%s\""; #define REQUEST_BUF_SIZE 4096 #define FAILURE_MODE_TIME 300 @@ -83,7 +82,6 @@ static void clientInterpretRequestHeaders(clientHttpRequest *); static void clientProcessRequest(clientHttpRequest *); static void clientProcessExpired(void *data); static void clientProcessOnlyIfCachedMiss(clientHttpRequest * http); -static HttpReply *clientConstructProxyAuthReply(clientHttpRequest * http); static int clientCachable(clientHttpRequest * http); static int clientHierarchical(clientHttpRequest * http); static int clientCheckContentLength(request_t * r); @@ -142,35 +140,6 @@ clientOnlyIfCached(clientHttpRequest * http) EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED); } -static HttpReply * -clientConstructProxyAuthReply(clientHttpRequest * http) -{ - ErrorState *err; - HttpReply *rep; - if (!http->flags.accel) { - /* Proxy authorisation needed */ - err = errorCon(ERR_CACHE_ACCESS_DENIED, - HTTP_PROXY_AUTHENTICATION_REQUIRED); - } else { - /* WWW authorisation needed */ - err = errorCon(ERR_CACHE_ACCESS_DENIED, HTTP_UNAUTHORIZED); - } - err->request = requestLink(http->request); - rep = errorBuildReply(err); - errorStateFree(err); - /* add Authenticate header */ - if (!http->flags.accel) { - /* Proxy authorisation needed */ - httpHeaderPutStrf(&rep->header, HDR_PROXY_AUTHENTICATE, - proxy_auth_challenge_fmt, Config.proxyAuthRealm); - } else { - /* WWW Authorisation needed */ - httpHeaderPutStrf(&rep->header, HDR_WWW_AUTHENTICATE, - proxy_auth_challenge_fmt, Config.proxyAuthRealm); - } - return rep; -} - StoreEntry * clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags) { @@ -191,12 +160,12 @@ clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags) return e; } - void clientAccessCheckDone(int answer, void *data) { clientHttpRequest *http = data; int page_id = -1; + http_status status; ErrorState *err = NULL; debug(33, 5) ("clientAccessCheckDone: '%s' answer=%d\n", http->uri, answer); http->acl_checklist = NULL; @@ -206,14 +175,6 @@ clientAccessCheckDone(int answer, void *data) assert(http->redirect_state == REDIRECT_NONE); http->redirect_state = REDIRECT_PENDING; redirectStart(http, clientRedirectDone, http); - } else if (answer == ACCESS_REQ_PROXY_AUTH) { - http->log_type = LOG_TCP_DENIED; - http->entry = clientCreateStoreEntry(http, http->request->method, - null_request_flags); - /* create appropriate response */ - http->entry->mem_obj->reply = clientConstructProxyAuthReply(http); - httpReplySwapOut(http->entry->mem_obj->reply, http->entry); - storeComplete(http->entry); } else { debug(33, 5) ("Access Denied: %s\n", http->uri); debug(33, 5) ("AclMatchedName = %s\n", @@ -222,13 +183,24 @@ clientAccessCheckDone(int answer, void *data) http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags); page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); - /* NOTE: don't use HTTP_UNAUTHORIZED because then the - * stupid browser wants us to authenticate */ - err = errorCon(ERR_ACCESS_DENIED, HTTP_FORBIDDEN); + if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { + if (!http->flags.accel) { + /* Proxy authorisation needed */ + status = HTTP_PROXY_AUTHENTICATION_REQUIRED; + } else { + /* WWW authorisation needed */ + status = HTTP_UNAUTHORIZED; + } + if (page_id <= 0) + page_id = ERR_CACHE_ACCESS_DENIED; + } else { + status = HTTP_FORBIDDEN; + if (page_id <= 0) + page_id = ERR_ACCESS_DENIED; + } + err = errorCon(page_id, status); err->request = requestLink(http->request); err->src_addr = http->conn->peer.sin_addr; - if (page_id > 0) - err->page_id = page_id; errorAppendEntry(http->entry, err); } } diff --git a/src/errorpage.cc b/src/errorpage.cc index 351335b066..bd9638b819 100644 --- a/src/errorpage.cc +++ b/src/errorpage.cc @@ -1,6 +1,6 @@ /* - * $Id: errorpage.cc,v 1.144 1998/12/05 00:54:23 wessels Exp $ + * $Id: errorpage.cc,v 1.145 1999/01/11 22:54:19 wessels Exp $ * * DEBUG: section 4 Error Generation * AUTHOR: Duane Wessels @@ -52,6 +52,8 @@ typedef struct { /* local constant and vars */ +static const char *const proxy_auth_challenge_fmt = "Basic realm=\"%s\""; + /* * note: hard coded error messages are not appended with %S automagically * to give you more control on the format @@ -268,6 +270,22 @@ errorAppendEntry(StoreEntry * entry, ErrorState * err) assert(mem->inmem_hi == 0); storeBuffer(entry); rep = errorBuildReply(err); + /* Add authentication header */ + switch (err->http_status) { + case HTTP_PROXY_AUTHENTICATION_REQUIRED: + /* Proxy authorisation needed */ + httpHeaderPutStrf(&rep->header, HDR_PROXY_AUTHENTICATE, + proxy_auth_challenge_fmt, Config.proxyAuthRealm); + break; + case HTTP_UNAUTHORIZED: + /* WWW Authorisation needed */ + httpHeaderPutStrf(&rep->header, HDR_WWW_AUTHENTICATE, + proxy_auth_challenge_fmt, Config.proxyAuthRealm); + break; + default: + /* Keep GCC happy */ + break; + } httpReplySwapOut(rep, entry); httpReplyDestroy(rep); mem->reply->sline.status = err->http_status; diff --git a/src/protos.h b/src/protos.h index 2bcd9f609a..a259d182e2 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.299 1999/01/11 21:55:39 wessels Exp $ + * $Id: protos.h,v 1.300 1999/01/11 22:54:20 wessels Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -55,7 +55,7 @@ extern void aclDestroyAccessList(struct _acl_access **list); extern void aclDestroyAcls(acl **); extern void aclParseAccessLine(struct _acl_access **); extern void aclParseAclLine(acl **); -extern struct _acl *aclFindByName(const char *name); +extern int aclIsProxyAuth(const char *name); extern int aclGetDenyInfoPage(acl_deny_info_list ** head, const char *name); extern void aclParseDenyInfoLine(struct _acl_deny_info_list **); extern void aclDestroyDenyInfoList(struct _acl_deny_info_list **);