From: wessels <> Date: Tue, 18 Aug 1998 08:56:42 +0000 (+0000) Subject: adding X-Git-Tag: SQUID_3_0_PRE1~2863 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1d62076534634576e2979da61bbdbc7ae4d498fd;p=thirdparty%2Fsquid.git adding --- diff --git a/src/authenticate.cc b/src/authenticate.cc new file mode 100644 index 0000000000..158ef85d1f --- /dev/null +++ b/src/authenticate.cc @@ -0,0 +1,456 @@ + +/* + * $Id: authenticate.cc,v 1.1 1998/08/18 02:56:42 wessels Exp $ + * + * DEBUG: section 29 Authenticator + * AUTHOR: Duane Wessels + * + * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from the + * Internet community. Development is led by Duane Wessels of the + * National Laboratory for Applied Network Research and funded by the + * National Science Foundation. Squid is Copyrighted (C) 1998 by + * Duane Wessels and the University of California San Diego. Please + * see the COPYRIGHT file for full details. Squid incorporates + * software developed and/or copyrighted by other sources. Please see + * the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +typedef struct { + void *data; + acl_proxy_auth_user *auth_user; + RH *handler; +} authenticateStateData; + +typedef struct _authenticator { + int index; + int flags; + int fd; + char *inbuf; + unsigned int size; + unsigned int offset; + struct timeval dispatch_time; + authenticateStateData *authenticateState; +} authenticator_t; + +static struct { + int requests; + int replies; + int errors; + int avg_svc_time; + int queue_size; + int use_hist[DefaultAuthenticateChildrenMax]; + int rewrites[DefaultAuthenticateChildrenMax]; +} AuthenticateStats; + + +struct authenticateQueueData { + struct authenticateQueueData *next; + authenticateStateData *authenticateState; +}; + +static authenticator_t *GetFirstAvailable(void); +static PF authenticateHandleRead; +static authenticateStateData *Dequeue(void); +static void Enqueue(authenticateStateData *); +static void authenticateDispatch(authenticator_t *, authenticateStateData *); +static void authenticateStateFree(authenticateStateData * r); + +static authenticator_t **authenticate_child_table = NULL; +static int NAuthenticators = 0; +static int NAuthenticatorsOpen = 0; +static struct authenticateQueueData *authenticateQueueHead = NULL; +static struct authenticateQueueData **authenticateQueueTailP = &authenticateQueueHead; + +static void +authenticateHandleRead(int fd, void *data) +{ + authenticator_t *authenticator = data; + int len; + authenticateStateData *r = authenticator->authenticateState; + char *t = NULL; + int n; + + len = read(fd, + authenticator->inbuf + authenticator->offset, + authenticator->size - authenticator->offset); + fd_bytes(fd, len, FD_READ); + debug(29, 5) ("authenticateHandleRead: %d bytes from Authenticator #%d.\n", + len, authenticator->index + 1); + if (len <= 0) { + if (len < 0) + debug(50, 1) ("authenticateHandleRead: FD %d read: %s\n", fd, xstrerror()); + debug(29, EBIT_TEST(authenticator->flags, HELPER_CLOSING) ? 5 : 1) + ("FD %d: Connection from Authenticator #%d is closed, disabling\n", + fd, authenticator->index + 1); + authenticator->flags = 0; + memFree(MEM_8K_BUF, authenticator->inbuf); + authenticator->inbuf = NULL; + comm_close(fd); + if (--NAuthenticatorsOpen == 0 && !shutting_down) + fatal_dump("All authenticators have exited!"); + return; + } + if (len != 1) + AuthenticateStats.rewrites[authenticator->index]++; + authenticator->offset += len; + authenticator->inbuf[authenticator->offset] = '\0'; + /* reschedule */ + commSetSelect(authenticator->fd, + COMM_SELECT_READ, + authenticateHandleRead, + authenticator, 0); + if ((t = strchr(authenticator->inbuf, '\n'))) { + /* end of record found */ + *t = '\0'; + if ((t = strchr(authenticator->inbuf, ' '))) + *t = '\0'; /* terminate at space */ + if (r == NULL) { + /* A naughty authenticator has spoken without being spoken to */ + /* B.R.Foster@massey.ac.nz, SQUID/1.1.3 */ + debug(29, 0) ("authenticateHandleRead: unexpected reply: '%s'\n", + authenticator->inbuf); + authenticator->offset = 0; + } else { + debug(29, 5) ("authenticateHandleRead: reply: '%s'\n", + authenticator->inbuf); + /* careful here. r->data might point to something which + * has recently been freed. If so, we require that r->handler + * be NULL */ + if (r->handler) { + r->handler(r->data, + t == authenticator->inbuf ? NULL : authenticator->inbuf); + } + authenticateStateFree(r); + authenticator->authenticateState = NULL; + EBIT_CLR(authenticator->flags, HELPER_BUSY); + authenticator->offset = 0; + n = ++AuthenticateStats.replies; + AuthenticateStats.avg_svc_time = + intAverage(AuthenticateStats.avg_svc_time, + tvSubMsec(authenticator->dispatch_time, current_time), + n, AUTHENTICATE_AV_FACTOR); + } + } + while ((authenticator = GetFirstAvailable()) && (r = Dequeue())) + authenticateDispatch(authenticator, r); +} + +static void +Enqueue(authenticateStateData * r) +{ + struct authenticateQueueData *new = xcalloc(1, sizeof(struct authenticateQueueData)); + new->authenticateState = r; + *authenticateQueueTailP = new; + authenticateQueueTailP = &new->next; + AuthenticateStats.queue_size++; +} + +static authenticateStateData * +Dequeue(void) +{ + struct authenticateQueueData *old = NULL; + authenticateStateData *r = NULL; + if (authenticateQueueHead) { + r = authenticateQueueHead->authenticateState; + old = authenticateQueueHead; + authenticateQueueHead = authenticateQueueHead->next; + if (authenticateQueueHead == NULL) + authenticateQueueTailP = &authenticateQueueHead; + safe_free(old); + AuthenticateStats.queue_size--; + } + return r; +} + +static authenticator_t * +GetFirstAvailable(void) +{ + int k; + authenticator_t *authenticate = NULL; + for (k = 0; k < NAuthenticators; k++) { + authenticate = *(authenticate_child_table + k); + if (EBIT_TEST(authenticate->flags, HELPER_BUSY)) + continue; + if (!EBIT_TEST(authenticate->flags, HELPER_ALIVE)) + continue; + return authenticate; + } + return NULL; +} + +static void +authenticateStateFree(authenticateStateData * r) +{ + safe_free(r); +} + + +static void +authenticateDispatch(authenticator_t * authenticate, authenticateStateData * r) +{ + char *buf = NULL; + int len; + if (r->handler == NULL) { + debug(29, 1) ("authenticateDispatch: skipping '%s' because no handler\n", + r->auth_user->user); + authenticateStateFree(r); + return; + } + EBIT_SET(authenticate->flags, HELPER_BUSY); + authenticate->authenticateState = r; + authenticate->dispatch_time = current_time; + buf = memAllocate(MEM_8K_BUF); + snprintf(buf, 8192, "%s %s\n", + r->auth_user->user, + r->auth_user->passwd); + len = strlen(buf); + comm_write(authenticate->fd, + buf, + len, + NULL, /* Handler */ + NULL, /* Handler-data */ + memFree8K); + debug(29, 5) ("authenticateDispatch: Request sent to Authenticator #%d, %d bytes\n", + authenticate->index + 1, len); + AuthenticateStats.use_hist[authenticate->index]++; + AuthenticateStats.requests++; +} + + +/**** PUBLIC FUNCTIONS ****/ + + +void +authenticateStart(acl_proxy_auth_user * auth_user, RH * handler, void *data) +{ + authenticateStateData *r = NULL; + authenticator_t *authenticator = NULL; + if (!auth_user) + fatal_dump("authenticateStart: NULL auth_user"); + if (!handler) + fatal_dump("authenticateStart: NULL handler"); + debug(29, 5) ("authenticateStart: '%s:%s'\n", auth_user->user, + auth_user->passwd); + if (Config.Program.authenticate == NULL) { + handler(data, NULL); + return; + } + r = xcalloc(1, sizeof(authenticateStateData)); + r->handler = handler; + r->data = data; + r->auth_user = auth_user; + if ((authenticator = GetFirstAvailable())) + authenticateDispatch(authenticator, r); + else + Enqueue(r); +} + +void +authenticateFreeMemory(void) +{ + int k; + /* free old structures if present */ + if (authenticate_child_table) { + for (k = 0; k < NAuthenticators; k++) { + if (authenticate_child_table[k]->inbuf) + memFree(MEM_8K_BUF, authenticate_child_table[k]->inbuf); + safe_free(authenticate_child_table[k]); + } + safe_free(authenticate_child_table); + } +} + +void +authenticateOpenServers(void) +{ + char *prg; + wordlist *auth_opts; + char *short_prg; + char *short_prg2; + int k; + int authenticatesocket; + LOCAL_ARRAY(char, fd_note_buf, FD_DESC_SZ); + static int first_time = 0; + char *s; + char *args[32]; + int i, x; + + authenticateFreeMemory(); + if (Config.Program.authenticate == NULL) + return; + prg = Config.Program.authenticate->key; + NAuthenticators = NAuthenticatorsOpen = Config.authenticateChildren; + authenticate_child_table = xcalloc(NAuthenticators, sizeof(authenticator_t *)); + debug(29, 1) ("authenticateOpenServers: Starting %d '%s' processes\n", + NAuthenticators, prg); + if ((s = strrchr(prg, '/'))) + short_prg = xstrdup(s + 1); + else + short_prg = xstrdup(prg); + short_prg2 = xmalloc(strlen(s) + 3); + snprintf(short_prg2, strlen(s) + 3, "(%s)", short_prg); + for (k = 0; k < NAuthenticators; k++) { + authenticate_child_table[k] = xcalloc(1, sizeof(authenticator_t)); + args[0] = short_prg2; + i = 1; + auth_opts = Config.Program.authenticate->next; + while ((auth_opts != NULL) && (i < 31)) { + args[i++] = auth_opts->key; + auth_opts = auth_opts->next; + } + if (auth_opts != NULL) { + debug(29, 0) ("WARNING: too many authenticate_options\n"); + } + args[i] = NULL; + x = ipcCreate(IPC_TCP_SOCKET, + prg, + args, + "authenticator", + &authenticatesocket, + &authenticatesocket); + if (x < 0) { + debug(29, 1) ("WARNING: Cannot run '%s' process.\n", prg); + EBIT_CLR(authenticate_child_table[k]->flags, HELPER_ALIVE); + } else { + EBIT_SET(authenticate_child_table[k]->flags, HELPER_ALIVE); + authenticate_child_table[k]->index = k; + authenticate_child_table[k]->fd = authenticatesocket; + authenticate_child_table[k]->inbuf = memAllocate(MEM_8K_BUF); + authenticate_child_table[k]->size = 8192; + authenticate_child_table[k]->offset = 0; + snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", + short_prg, + authenticate_child_table[k]->index + 1); + fd_note(authenticate_child_table[k]->fd, fd_note_buf); + commSetNonBlocking(authenticate_child_table[k]->fd); + /* set handler for incoming result */ + commSetSelect(authenticate_child_table[k]->fd, + COMM_SELECT_READ, + authenticateHandleRead, + authenticate_child_table[k], 0); + debug(29, 3) ("authenticateOpenServers: 'authenticate_server' %d started\n", + k); + } + } + if (first_time == 0) { + first_time++; + memset(&AuthenticateStats, '\0', sizeof(AuthenticateStats)); + cachemgrRegister("authenticator", + "Authenticator Stats", + authenticateStats, 0, 1); + } + safe_free(short_prg); + safe_free(short_prg2); +} + +void +authenticateShutdownServers(void *unused) +{ + authenticator_t *authenticate = NULL; + authenticateStateData *r = NULL; + int k; + int na = 0; + if (Config.Program.authenticate == NULL) + return; + if (authenticateQueueHead) { + while ((authenticate = GetFirstAvailable()) && (r = Dequeue())) + authenticateDispatch(authenticate, r); + return; + } + for (k = 0; k < NAuthenticators; k++) { + authenticate = *(authenticate_child_table + k); + if (!EBIT_TEST(authenticate->flags, HELPER_ALIVE)) + continue; + if (EBIT_TEST(authenticate->flags, HELPER_CLOSING)) + continue; + if (EBIT_TEST(authenticate->flags, HELPER_BUSY)) { + na++; + continue; + } + debug(29, 3) ("authenticateShutdownServers: closing authenticator #%d, FD %d\n", + authenticate->index + 1, authenticate->fd); + comm_close(authenticate->fd); + EBIT_SET(authenticate->flags, HELPER_CLOSING); + EBIT_SET(authenticate->flags, HELPER_BUSY); + } + if (na) + eventAdd("authenticateShutdownServers", authenticateShutdownServers, NULL, 1.0, 1); +} + +int +authenticateUnregister(const char *url, void *data) +{ + authenticator_t *authenticate = NULL; + authenticateStateData *r = NULL; + struct authenticateQueueData *rq = NULL; + int k; + int n = 0; + if (Config.Program.authenticate == NULL) + return 0; + debug(29, 3) ("authenticateUnregister: '%s'\n", url); + for (k = 0; k < NAuthenticators; k++) { + authenticate = *(authenticate_child_table + k); + if ((r = authenticate->authenticateState) == NULL) + continue; + if (r->data != data) + continue; + debug(29, 3) ("authenticateUnregister: Found match\n"); + r->handler = NULL; + n++; + } + for (rq = authenticateQueueHead; rq; rq = rq->next) { + if ((r = rq->authenticateState) == NULL) + continue; + if (r->data != data) + continue; + debug(29, 3) ("authenticateUnregister: Found match.\n"); + r->handler = NULL; + n++; + } + debug(29, 3) ("authenticateUnregister: Unregistered %d handlers\n", n); + return n; +} + +void +authenticateStats(StoreEntry * sentry) +{ + int k; + storeAppendPrintf(sentry, "Authenticator Statistics:\n"); + storeAppendPrintf(sentry, "requests: %d\n", + AuthenticateStats.requests); + storeAppendPrintf(sentry, "replies: %d\n", + AuthenticateStats.replies); + storeAppendPrintf(sentry, "queue length: %d\n", + AuthenticateStats.queue_size); + storeAppendPrintf(sentry, "avg service time: %d msec\n", + AuthenticateStats.avg_svc_time); + storeAppendPrintf(sentry, "number of authenticators: %d\n", + NAuthenticators); + storeAppendPrintf(sentry, "use histogram:\n"); + for (k = 0; k < NAuthenticators; k++) { + storeAppendPrintf(sentry, " authenticator #%d: %d (%d requests)\n", + k + 1, + AuthenticateStats.use_hist[k], + AuthenticateStats.rewrites[k]); + } +}