]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
patch that combines client-side informational IDENT lookups with
authorwessels <>
Sun, 24 Jan 1999 09:22:53 +0000 (09:22 +0000)
committerwessels <>
Sun, 24 Jan 1999 09:22:53 +0000 (09:22 +0000)
ACL "required" lookups.  initial patch from henrik

src/acl.cc
src/cf.data.pre
src/client_side.cc
src/ident.cc
src/main.cc
src/protos.h
src/redirect.cc
src/structs.h
src/typedefs.h

index b14ece1cecc3aaf2505bc30740301b7a3b34b38e..fdf78f32b1bf2ec306451ae21e17924b9f0bdc8d 100644 (file)
@@ -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)
 {
index bab4c6a37e804f54036c42097e77751ff7d72bb1..f0f46fbacb6c1d19be6eb580b5792a6db26d3349 100644 (file)
@@ -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
index b97003ecf3686d880433d0ee0b7f62c7a913c7de..103ad2e16039e2a0a03daad4ef62bf533d53d003 100644 (file)
@@ -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)++;
index 360bfda43a17a175c2f8ea32ea5911191e79598f..1bb14e8bff7a2469e47ce99107d26ca7c1a71028 100644 (file)
@@ -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
 #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);
 }
index 1dce1b8063cb5d9cdb7c4ee0f1e4f55844543e61..982eee15b720d93af182c14b559245829c99d320 100644 (file)
@@ -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
index 53e4ce169b0c8a02e423744ffcf600c232e723bc..4c603411a1ca6fd294851ddc75e36f02c43cac96 100644 (file)
@@ -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);
index f85891649049129a947dd7746cb81bf9e5f86608..68c342fc95c273cc241ef71e60193d41ea92dfde 100644 (file)
@@ -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;
index 9c9b4b2ea8418930766fb1bd9ab34210382bcb13..ed9f929eee6f33e33f12b6f405de5e0e2033e55c 100644 (file)
@@ -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 {
index 0f2dbfaa613fa23ffa5b749e644a1ce576b61094..d183022bbc8751856ab904466be9779e3acfd046 100644 (file)
@@ -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 *);