]>
Commit | Line | Data |
---|---|---|
94439e4e | 1 | /* |
411c6ea3 | 2 | * $Id: auth_basic.cc,v 1.36 2005/01/06 13:16:39 serassio 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" | |
924f73bc | 44 | #include "HttpReply.h" |
f5691f9c | 45 | #include "basicScheme.h" |
94439e4e | 46 | |
47 | static void | |
e6ccf245 | 48 | authenticateStateFree(AuthenticateStateData * r) |
94439e4e | 49 | { |
50 | cbdataFree(r); | |
51 | } | |
52 | ||
53 | /* Basic Scheme */ | |
54 | ||
55 | static HLPCB authenticateBasicHandleReply; | |
94439e4e | 56 | static AUTHSSTATS authenticateBasicStats; |
94439e4e | 57 | |
58 | static helper *basicauthenticators = NULL; | |
59 | ||
f5691f9c | 60 | static AuthBasicConfig basicConfig; |
94439e4e | 61 | |
62 | static int authbasic_initialised = 0; | |
94439e4e | 63 | |
2d72d4fd | 64 | |
94439e4e | 65 | /* |
66 | * | |
2d72d4fd | 67 | * Public Functions |
94439e4e | 68 | * |
69 | */ | |
70 | ||
2d72d4fd | 71 | /* internal functions */ |
72 | ||
f5691f9c | 73 | /* TODO: move to basicScheme.cc - after all per request and user functions are moved out */ |
74 | void | |
75 | basicScheme::done() | |
2d72d4fd | 76 | { |
f5691f9c | 77 | /* TODO: this should be a Config call. */ |
78 | ||
2d72d4fd | 79 | if (basicauthenticators) |
62e76326 | 80 | helperShutdown(basicauthenticators); |
81 | ||
2d72d4fd | 82 | authbasic_initialised = 0; |
62e76326 | 83 | |
2d72d4fd | 84 | if (!shutting_down) |
62e76326 | 85 | return; |
86 | ||
2d72d4fd | 87 | if (basicauthenticators) |
62e76326 | 88 | helperFree(basicauthenticators); |
89 | ||
2d72d4fd | 90 | basicauthenticators = NULL; |
62e76326 | 91 | |
f5691f9c | 92 | /* XXX Reinstate auth shutdown for dynamic schemes? */ |
2d72d4fd | 93 | debug(29, 2) ("authBasicDone: Basic authentication Shutdown.\n"); |
94 | } | |
95 | ||
f5691f9c | 96 | bool |
97 | AuthBasicConfig::active() const | |
2d70df72 | 98 | { |
f5691f9c | 99 | return authbasic_initialised == 1; |
2d70df72 | 100 | } |
101 | ||
f5691f9c | 102 | bool |
103 | AuthBasicConfig::configured() const | |
94439e4e | 104 | { |
f5691f9c | 105 | if ((authenticate != NULL) && (authenticateChildren != 0) && |
106 | (basicAuthRealm != NULL)) { | |
62e76326 | 107 | debug(29, 9) ("authBasicConfigured: returning configured\n"); |
f5691f9c | 108 | return true; |
2d70df72 | 109 | } |
62e76326 | 110 | |
2d70df72 | 111 | debug(29, 9) ("authBasicConfigured: returning unconfigured\n"); |
f5691f9c | 112 | return false; |
94439e4e | 113 | } |
114 | ||
f5691f9c | 115 | const char * |
116 | AuthBasicConfig::type() const | |
94439e4e | 117 | { |
f5691f9c | 118 | return basicScheme::GetInstance().type(); |
119 | } | |
62e76326 | 120 | |
f5691f9c | 121 | AuthBasicUserRequest::AuthBasicUserRequest() : _theUser(NULL) |
122 | {} | |
123 | ||
124 | AuthBasicUserRequest::~AuthBasicUserRequest() | |
125 | {} | |
126 | ||
127 | ||
128 | bool | |
129 | BasicUser::authenticated() const | |
94439e4e | 130 | { |
f5691f9c | 131 | if ((flags.credentials_ok == 1) && (credentials_checkedtime + basicConfig.credentialsTTL > squid_curtime)) |
132 | return true; | |
133 | ||
134 | debug(29, 4) ("User not authenticated or credentials need rechecking.\n"); | |
135 | ||
136 | return false; | |
94439e4e | 137 | } |
62e76326 | 138 | |
f5691f9c | 139 | int |
140 | AuthBasicUserRequest::authenticated() const | |
141 | { | |
142 | BasicUser const *basic_auth = dynamic_cast<BasicUser const *>(user()); | |
143 | assert (user()); | |
144 | ||
145 | if (basic_auth->authenticated()) | |
146 | return 1; | |
147 | ||
148 | return 0; | |
149 | } | |
94439e4e | 150 | |
151 | /* log a basic user in | |
152 | */ | |
f5691f9c | 153 | void |
154 | AuthBasicUserRequest::authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type) | |
94439e4e | 155 | { |
f5691f9c | 156 | assert(user() != NULL); |
94439e4e | 157 | |
f5691f9c | 158 | basic_data *basic_auth = dynamic_cast<BasicUser *>(user()); |
9bea1d5b | 159 | |
bd507204 | 160 | /* if the password is not ok, do an identity */ |
62e76326 | 161 | |
bd507204 | 162 | if (basic_auth->flags.credentials_ok != 1) |
62e76326 | 163 | return; |
94439e4e | 164 | |
165 | /* are we about to recheck the credentials externally? */ | |
f5691f9c | 166 | if ((basic_auth->credentials_checkedtime + basicConfig.credentialsTTL) <= squid_curtime) { |
62e76326 | 167 | debug(29, 4) ("authBasicAuthenticate: credentials expired - rechecking\n"); |
168 | return; | |
94439e4e | 169 | } |
62e76326 | 170 | |
94439e4e | 171 | /* we have been through the external helper, and the credentials haven't expired */ |
172 | debug(29, 9) ("authenticateBasicAuthenticateuser: user '%s' authenticated\n", | |
f5691f9c | 173 | basic_auth->username()); |
94439e4e | 174 | |
f5691f9c | 175 | /* Decode now takes care of finding the AuthUser struct in the cache */ |
94439e4e | 176 | /* after external auth occurs anyway */ |
f5691f9c | 177 | basic_auth->expiretime = current_time.tv_sec; |
62e76326 | 178 | |
94439e4e | 179 | return; |
180 | } | |
181 | ||
182 | int | |
f5691f9c | 183 | AuthBasicUserRequest::module_direction() |
94439e4e | 184 | { |
62e76326 | 185 | /* null auth_user is checked for by authenticateDirection */ |
f5691f9c | 186 | basic_data *basic_auth = dynamic_cast<BasicUser *>(user()); |
187 | assert (basic_auth); | |
62e76326 | 188 | |
bd507204 | 189 | switch (basic_auth->flags.credentials_ok) { |
62e76326 | 190 | |
94439e4e | 191 | case 0: /* not checked */ |
62e76326 | 192 | return -1; |
193 | ||
94439e4e | 194 | case 1: /* checked & ok */ |
62e76326 | 195 | |
f5691f9c | 196 | if (basic_auth->credentials_checkedtime + basicConfig.credentialsTTL <= squid_curtime) |
62e76326 | 197 | return -1; |
198 | ||
199 | return 0; | |
200 | ||
94439e4e | 201 | case 2: /* paused while waiting for a username:password check on another request */ |
62e76326 | 202 | return -1; |
203 | ||
94439e4e | 204 | case 3: /* authentication process failed. */ |
88d3f890 | 205 | return 0; |
94439e4e | 206 | } |
62e76326 | 207 | |
94439e4e | 208 | return -2; |
209 | } | |
210 | ||
211 | void | |
f5691f9c | 212 | AuthBasicConfig::fixHeader(auth_user_request_t *auth_user_request, HttpReply *rep, http_hdr_type type, HttpRequest * request) |
94439e4e | 213 | { |
f5691f9c | 214 | if (authenticate) { |
215 | debug(29, 9) ("authenticateFixErrorHeader: Sending type:%d header: 'Basic realm=\"%s\"'\n", type, basicAuthRealm); | |
216 | httpHeaderPutStrf(&rep->header, type, "Basic realm=\"%s\"", basicAuthRealm); | |
94439e4e | 217 | } |
218 | } | |
219 | ||
220 | /* free any allocated configuration details */ | |
221 | void | |
f5691f9c | 222 | AuthBasicConfig::done() |
94439e4e | 223 | { |
f5691f9c | 224 | if (authenticate) |
225 | wordlistDestroy(&authenticate); | |
62e76326 | 226 | |
f5691f9c | 227 | if (basicAuthRealm) |
228 | safe_free(basicAuthRealm); | |
94439e4e | 229 | } |
230 | ||
f5691f9c | 231 | BasicUser::~BasicUser() |
94439e4e | 232 | { |
f5691f9c | 233 | if (passwd) |
234 | xfree(passwd); | |
62e76326 | 235 | |
f5691f9c | 236 | safe_free (cleartext); |
94439e4e | 237 | } |
238 | ||
239 | static void | |
240 | authenticateBasicHandleReply(void *data, char *reply) | |
241 | { | |
e6ccf245 | 242 | AuthenticateStateData *r = static_cast<AuthenticateStateData *>(data); |
e6ccf245 | 243 | BasicAuthQueueNode *tmpnode; |
94439e4e | 244 | char *t = NULL; |
fa80a8ef | 245 | void *cbdata; |
94439e4e | 246 | debug(29, 9) ("authenticateBasicHandleReply: {%s}\n", reply ? reply : "<NULL>"); |
62e76326 | 247 | |
94439e4e | 248 | if (reply) { |
62e76326 | 249 | if ((t = strchr(reply, ' '))) |
250 | *t = '\0'; | |
251 | ||
252 | if (*reply == '\0') | |
253 | reply = NULL; | |
94439e4e | 254 | } |
62e76326 | 255 | |
94439e4e | 256 | assert(r->auth_user_request != NULL); |
f5691f9c | 257 | assert(r->auth_user_request->user()->auth_type == AUTH_BASIC); |
258 | basic_data *basic_auth = dynamic_cast<basic_data *>(r->auth_user_request->user()); | |
62e76326 | 259 | |
94439e4e | 260 | if (reply && (strncasecmp(reply, "OK", 2) == 0)) |
62e76326 | 261 | basic_auth->flags.credentials_ok = 1; |
94439e4e | 262 | else |
62e76326 | 263 | basic_auth->flags.credentials_ok = 3; |
264 | ||
94439e4e | 265 | basic_auth->credentials_checkedtime = squid_curtime; |
62e76326 | 266 | |
fa80a8ef | 267 | if (cbdataReferenceValidDone(r->data, &cbdata)) |
62e76326 | 268 | r->handler(cbdata, NULL); |
269 | ||
fa80a8ef | 270 | cbdataReferenceDone(r->data); |
62e76326 | 271 | |
f2afa96a | 272 | while (basic_auth->auth_queue) { |
62e76326 | 273 | tmpnode = basic_auth->auth_queue->next; |
274 | ||
275 | if (cbdataReferenceValidDone(basic_auth->auth_queue->data, &cbdata)) | |
276 | basic_auth->auth_queue->handler(cbdata, NULL); | |
277 | ||
278 | xfree(basic_auth->auth_queue); | |
279 | ||
280 | basic_auth->auth_queue = tmpnode; | |
94439e4e | 281 | } |
62e76326 | 282 | |
94439e4e | 283 | authenticateStateFree(r); |
284 | } | |
285 | ||
f5691f9c | 286 | void |
287 | AuthBasicConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme) | |
94439e4e | 288 | { |
f5691f9c | 289 | wordlist *list = authenticate; |
94439e4e | 290 | storeAppendPrintf(entry, "%s %s", name, "basic"); |
62e76326 | 291 | |
94439e4e | 292 | while (list != NULL) { |
62e76326 | 293 | storeAppendPrintf(entry, " %s", list->key); |
294 | list = list->next; | |
94439e4e | 295 | } |
62e76326 | 296 | |
07eca7e0 | 297 | storeAppendPrintf(entry, "\n"); |
298 | ||
f5691f9c | 299 | storeAppendPrintf(entry, "%s basic realm %s\n", name, basicAuthRealm); |
300 | storeAppendPrintf(entry, "%s basic children %d\n", name, authenticateChildren); | |
301 | storeAppendPrintf(entry, "%s basic concurrency %d\n", name, authenticateConcurrency); | |
302 | storeAppendPrintf(entry, "%s basic credentialsttl %d seconds\n", name, (int) credentialsTTL); | |
64658378 | 303 | storeAppendPrintf(entry, "%s basic casesensitive %s\n", name, casesensitive ? "on" : "off"); |
94439e4e | 304 | |
305 | } | |
306 | ||
f5691f9c | 307 | AuthBasicConfig::AuthBasicConfig() |
308 | { | |
309 | /* TODO: move into initialisation list */ | |
310 | authenticateChildren = 5; | |
311 | credentialsTTL = 2 * 60 * 60; /* two hours */ | |
312 | } | |
62e76326 | 313 | |
f5691f9c | 314 | void |
315 | AuthBasicConfig::parse(AuthConfig * scheme, int n_configured, char *param_str) | |
316 | { | |
94439e4e | 317 | if (strcasecmp(param_str, "program") == 0) { |
f5691f9c | 318 | if (authenticate) |
319 | wordlistDestroy(&authenticate); | |
62e76326 | 320 | |
f5691f9c | 321 | parse_wordlist(&authenticate); |
62e76326 | 322 | |
f5691f9c | 323 | requirePathnameExists("authparam basic program", authenticate->key); |
94439e4e | 324 | } else if (strcasecmp(param_str, "children") == 0) { |
f5691f9c | 325 | parse_int(&authenticateChildren); |
07eca7e0 | 326 | } else if (strcasecmp(param_str, "concurrency") == 0) { |
f5691f9c | 327 | parse_int(&authenticateConcurrency); |
94439e4e | 328 | } else if (strcasecmp(param_str, "realm") == 0) { |
f5691f9c | 329 | parse_eol(&basicAuthRealm); |
94439e4e | 330 | } else if (strcasecmp(param_str, "credentialsttl") == 0) { |
f5691f9c | 331 | parse_time_t(&credentialsTTL); |
64658378 | 332 | } else if (strcasecmp(param_str, "casesensitive") == 0) { |
333 | parse_onoff(&casesensitive); | |
94439e4e | 334 | } else { |
62e76326 | 335 | debug(28, 0) ("unrecognised basic auth scheme parameter '%s'\n", param_str); |
94439e4e | 336 | } |
337 | } | |
338 | ||
339 | static void | |
340 | authenticateBasicStats(StoreEntry * sentry) | |
341 | { | |
342 | storeAppendPrintf(sentry, "Basic Authenticator Statistics:\n"); | |
343 | helperStats(sentry, basicauthenticators); | |
344 | } | |
345 | ||
e6ccf245 | 346 | CBDATA_TYPE(AuthenticateStateData); |
94439e4e | 347 | |
2d72d4fd | 348 | static auth_user_t * |
94439e4e | 349 | authBasicAuthUserFindUsername(const char *username) |
350 | { | |
e6ccf245 | 351 | AuthUserHashPointer *usernamehash; |
94439e4e | 352 | debug(29, 9) ("authBasicAuthUserFindUsername: Looking for user '%s'\n", username); |
62e76326 | 353 | |
e6ccf245 | 354 | if (username && (usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, username)))) { |
62e76326 | 355 | while (usernamehash) { |
f5691f9c | 356 | if ((usernamehash->user()->auth_type == AUTH_BASIC) && |
62e76326 | 357 | !strcmp(username, (char const *)usernamehash->key)) |
f5691f9c | 358 | return usernamehash->user(); |
62e76326 | 359 | |
360 | usernamehash = static_cast<AuthUserHashPointer *>(usernamehash->next); | |
361 | } | |
94439e4e | 362 | } |
62e76326 | 363 | |
94439e4e | 364 | return NULL; |
365 | } | |
366 | ||
f5691f9c | 367 | void |
368 | BasicUser::deleteSelf() const | |
369 | { | |
370 | delete this; | |
371 | } | |
94439e4e | 372 | |
f5691f9c | 373 | BasicUser::BasicUser(AuthConfig *config) : AuthUser (config) , passwd (NULL), credentials_checkedtime(0), auth_queue(NULL), cleartext (NULL), currentRequest (NULL), httpAuthHeader (NULL) |
374 | { | |
375 | flags.credentials_ok = 0; | |
376 | } | |
62e76326 | 377 | |
f5691f9c | 378 | void |
379 | BasicUser::decodeCleartext() | |
380 | { | |
381 | char *sent_auth; | |
94439e4e | 382 | /* username and password */ |
f5691f9c | 383 | sent_auth = xstrdup(httpAuthHeader); |
94439e4e | 384 | /* Trim trailing \n before decoding */ |
385 | strtok(sent_auth, "\n"); | |
62e76326 | 386 | |
94439e4e | 387 | cleartext = uudecode(sent_auth); |
62e76326 | 388 | |
94439e4e | 389 | xfree(sent_auth); |
f5691f9c | 390 | } |
62e76326 | 391 | |
f5691f9c | 392 | void |
393 | BasicUser::extractUsername() | |
394 | { | |
94439e4e | 395 | /* |
396 | * Don't allow NL or CR in the credentials. | |
397 | * Oezguer Kesim <oec@codeblau.de> | |
398 | */ | |
399 | strtok(cleartext, "\r\n"); | |
62e76326 | 400 | |
94439e4e | 401 | debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext); |
62e76326 | 402 | |
411c6ea3 | 403 | char * tempusername = xstrndup(cleartext, USER_IDENT_SZ); |
94439e4e | 404 | xfree(cleartext); |
f5691f9c | 405 | /* terminate the username string */ |
62e76326 | 406 | |
411c6ea3 | 407 | if ((cleartext = strchr(tempusername, ':')) != NULL) |
62e76326 | 408 | *(cleartext)++ = '\0'; |
64658378 | 409 | |
411c6ea3 | 410 | username (tempusername); |
411 | ||
64658378 | 412 | if (!basicConfig.casesensitive) |
413 | Tolower((char *)username()); | |
f5691f9c | 414 | } |
62e76326 | 415 | |
f5691f9c | 416 | void |
417 | BasicUser::extractPassword() | |
418 | { | |
419 | passwd = cleartext; | |
62e76326 | 420 | |
94439e4e | 421 | if (cleartext == NULL) { |
62e76326 | 422 | debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n", |
f5691f9c | 423 | httpAuthHeader); |
424 | passwd = NULL; | |
425 | currentRequest->setDenyMessage ("no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug"); | |
94439e4e | 426 | } else if (*cleartext == '\0') { |
62e76326 | 427 | debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password," |
f5691f9c | 428 | "user is '%s'\n", username()); |
429 | passwd = NULL; | |
430 | currentRequest->setDenyMessage ("Request denied because you provided an empty password. Users MUST have a password."); | |
94439e4e | 431 | } |
62e76326 | 432 | |
f5691f9c | 433 | if (passwd) |
434 | passwd = xstrndup(cleartext, USER_IDENT_SZ); | |
62e76326 | 435 | |
f5691f9c | 436 | cleartext = NULL; |
437 | } | |
94439e4e | 438 | |
f5691f9c | 439 | void |
440 | BasicUser::decode(char const *proxy_auth, AuthUserRequest *auth_user_request) | |
441 | { | |
442 | currentRequest = auth_user_request; | |
443 | httpAuthHeader = proxy_auth; | |
444 | decodeCleartext (); | |
445 | extractUsername(); | |
446 | extractPassword(); | |
447 | currentRequest = NULL; | |
448 | httpAuthHeader = NULL; | |
449 | } | |
450 | ||
451 | bool | |
452 | BasicUser::valid() const | |
453 | { | |
454 | return passwd != NULL; | |
455 | } | |
94439e4e | 456 | |
f5691f9c | 457 | void |
458 | BasicUser::makeLoggingInstance(AuthBasicUserRequest *auth_user_request) | |
459 | { | |
460 | if (username()) { | |
461 | /* log the username */ | |
462 | debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", username()); | |
62e76326 | 463 | /* new scheme data */ |
f5691f9c | 464 | BasicUser *basic_auth = new BasicUser(& basicConfig); |
465 | auth_user_request->user(basic_auth); | |
62e76326 | 466 | /* save the credentials */ |
f5691f9c | 467 | basic_auth->username(username()); |
468 | username(NULL); | |
62e76326 | 469 | /* set the auth_user type */ |
f5691f9c | 470 | basic_auth->auth_type = AUTH_BROKEN; |
471 | /* link the request to the user */ | |
472 | basic_auth->addRequest(auth_user_request); | |
473 | } | |
474 | } | |
475 | ||
476 | AuthUser * | |
477 | BasicUser::makeCachedFrom() | |
478 | { | |
479 | /* the user doesn't exist in the username cache yet */ | |
480 | debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", username()); | |
481 | BasicUser *basic_user = new BasicUser(&basicConfig); | |
482 | /* save the credentials */ | |
483 | basic_user->username(username()); | |
484 | username(NULL); | |
485 | basic_user->passwd = passwd; | |
486 | passwd = NULL; | |
487 | /* set the auth_user type */ | |
488 | basic_user->auth_type = AUTH_BASIC; | |
489 | /* current time for timeouts */ | |
490 | basic_user->expiretime = current_time.tv_sec; | |
491 | ||
492 | /* this basic_user struct is the 'lucky one' to get added to the username cache */ | |
493 | /* the requests after this link to the basic_user */ | |
494 | /* store user in hash */ | |
495 | basic_user->addToNameCache(); | |
496 | return basic_user; | |
497 | } | |
498 | ||
499 | void | |
500 | BasicUser::updateCached(BasicUser *from) | |
501 | { | |
502 | debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%p'\n", from->username(), this); | |
503 | ||
504 | if (strcmp(from->passwd, passwd)) { | |
505 | debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n"); | |
506 | flags.credentials_ok = 0; | |
507 | xfree(passwd); | |
508 | passwd = from->passwd; | |
509 | from->passwd = NULL; | |
510 | } | |
511 | ||
512 | if (flags.credentials_ok == 3) { | |
513 | debug(29, 4) ("authBasicDecodeAuth: last attempt to authenticate this user failed, resetting auth state to unchecked\n"); | |
514 | flags.credentials_ok = 0; | |
515 | } | |
516 | } | |
517 | ||
518 | /* | |
519 | * Decode a Basic [Proxy-]Auth string, linking the passed | |
520 | * auth_user_request structure to any existing user structure or creating one | |
521 | * if needed. Note that just returning will be treated as | |
522 | * "cannot decode credentials". Use the message field to return a | |
523 | * descriptive message to the user. | |
524 | */ | |
525 | AuthUserRequest * | |
526 | AuthBasicConfig::decode(char const *proxy_auth) | |
527 | { | |
528 | AuthBasicUserRequest *auth_user_request = new AuthBasicUserRequest(); | |
529 | /* decode the username */ | |
530 | /* trim BASIC from string */ | |
531 | ||
ba53f4b8 | 532 | while (xisgraph(*proxy_auth)) |
f5691f9c | 533 | proxy_auth++; |
534 | ||
535 | BasicUser *basic_auth, local_basic(&basicConfig); | |
536 | ||
537 | /* Trim leading whitespace before decoding */ | |
538 | while (xisspace(*proxy_auth)) | |
539 | proxy_auth++; | |
540 | ||
541 | local_basic.decode(proxy_auth, auth_user_request); | |
542 | ||
543 | if (!local_basic.valid()) { | |
544 | local_basic.makeLoggingInstance(auth_user_request); | |
545 | return auth_user_request; | |
94439e4e | 546 | } |
62e76326 | 547 | |
f5691f9c | 548 | /* now lookup and see if we have a matching auth_user structure in |
549 | * memory. */ | |
62e76326 | 550 | |
f5691f9c | 551 | auth_user_t *auth_user; |
62e76326 | 552 | |
f5691f9c | 553 | if ((auth_user = authBasicAuthUserFindUsername(local_basic.username())) == NULL) { |
554 | auth_user = local_basic.makeCachedFrom(); | |
555 | basic_auth = dynamic_cast<BasicUser *>(auth_user); | |
556 | assert (basic_auth); | |
557 | } else { | |
558 | basic_auth = dynamic_cast<BasicUser *>(auth_user); | |
559 | assert (basic_auth); | |
560 | basic_auth->updateCached (&local_basic); | |
561 | } | |
62e76326 | 562 | |
f5691f9c | 563 | /* link the request to the in-cache user */ |
564 | auth_user_request->user(basic_auth); | |
62e76326 | 565 | |
f5691f9c | 566 | basic_auth->addRequest(auth_user_request); |
567 | ||
568 | return auth_user_request; | |
94439e4e | 569 | } |
570 | ||
571 | /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the | |
572 | * config file */ | |
f5691f9c | 573 | void |
574 | AuthBasicConfig::init(AuthConfig * scheme) | |
94439e4e | 575 | { |
576 | static int init = 0; | |
62e76326 | 577 | |
f5691f9c | 578 | if (authenticate) { |
62e76326 | 579 | authbasic_initialised = 1; |
580 | ||
581 | if (basicauthenticators == NULL) | |
582 | basicauthenticators = helperCreate("basicauthenticator"); | |
583 | ||
f5691f9c | 584 | basicauthenticators->cmdline = authenticate; |
62e76326 | 585 | |
f5691f9c | 586 | basicauthenticators->n_to_start = authenticateChildren; |
62e76326 | 587 | |
f5691f9c | 588 | basicauthenticators->concurrency = authenticateConcurrency; |
07eca7e0 | 589 | |
62e76326 | 590 | basicauthenticators->ipc_type = IPC_STREAM; |
591 | ||
592 | helperOpenServers(basicauthenticators); | |
593 | ||
594 | if (!init) { | |
595 | cachemgrRegister("basicauthenticator", | |
596 | "Basic User Authenticator Stats", | |
597 | authenticateBasicStats, 0, 1); | |
598 | init++; | |
599 | } | |
600 | ||
601 | CBDATA_INIT_TYPE(AuthenticateStateData); | |
94439e4e | 602 | } |
603 | } | |
604 | ||
f5691f9c | 605 | void |
606 | BasicUser::queueRequest(auth_user_request_t * auth_user_request, RH * handler, void *data) | |
607 | { | |
608 | BasicAuthQueueNode *node; | |
609 | node = static_cast<BasicAuthQueueNode *>(xmalloc(sizeof(BasicAuthQueueNode))); | |
610 | assert(node); | |
611 | /* save the details */ | |
612 | node->next = auth_queue; | |
613 | auth_queue = node; | |
614 | node->auth_user_request = auth_user_request; | |
615 | node->handler = handler; | |
616 | node->data = cbdataReference(data); | |
617 | } | |
618 | ||
94439e4e | 619 | /* send the initial data to a basic authenticator module */ |
f5691f9c | 620 | void |
621 | AuthBasicUserRequest::module_start(RH * handler, void *data) | |
94439e4e | 622 | { |
94439e4e | 623 | basic_data *basic_auth; |
f5691f9c | 624 | assert(user()->auth_type == AUTH_BASIC); |
625 | basic_auth = dynamic_cast<basic_data *>(user()); | |
626 | debug(29, 9) ("AuthBasicUserRequest::start: '%s:%s'\n", basic_auth->username(), | |
62e76326 | 627 | basic_auth->passwd); |
628 | ||
f5691f9c | 629 | if (basicConfig.authenticate == NULL) { |
62e76326 | 630 | handler(data, NULL); |
631 | return; | |
94439e4e | 632 | } |
62e76326 | 633 | |
94439e4e | 634 | /* check to see if the auth_user already has a request outstanding */ |
bd507204 | 635 | if (basic_auth->flags.credentials_ok == 2) { |
62e76326 | 636 | /* there is a request with the same credentials already being verified */ |
f5691f9c | 637 | basic_auth->queueRequest(this, handler, data); |
62e76326 | 638 | return; |
94439e4e | 639 | } |
f5691f9c | 640 | |
641 | basic_auth->submitRequest (this, handler, data); | |
94439e4e | 642 | } |
f5691f9c | 643 | |
644 | void | |
645 | BasicUser::submitRequest (auth_user_request_t * auth_user_request, RH * handler, void *data) | |
646 | { | |
647 | /* mark the user as haveing verification in progress */ | |
648 | flags.credentials_ok = 2; | |
649 | AuthenticateStateData *r = NULL; | |
650 | char buf[8192]; | |
651 | char user[1024], pass[1024]; | |
652 | r = cbdataAlloc(AuthenticateStateData); | |
653 | r->handler = handler; | |
654 | r->data = cbdataReference(data); | |
655 | r->auth_user_request = auth_user_request; | |
656 | xstrncpy(user, rfc1738_escape(username()), sizeof(user)); | |
657 | xstrncpy(pass, rfc1738_escape(passwd), sizeof(pass)); | |
658 | snprintf(buf, sizeof(buf), "%s %s\n", user, pass); | |
659 | helperSubmit(basicauthenticators, buf, authenticateBasicHandleReply, r); | |
660 | } | |
661 | ||
662 | AuthConfig * | |
663 | basicScheme::createConfig() | |
664 | { | |
665 | return &basicConfig; | |
666 | } | |
667 |