--------------------- PatchSet 886 Date: 2000/12/04 11:02:14 Author: rbcollins Branch: auth_rewrite Tag: (none) Log: NTLM helper protocol V3 support. Not quite complete - Challenge caching needs implementing but it will authenticate correctly, with a unique challenge per request. Members: ntlm_auth_modules/fakeauth/fakeauth_auth.c:1.1.2.6.2.3->1.1.2.6.2.4 src/helper.c:1.1.1.3.12.13->1.1.1.3.12.13.2.1 src/protos.h:1.1.1.3.12.17.2.6->1.1.1.3.12.17.2.7 src/structs.h:1.1.1.3.4.1.2.26.2.6->1.1.1.3.4.1.2.26.2.7 src/typedefs.h:1.1.1.3.12.13.2.6->1.1.1.3.12.13.2.7 src/auth/ntlm/auth_ntlm.c:1.1.2.6->1.1.2.7 src/auth/ntlm/auth_ntlm.h:1.1->1.1.2.1 Index: squid/ntlm_auth_modules/fakeauth/fakeauth_auth.c =================================================================== RCS file: /cvsroot/squid-sf//squid/ntlm_auth_modules/fakeauth/Attic/fakeauth_auth.c,v retrieving revision 1.1.2.6.2.3 retrieving revision 1.1.2.6.2.4 diff -u -r1.1.2.6.2.3 -r1.1.2.6.2.4 --- squid/ntlm_auth_modules/fakeauth/fakeauth_auth.c 4 Dec 2000 08:36:30 -0000 1.1.2.6.2.3 +++ squid/ntlm_auth_modules/fakeauth/fakeauth_auth.c 4 Dec 2000 11:02:14 -0000 1.1.2.6.2.4 @@ -278,7 +278,7 @@ printf ("TT %s\n", data); } else if (strncasecmp (buf, "KK ",3) == 0) { - cleartext = (char *) uudecode (buf); + cleartext = (char *) uudecode (buf+3); if (!ntlmCheckHeader ((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) { if (!ntlmDecodeAuth((struct ntlm_authenticate *) cleartext, user, 256)) @@ -287,11 +287,11 @@ printf ("AF %s\n", user); } else { lc (user); - printf ("NA %s\n", user); + printf ("NA invalid credentials%s\n", user); } } else { lc (user); - printf ("BH %s\n", user); + printf ("BH wrong packet type!%s\n", user); } } #endif Index: squid/src/helper.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/helper.c,v retrieving revision 1.1.1.3.12.13 retrieving revision 1.1.1.3.12.13.2.1 diff -u -r1.1.1.3.12.13 -r1.1.1.3.12.13.2.1 --- squid/src/helper.c 12 Nov 2000 21:22:21 -0000 1.1.1.3.12.13 +++ squid/src/helper.c 4 Dec 2000 11:02:15 -0000 1.1.1.3.12.13.2.1 @@ -1,6 +1,6 @@ /* - * $Id: helper.c,v 1.1.1.3.12.13 2000/11/12 21:22:21 rbcollins Exp $ + * $Id: helper.c,v 1.1.1.3.12.13.2.1 2000/12/04 11:02:15 rbcollins Exp $ * * DEBUG: section 29 Helper process maintenance * AUTHOR: Harvest Derived? @@ -42,7 +42,6 @@ static PF helperServerFree; static PF helperStatefulServerFree; static void Enqueue(helper * hlp, helper_request *); -static void StatefulEnqueue(statefulhelper * hlp, helper_stateful_request *); static helper_request *Dequeue(helper * hlp); static helper_stateful_request *StatefulDequeue(statefulhelper * hlp); static helper_server *GetFirstAvailable(helper * hlp); @@ -193,6 +192,8 @@ srv->buf_sz = 8192; srv->offset = 0; srv->parent = hlp; + if (hlp->datapool != NULL) + srv->data = memPoolAlloc(hlp->datapool); cbdataLock(hlp); /* lock because of the parent backlink */ dlinkAddTail(srv, &srv->link, &hlp->servers); if (rfd == wfd) { @@ -273,6 +274,50 @@ debug(29,9) ("helperStatefulSubmit: %s\n",buf); } +helper_stateful_server * +helperStatefulDefer(statefulhelper *hlp) +/* find and add a deferred request to a server */ +{ + dlink_node *n; + helper_stateful_server *srv = NULL, *rv = NULL; + if (hlp == NULL) { + debug(29, 3) ("helperStatefulReserve: hlp == NULL\n"); + return NULL; + } + debug(29,5)("helperStatefulDefer: Running servers %d.\n",hlp->n_running); + if (hlp->n_running == 0) + return NULL; + + srv = StatefulGetFirstAvailable(hlp); + /* all currently busy:loop through servers and find server with the shortest queue */ + rv = srv; + if (rv == NULL) + for (n = hlp->servers.head; n != NULL; n = n->next) { + srv = n->data; + if (srv->flags.busy) + continue; + if (srv->flags.reserved==S_HELPER_RESERVED) + continue; + if (!srv->flags.alive) + continue; + if ((hlp->available != NULL) && (srv->data != NULL) && + !(hlp->available(srv->data))) + continue; + if ((rv != NULL) && (rv->deferred_requestsdeferred_requests)) + continue; + rv = srv; + } + if (rv == NULL) + { + debug(29,5)("helperStatefulDefer: None available.\n"); + return NULL; + } + + rv->flags.reserved=S_HELPER_DEFERRED; + rv->deferred_requests++; + return rv; +} + void helperStatefulReset(helper_stateful_server * srv) /* puts this helper back in the queue. the calling app is required to @@ -312,6 +357,13 @@ srv->flags.reserved=S_HELPER_FREE; } +void * +helperStatefulServerGetData(helper_stateful_server * srv) +/* return a pointer to the stateful routines data area */ +{ + return srv->data; +} + void helperStats(StoreEntry * sentry, helper * hlp) { @@ -490,7 +542,7 @@ return hlp; } -helper * +statefulhelper * helperStatefulCreate(const char *name) { statefulhelper *hlp = memAllocate(MEM_HELPER_STATEFUL); @@ -511,7 +563,7 @@ } void -helperStatefulFree(helper * hlp) +helperStatefulFree(statefulhelper * hlp) { /* note, don't free hlp->name, it probably points to static memory */ if (hlp->queue.head) @@ -585,6 +637,8 @@ if (hlp->n_running < hlp->n_to_start / 2) fatalf("Too few %s processes are running", hlp->id_name); } + if (srv->data != NULL) + memPoolFree(hlp->datapool,srv->data); cbdataUnlock(srv->parent); cbdataFree(srv); } @@ -859,7 +913,7 @@ } static helper_stateful_server * -StatefulGetFirstAvailable(helper * hlp) +StatefulGetFirstAvailable(statefulhelper * hlp) { dlink_node *n; helper_stateful_server *srv = NULL; @@ -874,6 +928,8 @@ continue; if (!srv->flags.alive) continue; + if ((hlp->available != NULL) && (srv->data != NULL) && !(hlp->available(srv->data))) + continue; return srv; } debug(29,5)("StatefulGetFirstAvailable: None available.\n"); Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.1.1.3.12.17.2.6 retrieving revision 1.1.1.3.12.17.2.7 diff -u -r1.1.1.3.12.17.2.6 -r1.1.1.3.12.17.2.7 --- squid/src/protos.h 24 Nov 2000 00:01:03 -0000 1.1.1.3.12.17.2.6 +++ squid/src/protos.h 4 Dec 2000 11:02:15 -0000 1.1.1.3.12.17.2.7 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.1.1.3.12.17.2.6 2000/11/24 00:01:03 rbcollins Exp $ + * $Id: protos.h,v 1.1.1.3.12.17.2.7 2000/12/04 11:02:15 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -1219,6 +1219,8 @@ extern void helperStatefulFree(statefulhelper *); extern void helperStatefulReset(helper_stateful_server * srv); extern void helperStatefulReleaseServer(helper_stateful_server * srv); +extern void *helperStatefulServerGetData(helper_stateful_server * srv); +extern helper_stateful_server *helperStatefulDefer(statefulhelper *); Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.1.1.3.4.1.2.26.2.6 retrieving revision 1.1.1.3.4.1.2.26.2.7 diff -u -r1.1.1.3.4.1.2.26.2.6 -r1.1.1.3.4.1.2.26.2.7 --- squid/src/structs.h 23 Nov 2000 10:37:27 -0000 1.1.1.3.4.1.2.26.2.6 +++ squid/src/structs.h 4 Dec 2000 11:02:15 -0000 1.1.1.3.4.1.2.26.2.7 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.6 2000/11/23 10:37:27 rbcollins Exp $ + * $Id: structs.h,v 1.1.1.3.4.1.2.26.2.7 2000/12/04 11:02:15 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -1916,6 +1916,25 @@ } stats; }; +struct _helper_stateful { + wordlist *cmdline; + dlink_list servers; + dlink_list queue; + const char *id_name; + int n_to_start; + int n_running; + int ipc_type; + MemPool *datapool; + HLPSAVAIL *available; + time_t last_queue_warn; + struct { + int requests; + int replies; + int queue_size; + int avg_svc_time; + } stats; +}; + struct _helper_server { int index; int rfd; @@ -1951,7 +1970,7 @@ struct timeval answer_time; dlink_node link; dlink_list queue; - helper *parent; + statefulhelper *parent; helper_stateful_request *request; struct _helper_stateful_flags { unsigned int alive:1; @@ -1964,6 +1983,7 @@ int uses; } stats; size_t deferred_requests; /* current number of deferred requests */ + void *data; /* State data used by the calling routines */ }; /* Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.1.1.3.12.13.2.6 retrieving revision 1.1.1.3.12.13.2.7 diff -u -r1.1.1.3.12.13.2.6 -r1.1.1.3.12.13.2.7 --- squid/src/typedefs.h 23 Nov 2000 10:37:27 -0000 1.1.1.3.12.13.2.6 +++ squid/src/typedefs.h 4 Dec 2000 11:02:15 -0000 1.1.1.3.12.13.2.7 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.1.1.3.12.13.2.6 2000/11/23 10:37:27 rbcollins Exp $ + * $Id: typedefs.h,v 1.1.1.3.12.13.2.7 2000/12/04 11:02:15 rbcollins Exp $ * * * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ @@ -167,7 +167,7 @@ typedef struct _FwdState FwdState; typedef struct _FwdServer FwdServer; typedef struct _helper helper; -typedef struct _helper statefulhelper; +typedef struct _helper_stateful statefulhelper; typedef struct _helper_server helper_server; typedef struct _helper_stateful_server helper_stateful_server; typedef struct _helper_request helper_request; @@ -246,6 +246,7 @@ typedef void STVLDCB(void *, int, int); typedef void HLPCB(void *, char *buf); typedef stateful_helper_callback_t HLPSCB(void *, void * lastserver, char *buf); +typedef int HLPSAVAIL(void *); typedef void HLPCMDOPTS(int *argc, char **argv); typedef void IDNSCB(void *, rfc1035_rr *, int); Index: squid/src/auth/ntlm/auth_ntlm.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/auth/ntlm/auth_ntlm.c,v retrieving revision 1.1.2.6 retrieving revision 1.1.2.7 diff -u -r1.1.2.6 -r1.1.2.7 --- squid/src/auth/ntlm/auth_ntlm.c 24 Nov 2000 00:01:03 -0000 1.1.2.6 +++ squid/src/auth/ntlm/auth_ntlm.c 4 Dec 2000 11:02:17 -0000 1.1.2.7 @@ -39,6 +39,7 @@ #include "squid.h" +#include "auth_ntlm.h" #if 0 typedef struct { @@ -79,10 +80,14 @@ static AUTHSSTART authenticateNTLMStart; static AUTHSSTATS authenticateNTLMStats; +static HLPSAVAIL authenticateNTLMHelperServerAvailable; + static statefulhelper *ntlmauthenticators = NULL; static int authntlm_initialised = 0; +MemPool *ntlm_helper_state_pool = NULL; + /* * * Private Functions @@ -101,6 +106,7 @@ return; helperStatefulFree(ntlmauthenticators); ntlmauthenticators = NULL; + memPoolDestroy(ntlm_helper_state_pool); } void @@ -121,14 +127,17 @@ authscheme->decodeauth =authenticateDecodeNTLMAuth; authscheme->donefunc = authNTLMDone; authscheme->oncloseconnection = authenticateNTLMOnCloseConnection; -// ufs_state_pool = memPoolCreate("UFS IO State data", sizeof(ufsstate_t)); + ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t)); authntlm_initialised = 1; if (ntlmauthenticators == NULL) ntlmauthenticators = helperStatefulCreate("ntlmauthenticator"); ntlmauthenticators->cmdline = Config.Program.ntlmauthenticate; ntlmauthenticators->n_to_start = Config.ntlmauthenticateChildren; ntlmauthenticators->ipc_type = IPC_TCP_SOCKET; + ntlmauthenticators->datapool=ntlm_helper_state_pool; + ntlmauthenticators->available=authenticateNTLMHelperServerAvailable; helperStatefulOpenServers(ntlmauthenticators); + /* TODO: In here send the initial YR */ if (!ntlminit) { cachemgrRegister("ntlmauthenticator", "User NTLM Authenticator Stats", @@ -227,6 +236,7 @@ authenticateStatefulStateData *r = data; #endif authenticateStateData *r = data; + ntlm_helper_state_t * helperstate; int valid; stateful_helper_callback_t result = S_HELPER_UNKNOWN; #if 0 @@ -240,13 +250,25 @@ if (valid) { if (reply) { /* seperate out the useful data */ +#ifdef NTLMHELPROTOCOLV2 if (strncasecmp(reply, "CH ", 3) == 0) { +#else + if (strncasecmp(reply, "TT ", 3) == 0) { + /* TODO: Here we update the challenge associated with the helper */ +#endif reply += 3; /* we have been given a Challenge */ /* we should check we weren't given an empty challenge */ #if 0 result=S_HELPER_RESERVE; #endif +#ifndef NTLMHELPPROTOCOLV2 + /* 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); + /* and we satisfy the request that happended on the refresh boundary */ +#endif assert(r->auth_user != NULL); assert(r->auth_user->auth_type == AUTH_NTLM); auth_user=r->auth_user; @@ -261,7 +283,11 @@ auth_user->auth_data.ntlm_auth.authchallenge = xstrndup(reply, NTLM_CHALLENGE_SZ+5); } +#ifdef NTLMHELPPROTOCOLV2 else if (strncasecmp(reply, "OK ", 3) == 0) { +#else + else if (strncasecmp(reply, "AF ", 3) == 0) { +#endif /* we're finished, release the helper*/ reply+=3; assert(r->auth_user != NULL); @@ -274,6 +300,7 @@ auth_user->auth_data.ntlm_auth.authhelper = NULL; auth_user->flags.credentials_ok = 1; /* login ok */ } +#ifdef NTLMHELPPROTOCOLV2 else if (strncasecmp(reply, "RESET OK", 8) == 0) { /* Helper successfully reset */ /* note a reset request returning here MUST NOT reserve the helper */ @@ -281,7 +308,12 @@ result=S_HELPER_RELEASE; if (r->auth_user) r->auth_user->auth_data.ntlm_auth.authhelper=NULL; } +#endif +#ifdef NTLMHELPPROTOCOLV2 else if (strncasecmp(reply, "ERR", 3) == 0) { +#else + else if (strncasecmp(reply, "NA ", 3) == 0) { +#endif /* TODO: only work with auth_user here if it exists */ assert(r->auth_user != NULL); assert(r->auth_user->auth_type == AUTH_NTLM); @@ -301,7 +333,13 @@ } if ((t = strchr(reply, ' ')))/* strip after a space */ *t = '\0'; - } else { + } +#ifndef NTLMHELPPROTOCOLV2 + else if (strncasecmp(reply, "BH ", 3) == 0) { + /* TODO kick off a refresh process */ + } +#endif + else { /* TODO: only work with auth_user here if it exists */ assert(r->auth_user != NULL); assert(r->auth_user->auth_type == AUTH_NTLM); @@ -356,6 +394,8 @@ authenticateStatefulStateData *r = NULL; #endif authenticateStateData *r = NULL; + helper_stateful_server *server; + ntlm_helper_state_t *helperstate; char buf[8192]; char *sent_string=NULL; @@ -382,6 +422,7 @@ while (xisspace(*sent_string)) /*trim leading spaces */ sent_string++; + debug(29, 5) ("authenticateNTLMStart: state '%d'\n", auth_user->auth_data.ntlm_auth.auth_state); debug(29, 5) ("authenticateNTLMStart: '%s'\n", sent_string); if (Config.Program.ntlmauthenticate == NULL) { @@ -390,6 +431,7 @@ handler(data, NULL); return; } +#ifdef NTLMHELPPROTOCOLV2 r = xcalloc(1, sizeof(authenticateStateData)); #if 0 r = xcalloc(1, sizeof(authenticateStatefulStateData)); @@ -402,8 +444,77 @@ snprintf(buf, 8192, "%s\n", sent_string); helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, auth_user->auth_data.ntlm_auth.authhelper); debug(29,9)("authenticateNTLMstart: finished\n"); +#else + /* this is ugly TODO: move the challenge generation routines to their own function and + * tidy the logic up to make use of the efficiency we now have */ + switch(auth_user->auth_data.ntlm_auth.auth_state) { + case AUTHENTICATE_STATE_NEGOTIATE: + /* + * 1: get a helper server + * 2: does it have a challenge? + * 3: tell it to get a challenge, or give ntlmauthdone the challenge + */ + server=helperStatefulDefer(ntlmauthenticators); + if (server==NULL) fatal("unable to get a deferred ntlm helper... this shouldn't happen.\n"); + helperstate=helperStatefulServerGetData(server); + /* valid challenge? */ + if((helperstate->challenge == NULL) || 1) + { + auth_user->auth_data.ntlm_auth.authhelper=server; + r = xcalloc(1, sizeof(authenticateStateData)); + cbdataAdd(r, cbdataXfree, 0); + r->handler = handler; + cbdataLock(data); + r->data = data; + r->auth_user = auth_user; + snprintf(buf, 8192, "YR\n", sent_string); + helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, auth_user->auth_data.ntlm_auth.authhelper); + } else { + /* we have a valid challenge */ + /* TODO: reuse the challenge */ + } + + break; + case AUTHENTICATE_STATE_RESPONSE: + r = xcalloc(1, sizeof(authenticateStateData)); + cbdataAdd(r, cbdataXfree, 0); + r->handler = handler; + cbdataLock(data); + r->data = data; + r->auth_user = auth_user; + snprintf(buf, 8192, "KK %s\n", sent_string); + helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, auth_user->auth_data.ntlm_auth.authhelper); + debug(29,9)("authenticateNTLMstart: finished\n"); + break; + default: + fatal("Invalid authenticate state for NTLMStart"); + } +#endif } +/* callback used by stateful helper routines */ +int +authenticateNTLMHelperServerAvailable(void *data) +{ + ntlm_helper_state_t *statedata=data; + if (statedata != NULL) + { + if (statedata->starve) + { + debug(29,6)("authenticateNTLMHelperServerAvailable: returning 0\n"); + return 0; + } + else + { + debug(29,6)("authenticateNTLMHelperServerAvailable: returning 1\n"); + return 1; + } + } + debug(29,6)("authenticateNTLMHelperServerAvailable: returning 0\n"); + return 0; +} + + /* clear the NTLM helper of being reserved for future requests */ void authenticateNTLMReleasehelper(acl_proxy_auth_user *auth_user){ --- /dev/null Wed Feb 14 00:45:56 2007 +++ squid/src/auth/ntlm/auth_ntlm.h Wed Feb 14 00:47:04 2007 @@ -0,0 +1,18 @@ +/* + * auth_ntlm.h + * Internal declarations for the ntlm auth module + */ + +#ifndef __AUTH_NTLM_H__ +#define __AUTH_NTLM_H__ + +struct _ntlm_helper_state_t { + char *challenge; /* the challenge to use with this helper */ + int starve; /* 0= normal operation. 1=don't hand out any more challenges */ +}; + +typedef struct _ntlm_helper_state_t ntlm_helper_state_t; + +extern MemPool *ntlm_helper_state_pool; + +#endif