]> git.ipfire.org Git - thirdparty/squid.git/blob - src/auth/ntlm/auth_ntlm.cc
Add a CacheManager class which provides the cachemanager menu registration facility...
[thirdparty/squid.git] / src / auth / ntlm / auth_ntlm.cc
1
2 /*
3 * $Id: auth_ntlm.cc,v 1.58 2006/05/29 00:15:07 robertc Exp $
4 *
5 * DEBUG: section 29 NTLM Authenticator
6 * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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"
43 #include "authenticate.h"
44 #include "CacheManager.h"
45 #include "Store.h"
46 #include "client_side.h"
47 #include "HttpReply.h"
48 #include "HttpRequest.h"
49 /* TODO remove this include */
50 #include "ntlmScheme.h"
51 #include "wordlist.h"
52
53 static void
54 authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request);
55
56
57 static void
58 authenticateStateFree(authenticateStateData * r)
59 {
60 cbdataFree(r);
61 }
62
63 /* NTLM Scheme */
64 static HLPSCB authenticateNTLMHandleReply;
65 static AUTHSSTATS authenticateNTLMStats;
66
67 static statefulhelper *ntlmauthenticators = NULL;
68
69 CBDATA_TYPE(authenticateStateData);
70
71 static int authntlm_initialised = 0;
72
73 //static MemAllocatorProxy *ntlm_user_hash_pool = NULL;
74
75 static auth_ntlm_config ntlmConfig;
76
77 static hash_table *proxy_auth_cache = NULL;
78
79 /*
80 *
81 * Private Functions
82 *
83 */
84
85 /* move to ntlmScheme.cc */
86 void
87 ntlmScheme::done()
88 {
89 /* TODO: this should be a Config call. */
90 debug(29, 2) ("ntlmScheme::done: shutting down NTLM authentication.\n");
91
92 if (ntlmauthenticators)
93 helperStatefulShutdown(ntlmauthenticators);
94
95 authntlm_initialised = 0;
96
97 if (!shutting_down)
98 return;
99
100 if (ntlmauthenticators)
101 helperStatefulFree(ntlmauthenticators);
102
103 ntlmauthenticators = NULL;
104
105 debug(29, 2) ("ntlmScheme::done: NTLM authentication Shutdown.\n");
106 }
107
108 /* free any allocated configuration details */
109 void
110 AuthNTLMConfig::done()
111 {
112 if (authenticate)
113 wordlistDestroy(&authenticate);
114 }
115
116 void
117 AuthNTLMConfig::dump(StoreEntry * entry, const char *name, AuthConfig * scheme)
118 {
119 wordlist *list = authenticate;
120 storeAppendPrintf(entry, "%s %s", name, "ntlm");
121
122 while (list != NULL) {
123 storeAppendPrintf(entry, " %s", list->key);
124 list = list->next;
125 }
126
127 storeAppendPrintf(entry, "\n%s ntlm children %d\n",
128 name, authenticateChildren);
129 storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "ntlm", keep_alive ? "on" : "off");
130
131 }
132
133 AuthNTLMConfig::AuthNTLMConfig() : authenticateChildren(5), keep_alive(1)
134 { }
135
136 void
137 AuthNTLMConfig::parse(AuthConfig * scheme, int n_configured, char *param_str)
138 {
139 if (strcasecmp(param_str, "program") == 0) {
140 if (authenticate)
141 wordlistDestroy(&authenticate);
142
143 parse_wordlist(&authenticate);
144
145 requirePathnameExists("authparam ntlm program", authenticate->key);
146 } else if (strcasecmp(param_str, "children") == 0) {
147 parse_int(&authenticateChildren);
148 } else if (strcasecmp(param_str, "keep_alive") == 0) {
149 parse_onoff(&keep_alive);
150 } else {
151 debug(28, 0) ("AuthNTLMConfig::parse: unrecognised ntlm auth scheme parameter '%s'\n", param_str);
152 }
153
154 /*
155 * disable client side request pipelining. There is a race with
156 * NTLM when the client sends a second request on an NTLM
157 * connection before the authenticate challenge is sent. With
158 * this patch, the client may fail to authenticate, but squid's
159 * state will be preserved. Caveats: this should be a post-parse
160 * test, but that can wait for the modular parser to be integrated.
161 */
162 if (authenticate)
163 Config.onoff.pipeline_prefetch = 0;
164 }
165
166 const char *
167 AuthNTLMConfig::type() const
168 {
169 return ntlmScheme::GetInstance().type();
170 }
171
172 /* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
173 * config file */
174 void
175 AuthNTLMConfig::init(AuthConfig * scheme)
176 {
177 if (authenticate) {
178 #if PLACEHOLDER
179
180 if (!ntlm_user_hash_pool)
181
182 ntlm_user_hash_pool = new MemAllocatorProxy("NTLM Header Hash Data", sizeof(struct ProxyAuthCachePointer));
183
184 #endif
185
186 authntlm_initialised = 1;
187
188 if (ntlmauthenticators == NULL)
189 ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
190
191 if (!proxy_auth_cache)
192 proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
193
194 assert(proxy_auth_cache);
195
196 ntlmauthenticators->cmdline = authenticate;
197
198 ntlmauthenticators->n_to_start = authenticateChildren;
199
200 ntlmauthenticators->ipc_type = IPC_STREAM;
201
202 helperStatefulOpenServers(ntlmauthenticators);
203
204 CBDATA_INIT_TYPE(authenticateStateData);
205 }
206 }
207
208 void
209 AuthNTLMConfig::registerWithCacheManager(CacheManager & manager)
210 {
211 manager.registerAction("ntlmauthenticator",
212 "NTLM User Authenticator Stats",
213 authenticateNTLMStats, 0, 1);
214 }
215
216 bool
217 AuthNTLMConfig::active() const
218 {
219 return authntlm_initialised == 1;
220 }
221
222 bool
223 AuthNTLMConfig::configured() const
224 {
225 if ((authenticate != NULL) && (authenticateChildren != 0)) {
226 debug(29, 9) ("AuthNTLMConfig::configured: returning configured\n");
227 return true;
228 }
229
230 debug(29, 9) ("AuthNTLMConfig::configured: returning unconfigured\n");
231 return false;
232 }
233
234 /* NTLM Scheme */
235 /* See AuthUserRequest.cc::authenticateDirection for return values */
236 int
237 AuthNTLMUserRequest::module_direction()
238 {
239 /* null auth_user is checked for by authenticateDirection */
240
241 if (waiting || client_blob)
242 return -1; /* need helper response to continue */
243
244 switch (auth_state) {
245
246 /* no progress at all. */
247
248 case AUTHENTICATE_STATE_NONE:
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 */
251
252 case AUTHENTICATE_STATE_FAILED:
253 return -2; /* error */
254
255
256 case AUTHENTICATE_STATE_IN_PROGRESS:
257 assert(server_blob);
258 return 1; /* send to client */
259
260 case AUTHENTICATE_STATE_FINISHED:
261 return 0; /* do nothing */
262
263 case AUTHENTICATE_STATE_DONE:
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;
269 }
270
271 return -2;
272 }
273
274 void
275 AuthNTLMConfig::fixHeader(auth_user_request_t *auth_user_request, HttpReply *rep, http_hdr_type type, HttpRequest * request)
276 {
277 AuthNTLMUserRequest *ntlm_request;
278
279 if (!authenticate)
280 return;
281
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) {
288 /* drop the connection */
289 rep->header.delByName("keep-alive");
290 request->flags.proxy_keepalive = 0;
291 }
292 } else {
293 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
294
295 switch (ntlm_request->auth_state) {
296
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 */
300 rep->header.delByName("keep-alive");
301 request->flags.proxy_keepalive = 0;
302 /* fall through */
303
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 */
309
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;
316
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;
324
325
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 }
332
333 NTLMUser::~NTLMUser()
334 {
335 debug(29, 5) ("NTLMUser::~NTLMUser: doing nothing to clearNTLM scheme data for '%p'\n",this);
336 }
337
338 static stateful_helper_callback_t
339 authenticateNTLMHandleReply(void *data, void *lastserver, char *reply)
340 {
341 authenticateStateData *r = static_cast<authenticateStateData *>(data);
342
343 int valid;
344 stateful_helper_callback_t result = S_HELPER_UNKNOWN;
345 char *blob;
346
347 auth_user_request_t *auth_user_request;
348 AuthUser *auth_user;
349 NTLMUser *ntlm_user;
350 AuthNTLMUserRequest *ntlm_request;
351
352 debug(29, 8) ("authenticateNTLMHandleReply: helper: '%p' sent us '%s'\n", lastserver, reply ? reply : "<NULL>");
353 valid = cbdataReferenceValid(r->data);
354
355 if (!valid) {
356 debug(29, 1) ("authenticateNTLMHandleReply: invalid callback data. Releasing helper '%p'.\n", lastserver);
357 cbdataReferenceDone(r->data);
358 authenticateStateFree(r);
359 debug(29, 9) ("authenticateNTLMHandleReply: telling stateful helper : %d\n", S_HELPER_RELEASE);
360 return S_HELPER_RELEASE;
361 }
362
363 if (!reply) {
364 debug(29, 1) ("authenticateNTLMHandleReply: Helper '%p' crashed!.\n", lastserver);
365 reply = (char *)"BH Internal error";
366 }
367
368 auth_user_request = r->auth_user_request;
369 assert(auth_user_request != NULL);
370 ntlm_request = dynamic_cast<AuthNTLMUserRequest *>(auth_user_request);
371
372 assert(ntlm_request->waiting);
373 ntlm_request->waiting = 0;
374 safe_free(ntlm_request->client_blob);
375
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());
380
381 if (ntlm_request->authserver == NULL)
382 ntlm_request->authserver = static_cast<helper_stateful_server*>(lastserver);
383 else
384 assert(ntlm_request->authserver == lastserver);
385
386 /* seperate out the useful data */
387 blob = strchr(reply, ' ');
388
389 if (blob)
390 blob++;
391
392 if (strncasecmp(reply, "TT ", 3) == 0) {
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;
400 } else if (strncasecmp(reply, "AF ", 3) == 0) {
401 /* we're finished, release the helper */
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;
407
408 result = S_HELPER_RELEASE;
409 debug(29, 4) ("authenticateNTLMHandleReply: Successfully validated user via NTLM. Username '%s'\n", blob);
410 } else if (strncasecmp(reply, "NA ", 3) == 0) {
411 /* authentication failure (wrong password, etc.) */
412 auth_user_request->denyMessage(blob);
413 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
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);
418 } else if (strncasecmp(reply, "BH ", 3) == 0) {
419 /* TODO kick off a refresh process. This can occur after a YR or after
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
423 * Needing YR. */
424 auth_user_request->denyMessage(blob);
425 ntlm_request->auth_state = AUTHENTICATE_STATE_FAILED;
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);
430 } else {
431 /* protocol error */
432 fatalf("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
433 }
434
435 r->handler(r->data, NULL);
436 cbdataReferenceDone(r->data);
437 authenticateStateFree(r);
438 debug(29, 9) ("authenticateNTLMHandleReply: telling stateful helper : %d\n", result);
439 return result;
440 }
441
442 static void
443 authenticateNTLMStats(StoreEntry * sentry)
444 {
445 storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
446 helperStatefulStats(sentry, ntlmauthenticators);
447 }
448
449
450 /* send the initial data to a stateful ntlm authenticator module */
451 void
452 AuthNTLMUserRequest::module_start(RH * handler, void *data)
453 {
454 authenticateStateData *r = NULL;
455 static char buf[8192];
456 ntlm_user_t *ntlm_user;
457 auth_user_t *auth_user = user();
458
459 assert(data);
460 assert(handler);
461 assert(auth_user);
462 assert(auth_user->auth_type == AUTH_NTLM);
463
464 ntlm_user = dynamic_cast<ntlm_user_t *>(user());
465
466 debug(29, 8) ("AuthNTLMUserRequest::module_start: auth state is '%d'\n", auth_state);
467
468 if (ntlmConfig.authenticate == NULL) {
469 debug(29, 0) ("AuthNTLMUserRequest::module_start: no NTLM program specified.");
470 handler(data, NULL);
471 return;
472 }
473
474 r = cbdataAlloc(authenticateStateData);
475 r->handler = handler;
476 r->data = cbdataReference(data);
477 r->auth_user_request = this;
478
479 lock()
480
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);
486 }
487
488 waiting = 1;
489
490 safe_free(client_blob);
491 helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, authserver);
492 }
493
494 /* clear the NTLM helper of being reserved for future requests */
495 static void
496 authenticateNTLMReleaseServer(auth_user_request_t * auth_user_request)
497 {
498 AuthNTLMUserRequest *ntlm_request;
499 assert(auth_user_request->user()->auth_type == AUTH_NTLM);
500 ntlm_request = dynamic_cast< AuthNTLMUserRequest *>(auth_user_request);
501 debug(29, 9) ("authenticateNTLMReleaseServer: releasing server '%p'\n", ntlm_request->authserver);
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 */
506 helperStatefulReleaseServer(ntlm_request->authserver);
507 ntlm_request->authserver = NULL;
508 }
509
510 /* clear any connection related authentication details */
511 void
512 AuthNTLMUserRequest::onConnectionClose(ConnStateData *connection)
513 {
514 assert(connection != NULL);
515
516 debug(29,8)("AuthNTLMUserRequest::onConnectionClose: closing connection '%p' (this is '%p')\n",connection,this);
517
518 if (connection->auth_user_request == NULL) {
519 debug(29,8)("AuthNTLMUserRequest::onConnectionClose: no auth_user_request\n");
520 return;
521 }
522
523 if (authserver != NULL)
524 authenticateNTLMReleaseServer(this);
525
526 /* unlock the connection based lock */
527 debug(29, 9) ("AuthNTLMUserRequest::onConnectionClose: Unlocking auth_user from the connection '%p'.\n",connection);
528
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();
534
535 connection->auth_user_request = NULL;
536 }
537
538 /*
539 * Decode a NTLM [Proxy-]Auth string, placing the results in the passed
540 * Auth_user structure.
541 */
542 AuthUserRequest *
543 AuthNTLMConfig::decode(char const *proxy_auth)
544 {
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);
551
552 /* all we have to do is identify that it's NTLM - the helper does the rest */
553 debug(29, 9) ("AuthNTLMConfig::decode: NTLM authentication\n");
554 return auth_user_request;
555 }
556
557 int
558 AuthNTLMUserRequest::authenticated() const
559 {
560 if (auth_state == AUTHENTICATE_STATE_FINISHED) {
561 debug(29, 9) ("AuthNTLMUserRequest::authenticated: user authenticated.\n");
562 return 1;
563 }
564
565 debug(29, 9) ("AuthNTLMUserRequest::authenticated: user not fully authenticated.\n");
566
567 return 0;
568 }
569
570 void
571 AuthNTLMUserRequest::authenticate(HttpRequest * request, ConnStateData::Pointer conn, http_hdr_type type)
572 {
573 const char *proxy_auth, *blob;
574
575 //ProxyAuthCachePointer *proxy_auth_hash = NULL;
576 auth_user_hash_pointer *usernamehash;
577
578 /* TODO: rename this!! */
579 auth_user_t *local_auth_user;
580 ntlm_user_t *ntlm_user;
581
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
588 /* Check that we are in the client side, where we can generate
589 * auth challenges */
590
591 if (conn.getRaw() == NULL) {
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");
599 return;
600 }
601
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 */
608 proxy_auth = request->header.getStr(type);
609
610 /* locate second word */
611 blob = proxy_auth;
612
613 while (xisspace(*blob) && *blob)
614 blob++;
615
616 while (!xisspace(*blob) && *blob)
617 blob++;
618
619 while (xisspace(*blob) && *blob)
620 blob++;
621
622 switch (auth_state) {
623
624 case AUTHENTICATE_STATE_NONE:
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);
630 conn->auth_type = AUTH_NTLM;
631 conn->auth_user_request = this;
632 conn = conn;
633
634 lock()
635
636 ;
637 return;
638
639 break;
640
641 case AUTHENTICATE_STATE_INITIAL:
642 debug(29,1)("AuthNTLMUserRequest::authenticate: need to ask helper\n");
643
644 return;
645
646 break;
647
648
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);
653
654 client_blob = xstrdup (blob);
655
656 return;
657
658 break;
659
660 case AUTHENTICATE_STATE_FINISHED:
661 /* connection is authenticated */
662 debug(29, 4) ("AuthNTLMUserRequest::authenticate: authenticated user %s\n", ntlm_user->username());
663
664 /* see if this is an existing user with a different proxy_auth
665 * string */
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;
679 } else {
680 /* store user in hash's */
681 local_auth_user->addToNameCache();
682 // authenticateUserNameCacheAdd(local_auth_user);
683 }
684
685 /* set these to now because this is either a new login from an
686 * existing user or a new user */
687 local_auth_user->expiretime = current_time.tv_sec;
688
689 authenticateNTLMReleaseServer(this);
690
691 auth_state = AUTHENTICATE_STATE_DONE;
692
693 return;
694
695 break;
696
697 case AUTHENTICATE_STATE_DONE:
698 fatal("AuthNTLMUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
699
700 break;
701
702 case AUTHENTICATE_STATE_FAILED:
703 /* we've failed somewhere in authentication */
704 debug(29, 9) ("AuthNTLMUserRequest::authenticate: auth state ntlm failed. %s\n", proxy_auth);
705
706 return;
707
708 break;
709 }
710
711 return;
712 }
713
714 AuthNTLMUserRequest::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 }
723
724 AuthNTLMUserRequest::~AuthNTLMUserRequest()
725 {
726 safe_free(server_blob);
727 safe_free(client_blob);
728
729 if (authserver != NULL) {
730 debug(29, 9) ("AuthNTLMUserRequest::~AuthNTLMUserRequest: releasing server '%p'\n", authserver);
731 helperStatefulReleaseServer(authserver);
732 authserver = NULL;
733 }
734 }
735
736 void
737 NTLMUser::deleteSelf() const
738 {
739 delete this;
740 }
741
742 NTLMUser::NTLMUser (AuthConfig *config) : AuthUser (config)
743 {
744 proxy_auth_list.head = proxy_auth_list.tail = NULL;
745 }
746
747 AuthConfig *
748 ntlmScheme::createConfig()
749 {
750 return &ntlmConfig;
751 }
752
753 const char *
754 AuthNTLMUserRequest::connLastHeader()
755 {
756 return NULL;
757 }
758