From: wessels <> Date: Sun, 24 Jan 1999 09:22:53 +0000 (+0000) Subject: patch that combines client-side informational IDENT lookups with X-Git-Tag: SQUID_3_0_PRE1~2355 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=05832ae181a2c57deed4a290e1e82ec9c1152f85;p=thirdparty%2Fsquid.git patch that combines client-side informational IDENT lookups with ACL "required" lookups. initial patch from henrik --- diff --git a/src/acl.cc b/src/acl.cc index b14ece1cec..fdf78f32b1 100644 --- a/src/acl.cc +++ b/src/acl.cc @@ -1,6 +1,6 @@ /* - * $Id: acl.cc,v 1.194 1999/01/13 22:13:38 wessels Exp $ + * $Id: acl.cc,v 1.195 1999/01/24 02:22:53 wessels Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -68,6 +68,7 @@ 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); static void aclCheckCallback(aclCheck_t * checklist, allow_t answer); +static IDCB aclLookupIdentDone; static IPH aclLookupDstIPDone; static IPH aclLookupDstIPforASNDone; static FQDNH aclLookupSrcFQDNDone; @@ -689,7 +690,6 @@ aclParseAclLine(acl ** head) aclParseIntRange(&A->data); break; case ACL_IDENT: - Config.onoff.ident_lookup = 1; aclParseWordList(&A->data); break; case ACL_PROTO: @@ -959,7 +959,7 @@ aclMatchUser(wordlist * data, const char *user) debug(28, 3) ("aclMatchUser: checking '%s'\n", user); while (data) { debug(28, 3) ("aclMatchUser: looking for '%s'\n", data->key); - if (strcmp(data->key, "REQUIRED") == 0 && *user != '\0') + if (strcmp(data->key, "REQUIRED") == 0 && *user != '\0' && strcmp(user, "-") != 0) return 1; if (strcmp(data->key, user) == 0) return 1; @@ -1310,7 +1310,12 @@ aclMatchAcl(acl * ae, aclCheck_t * checklist) return aclMatchIntegerRange(ae->data, r->port); /* NOTREACHED */ case ACL_IDENT: - return aclMatchUser(ae->data, checklist->ident); + if (*checklist->ident) { + return aclMatchUser(ae->data, checklist->ident); + } else { + checklist->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; + return 0; + } /* NOTREACHED */ case ACL_PROTO: return aclMatchInteger(ae->data, r->protocol); @@ -1502,9 +1507,18 @@ aclCheck(aclCheck_t * checklist) match = -1; } else if (checklist->state[ACL_IDENT] == ACL_LOOKUP_NEEDED) { debug(28, 3) ("aclCheck: Doing ident lookup\n"); - /* XXX how to do ident lookup? */ - checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING; - return; + if (cbdataValid(checklist->conn)) { + identStart(&checklist->conn->me, &checklist->conn->peer, + aclLookupIdentDone, checklist); + checklist->state[ACL_IDENT] = ACL_LOOKUP_PENDING; + return; + } else { + debug(28, 1) ("aclCheck: Can't start ident lookup. No client connection\n"); + cbdataUnlock(checklist->conn); + checklist->conn = NULL; + allow = 0; + match = -1; + } } /* * We are done with this _acl_access entry. Either the request @@ -1540,6 +1554,10 @@ aclChecklistFree(aclCheck_t * checklist) if (checklist->request) requestUnlink(checklist->request); checklist->request = NULL; + if (checklist->conn) { + cbdataUnlock(checklist->conn); + checklist->conn = NULL; + } cbdataFree(checklist); } @@ -1555,6 +1573,24 @@ aclCheckCallback(aclCheck_t * checklist, allow_t answer) aclChecklistFree(checklist); } +static void +aclLookupIdentDone(const char *ident, void *data) +{ + aclCheck_t *checklist = data; + if (ident) { + xstrncpy(checklist->ident, ident, sizeof(checklist->ident)); + xstrncpy(checklist->request->user_ident, ident, sizeof(checklist->request->user_ident)); + } else { + xstrncpy(checklist->ident, "-", sizeof(checklist->ident)); + } + /* Cache the ident result in the connection, to avoid redoing ident lookup + * over and over on persistent connections + */ + if (cbdataValid(checklist->conn) && !*checklist->conn->ident) + xstrncpy(checklist->conn->ident, checklist->ident, sizeof(checklist->conn->ident)); + aclCheck(checklist); +} + static void aclLookupDstIPDone(const ipcache_addrs * ia, void *data) { diff --git a/src/cf.data.pre b/src/cf.data.pre index bab4c6a37e..f0f46fbacb 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.134 1999/01/22 19:07:03 glenn Exp $ +# $Id: cf.data.pre,v 1.135 1999/01/24 02:22:54 wessels Exp $ # # # SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -1351,6 +1351,18 @@ DOC_START pconn_timeout 120 seconds DOC_END +NAME: ident_timeout +TYPE: time_t +LOC: Config.Timeout.ident +DEFAULT: 10 seconds +DOC_START + Maximum time to wait for IDENT requests. If this is too high, + and you enabled 'ident_lookup', then you might be susceptible + to denial-of-service by having many ident requests going at + once. +ident_timeout 10 seconds +DOC_END + NAME: shutdown_lifetime COMMENT: time-units diff --git a/src/client_side.cc b/src/client_side.cc index b97003ecf3..103ad2e160 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1,6 +1,6 @@ /* - * $Id: client_side.cc,v 1.434 1999/01/21 23:58:43 wessels Exp $ + * $Id: client_side.cc,v 1.435 1999/01/24 02:22:56 wessels Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -74,6 +74,7 @@ static RH clientRedirectDone; static STCB clientHandleIMSReply; static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request); static int checkAccelOnly(clientHttpRequest *); +static IDCB clientIdentDone; static int clientOnlyIfCached(clientHttpRequest * http); static STCB clientSendMoreData; static STCB clientCacheHit; @@ -104,16 +105,22 @@ checkAccelOnly(clientHttpRequest * http) return 1; } +void +clientIdentDone(const char *ident, void *data) +{ + ConnStateData *conn = data; + if (ident) + xstrncpy(conn->ident, ident, sizeof(conn->ident)); + else + xstrncpy(conn->ident, "-", sizeof(conn->ident)); +} + void clientAccessCheck(void *data) { clientHttpRequest *http = data; ConnStateData *conn = http->conn; const char *browser; - if (Config.onoff.ident_lookup && conn->ident.state == IDENT_NONE) { - identStart(-1, conn, clientAccessCheck, http); - return; - } if (checkAccelOnly(http)) { clientAccessCheckDone(0, http); return; @@ -123,7 +130,12 @@ clientAccessCheck(void *data) http->request, conn->peer.sin_addr, browser, - conn->ident.ident); + conn->ident); + /* hack for ident ACL. It needs to get full addresses, and a + * place to store the ident result on persistent connections... + */ + http->acl_checklist->conn = conn; + cbdataLock(http->acl_checklist->conn); aclNBCheck(http->acl_checklist, clientAccessCheckDone, http); } @@ -611,7 +623,7 @@ httpRequestFree(void *data) if (request->user_ident[0]) http->al.cache.ident = request->user_ident; else - http->al.cache.ident = conn->ident.ident; + http->al.cache.ident = conn->ident; if (request) { Packer p; MemBuf mb; @@ -680,8 +692,6 @@ connStateFree(int fd, void *data) assert(connState->chr != connState->chr->next); httpRequestFree(http); } - if (connState->ident.fd > -1) - comm_close(connState->ident.fd); safe_free(connState->in.buf); /* XXX account connState->in.buf */ pconnHistCount(0, connState->nrequests); @@ -2411,7 +2421,6 @@ httpAccept(int sock, void *data) connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; connState->me = me; connState->fd = fd; - connState->ident.fd = -1; connState->in.size = REQUEST_BUF_SIZE; connState->in.buf = xcalloc(connState->in.size, 1); cbdataAdd(connState, cbdataXfree, 0); @@ -2420,6 +2429,8 @@ httpAccept(int sock, void *data) if (Config.onoff.log_fqdn) fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); commSetTimeout(fd, Config.Timeout.request, requestTimeout, connState); + if (Config.onoff.ident_lookup) + identStart(&me, &peer, clientIdentDone, connState); commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, connState, 0); commSetDefer(fd, clientReadDefer, connState); (*N)++; diff --git a/src/ident.cc b/src/ident.cc index 360bfda43a..1bb14e8bff 100644 --- a/src/ident.cc +++ b/src/ident.cc @@ -1,6 +1,6 @@ /* - * $Id: ident.cc,v 1.46 1998/12/04 22:20:17 wessels Exp $ + * $Id: ident.cc,v 1.47 1999/01/24 02:22:57 wessels Exp $ * * DEBUG: section 30 Ident (RFC 931) * AUTHOR: Duane Wessels @@ -36,112 +36,202 @@ #include "squid.h" #define IDENT_PORT 113 +#define IDENT_KEY_SZ 50 + +typedef struct _IdentClient { + IDCB *callback; + void *callback_data; + struct _IdentClient *next; +} IdentClient; + +typedef struct _IdentStateData { + char *key; + struct _IdentStateData *next; + int fd; /* IDENT fd */ + struct sockaddr_in me; + struct sockaddr_in peer; + IdentClient *clients; +} IdentStateData; static PF identReadReply; static PF identClose; static PF identTimeout; static CNCB identConnectDone; -static void identCallback(ConnStateData * connState); +static hash_table *ident_hash = NULL; +static void identClientAdd(IdentStateData *, IDCB *, void *); + +/**** PRIVATE FUNCTIONS ****/ + +static void +identCallback(IdentStateData * state, char *result) +{ + IdentClient *client; + if (result && *result == '\0') + result = NULL; + while ((client = state->clients)) { + state->clients = client->next; + if (cbdataValid(client->callback_data)) + client->callback(result, client->callback_data); + cbdataUnlock(client->callback_data); + xfree(client); + } +} static void identClose(int fdnotused, void *data) { - ConnStateData *connState = data; - connState->ident.fd = -1; + IdentStateData *state = data; + identCallback(state, NULL); + comm_close(state->fd); + hash_remove_link(ident_hash, (hash_link *) state); + cbdataFree(state); } static void identTimeout(int fd, void *data) { - ConnStateData *connState = data; + IdentStateData *state = data; debug(30, 3) ("identTimeout: FD %d, %s\n", fd, - inet_ntoa(connState->peer.sin_addr)); + inet_ntoa(state->peer.sin_addr)); comm_close(fd); } -/* start a TCP connection to the peer host on port 113 */ -void -identStart(int fd, ConnStateData * connState, IDCB * callback, void *data) -{ - connState->ident.callback = callback; - connState->ident.callback_data = data; - connState->ident.state = IDENT_PENDING; - if (fd < 0) { - fd = comm_open(SOCK_STREAM, - 0, - connState->me.sin_addr, - 0, - COMM_NONBLOCKING, - "ident"); - if (fd == COMM_ERROR) { - identCallback(connState); - return; - } - } - connState->ident.fd = fd; - comm_add_close_handler(fd, - identClose, - connState); - commConnectStart(fd, - inet_ntoa(connState->peer.sin_addr), - IDENT_PORT, - identConnectDone, - connState); -} - static void identConnectDone(int fd, int status, void *data) { - ConnStateData *connState = data; + IdentStateData *state = data; + IdentClient *c; MemBuf mb; if (status != COMM_OK) { + /* Failed to connect */ comm_close(fd); - identCallback(connState); return; } + /* + * see if our clients still care + */ + for (c = state->clients; c; c = c->next) { + if (cbdataValid(c->callback_data)) + break; + } + if (c == NULL) /* no clients care */ + comm_close(fd); memBufDefInit(&mb); memBufPrintf(&mb, "%d, %d\r\n", - ntohs(connState->peer.sin_port), - ntohs(connState->me.sin_port)); - comm_write_mbuf(fd, mb, NULL, connState); - commSetSelect(fd, COMM_SELECT_READ, identReadReply, connState, 0); - commSetTimeout(fd, Config.Timeout.read, identTimeout, connState); + ntohs(state->peer.sin_port), + ntohs(state->me.sin_port)); + comm_write_mbuf(fd, mb, NULL, state); + commSetSelect(fd, COMM_SELECT_READ, identReadReply, state, 0); + commSetTimeout(fd, Config.Timeout.ident, identTimeout, state); } static void identReadReply(int fd, void *data) { - ConnStateData *connState = data; + IdentStateData *state = data; LOCAL_ARRAY(char, buf, BUFSIZ); + char *ident = NULL; char *t = NULL; int len = -1; - buf[0] = '\0'; Counter.syscalls.sock.reads++; len = read(fd, buf, BUFSIZ - 1); fd_bytes(fd, len, FD_READ); - if (len > 0) { - buf[len] = '\0'; - if ((t = strchr(buf, '\r'))) - *t = '\0'; - if ((t = strchr(buf, '\n'))) - *t = '\0'; - debug(30, 5) ("identReadReply: FD %d: Read '%s'\n", fd, buf); - if (strstr(buf, "USERID")) { - if ((t = strrchr(buf, ':'))) { - while (isspace(*++t)); - xstrncpy(connState->ident.ident, t, USER_IDENT_SZ); - } + if (len <= 0) { + comm_close(fd); + return; + } + /* + * XXX This isn't really very tolerant. It should read until EOL + * or EOF and then decode the answer... If the reply is fragmented + * then this will fail + */ + buf[len] = '\0'; + if ((t = strchr(buf, '\r'))) + *t = '\0'; + if ((t = strchr(buf, '\n'))) + *t = '\0'; + debug(30, 5) ("identReadReply: FD %d: Read '%s'\n", fd, buf); + if (strstr(buf, "USERID")) { + if ((ident = strrchr(buf, ':'))) { + while (isspace(*++ident)); + identCallback(state, ident); } } comm_close(fd); - identCallback(connState); } + static void -identCallback(ConnStateData * connState) +identClientAdd(IdentStateData * state, IDCB * callback, void *callback_data) +{ + IdentClient *c = xcalloc(1, sizeof(*c)); + IdentClient **C; + c->callback = callback; + c->callback_data = callback_data; + cbdataLock(callback_data); + for (C = &state->clients; *C; C = &(*C)->next); + *C = c; +} + +/**** PUBLIC FUNCTIONS ****/ + +/* + * start a TCP connection to the peer host on port 113 + */ +void +identStart(struct sockaddr_in *me, struct sockaddr_in *peer, IDCB * callback, void *data) +{ + IdentStateData *state; + int fd; + char key1[IDENT_KEY_SZ]; + char key2[IDENT_KEY_SZ]; + char key[IDENT_KEY_SZ]; + snprintf(key1, IDENT_KEY_SZ, "%s:%d", + inet_ntoa(me->sin_addr), + ntohs(me->sin_port)); + snprintf(key2, IDENT_KEY_SZ, "%s:%d", + inet_ntoa(peer->sin_addr), + ntohs(peer->sin_port)); + snprintf(key, IDENT_KEY_SZ, "%s,%s", key1, key2); + if ((state = hash_lookup(ident_hash, key)) != NULL) { + identClientAdd(state, callback, data); + return; + } + fd = comm_open(SOCK_STREAM, + 0, + me->sin_addr, + 0, + COMM_NONBLOCKING, + "ident"); + if (fd == COMM_ERROR) { + /* Failed to get a local socket */ + callback(NULL, data); + return; + } + state = xcalloc(1, sizeof(IdentStateData)); + cbdataAdd(state, cbdataXfree, 0); + state->key = xstrdup(key); + state->fd = fd; + state->me = *me; + state->peer = *peer; + identClientAdd(state, callback, data); + hash_join(ident_hash, (hash_link *) state); + comm_add_close_handler(fd, + identClose, + state); + commSetTimeout(fd, Config.Timeout.ident, identTimeout, state); + commConnectStart(fd, + inet_ntoa(state->peer.sin_addr), + IDENT_PORT, + identConnectDone, + state); +} + +void +identInit(void) { - connState->ident.state = IDENT_DONE; - if (connState->ident.callback) - connState->ident.callback(connState->ident.callback_data); + ident_hash = hash_create((HASHCMP *) strcmp, + hashPrime(Squid_MaxFD / 8), + hash4); } diff --git a/src/main.cc b/src/main.cc index 1dce1b8063..982eee15b7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,6 +1,6 @@ /* - * $Id: main.cc,v 1.288 1999/01/22 19:07:04 glenn Exp $ + * $Id: main.cc,v 1.289 1999/01/24 02:22:57 wessels Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -413,6 +413,7 @@ mainInitialize(void) httpReplyInitModule(); /* must go before accepting replies */ errorInitialize(); accessLogInit(); + identInit(); #ifdef SQUID_SNMP snmpInit(); #endif diff --git a/src/protos.h b/src/protos.h index 53e4ce169b..4c603411a1 100644 --- a/src/protos.h +++ b/src/protos.h @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.310 1999/01/22 19:07:05 glenn Exp $ + * $Id: protos.h,v 1.311 1999/01/24 02:22:58 wessels Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -683,7 +683,10 @@ extern void shut_down(int); extern void start_announce(void *unused); extern void sslStart(int fd, const char *, request_t *, size_t * sz); extern void waisStart(FwdState *); -extern void identStart(int, ConnStateData *, IDCB * callback, void *); + +/* ident.c */ +extern void identStart(struct sockaddr_in *me, struct sockaddr_in *peer, IDCB * callback, void *cbdata); +extern void identInit(void); extern void statInit(void); extern void statFreeMemory(void); diff --git a/src/redirect.cc b/src/redirect.cc index f858916490..68c342fc95 100644 --- a/src/redirect.cc +++ b/src/redirect.cc @@ -1,6 +1,6 @@ /* - * $Id: redirect.cc,v 1.77 1998/12/05 00:54:38 wessels Exp $ + * $Id: redirect.cc,v 1.78 1999/01/24 02:22:59 wessels Exp $ * * DEBUG: section 29 Redirector * AUTHOR: Duane Wessels @@ -103,10 +103,10 @@ redirectStart(clientHttpRequest * http, RH * handler, void *data) cbdataAdd(r, cbdataXfree, 0); r->orig_url = xstrdup(http->uri); r->client_addr = conn->log_addr; - if (conn->ident.ident == NULL || *conn->ident.ident == '\0') { + if (conn->ident == NULL || *conn->ident == '\0') { r->client_ident = dash_str; } else { - r->client_ident = conn->ident.ident; + r->client_ident = conn->ident; } r->method_s = RequestMethodStr[http->request->method]; r->handler = handler; diff --git a/src/structs.h b/src/structs.h index 9c9b4b2ea8..ed9f929eee 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1,7 +1,7 @@ /* - * $Id: structs.h,v 1.268 1999/01/22 19:07:06 glenn Exp $ + * $Id: structs.h,v 1.269 1999/01/24 02:22:59 wessels Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -142,6 +142,7 @@ struct _aclCheck_t { const acl_access *access_list; struct in_addr src_addr; struct in_addr dst_addr; + ConnStateData *conn; /* hack for ident */ request_t *request; char ident[USER_IDENT_SZ]; char browser[BROWSERNAMELEN]; @@ -226,6 +227,7 @@ struct _SquidConfig { time_t deadPeer; int icp_query; /* msec */ int mcast_icp_query; /* msec */ + time_t ident; } Timeout; size_t maxRequestSize; struct { @@ -822,13 +824,7 @@ struct _ConnStateData { struct sockaddr_in peer; struct sockaddr_in me; struct in_addr log_addr; - struct { - int fd; - char ident[USER_IDENT_SZ]; - IDCB *callback; - int state; - void *callback_data; - } ident; + char ident[USER_IDENT_SZ]; int nrequests; int persistent; struct { diff --git a/src/typedefs.h b/src/typedefs.h index 0f2dbfaa61..d183022bbc 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.84 1999/01/11 21:55:45 wessels Exp $ + * $Id: typedefs.h,v 1.85 1999/01/24 02:23:00 wessels Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -180,7 +180,7 @@ typedef void PF(int, void *); typedef void DRCB(int fd, const char *buf, int size, int errflag, void *data); typedef void DWCB(int, int, size_t, void *); typedef void FQDNH(const char *, void *); -typedef void IDCB(void *); +typedef void IDCB(const char *ident, void *data); typedef void IPH(const ipcache_addrs *, void *); typedef void IRCB(peer *, peer_t, protocol_t, void *, void *data); typedef void PSC(FwdServer *, void *);