]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/ntlm/auth_ntlm.cc
Bootstrapped
[thirdparty/squid.git] / src / auth / ntlm / auth_ntlm.cc
CommitLineData
94439e4e 1
2/*
30abd221 3 * $Id: auth_ntlm.cc,v 1.70 2007/05/29 13:31:46 amosjeffries Exp $
94439e4e 4 *
5 * DEBUG: section 29 NTLM Authenticator
6bf4f823 6 * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli
94439e4e 7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
94439e4e 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
94439e4e 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/* 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
41#include "squid.h"
42#include "auth_ntlm.h"
e6ccf245 43#include "authenticate.h"
62ee09ca 44#include "CacheManager.h"
e6ccf245 45#include "Store.h"
a46d2c0e 46#include "client_side.h"
924f73bc 47#include "HttpReply.h"
a2ac85d9 48#include "HttpRequest.h"
f5691f9c 49/* TODO remove this include */
50#include "ntlmScheme.h"
d295d770 51#include "wordlist.h"
c78aa667 52
6bf4f823 53static void
76f142cd 54authenticateNTLMReleaseServer(AuthUserRequest * auth_user_request);
6bf4f823 55
56
94439e4e 57static void
58authenticateStateFree(authenticateStateData * r)
59{
4f0ef8e8 60 AUTHUSERREQUESTUNLOCK(r->auth_user_request, "r");
94439e4e 61 cbdataFree(r);
62}
63
64/* NTLM Scheme */
65static HLPSCB authenticateNTLMHandleReply;
94439e4e 66static AUTHSSTATS authenticateNTLMStats;
94439e4e 67
94439e4e 68static statefulhelper *ntlmauthenticators = NULL;
69
70CBDATA_TYPE(authenticateStateData);
71
72static int authntlm_initialised = 0;
73
f5691f9c 74static auth_ntlm_config ntlmConfig;
94439e4e 75
76static hash_table *proxy_auth_cache = NULL;
77
78/*
79 *
80 * Private Functions
81 *
82 */
83
f5691f9c 84/* move to ntlmScheme.cc */
85void
86ntlmScheme::done()
94439e4e 87{
f5691f9c 88 /* TODO: this should be a Config call. */
bf8fe701 89 debugs(29, 2, "ntlmScheme::done: shutting down NTLM authentication.");
62e76326 90
bd507204 91 if (ntlmauthenticators)
62e76326 92 helperStatefulShutdown(ntlmauthenticators);
93
94439e4e 94 authntlm_initialised = 0;
62e76326 95
94439e4e 96 if (!shutting_down)
62e76326 97 return;
98
bd507204 99 if (ntlmauthenticators)
62e76326 100 helperStatefulFree(ntlmauthenticators);
101
94439e4e 102 ntlmauthenticators = NULL;
62e76326 103
bf8fe701 104 debugs(29, 2, "ntlmScheme::done: NTLM authentication Shutdown.");
94439e4e 105}
106
107/* free any allocated configuration details */
f5691f9c 108void
109AuthNTLMConfig::done()
94439e4e 110{
f5691f9c 111 if (authenticate)
112 wordlistDestroy(&authenticate);
94439e4e 113}
114
f5691f9c 115void
116AuthNTLMConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme)
94439e4e 117{
f5691f9c 118 wordlist *list = authenticate;
94439e4e 119 storeAppendPrintf(entry, "%s %s", name, "ntlm");
62e76326 120
94439e4e 121 while (list != NULL) {
62e76326 122 storeAppendPrintf(entry, " %s", list->key);
123 list = list->next;
94439e4e 124 }
62e76326 125
6bf4f823 126 storeAppendPrintf(entry, "\n%s ntlm children %d\n",
127 name, authenticateChildren);
128 storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "ntlm", keep_alive ? "on" : "off");
94439e4e 129
130}
131
6bf4f823 132AuthNTLMConfig::AuthNTLMConfig() : authenticateChildren(5), keep_alive(1)
133{ }
62e76326 134
f5691f9c 135void
136AuthNTLMConfig::parse(AuthConfig * scheme, int n_configured, char *param_str)
137{
94439e4e 138 if (strcasecmp(param_str, "program") == 0) {
f5691f9c 139 if (authenticate)
140 wordlistDestroy(&authenticate);
62e76326 141
f5691f9c 142 parse_wordlist(&authenticate);
62e76326 143
f5691f9c 144 requirePathnameExists("authparam ntlm program", authenticate->key);
94439e4e 145 } else if (strcasecmp(param_str, "children") == 0) {
f5691f9c 146 parse_int(&authenticateChildren);
6bf4f823 147 } else if (strcasecmp(param_str, "keep_alive") == 0) {
148 parse_onoff(&keep_alive);
94439e4e 149 } else {
bf8fe701 150 debugs(29, 0, "AuthNTLMConfig::parse: unrecognised ntlm auth scheme parameter '" << param_str << "'");
94439e4e 151 }
62e76326 152
dff99376 153 /*
154 * disable client side request pipelining. There is a race with
155 * NTLM when the client sends a second request on an NTLM
156 * connection before the authenticate challenge is sent. With
157 * this patch, the client may fail to authenticate, but squid's
158 * state will be preserved. Caveats: this should be a post-parse
159 * test, but that can wait for the modular parser to be integrated.
721b0310 160 */
f5691f9c 161 if (authenticate)
62e76326 162 Config.onoff.pipeline_prefetch = 0;
94439e4e 163}
164
f5691f9c 165const char *
166AuthNTLMConfig::type() const
94439e4e 167{
f5691f9c 168 return ntlmScheme::GetInstance().type();
94439e4e 169}
170
171/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
172 * config file */
f5691f9c 173void
174AuthNTLMConfig::init(AuthConfig * scheme)
94439e4e 175{
f5691f9c 176 if (authenticate) {
6bf4f823 177
62e76326 178 authntlm_initialised = 1;
179
180 if (ntlmauthenticators == NULL)
181 ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
182
183 if (!proxy_auth_cache)
30abd221 184 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
62e76326 185
186 assert(proxy_auth_cache);
187
f5691f9c 188 ntlmauthenticators->cmdline = authenticate;
62e76326 189
f5691f9c 190 ntlmauthenticators->n_to_start = authenticateChildren;
62e76326 191
192 ntlmauthenticators->ipc_type = IPC_STREAM;
193
62e76326 194 helperStatefulOpenServers(ntlmauthenticators);
195
62e76326 196 CBDATA_INIT_TYPE(authenticateStateData);
94439e4e 197 }
198}
199
62ee09ca 200void
201AuthNTLMConfig::registerWithCacheManager(CacheManager & manager)
202{
203 manager.registerAction("ntlmauthenticator",
204 "NTLM User Authenticator Stats",
205 authenticateNTLMStats, 0, 1);
206}
207
f5691f9c 208bool
209AuthNTLMConfig::active() const
2d70df72 210{
f5691f9c 211 return authntlm_initialised == 1;
2d70df72 212}
213
f5691f9c 214bool
215AuthNTLMConfig::configured() const
94439e4e 216{
6bf4f823 217 if ((authenticate != NULL) && (authenticateChildren != 0)) {
bf8fe701 218 debugs(29, 9, "AuthNTLMConfig::configured: returning configured");
f5691f9c 219 return true;
2d70df72 220 }
62e76326 221
bf8fe701 222 debugs(29, 9, "AuthNTLMConfig::configured: returning unconfigured");
f5691f9c 223 return false;
94439e4e 224}
225
226/* NTLM Scheme */
6bf4f823 227/* See AuthUserRequest.cc::authenticateDirection for return values */
82b045dc 228int
f5691f9c 229AuthNTLMUserRequest::module_direction()
94439e4e 230{
bd507204 231 /* null auth_user is checked for by authenticateDirection */
62e76326 232
6bf4f823 233 if (waiting || client_blob)
234 return -1; /* need helper response to continue */
235
82b045dc 236 switch (auth_state) {
62e76326 237
82b045dc 238 /* no progress at all. */
239
240 case AUTHENTICATE_STATE_NONE:
bf8fe701 241 debugs(29, 1, "AuthNTLMUserRequest::direction: called before NTLM Authenticate for request " << this << "!. Report a bug to squid-dev.");
6bf4f823 242 return -2; /* error */
62e76326 243
3c641669 244 case AUTHENTICATE_STATE_FAILED:
6bf4f823 245 return -2; /* error */
62e76326 246
82b045dc 247
6bf4f823 248 case AUTHENTICATE_STATE_IN_PROGRESS:
249 assert(server_blob);
250 return 1; /* send to client */
82b045dc 251
82b045dc 252 case AUTHENTICATE_STATE_DONE:
6bf4f823 253 return 0; /* do nothing */
254
255 case AUTHENTICATE_STATE_INITIAL:
bf8fe701 256 debugs(29, 1, "AuthNTLMUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL");
6bf4f823 257 return -2;
94439e4e 258 }
62e76326 259
94439e4e 260 return -2;
261}
262
f5691f9c 263void
76f142cd 264AuthNTLMConfig::fixHeader(AuthUserRequest *auth_user_request, HttpReply *rep, http_hdr_type type, HttpRequest * request)
94439e4e 265{
f5691f9c 266 AuthNTLMUserRequest *ntlm_request;
62e76326 267
6bf4f823 268 if (!authenticate)
269 return;
62e76326 270
6bf4f823 271 /* New request, no user details */
272 if (auth_user_request == NULL) {
bf8fe701 273 debugs(29, 9, "AuthNTLMConfig::fixHeader: Sending type:" << type << " header: 'NTLM'");
6bf4f823 274 httpHeaderPutStrf(&rep->header, type, "NTLM");
275
276 if (!keep_alive) {
62e76326 277 /* drop the connection */
a9925b40 278 rep->header.delByName("keep-alive");
62e76326 279 request->flags.proxy_keepalive = 0;
62e76326 280 }
6bf4f823 281 } else {
282 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
94439e4e 283
6bf4f823 284 switch (ntlm_request->auth_state) {
62e76326 285
6bf4f823 286 case AUTHENTICATE_STATE_FAILED:
287 /* here it makes sense to drop the connection, as auth is
288 * tied to it, even if MAYBE the client could handle it - Kinkie */
a9925b40 289 rep->header.delByName("keep-alive");
6bf4f823 290 request->flags.proxy_keepalive = 0;
291 /* fall through */
94439e4e 292
ebd65a33 293 case AUTHENTICATE_STATE_DONE:
6bf4f823 294 /* Special case: authentication finished OK but disallowed by ACL.
295 * Need to start over to give the client another chance.
296 */
297 /* fall through */
62e76326 298
6bf4f823 299 case AUTHENTICATE_STATE_NONE:
300 /* semantic change: do not drop the connection.
301 * 2.5 implementation used to keep it open - Kinkie */
bf8fe701 302 debugs(29, 9, "AuthNTLMConfig::fixHeader: Sending type:" << type << " header: 'NTLM'");
6bf4f823 303 httpHeaderPutStrf(&rep->header, type, "NTLM");
304 break;
62e76326 305
6bf4f823 306 case AUTHENTICATE_STATE_IN_PROGRESS:
307 /* we're waiting for a response from the client. Pass it the blob */
bf8fe701 308 debugs(29, 9, "AuthNTLMConfig::fixHeader: Sending type:" << type << " header: 'NTLM " << ntlm_request->server_blob << "'");
6bf4f823 309 httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->server_blob);
310 request->flags.must_keepalive = 1;
311 safe_free(ntlm_request->server_blob);
312 break;
62e76326 313
62e76326 314
6bf4f823 315 default:
bf8fe701 316 debugs(29, 0, "AuthNTLMConfig::fixHeader: state " << ntlm_request->auth_state << ".");
6bf4f823 317 fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
318 }
319 }
320}
62e76326 321
6bf4f823 322NTLMUser::~NTLMUser()
323{
bf8fe701 324 debugs(29, 5, "NTLMUser::~NTLMUser: doing nothing to clearNTLM scheme data for '" << this << "'");
94439e4e 325}
326
327static stateful_helper_callback_t
328authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
329{
e6ccf245 330 authenticateStateData *r = static_cast<authenticateStateData *>(data);
6bf4f823 331
332 int valid;
94439e4e 333 stateful_helper_callback_t result = S_HELPER_UNKNOWN;
6bf4f823 334 char *blob;
335
76f142cd 336 AuthUserRequest *auth_user_request;
6bf4f823 337 AuthUser *auth_user;
338 NTLMUser *ntlm_user;
f5691f9c 339 AuthNTLMUserRequest *ntlm_request;
62e76326 340
bf8fe701 341 debugs(29, 8, "authenticateNTLMHandleReply: helper: '" << lastserver << "' sent us '" << (reply ? reply : "<NULL>") << "'");
a6151f51 342 valid = cbdataReferenceValid(r->data);
6bf4f823 343
344 if (!valid) {
bf8fe701 345 debugs(29, 1, "authenticateNTLMHandleReply: invalid callback data. Releasing helper '" << lastserver << "'.");
62e76326 346 cbdataReferenceDone(r->data);
347 authenticateStateFree(r);
bf8fe701 348 debugs(29, 9, "authenticateNTLMHandleReply: telling stateful helper : " << S_HELPER_RELEASE);
62e76326 349 return S_HELPER_RELEASE;
9bea1d5b 350 }
62e76326 351
5d146f7d 352 if (!reply) {
bf8fe701 353 debugs(29, 1, "authenticateNTLMHandleReply: Helper '" << lastserver << "' crashed!.");
c9c40182 354 reply = (char *)"BH Internal error";
9bea1d5b 355 }
62e76326 356
6bf4f823 357 auth_user_request = r->auth_user_request;
358 assert(auth_user_request != NULL);
359 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
62e76326 360
6bf4f823 361 assert(ntlm_request->waiting);
362 ntlm_request->waiting = 0;
363 safe_free(ntlm_request->client_blob);
62e76326 364
6bf4f823 365 auth_user = ntlm_request->user();
366 assert(auth_user != NULL);
367 assert(auth_user->auth_type == AUTH_NTLM);
368 ntlm_user = dynamic_cast<ntlm_user_t *>(auth_user_request->user());
62e76326 369
6bf4f823 370 if (ntlm_request->authserver == NULL)
371 ntlm_request->authserver = static_cast<helper_stateful_server*>(lastserver);
372 else
373 assert(ntlm_request->authserver == lastserver);
62e76326 374
6bf4f823 375 /* seperate out the useful data */
376 blob = strchr(reply, ' ');
62e76326 377
c9c40182 378 if (blob)
6bf4f823 379 blob++;
62e76326 380
c9c40182 381 if (strncasecmp(reply, "TT ", 3) == 0) {
6bf4f823 382 /* we have been given a blob to send to the client */
383 safe_free(ntlm_request->server_blob);
384 ntlm_request->server_blob = xstrdup(blob);
385 ntlm_request->auth_state = AUTHENTICATE_STATE_IN_PROGRESS;
386 auth_user_request->denyMessage("Authenication in progress");
bf8fe701 387 debugs(29, 4, "authenticateNTLMHandleReply: Need to challenge the client with a server blob '" << blob << "'");
6bf4f823 388 result = S_HELPER_RESERVE;
c9c40182 389 } else if (strncasecmp(reply, "AF ", 3) == 0) {
62e76326 390 /* we're finished, release the helper */
6bf4f823 391 ntlm_user->username(blob);
392 auth_user_request->denyMessage("Login successful");
393 safe_free(ntlm_request->server_blob);
62e76326 394
6bf4f823 395 result = S_HELPER_RELEASE;
bf8fe701 396 debugs(29, 4, "authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '" << blob << "'");
71ee0c43 397 /* connection is authenticated */
398 debugs(29, 4, "AuthNTLMUserRequest::authenticate: authenticated user " << ntlm_user->username());
399 /* see if this is an existing user with a different proxy_auth
400 * string */
401 auth_user_hash_pointer *usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, ntlm_user->username()));
402 auth_user_t *local_auth_user = ntlm_request->user();
71ee0c43 403 while (usernamehash && (usernamehash->user()->auth_type != AUTH_NTLM || strcmp(usernamehash->user()->username(), ntlm_user->username()) != 0))
404 usernamehash = static_cast<AuthUserHashPointer *>(usernamehash->next);
405 if (usernamehash) {
406 /* we can't seamlessly recheck the username due to the
407 * challenge-response nature of the protocol.
408 * Just free the temporary auth_user */
409 usernamehash->user()->absorb(local_auth_user);
410 //authenticateAuthUserMerge(local_auth_user, usernamehash->user());
411 local_auth_user = usernamehash->user();
412 ntlm_request->_auth_user = local_auth_user;
413 } else {
414 /* store user in hash's */
415 local_auth_user->addToNameCache();
416 // authenticateUserNameCacheAdd(local_auth_user);
417 }
418 /* set these to now because this is either a new login from an
419 * existing user or a new user */
420 local_auth_user->expiretime = current_time.tv_sec;
421 authenticateNTLMReleaseServer(ntlm_request);
422 ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
c9c40182 423 } else if (strncasecmp(reply, "NA ", 3) == 0) {
6bf4f823 424 /* authentication failure (wrong password, etc.) */
425 auth_user_request->denyMessage(blob);
62e76326 426 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
6bf4f823 427 safe_free(ntlm_request->server_blob);
428 authenticateNTLMReleaseServer(ntlm_request);
429 result = S_HELPER_RELEASE;
bf8fe701 430 debugs(29, 4, "authenticateNTLMHandleReply: Failed validating user via NTLM. Error returned '" << blob << "'");
5d146f7d 431 } else if (strncasecmp(reply, "BH ", 3) == 0) {
62e76326 432 /* TODO kick off a refresh process. This can occur after a YR or after
6bf4f823 433 * a KK. If after a YR release the helper and resubmit the request via
434 * Authenticate NTLM start.
435 * If after a KK deny the user's request w/ 407 and mark the helper as
62e76326 436 * Needing YR. */
6bf4f823 437 auth_user_request->denyMessage(blob);
62e76326 438 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
6bf4f823 439 safe_free(ntlm_request->server_blob);
440 authenticateNTLMReleaseServer(ntlm_request);
441 result = S_HELPER_RELEASE;
bf8fe701 442 debugs(29, 1, "authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '" << reply << "'");
94439e4e 443 } else {
6bf4f823 444 /* protocol error */
445 fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
94439e4e 446 }
62e76326 447
5d146f7d 448 r->handler(r->data, NULL);
fa80a8ef 449 cbdataReferenceDone(r->data);
94439e4e 450 authenticateStateFree(r);
bf8fe701 451 debugs(29, 9, "authenticateNTLMHandleReply: telling stateful helper : " << result);
94439e4e 452 return result;
453}
454
94439e4e 455static void
456authenticateNTLMStats(StoreEntry * sentry)
457{
9522b380 458 helperStatefulStats(sentry, ntlmauthenticators, "NTLM Authenticator Statistics");
94439e4e 459}
460
94439e4e 461
462/* send the initial data to a stateful ntlm authenticator module */
f5691f9c 463void
464AuthNTLMUserRequest::module_start(RH * handler, void *data)
94439e4e 465{
94439e4e 466 authenticateStateData *r = NULL;
6bf4f823 467 static char buf[8192];
94439e4e 468 ntlm_user_t *ntlm_user;
6bf4f823 469 auth_user_t *auth_user = user();
94439e4e 470
94439e4e 471 assert(data);
6bf4f823 472 assert(handler);
473 assert(auth_user);
9970d4b1 474 assert(auth_user->auth_type == AUTH_NTLM);
62e76326 475
6bf4f823 476 ntlm_user = dynamic_cast<ntlm_user_t *>(user());
62e76326 477
bf8fe701 478 debugs(29, 8, "AuthNTLMUserRequest::module_start: auth state is '" << auth_state << "'");
62e76326 479
f5691f9c 480 if (ntlmConfig.authenticate == NULL) {
bf8fe701 481 debugs(29, 0, "AuthNTLMUserRequest::module_start: no NTLM program specified.");
62e76326 482 handler(data, NULL);
483 return;
94439e4e 484 }
62e76326 485
6bf4f823 486 r = cbdataAlloc(authenticateStateData);
487 r->handler = handler;
1d412b78 488 r->data = cbdataReference(data);
6bf4f823 489 r->auth_user_request = this;
4f0ef8e8 490 AUTHUSERREQUESTLOCK(r->auth_user_request, "r");
62e76326 491
6bf4f823 492 if (auth_state == AUTHENTICATE_STATE_INITIAL) {
493 snprintf(buf, 8192, "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
494 } else {
495 snprintf(buf, 8192, "KK %s\n", client_blob);
94439e4e 496 }
62e76326 497
6bf4f823 498 waiting = 1;
94439e4e 499
6bf4f823 500 safe_free(client_blob);
501 helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, authserver);
94439e4e 502}
503
94439e4e 504/* clear the NTLM helper of being reserved for future requests */
c78aa667 505static void
76f142cd 506authenticateNTLMReleaseServer(AuthUserRequest * auth_user_request)
94439e4e 507{
f5691f9c 508 AuthNTLMUserRequest *ntlm_request;
509 assert(auth_user_request->user()->auth_type == AUTH_NTLM);
510 ntlm_request = dynamic_cast< AuthNTLMUserRequest *>(auth_user_request);
bf8fe701 511 debugs(29, 9, "authenticateNTLMReleaseServer: releasing server '" << ntlm_request->authserver << "'");
6bf4f823 512 /* is it possible for the server to be NULL? hno seems to think so.
513 * Let's see what happens, might segfault in helperStatefulReleaseServer
514 * if it does. I leave it like this not to cover possibly problematic
515 * code-paths. Kinkie */
4f0ef8e8 516 /* DPW 2007-05-07
517 * yes, it is possible */
518 if (ntlm_request->authserver) {
519 helperStatefulReleaseServer(ntlm_request->authserver);
520 ntlm_request->authserver = NULL;
521 }
94439e4e 522}
523
524/* clear any connection related authentication details */
f5691f9c 525void
4f0ef8e8 526AuthNTLMUserRequest::onConnectionClose(ConnStateData *conn)
94439e4e 527{
4f0ef8e8 528 assert(conn != NULL);
62e76326 529
4f0ef8e8 530 debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: closing connection '" << conn << "' (this is '" << this << "')");
62e76326 531
4f0ef8e8 532 if (conn->auth_user_request == NULL) {
bf8fe701 533 debugs(29, 8, "AuthNTLMUserRequest::onConnectionClose: no auth_user_request");
6bf4f823 534 return;
535 }
62e76326 536
6bf4f823 537 if (authserver != NULL)
538 authenticateNTLMReleaseServer(this);
62e76326 539
6bf4f823 540 /* unlock the connection based lock */
4f0ef8e8 541 debugs(29, 9, "AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn << "'.");
62e76326 542
4f0ef8e8 543 AUTHUSERREQUESTUNLOCK(conn->auth_user_request, "conn");
60d096f4 544}
94439e4e 545
546/*
6bf4f823 547 * Decode a NTLM [Proxy-]Auth string, placing the results in the passed
94439e4e 548 * Auth_user structure.
549 */
f5691f9c 550AuthUserRequest *
551AuthNTLMConfig::decode(char const *proxy_auth)
94439e4e 552{
f5691f9c 553 NTLMUser *newUser = new NTLMUser(&ntlmConfig);
554 AuthNTLMUserRequest *auth_user_request = new AuthNTLMUserRequest ();
555 assert(auth_user_request->user() == NULL);
556 auth_user_request->user(newUser);
557 auth_user_request->user()->auth_type = AUTH_NTLM;
558 auth_user_request->user()->addRequest(auth_user_request);
94439e4e 559
560 /* all we have to do is identify that it's NTLM - the helper does the rest */
bf8fe701 561 debugs(29, 9, "AuthNTLMConfig::decode: NTLM authentication");
f5691f9c 562 return auth_user_request;
94439e4e 563}
564
82b045dc 565int
f5691f9c 566AuthNTLMUserRequest::authenticated() const
94439e4e 567{
c9acda3a 568 if (auth_state == AUTHENTICATE_STATE_DONE) {
bf8fe701 569 debugs(29, 9, "AuthNTLMUserRequest::authenticated: user authenticated.");
62e76326 570 return 1;
6bf4f823 571 }
62e76326 572
bf8fe701 573 debugs(29, 9, "AuthNTLMUserRequest::authenticated: user not fully authenticated.");
62e76326 574
94439e4e 575 return 0;
576}
577
82b045dc 578void
f5691f9c 579AuthNTLMUserRequest::authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type)
94439e4e 580{
6bf4f823 581 const char *proxy_auth, *blob;
62e76326 582
f5691f9c 583 /* TODO: rename this!! */
6bf4f823 584 auth_user_t *local_auth_user;
94439e4e 585 ntlm_user_t *ntlm_user;
94439e4e 586
6bf4f823 587 local_auth_user = user();
588 assert(local_auth_user);
589 assert(local_auth_user->auth_type == AUTH_NTLM);
590 ntlm_user = dynamic_cast<ntlm_user_t *>(local_auth_user);
591 assert (this);
592
3a73fe76 593 /* Check that we are in the client side, where we can generate
594 * auth challenges */
62e76326 595
a2ac85d9 596 if (conn.getRaw() == NULL) {
6bf4f823 597 auth_state = AUTHENTICATE_STATE_FAILED;
bf8fe701 598 debugs(29, 1, "AuthNTLMUserRequest::authenticate: attempt to perform authentication without a connection!");
6bf4f823 599 return;
600 }
601
602 if (waiting) {
bf8fe701 603 debugs(29, 1, "AuthNTLMUserRequest::authenticate: waiting for helper reply!");
62e76326 604 return;
3a73fe76 605 }
62e76326 606
6bf4f823 607 if (server_blob) {
bf8fe701 608 debugs(29, 2, "AuthNTLMUserRequest::authenticate: need to challenge client '" << server_blob << "'!");
6bf4f823 609 return;
610 }
611
612 /* get header */
a9925b40 613 proxy_auth = request->header.getStr(type);
6bf4f823 614
c9c40182 615 /* locate second word */
616 blob = proxy_auth;
617
618 while (xisspace(*blob) && *blob)
619 blob++;
620
621 while (!xisspace(*blob) && *blob)
622 blob++;
6bf4f823 623
c9c40182 624 while (xisspace(*blob) && *blob)
6bf4f823 625 blob++;
626
627 switch (auth_state) {
62e76326 628
94439e4e 629 case AUTHENTICATE_STATE_NONE:
6bf4f823 630 /* we've recieved a ntlm request. pass to a helper */
bf8fe701 631 debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm none. Received blob: '" << proxy_auth << "'");
6bf4f823 632 auth_state = AUTHENTICATE_STATE_INITIAL;
633 safe_free(client_blob);
634 client_blob=xstrdup(blob);
62e76326 635 conn->auth_type = AUTH_NTLM;
4f0ef8e8 636 assert(conn->auth_user_request == NULL);
f5691f9c 637 conn->auth_user_request = this;
4f0ef8e8 638 AUTHUSERREQUESTLOCK(conn->auth_user_request, "conn");
62e76326 639 return;
f5691f9c 640
62e76326 641 break;
642
6bf4f823 643 case AUTHENTICATE_STATE_INITIAL:
bf8fe701 644 debugs(29, 1, "AuthNTLMUserRequest::authenticate: need to ask helper");
f5691f9c 645
62e76326 646 return;
f5691f9c 647
62e76326 648 break;
649
62e76326 650
6bf4f823 651 case AUTHENTICATE_STATE_IN_PROGRESS:
652 /* we should have received a blob from the client. Hand it off to
653 * some helper */
654 safe_free(client_blob);
62e76326 655
6bf4f823 656 client_blob = xstrdup (blob);
62e76326 657
658 return;
6bf4f823 659
62e76326 660 break;
661
94439e4e 662 case AUTHENTICATE_STATE_DONE:
71ee0c43 663 fatal("AuthNTLMUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
6bf4f823 664
71ee0c43 665 break;
62e76326 666
3c641669 667 case AUTHENTICATE_STATE_FAILED:
62e76326 668 /* we've failed somewhere in authentication */
bf8fe701 669 debugs(29, 9, "AuthNTLMUserRequest::authenticate: auth state ntlm failed. " << proxy_auth);
6bf4f823 670
62e76326 671 return;
6bf4f823 672
673 break;
94439e4e 674 }
62e76326 675
94439e4e 676 return;
677}
82b045dc 678
6bf4f823 679AuthNTLMUserRequest::AuthNTLMUserRequest() :
680 conn(NULL), auth_state(AUTHENTICATE_STATE_NONE),
681 _theUser(NULL)
682{
683 waiting=0;
684 client_blob=0;
685 server_blob=0;
686 authserver=NULL;
687}
f5691f9c 688
689AuthNTLMUserRequest::~AuthNTLMUserRequest()
690{
6bf4f823 691 safe_free(server_blob);
692 safe_free(client_blob);
f5691f9c 693
6bf4f823 694 if (authserver != NULL) {
bf8fe701 695 debugs(29, 9, "AuthNTLMUserRequest::~AuthNTLMUserRequest: releasing server '" << authserver << "'");
f5691f9c 696 helperStatefulReleaseServer(authserver);
697 authserver = NULL;
698 }
699}
700
f5691f9c 701void
702NTLMUser::deleteSelf() const
703{
704 delete this;
705}
706
f5691f9c 707NTLMUser::NTLMUser (AuthConfig *config) : AuthUser (config)
708{
709 proxy_auth_list.head = proxy_auth_list.tail = NULL;
710}
711
712AuthConfig *
713ntlmScheme::createConfig()
714{
715 return &ntlmConfig;
716}
717
6bf4f823 718const char *
719AuthNTLMUserRequest::connLastHeader()
720{
721 return NULL;
722}
723