~squid/squid/sbuf-use

« back to all changes in this revision

Viewing changes to src/authenticate.cc

  • Committer: hno
  • Date: 2001-01-08 06:32:04 UTC
  • Revision ID: cvs-1:hno-20010108063204-w6a8e1zz6eprqnp8
Major rewrite of proxy authentication to support other schemes than
Basic (auth_rewrite branch on SourceForge).
Contributors:
   Andy Doran
   Robert Collins
   Chemolli Francesco
   Henrik Nordstrom

For details about the new API's, see Programmers Guide.

As part of this change everything from auth_modules has been moved to
src/auth/basic/helpers

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/*
3
 
 * $Id: authenticate.cc,v 1.14 2001/01/05 09:51:36 adrian Exp $
 
3
 * $Id: authenticate.cc,v 1.15 2001/01/07 23:36:37 hno Exp $
4
4
 *
5
5
 * DEBUG: section 29    Authenticator
6
6
 * AUTHOR: Duane Wessels
33
33
 *
34
34
 */
35
35
 
 
36
/* The functions in this file handle authentication.
 
37
 * They DO NOT perform access control or auditing.
 
38
 * See acl.c for access control and client_side.c for auditing */
 
39
 
 
40
 
36
41
#include "squid.h"
37
42
 
38
 
typedef struct {
39
 
    void *data;
40
 
    acl_proxy_auth_user *auth_user;
41
 
    RH *handler;
42
 
} authenticateStateData;
43
 
 
44
 
static HLPCB authenticateHandleReply;
45
 
static void authenticateStateFree(authenticateStateData * r);
46
 
static helper *authenticators = NULL;
47
 
 
48
 
static void
49
 
authenticateHandleReply(void *data, char *reply)
50
 
{
51
 
    authenticateStateData *r = data;
52
 
    int valid;
53
 
    char *t = NULL;
54
 
    debug(29, 5) ("authenticateHandleReply: {%s}\n", reply ? reply : "<NULL>");
55
 
    if (reply) {
56
 
        if ((t = strchr(reply, ' ')))
57
 
            *t = '\0';
58
 
        if (*reply == '\0')
59
 
            reply = NULL;
60
 
    }
61
 
    valid = cbdataValid(r->data);
62
 
    cbdataUnlock(r->data);
63
 
    if (valid)
64
 
        r->handler(r->data, reply);
65
 
    authenticateStateFree(r);
66
 
}
67
 
 
68
 
static void
69
 
authenticateStateFree(authenticateStateData * r)
70
 
{
71
 
    cbdataFree(r);
72
 
}
73
 
 
74
 
static void
75
 
authenticateStats(StoreEntry * sentry)
76
 
{
77
 
    storeAppendPrintf(sentry, "Authenticator Statistics:\n");
78
 
    helperStats(sentry, authenticators);
79
 
}
80
 
 
81
 
CBDATA_TYPE(authenticateStateData);
82
 
 
83
 
/**** PUBLIC FUNCTIONS ****/
84
 
 
85
 
 
86
 
void
87
 
authenticateStart(acl_proxy_auth_user * auth_user, RH * handler, void *data)
88
 
{
89
 
    authenticateStateData *r = NULL;
90
 
    char buf[8192];
91
 
    assert(auth_user);
 
43
static void
 
44
     authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request);
 
45
 
 
46
/*
 
47
 *
 
48
 * Private Data
 
49
 *
 
50
 */
 
51
 
 
52
MemPool *auth_user_request_pool = NULL;
 
53
 
 
54
/* Generic Functions */
 
55
 
 
56
 
 
57
int
 
58
authenticateAuthSchemeConfigured(const char *proxy_auth)
 
59
{
 
60
    authScheme *scheme;
 
61
    int i;
 
62
    for (i = 0; i < Config.authConfig.n_configured; i++) {
 
63
        scheme = Config.authConfig.schemes + i;
 
64
        if (strncasecmp(proxy_auth, scheme->typestr, strlen(scheme->typestr)) == 0)
 
65
            return 1;
 
66
    }
 
67
    return 0;
 
68
}
 
69
 
 
70
int
 
71
authenticateAuthSchemeId(const char *typestr)
 
72
{
 
73
    int i = 0;
 
74
    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
 
75
        if (strncasecmp(typestr, authscheme_list[i].typestr, strlen(authscheme_list[i].typestr)) == 0) {
 
76
            return i;
 
77
        }
 
78
    }
 
79
    return -1;
 
80
}
 
81
 
 
82
void
 
83
authenticateDecodeAuth(const char *proxy_auth, auth_user_request_t * auth_user_request)
 
84
{
 
85
    int i = 0;
 
86
    assert(proxy_auth != NULL);
 
87
    assert(auth_user_request != NULL);  /* we need this created for us. */
 
88
    debug(29, 9) ("authenticateDecodeAuth: header = '%s'\n", proxy_auth);
 
89
    if (authenticateAuthSchemeConfigured(proxy_auth)) {
 
90
        /* we're configured to use this scheme - but is it active ? */
 
91
        if ((i = authenticateAuthSchemeId(proxy_auth)) != -1) {
 
92
            authscheme_list[i].decodeauth(auth_user_request, proxy_auth);
 
93
            auth_user_request->auth_user->auth_module = i + 1;
 
94
            return;
 
95
        }
 
96
    }
 
97
    debug(29, 1)
 
98
        ("authenticateDecodeAuth: Unsupported or unconfigured proxy-auth scheme, '%s'\n",
 
99
        proxy_auth);
 
100
    return;
 
101
}
 
102
 
 
103
/* clear any connection related authentication details */
 
104
void
 
105
authenticateOnCloseConnection(ConnStateData * conn)
 
106
{
 
107
    auth_user_request_t *auth_user_request;
 
108
    assert(conn != NULL);
 
109
    if (conn->auth_user_request != NULL) {
 
110
        auth_user_request = conn->auth_user_request;
 
111
        if (authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection) {
 
112
            authscheme_list[auth_user_request->auth_user->auth_module - 1].oncloseconnection(conn);
 
113
        }
 
114
    }
 
115
}
 
116
 
 
117
/**** PUBLIC FUNCTIONS (ALL GENERIC!)  ****/
 
118
 
 
119
/* send the initial data to an authenticator module */
 
120
void
 
121
authenticateStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
 
122
{
 
123
    assert(auth_user_request);
92
124
    assert(handler);
93
 
    debug(29, 5) ("authenticateStart: '%s:%s'\n", hashKeyStr(&auth_user->hash),
94
 
        auth_user->passwd);
95
 
    if (Config.Program.authenticate == NULL) {
 
125
    debug(29, 9) ("authenticateStart: auth_user_request '%d'\n", auth_user_request);
 
126
    if (auth_user_request->auth_user->auth_module > 0)
 
127
        authscheme_list[auth_user_request->auth_user->auth_module - 1].authStart(auth_user_request, handler, data);
 
128
    else
96
129
        handler(data, NULL);
97
 
        return;
98
 
    }
99
 
    r = CBDATA_ALLOC(authenticateStateData, NULL);
100
 
    r->handler = handler;
101
 
    cbdataLock(data);
102
 
    r->data = data;
103
 
    r->auth_user = auth_user;
104
 
    snprintf(buf, 8192, "%s %s\n", hashKeyStr(&r->auth_user->hash),
105
 
        r->auth_user->passwd);
106
 
    helperSubmit(authenticators, buf, authenticateHandleReply, r);
107
 
}
108
 
 
109
 
void
110
 
authenticateInit(void)
111
 
{
112
 
    static int init = 0;
113
 
    if (!Config.Program.authenticate)
114
 
        return;
115
 
    if (authenticators == NULL)
116
 
        authenticators = helperCreate("authenticator");
117
 
    authenticators->cmdline = Config.Program.authenticate;
118
 
    authenticators->n_to_start = Config.authenticateChildren;
119
 
    authenticators->ipc_type = IPC_TCP_SOCKET;
120
 
    helperOpenServers(authenticators);
121
 
    if (!init) {
122
 
        cachemgrRegister("authenticator",
123
 
            "User Authenticator Stats",
124
 
            authenticateStats, 0, 1);
125
 
        init++;
126
 
    }
127
 
    CBDATA_INIT_TYPE(authenticateStateData);
 
130
}
 
131
 
 
132
/*
 
133
 * Check a auth_user pointer for validity. Does not check passwords, just data
 
134
 * sensability. Broken or Unknown auth_types are not valid for use...
 
135
 */
 
136
 
 
137
int
 
138
authenticateValidateUser(auth_user_request_t * auth_user_request)
 
139
{
 
140
    debug(29, 9) ("authenticateValidateUser: Validating Auth_user request '%d'.\n", auth_user_request);
 
141
    if (auth_user_request == NULL) {
 
142
        debug(29, 4) ("authenticateValidateUser: Auth_user_request was NULL!\n");
 
143
        return 0;
 
144
    }
 
145
    if (auth_user_request->auth_user == NULL) {
 
146
        debug(29, 4) ("authenticateValidateUser: No associated auth_user structure\n");
 
147
        return 0;
 
148
    }
 
149
    if (auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) {
 
150
        debug(29, 4) ("authenticateValidateUser: Auth_user '%d' uses unknown scheme.\n", auth_user_request->auth_user);
 
151
        return 0;
 
152
    }
 
153
    if (auth_user_request->auth_user->auth_type == AUTH_BROKEN) {
 
154
        debug(29, 4) ("authenticateValidateUser: Auth_user '%d' is broken for it's scheme.\n", auth_user_request->auth_user);
 
155
        return 0;
 
156
    }
 
157
    /* any other sanity checks that we need in the future */
 
158
 
 
159
    /* Thus should a module call to something like authValidate */
 
160
 
 
161
    /* finally return ok */
 
162
    debug(29, 4) ("authenticateValidateUser: Validated Auth_user request '%d'.\n", auth_user_request);
 
163
    return 1;
 
164
 
 
165
}
 
166
 
 
167
auth_user_t *
 
168
authenticateAuthUserNew(const char *scheme)
 
169
{
 
170
    auth_user_t *temp_auth;
 
171
    temp_auth = memAllocate(MEM_AUTH_USER_T);
 
172
    assert(temp_auth != NULL);
 
173
    temp_auth->auth_type = AUTH_UNKNOWN;
 
174
    temp_auth->references = 0;
 
175
    temp_auth->auth_module = authenticateAuthSchemeId(scheme) + 1;
 
176
    return temp_auth;
 
177
}
 
178
 
 
179
auth_user_request_t *
 
180
authenticateAuthUserRequestNew()
 
181
{
 
182
    auth_user_request_t *temp_request;
 
183
    if (!auth_user_request_pool)
 
184
        auth_user_request_pool = memPoolCreate("Authenticate Request Data", sizeof(auth_user_request_t));
 
185
    temp_request = memPoolAlloc(auth_user_request_pool);
 
186
    assert(temp_request != NULL);
 
187
    temp_request->auth_user = NULL;
 
188
    temp_request->message = NULL;
 
189
    temp_request->scheme_data = NULL;
 
190
    temp_request->references = 0;
 
191
    return temp_request;
 
192
}
 
193
 
 
194
void
 
195
authenticateAuthUserRequestFree(auth_user_request_t * auth_user_request)
 
196
{
 
197
    dlink_node *link;
 
198
    debug(29, 5) ("authenticateAuthUserRequestFree: freeing request %d\n", auth_user_request);
 
199
    if (!auth_user_request)
 
200
        return;
 
201
    assert(auth_user_request->references == 0);
 
202
    if (auth_user_request->auth_user) {
 
203
        if (auth_user_request->scheme_data != NULL) {
 
204
            /* we MUST know the module */
 
205
            assert((auth_user_request->auth_user->auth_module > 0));
 
206
            /* and the module MUST support requestFree if it has created scheme data */
 
207
            assert(authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree != NULL);
 
208
            authscheme_list[auth_user_request->auth_user->auth_module - 1].requestFree(auth_user_request);
 
209
        }
 
210
        /* unlink from the auth_user struct */
 
211
        link = auth_user_request->auth_user->requests.head;
 
212
        while (link && (link->data != auth_user_request))
 
213
            link = link->next;
 
214
        assert(link != NULL);
 
215
        dlinkDelete(link, &auth_user_request->auth_user->requests);
 
216
        dlinkNodeDelete(link);
 
217
 
 
218
        /* unlock the request structure's lock */
 
219
        authenticateAuthUserUnlock(auth_user_request->auth_user);
 
220
        auth_user_request->auth_user = NULL;
 
221
    } else
 
222
        assert(auth_user_request->scheme_data == NULL);
 
223
    if (auth_user_request->message)
 
224
        xfree(auth_user_request->message);
 
225
}
 
226
 
 
227
char *
 
228
authenticateAuthUserRequestMessage(auth_user_request_t * auth_user_request)
 
229
{
 
230
    if (auth_user_request)
 
231
        return auth_user_request->message;
 
232
    return NULL;
 
233
}
 
234
 
 
235
void
 
236
authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
 
237
{
 
238
    if (auth_user_request->auth_user)
 
239
        if (!auth_user_request->auth_user->ipaddr.s_addr)
 
240
            auth_user_request->auth_user->ipaddr = ipaddr;
 
241
}
 
242
 
 
243
/* Get Auth User: Return a filled out auth_user structure for the given
 
244
 * Proxy Auth (or Auth) header. It may be a cached Auth User or a new
 
245
 * Unauthenticated structure. The structure is given an inital lock here.
 
246
 */
 
247
auth_user_request_t *
 
248
authenticateGetAuthUser(const char *proxy_auth)
 
249
{
 
250
    auth_user_request_t *auth_user_request = authenticateAuthUserRequestNew();
 
251
    /* and lock for the callers instance */
 
252
    authenticateAuthUserRequestLock(auth_user_request);
 
253
    authenticateDecodeAuth(proxy_auth, auth_user_request);
 
254
    return auth_user_request;
 
255
}
 
256
 
 
257
/*
 
258
 * authenticateUserAuthenticated: is this auth_user structure logged in ?
 
259
 */
 
260
int
 
261
authenticateUserAuthenticated(auth_user_request_t * auth_user_request)
 
262
{
 
263
    assert(authenticateValidateUser(auth_user_request));
 
264
    if (auth_user_request->auth_user->auth_module > 0)
 
265
        return authscheme_list[auth_user_request->auth_user->auth_module - 1].authenticated(auth_user_request);
 
266
    else
 
267
        return 0;
 
268
}
 
269
 
 
270
/*
 
271
 * authenticateAuthenticateUser: log this user request in.
 
272
 * Cache hits may change the auth_user pointer in the structure if needed.
 
273
 * This is basically a handle approach.
 
274
 */
 
275
void
 
276
authenticateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
 
277
{
 
278
    assert(auth_user_request != NULL);
 
279
    if (auth_user_request->auth_user->auth_module > 0)
 
280
        authscheme_list[auth_user_request->auth_user->auth_module - 1].authAuthenticate(auth_user_request, request, conn, type);
 
281
}
 
282
 
 
283
/* authenticateUserUsername: return a pointer to the username in the */
 
284
char *
 
285
authenticateUserUsername(auth_user_t * auth_user)
 
286
{
 
287
    if (!auth_user)
 
288
        return NULL;
 
289
    if (auth_user->auth_module > 0)
 
290
        return authscheme_list[auth_user->auth_module - 1].authUserUsername(auth_user);
 
291
    return NULL;
 
292
}
 
293
 
 
294
/* authenticateUserRequestUsername: return a pointer to the username in the */
 
295
char *
 
296
authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
 
297
{
 
298
    assert(auth_user_request != NULL);
 
299
    return authenticateUserUsername(auth_user_request->auth_user);
 
300
}
 
301
 
 
302
/* returns
 
303
 * 0: no output needed
 
304
 * 1: send to client
 
305
 * -1: send to helper
 
306
 * -2: authenticate broken in some fashion
 
307
 */
 
308
int
 
309
authenticateDirection(auth_user_request_t * auth_user_request)
 
310
{
 
311
    if (!auth_user_request)
 
312
        return -2;
 
313
    if (authenticateUserAuthenticated(auth_user_request))
 
314
        return 0;
 
315
    if (auth_user_request->auth_user->auth_module > 0)
 
316
        return authscheme_list[auth_user_request->auth_user->auth_module - 1].getdirection(auth_user_request);
 
317
    return -2;
 
318
}
 
319
 
 
320
int
 
321
authenticateActiveSchemeCount()
 
322
{
 
323
    int i = 0, rv = 0;
 
324
    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
 
325
        if (authscheme_list[i].Active())
 
326
            rv++;
 
327
    debug(29, 9) ("authenticateActiveSchemeCount: %d active.\n", rv);
 
328
    return rv;
 
329
}
 
330
 
 
331
int
 
332
authenticateSchemeCount()
 
333
{
 
334
    int i = 0, rv = 0;
 
335
    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++)
 
336
        rv++;
 
337
    debug(29, 9) ("authenticateSchemeCount: %d active.\n", rv);
 
338
    return rv;
 
339
}
 
340
 
 
341
void
 
342
authenticateSchemeInit(void)
 
343
{
 
344
    authSchemeSetup();
 
345
}
 
346
 
 
347
void
 
348
authenticateInit(authConfig * config)
 
349
{
 
350
    int i;
 
351
    authScheme *scheme;
 
352
    for (i = 0; i < config->n_configured; i++) {
 
353
        if (authscheme_list[i].init) {
 
354
            scheme = config->schemes + i;
 
355
            authscheme_list[i].init(scheme);
 
356
        }
 
357
    }
 
358
    if (!proxy_auth_username_cache)
 
359
        authenticateInitUserCache();
128
360
}
129
361
 
130
362
void
131
363
authenticateShutdown(void)
132
364
{
133
 
    if (!authenticators)
134
 
        return;
135
 
    helperShutdown(authenticators);
136
 
    if (!shutting_down)
137
 
        return;
138
 
    helperFree(authenticators);
139
 
    authenticators = NULL;
 
365
    int i;
 
366
    debug(29, 2) ("authenticateShutdown: shutting down auth schemes\n");
 
367
    /* find the currently known authscheme types */
 
368
    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
 
369
        if (authscheme_list[i].donefunc != NULL)
 
370
            authscheme_list[i].donefunc();
 
371
        else
 
372
            debug(29, 2) ("authenticateShutdown: scheme %s has not registered a shutdown function.\n", authscheme_list[i].typestr);
 
373
        authscheme_list[i].typestr = NULL;
 
374
    }
 
375
}
 
376
 
 
377
void
 
378
authenticateFixHeader(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
 
379
/* send the auth types we are configured to support (and have compiled in!) */
 
380
{
 
381
/*    auth_type_t auth_type=err->auth_type;
 
382
 * auth_state_t auth_state=err->auth_state;
 
383
 * char *authchallenge=err->authchallenge;
 
384
 * auth_user_request_t *auth_user_request=err->auth_user_request;
 
385
 */
 
386
    int type = 0;
 
387
    switch (rep->sline.status) {
 
388
    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
 
389
        /* Proxy authorisation needed */
 
390
        type = HDR_PROXY_AUTHENTICATE;
 
391
        break;
 
392
    case HTTP_UNAUTHORIZED:
 
393
        /* WWW Authorisation needed */
 
394
        type = HDR_WWW_AUTHENTICATE;
 
395
        break;
 
396
    default:
 
397
        /* Keep GCC happy */
 
398
        /* some other HTTP status */
 
399
        break;
 
400
    }
 
401
    debug(29, 9) ("authenticateFixHeader: headertype:%d authuser:%d\n", type, auth_user_request);
 
402
    if ((rep->sline.status == HTTP_PROXY_AUTHENTICATION_REQUIRED)
 
403
        || (rep->sline.status == HTTP_UNAUTHORIZED))
 
404
        /* this is a authenticate-needed response */
 
405
    {
 
406
        if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0))
 
407
            authscheme_list[auth_user_request->auth_user->auth_module - 1].authFixHeader(auth_user_request, rep, type, request);
 
408
        else {
 
409
            int i;
 
410
            authScheme *scheme;
 
411
            /* call each configured authscheme */
 
412
            for (i = 0; i < Config.authConfig.n_configured; i++) {
 
413
                scheme = Config.authConfig.schemes + i;
 
414
                if (authscheme_list[scheme->Id].Active())
 
415
                    authscheme_list[scheme->Id].authFixHeader(auth_user_request, rep, type,
 
416
                        request);
 
417
                else
 
418
                    debug(29, 4) ("authenticateFixHeader: Configured scheme %s not Active\n", scheme->typestr);
 
419
            }
 
420
        }
 
421
    }
 
422
    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
 
423
        && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader))
 
424
        authscheme_list[auth_user_request->auth_user->auth_module - 1].AddHeader(auth_user_request, rep, accelerated);
 
425
}
 
426
 
 
427
/* call the active auth module and allow it to add a trailer to the request */
 
428
void
 
429
authenticateAddTrailer(HttpReply * rep, auth_user_request_t * auth_user_request, request_t * request, int accelerated)
 
430
{
 
431
    if ((auth_user_request != NULL) && (auth_user_request->auth_user->auth_module > 0)
 
432
        && (authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer))
 
433
        authscheme_list[auth_user_request->auth_user->auth_module - 1].AddTrailer(auth_user_request, rep, accelerated);
 
434
}
 
435
 
 
436
void
 
437
authenticateAuthUserLock(auth_user_t * auth_user)
 
438
{
 
439
    debug(29, 9) ("authenticateAuthUserLock auth_user '%d'.\n", auth_user);
 
440
    assert(auth_user != NULL);
 
441
    auth_user->references++;
 
442
    debug(29, 9) ("authenticateAuthUserLock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
 
443
}
 
444
 
 
445
void
 
446
authenticateAuthUserUnlock(auth_user_t * auth_user)
 
447
{
 
448
    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d'.\n", auth_user);
 
449
    assert(auth_user != NULL);
 
450
    if (auth_user->references > 0) {
 
451
        auth_user->references--;
 
452
    } else {
 
453
        debug(29, 1) ("Attempt to lower Auth User %d refcount below 0!\n", auth_user);
 
454
    }
 
455
    debug(29, 9) ("authenticateAuthUserUnlock auth_user '%d' now at '%d'.\n", auth_user, auth_user->references);
 
456
    if (auth_user->references == 0)
 
457
        authenticateFreeProxyAuthUser(auth_user);
 
458
}
 
459
 
 
460
void
 
461
authenticateAuthUserRequestLock(auth_user_request_t * auth_user_request)
 
462
{
 
463
    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d'.\n", auth_user_request);
 
464
    assert(auth_user_request != NULL);
 
465
    auth_user_request->references++;
 
466
    debug(29, 9) ("authenticateAuthUserRequestLock auth_user request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
 
467
}
 
468
 
 
469
void
 
470
authenticateAuthUserRequestUnlock(auth_user_request_t * auth_user_request)
 
471
{
 
472
    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user request '%d'.\n", auth_user_request);
 
473
    assert(auth_user_request != NULL);
 
474
    if (auth_user_request->references > 0) {
 
475
        auth_user_request->references--;
 
476
    } else {
 
477
        debug(29, 1) ("Attempt to lower Auth User request %d refcount below 0!\n", auth_user_request);
 
478
    }
 
479
    debug(29, 9) ("authenticateAuthUserRequestUnlock auth_user_request '%d' now at '%d'.\n", auth_user_request, auth_user_request->references);
 
480
    if (auth_user_request->references == 0) {
 
481
        /* not locked anymore */
 
482
        authenticateAuthUserRequestFree(auth_user_request);
 
483
    }
 
484
}
 
485
 
 
486
int
 
487
authenticateAuthUserInuse(auth_user_t * auth_user)
 
488
/* returns 0 for not in use */
 
489
{
 
490
    assert(auth_user != NULL);
 
491
    return auth_user->references;
 
492
}
 
493
 
 
494
/* Combine two user structs. ONLY to be called from within a scheme module.
 
495
 * The scheme module is responsible for ensuring that the two users _can_ be merged 
 
496
 * without invalidating all the request scheme data. 
 
497
 * the scheme is also responsible for merging any user related scheme data itself. */
 
498
void
 
499
authenticateAuthUserMerge(auth_user_t * from, auth_user_t * to)
 
500
{
 
501
    dlink_node *link, *tmplink;
 
502
    auth_user_request_t *auth_user_request;
 
503
/* XXX combine two authuser structs. Incomplete: it should merge in hash references 
 
504
 * too and ask the module to merge in scheme data */
 
505
    debug(29, 5) ("authenticateAuthUserMerge auth_user '%d' into auth_user '%d'.\n", from, to);
 
506
    link = from->requests.head;
 
507
    while (link) {
 
508
        auth_user_request = link->data;
 
509
        tmplink = link;
 
510
        link = link->next;
 
511
        dlinkDelete(tmplink, &from->requests);
 
512
        dlinkAddTail(auth_user_request, tmplink, &to->requests);
 
513
        auth_user_request->auth_user = to;
 
514
    }
 
515
    to->references += from->references;
 
516
    from->references = 0;
 
517
    authenticateFreeProxyAuthUser(from);
 
518
}
 
519
 
 
520
void
 
521
authenticateFreeProxyAuthUser(void *data)
 
522
{
 
523
    auth_user_t *u = data;
 
524
    auth_user_request_t *auth_user_request;
 
525
#if 0
 
526
    auth_user_hash_pointer *proxy_auth_hash;
 
527
#endif
 
528
    dlink_node *link, *tmplink;
 
529
    assert(data != NULL);
 
530
    debug(29, 5) ("authenticateFreeProxyAuthUser: Freeing auth_user '%d' with refcount '%d'.\n", u, u->references);
 
531
    assert(u->references == 0);
 
532
    /* were they linked in by username ? */
 
533
    if (u->usernamehash) {
 
534
        assert(u->usernamehash->auth_user == u);
 
535
        debug(29, 5) ("authenticateFreeProxyAuthUser: removing usernamehash entry '%d'\n", u->usernamehash);
 
536
        hash_remove_link(proxy_auth_username_cache,
 
537
            (hash_link *) u->usernamehash);
 
538
        /* don't free the key as we use the same user string as the auth_user 
 
539
         * structure */
 
540
        memFree(u->usernamehash, MEM_AUTH_USER_HASH);
 
541
    }
 
542
    /* remove any outstanding requests */
 
543
    link = u->requests.head;
 
544
    while (link) {
 
545
        debug(29, 5) ("authenticateFreeProxyAuthUser: removing request entry '%d'\n", link->data);
 
546
        auth_user_request = link->data;
 
547
        tmplink = link;
 
548
        link = link->next;
 
549
        dlinkDelete(tmplink, &u->requests);
 
550
        dlinkNodeDelete(tmplink);
 
551
        authenticateAuthUserRequestFree(auth_user_request);
 
552
    }
 
553
    /* free cached acl results */
 
554
    aclCacheMatchFlush(&u->proxy_match_cache);
 
555
    if (u->scheme_data && u->auth_module > 0)
 
556
        authscheme_list[u->auth_module - 1].FreeUser(u);
 
557
    /* prevent accidental reuse */
 
558
    u->auth_type = AUTH_UNKNOWN;
 
559
    memFree(u, MEM_AUTH_USER_T);
 
560
}
 
561
 
 
562
void
 
563
authenticateInitUserCache()
 
564
{
 
565
    if (!proxy_auth_username_cache) {
 
566
        /* First time around, 7921 should be big enough */
 
567
        proxy_auth_username_cache =
 
568
            hash_create((HASHCMP *) strcmp, 7921, hash_string);
 
569
        assert(proxy_auth_username_cache);
 
570
        eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
 
571
    }
 
572
}
 
573
 
 
574
void
 
575
authenticateProxyUserCacheCleanup(void *datanotused)
 
576
{
 
577
    /*
 
578
     * We walk the hash by username as that is the unique key we use.
 
579
     * For big hashs we could consider stepping through the cache, 100/200
 
580
     * entries at a time. Lets see how it flys first.
 
581
     */
 
582
    auth_user_hash_pointer *usernamehash;
 
583
    auth_user_t *auth_user;
 
584
    char *username = NULL;
 
585
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n");
 
586
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %d\n", current_time.tv_sec);
 
587
    hash_first(proxy_auth_username_cache);
 
588
    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
 
589
        auth_user = usernamehash->auth_user;
 
590
        username = authenticateUserUsername(auth_user);
 
591
 
 
592
        /* if we need to have inpedendent expiry clauses, insert a module call
 
593
         * here */
 
594
        debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %d\n\treferences: %d\n", auth_user->auth_type, username, auth_user->expiretime + Config.authenticateTTL, auth_user->references);
 
595
        if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
 
596
            debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username);
 
597
            /* the minus 1 accounts for the cache lock */
 
598
            if ((authenticateAuthUserInuse(auth_user) - 1))
 
599
                debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
 
600
            else
 
601
                authenticateAuthUserUnlock(auth_user);
 
602
        }
 
603
    }
 
604
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n");
 
605
    eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
 
606
}
 
607
 
 
608
/*
 
609
 * authenticateUserCacheRestart() cleans all config-dependent data from the 
 
610
 * auth_user cache. It DOES NOT Flush the user cache.
 
611
 */
 
612
 
 
613
void
 
614
authenticateUserCacheRestart()
 
615
{
 
616
    auth_user_hash_pointer *usernamehash;
 
617
    auth_user_t *auth_user;
 
618
    char *username = NULL;
 
619
    debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
 
620
    hash_first(proxy_auth_username_cache);
 
621
    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
 
622
        auth_user = usernamehash->auth_user;
 
623
        username = authenticateUserUsername(auth_user);
 
624
        debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username);
 
625
        aclCacheMatchFlush(&auth_user->proxy_match_cache);
 
626
    }
 
627
 
 
628
}
 
629
 
 
630
/*
 
631
 * called to add another auth scheme module
 
632
 */
 
633
void
 
634
authSchemeAdd(char *type, AUTHSSETUP * setup)
 
635
{
 
636
    int i;
 
637
    /* find the number of currently known authscheme types */
 
638
    for (i = 0; authscheme_list && authscheme_list[i].typestr; i++) {
 
639
        assert(strcmp(authscheme_list[i].typestr, type) != 0);
 
640
    }
 
641
    /* add the new type */
 
642
    authscheme_list = xrealloc(authscheme_list, (i + 2) * sizeof(authscheme_entry_t));
 
643
    memset(&authscheme_list[i + 1], 0, sizeof(authscheme_entry_t));
 
644
    authscheme_list[i].typestr = type;
 
645
    /* Call the scheme module to set up capabilities and initialize any global data */
 
646
    setup(&authscheme_list[i]);
 
647
}
 
648
 
 
649
 
 
650
 
 
651
/* UserNameCacheAdd: add a auth_user structure to the username cache */
 
652
void
 
653
authenticateUserNameCacheAdd(auth_user_t * auth_user)
 
654
{
 
655
    auth_user_hash_pointer *usernamehash;
 
656
    usernamehash = memAllocate(MEM_AUTH_USER_HASH);
 
657
    usernamehash->key = authenticateUserUsername(auth_user);
 
658
    usernamehash->auth_user = auth_user;
 
659
    hash_join(proxy_auth_username_cache, (hash_link *) usernamehash);
 
660
    auth_user->usernamehash = usernamehash;
 
661
    /* lock for presence in the cache */
 
662
    authenticateAuthUserLock(auth_user);
 
663
}
 
664
 
 
665
 
 
666
 
 
667
/*
 
668
 * check the user for ip changes timeouts
 
669
 * 0 = failed check
 
670
 * 1 = ip requirements are ok.
 
671
 */
 
672
/* TODO:
 
673
 * ip_expire data should be in a struct of it's own - for code reuse */
 
674
int
 
675
authenticateCheckAuthUserIP(struct in_addr request_src_addr, auth_user_request_t * auth_user_request)
 
676
{
 
677
    char *username = authenticateUserRequestUsername(auth_user_request);
 
678
    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) {
 
679
        /* user has not moved ip or had the ip timeout expire */
 
680
        if ((auth_user_request->auth_user->auth_type == AUTH_UNKNOWN) ||
 
681
            (auth_user_request->auth_user->auth_type == AUTH_BROKEN)) {
 
682
            debug(29, 1) ("authenticateCheckProxyAuthIP: broken or unknown auth type %d.\n", auth_user_request->auth_user->auth_type);
 
683
            return 0;
 
684
        }
 
685
        username = authenticateUserRequestUsername(auth_user_request);
 
686
        /* Update IP ttl */
 
687
        auth_user_request->auth_user->ip_expiretime = squid_curtime;
 
688
        auth_user_request->auth_user->ipaddr = request_src_addr;
 
689
        return 1;
 
690
    } else {
 
691
        char *ip1 = xstrdup(inet_ntoa(auth_user_request->auth_user->ipaddr));
 
692
        char *ip2 = xstrdup(inet_ntoa(request_src_addr));
 
693
        if (Config.onoff.authenticateIpTTLStrict) {
 
694
            debug(29, 1) ("aclMatchProxyAuth: user '%s' tried to use multiple IP addresses! (%s, %s)\n ", username, ip1, ip2);
 
695
        } else {
 
696
            /* Non-strict mode. Reassign ownership to the new IP */
 
697
            auth_user_request->auth_user->ipaddr.s_addr = request_src_addr.s_addr;
 
698
            debug(29, 1) ("aclMatchProxyAuth: user '%s' has changed IP address (%s, %s)\n ", username, ip1, ip2);
 
699
        }
 
700
        safe_free(ip1);
 
701
        safe_free(ip2);
 
702
        /* and deny access */
 
703
        return 0;
 
704
    }
140
705
}