]>
Commit | Line | Data |
---|---|---|
94439e4e | 1 | /* |
62e76326 | 2 | * $Id: auth_basic.cc,v 1.24 2003/02/21 22:50:26 robertc Exp $ |
94439e4e | 3 | * |
4 | * DEBUG: section 29 Authenticator | |
5 | * AUTHOR: Duane Wessels | |
6 | * | |
2b6662ba | 7 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
94439e4e | 8 | * ---------------------------------------------------------- |
9 | * | |
2b6662ba | 10 | * Squid is the result of efforts by numerous individuals from |
11 | * the Internet community; see the CONTRIBUTORS file for full | |
12 | * details. Many organizations have provided support for Squid's | |
13 | * development; see the SPONSORS file for full details. Squid is | |
14 | * Copyrighted (C) 2001 by the Regents of the University of | |
15 | * California; see the COPYRIGHT file for full details. Squid | |
16 | * incorporates software developed and/or copyrighted by other | |
17 | * sources; see the CREDITS file for full details. | |
94439e4e | 18 | * |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the GNU General Public License as published by | |
21 | * the Free Software Foundation; either version 2 of the License, or | |
22 | * (at your option) any later version. | |
23 | * | |
24 | * This program is distributed in the hope that it will be useful, | |
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
27 | * GNU General Public License for more details. | |
28 | * | |
29 | * You should have received a copy of the GNU General Public License | |
30 | * along with this program; if not, write to the Free Software | |
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
32 | * | |
33 | */ | |
34 | ||
35 | /* The functions in this file handle authentication. | |
36 | * They DO NOT perform access control or auditing. | |
37 | * See acl.c for access control and client_side.c for auditing */ | |
38 | ||
39 | ||
40 | #include "squid.h" | |
41 | #include "auth_basic.h" | |
e6ccf245 | 42 | #include "authenticate.h" |
43 | #include "Store.h" | |
94439e4e | 44 | |
45 | static void | |
e6ccf245 | 46 | authenticateStateFree(AuthenticateStateData * r) |
94439e4e | 47 | { |
48 | cbdataFree(r); | |
49 | } | |
50 | ||
51 | /* Basic Scheme */ | |
52 | ||
53 | static HLPCB authenticateBasicHandleReply; | |
54 | static AUTHSACTIVE authenticateBasicActive; | |
55 | static AUTHSAUTHED authenticateBasicAuthenticated; | |
56 | static AUTHSAUTHUSER authenticateBasicAuthenticateUser; | |
2d70df72 | 57 | static AUTHSCONFIGURED authBasicConfigured; |
94439e4e | 58 | static AUTHSDIRECTION authenticateBasicDirection; |
59 | static AUTHSDECODE authenticateBasicDecodeAuth; | |
60 | static AUTHSDUMP authBasicCfgDump; | |
61 | static AUTHSFIXERR authenticateBasicFixErrorHeader; | |
62 | static AUTHSFREE authenticateBasicFreeUser; | |
63 | static AUTHSFREECONFIG authBasicFreeConfig; | |
64 | static AUTHSPARSE authBasicParse; | |
65 | static AUTHSINIT authBasicInit; | |
66 | static AUTHSSTART authenticateBasicStart; | |
67 | static AUTHSSTATS authenticateBasicStats; | |
68 | static AUTHSUSERNAME authenticateBasicUsername; | |
69 | static AUTHSSHUTDOWN authBasicDone; | |
70 | ||
71 | static helper *basicauthenticators = NULL; | |
72 | ||
73 | static auth_basic_config *basicConfig = NULL; | |
74 | ||
75 | static int authbasic_initialised = 0; | |
76 | MemPool *basic_data_pool = NULL; | |
77 | ||
2d72d4fd | 78 | |
94439e4e | 79 | /* |
80 | * | |
2d72d4fd | 81 | * Public Functions |
94439e4e | 82 | * |
83 | */ | |
84 | ||
2d72d4fd | 85 | AUTHSSETUP authSchemeSetup_basic; |
94439e4e | 86 | |
87 | void | |
88 | authSchemeSetup_basic(authscheme_entry_t * authscheme) | |
89 | { | |
90 | assert(!authbasic_initialised); | |
91 | authscheme->Active = authenticateBasicActive; | |
92 | authscheme->parse = authBasicParse; | |
93 | authscheme->dump = authBasicCfgDump; | |
94 | authscheme->init = authBasicInit; | |
95 | authscheme->authAuthenticate = authenticateBasicAuthenticateUser; | |
96 | authscheme->authenticated = authenticateBasicAuthenticated; | |
2d70df72 | 97 | authscheme->configured = authBasicConfigured; |
94439e4e | 98 | authscheme->authFixHeader = authenticateBasicFixErrorHeader; |
99 | authscheme->FreeUser = authenticateBasicFreeUser; | |
100 | authscheme->freeconfig = authBasicFreeConfig; | |
101 | authscheme->authStart = authenticateBasicStart; | |
102 | authscheme->authStats = authenticateBasicStats; | |
103 | authscheme->authUserUsername = authenticateBasicUsername; | |
104 | authscheme->getdirection = authenticateBasicDirection; | |
105 | authscheme->oncloseconnection = NULL; | |
106 | authscheme->decodeauth = authenticateBasicDecodeAuth; | |
107 | authscheme->donefunc = authBasicDone; | |
60d096f4 | 108 | authscheme->authConnLastHeader = NULL; |
94439e4e | 109 | } |
110 | ||
2d72d4fd | 111 | /* internal functions */ |
112 | ||
113 | static void | |
114 | authBasicDone(void) | |
115 | { | |
116 | if (basicauthenticators) | |
62e76326 | 117 | helperShutdown(basicauthenticators); |
118 | ||
2d72d4fd | 119 | authbasic_initialised = 0; |
62e76326 | 120 | |
2d72d4fd | 121 | if (!shutting_down) |
62e76326 | 122 | return; |
123 | ||
2d72d4fd | 124 | if (basicauthenticators) |
62e76326 | 125 | helperFree(basicauthenticators); |
126 | ||
2d72d4fd | 127 | basicauthenticators = NULL; |
62e76326 | 128 | |
2f44bd34 | 129 | #if DEBUGSHUTDOWN |
62e76326 | 130 | |
2d72d4fd | 131 | if (basic_data_pool) { |
62e76326 | 132 | memPoolDestroy(&basic_data_pool); |
133 | basic_data_pool = NULL; | |
2d72d4fd | 134 | } |
62e76326 | 135 | |
2f44bd34 | 136 | #endif |
2d72d4fd | 137 | debug(29, 2) ("authBasicDone: Basic authentication Shutdown.\n"); |
138 | } | |
139 | ||
140 | static int | |
94439e4e | 141 | authenticateBasicActive() |
2d70df72 | 142 | { |
143 | return (authbasic_initialised == 1) ? 1 : 0; | |
144 | } | |
145 | ||
2d72d4fd | 146 | static int |
2d70df72 | 147 | authBasicConfigured() |
94439e4e | 148 | { |
94439e4e | 149 | if ((basicConfig != NULL) && (basicConfig->authenticate != NULL) && |
62e76326 | 150 | (basicConfig->authenticateChildren != 0) && |
151 | (basicConfig->basicAuthRealm != NULL)) { | |
152 | debug(29, 9) ("authBasicConfigured: returning configured\n"); | |
153 | return 1; | |
2d70df72 | 154 | } |
62e76326 | 155 | |
2d70df72 | 156 | debug(29, 9) ("authBasicConfigured: returning unconfigured\n"); |
94439e4e | 157 | return 0; |
158 | } | |
159 | ||
2d72d4fd | 160 | static int |
94439e4e | 161 | authenticateBasicAuthenticated(auth_user_request_t * auth_user_request) |
162 | { | |
e6ccf245 | 163 | basic_data *basic_auth = static_cast<basic_data *>(auth_user_request->auth_user->scheme_data); |
62e76326 | 164 | |
bd507204 | 165 | if ((basic_auth->flags.credentials_ok == 1) && (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL > squid_curtime)) |
62e76326 | 166 | return 1; |
167 | ||
94439e4e | 168 | debug(29, 4) ("User not authenticated or credentials need rechecking.\n"); |
62e76326 | 169 | |
94439e4e | 170 | return 0; |
171 | } | |
172 | ||
2d72d4fd | 173 | #if UNUSED_CODE |
174 | static int | |
94439e4e | 175 | authenticateBasiccmpUsername(basic_data * u1, basic_data * u2) |
176 | { | |
177 | return strcmp(u1->username, u2->username); | |
178 | } | |
62e76326 | 179 | |
2d72d4fd | 180 | #endif |
94439e4e | 181 | |
182 | /* log a basic user in | |
183 | */ | |
184 | static void | |
185 | authenticateBasicAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type) | |
186 | { | |
94439e4e | 187 | auth_user_t *auth_user; |
188 | basic_data *basic_auth; | |
94439e4e | 189 | |
190 | assert(auth_user_request->auth_user != NULL); | |
191 | auth_user = auth_user_request->auth_user; | |
192 | ||
94439e4e | 193 | assert(auth_user->scheme_data != NULL); |
e6ccf245 | 194 | basic_auth = static_cast<basic_data *>(auth_user->scheme_data); |
9bea1d5b | 195 | |
bd507204 | 196 | /* if the password is not ok, do an identity */ |
62e76326 | 197 | |
bd507204 | 198 | if (basic_auth->flags.credentials_ok != 1) |
62e76326 | 199 | return; |
94439e4e | 200 | |
201 | /* are we about to recheck the credentials externally? */ | |
202 | if ((basic_auth->credentials_checkedtime + basicConfig->credentialsTTL) <= squid_curtime) { | |
62e76326 | 203 | debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n"); |
204 | return; | |
94439e4e | 205 | } |
62e76326 | 206 | |
94439e4e | 207 | /* we have been through the external helper, and the credentials haven't expired */ |
208 | debug(29, 9) ("authenticateBasicAuthenticateuser: user '%s' authenticated\n", | |
62e76326 | 209 | basic_auth->username); |
94439e4e | 210 | |
211 | /* Decode now takes care of finding the auth_user struct in the cache */ | |
94439e4e | 212 | /* after external auth occurs anyway */ |
213 | auth_user->expiretime = current_time.tv_sec; | |
62e76326 | 214 | |
94439e4e | 215 | return; |
216 | } | |
217 | ||
218 | int | |
219 | authenticateBasicDirection(auth_user_request_t * auth_user_request) | |
220 | { | |
62e76326 | 221 | /* null auth_user is checked for by authenticateDirection */ |
94439e4e | 222 | auth_user_t *auth_user = auth_user_request->auth_user; |
e6ccf245 | 223 | basic_data *basic_auth = static_cast<basic_data *>(auth_user->scheme_data); |
62e76326 | 224 | |
bd507204 | 225 | switch (basic_auth->flags.credentials_ok) { |
62e76326 | 226 | |
94439e4e | 227 | case 0: /* not checked */ |
62e76326 | 228 | return -1; |
229 | ||
94439e4e | 230 | case 1: /* checked & ok */ |
62e76326 | 231 | |
232 | if (basic_auth->credentials_checkedtime + basicConfig->credentialsTTL <= squid_curtime) | |
233 | return -1; | |
234 | ||
235 | return 0; | |
236 | ||
94439e4e | 237 | case 2: /* paused while waiting for a username:password check on another request */ |
62e76326 | 238 | return -1; |
239 | ||
94439e4e | 240 | case 3: /* authentication process failed. */ |
62e76326 | 241 | return -2; |
94439e4e | 242 | } |
62e76326 | 243 | |
94439e4e | 244 | return -2; |
245 | } | |
246 | ||
247 | void | |
248 | authenticateBasicFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request) | |
249 | { | |
250 | if (basicConfig->authenticate) { | |
62e76326 | 251 | debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicConfig->basicAuthRealm); |
252 | httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicConfig->basicAuthRealm); | |
94439e4e | 253 | } |
254 | } | |
255 | ||
256 | /* free any allocated configuration details */ | |
257 | void | |
258 | authBasicFreeConfig(authScheme * scheme) | |
259 | { | |
260 | if (basicConfig == NULL) | |
62e76326 | 261 | return; |
262 | ||
94439e4e | 263 | assert(basicConfig == scheme->scheme_data); |
62e76326 | 264 | |
94439e4e | 265 | if (basicConfig->authenticate) |
62e76326 | 266 | wordlistDestroy(&basicConfig->authenticate); |
267 | ||
94439e4e | 268 | if (basicConfig->basicAuthRealm) |
62e76326 | 269 | safe_free(basicConfig->basicAuthRealm); |
270 | ||
94439e4e | 271 | xfree(basicConfig); |
62e76326 | 272 | |
94439e4e | 273 | basicConfig = NULL; |
274 | } | |
275 | ||
276 | void | |
277 | authenticateBasicFreeUser(auth_user_t * auth_user) | |
278 | { | |
e6ccf245 | 279 | basic_data *basic_auth = static_cast<basic_data *>(auth_user->scheme_data); |
94439e4e | 280 | debug(29, 5) ("authenticateBasicFreeUser: Clearing Basic scheme data\n"); |
62e76326 | 281 | |
94439e4e | 282 | if (basic_auth->username) |
62e76326 | 283 | xfree(basic_auth->username); |
284 | ||
94439e4e | 285 | if (basic_auth->passwd) |
62e76326 | 286 | xfree(basic_auth->passwd); |
287 | ||
94439e4e | 288 | memPoolFree(basic_data_pool, auth_user->scheme_data); |
62e76326 | 289 | |
94439e4e | 290 | auth_user->scheme_data = NULL; |
291 | } | |
292 | ||
293 | static void | |
294 | authenticateBasicHandleReply(void *data, char *reply) | |
295 | { | |
e6ccf245 | 296 | AuthenticateStateData *r = static_cast<AuthenticateStateData *>(data); |
94439e4e | 297 | auth_user_t *auth_user; |
298 | basic_data *basic_auth; | |
e6ccf245 | 299 | BasicAuthQueueNode *tmpnode; |
94439e4e | 300 | char *t = NULL; |
fa80a8ef | 301 | void *cbdata; |
94439e4e | 302 | debug(29, 9) ("authenticateBasicHandleReply: {%s}\n", reply ? reply : "<NULL>"); |
62e76326 | 303 | |
94439e4e | 304 | if (reply) { |
62e76326 | 305 | if ((t = strchr(reply, ' '))) |
306 | *t = '\0'; | |
307 | ||
308 | if (*reply == '\0') | |
309 | reply = NULL; | |
94439e4e | 310 | } |
62e76326 | 311 | |
94439e4e | 312 | assert(r->auth_user_request != NULL); |
313 | assert(r->auth_user_request->auth_user->auth_type == AUTH_BASIC); | |
314 | auth_user = r->auth_user_request->auth_user; | |
e6ccf245 | 315 | basic_auth = static_cast<basic_data *>(auth_user->scheme_data); |
62e76326 | 316 | |
94439e4e | 317 | if (reply && (strncasecmp(reply, "OK", 2) == 0)) |
62e76326 | 318 | basic_auth->flags.credentials_ok = 1; |
94439e4e | 319 | else |
62e76326 | 320 | basic_auth->flags.credentials_ok = 3; |
321 | ||
94439e4e | 322 | basic_auth->credentials_checkedtime = squid_curtime; |
62e76326 | 323 | |
fa80a8ef | 324 | if (cbdataReferenceValidDone(r->data, &cbdata)) |
62e76326 | 325 | r->handler(cbdata, NULL); |
326 | ||
fa80a8ef | 327 | cbdataReferenceDone(r->data); |
62e76326 | 328 | |
f2afa96a | 329 | while (basic_auth->auth_queue) { |
62e76326 | 330 | tmpnode = basic_auth->auth_queue->next; |
331 | ||
332 | if (cbdataReferenceValidDone(basic_auth->auth_queue->data, &cbdata)) | |
333 | basic_auth->auth_queue->handler(cbdata, NULL); | |
334 | ||
335 | xfree(basic_auth->auth_queue); | |
336 | ||
337 | basic_auth->auth_queue = tmpnode; | |
94439e4e | 338 | } |
62e76326 | 339 | |
94439e4e | 340 | authenticateStateFree(r); |
341 | } | |
342 | ||
343 | static void | |
344 | authBasicCfgDump(StoreEntry * entry, const char *name, authScheme * scheme) | |
345 | { | |
e6ccf245 | 346 | auth_basic_config *config = static_cast<auth_basic_config *>(scheme->scheme_data); |
94439e4e | 347 | wordlist *list = config->authenticate; |
348 | storeAppendPrintf(entry, "%s %s", name, "basic"); | |
62e76326 | 349 | |
94439e4e | 350 | while (list != NULL) { |
62e76326 | 351 | storeAppendPrintf(entry, " %s", list->key); |
352 | list = list->next; | |
94439e4e | 353 | } |
62e76326 | 354 | |
94439e4e | 355 | storeAppendPrintf(entry, "\n%s %s realm %s\n%s %s children %d\n%s %s credentialsttl %d seconds\n", |
62e76326 | 356 | name, "basic", config->basicAuthRealm, |
357 | name, "basic", config->authenticateChildren, | |
358 | name, "basic", (int) config->credentialsTTL); | |
94439e4e | 359 | |
360 | } | |
361 | ||
362 | static void | |
363 | authBasicParse(authScheme * scheme, int n_configured, char *param_str) | |
364 | { | |
365 | if (scheme->scheme_data == NULL) { | |
62e76326 | 366 | assert(basicConfig == NULL); |
367 | /* this is the first param to be found */ | |
368 | scheme->scheme_data = xmalloc(sizeof(auth_basic_config)); | |
369 | memset(scheme->scheme_data, 0, sizeof(auth_basic_config)); | |
370 | basicConfig = static_cast<auth_basic_config *>(scheme->scheme_data); | |
371 | basicConfig->authenticateChildren = 5; | |
372 | basicConfig->credentialsTTL = 2 * 60 * 60; /* two hours */ | |
94439e4e | 373 | } |
62e76326 | 374 | |
e6ccf245 | 375 | basicConfig = static_cast<auth_basic_config *>(scheme->scheme_data); |
62e76326 | 376 | |
94439e4e | 377 | if (strcasecmp(param_str, "program") == 0) { |
62e76326 | 378 | if (basicConfig->authenticate) |
379 | wordlistDestroy(&basicConfig->authenticate); | |
380 | ||
381 | parse_wordlist(&basicConfig->authenticate); | |
382 | ||
383 | requirePathnameExists("authparam basic program", basicConfig->authenticate->key); | |
94439e4e | 384 | } else if (strcasecmp(param_str, "children") == 0) { |
62e76326 | 385 | parse_int(&basicConfig->authenticateChildren); |
94439e4e | 386 | } else if (strcasecmp(param_str, "realm") == 0) { |
62e76326 | 387 | parse_eol(&basicConfig->basicAuthRealm); |
94439e4e | 388 | } else if (strcasecmp(param_str, "credentialsttl") == 0) { |
62e76326 | 389 | parse_time_t(&basicConfig->credentialsTTL); |
94439e4e | 390 | } else { |
62e76326 | 391 | debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str); |
94439e4e | 392 | } |
393 | } | |
394 | ||
395 | static void | |
396 | authenticateBasicStats(StoreEntry * sentry) | |
397 | { | |
398 | storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n"); | |
399 | helperStats(sentry, basicauthenticators); | |
400 | } | |
401 | ||
e6ccf245 | 402 | CBDATA_TYPE(AuthenticateStateData); |
94439e4e | 403 | |
404 | /* authenticateBasicUsername: return a pointer to the username in the */ | |
e6ccf245 | 405 | char const * |
406 | authenticateBasicUsername(auth_user_t const * auth_user) | |
94439e4e | 407 | { |
e6ccf245 | 408 | basic_data *basic_auth = static_cast<basic_data *>(auth_user->scheme_data); |
62e76326 | 409 | |
94439e4e | 410 | if (basic_auth) |
62e76326 | 411 | return basic_auth->username; |
412 | ||
94439e4e | 413 | return NULL; |
414 | } | |
415 | ||
2d72d4fd | 416 | static basic_data * |
c193c972 | 417 | authBasicDataNew(void) |
94439e4e | 418 | { |
419 | basic_data *temp; | |
e6ccf245 | 420 | temp = static_cast<basic_data *>(memPoolAlloc(basic_data_pool)); |
94439e4e | 421 | assert(temp != NULL); |
422 | temp->username = NULL; | |
423 | temp->passwd = NULL; | |
424 | temp->auth_queue = NULL; | |
425 | return temp; | |
426 | } | |
427 | ||
2d72d4fd | 428 | #if UNUSED_CODE |
429 | static void | |
94439e4e | 430 | authBasicDataFree(basic_data * basic_auth) |
62e76326 | 431 | {} |
72711e31 | 432 | |
2d72d4fd | 433 | #endif |
94439e4e | 434 | |
2d72d4fd | 435 | static auth_user_t * |
94439e4e | 436 | authBasicAuthUserFindUsername(const char *username) |
437 | { | |
e6ccf245 | 438 | AuthUserHashPointer *usernamehash; |
94439e4e | 439 | debug(29, 9) ("authBasicAuthUserFindUsername: Looking for user '%s'\n", username); |
62e76326 | 440 | |
e6ccf245 | 441 | if (username && (usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, username)))) { |
62e76326 | 442 | while (usernamehash) { |
443 | if ((authUserHashPointerUser(usernamehash)->auth_type == AUTH_BASIC) && | |
444 | !strcmp(username, (char const *)usernamehash->key)) | |
445 | return authUserHashPointerUser(usernamehash); | |
446 | ||
447 | usernamehash = static_cast<AuthUserHashPointer *>(usernamehash->next); | |
448 | } | |
94439e4e | 449 | } |
62e76326 | 450 | |
94439e4e | 451 | return NULL; |
452 | } | |
453 | ||
454 | ||
455 | ||
456 | /* | |
457 | * Decode a Basic [Proxy-]Auth string, linking the passed auth_user_request structure | |
458 | * to any existing user structure or creating one if needed. Note that just returning | |
459 | * will be treated as "cannot decode credentials". Use the message field to return a | |
460 | * descriptive message to the user. | |
461 | */ | |
462 | ||
463 | static void | |
464 | authenticateBasicDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth) | |
465 | { | |
466 | char *sent_auth; | |
467 | char *cleartext; | |
468 | basic_data *basic_auth, local_basic; | |
469 | auth_user_t *auth_user; | |
470 | dlink_node *node; | |
471 | ||
472 | /* decode the username */ | |
473 | /* trim BASIC from string */ | |
62e76326 | 474 | |
94439e4e | 475 | while (!xisspace(*proxy_auth)) |
62e76326 | 476 | proxy_auth++; |
94439e4e | 477 | |
478 | local_basic.passwd = NULL; | |
479 | ||
480 | /* Trim leading whitespace before decoding */ | |
481 | while (xisspace(*proxy_auth)) | |
62e76326 | 482 | proxy_auth++; |
483 | ||
94439e4e | 484 | /* username and password */ |
485 | sent_auth = xstrdup(proxy_auth); | |
62e76326 | 486 | |
94439e4e | 487 | /* Trim trailing \n before decoding */ |
488 | strtok(sent_auth, "\n"); | |
62e76326 | 489 | |
94439e4e | 490 | cleartext = uudecode(sent_auth); |
62e76326 | 491 | |
94439e4e | 492 | xfree(sent_auth); |
62e76326 | 493 | |
94439e4e | 494 | /* |
495 | * Don't allow NL or CR in the credentials. | |
496 | * Oezguer Kesim <oec@codeblau.de> | |
497 | */ | |
498 | strtok(cleartext, "\r\n"); | |
62e76326 | 499 | |
94439e4e | 500 | debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext); |
62e76326 | 501 | |
94439e4e | 502 | local_basic.username = xstrndup(cleartext, USER_IDENT_SZ); |
62e76326 | 503 | |
94439e4e | 504 | xfree(cleartext); |
62e76326 | 505 | |
94439e4e | 506 | if ((cleartext = strchr(local_basic.username, ':')) != NULL) |
62e76326 | 507 | *(cleartext)++ = '\0'; |
508 | ||
94439e4e | 509 | local_basic.passwd = cleartext; |
62e76326 | 510 | |
94439e4e | 511 | if (cleartext == NULL) { |
62e76326 | 512 | debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n", |
513 | proxy_auth); | |
514 | local_basic.passwd = NULL; | |
515 | authenticateSetDenyMessage (auth_user_request, "no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug"); | |
94439e4e | 516 | } else if (*cleartext == '\0') { |
62e76326 | 517 | debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password," |
518 | "user is '%s'\n", local_basic.username); | |
519 | local_basic.passwd = NULL; | |
520 | authenticateSetDenyMessage (auth_user_request, "Request denied because you provided an empty password. Users MUST have a password."); | |
94439e4e | 521 | } |
62e76326 | 522 | |
94439e4e | 523 | /* special case: we have to free the strings for user and password |
524 | * if we are not returning a filled out structure | |
525 | */ | |
526 | if (local_basic.passwd == NULL) { | |
62e76326 | 527 | if (local_basic.username) { |
528 | /* log the username */ | |
529 | debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", local_basic.username); | |
530 | /* new auth_user */ | |
531 | auth_user = authenticateAuthUserNew("basic"); | |
532 | /* new scheme data */ | |
533 | basic_auth = authBasicDataNew(); | |
534 | /* save the credentials */ | |
535 | basic_auth->username = local_basic.username; | |
536 | /* link the scheme data in */ | |
537 | auth_user->scheme_data = basic_auth; | |
538 | /* set the auth_user type */ | |
539 | auth_user->auth_type = AUTH_BROKEN; | |
540 | /* link the request to the user */ | |
541 | auth_user_request->auth_user = auth_user; | |
542 | /* lock for the auth_user_request link */ | |
543 | authenticateAuthUserLock(auth_user); | |
544 | node = dlinkNodeNew(); | |
545 | dlinkAdd(auth_user_request, node, &auth_user->requests); | |
546 | } | |
547 | ||
548 | return; | |
94439e4e | 549 | } else { |
62e76326 | 550 | local_basic.passwd = xstrndup(cleartext, USER_IDENT_SZ); |
94439e4e | 551 | } |
552 | ||
553 | /* now lookup and see if we have a matching auth_user structure in memory. */ | |
554 | ||
555 | if ((auth_user = authBasicAuthUserFindUsername(local_basic.username)) == NULL) { | |
62e76326 | 556 | /* the user doesn't exist in the username cache yet */ |
557 | debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", local_basic.username); | |
558 | /* new auth_user */ | |
559 | auth_user = authenticateAuthUserNew("basic"); | |
560 | /* new scheme data */ | |
561 | basic_auth = authBasicDataNew(); | |
562 | /* save the credentials */ | |
563 | basic_auth->username = local_basic.username; | |
564 | basic_auth->passwd = local_basic.passwd; | |
565 | /* link the scheme data in */ | |
566 | auth_user->scheme_data = basic_auth; | |
567 | /* set the auth_user type */ | |
568 | auth_user->auth_type = AUTH_BASIC; | |
569 | /* current time for timeouts */ | |
570 | auth_user->expiretime = current_time.tv_sec; | |
571 | ||
572 | /* this auth_user struct is the 'lucky one' to get added to the username cache */ | |
573 | /* the requests after this link to the auth_user */ | |
574 | /* store user in hash */ | |
575 | authenticateUserNameCacheAdd(auth_user); | |
94439e4e | 576 | } else { |
62e76326 | 577 | debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%p'\n", local_basic.username, auth_user); |
578 | xfree(local_basic.username); | |
579 | basic_auth = static_cast<basic_data *>(auth_user->scheme_data); | |
580 | ||
581 | if (strcmp(local_basic.passwd, basic_auth->passwd)) { | |
582 | debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n"); | |
583 | basic_auth->flags.credentials_ok = 0; | |
584 | xfree(basic_auth->passwd); | |
585 | basic_auth->passwd = local_basic.passwd; | |
586 | } else | |
587 | xfree(local_basic.passwd); | |
588 | ||
589 | if (basic_auth->flags.credentials_ok == 3) { | |
590 | debug(29, 4) ("authBasicDecodeAuth: last attempt to authenticate this user failed, resetting auth state to unchecked\n"); | |
591 | basic_auth->flags.credentials_ok = 0; | |
592 | } | |
94439e4e | 593 | } |
62e76326 | 594 | |
94439e4e | 595 | /* link the request to the user */ |
596 | auth_user_request->auth_user = auth_user; | |
62e76326 | 597 | |
94439e4e | 598 | /* lock for the auth_user_request link */ |
599 | authenticateAuthUserLock(auth_user); | |
62e76326 | 600 | |
94439e4e | 601 | node = dlinkNodeNew(); |
62e76326 | 602 | |
94439e4e | 603 | dlinkAdd(auth_user_request, node, &auth_user->requests); |
62e76326 | 604 | |
94439e4e | 605 | return; |
606 | } | |
607 | ||
608 | /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the | |
609 | * config file */ | |
610 | static void | |
611 | authBasicInit(authScheme * scheme) | |
612 | { | |
613 | static int init = 0; | |
62e76326 | 614 | |
94439e4e | 615 | if (basicConfig->authenticate) { |
62e76326 | 616 | if (!basic_data_pool) |
617 | basic_data_pool = memPoolCreate("Basic Scheme User Data", sizeof(basic_data)); | |
618 | ||
619 | authbasic_initialised = 1; | |
620 | ||
621 | if (basicauthenticators == NULL) | |
622 | basicauthenticators = helperCreate("basicauthenticator"); | |
623 | ||
624 | basicauthenticators->cmdline = basicConfig->authenticate; | |
625 | ||
626 | basicauthenticators->n_to_start = basicConfig->authenticateChildren; | |
627 | ||
628 | basicauthenticators->ipc_type = IPC_STREAM; | |
629 | ||
630 | helperOpenServers(basicauthenticators); | |
631 | ||
632 | if (!init) { | |
633 | cachemgrRegister("basicauthenticator", | |
634 | "Basic User Authenticator Stats", | |
635 | authenticateBasicStats, 0, 1); | |
636 | init++; | |
637 | } | |
638 | ||
639 | CBDATA_INIT_TYPE(AuthenticateStateData); | |
94439e4e | 640 | } |
641 | } | |
642 | ||
643 | /* send the initial data to a basic authenticator module */ | |
644 | static void | |
645 | authenticateBasicStart(auth_user_request_t * auth_user_request, RH * handler, void *data) | |
646 | { | |
e6ccf245 | 647 | AuthenticateStateData *r = NULL; |
94439e4e | 648 | char buf[8192]; |
9bbd1655 | 649 | char user[1024], pass[1024]; |
94439e4e | 650 | basic_data *basic_auth; |
651 | assert(auth_user_request); | |
652 | assert(handler); | |
653 | assert(auth_user_request->auth_user->auth_type == AUTH_BASIC); | |
654 | assert(auth_user_request->auth_user->scheme_data != NULL); | |
e6ccf245 | 655 | basic_auth = static_cast<basic_data *>(auth_user_request->auth_user->scheme_data); |
94439e4e | 656 | debug(29, 9) ("authenticateStart: '%s:%s'\n", basic_auth->username, |
62e76326 | 657 | basic_auth->passwd); |
658 | ||
94439e4e | 659 | if (basicConfig->authenticate == NULL) { |
62e76326 | 660 | handler(data, NULL); |
661 | return; | |
94439e4e | 662 | } |
62e76326 | 663 | |
94439e4e | 664 | /* check to see if the auth_user already has a request outstanding */ |
bd507204 | 665 | if (basic_auth->flags.credentials_ok == 2) { |
62e76326 | 666 | /* there is a request with the same credentials already being verified */ |
667 | BasicAuthQueueNode *node; | |
668 | node = static_cast<BasicAuthQueueNode *>(xmalloc(sizeof(BasicAuthQueueNode))); | |
669 | assert(node); | |
670 | /* save the details */ | |
671 | node->next = basic_auth->auth_queue; | |
672 | basic_auth->auth_queue = node; | |
673 | node->auth_user_request = auth_user_request; | |
674 | node->handler = handler; | |
675 | node->data = cbdataReference(data); | |
676 | return; | |
94439e4e | 677 | } else { |
62e76326 | 678 | r = cbdataAlloc(AuthenticateStateData); |
679 | r->handler = handler; | |
680 | r->data = cbdataReference(data); | |
681 | r->auth_user_request = auth_user_request; | |
682 | /* mark the user as haveing verification in progress */ | |
683 | basic_auth->flags.credentials_ok = 2; | |
684 | xstrncpy(user, rfc1738_escape(basic_auth->username), sizeof(user)); | |
685 | xstrncpy(pass, rfc1738_escape(basic_auth->passwd), sizeof(pass)); | |
686 | snprintf(buf, sizeof(buf), "%s %s\n", user, pass); | |
687 | helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r); | |
94439e4e | 688 | } |
689 | } |