]>
Commit | Line | Data |
---|---|---|
1d620765 | 1 | |
2 | /* | |
3 | * $Id: authenticate.cc,v 1.1 1998/08/18 02:56:42 wessels Exp $ | |
4 | * | |
5 | * DEBUG: section 29 Authenticator | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
9 | * ---------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by the | |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * the CREDITS file for full details. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
33 | * | |
34 | */ | |
35 | ||
36 | #include "squid.h" | |
37 | ||
38 | typedef struct { | |
39 | void *data; | |
40 | acl_proxy_auth_user *auth_user; | |
41 | RH *handler; | |
42 | } authenticateStateData; | |
43 | ||
44 | typedef struct _authenticator { | |
45 | int index; | |
46 | int flags; | |
47 | int fd; | |
48 | char *inbuf; | |
49 | unsigned int size; | |
50 | unsigned int offset; | |
51 | struct timeval dispatch_time; | |
52 | authenticateStateData *authenticateState; | |
53 | } authenticator_t; | |
54 | ||
55 | static struct { | |
56 | int requests; | |
57 | int replies; | |
58 | int errors; | |
59 | int avg_svc_time; | |
60 | int queue_size; | |
61 | int use_hist[DefaultAuthenticateChildrenMax]; | |
62 | int rewrites[DefaultAuthenticateChildrenMax]; | |
63 | } AuthenticateStats; | |
64 | ||
65 | ||
66 | struct authenticateQueueData { | |
67 | struct authenticateQueueData *next; | |
68 | authenticateStateData *authenticateState; | |
69 | }; | |
70 | ||
71 | static authenticator_t *GetFirstAvailable(void); | |
72 | static PF authenticateHandleRead; | |
73 | static authenticateStateData *Dequeue(void); | |
74 | static void Enqueue(authenticateStateData *); | |
75 | static void authenticateDispatch(authenticator_t *, authenticateStateData *); | |
76 | static void authenticateStateFree(authenticateStateData * r); | |
77 | ||
78 | static authenticator_t **authenticate_child_table = NULL; | |
79 | static int NAuthenticators = 0; | |
80 | static int NAuthenticatorsOpen = 0; | |
81 | static struct authenticateQueueData *authenticateQueueHead = NULL; | |
82 | static struct authenticateQueueData **authenticateQueueTailP = &authenticateQueueHead; | |
83 | ||
84 | static void | |
85 | authenticateHandleRead(int fd, void *data) | |
86 | { | |
87 | authenticator_t *authenticator = data; | |
88 | int len; | |
89 | authenticateStateData *r = authenticator->authenticateState; | |
90 | char *t = NULL; | |
91 | int n; | |
92 | ||
93 | len = read(fd, | |
94 | authenticator->inbuf + authenticator->offset, | |
95 | authenticator->size - authenticator->offset); | |
96 | fd_bytes(fd, len, FD_READ); | |
97 | debug(29, 5) ("authenticateHandleRead: %d bytes from Authenticator #%d.\n", | |
98 | len, authenticator->index + 1); | |
99 | if (len <= 0) { | |
100 | if (len < 0) | |
101 | debug(50, 1) ("authenticateHandleRead: FD %d read: %s\n", fd, xstrerror()); | |
102 | debug(29, EBIT_TEST(authenticator->flags, HELPER_CLOSING) ? 5 : 1) | |
103 | ("FD %d: Connection from Authenticator #%d is closed, disabling\n", | |
104 | fd, authenticator->index + 1); | |
105 | authenticator->flags = 0; | |
106 | memFree(MEM_8K_BUF, authenticator->inbuf); | |
107 | authenticator->inbuf = NULL; | |
108 | comm_close(fd); | |
109 | if (--NAuthenticatorsOpen == 0 && !shutting_down) | |
110 | fatal_dump("All authenticators have exited!"); | |
111 | return; | |
112 | } | |
113 | if (len != 1) | |
114 | AuthenticateStats.rewrites[authenticator->index]++; | |
115 | authenticator->offset += len; | |
116 | authenticator->inbuf[authenticator->offset] = '\0'; | |
117 | /* reschedule */ | |
118 | commSetSelect(authenticator->fd, | |
119 | COMM_SELECT_READ, | |
120 | authenticateHandleRead, | |
121 | authenticator, 0); | |
122 | if ((t = strchr(authenticator->inbuf, '\n'))) { | |
123 | /* end of record found */ | |
124 | *t = '\0'; | |
125 | if ((t = strchr(authenticator->inbuf, ' '))) | |
126 | *t = '\0'; /* terminate at space */ | |
127 | if (r == NULL) { | |
128 | /* A naughty authenticator has spoken without being spoken to */ | |
129 | /* B.R.Foster@massey.ac.nz, SQUID/1.1.3 */ | |
130 | debug(29, 0) ("authenticateHandleRead: unexpected reply: '%s'\n", | |
131 | authenticator->inbuf); | |
132 | authenticator->offset = 0; | |
133 | } else { | |
134 | debug(29, 5) ("authenticateHandleRead: reply: '%s'\n", | |
135 | authenticator->inbuf); | |
136 | /* careful here. r->data might point to something which | |
137 | * has recently been freed. If so, we require that r->handler | |
138 | * be NULL */ | |
139 | if (r->handler) { | |
140 | r->handler(r->data, | |
141 | t == authenticator->inbuf ? NULL : authenticator->inbuf); | |
142 | } | |
143 | authenticateStateFree(r); | |
144 | authenticator->authenticateState = NULL; | |
145 | EBIT_CLR(authenticator->flags, HELPER_BUSY); | |
146 | authenticator->offset = 0; | |
147 | n = ++AuthenticateStats.replies; | |
148 | AuthenticateStats.avg_svc_time = | |
149 | intAverage(AuthenticateStats.avg_svc_time, | |
150 | tvSubMsec(authenticator->dispatch_time, current_time), | |
151 | n, AUTHENTICATE_AV_FACTOR); | |
152 | } | |
153 | } | |
154 | while ((authenticator = GetFirstAvailable()) && (r = Dequeue())) | |
155 | authenticateDispatch(authenticator, r); | |
156 | } | |
157 | ||
158 | static void | |
159 | Enqueue(authenticateStateData * r) | |
160 | { | |
161 | struct authenticateQueueData *new = xcalloc(1, sizeof(struct authenticateQueueData)); | |
162 | new->authenticateState = r; | |
163 | *authenticateQueueTailP = new; | |
164 | authenticateQueueTailP = &new->next; | |
165 | AuthenticateStats.queue_size++; | |
166 | } | |
167 | ||
168 | static authenticateStateData * | |
169 | Dequeue(void) | |
170 | { | |
171 | struct authenticateQueueData *old = NULL; | |
172 | authenticateStateData *r = NULL; | |
173 | if (authenticateQueueHead) { | |
174 | r = authenticateQueueHead->authenticateState; | |
175 | old = authenticateQueueHead; | |
176 | authenticateQueueHead = authenticateQueueHead->next; | |
177 | if (authenticateQueueHead == NULL) | |
178 | authenticateQueueTailP = &authenticateQueueHead; | |
179 | safe_free(old); | |
180 | AuthenticateStats.queue_size--; | |
181 | } | |
182 | return r; | |
183 | } | |
184 | ||
185 | static authenticator_t * | |
186 | GetFirstAvailable(void) | |
187 | { | |
188 | int k; | |
189 | authenticator_t *authenticate = NULL; | |
190 | for (k = 0; k < NAuthenticators; k++) { | |
191 | authenticate = *(authenticate_child_table + k); | |
192 | if (EBIT_TEST(authenticate->flags, HELPER_BUSY)) | |
193 | continue; | |
194 | if (!EBIT_TEST(authenticate->flags, HELPER_ALIVE)) | |
195 | continue; | |
196 | return authenticate; | |
197 | } | |
198 | return NULL; | |
199 | } | |
200 | ||
201 | static void | |
202 | authenticateStateFree(authenticateStateData * r) | |
203 | { | |
204 | safe_free(r); | |
205 | } | |
206 | ||
207 | ||
208 | static void | |
209 | authenticateDispatch(authenticator_t * authenticate, authenticateStateData * r) | |
210 | { | |
211 | char *buf = NULL; | |
212 | int len; | |
213 | if (r->handler == NULL) { | |
214 | debug(29, 1) ("authenticateDispatch: skipping '%s' because no handler\n", | |
215 | r->auth_user->user); | |
216 | authenticateStateFree(r); | |
217 | return; | |
218 | } | |
219 | EBIT_SET(authenticate->flags, HELPER_BUSY); | |
220 | authenticate->authenticateState = r; | |
221 | authenticate->dispatch_time = current_time; | |
222 | buf = memAllocate(MEM_8K_BUF); | |
223 | snprintf(buf, 8192, "%s %s\n", | |
224 | r->auth_user->user, | |
225 | r->auth_user->passwd); | |
226 | len = strlen(buf); | |
227 | comm_write(authenticate->fd, | |
228 | buf, | |
229 | len, | |
230 | NULL, /* Handler */ | |
231 | NULL, /* Handler-data */ | |
232 | memFree8K); | |
233 | debug(29, 5) ("authenticateDispatch: Request sent to Authenticator #%d, %d bytes\n", | |
234 | authenticate->index + 1, len); | |
235 | AuthenticateStats.use_hist[authenticate->index]++; | |
236 | AuthenticateStats.requests++; | |
237 | } | |
238 | ||
239 | ||
240 | /**** PUBLIC FUNCTIONS ****/ | |
241 | ||
242 | ||
243 | void | |
244 | authenticateStart(acl_proxy_auth_user * auth_user, RH * handler, void *data) | |
245 | { | |
246 | authenticateStateData *r = NULL; | |
247 | authenticator_t *authenticator = NULL; | |
248 | if (!auth_user) | |
249 | fatal_dump("authenticateStart: NULL auth_user"); | |
250 | if (!handler) | |
251 | fatal_dump("authenticateStart: NULL handler"); | |
252 | debug(29, 5) ("authenticateStart: '%s:%s'\n", auth_user->user, | |
253 | auth_user->passwd); | |
254 | if (Config.Program.authenticate == NULL) { | |
255 | handler(data, NULL); | |
256 | return; | |
257 | } | |
258 | r = xcalloc(1, sizeof(authenticateStateData)); | |
259 | r->handler = handler; | |
260 | r->data = data; | |
261 | r->auth_user = auth_user; | |
262 | if ((authenticator = GetFirstAvailable())) | |
263 | authenticateDispatch(authenticator, r); | |
264 | else | |
265 | Enqueue(r); | |
266 | } | |
267 | ||
268 | void | |
269 | authenticateFreeMemory(void) | |
270 | { | |
271 | int k; | |
272 | /* free old structures if present */ | |
273 | if (authenticate_child_table) { | |
274 | for (k = 0; k < NAuthenticators; k++) { | |
275 | if (authenticate_child_table[k]->inbuf) | |
276 | memFree(MEM_8K_BUF, authenticate_child_table[k]->inbuf); | |
277 | safe_free(authenticate_child_table[k]); | |
278 | } | |
279 | safe_free(authenticate_child_table); | |
280 | } | |
281 | } | |
282 | ||
283 | void | |
284 | authenticateOpenServers(void) | |
285 | { | |
286 | char *prg; | |
287 | wordlist *auth_opts; | |
288 | char *short_prg; | |
289 | char *short_prg2; | |
290 | int k; | |
291 | int authenticatesocket; | |
292 | LOCAL_ARRAY(char, fd_note_buf, FD_DESC_SZ); | |
293 | static int first_time = 0; | |
294 | char *s; | |
295 | char *args[32]; | |
296 | int i, x; | |
297 | ||
298 | authenticateFreeMemory(); | |
299 | if (Config.Program.authenticate == NULL) | |
300 | return; | |
301 | prg = Config.Program.authenticate->key; | |
302 | NAuthenticators = NAuthenticatorsOpen = Config.authenticateChildren; | |
303 | authenticate_child_table = xcalloc(NAuthenticators, sizeof(authenticator_t *)); | |
304 | debug(29, 1) ("authenticateOpenServers: Starting %d '%s' processes\n", | |
305 | NAuthenticators, prg); | |
306 | if ((s = strrchr(prg, '/'))) | |
307 | short_prg = xstrdup(s + 1); | |
308 | else | |
309 | short_prg = xstrdup(prg); | |
310 | short_prg2 = xmalloc(strlen(s) + 3); | |
311 | snprintf(short_prg2, strlen(s) + 3, "(%s)", short_prg); | |
312 | for (k = 0; k < NAuthenticators; k++) { | |
313 | authenticate_child_table[k] = xcalloc(1, sizeof(authenticator_t)); | |
314 | args[0] = short_prg2; | |
315 | i = 1; | |
316 | auth_opts = Config.Program.authenticate->next; | |
317 | while ((auth_opts != NULL) && (i < 31)) { | |
318 | args[i++] = auth_opts->key; | |
319 | auth_opts = auth_opts->next; | |
320 | } | |
321 | if (auth_opts != NULL) { | |
322 | debug(29, 0) ("WARNING: too many authenticate_options\n"); | |
323 | } | |
324 | args[i] = NULL; | |
325 | x = ipcCreate(IPC_TCP_SOCKET, | |
326 | prg, | |
327 | args, | |
328 | "authenticator", | |
329 | &authenticatesocket, | |
330 | &authenticatesocket); | |
331 | if (x < 0) { | |
332 | debug(29, 1) ("WARNING: Cannot run '%s' process.\n", prg); | |
333 | EBIT_CLR(authenticate_child_table[k]->flags, HELPER_ALIVE); | |
334 | } else { | |
335 | EBIT_SET(authenticate_child_table[k]->flags, HELPER_ALIVE); | |
336 | authenticate_child_table[k]->index = k; | |
337 | authenticate_child_table[k]->fd = authenticatesocket; | |
338 | authenticate_child_table[k]->inbuf = memAllocate(MEM_8K_BUF); | |
339 | authenticate_child_table[k]->size = 8192; | |
340 | authenticate_child_table[k]->offset = 0; | |
341 | snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", | |
342 | short_prg, | |
343 | authenticate_child_table[k]->index + 1); | |
344 | fd_note(authenticate_child_table[k]->fd, fd_note_buf); | |
345 | commSetNonBlocking(authenticate_child_table[k]->fd); | |
346 | /* set handler for incoming result */ | |
347 | commSetSelect(authenticate_child_table[k]->fd, | |
348 | COMM_SELECT_READ, | |
349 | authenticateHandleRead, | |
350 | authenticate_child_table[k], 0); | |
351 | debug(29, 3) ("authenticateOpenServers: 'authenticate_server' %d started\n", | |
352 | k); | |
353 | } | |
354 | } | |
355 | if (first_time == 0) { | |
356 | first_time++; | |
357 | memset(&AuthenticateStats, '\0', sizeof(AuthenticateStats)); | |
358 | cachemgrRegister("authenticator", | |
359 | "Authenticator Stats", | |
360 | authenticateStats, 0, 1); | |
361 | } | |
362 | safe_free(short_prg); | |
363 | safe_free(short_prg2); | |
364 | } | |
365 | ||
366 | void | |
367 | authenticateShutdownServers(void *unused) | |
368 | { | |
369 | authenticator_t *authenticate = NULL; | |
370 | authenticateStateData *r = NULL; | |
371 | int k; | |
372 | int na = 0; | |
373 | if (Config.Program.authenticate == NULL) | |
374 | return; | |
375 | if (authenticateQueueHead) { | |
376 | while ((authenticate = GetFirstAvailable()) && (r = Dequeue())) | |
377 | authenticateDispatch(authenticate, r); | |
378 | return; | |
379 | } | |
380 | for (k = 0; k < NAuthenticators; k++) { | |
381 | authenticate = *(authenticate_child_table + k); | |
382 | if (!EBIT_TEST(authenticate->flags, HELPER_ALIVE)) | |
383 | continue; | |
384 | if (EBIT_TEST(authenticate->flags, HELPER_CLOSING)) | |
385 | continue; | |
386 | if (EBIT_TEST(authenticate->flags, HELPER_BUSY)) { | |
387 | na++; | |
388 | continue; | |
389 | } | |
390 | debug(29, 3) ("authenticateShutdownServers: closing authenticator #%d, FD %d\n", | |
391 | authenticate->index + 1, authenticate->fd); | |
392 | comm_close(authenticate->fd); | |
393 | EBIT_SET(authenticate->flags, HELPER_CLOSING); | |
394 | EBIT_SET(authenticate->flags, HELPER_BUSY); | |
395 | } | |
396 | if (na) | |
397 | eventAdd("authenticateShutdownServers", authenticateShutdownServers, NULL, 1.0, 1); | |
398 | } | |
399 | ||
400 | int | |
401 | authenticateUnregister(const char *url, void *data) | |
402 | { | |
403 | authenticator_t *authenticate = NULL; | |
404 | authenticateStateData *r = NULL; | |
405 | struct authenticateQueueData *rq = NULL; | |
406 | int k; | |
407 | int n = 0; | |
408 | if (Config.Program.authenticate == NULL) | |
409 | return 0; | |
410 | debug(29, 3) ("authenticateUnregister: '%s'\n", url); | |
411 | for (k = 0; k < NAuthenticators; k++) { | |
412 | authenticate = *(authenticate_child_table + k); | |
413 | if ((r = authenticate->authenticateState) == NULL) | |
414 | continue; | |
415 | if (r->data != data) | |
416 | continue; | |
417 | debug(29, 3) ("authenticateUnregister: Found match\n"); | |
418 | r->handler = NULL; | |
419 | n++; | |
420 | } | |
421 | for (rq = authenticateQueueHead; rq; rq = rq->next) { | |
422 | if ((r = rq->authenticateState) == NULL) | |
423 | continue; | |
424 | if (r->data != data) | |
425 | continue; | |
426 | debug(29, 3) ("authenticateUnregister: Found match.\n"); | |
427 | r->handler = NULL; | |
428 | n++; | |
429 | } | |
430 | debug(29, 3) ("authenticateUnregister: Unregistered %d handlers\n", n); | |
431 | return n; | |
432 | } | |
433 | ||
434 | void | |
435 | authenticateStats(StoreEntry * sentry) | |
436 | { | |
437 | int k; | |
438 | storeAppendPrintf(sentry, "Authenticator Statistics:\n"); | |
439 | storeAppendPrintf(sentry, "requests: %d\n", | |
440 | AuthenticateStats.requests); | |
441 | storeAppendPrintf(sentry, "replies: %d\n", | |
442 | AuthenticateStats.replies); | |
443 | storeAppendPrintf(sentry, "queue length: %d\n", | |
444 | AuthenticateStats.queue_size); | |
445 | storeAppendPrintf(sentry, "avg service time: %d msec\n", | |
446 | AuthenticateStats.avg_svc_time); | |
447 | storeAppendPrintf(sentry, "number of authenticators: %d\n", | |
448 | NAuthenticators); | |
449 | storeAppendPrintf(sentry, "use histogram:\n"); | |
450 | for (k = 0; k < NAuthenticators; k++) { | |
451 | storeAppendPrintf(sentry, " authenticator #%d: %d (%d requests)\n", | |
452 | k + 1, | |
453 | AuthenticateStats.use_hist[k], | |
454 | AuthenticateStats.rewrites[k]); | |
455 | } | |
456 | } |