4 * DEBUG: section 29 Negotiate Authenticator
5 * AUTHOR: Robert Collins, Henrik Nordstrom, Francesco Chemolli
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
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.
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.
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.
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.
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 */
41 #include "auth_negotiate.h"
42 #include "authenticate.h"
43 #include "CacheManager.h"
45 #include "client_side.h"
46 #include "HttpReply.h"
47 #include "HttpRequest.h"
48 #include "SquidTime.h"
49 /** \todo remove this include */
50 #include "negotiateScheme.h"
54 \defgroup AuthNegotiateInternal Negotiate Authenticator Internals
55 \ingroup AuthNegotiateAPI
59 * Maximum length (buffer size) for token strings.
61 // AYJ: must match re-definition in helpers/negotiate_auth/squid_kerb_auth/squid_kerb_auth.c
62 #define MAX_AUTHTOKEN_LEN 32768
65 authenticateNegotiateReleaseServer(AuthUserRequest
* auth_user_request
);
68 /// \ingroup AuthNegotiateInternal
70 authenticateStateFree(authenticateStateData
* r
)
72 AUTHUSERREQUESTUNLOCK(r
->auth_user_request
, "r");
76 /* Negotiate Scheme */
77 static HLPSCB authenticateNegotiateHandleReply
;
78 static AUTHSSTATS authenticateNegotiateStats
;
80 /// \ingroup AuthNegotiateInternal
81 static statefulhelper
*negotiateauthenticators
= NULL
;
83 CBDATA_TYPE(authenticateStateData
);
85 /// \ingroup AuthNegotiateInternal
86 static int authnegotiate_initialised
= 0;
88 /// \ingroup AuthNegotiateInternal
89 static auth_negotiate_config negotiateConfig
;
91 /// \ingroup AuthNegotiateInternal
92 static hash_table
*proxy_auth_cache
= NULL
;
101 \ingroup AuthNegotiateInternal
102 \todo move to negotiateScheme.cc
105 negotiateScheme::done()
107 /* TODO: this should be a Config call. */
108 debugs(29, 2, "negotiateScheme::done: shutting down Negotiate authentication.");
110 if (negotiateauthenticators
)
111 helperStatefulShutdown(negotiateauthenticators
);
113 authnegotiate_initialised
= 0;
118 if (negotiateauthenticators
)
119 helperStatefulFree(negotiateauthenticators
);
121 negotiateauthenticators
= NULL
;
123 debugs(29, 2, "negotiateScheme::done: Negotiate authentication Shutdown.");
127 AuthNegotiateConfig::done()
130 wordlistDestroy(&authenticate
);
134 AuthNegotiateConfig::dump(StoreEntry
* entry
, const char *name
, AuthConfig
* scheme
)
136 wordlist
*list
= authenticate
;
137 storeAppendPrintf(entry
, "%s %s", name
, "negotiate");
139 while (list
!= NULL
) {
140 storeAppendPrintf(entry
, " %s", list
->key
);
144 storeAppendPrintf(entry
, "\n%s negotiate children %d\n",
145 name
, authenticateChildren
);
146 storeAppendPrintf(entry
, "%s %s keep_alive %s\n", name
, "negotiate", keep_alive
? "on" : "off");
150 AuthNegotiateConfig::AuthNegotiateConfig() : authenticateChildren(5), keep_alive(1)
154 AuthNegotiateConfig::parse(AuthConfig
* scheme
, int n_configured
, char *param_str
)
156 if (strcasecmp(param_str
, "program") == 0) {
158 wordlistDestroy(&authenticate
);
160 parse_wordlist(&authenticate
);
162 requirePathnameExists("authparam negotiate program", authenticate
->key
);
163 } else if (strcasecmp(param_str
, "children") == 0) {
164 parse_int(&authenticateChildren
);
165 } else if (strcasecmp(param_str
, "keep_alive") == 0) {
166 parse_onoff(&keep_alive
);
168 debugs(29, 0, "AuthNegotiateConfig::parse: unrecognised negotiate auth scheme parameter '" << param_str
<< "'");
172 * disable client side request pipelining. There is a race with
173 * Negotiate when the client sends a second request on an Negotiate
174 * connection before the authenticate challenge is sent. With
175 * this patch, the client may fail to authenticate, but squid's
176 * state will be preserved. Caveats: this should be a post-parse
177 * test, but that can wait for the modular parser to be integrated.
180 Config
.onoff
.pipeline_prefetch
= 0;
184 AuthNegotiateConfig::type() const
186 return negotiateScheme::GetInstance().type();
190 * Initialize helpers and the like for this auth scheme.
191 * Called AFTER parsing the config file
194 AuthNegotiateConfig::init(AuthConfig
* scheme
)
198 authnegotiate_initialised
= 1;
200 if (negotiateauthenticators
== NULL
)
201 negotiateauthenticators
= helperStatefulCreate("negotiateauthenticator");
203 if (!proxy_auth_cache
)
204 proxy_auth_cache
= hash_create((HASHCMP
*) strcmp
, 7921, hash_string
);
206 assert(proxy_auth_cache
);
208 negotiateauthenticators
->cmdline
= authenticate
;
210 negotiateauthenticators
->n_to_start
= authenticateChildren
;
212 negotiateauthenticators
->ipc_type
= IPC_STREAM
;
214 helperStatefulOpenServers(negotiateauthenticators
);
216 CBDATA_INIT_TYPE(authenticateStateData
);
221 AuthNegotiateConfig::registerWithCacheManager(void)
223 CacheManager::GetInstance()->
224 registerAction("negotiateauthenticator",
225 "Negotiate User Authenticator Stats",
226 authenticateNegotiateStats
, 0, 1);
230 AuthNegotiateConfig::active() const
232 return authnegotiate_initialised
== 1;
236 AuthNegotiateConfig::configured() const
238 if ((authenticate
!= NULL
) && (authenticateChildren
!= 0)) {
239 debugs(29, 9, "AuthNegotiateConfig::configured: returning configured");
243 debugs(29, 9, "AuthNegotiateConfig::configured: returning unconfigured");
247 /* Negotiate Scheme */
248 /* See AuthUserRequest.cc::authenticateDirection for return values */
250 AuthNegotiateUserRequest::module_direction()
252 /* null auth_user is checked for by authenticateDirection */
254 if (waiting
|| client_blob
)
255 return -1; /* need helper response to continue */
257 switch (auth_state
) {
259 /* no progress at all. */
261 case AUTHENTICATE_STATE_NONE
:
262 debugs(29, 1, "AuthNegotiateUserRequest::direction: called before Negotiate Authenticate for request " << this << "!. Report a bug to squid-dev.");
263 return -2; /* error */
265 case AUTHENTICATE_STATE_FAILED
:
266 return -2; /* error */
269 case AUTHENTICATE_STATE_IN_PROGRESS
:
271 return 1; /* send to client */
273 case AUTHENTICATE_STATE_DONE
:
274 return 0; /* do nothing */
276 case AUTHENTICATE_STATE_INITIAL
:
277 debugs(29, 1, "AuthNegotiateUserRequest::direction: Unexpected AUTHENTICATE_STATE_INITIAL");
284 /* add the [proxy]authorisation header */
286 AuthNegotiateUserRequest::addHeader(HttpReply
* rep
, int accel
)
293 /* don't add to authentication error pages */
295 if ((!accel
&& rep
->sline
.status
== HTTP_PROXY_AUTHENTICATION_REQUIRED
)
296 || (accel
&& rep
->sline
.status
== HTTP_UNAUTHORIZED
))
299 type
= accel
? HDR_AUTHENTICATION_INFO
: HDR_PROXY_AUTHENTICATION_INFO
;
301 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate %s", server_blob
);
303 safe_free(server_blob
);
307 AuthNegotiateConfig::fixHeader(AuthUserRequest
*auth_user_request
, HttpReply
*rep
, http_hdr_type type
, HttpRequest
* request
)
309 AuthNegotiateUserRequest
*negotiate_request
;
314 /* Need keep-alive */
315 if (!request
->flags
.proxy_keepalive
&& request
->flags
.must_keepalive
)
318 /* New request, no user details */
319 if (auth_user_request
== NULL
) {
320 debugs(29, 9, "AuthNegotiateConfig::fixHeader: Sending type:" << type
<< " header: 'Negotiate'");
321 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate");
324 /* drop the connection */
325 rep
->header
.delByName("keep-alive");
326 request
->flags
.proxy_keepalive
= 0;
329 negotiate_request
= dynamic_cast<AuthNegotiateUserRequest
*>(auth_user_request
);
331 assert(negotiate_request
!= NULL
);
333 switch (negotiate_request
->auth_state
) {
335 case AUTHENTICATE_STATE_FAILED
:
336 /* here it makes sense to drop the connection, as auth is
337 * tied to it, even if MAYBE the client could handle it - Kinkie */
338 rep
->header
.delByName("keep-alive");
339 request
->flags
.proxy_keepalive
= 0;
342 case AUTHENTICATE_STATE_DONE
:
343 /* Special case: authentication finished OK but disallowed by ACL.
344 * Need to start over to give the client another chance.
347 if (negotiate_request
->server_blob
) {
348 debugs(29, 9, "authenticateNegotiateFixErrorHeader: Sending type:" << type
<< " header: 'Negotiate " << negotiate_request
->server_blob
<< "'");
349 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate %s", negotiate_request
->server_blob
);
350 safe_free(negotiate_request
->server_blob
);
352 debugs(29, 9, "authenticateNegotiateFixErrorHeader: Connection authenticated");
353 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate");
358 case AUTHENTICATE_STATE_NONE
:
359 /* semantic change: do not drop the connection.
360 * 2.5 implementation used to keep it open - Kinkie */
361 debugs(29, 9, "AuthNegotiateConfig::fixHeader: Sending type:" << type
<< " header: 'Negotiate'");
362 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate");
365 case AUTHENTICATE_STATE_IN_PROGRESS
:
366 /* we're waiting for a response from the client. Pass it the blob */
367 debugs(29, 9, "AuthNegotiateConfig::fixHeader: Sending type:" << type
<< " header: 'Negotiate " << negotiate_request
->server_blob
<< "'");
368 httpHeaderPutStrf(&rep
->header
, type
, "Negotiate %s", negotiate_request
->server_blob
);
369 safe_free(negotiate_request
->server_blob
);
374 debugs(29, 0, "AuthNegotiateConfig::fixHeader: state " << negotiate_request
->auth_state
<< ".");
375 fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n");
380 NegotiateUser::~NegotiateUser()
382 debugs(29, 5, "NegotiateUser::~NegotiateUser: doing nothing to clearNegotiate scheme data for '" << this << "'");
385 static stateful_helper_callback_t
386 authenticateNegotiateHandleReply(void *data
, void *lastserver
, char *reply
)
388 authenticateStateData
*r
= static_cast<authenticateStateData
*>(data
);
391 stateful_helper_callback_t result
= S_HELPER_UNKNOWN
;
392 char *blob
, *arg
= NULL
;
394 AuthUserRequest
*auth_user_request
;
396 NegotiateUser
*negotiate_user
;
397 AuthNegotiateUserRequest
*negotiate_request
;
399 debugs(29, 8, "authenticateNegotiateHandleReply: helper: '" << lastserver
<< "' sent us '" << (reply
? reply
: "<NULL>") << "'");
400 valid
= cbdataReferenceValid(r
->data
);
403 debugs(29, 1, "authenticateNegotiateHandleReply: invalid callback data. Releasing helper '" << lastserver
<< "'.");
404 cbdataReferenceDone(r
->data
);
405 authenticateStateFree(r
);
406 debugs(29, 9, "authenticateNegotiateHandleReply: telling stateful helper : " << S_HELPER_RELEASE
);
407 return S_HELPER_RELEASE
;
411 debugs(29, 1, "authenticateNegotiateHandleReply: Helper '" << lastserver
<< "' crashed!.");
412 reply
= (char *)"BH Internal error";
415 auth_user_request
= r
->auth_user_request
;
416 assert(auth_user_request
!= NULL
);
417 negotiate_request
= dynamic_cast<AuthNegotiateUserRequest
*>(auth_user_request
);
419 assert(negotiate_request
!= NULL
);
420 assert(negotiate_request
->waiting
);
421 negotiate_request
->waiting
= 0;
422 safe_free(negotiate_request
->client_blob
);
424 auth_user
= negotiate_request
->user();
425 assert(auth_user
!= NULL
);
426 assert(auth_user
->auth_type
== AUTH_NEGOTIATE
);
427 negotiate_user
= dynamic_cast<negotiate_user_t
*>(auth_user_request
->user());
429 assert(negotiate_user
!= NULL
);
431 if (negotiate_request
->authserver
== NULL
)
432 negotiate_request
->authserver
= static_cast<helper_stateful_server
*>(lastserver
);
434 assert(negotiate_request
->authserver
== lastserver
);
436 /* seperate out the useful data */
437 blob
= strchr(reply
, ' ');
441 arg
= strchr(blob
+ 1, ' ');
446 if (strncasecmp(reply
, "TT ", 3) == 0) {
447 /* we have been given a blob to send to the client */
450 safe_free(negotiate_request
->server_blob
);
451 negotiate_request
->request
->flags
.must_keepalive
= 1;
452 if (negotiate_request
->request
->flags
.proxy_keepalive
) {
453 negotiate_request
->server_blob
= xstrdup(blob
);
454 negotiate_request
->auth_state
= AUTHENTICATE_STATE_IN_PROGRESS
;
455 auth_user_request
->denyMessage("Authentication in progress");
456 debugs(29, 4, "authenticateNegotiateHandleReply: Need to challenge the client with a server blob '" << blob
<< "'");
457 result
= S_HELPER_RESERVE
;
459 negotiate_request
->auth_state
= AUTHENTICATE_STATE_FAILED
;
460 auth_user_request
->denyMessage("NTLM authentication requires a persistent connection");
461 result
= S_HELPER_RELEASE
;
463 } else if (strncasecmp(reply
, "AF ", 3) == 0 && arg
!= NULL
) {
464 /* we're finished, release the helper */
469 negotiate_user
->username(arg
);
471 auth_user_request
->denyMessage("Login successful");
473 safe_free(negotiate_request
->server_blob
);
475 negotiate_request
->server_blob
= xstrdup(blob
);
477 authenticateNegotiateReleaseServer(negotiate_request
);
479 negotiate_request
->auth_state
= AUTHENTICATE_STATE_DONE
;
481 result
= S_HELPER_RELEASE
;
483 debugs(29, 4, "authenticateNegotiateHandleReply: Successfully validated user via Negotiate. Username '" << blob
<< "'");
485 /* connection is authenticated */
486 debugs(29, 4, "AuthNegotiateUserRequest::authenticate: authenticated user " << negotiate_user
->username());
487 /* see if this is an existing user with a different proxy_auth
489 AuthUserHashPointer
*usernamehash
= static_cast<AuthUserHashPointer
*>(hash_lookup(proxy_auth_username_cache
, negotiate_user
->username()));
490 AuthUser
*local_auth_user
= negotiate_request
->user();
491 while (usernamehash
&& (usernamehash
->user()->auth_type
!= AUTH_NEGOTIATE
|| strcmp(usernamehash
->user()->username(), negotiate_user
->username()) != 0))
492 usernamehash
= static_cast<AuthUserHashPointer
*>(usernamehash
->next
);
494 /* we can't seamlessly recheck the username due to the
495 * challenge-response nature of the protocol.
496 * Just free the temporary auth_user */
497 usernamehash
->user()->absorb(local_auth_user
);
498 //authenticateAuthUserMerge(local_auth_user, usernamehash->user());
499 local_auth_user
= usernamehash
->user();
500 negotiate_request
->_auth_user
= local_auth_user
;
502 /* store user in hash's */
503 local_auth_user
->addToNameCache();
504 // authenticateUserNameCacheAdd(local_auth_user);
506 /* set these to now because this is either a new login from an
507 * existing user or a new user */
508 local_auth_user
->expiretime
= current_time
.tv_sec
;
509 authenticateNegotiateReleaseServer(negotiate_request
);
510 negotiate_request
->auth_state
= AUTHENTICATE_STATE_DONE
;
512 } else if (strncasecmp(reply
, "NA ", 3) == 0 && arg
!= NULL
) {
513 /* authentication failure (wrong password, etc.) */
518 auth_user_request
->denyMessage(arg
);
520 negotiate_request
->auth_state
= AUTHENTICATE_STATE_FAILED
;
522 safe_free(negotiate_request
->server_blob
);
524 negotiate_request
->server_blob
= xstrdup(blob
);
526 authenticateNegotiateReleaseServer(negotiate_request
);
528 result
= S_HELPER_RELEASE
;
530 debugs(29, 4, "authenticateNegotiateHandleReply: Failed validating user via Negotiate. Error returned '" << blob
<< "'");
531 } else if (strncasecmp(reply
, "BH ", 3) == 0) {
532 /* TODO kick off a refresh process. This can occur after a YR or after
533 * a KK. If after a YR release the helper and resubmit the request via
534 * Authenticate Negotiate start.
535 * If after a KK deny the user's request w/ 407 and mark the helper as
537 auth_user_request
->denyMessage(blob
);
538 negotiate_request
->auth_state
= AUTHENTICATE_STATE_FAILED
;
539 safe_free(negotiate_request
->server_blob
);
540 authenticateNegotiateReleaseServer(negotiate_request
);
541 result
= S_HELPER_RELEASE
;
542 debugs(29, 1, "authenticateNegotiateHandleReply: Error validating user via Negotiate. Error returned '" << reply
<< "'");
545 fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply
);
548 if (negotiate_request
->request
) {
549 HTTPMSGUNLOCK(negotiate_request
->request
);
550 negotiate_request
->request
= NULL
;
552 r
->handler(r
->data
, NULL
);
553 cbdataReferenceDone(r
->data
);
554 authenticateStateFree(r
);
555 debugs(29, 9, "authenticateNegotiateHandleReply: telling stateful helper : " << result
);
560 authenticateNegotiateStats(StoreEntry
* sentry
)
562 helperStatefulStats(sentry
, negotiateauthenticators
, "Negotiate Authenticator Statistics");
566 /** send the initial data to a stateful negotiate authenticator module */
568 AuthNegotiateUserRequest::module_start(RH
* handler
, void *data
)
570 authenticateStateData
*r
= NULL
;
571 static char buf
[MAX_AUTHTOKEN_LEN
];
572 negotiate_user_t
*negotiate_user
;
573 AuthUser
*auth_user
= user();
578 assert(auth_user
->auth_type
== AUTH_NEGOTIATE
);
580 negotiate_user
= dynamic_cast<negotiate_user_t
*>(user());
582 debugs(29, 8, "AuthNegotiateUserRequest::module_start: auth state is '" << auth_state
<< "'");
584 if (negotiateConfig
.authenticate
== NULL
) {
585 debugs(29, 0, "AuthNegotiateUserRequest::module_start: no Negotiate program specified.");
590 r
= cbdataAlloc(authenticateStateData
);
591 r
->handler
= handler
;
592 r
->data
= cbdataReference(data
);
593 r
->auth_user_request
= this;
594 AUTHUSERREQUESTLOCK(r
->auth_user_request
, "r");
596 if (auth_state
== AUTHENTICATE_STATE_INITIAL
) {
597 snprintf(buf
, MAX_AUTHTOKEN_LEN
, "YR %s\n", client_blob
); //CHECKME: can ever client_blob be 0 here?
599 snprintf(buf
, MAX_AUTHTOKEN_LEN
, "KK %s\n", client_blob
);
604 safe_free(client_blob
);
605 helperStatefulSubmit(negotiateauthenticators
, buf
, authenticateNegotiateHandleReply
, r
, authserver
);
608 /* clear the Negotiate helper of being reserved for future requests */
610 authenticateNegotiateReleaseServer(AuthUserRequest
* auth_user_request
)
612 AuthNegotiateUserRequest
*negotiate_request
;
613 assert(auth_user_request
->user()->auth_type
== AUTH_NEGOTIATE
);
614 negotiate_request
= dynamic_cast< AuthNegotiateUserRequest
*>(auth_user_request
);
615 assert(negotiate_request
!= NULL
);
616 debugs(29, 9, "authenticateNegotiateReleaseServer: releasing server '" << negotiate_request
->authserver
<< "'");
617 /* is it possible for the server to be NULL? hno seems to think so.
618 * Let's see what happens, might segfault in helperStatefulReleaseServer
619 * if it does. I leave it like this not to cover possibly problematic
620 * code-paths. Kinkie */
622 * yes, it is possible */
623 if (negotiate_request
->authserver
) {
624 helperStatefulReleaseServer(negotiate_request
->authserver
);
625 negotiate_request
->authserver
= NULL
;
629 /* clear any connection related authentication details */
631 AuthNegotiateUserRequest::onConnectionClose(ConnStateData
*conn
)
633 assert(conn
!= NULL
);
635 debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: closing connection '" << conn
<< "' (this is '" << this << "')");
637 if (conn
->auth_user_request
== NULL
) {
638 debugs(29, 8, "AuthNegotiateUserRequest::onConnectionClose: no auth_user_request");
642 if (authserver
!= NULL
)
643 authenticateNegotiateReleaseServer(this);
645 /* unlock the connection based lock */
646 debugs(29, 9, "AuthNegotiateUserRequest::onConnectionClose: Unlocking auth_user from the connection '" << conn
<< "'.");
648 AUTHUSERREQUESTUNLOCK(conn
->auth_user_request
, "conn");
652 * Decode a Negotiate [Proxy-]Auth string, placing the results in the passed
653 * Auth_user structure.
656 AuthNegotiateConfig::decode(char const *proxy_auth
)
658 NegotiateUser
*newUser
= new NegotiateUser(&negotiateConfig
);
659 AuthNegotiateUserRequest
*auth_user_request
= new AuthNegotiateUserRequest ();
660 assert(auth_user_request
->user() == NULL
);
661 auth_user_request
->user(newUser
);
662 auth_user_request
->user()->auth_type
= AUTH_NEGOTIATE
;
663 auth_user_request
->user()->addRequest(auth_user_request
);
665 /* all we have to do is identify that it's Negotiate - the helper does the rest */
666 debugs(29, 9, "AuthNegotiateConfig::decode: Negotiate authentication");
667 return auth_user_request
;
671 AuthNegotiateUserRequest::authenticated() const
673 if (auth_state
== AUTHENTICATE_STATE_DONE
) {
674 debugs(29, 9, "AuthNegotiateUserRequest::authenticated: user authenticated.");
678 debugs(29, 9, "AuthNegotiateUserRequest::authenticated: user not fully authenticated.");
684 AuthNegotiateUserRequest::authenticate(HttpRequest
* request
, ConnStateData
* conn
, http_hdr_type type
)
686 const char *proxy_auth
, *blob
;
688 /** \todo rename this!! */
689 AuthUser
*local_auth_user
;
690 negotiate_user_t
*negotiate_user
;
692 local_auth_user
= user();
693 assert(local_auth_user
);
694 assert(local_auth_user
->auth_type
== AUTH_NEGOTIATE
);
695 negotiate_user
= dynamic_cast<negotiate_user_t
*>(local_auth_user
);
698 /** Check that we are in the client side, where we can generate
702 auth_state
= AUTHENTICATE_STATE_FAILED
;
703 debugs(29, 1, "AuthNegotiateUserRequest::authenticate: attempt to perform authentication without a connection!");
708 debugs(29, 1, "AuthNegotiateUserRequest::authenticate: waiting for helper reply!");
713 debugs(29, 2, "AuthNegotiateUserRequest::authenticate: need to challenge client '" << server_blob
<< "'!");
718 proxy_auth
= request
->header
.getStr(type
);
720 /* locate second word */
724 while (xisspace(*blob
) && *blob
)
727 while (!xisspace(*blob
) && *blob
)
730 while (xisspace(*blob
) && *blob
)
734 switch (auth_state
) {
736 case AUTHENTICATE_STATE_NONE
:
737 /* we've received a negotiate request. pass to a helper */
738 debugs(29, 9, "AuthNegotiateUserRequest::authenticate: auth state negotiate none. Received blob: '" << proxy_auth
<< "'");
739 auth_state
= AUTHENTICATE_STATE_INITIAL
;
740 safe_free(client_blob
);
741 client_blob
=xstrdup(blob
);
742 conn
->auth_type
= AUTH_NEGOTIATE
;
743 assert(conn
->auth_user_request
== NULL
);
744 conn
->auth_user_request
= this;
745 AUTHUSERREQUESTLOCK(conn
->auth_user_request
, "conn");
746 this->request
= request
;
747 HTTPMSGLOCK(this->request
);
752 case AUTHENTICATE_STATE_INITIAL
:
753 debugs(29, 1, "AuthNegotiateUserRequest::authenticate: need to ask helper");
760 case AUTHENTICATE_STATE_IN_PROGRESS
:
761 /* we should have received a blob from the client. Hand it off to
763 safe_free(client_blob
);
765 client_blob
= xstrdup (blob
);
768 HTTPMSGUNLOCK(this->request
);
769 this->request
= request
;
770 HTTPMSGLOCK(this->request
);
775 case AUTHENTICATE_STATE_DONE
:
776 fatal("AuthNegotiateUserRequest::authenticate: unexpect auth state DONE! Report a bug to the squid developers.\n");
780 case AUTHENTICATE_STATE_FAILED
:
781 /* we've failed somewhere in authentication */
782 debugs(29, 9, "AuthNegotiateUserRequest::authenticate: auth state negotiate failed. " << proxy_auth
);
792 AuthNegotiateUserRequest::AuthNegotiateUserRequest() :
793 /*conn(NULL),*/ auth_state(AUTHENTICATE_STATE_NONE
),
803 AuthNegotiateUserRequest::~AuthNegotiateUserRequest()
805 safe_free(server_blob
);
806 safe_free(client_blob
);
808 if (authserver
!= NULL
) {
809 debugs(29, 9, "AuthNegotiateUserRequest::~AuthNegotiateUserRequest: releasing server '" << authserver
<< "'");
810 helperStatefulReleaseServer(authserver
);
814 HTTPMSGUNLOCK(request
);
820 NegotiateUser::deleteSelf() const
825 NegotiateUser::NegotiateUser (AuthConfig
*config
) : AuthUser (config
)
827 proxy_auth_list
.head
= proxy_auth_list
.tail
= NULL
;
831 negotiateScheme::createConfig()
833 return &negotiateConfig
;
837 AuthNegotiateUserRequest::connLastHeader()