]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
This patch fully transforms proxy_auth into a ACL type, allowing both
authorwessels <>
Tue, 12 Jan 1999 05:54:15 +0000 (05:54 +0000)
committerwessels <>
Tue, 12 Jan 1999 05:54:15 +0000 (05:54 +0000)
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.

src/acl.cc
src/client_side.cc
src/errorpage.cc
src/protos.h

index 96c6b0b3a1f5f8604e7fd7af5ee9185aac28455f..11b4f1a3c703ed97599f50e8ceb3435a783c35c5 100644 (file)
@@ -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
             */
index f79f9ee6b3b8d72d29887a0b55d4131e688d468a..8519af5011600942ecb79dd52d639d870ff4911f 100644 (file)
@@ -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);
     }
 }
index 351335b06681bc6a955989204ead5cf4c5dca9fb..bd9638b819752eab0d735c6ea470d859d5d966d2 100644 (file)
@@ -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;
index 2bcd9f609a729fd29e2a95b6f76e9ac4dcce8203..a259d182e2a9a9450cfb2217249101d0f3cbeac8 100644 (file)
@@ -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 **);