---------------------
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_requests<srv->deferred_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
