--------------------- PatchSet 2673 Date: 2001/07/27 14:23:49 Author: rbcollins Branch: ntlm Tag: (none) Log: working max_user_ip acl code Members: src/acl.c:1.1.1.3.12.60->1.1.1.3.12.61 src/authenticate.c:1.1.1.3.12.40->1.1.1.3.12.41 src/protos.h:1.1.1.3.12.35->1.1.1.3.12.36 src/structs.h:1.1.1.3.4.1.2.44->1.1.1.3.4.1.2.45 src/typedefs.h:1.1.1.3.12.26->1.1.1.3.12.27 src/auth/basic/auth_basic.c:1.1.10.17->1.1.10.18 Index: squid/src/acl.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/acl.c,v retrieving revision 1.1.1.3.12.60 retrieving revision 1.1.1.3.12.61 diff -u -r1.1.1.3.12.60 -r1.1.1.3.12.61 --- squid/src/acl.c 26 Jul 2001 14:58:50 -0000 1.1.1.3.12.60 +++ squid/src/acl.c 27 Jul 2001 14:23:49 -0000 1.1.1.3.12.61 @@ -1,6 +1,6 @@ /* - * $Id: acl.c,v 1.1.1.3.12.60 2001/07/26 14:58:50 rbcollins Exp $ + * $Id: acl.c,v 1.1.1.3.12.61 2001/07/27 14:23:49 rbcollins Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -67,7 +67,10 @@ #if SQUID_SNMP static int aclMatchWordList(wordlist *, const char *); #endif -static int aclMatchUserMaxIP(void *, auth_user_request_t *); +static void aclParseUserMaxIP(void * data); +static void aclDestroyUserMaxIP(void * data); +static wordlist *aclDumpUserMaxIP(void *data); +static int aclMatchUserMaxIP(void *, auth_user_request_t *, struct in_addr); static squid_acl aclStrToType(const char *s); static int decode_addr(const char *, struct in_addr *, struct in_addr *); static void aclCheck(aclCheck_t * checklist); @@ -787,9 +790,11 @@ case ACL_SRC_ASN: case ACL_MAXCONN: case ACL_DST_ASN: - case ACL_MAX_USER_IP: aclParseIntlist(&A->data); break; + case ACL_MAX_USER_IP: + aclParseUserMaxIP(&A->data); + break; #if SRC_RTT_NOT_YET_FINISHED case ACL_NETDB_SRC_RTT: aclParseIntlist(&A->data); @@ -1205,7 +1210,7 @@ * the authenticateStart routine for rv==AUTH_ACL_HELPER */ static auth_acl_t -AuthenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t *request, ConnStateData *conn) +AuthenticateAuthenticate(auth_user_request_t ** auth_user_request, http_hdr_type headertype, request_t *request, ConnStateData *conn, struct in_addr src_addr) { const char * proxy_auth; assert(headertype != 0); @@ -1351,7 +1356,8 @@ if (!request->auth_user_request) { /* lock the user for the request structure link */ authenticateAuthUserRequestLock(*auth_user_request); - request->auth_user_request = *auth_user_request; + request->auth_user_request = *auth_user_request; + authenticateAuthUserRequestSetIp(*auth_user_request, src_addr); } /* Unlock the request - we've authenticated it */ @@ -1377,11 +1383,6 @@ * username */ - /* get the auth_user_request */ - auth_user_request = checklist->auth_user_request; - /* Clear the reference in the checklist */ - checklist->auth_user_request = NULL; - /* for completeness */ authenticateAuthUserRequestLock(auth_user_request); @@ -1395,40 +1396,85 @@ authenticateUserRequestUsername(auth_user_request)); } +CBDATA_TYPE (acl_user_ip_data); + +void +aclParseUserMaxIP(void * data) +{ + acl_user_ip_data ** acldata = data; + char *t = NULL; + CBDATA_INIT_TYPE (acl_user_ip_data); + if (*acldata) { + debug (28, 1) ("Attempting to alter already set User max IP acl\n"); + return; + } + + *acldata = cbdataAlloc (acl_user_ip_data); + if ((t = strtokFile())) { + debug(28, 5) ("aclParseUserMaxIP: First token is %s\n", t); + if (strcmp("-s", t) == 0) { + debug(28, 5) ("aclParseUserMaxIP: Going strict\n"); + (*acldata)->flags.strict = 1; + } else { + (*acldata)->max = atoi(t); + debug(28, 5) ("aclParseUserMaxIP: Max IP address's %d\n", (*acldata)->max); + } + } else + fatal("aclParseUserMaxIP: Malformed ACL %d\n"); +} + +void +aclDestroyUserMaxIP(void * data) +{ + // acl_user_ip_data ** acldata = data; +} + +wordlist * +aclDumpUserMaxIP(void * data) +{ + // acl_user_ip_data * acldata = data; + return NULL; +} + /* aclMatchUserMaxIP - check for users logging in from multiple IP's - * 0 : Did not match - * 1 : Matched + * 0 : No match + * 1 : Match */ int -aclMatchUserMaxIP(void *data, auth_user_request_t *auth_user_request) +aclMatchUserMaxIP(void *data, auth_user_request_t *auth_user_request, + struct in_addr src_addr) { /* > the logic for flush the ip list when the limit is hit vs keep it sorted in most recent access order and just drop the oldest one off is currently undecided */ + acl_user_ip_data *acldata = data; - /* This needs to move into a new ACL in some way - * authenticateAuthUserRequestSetIp(auth_user_request, - * checklist->src_addr); - * */ - -#if 0 - if (authenticateCheckAuthUserIP(checklist->src_addr, auth_user_request)) { - /* Once the match is completed we have finished with the - * * auth_user structure */ -#endif + if (authenticateAuthUserRequestIPCount(auth_user_request) <= acldata->max) + return 0; -#if 0 + /* this is a match */ + if (acldata->flags.strict) { + /* simply deny access - the user name is already associated with + * the request + */ + /* remove _this_ ip, as it is the culprit for going over the limit */ + authenticateAuthUserRequestRemoveIp(auth_user_request, src_addr); + debug (28,4) ("aclMatchUserMaxIP: Denying access in strict mode\n"); } else { + /* non-strict - remove some/all of the cached entries + * ie to allow the user to move machines easily + */ + authenticateAuthUserRequestClearIp(auth_user_request); + debug (28,4) ("aclMatchUserMaxIP: Denying access in non-strict mode - flushing the user ip cache\n"); + } +#if 0 debug(28, 1) ("XXX authenticateCheckAuthUserIP returned 0, somebody " "make sure the username gets logged to access.log.\n"); debug(28, 1) ("XXX if it works, tell developers to remove this " "message\n"); - } #endif - /* never match for now */ -// authenticateAuthUserRequestUnlock(auth_user_request); - return 0; + return 1; } static void @@ -1716,7 +1762,7 @@ #endif } /* get authed here */ - if ((ti = AuthenticateAuthenticate(&checklist->auth_user_request, headertype, checklist->request, checklist->conn)) != AUTH_AUTHENTICATED) { + if ((ti = AuthenticateAuthenticate(&checklist->auth_user_request, headertype, checklist->request, checklist->conn, checklist->src_addr)) != AUTH_AUTHENTICATED) { switch (ti) { case 0: /* Authenticated but not Authorised for this ACL */ @@ -1745,12 +1791,14 @@ checklist->auth_user_request, checklist, ae->type); break; case ACL_MAX_USER_IP: - ti = aclMatchUserMaxIP(ae->data, checklist->auth_user_request); + ti = aclMatchUserMaxIP(ae->data, checklist->auth_user_request, + checklist->src_addr); break; default: /* Keep GCC happy */ break; } + checklist->auth_user_request = NULL; /* Check the credentials */ switch (ti) { case 0: @@ -2199,9 +2247,11 @@ case ACL_NETDB_SRC_RTT: #endif case ACL_MAXCONN: - case ACL_MAX_USER_IP: intlistDestroy((intlist **) & a->data); break; + case ACL_MAX_USER_IP: + aclDestroyUserMaxIP(&a->data); + break; case ACL_URL_PORT: case ACL_MY_PORT: aclDestroyIntRange(a->data); @@ -2538,8 +2588,9 @@ case ACL_SRC_ASN: case ACL_MAXCONN: case ACL_DST_ASN: - case ACL_MAX_USER_IP: return aclDumpIntlistList(a->data); + case ACL_MAX_USER_IP: + return aclDumpUserMaxIP(a->data); case ACL_URL_PORT: case ACL_MY_PORT: return aclDumpIntRangeList(a->data); Index: squid/src/authenticate.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/authenticate.c,v retrieving revision 1.1.1.3.12.40 retrieving revision 1.1.1.3.12.41 diff -u -r1.1.1.3.12.40 -r1.1.1.3.12.41 --- squid/src/authenticate.c 20 Jul 2001 13:25:41 -0000 1.1.1.3.12.40 +++ squid/src/authenticate.c 27 Jul 2001 14:23:49 -0000 1.1.1.3.12.41 @@ -1,6 +1,6 @@ /* - * $Id: authenticate.c,v 1.1.1.3.12.40 2001/07/20 13:25:41 rbcollins Exp $ + * $Id: authenticate.c,v 1.1.1.3.12.41 2001/07/27 14:23:49 rbcollins Exp $ * * DEBUG: section 29 Authenticator * AUTHOR: Duane Wessels @@ -40,6 +40,8 @@ #include "squid.h" +CBDATA_TYPE (auth_user_ip_t); + static void authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request); @@ -175,6 +177,7 @@ auth_user_t *temp_auth; temp_auth = memAllocate(MEM_AUTH_USER_T); assert(temp_auth != NULL); + memset (temp_auth, '\0', sizeof (auth_user_t)); temp_auth->auth_type = AUTH_UNKNOWN; temp_auth->references = 0; temp_auth->auth_module = authenticateAuthSchemeId(scheme) + 1; @@ -241,11 +244,113 @@ void authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr) { - if (auth_user_request->auth_user) - if (!auth_user_request->auth_user->ipaddr.s_addr) - auth_user_request->auth_user->ipaddr = ipaddr; + auth_user_ip_t *ipdata, *tempnode; + auth_user_t *auth_user; + CBDATA_INIT_TYPE (auth_user_ip_t); + if (!auth_user_request->auth_user) + return; + auth_user = auth_user_request->auth_user; + ipdata = (auth_user_ip_t *) auth_user->ip_list.head; + while (ipdata) { + tempnode = (auth_user_ip_t *) ipdata->node.next; + /* walk the ip list */ + if (ipdata->ipaddr.s_addr == ipaddr.s_addr) { + /* This ip has alreadu been seen. */ + /* update IP ttl */ + ipdata->ip_expiretime = squid_curtime; + return; + } + if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) { + /* This IP has expired - remove from the seen list */ + dlinkDelete (&ipdata->node, &auth_user->ip_list); + cbdataFree (ipdata); + /* catch incipient underflow */ + assert(auth_user->ipcount); + auth_user->ipcount--; + } + ipdata = tempnode; + } + + /* This ip is not in the seen list */ + ipdata = cbdataAlloc (auth_user_ip_t); + ipdata->ip_expiretime = squid_curtime; + ipdata->ipaddr = ipaddr; + dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list); + auth_user->ipcount++; + +#if 0 +username = authenticateUserRequestUsername(auth_user_request); +char *ip1 = xstrdup(inet_ntoa(auth_user_request->auth_user->ipaddr)); +char *ip2 = xstrdup(inet_ntoa(request_src_addr)); +debug(29, 1) ("aclMatchProxyAuth: user '%s' has changed IP address (%s, %s)\n ", username, ip1, ip2); +safe_free(ip1); +safe_free(ip2); +#endif +} + +void +authenticateAuthUserRequestRemoveIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr) +{ + auth_user_ip_t *ipdata; + auth_user_t *auth_user; + if (!auth_user_request->auth_user) + return; + auth_user = auth_user_request->auth_user; + ipdata = (auth_user_ip_t *) auth_user->ip_list.head; + while (ipdata) { + /* walk the ip list */ + if (ipdata->ipaddr.s_addr == ipaddr.s_addr) { + /* remove the node */ + dlinkDelete (&ipdata->node, &auth_user->ip_list); + cbdataFree (ipdata); + /* catch incipient underflow */ + assert(auth_user->ipcount); + auth_user->ipcount--; + return; + } + ipdata = (auth_user_ip_t *) ipdata->node.next; + } + +} + +static void +authenticateAuthUserClearIp(auth_user_t * auth_user) +{ + auth_user_ip_t *ipdata, *tempnode; + if (!auth_user) + return; + ipdata = (auth_user_ip_t *) auth_user->ip_list.head; + while (ipdata) { + tempnode = (auth_user_ip_t *) ipdata->node.next; + /* walk the ip list */ + dlinkDelete (&ipdata->node, &auth_user->ip_list); + cbdataFree (ipdata); + /* catch incipient underflow */ + assert(auth_user->ipcount); + auth_user->ipcount--; + ipdata = tempnode; + } + /* integrity check */ + assert (auth_user->ipcount == 0); } + +void +authenticateAuthUserRequestClearIp(auth_user_request_t * auth_user_request) +{ + if (auth_user_request) + authenticateAuthUserClearIp(auth_user_request->auth_user); +} + +size_t +authenticateAuthUserRequestIPCount(auth_user_request_t * auth_user_request) +{ + assert (auth_user_request); + assert (auth_user_request->auth_user); + return auth_user_request->auth_user->ipcount; +} + + /* Get Auth User: Return a filled out auth_user structure for the given * Proxy Auth (or Auth) header. It may be a cached Auth User or a new * Unauthenticated structure. The structure is given an inital lock here. @@ -608,6 +713,8 @@ } /* free cached acl results */ aclCacheMatchFlush(&u->proxy_match_cache); + /* free seen ip address's */ + authenticateAuthUserClearIp(u); if (u->scheme_data && u->auth_module > 0) authscheme_list[u->auth_module - 1].FreeUser(u); /* prevent accidental reuse */ @@ -740,45 +847,3 @@ /* lock for presence in the cache */ authenticateAuthUserLock(auth_user); } - - - -/* - * check the user for ip changes timeouts - * 0 = failed check - * 1 = ip requirements are ok. - */ -/* TODO: - * ip_expire data should be in a struct of it's own - for code reuse */ -int -authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user_request) -{ - char *username = authenticateUserRequestUsername(auth_user_request); - if (request_src_addr.s_addr == auth_user_request->auth_user->ipaddr.s_addr || auth_user_request->auth_user->ip_expiretime + Config.authenticateIpTTL <= squid_curtime) { - /* user has not moved ip or had the ip timeout expire */ - if ((auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) || - (auth_user_request->auth_user->auth_type == AUTH_BROKEN)) { - debug(29, 1) ("authenticateCheckProxyAuthIP: broken or unknown auth type %d.\n", auth_user_request->auth_user->auth_type); - return 0; - } - username = authenticateUserRequestUsername(auth_user_request); - /* Update IP ttl */ - auth_user_request->auth_user->ip_expiretime = squid_curtime; - auth_user_request->auth_user->ipaddr = request_src_addr; - return 1; - } else { - char *ip1 = xstrdup(inet_ntoa(auth_user_request->auth_user->ipaddr)); - char *ip2 = xstrdup(inet_ntoa(request_src_addr)); - if (Config.onoff.authenticateIpTTLStrict) { - debug(29, 1) ("aclMatchProxyAuth: user '%s' tried to use multiple IP addresses! (%s, %s)\n ", username, ip1, ip2); - } else { - /* Non-strict mode. Reassign ownership to the new IP */ - auth_user_request->auth_user->ipaddr.s_addr = request_src_addr.s_addr; - debug(29, 1) ("aclMatchProxyAuth: user '%s' has changed IP address (%s, %s)\n ", username, ip1, ip2); - } - safe_free(ip1); - safe_free(ip2); - /* and deny access */ - return 0; - } -} Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.12.35 retrieving revision 1.1.1.3.12.36 diff -u -r1.1.1.3.12.35 -r1.1.1.3.12.36 --- squid/src/protos.h 20 Jul 2001 13:25:42 -0000 1.1.1.3.12.35 +++ squid/src/protos.h 27 Jul 2001 14:23:49 -0000 1.1.1.3.12.36 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.12.35 2001/07/20 13:25:42 rbcollins Exp $ + * $Id: protos.h,v 1.1.1.3.12.36 2001/07/27 14:23:49 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -745,6 +745,9 @@ extern char *authenticateAuthUserRequestMessage(auth_user_request_t *); extern int authenticateAuthUserInuse(auth_user_t * auth_user); extern void authenticateAuthUserRequestSetIp(auth_user_request_t *, struct in_addr); +extern void authenticateAuthUserRequestRemoveIp(auth_user_request_t *, struct in_addr); +extern void authenticateAuthUserRequestClearIp(auth_user_request_t *); +extern size_t authenticateAuthUserRequestIPCount(auth_user_request_t *); extern int authenticateDirection(auth_user_request_t *); extern FREE authenticateFreeProxyAuthUser; extern void authenticateFreeProxyAuthUserACLResults(void *data); Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.1.1.3.4.1.2.44 retrieving revision 1.1.1.3.4.1.2.45 diff -u -r1.1.1.3.4.1.2.44 -r1.1.1.3.4.1.2.45 --- squid/src/structs.h 20 Jul 2001 13:25:42 -0000 1.1.1.3.4.1.2.44 +++ squid/src/structs.h 27 Jul 2001 14:23:49 -0000 1.1.1.3.4.1.2.45 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.1.1.3.4.1.2.44 2001/07/20 13:25:42 rbcollins Exp $ + * $Id: structs.h,v 1.1.1.3.4.1.2.45 2001/07/27 14:23:49 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -53,6 +53,12 @@ } flags; }; +struct _acl_user_ip_data { + size_t max; + struct { + unsigned int strict:1; + } flags; +}; struct _acl_ip_data { struct in_addr addr1; /* if addr2 non-zero then its a range */ @@ -87,6 +93,13 @@ dlink_node link; /* other hash entries that point to the same auth_user */ }; +struct _auth_user_ip_t { + dlink_node node; + /* IP addr this user authenticated from */ + struct in_addr ipaddr; + time_t ip_expiretime; +}; + struct _auth_user_t { /* extra fields for proxy_auth */ /* this determines what scheme owns the user data. */ @@ -98,13 +111,12 @@ /* we may have many proxy-authenticate strings that decode to the same user */ dlink_list proxy_auth_list; dlink_list proxy_match_cache; + dlink_list ip_list; + size_t ipcount; struct { unsigned int credentials_ok:2; /*0=unchecked,1=ok,2=failed */ } flags; long expiretime; - /* IP addr this user authenticated from */ - struct in_addr ipaddr; - time_t ip_expiretime; /* how many references are outstanding to this instance */ size_t references; /* the auth scheme has it's own private data area */ Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.1.1.3.12.26 retrieving revision 1.1.1.3.12.27 diff -u -r1.1.1.3.12.26 -r1.1.1.3.12.27 --- squid/src/typedefs.h 18 May 2001 10:01:17 -0000 1.1.1.3.12.26 +++ squid/src/typedefs.h 27 Jul 2001 14:23:49 -0000 1.1.1.3.12.27 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.1.1.3.12.26 2001/05/18 10:01:17 rbcollins Exp $ + * $Id: typedefs.h,v 1.1.1.3.12.27 2001/07/27 14:23:49 rbcollins Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -64,10 +64,12 @@ typedef struct _auth_user_t auth_user_t; typedef struct _auth_user_request_t auth_user_request_t; typedef struct _auth_user_hash_pointer auth_user_hash_pointer; +typedef struct _auth_user_ip_t auth_user_ip_t; typedef struct _acl_proxy_auth_match_cache acl_proxy_auth_match_cache; typedef struct _authscheme_entry authscheme_entry_t; typedef struct _authScheme authScheme; typedef struct _acl_user_data acl_user_data; +typedef struct _acl_user_ip_data acl_user_ip_data; typedef struct _acl_arp_data acl_arp_data; typedef struct _acl acl; typedef struct _acl_snmp_comm acl_snmp_comm; Index: squid/src/auth/basic/auth_basic.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/basic/auth_basic.c,v retrieving revision 1.1.10.17 retrieving revision 1.1.10.18 diff -u -r1.1.10.17 -r1.1.10.18 --- squid/src/auth/basic/auth_basic.c 28 Jun 2001 13:53:59 -0000 1.1.10.17 +++ squid/src/auth/basic/auth_basic.c 27 Jul 2001 14:23:50 -0000 1.1.10.18 @@ -200,7 +200,6 @@ /* Decode now takes care of finding the auth_user struct in the cache */ /* after external auth occurs anyway */ auth_user->expiretime = current_time.tv_sec; - auth_user->ip_expiretime = squid_curtime; return; } @@ -507,7 +506,6 @@ auth_user->auth_type = AUTH_BASIC; /* current time for timeouts */ auth_user->expiretime = current_time.tv_sec; - auth_user->ip_expiretime = squid_curtime; /* this auth_user struct is the 'lucky one' to get added to the username cache */ /* the requests after this link to the auth_user */