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