]> git.ipfire.org Git - thirdparty/squid.git/blame - src/auth/ntlm/auth_ntlm.cc
Forward port of latest 2.6 changes
[thirdparty/squid.git] / src / auth / ntlm / auth_ntlm.cc
CommitLineData
94439e4e 1
2/*
a9925b40 3 * $Id: auth_ntlm.cc,v 1.57 2006/05/06 22:13:19 wessels 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"
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"
c78aa667 51
6bf4f823 52static void
53authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request);
54
55
94439e4e 56static void
57authenticateStateFree(authenticateStateData * r)
58{
59 cbdataFree(r);
60}
61
62/* NTLM Scheme */
63static HLPSCB authenticateNTLMHandleReply;
94439e4e 64static AUTHSSTATS authenticateNTLMStats;
94439e4e 65
94439e4e 66static statefulhelper *ntlmauthenticators = NULL;
67
68CBDATA_TYPE(authenticateStateData);
69
70static int authntlm_initialised = 0;
71
6bf4f823 72//static MemAllocatorProxy *ntlm_user_hash_pool = NULL;
e6ccf245 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. */
6bf4f823 89 debug(29, 2) ("ntlmScheme::done: shutting down NTLM authentication.\n");
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
6bf4f823 104 debug(29, 2) ("ntlmScheme::done: NTLM authentication Shutdown.\n");
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 {
6bf4f823 150 debug(28, 0) ("AuthNTLMConfig::parse: unrecognised ntlm auth scheme parameter '%s'\n", 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{
6bf4f823 176 static unsigned char ntlm_was_already_initialised = 0;
62e76326 177
f5691f9c 178 if (authenticate) {
6bf4f823 179#if PLACEHOLDER
62e76326 180
62e76326 181 if (!ntlm_user_hash_pool)
182
b001e822 183 ntlm_user_hash_pool = new MemAllocatorProxy("NTLM Header Hash Data", sizeof(struct ProxyAuthCachePointer));
62e76326 184
6bf4f823 185#endif
186
62e76326 187 authntlm_initialised = 1;
188
189 if (ntlmauthenticators == NULL)
190 ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
191
192 if (!proxy_auth_cache)
193 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
194
195 assert(proxy_auth_cache);
196
f5691f9c 197 ntlmauthenticators->cmdline = authenticate;
62e76326 198
f5691f9c 199 ntlmauthenticators->n_to_start = authenticateChildren;
62e76326 200
201 ntlmauthenticators->ipc_type = IPC_STREAM;
202
62e76326 203 helperStatefulOpenServers(ntlmauthenticators);
204
6bf4f823 205 if (!ntlm_was_already_initialised) {
62e76326 206 cachemgrRegister("ntlmauthenticator",
207 "NTLM User Authenticator Stats",
208 authenticateNTLMStats, 0, 1);
6bf4f823 209 ntlm_was_already_initialised++;
62e76326 210 }
211
212 CBDATA_INIT_TYPE(authenticateStateData);
94439e4e 213 }
214}
215
f5691f9c 216bool
217AuthNTLMConfig::active() const
2d70df72 218{
f5691f9c 219 return authntlm_initialised == 1;
2d70df72 220}
221
f5691f9c 222bool
223AuthNTLMConfig::configured() const
94439e4e 224{
6bf4f823 225 if ((authenticate != NULL) && (authenticateChildren != 0)) {
226 debug(29, 9) ("AuthNTLMConfig::configured: returning configured\n");
f5691f9c 227 return true;
2d70df72 228 }
62e76326 229
6bf4f823 230 debug(29, 9) ("AuthNTLMConfig::configured: returning unconfigured\n");
f5691f9c 231 return false;
94439e4e 232}
233
234/* NTLM Scheme */
6bf4f823 235/* See AuthUserRequest.cc::authenticateDirection for return values */
82b045dc 236int
f5691f9c 237AuthNTLMUserRequest::module_direction()
94439e4e 238{
bd507204 239 /* null auth_user is checked for by authenticateDirection */
62e76326 240
6bf4f823 241 if (waiting || client_blob)
242 return -1; /* need helper response to continue */
243
82b045dc 244 switch (auth_state) {
62e76326 245
82b045dc 246 /* no progress at all. */
247
248 case AUTHENTICATE_STATE_NONE:
6bf4f823 249 debug(29, 1) ("AuthNTLMUserRequest::direction: called before NTLM Authenticate for request %p!. Report a bug to squid-dev.\n",this);
250 return -2; /* error */
62e76326 251
3c641669 252 case AUTHENTICATE_STATE_FAILED:
6bf4f823 253 return -2; /* error */
62e76326 254
82b045dc 255
6bf4f823 256 case AUTHENTICATE_STATE_IN_PROGRESS:
257 assert(server_blob);
258 return 1; /* send to client */
82b045dc 259
6bf4f823 260 case AUTHENTICATE_STATE_FINISHED:
261 return 0; /* do nothing */
82b045dc 262
263 case AUTHENTICATE_STATE_DONE:
6bf4f823 264 return 0; /* do nothing */
265
266 case AUTHENTICATE_STATE_INITIAL:
267 debug(29, 1) ("AuthNTLMUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL\n");
268 return -2;
94439e4e 269 }
62e76326 270
94439e4e 271 return -2;
272}
273
f5691f9c 274void
275AuthNTLMConfig::fixHeader(auth_user_request_t *auth_user_request, HttpReply *rep, http_hdr_type type, HttpRequest * request)
94439e4e 276{
f5691f9c 277 AuthNTLMUserRequest *ntlm_request;
62e76326 278
6bf4f823 279 if (!authenticate)
280 return;
62e76326 281
6bf4f823 282 /* New request, no user details */
283 if (auth_user_request == NULL) {
284 debug(29, 9) ("AuthNTLMConfig::fixHeader: Sending type:%d header: 'NTLM'\n", type);
285 httpHeaderPutStrf(&rep->header, type, "NTLM");
286
287 if (!keep_alive) {
62e76326 288 /* drop the connection */
a9925b40 289 rep->header.delByName("keep-alive");
62e76326 290 request->flags.proxy_keepalive = 0;
62e76326 291 }
6bf4f823 292 } else {
293 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
94439e4e 294
6bf4f823 295 switch (ntlm_request->auth_state) {
62e76326 296
6bf4f823 297 case AUTHENTICATE_STATE_FAILED:
298 /* here it makes sense to drop the connection, as auth is
299 * tied to it, even if MAYBE the client could handle it - Kinkie */
a9925b40 300 rep->header.delByName("keep-alive");
6bf4f823 301 request->flags.proxy_keepalive = 0;
302 /* fall through */
94439e4e 303
6bf4f823 304 case AUTHENTICATE_STATE_FINISHED:
305 /* Special case: authentication finished OK but disallowed by ACL.
306 * Need to start over to give the client another chance.
307 */
308 /* fall through */
62e76326 309
6bf4f823 310 case AUTHENTICATE_STATE_NONE:
311 /* semantic change: do not drop the connection.
312 * 2.5 implementation used to keep it open - Kinkie */
313 debug(29, 9) ("AuthNTLMConfig::fixHeader: Sending type:%d header: 'NTLM'\n", type);
314 httpHeaderPutStrf(&rep->header, type, "NTLM");
315 break;
62e76326 316
6bf4f823 317 case AUTHENTICATE_STATE_IN_PROGRESS:
318 /* we're waiting for a response from the client. Pass it the blob */
319 debug(29, 9) ("AuthNTLMConfig::fixHeader: Sending type:%d header: 'NTLM %s'\n", type, ntlm_request->server_blob);
320 httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->server_blob);
321 request->flags.must_keepalive = 1;
322 safe_free(ntlm_request->server_blob);
323 break;
62e76326 324
62e76326 325
6bf4f823 326 default:
327 debug(29, 0) ("AuthNTLMConfig::fixHeader: state %d.\n", ntlm_request->auth_state);
328 fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
329 }
330 }
331}
62e76326 332
6bf4f823 333NTLMUser::~NTLMUser()
334{
335 debug(29, 5) ("NTLMUser::~NTLMUser: doing nothing to clearNTLM scheme data for '%p'\n",this);
94439e4e 336}
337
338static stateful_helper_callback_t
339authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
340{
e6ccf245 341 authenticateStateData *r = static_cast<authenticateStateData *>(data);
6bf4f823 342
343 int valid;
94439e4e 344 stateful_helper_callback_t result = S_HELPER_UNKNOWN;
6bf4f823 345 char *blob;
346
94439e4e 347 auth_user_request_t *auth_user_request;
6bf4f823 348 AuthUser *auth_user;
349 NTLMUser *ntlm_user;
f5691f9c 350 AuthNTLMUserRequest *ntlm_request;
62e76326 351
6bf4f823 352 debug(29, 8) ("authenticateNTLMHandleReply: helper: '%p' sent us '%s'\n", lastserver, reply ? reply : "<NULL>");
a6151f51 353 valid = cbdataReferenceValid(r->data);
6bf4f823 354
355 if (!valid) {
356 debug(29, 1) ("authenticateNTLMHandleReply: invalid callback data. Releasing helper '%p'.\n", lastserver);
62e76326 357 cbdataReferenceDone(r->data);
358 authenticateStateFree(r);
6bf4f823 359 debug(29, 9) ("authenticateNTLMHandleReply: telling stateful helper : %d\n", S_HELPER_RELEASE);
62e76326 360 return S_HELPER_RELEASE;
9bea1d5b 361 }
62e76326 362
5d146f7d 363 if (!reply) {
7da10d2b 364 debug(29, 1) ("authenticateNTLMHandleReply: Helper '%p' crashed!.\n", lastserver);
c9c40182 365 reply = (char *)"BH Internal error";
9bea1d5b 366 }
62e76326 367
6bf4f823 368 auth_user_request = r->auth_user_request;
369 assert(auth_user_request != NULL);
370 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
62e76326 371
6bf4f823 372 assert(ntlm_request->waiting);
373 ntlm_request->waiting = 0;
374 safe_free(ntlm_request->client_blob);
62e76326 375
6bf4f823 376 auth_user = ntlm_request->user();
377 assert(auth_user != NULL);
378 assert(auth_user->auth_type == AUTH_NTLM);
379 ntlm_user = dynamic_cast<ntlm_user_t *>(auth_user_request->user());
62e76326 380
6bf4f823 381 if (ntlm_request->authserver == NULL)
382 ntlm_request->authserver = static_cast<helper_stateful_server*>(lastserver);
383 else
384 assert(ntlm_request->authserver == lastserver);
62e76326 385
6bf4f823 386 /* seperate out the useful data */
387 blob = strchr(reply, ' ');
62e76326 388
c9c40182 389 if (blob)
6bf4f823 390 blob++;
62e76326 391
c9c40182 392 if (strncasecmp(reply, "TT ", 3) == 0) {
6bf4f823 393 /* we have been given a blob to send to the client */
394 safe_free(ntlm_request->server_blob);
395 ntlm_request->server_blob = xstrdup(blob);
396 ntlm_request->auth_state = AUTHENTICATE_STATE_IN_PROGRESS;
397 auth_user_request->denyMessage("Authenication in progress");
398 debug(29, 4) ("authenticateNTLMHandleReply: Need to challenge the client with a server blob '%s'\n", blob);
399 result = S_HELPER_RESERVE;
c9c40182 400 } else if (strncasecmp(reply, "AF ", 3) == 0) {
62e76326 401 /* we're finished, release the helper */
6bf4f823 402 ntlm_user->username(blob);
403 auth_user_request->denyMessage("Login successful");
404 safe_free(ntlm_request->server_blob);
405 authenticateNTLMReleaseServer(ntlm_request);
406 ntlm_request->auth_state = AUTHENTICATE_STATE_FINISHED;
62e76326 407
6bf4f823 408 result = S_HELPER_RELEASE;
409 debug(29, 4) ("authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '%s'\n", blob);
c9c40182 410 } else if (strncasecmp(reply, "NA ", 3) == 0) {
6bf4f823 411 /* authentication failure (wrong password, etc.) */
412 auth_user_request->denyMessage(blob);
62e76326 413 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
6bf4f823 414 safe_free(ntlm_request->server_blob);
415 authenticateNTLMReleaseServer(ntlm_request);
416 result = S_HELPER_RELEASE;
417 debug(29, 4) ("authenticateNTLMHandleReply: Failed validating user via NTLM. Error returned '%s'\n", blob);
5d146f7d 418 } else if (strncasecmp(reply, "BH ", 3) == 0) {
62e76326 419 /* TODO kick off a refresh process. This can occur after a YR or after
6bf4f823 420 * a KK. If after a YR release the helper and resubmit the request via
421 * Authenticate NTLM start.
422 * If after a KK deny the user's request w/ 407 and mark the helper as
62e76326 423 * Needing YR. */
6bf4f823 424 auth_user_request->denyMessage(blob);
62e76326 425 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
6bf4f823 426 safe_free(ntlm_request->server_blob);
427 authenticateNTLMReleaseServer(ntlm_request);
428 result = S_HELPER_RELEASE;
429 debug(29, 1) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
94439e4e 430 } else {
6bf4f823 431 /* protocol error */
432 fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
94439e4e 433 }
62e76326 434
5d146f7d 435 r->handler(r->data, NULL);
fa80a8ef 436 cbdataReferenceDone(r->data);
94439e4e 437 authenticateStateFree(r);
6bf4f823 438 debug(29, 9) ("authenticateNTLMHandleReply: telling stateful helper : %d\n", result);
94439e4e 439 return result;
440}
441
94439e4e 442static void
443authenticateNTLMStats(StoreEntry * sentry)
444{
445 storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
446 helperStatefulStats(sentry, ntlmauthenticators);
447}
448
94439e4e 449
450/* send the initial data to a stateful ntlm authenticator module */
f5691f9c 451void
452AuthNTLMUserRequest::module_start(RH * handler, void *data)
94439e4e 453{
94439e4e 454 authenticateStateData *r = NULL;
6bf4f823 455 static char buf[8192];
94439e4e 456 ntlm_user_t *ntlm_user;
6bf4f823 457 auth_user_t *auth_user = user();
94439e4e 458
94439e4e 459 assert(data);
6bf4f823 460 assert(handler);
461 assert(auth_user);
9970d4b1 462 assert(auth_user->auth_type == AUTH_NTLM);
62e76326 463
6bf4f823 464 ntlm_user = dynamic_cast<ntlm_user_t *>(user());
62e76326 465
6bf4f823 466 debug(29, 8) ("AuthNTLMUserRequest::module_start: auth state is '%d'\n", auth_state);
62e76326 467
f5691f9c 468 if (ntlmConfig.authenticate == NULL) {
6bf4f823 469 debug(29, 0) ("AuthNTLMUserRequest::module_start: no NTLM program specified.");
62e76326 470 handler(data, NULL);
471 return;
94439e4e 472 }
62e76326 473
6bf4f823 474 r = cbdataAlloc(authenticateStateData);
475 r->handler = handler;
1d412b78 476 r->data = cbdataReference(data);
6bf4f823 477 r->auth_user_request = this;
62e76326 478
6bf4f823 479 lock()
62e76326 480
6bf4f823 481 ;
482 if (auth_state == AUTHENTICATE_STATE_INITIAL) {
483 snprintf(buf, 8192, "YR %s\n", client_blob); //CHECKME: can ever client_blob be 0 here?
484 } else {
485 snprintf(buf, 8192, "KK %s\n", client_blob);
94439e4e 486 }
62e76326 487
6bf4f823 488 waiting = 1;
94439e4e 489
6bf4f823 490 safe_free(client_blob);
491 helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, authserver);
94439e4e 492}
493
94439e4e 494/* clear the NTLM helper of being reserved for future requests */
c78aa667 495static void
60d096f4 496authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request)
94439e4e 497{
f5691f9c 498 AuthNTLMUserRequest *ntlm_request;
499 assert(auth_user_request->user()->auth_type == AUTH_NTLM);
500 ntlm_request = dynamic_cast< AuthNTLMUserRequest *>(auth_user_request);
33272404 501 debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", ntlm_request->authserver);
6bf4f823 502 /* is it possible for the server to be NULL? hno seems to think so.
503 * Let's see what happens, might segfault in helperStatefulReleaseServer
504 * if it does. I leave it like this not to cover possibly problematic
505 * code-paths. Kinkie */
60d096f4 506 helperStatefulReleaseServer(ntlm_request->authserver);
507 ntlm_request->authserver = NULL;
94439e4e 508}
509
510/* clear any connection related authentication details */
f5691f9c 511void
6bf4f823 512AuthNTLMUserRequest::onConnectionClose(ConnStateData *connection)
94439e4e 513{
6bf4f823 514 assert(connection != NULL);
62e76326 515
6bf4f823 516 debug(29,8)("AuthNTLMUserRequest::onConnectionClose: closing connection '%p' (this is '%p')\n",connection,this);
62e76326 517
6bf4f823 518 if (connection->auth_user_request == NULL) {
519 debug(29,8)("AuthNTLMUserRequest::onConnectionClose: no auth_user_request\n");
520 return;
521 }
62e76326 522
6bf4f823 523 if (authserver != NULL)
524 authenticateNTLMReleaseServer(this);
62e76326 525
6bf4f823 526 /* unlock the connection based lock */
527 debug(29, 9) ("AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '%p'.\n",connection);
62e76326 528
6bf4f823 529 /* This still breaks the abstraction, but is at least read only now.
530 * If needed, this could be ignored, as the conn deletion will also unlock
531 * the auth user request.
532 */
533 unlock();
94439e4e 534
6bf4f823 535 connection->auth_user_request = NULL;
60d096f4 536}
94439e4e 537
538/*
6bf4f823 539 * Decode a NTLM [Proxy-]Auth string, placing the results in the passed
94439e4e 540 * Auth_user structure.
541 */
f5691f9c 542AuthUserRequest *
543AuthNTLMConfig::decode(char const *proxy_auth)
94439e4e 544{
f5691f9c 545 NTLMUser *newUser = new NTLMUser(&ntlmConfig);
546 AuthNTLMUserRequest *auth_user_request = new AuthNTLMUserRequest ();
547 assert(auth_user_request->user() == NULL);
548 auth_user_request->user(newUser);
549 auth_user_request->user()->auth_type = AUTH_NTLM;
550 auth_user_request->user()->addRequest(auth_user_request);
94439e4e 551
552 /* all we have to do is identify that it's NTLM - the helper does the rest */
6bf4f823 553 debug(29, 9) ("AuthNTLMConfig::decode: NTLM authentication\n");
f5691f9c 554 return auth_user_request;
94439e4e 555}
556
82b045dc 557int
f5691f9c 558AuthNTLMUserRequest::authenticated() const
94439e4e 559{
6bf4f823 560 if (auth_state == AUTHENTICATE_STATE_FINISHED) {
561 debug(29, 9) ("AuthNTLMUserRequest::authenticated: user authenticated.\n");
62e76326 562 return 1;
6bf4f823 563 }
62e76326 564
6bf4f823 565 debug(29, 9) ("AuthNTLMUserRequest::authenticated: user not fully authenticated.\n");
62e76326 566
94439e4e 567 return 0;
568}
569
82b045dc 570void
f5691f9c 571AuthNTLMUserRequest::authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type)
94439e4e 572{
6bf4f823 573 const char *proxy_auth, *blob;
62e76326 574
6bf4f823 575 //ProxyAuthCachePointer *proxy_auth_hash = NULL;
e6ccf245 576 auth_user_hash_pointer *usernamehash;
6bf4f823 577
f5691f9c 578 /* TODO: rename this!! */
6bf4f823 579 auth_user_t *local_auth_user;
94439e4e 580 ntlm_user_t *ntlm_user;
94439e4e 581
6bf4f823 582 local_auth_user = user();
583 assert(local_auth_user);
584 assert(local_auth_user->auth_type == AUTH_NTLM);
585 ntlm_user = dynamic_cast<ntlm_user_t *>(local_auth_user);
586 assert (this);
587
3a73fe76 588 /* Check that we are in the client side, where we can generate
589 * auth challenges */
62e76326 590
a2ac85d9 591 if (conn.getRaw() == NULL) {
6bf4f823 592 auth_state = AUTHENTICATE_STATE_FAILED;
593 debug(29, 1) ("AuthNTLMUserRequest::authenticate: attempt to perform authentication without a connection!\n");
594 return;
595 }
596
597 if (waiting) {
598 debug(29, 1) ("AuthNTLMUserRequest::authenticate: waiting for helper reply!\n");
62e76326 599 return;
3a73fe76 600 }
62e76326 601
6bf4f823 602 if (server_blob) {
603 debug(29,2)("AuthNTLMUserRequest::authenticate: need to challenge client '%s'!\n", server_blob);
604 return;
605 }
606
607 /* get header */
a9925b40 608 proxy_auth = request->header.getStr(type);
6bf4f823 609
c9c40182 610 /* locate second word */
611 blob = proxy_auth;
612
613 while (xisspace(*blob) && *blob)
614 blob++;
615
616 while (!xisspace(*blob) && *blob)
617 blob++;
6bf4f823 618
c9c40182 619 while (xisspace(*blob) && *blob)
6bf4f823 620 blob++;
621
622 switch (auth_state) {
62e76326 623
94439e4e 624 case AUTHENTICATE_STATE_NONE:
6bf4f823 625 /* we've recieved a ntlm request. pass to a helper */
626 debug(29, 9) ("AuthNTLMUserRequest::authenticate: auth state ntlm none. Received blob: '%s'\n", proxy_auth);
627 auth_state = AUTHENTICATE_STATE_INITIAL;
628 safe_free(client_blob);
629 client_blob=xstrdup(blob);
62e76326 630 conn->auth_type = AUTH_NTLM;
f5691f9c 631 conn->auth_user_request = this;
6bf4f823 632 conn = conn;
f5691f9c 633
6bf4f823 634 lock()
f5691f9c 635
6bf4f823 636 ;
62e76326 637 return;
f5691f9c 638
62e76326 639 break;
640
6bf4f823 641 case AUTHENTICATE_STATE_INITIAL:
642 debug(29,1)("AuthNTLMUserRequest::authenticate: need to ask helper\n");
f5691f9c 643
62e76326 644 return;
f5691f9c 645
62e76326 646 break;
647
62e76326 648
6bf4f823 649 case AUTHENTICATE_STATE_IN_PROGRESS:
650 /* we should have received a blob from the client. Hand it off to
651 * some helper */
652 safe_free(client_blob);
62e76326 653
6bf4f823 654 client_blob = xstrdup (blob);
62e76326 655
656 return;
6bf4f823 657
62e76326 658 break;
659
6bf4f823 660 case AUTHENTICATE_STATE_FINISHED:
661 /* connection is authenticated */
662 debug(29, 4) ("AuthNTLMUserRequest::authenticate: authenticated user %s\n", ntlm_user->username());
663
62e76326 664 /* see if this is an existing user with a different proxy_auth
665 * string */
6bf4f823 666 usernamehash = static_cast<AuthUserHashPointer *>(hash_lookup(proxy_auth_username_cache, ntlm_user->username()));
667
668 while (usernamehash && (usernamehash->user()->auth_type != AUTH_NTLM || strcmp(usernamehash->user()->username(), ntlm_user->username()) != 0))
669 usernamehash = static_cast<AuthUserHashPointer *>(usernamehash->next);
670
671 if (usernamehash) {
672 /* we can't seamlessly recheck the username due to the
673 * challenge-response nature of the protocol.
674 * Just free the temporary auth_user */
675 usernamehash->user()->absorb(local_auth_user);
676 //authenticateAuthUserMerge(local_auth_user, usernamehash->user());
677 local_auth_user = usernamehash->user();
678 _auth_user = local_auth_user;
62e76326 679 } else {
680 /* store user in hash's */
6bf4f823 681 local_auth_user->addToNameCache();
682 // authenticateUserNameCacheAdd(local_auth_user);
62e76326 683 }
684
685 /* set these to now because this is either a new login from an
686 * existing user or a new user */
6bf4f823 687 local_auth_user->expiretime = current_time.tv_sec;
688
689 authenticateNTLMReleaseServer(this);
690
691 auth_state = AUTHENTICATE_STATE_DONE;
692
62e76326 693 return;
6bf4f823 694
62e76326 695 break;
696
94439e4e 697 case AUTHENTICATE_STATE_DONE:
6bf4f823 698 fatal("AuthNTLMUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
699
62e76326 700 break;
701
3c641669 702 case AUTHENTICATE_STATE_FAILED:
62e76326 703 /* we've failed somewhere in authentication */
6bf4f823 704 debug(29, 9) ("AuthNTLMUserRequest::authenticate: auth state ntlm failed. %s\n", proxy_auth);
705
62e76326 706 return;
6bf4f823 707
708 break;
94439e4e 709 }
62e76326 710
94439e4e 711 return;
712}
82b045dc 713
6bf4f823 714AuthNTLMUserRequest::AuthNTLMUserRequest() :
715 conn(NULL), auth_state(AUTHENTICATE_STATE_NONE),
716 _theUser(NULL)
717{
718 waiting=0;
719 client_blob=0;
720 server_blob=0;
721 authserver=NULL;
722}
f5691f9c 723
724AuthNTLMUserRequest::~AuthNTLMUserRequest()
725{
6bf4f823 726 safe_free(server_blob);
727 safe_free(client_blob);
f5691f9c 728
6bf4f823 729 if (authserver != NULL) {
730 debug(29, 9) ("AuthNTLMUserRequest::~AuthNTLMUserRequest: releasing server '%p'\n", authserver);
f5691f9c 731 helperStatefulReleaseServer(authserver);
732 authserver = NULL;
733 }
734}
735
f5691f9c 736void
737NTLMUser::deleteSelf() const
738{
739 delete this;
740}
741
f5691f9c 742NTLMUser::NTLMUser (AuthConfig *config) : AuthUser (config)
743{
744 proxy_auth_list.head = proxy_auth_list.tail = NULL;
745}
746
747AuthConfig *
748ntlmScheme::createConfig()
749{
750 return &ntlmConfig;
751}
752
6bf4f823 753const char *
754AuthNTLMUserRequest::connLastHeader()
755{
756 return NULL;
757}
758