#include "smbval/smblib-common.h"
#include "smbval/rfcnb-error.h"
+#include <signal.h>
+#include <unistd.h>
+
/* these are part of rfcnb-priv.h and smblib-priv.h */
extern int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
extern int SMB_Get_Last_Error();
char error_messages_buffer[BUFFER_SIZE];
#endif
-char load_balance = 0, failover_enabled = 0, protocol_pedantic = 0, last_ditch_enabled = 0;
+char load_balance = 0, protocol_pedantic = 0;
+#ifdef NTLM_FAIL_OPEN
+char last_ditch_enabled = 0;
+#endif
dc *controllers = NULL;
int numcontrollers = 0;
char smb_error_buffer[1000];
-/* housekeeping cycle and periodic operations */
-static unsigned char need_dc_resurrection = 0;
+/* signal handler to be invoked when the authentication operation
+ times out */
+static char got_timeout=0;
static void
-resurrect_dead_dc()
-{
- int j;
- dc *c = controllers;
-
- need_dc_resurrection = 0;
- for (j = 0; j < numcontrollers; j++)
- if (c->status != DC_OK && is_dc_ok(c->domain, c->controller))
- c->status = DC_OK;
+timeout_during_auth(int signum) {
+ dc_disconnect();
}
/* makes a null-terminated string upper-case. Changes CONTENTS! */
send_bh_or_ld(char *bhmessage, ntlm_authenticate * failedauth, int authlen)
{
char *creds = NULL;
+#ifdef NTLM_FAIL_OPEN
if (last_ditch_enabled) {
creds = fetch_credentials(failedauth, authlen);
if (creds) {
SEND("NA last-ditch on, but no credentials");
}
} else {
+#endif
SEND2("BH %s", bhmessage);
+#ifdef NTLM_FAIL_OPEN
}
+#endif
}
/*
* options:
* -b try load-balancing the domain-controllers
* -f fail-over to another DC if DC connection fails.
+ * DEPRECATED and VERBOSELY IGNORED. This is on by default now.
* -l last-ditch-mode
* domain\controller ...
*/
usage()
{
fprintf(stderr,
- "%s usage:\n%s [-b] [-f] domain\\controller [domain\\controller ...]\n-b, if specified, enables load-balancing among controllers\n-f, if specified, enables failover among controllers\n-l, if specified, changes behavior on domain controller failyures to\tlast-ditch\n\nYou MUST specify at least one Domain Controller.\nYou can use either \\ or / as separator between the domain name \n\tand the controller name\n",
+ "%s usage:\n%s [-b] [-f] domain\\controller [domain\\controller ...]\n-b, if specified, enables load-balancing among controllers\n-f, if specified, enables failover among controllers (DEPRECATED and always active)\n-l, if specified, changes behavior on domain controller failyures to\tlast-ditch\n\nYou MUST specify at least one Domain Controller.\nYou can use either \\ or / as separator between the domain name \n\tand the controller name\n",
my_program_name, my_program_name);
}
load_balance = 1;
break;
case 'f':
- failover_enabled = 1;
+ fprintf(stderr,
+ "WARNING. The -f flag is DEPRECATED and always active.\n");
break;
+#ifdef NTLM_FAIL_OPEN
case 'l':
last_ditch_enabled = 1;
break;
+#endif
default:
fprintf(stderr, "unknown option: -%c. Exiting\n", opt);
usage();
numcontrollers++;
new_dc->domain = d;
new_dc->controller = c;
- new_dc->status = DC_OK;
+ new_dc->dead = 0;
if (controllers == NULL) { /* first controller */
controllers = new_dc;
last_dc = new_dc;
{
int j = 0;
const char *ch = NULL;
- debug("obtain_challenge: getting new challenge\n");
for (j = 0; j < numcontrollers; j++) {
- if (current_dc->status == DC_OK) {
- debug("getting challenge from %s\\%s (attempt no. %d)\n",
- current_dc->domain, current_dc->controller, j + 1);
- ch = make_challenge(current_dc->domain, current_dc->controller);
- debug("make_challenge retuned %p\n", ch);
- if (ch) {
- debug("Got it\n");
- return ch; /* All went OK, returning */
+ debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n",
+ current_dc->domain, current_dc->controller, j + 1);
+ if (current_dc->dead != 0) {
+ if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) {
+ /* mark helper as retry-worthy if it's so. */
+ debug("Reviving DC\n");
+ current_dc->dead = 0;
+ } else { /* skip it */
+ debug("Skipping it\n");
+ continue;
}
- /* Huston, we've got a problem. Take this DC out of the loop */
- debug("Marking DC as DEAD\n");
- current_dc->status = DC_DEAD;
- need_dc_resurrection = 1;
- } else {
- debug("controller %s\\%s not OK, skipping\n", current_dc->domain,
- current_dc->controller);
}
- if (failover_enabled == 0) /* No failover. Just return */
- return NULL;
+ /* else branch. Here we KNOW that the DC is fine */
+ debug("attempting challenge retrieval\n");
+ ch = make_challenge(current_dc->domain, current_dc->controller);
+ debug("make_challenge retuned %p\n", ch);
+ if (ch) {
+ debug("Got it\n");
+ return ch; /* All went OK, returning */
+ }
+ /* Huston, we've got a problem. Take this DC out of the loop */
+ debug("Marking DC as DEAD\n");
+ current_dc->dead = time(NULL);
/* Try with the next */
debug("moving on to next controller\n");
current_dc = current_dc->next;
}
- /* DC (all DCs if failover is enabled) failed. */
+ /* all DCs failed. */
return NULL;
}
if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
fprintf(stderr, "fgets() failed! dying..... errno=%d (%s)\n", errno,
strerror(errno));
- abort();
exit(1); /* BIIG buffer */
}
debug("managing request\n");
/* notreached */
case NTLM_AUTHENTICATE:
/* check against the DC */
- plen = strlen(buf) * 3 / 4; /* we only need it here. Optimization */
+ plen = strlen(buf) * 3 / 4; /* we only need it here. Optimization */
+ signal(SIGALRM,timeout_during_auth);
+ alarm(30);
cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen);
+ alarm(0);
+ signal(SIGALRM,SIG_DFL);
+ if (got_timeout != 0) {
+ fprintf(stderr,"ntlm-auth[%d]: Timeout during authentication.\n", getpid());
+ SEND("BH Timeout during authentication");
+ got_timeout=0;
+ return;
+ }
if (cred == NULL) {
int smblib_err, smb_errorclass, smb_errorcode, nb_error;
/* there was an error. We have two errno's to look at.
smb_errorclass = SMBlib_Error_Class(SMB_Get_Last_SMB_Err());
smb_errorcode = SMBlib_Error_Code(SMB_Get_Last_SMB_Err());
nb_error = RFCNB_Get_Last_Error();
- debug
- ("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
+ debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
smblib_err, smb_errorclass, smb_errorcode, nb_error);
/* Should I use smblib_err? Actually it seems I can do as well
* without it.. */
ch = obtain_challenge();
}
SEND2("TT %s", ch);
- if (need_dc_resurrection) /* looks like a good moment... */
- resurrect_dead_dc();
return;
}
SEND("BH Helper detected protocol error");
/*
- * $Id: auth_ntlm.cc,v 1.10 2001/08/03 15:13:12 adrian Exp $
+ * $Id: auth_ntlm.cc,v 1.11 2001/08/29 14:57:36 robertc Exp $
*
* DEBUG: section 29 NTLM Authenticator
* AUTHOR: Robert Collins
/* null auth_user is checked for by authenticateDirection */
switch (ntlm_request->auth_state) {
case AUTHENTICATE_STATE_NONE: /* no progress at all. */
- debug(28, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev.\n");
+ if (auth_user_request->auth_user->flags.credentials_ok != 2)
+ debug(29, 1) ("authenticateNTLMDirection: called before NTLM Authenticate!. Report a bug to squid-dev. au %x\n", auth_user_request);
return -2;
case AUTHENTICATE_STATE_NEGOTIATE: /* send to helper */
case AUTHENTICATE_STATE_RESPONSE: /*send to helper */
xfree(ntlm_request->authchallenge);
if (ntlm_request->ntlmauthenticate)
xfree(ntlm_request->ntlmauthenticate);
+ if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred) {
+ debug(29, 9) ("authenticateNTLMRequestFree: releasing server '%d'\n", ntlm_request->authserver);
+ helperStatefulReleaseServer(ntlm_request->authserver);
+ ntlm_request->authserver = NULL;
+ }
memPoolFree(ntlm_request_pool, ntlm_request);
}
ntlm_request_t *ntlm_request;
debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%d' {%s}\n", lastserver, reply ? reply : "<NULL>");
valid = cbdataValid(r->data);
- if (valid) {
- if (reply) {
- /* seperate out the useful data */
- if (strncasecmp(reply, "TT ", 3) == 0) {
- reply += 3;
- /* we have been given a Challenge */
- /* we should check we weren't given an empty challenge */
- /* copy the challenge to the state data */
- helperstate = helperStatefulServerGetData(lastserver);
- if (helperstate == NULL)
- fatal("lost NTLM helper state! quitting\n");
- helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
- helperstate->challengeuses = 0;
- helperstate->renewed = squid_curtime;
- /* and we satisfy the request that happended on the refresh boundary */
- /* note this code is now in two places FIXME */
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- ntlm_request = auth_user_request->scheme_data;
- assert(ntlm_request != NULL);
- result = S_HELPER_DEFER;
- /* reserve the server for future authentication */
- ntlm_request->authserver_deferred = 1;
- debug(29, 9) ("authenticateNTLMHandleReply: helper '%d'\n", lastserver);
- assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
- ntlm_request->authserver = lastserver;
- ntlm_request->authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
- } else if (strncasecmp(reply, "AF ", 3) == 0) {
- /* we're finished, release the helper */
- reply += 3;
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- assert(auth_user_request->scheme_data != NULL);
- ntlm_request = auth_user_request->scheme_data;
- auth_user = auth_user_request->auth_user;
- ntlm_user = auth_user_request->auth_user->scheme_data;
- assert(ntlm_user != NULL);
- result = S_HELPER_RELEASE;
- /* we only expect OK when finishing the handshake */
- assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
- ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
- ntlm_request->authserver = NULL;
- auth_user->flags.credentials_ok = 1; /* login ok */
+ if (!valid) {
+ debug(29, 1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%d'.\n", lastserver);
+ cbdataUnlock(r->data);
+ authenticateStateFree(r);
+ debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", S_HELPER_RELEASE);
+ return S_HELPER_RELEASE;
+ }
+
+ if (!reply) {
+ fatal("authenticateNTLMHandleReply: called with no result string\n");
+ }
+
+ /* seperate out the useful data */
+ if (strncasecmp(reply, "TT ", 3) == 0) {
+ reply += 3;
+ /* we have been given a Challenge */
+ /* we should check we weren't given an empty challenge */
+ /* copy the challenge to the state data */
+ helperstate = helperStatefulServerGetData(lastserver);
+ if (helperstate == NULL)
+ fatal("lost NTLM helper state! quitting\n");
+ helperstate->challenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+ helperstate->challengeuses = 0;
+ helperstate->renewed = squid_curtime;
+ /* and we satisfy the request that happended on the refresh boundary */
+ /* note this code is now in two places FIXME */
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ ntlm_request = auth_user_request->scheme_data;
+ assert(ntlm_request != NULL);
+ result = S_HELPER_DEFER;
+ /* reserve the server for future authentication */
+ ntlm_request->authserver_deferred = 1;
+ debug(29, 9) ("authenticateNTLMHandleReply: helper '%d'\n", lastserver);
+ assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
+ ntlm_request->authserver = lastserver;
+ ntlm_request->authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ + 5);
+ } else if (strncasecmp(reply, "AF ", 3) == 0) {
+ /* we're finished, release the helper */
+ reply += 3;
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ assert(auth_user_request->scheme_data != NULL);
+ ntlm_request = auth_user_request->scheme_data;
+ auth_user = auth_user_request->auth_user;
+ ntlm_user = auth_user_request->auth_user->scheme_data;
+ assert(ntlm_user != NULL);
+ result = S_HELPER_RELEASE;
+ /* we only expect OK when finishing the handshake */
+ assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
+ ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
+ ntlm_request->authserver = NULL;
+ auth_user->flags.credentials_ok = 1; /* login ok */
#ifdef NTLM_FAIL_OPEN
- } else if (strncasecmp(reply, "LD ", 3) == 0) {
- /* This is a variant of BH, which rather than deny access
- * allows the user through. The helper is starved and then refreshed
- * via YR, all pending authentications are likely to fail also.
- * It is meant for those helpers which occasionally fail for
- * no reason at all (casus belli, NTLMSSP helper on NT domain,
- * failing about 1 auth out of 1k.
- * The code is a merge from the BH case with snippets of the AF
- * case */
- /* AF code: mark user as authenticated */
- reply += 3;
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- assert(auth_user_request->scheme_data != NULL);
- ntlm_request = auth_user_request->scheme_data;
- auth_user = auth_user_request->auth_user;
- ntlm_user = auth_user_request->auth_user->scheme_data;
- assert(ntlm_user != NULL);
- result = S_HELPER_RELEASE;
- /* we only expect OK when finishing the handshake */
- assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
- ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
- helperstate = helperStatefulServerGetData(ntlm_request->authserver);
- ntlm_request->authserver = NULL;
- auth_user->flags.credentials_ok = 1; /* login ok */
- /* BH code: mark helper as broken */
- /* Not a valid helper response to a YR request. Assert so the helper
- * programmer will fix their bugs! */
- assert(ntlm_request->auth_state != AUTHENTICATE_STATE_NEGOTIATE);
- /* mark it for starving */
- helperstate->starve = 1;
+ } else if (strncasecmp(reply, "LD ", 3) == 0) {
+ /* This is a variant of BH, which rather than deny access
+ * allows the user through. The helper is starved and then refreshed
+ * via YR, all pending authentications are likely to fail also.
+ * It is meant for those helpers which occasionally fail for
+ * no reason at all (casus belli, NTLMSSP helper on NT domain,
+ * failing about 1 auth out of 1k.
+ * The code is a merge from the BH case with snippets of the AF
+ * case */
+ /* AF code: mark user as authenticated */
+ reply += 3;
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ assert(auth_user_request->scheme_data != NULL);
+ ntlm_request = auth_user_request->scheme_data;
+ auth_user = auth_user_request->auth_user;
+ ntlm_user = auth_user_request->auth_user->scheme_data;
+ assert(ntlm_user != NULL);
+ result = S_HELPER_RELEASE;
+ /* we only expect OK when finishing the handshake */
+ assert(ntlm_request->auth_state == AUTHENTICATE_STATE_RESPONSE);
+ ntlm_user->username = xstrndup(reply, MAX_LOGIN_SZ);
+ helperstate = helperStatefulServerGetData(ntlm_request->authserver);
+ ntlm_request->authserver = NULL;
+ auth_user->flags.credentials_ok = 1; /* login ok */
+ /* BH code: mark helper as broken */
+ /* Not a valid helper response to a YR request. Assert so the helper
+ * programmer will fix their bugs! */
+ assert(ntlm_request->auth_state != AUTHENTICATE_STATE_NEGOTIATE);
+ /* mark it for starving */
+ helperstate->starve = 1;
#endif
- } else if (strncasecmp(reply, "NA ", 3) == 0) {
- /* TODO: only work with auth_user here if it exists */
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- auth_user = auth_user_request->auth_user;
- assert(auth_user != NULL);
- ntlm_user = auth_user->scheme_data;
- ntlm_request = auth_user_request->scheme_data;
- assert((ntlm_user != NULL) && (ntlm_request != NULL));
- /* todo: action of Negotiate state on error */
- result = S_HELPER_RELEASE; /*some error has occured. no more requests */
- ntlm_request->authserver = NULL;
- auth_user->flags.credentials_ok = 2; /* Login/Usercode failed */
- debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
- ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
- if ((t = strchr(reply, ' '))) /* strip after a space */
- *t = '\0';
- } else if (strncasecmp(reply, "BH ", 3) == 0) {
- /* TODO kick off a refresh process. This can occur after a YR or after
- * a KK. If after a YR release the helper and resubmit the request via
- * Authenticate NTLM start.
- * If after a KK deny the user's request w/ 407 and mark the helper as
- * Needing YR. */
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- auth_user = auth_user_request->auth_user;
- assert(auth_user != NULL);
- ntlm_user = auth_user->scheme_data;
- ntlm_request = auth_user_request->scheme_data;
- assert((ntlm_user != NULL) && (ntlm_request != NULL));
- result = S_HELPER_RELEASE; /*some error has occured. no more requests for
- * this helper */
- helperstate = helperStatefulServerGetData(ntlm_request->authserver);
- ntlm_request->authserver = NULL;
- if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) {
- /* The helper broke on YR. It automatically
- * resets */
- auth_user->flags.credentials_ok = 3; /* cannot process */
- debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %d. Error returned '%s'\n", lastserver, reply);
- /* mark it for starving */
- helperstate->starve = 1;
- /* resubmit the request. This helper is currently busy, so we will get
- * a different one. */
- authenticateNTLMStart(auth_user_request, r->handler, r->data);
- } else {
- /* the helper broke on a KK */
- /* first the standard KK stuff */
- auth_user->flags.credentials_ok = 2; /* Login/Usercode failed */
- debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
- ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
- if ((t = strchr(reply, ' '))) /* strip after a space */
- *t = '\0';
- /* now we mark the helper for resetting. */
- helperstate->starve = 1;
- }
- ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
- } else {
- /* TODO: only work with auth_user here if it exists */
- assert(r->auth_user_request != NULL);
- assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
- auth_user_request = r->auth_user_request;
- auth_user = auth_user_request->auth_user;
- assert(auth_user != NULL);
- ntlm_user = auth_user->scheme_data;
- ntlm_request = auth_user_request->scheme_data;
- assert((ntlm_user != NULL) && (ntlm_request != NULL));
- debug(29, 1) ("authenticateNTLMHandleReply: Unsupported helper response, '%s'\n", reply);
- /* restart the authentication process */
- ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
- auth_user->flags.credentials_ok = 3; /* cannot process */
- ntlm_request->authserver = NULL;
- }
+ } else if (strncasecmp(reply, "NA ", 3) == 0) {
+ /* TODO: only work with auth_user here if it exists */
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ auth_user = auth_user_request->auth_user;
+ assert(auth_user != NULL);
+ ntlm_user = auth_user->scheme_data;
+ ntlm_request = auth_user_request->scheme_data;
+ assert((ntlm_user != NULL) && (ntlm_request != NULL));
+ /* todo: action of Negotiate state on error */
+ result = S_HELPER_RELEASE; /*some error has occured. no more requests */
+ ntlm_request->authserver = NULL;
+ auth_user->flags.credentials_ok = 2; /* Login/Usercode failed */
+ debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
+ ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+ if ((t = strchr(reply, ' '))) /* strip after a space */
+ *t = '\0';
+ } else if (strncasecmp(reply, "NA", 2) == 0) {
+ /* NTLM Helper protocol violation! */
+ fatal ("NTLM Helper returned invalid response \"NA\" - a error message MUST be attached\n");
+ } else if (strncasecmp(reply, "BH ", 3) == 0) {
+ /* TODO kick off a refresh process. This can occur after a YR or after
+ * a KK. If after a YR release the helper and resubmit the request via
+ * Authenticate NTLM start.
+ * If after a KK deny the user's request w/ 407 and mark the helper as
+ * Needing YR. */
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ auth_user = auth_user_request->auth_user;
+ assert(auth_user != NULL);
+ ntlm_user = auth_user->scheme_data;
+ ntlm_request = auth_user_request->scheme_data;
+ assert((ntlm_user != NULL) && (ntlm_request != NULL));
+ result = S_HELPER_RELEASE; /*some error has occured. no more requests for
+ * this helper */
+ assert (ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
+ helperstate = helperStatefulServerGetData(ntlm_request->authserver);
+ ntlm_request->authserver = NULL;
+ if (ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE) {
+ /* The helper broke on YR. It automatically
+ * resets */
+ auth_user->flags.credentials_ok = 3; /* cannot process */
+ debug(29, 1) ("authenticateNTLMHandleReply: Error obtaining challenge from helper: %d. Error returned '%s'\n", lastserver, reply);
+ /* mark it for starving */
+ helperstate->starve = 1;
+ /* resubmit the request. This helper is currently busy, so we will get
+ * a different one. */
+ authenticateNTLMStart(auth_user_request, r->handler, r->data);
+ /* don't call the callback */
+ cbdataUnlock(r->data);
+ authenticateStateFree(r);
+ debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
+ return result;
} else {
- fatal("authenticateNTLMHandleReply: called with no result string\n");
+ /* the helper broke on a KK */
+ /* first the standard KK stuff */
+ auth_user->flags.credentials_ok = 2; /* Login/Usercode failed */
+ debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM. Error returned '%s'\n", reply);
+ if ((t = strchr(reply, ' '))) /* strip after a space */
+ *t = '\0';
+ /* now we mark the helper for resetting. */
+ helperstate->starve = 1;
}
- r->handler(r->data, NULL);
+ ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
} else {
- debug(29, 1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%d'.\n", lastserver);
- result = S_HELPER_RELEASE;
+ /* TODO: only work with auth_user here if it exists */
+ assert(r->auth_user_request != NULL);
+ assert(r->auth_user_request->auth_user->auth_type == AUTH_NTLM);
+ auth_user_request = r->auth_user_request;
+ auth_user = auth_user_request->auth_user;
+ assert(auth_user != NULL);
+ ntlm_user = auth_user->scheme_data;
+ ntlm_request = auth_user_request->scheme_data;
+ assert((ntlm_user != NULL) && (ntlm_request != NULL));
+ debug(29, 1) ("authenticateNTLMHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
+ /* restart the authentication process */
+ ntlm_request->auth_state = AUTHENTICATE_STATE_NONE;
+ auth_user->flags.credentials_ok = 3; /* cannot process */
+ assert (ntlm_request->authserver ? ntlm_request->authserver == lastserver : 1);
+ ntlm_request->authserver = NULL;
}
+ r->handler(r->data, NULL);
cbdataUnlock(r->data);
authenticateStateFree(r);
debug(29, 9) ("NTLM HandleReply, telling stateful helper : %d\n", result);
helperStatefulReleaseServer(server);
/* Get another deferrable server */
server = helperStatefulDefer(ntlmauthenticators);
- if (server != NULL)
- helperstate = helperStatefulServerGetData(server);
+ helperstate = server ? helperStatefulServerGetData(server) : NULL;
}
if (server == NULL)
debug(29, 9) ("unable to get a deferred ntlm helper... all helpers are refreshing challenges. Queuing as a placeholder request.\n");
helperstate->challengeuses++;
/* assign the challenge */
ntlm_request->authchallenge = xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ + 5);
- /* we're not actually submitting a request, so we need to release the helper should
- * the connection close unexpectedly
+ /* we're not actually submitting a request, so we need to release the helper
+ * should the connection close unexpectedly
*/
ntlm_request->authserver_deferred = 1;
handler(data, NULL);
if (conn->auth_user_request != NULL) {
assert(conn->auth_user_request->scheme_data != NULL);
ntlm_request = conn->auth_user_request->scheme_data;
+ assert (ntlm_request->conn == conn);
if (ntlm_request->authserver != NULL && ntlm_request->authserver_deferred)
authenticateNTLMReleaseServer(conn->auth_user_request);
/* unlock the connection based lock */
debug(29, 9) ("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n");
+ /* minor abstraction break here: FIXME */
+ /* Ensure that the auth user request will be getting closed */
+ /* IFF we start persisting the struct after the conn closes - say for logging
+ * then this test may become invalid
+ */
+ assert(conn->auth_user_request->references == 1);
authenticateAuthUserRequestUnlock(conn->auth_user_request);
conn->auth_user_request = NULL;
}
ntlm_request->ntlmnegotiate = xstrndup(proxy_auth, NTLM_CHALLENGE_SZ + 5);
conn->auth_type = AUTH_NTLM;
conn->auth_user_request = auth_user_request;
+ ntlm_request->conn = conn;
/* and lock for the connection duration */
debug(29, 9) ("authenticateNTLMAuthenticateUser: Locking auth_user from the connection.\n");
authenticateAuthUserRequestLock(auth_user_request);
} else {
debug(29, 4) ("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n");
/* throw away the temporary entry */
+ ntlm_request->authserver_deferred = 0;
authenticateNTLMReleaseServer(auth_user_request);
authenticateAuthUserMerge(auth_user, proxy_auth_hash->auth_user);
auth_user = proxy_auth_hash->auth_user;
return;
break;
case AUTHENTICATE_STATE_RESPONSE:
- /* auth-challenge pair cache miss. We've just got the response */
+ /* auth-challenge pair cache miss. We've just got the response from the helper */
/*add to cache and let them through */
ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
/* this connection is authenticated */