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