---------------------
PatchSet 1145 
Date: 2001/01/07 02:49:31
Author: rbcollins
Branch: auth_rewrite
Tag: (none) 
Log:
merged in ntlm

Members: 
	lib/ntlmauth.c:1.1.4.2->1.1.4.3 
	ntlm_auth_modules/Makefile.in:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/Makefile.in:1.1.2.3.2.2->1.1.2.3.2.3 
	ntlm_auth_modules/NTLMSSP/libntlmssp.c:1.1.2.12.2.5->1.1.2.12.2.6 
	ntlm_auth_modules/NTLMSSP/ntlm.h:1.1.2.12.2.5->1.1.2.12.2.6 
	ntlm_auth_modules/NTLMSSP/ntlm_auth.c:1.1.2.10.2.5->1.1.2.10.2.6 
	ntlm_auth_modules/NTLMSSP/smbval/Makefile.in:1.1.2.1.2.3->1.1.2.1.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/byteorder.h:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/md4.c:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/md4.h:1.1.2.2->1.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-common.h:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-error.h:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-io.c:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-io.h:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-priv.h:1.1.2.2.2.2->1.1.2.2.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-util.c:1.1.2.1.2.3->1.1.2.1.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb-util.h:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/rfcnb.h:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/session.c:1.1.2.1.2.3->1.1.2.1.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/smbdes.c:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/smbdes.h:1.1.2.2->1.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/smbencrypt.c:1.1.2.1.2.3->1.1.2.1.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/smbencrypt.h:1.1.2.2->1.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/smblib-common.h:1.1.2.2.2.1->1.1.2.2.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/smblib-priv.h:1.1.2.2.2.3->1.1.2.2.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/smblib-util.c:1.1.2.1.2.3->1.1.2.1.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/smblib.c:1.1.2.6.2.3->1.1.2.6.2.4 
	ntlm_auth_modules/NTLMSSP/smbval/smblib.h:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/std-defines.h:1.1.2.3.2.1->1.1.2.3.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/std-includes.h:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/NTLMSSP/smbval/valid.c:1.1.2.1.2.2->1.1.2.1.2.3 
	ntlm_auth_modules/NTLMSSP/smbval/valid.h:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/fakeauth/Makefile.in:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/fakeauth/fakeauth_auth.c:1.1.2.6.2.6->1.1.2.6.2.7 
	ntlm_auth_modules/fakeauth/ntlm.h:1.1.2.3.2.1->1.1.2.3.2.2 
	ntlm_auth_modules/no_check/Makefile.in:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/no_check/README.no_check_ntlm_auth:1.1.2.1.2.1->1.1.2.1.2.2 
	ntlm_auth_modules/no_check/no_check:1.1.2.1.2.3->1.1.2.1.2.4 
	src/auth/ntlm/Makefile.in:1.1.2.3->1.1.2.4 
	src/auth/ntlm/auth_ntlm.c:1.1.2.16->1.1.2.17 
	src/auth/ntlm/auth_ntlm.h:1.1.2.5->1.1.2.6 

--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/lib/ntlmauth.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,131 @@
+/*
+ * $Id$
+ *
+ * * * * * * * * Legal stuff * * * * * * *
+ *
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *   inspired by previous work by Andy Doran.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+#include "ntlmauth.h"
+#include "util.h"								/* for base64-related stuff */
+
+/* Dumps NTLM flags to standard error for debugging purposes */
+void ntlm_dump_ntlmssp_flags(u_int32_t flags) {
+	fprintf(stderr,"flags: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+					(flags&NEGOTIATE_UNICODE?"Unicode ":""),
+					(flags&NEGOTIATE_ASCII?"ASCII ":""),
+					(flags&NEGOTIATE_REQUEST_TARGET?"ReqTgt ":""),
+					(flags&NEGOTIATE_REQUEST_SIGN?"ReqSign ":""),
+					(flags&NEGOTIATE_REQUEST_SEAL?"ReqSeal ":""),
+					(flags&NEGOTIATE_DATAGRAM_STYLE?"Dgram ":""),
+					(flags&NEGOTIATE_USE_LM?"UseLM ":""),
+					(flags&NEGOTIATE_USE_NETWARE?"UseNW ":""),
+					(flags&NEGOTIATE_USE_NTLM?"UseNTLM ":""),
+					(flags&NEGOTIATE_DOMAIN_SUPPLIED?"HaveDomain ":""),
+					(flags&NEGOTIATE_WORKSTATION_SUPPLIED?"HaveWKS ":""),
+					(flags&NEGOTIATE_THIS_IS_LOCAL_CALL?"LocalCall ":""),
+					(flags&NEGOTIATE_ALWAYS_SIGN?"AlwaysSign ":""),
+					(flags&CHALLENGE_TARGET_IS_DOMAIN?"Tgt_is_domain":""),
+					(flags&CHALLENGE_TARGET_IS_SERVER?"Tgt_is_server ":""),
+					(flags&CHALLENGE_TARGET_IS_SHARE?"Tgt_is_share ":""),
+					(flags&REQUEST_INIT_RESPONSE?"Req_init_response ":""),
+					(flags&REQUEST_ACCEPT_RESPONSE?"Req_accept_response ":""),
+					(flags&REQUEST_NON_NT_SESSION_KEY?"Req_nonnt_sesskey ":"")
+					);
+}
+
+#define lstring_zero(s) s.str=NULL; s.l=-1;
+
+/* fetches a string from the authentication packet.
+ * The lstring data-part points to inside the packet itself.
+ * It's up to the user to memcpy() that if the value needs to
+ * be used in any way that requires a tailing \0. (he can check whether the
+ * value is there though, in that case lstring.length==-1).
+ */
+lstring ntlm_fetch_string (char * packet, int32_t length, strhdr *str) {
+	int16_t l;									/* length */
+	int32_t o;									/* offset */
+	lstring rv;
+
+	lstring_zero(rv);
+	
+	l = SSWAP(str->len);
+	o = WSWAP(str->offset);
+	/* debug("fetch_string(plength=%d,l=%d,o=%d)\n",length,l,o); */
+	
+	if (l < 0 || l > MAX_FIELD_LENGTH || o+l > length || o==0) {
+		/* debug("ntlmssp: insane data (l: %d, o: %d)\n", l,o); */
+		return rv;
+	}
+	
+	rv.str=packet+o;
+	rv.l=l;
+		
+	return rv;
+}
+
+/* Adds something to the payload. The caller must guarrantee that
+ * there is enough space in the payload string to accommodate the
+ * added value.
+ * payload_length and hdr will be modified as a side-effect.
+ * base_offset is the payload offset from the packet's beginning, and is
+ */
+void ntlm_add_to_payload (char *payload, int *payload_length,
+													strhdr *hdr, char *toadd,
+													int toadd_length, int base_offset) {
+	
+	int l=(*payload_length);
+	memcpy(payload+l,toadd,toadd_length);
+
+	hdr->len=toadd_length;
+	hdr->maxlen=toadd_length;
+	hdr->offset=l+base_offset;	/* 48 is the base offset of the payload */
+	(*payload_length)+=toadd_length;
+}
+
+
+/* prepares a base64-encode challenge packet to be sent to the client
+ * note: domain should be upper_case
+ * note: the storage type for the returned value depends on
+ *    base64_encode_bin. Currently this means static storage.
+ */
+char* ntlm_make_challenge(char *domain, char *domain_controller,
+										 char *challenge_nonce, int challenge_nonce_len) {
+	ntlm_challenge ch;
+	int pl=0;
+	char * encoded;
+	memset(&ch, 0, sizeof(ntlm_challenge)); /* reset */
+	memcpy(ch.signature, "NTLMSSP", 8);	/* set the signature */
+	ch.type = WSWAP(NTLM_CHALLENGE); /* this is a challenge */
+	ntlm_add_to_payload(ch.payload, &pl, &ch.target, domain, strlen(domain),
+								 NTLM_CHALLENGE_HEADER_OFFSET);
+	ch.flags=WSWAP(
+								 REQUEST_NON_NT_SESSION_KEY |
+								 CHALLENGE_TARGET_IS_DOMAIN |
+								 NEGOTIATE_ALWAYS_SIGN |
+								 NEGOTIATE_USE_NTLM |
+								 NEGOTIATE_USE_LM |
+								 NEGOTIATE_ASCII |
+								 0
+								 );
+	ch.context_low=0;							/* check this out */
+	ch.context_high=0; 
+	memcpy(ch.challenge,challenge_nonce,challenge_nonce_len);
+ 	encoded=base64_encode_bin((char *)&ch,NTLM_CHALLENGE_HEADER_OFFSET+pl);
+	return encoded;
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,38 @@
+#  Makefile for storage modules in the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1.2.1.2.2 2001/01/07 02:49:31 rbcollins Exp $
+#
+
+# The 'nop' is in the SUBDIRS list because some Unixes that can't
+# handle empty for lists.
+
+SUBDIRS		= @NTLM_AUTH_MODULES@ nop
+
+all:
+	@for dir in $(SUBDIRS); do \
+	    if [ -f $$dir/Makefile ]; then \
+	        sh -c "cd $$dir && $(MAKE) all" || exit 1; \
+	    fi; \
+	done;
+
+clean:
+	-for dir in *; do \
+	    if [ -f $$dir/Makefile ]; then \
+		sh -c "cd $$dir && $(MAKE) clean"; \
+	    fi; \
+	done
+
+distclean:
+	-rm -f Makefile
+	-for dir in *; do \
+	    if [ -f $$dir/Makefile ]; then \
+		sh -c "cd $$dir && $(MAKE) distclean"; \
+	    fi; \
+	done
+
+.DEFAULT:
+	@for dir in $(SUBDIRS); do \
+	    if [ -f $$dir/Makefile ]; then \
+		sh -c "cd $$dir && $(MAKE) $@" || exit 1; \
+	    fi; \
+	done;
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,86 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1.2.3.2.3 2001/01/07 02:49:31 rbcollins Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix		= @prefix@
+exec_prefix	= @exec_prefix@
+exec_suffix	= @exec_suffix@
+top_srcdir	= @top_srcdir@
+bindir		= @bindir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+# Gotta love the DOS legacy
+#
+NTLM_AUTH_EXE	= ntlm_auth$(exec_suffix)
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+INSTALL		= @INSTALL@
+INSTALL_BIN	= @INSTALL_PROGRAM@
+CRYPTLIB	= @CRYPTLIB@
+AC_CFLAGS	= @CFLAGS@
+LDFLAGS		= @LDFLAGS@
+XTRA_LIBS	= @XTRA_LIBS@
+XTRA_OBJS	= @XTRA_OBJS@
+MV		= @MV@
+RM		= @RM@
+SHELL		= /bin/sh
+
+
+INCLUDE		= -I. -I../../include -I$(srcdir)/smbval -I$(top_srcdir)/include
+CFLAGS		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS	= -L../../lib -lntlmauth -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS		= $(NTLM_AUTH_EXE)
+OBJS		= ntlm_auth.o libntlmssp.o
+
+all:	$(NTLM_AUTH_EXE)  smbval/smbvalid.a
+
+$(OBJS): $(top_srcdir)/include/version.h ntlm.h
+
+$(NTLM_AUTH_EXE): $(OBJS) smbval/smbvalid.a 
+	$(CC) $(LDFLAGS) $(OBJS) smbval/smbvalid.a -o $@ $(AUTH_LIBS)
+
+smbval/smbvalid.a: smbval/stamp
+
+smbval smbval/stamp:
+	@sh -c "cd smbval && $(MAKE) all"
+
+install-mkdirs:
+	-@if test ! -d $(prefix); then \
+		echo "mkdir $(prefix)"; \
+		mkdir $(prefix); \
+	fi
+	-@if test ! -d $(bindir); then \
+		echo "mkdir $(bindir)"; \
+		mkdir $(bindir); \
+	fi
+
+install: all install-mkdirs
+	@for f in $(PROGS); do \
+		if test -f $(bindir)/$$f; then \
+			echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+			$(MV) $(bindir)/$$f $(bindir)/-$$f; \
+		fi; \
+		echo $(INSTALL_BIN) $$f $(bindir); \
+		$(INSTALL_BIN) $$f $(bindir); \
+		if test -f $(bindir)/-$$f; then \
+			echo $(RM) -f $(bindir)/-$$f; \
+			$(RM) -f $(bindir)/-$$f; \
+		fi; \
+	done
+
+clean:
+	-rm -rf *.o *pure_* core $(PROGS)
+	cd smbval; make clean
+
+distclean:     clean
+	-rm -f Makefile
+
+depend:
+	$(MAKEDEPEND) -I../include -I. -fMakefile *.c
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/libntlmssp.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,214 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+
+#include "ntlm.h"
+#include "util.h"								/* from Squid */
+#include "valid.h"
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "smblib-priv.h"				/* for SMB_Handle_Type */
+
+/* a few forward-declarations. Hackish, but I don't care right now */
+SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+		 char *server, char *NTdomain);
+
+/* this one is reallllly haackiish. We really should be using anything from smblib-priv.h
+ */
+static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
+                            "MICROSOFT NETWORKS 1.03",
+                            "MICROSOFT NETWORKS 3.0",
+                            "DOS LANMAN1.0",
+                            "LANMAN1.0",
+                            "DOS LM1.2X002",
+                            "LM1.2X002",
+                            "DOS LANMAN2.1",
+                            "LANMAN2.1",
+                            "Samba",
+                            "NT LM 0.12",
+                            "NT LANMAN 1.0",
+                            NULL};
+
+#if 0
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, 
+										 char *PassWord, char * Domain, int precrypted);
+#endif
+
+#ifdef DEBUG
+#define debug_dump_ntlmssp_flags dump_ntlmssp_flags
+#else	 /* DEBUG */
+#define debug_dump_ntlmssp_flags(X) /* empty */
+#endif /* DEBUG */
+
+
+static char challenge[NONCE_LEN];
+SMB_Handle_Type handle=NULL;
+
+/* Disconnects from the DC. A reconnection will be done upon the next request
+ */
+void dc_disconnect() {
+	if (handle != NULL)
+		SMB_Discon(handle,0);
+	handle=NULL;
+}
+
+int connectedp() {
+	return (handle!=NULL);
+}
+
+
+/* Tries to connect to a DC. Returns 0 on failure, 1 on OK */
+int is_dc_ok (char *domain,
+							char *domain_controller) {
+	SMB_Handle_Type h=SMB_Connect_Server(NULL,domain_controller,domain);
+	if (h==NULL)
+		return 0;
+	SMB_Discon(h,0);
+	return 1;
+}
+
+
+/* returns 0 on success, > 0 on failure */
+static int init_challenge(char* domain, char* domain_controller) {
+int smberr;
+char errstr[100];
+
+	if (handle != NULL) {
+		return 0;
+	}
+
+	debug("Connecting to server %s domain %s\n",domain_controller,domain);
+	handle=SMB_Connect_Server(NULL,domain_controller,domain);
+        smberr=SMB_Get_Last_Error();
+        SMB_Get_Error_Msg(smberr,errstr,100);
+        
+	
+	if (handle==NULL) {	/* couldn't connect */
+		debug("Couldn't connect to SMB Server. Error:%s\n",errstr);
+		return 1;
+	}
+	
+	if (SMB_Negotiate(handle, SMB_Prots) < 0) { /* An error */
+		debug("Error negotiating protocol with SMB Server\n");
+		SMB_Discon(handle,0);
+		handle=NULL;
+		return 2;
+	}
+	
+	if (handle -> Security == 0) {	/* share-level security, unuseable */
+		debug("SMB Server uses share-level security .. we need user sercurity.\n");
+		SMB_Discon(handle,0);
+		handle=NULL;
+		return 3;
+	}
+	
+	memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
+	return 0;
+}
+
+char *make_challenge (char *domain, char *domain_controller) {
+	if (init_challenge(domain,domain_controller) > 0)
+		return NULL;
+	return ntlm_make_challenge(domain, domain_controller,challenge,
+														 NONCE_LEN);
+}
+
+#define min(A,B) (A<B?A:B)
+/* returns NULL on failure, or a pointer to
+ * the user's credentials (domain\\username)
+ * upon success. WARNING. It's pointing to static storage.
+ * In case of problem sets as side-effect ntlm_errno to one of the
+ * codes defined in ntlm.h
+ */
+int ntlm_errno;
+static char credentials[1024];	/* we can afford to waste */
+char * ntlm_check_auth(ntlm_authenticate * auth, int auth_length) {
+	int rv, retries=0;
+	char pass[25];
+	char *domain=credentials;
+	char *user;
+	lstring tmp;
+	
+	if (handle==NULL) { /*if null we aren't connected, but it shouldn't happen*/
+		debug("Weird, we've been disconnected\n");
+		ntlm_errno=NTLM_NOT_CONNECTED;
+		return NULL;
+	}
+
+	/* Authenticating against the NT response doesn't seem to work... */
+	tmp=ntlm_fetch_string((char *)auth,auth_length,&auth->lmresponse);
+	if (tmp.str==NULL) {
+		fprintf(stderr,"No auth at all. Returning no-auth\n");
+		ntlm_errno=NTLM_LOGON_ERROR;
+		return NULL;
+	}
+	memcpy(pass,tmp.str,tmp.l);
+	pass[25]='\0';
+
+/* 	debug("fetching domain\n"); */
+	tmp=ntlm_fetch_string((char *)auth,auth_length,&auth->domain);
+	if (tmp.str==NULL) {
+		debug("No domain supplied. Returning no-auth\n");
+		ntlm_errno=NTLM_LOGON_ERROR;
+		return NULL;
+	}
+	memcpy(domain,tmp.str,tmp.l);
+	user=domain+tmp.l;
+	*user++='\0';
+
+/* 	debug("fetching user name\n"); */
+	tmp=ntlm_fetch_string((char *)auth,auth_length,&auth->user);
+	if (tmp.str==NULL) {
+		debug("No username supplied. Returning no-auth\n");
+		ntlm_errno=NTLM_LOGON_ERROR;
+		return NULL;
+	}
+	memcpy(user,tmp.str,tmp.l);
+	*(user+tmp.l)='\0';
+
+	debug("checking domain: '%s', user: '%s', pass='%s'\n",domain,user,pass);
+
+	rv=SMB_Logon_Server(handle,user,pass,domain,1);
+
+	while ( (rv == NTLM_BAD_PROTOCOL || rv==NTLM_SERVER_ERROR)
+					&& retries < BAD_DC_RETRIES_NUMBER) {
+		retries++;
+		usleep ((unsigned long)100000);
+		rv=SMB_Logon_Server(handle,user,pass,domain,1);
+	}
+
+	debug("\tresult is %d\n",rv);
+	
+	if (rv!=NTV_NO_ERROR){   /* failed */
+		ntlm_errno=rv;
+		return NULL;
+	}
+
+	*(user-1)='\\';
+
+	debug("credentials: %s\n",credentials);
+	return credentials;
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/ntlm.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,100 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>,
+ *        inspired by previous work by Andy Doran
+ *
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef _NTLM_H_
+#define _NTLM_H_
+
+#include "config.h"
+#include "ntlmauth.h"
+
+/* for time_t */
+#if HAVE_TIME_H
+#include <time.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+/************* CONFIGURATION ***************/
+/*
+ * define this if you want debugging
+ */
+#define DEBUG
+
+/*
+ * Number of authentication attempts to perform in case of certain errors
+ */
+#define BAD_DC_RETRIES_NUMBER 3
+
+/************* END CONFIGURATION ***************/
+
+#include <sys/types.h>
+
+
+/* Debugging stuff */
+
+#ifdef __GNUC__ /* this is really a gcc-ism */
+#ifdef DEBUG
+#include <stdio.h>
+#include <unistd.h>
+static char* __foo;
+#define debug(X...) fprintf(stderr,"ntlm-auth[%d](%s:%d): ", getpid(), \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X)
+#else	 /* DEBUG */
+#define debug(X...) /* */
+#endif /* DEBUG */
+#else	 /* __GNUC__ */
+#define debug(char *format, ...) {}	/* Too lazy to write va_args stuff */
+#endif
+
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X); printf("\n");
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X,Y);\
+         printf("\n");
+
+extern int ntlm_errno;
+#define NTLM_NO_ERROR 0
+#define NTLM_SERVER_ERROR 1
+#define NTLM_PROTOCOL_ERROR 2
+#define NTLM_LOGON_ERROR 3
+#define NTLM_BAD_PROTOCOL -1
+#define NTLM_NOT_CONNECTED 10
+
+
+char* make_challenge(char *domain, char *controller);
+extern char* ntlm_check_auth(ntlm_authenticate *auth, int auth_length);
+void dc_disconnect(void);
+int connectedp(void);
+int is_dc_ok (char *domain,char *domain_controller);
+
+/* flags used for dc status */
+#define DC_OK 0x0
+#define DC_DEAD 0x1
+
+typedef struct _dc dc;
+struct _dc {
+	char *domain;
+	char *controller;
+	unsigned char status;
+	dc *next;
+};
+
+
+#endif /* _NTLM_H_ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/ntlm_auth.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,324 @@
+/*
+ * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * Distributed freely under the terms of the GNU General Public License,
+ * version 2. See the file COPYING for licensing details
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ * Warning! We MIGHT be open to buffer overflows caused by malformed headers
+ *
+ * DONE list:
+ * use hashtable to cache authentications. Yummy performance-boost, security
+ *  loss should be negligible for two reasons:
+ *   - if they-re using NT, there's no security to speak of anyways
+ *   - it can't get worse than basic authentication.
+ * cache expiration
+ * challenge hash expiry and renewal.
+ * PDC disconnect, after X minutes of inactivity
+ *
+ * TODO list:
+ * change syntax from options-driven to args-driven, with args domain
+ *   or domain[/\]server, and an arbitrary number of backup Domain Controllers
+ * we don't really need the "status" management, it's more for debugging
+ *  purposes. Remove it.
+ * Maybe we can cache the created challenge, saving more time?
+ *
+ */
+
+
+#include "config.h"
+#include "ntlmauth.h"
+#include "ntlm.h"
+#include "util.h"
+
+#define BUFFER_SIZE 10240
+
+#if HAVE_STDLIB_H   
+#include <stdlib.h>   
+#endif 
+
+
+#if HAVE_GETOPT_H   
+#include <getopt.h>   
+#endif 
+
+
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+char load_balance=0, failover_enabled=0, protocol_pedantic=0;
+
+dc *controllers=NULL;
+int numcontrollers=0;
+dc *current_dc;
+
+/* housekeeping cycle and periodic operations */
+static unsigned char need_dc_resurrection=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;
+}
+
+/* makes a null-terminated string upper-case. Changes CONTENTS! */
+static void uc (char *string) {
+	char *p=string, c;
+	while ((c=*p)) {
+		*p=toupper(c);
+		p++;
+	}
+}
+
+/* makes a null-terminated string lower-case. Changes CONTENTS! */
+static void lc (char *string) {
+	char *p=string, c;
+	while ((c=*p)) {
+		*p=tolower(c);
+		p++;
+	}
+}
+
+/*
+ * options:
+ * -b try load-balancing the domain-controllers
+ * -f fail-over to another DC if DC connection fails.
+ * domain\controller ...
+ */
+void process_options (int argc, char *argv[]) {
+	int opt,j,had_error=0;
+	dc *new_dc=NULL, *last_dc=NULL;
+	while (-1!=(opt=getopt(argc,argv,"bf"))) {
+		switch(opt) {
+		case 'b':
+			load_balance=1;
+			break;
+		case 'f':
+			failover_enabled=1;
+			break;
+		default:
+			fprintf(stderr,"unknown option: -%c. Exiting\n",opt);
+			had_error=1;
+		}
+	}
+	if (had_error)
+		exit(1);
+	/* Okay, now begin filling controllers up */
+	/* we can avoid memcpy-ing, and just reuse argv[] */
+	for (j=optind;j<argc;j++) {
+		char *d, *c;
+		d=argv[j];
+		if (NULL==(c=strchr(d,'\\')) && NULL==(c=strchr(d,'/'))) {
+			fprintf(stderr,"Couldn't grok domain-controller %s\n",d);
+			continue;
+		}
+		*c++='\0';
+		new_dc=(dc *)malloc(sizeof(dc));
+		if (!new_dc) {
+			fprintf(stderr,"Malloc error while parsing DC options\n");
+			continue;
+		}
+		/* capitalize */
+		uc(c);
+		uc(d);
+		numcontrollers++;
+		new_dc->domain=d;
+		new_dc->controller=c;
+		new_dc->status=DC_OK;
+		if (controllers==NULL) {		/* first controller */
+			controllers=new_dc;
+			last_dc=new_dc;
+		} else {
+			last_dc->next=new_dc;			/* can't be null */
+			last_dc=new_dc;
+		}
+	}
+	if (numcontrollers==0) {
+		fprintf(stderr,"You must specify at least one domain-controller!\n");
+		exit(1);
+	}
+	last_dc->next=controllers;		/* close the queue, now it's circular */
+}
+
+/* tries connecting to the domain controllers in the "controllers" ring,
+ * with failover if the adequate option is specified.
+ */
+char *obtain_challenge() {
+	int j=0;
+	char *ch;
+	for (j=0;j<numcontrollers;j++) {
+		if (current_dc->status == DC_OK) {
+			ch=make_challenge(current_dc->domain,current_dc->controller);
+			if (ch)
+				return ch; /* All went OK, returning */
+			/* Huston, we've got a problem. Take this DC out of the loop */
+			current_dc->status=DC_DEAD;
+			need_dc_resurrection=1;
+		}
+		if (failover_enabled==0) /* No failover. Just return */
+			return NULL;
+		/* Try with the next */
+		current_dc=current_dc->next;
+	}
+	return NULL;
+}
+
+void manage_request () {
+	ntlmhdr *fast_header;
+	char buf[10240];
+	char *ch, *decoded, *cred;
+	int plen;
+
+	if(fgets(buf, BUFFER_SIZE, stdin) == NULL) exit(0); /* BIIG buffer */
+	ch=memchr(buf,'\n', BUFFER_SIZE); /* safer against overrun than strchr */
+	if (ch)
+		*ch='\0';									/* terminate the string at newline. */
+	debug("ntlm authenticator. Got '%s' from Squid\n",buf);
+
+	if (memcmp(buf,"KK ",3)==0) {	/* authenticate-request */
+		/* figure out what we got */
+		decoded=base64_decode(buf+3);
+		/* Note: we don't need to manage memory at this point, since
+		 *  base64_decode returns a pointer to static storage.
+		 */
+		
+		if (!decoded) {							/* decoding failure, return error */
+			SEND("NA Packet format error, couldn't base64-decode");
+			return;
+		}
+
+		/* fast-track-decode request type. */
+		fast_header=(struct _ntlmhdr *)decoded;
+	
+		/* sanity-check: it IS a NTLMSSP packet, isn't it? */
+		if (memcmp(fast_header->signature,"NTLMSSP",8) != 0) {
+			SEND("NA Broken authentication packet");
+			return;
+		}
+
+		switch (fast_header->type) {
+		case NTLM_NEGOTIATE:
+			SEND("NA Invalid negotiation request received");
+			return;
+			/* notreached */
+		case NTLM_CHALLENGE:
+			SEND("NA Got a challenge. We refuse to have our authority disputed");
+			return;
+			/* notreached */
+		case NTLM_AUTHENTICATE:
+			/* check against the DC */
+			plen=strlen(buf)*3/4; /* we only need it here. Optimization */
+			cred=ntlm_check_auth((ntlm_authenticate *)decoded, plen);
+			if (cred==NULL) {
+				switch (ntlm_errno) {
+				case NTLM_LOGON_ERROR:
+					SEND("NA authentication failure");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				case NTLM_SERVER_ERROR:
+					SEND("BH Domain Controller Error");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				case NTLM_PROTOCOL_ERROR:
+					SEND("BH Domain Controller communication error");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				case NTLM_NOT_CONNECTED:
+					SEND("BH Domain Controller (or network) died on us");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				case NTLM_BAD_PROTOCOL:
+					SEND("BH Domain controller failure");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				default:
+					SEND("BH Unhandled error while talking to Domain Controller");
+					dc_disconnect();
+					current_dc=current_dc->next;
+					return;
+				}
+			}
+			lc(cred); /* let's lowercase them for our convenience */
+			SEND2("AF %s",cred);
+			return;
+		default:
+			SEND("BH unknown authentication packet type");
+			return;
+		}
+
+		
+		return;
+	}
+
+	if (memcmp(buf,"YR",2)==0) {	/* refresh-request */
+		dc_disconnect();
+		ch=obtain_challenge();
+		while (ch==NULL) {
+			sleep(30);
+			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");
+	return;
+	/********* END ********/
+
+	
+}
+
+int main(int argc, char *argv[]) {
+
+	debug("starting up...\n");
+	
+	process_options(argc,argv);
+
+	debug("options processed OK\n");
+
+	/* initialize FDescs */
+	setbuf(stdout,NULL);
+	setbuf(stderr,NULL);
+
+	/* select the first domain controller we're going to use */
+	current_dc=controllers;
+	if (load_balance!=0 && numcontrollers > 1) {
+		int n;
+		pid_t pid=getpid();
+		n=pid%numcontrollers;
+		debug("load balancing. Selected controller #%d\n",n);
+		while (n > 0) {
+			current_dc=current_dc->next;
+			n--;
+		}
+	}
+
+	while (1) {
+		debug("managing request\n");
+		manage_request();
+	}
+	return 0;
+}
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,52 @@
+# makefile for smblib
+# Type make system, where system is ULTRIX, DU, DECOSF1, Solaris etc
+
+prefix		= @prefix@
+exec_prefix	= @exec_prefix@
+exec_suffix	= @exec_suffix@
+top_srcdir	= @top_srcdir@
+bindir		= @bindir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+CC              = @CC@
+MAKEDEPEND      = @MAKEDEPEND@
+INSTALL         = @INSTALL@
+INSTALL_BIN     = @INSTALL_PROGRAM@
+INSTALL_FILE    = @INSTALL_DATA@
+RANLIB          = @RANLIB@
+AC_CFLAGS       = @CFLAGS@
+LDFLAGS         = @LDFLAGS@
+XTRA_LIBS       = @XTRA_LIBS@
+RM              = @RM@
+AR_R		= @AR_R@
+
+CFLAGS		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+# CFLAGS = -fpic -g
+
+INCLUDE  = -I. -I../../../include -I$(top_srcdir)/include
+INCLUDES = smblib.h smblib-priv.h
+
+#RFCNB = session.o rfcnb-util.o rfcnb-io.o
+
+#OBJS = smblib.o smblib-util.o file.o smb-errors.o exper.o smblib-api.o smbencrypt.o smbdes.o md4.o
+
+VALIDATE = valid.o session.o rfcnb-util.o \
+           rfcnb-io.o smblib-util.o smblib.o smbencrypt.o smbdes.o md4.o
+
+#.SUFFIXES: .c .o .h
+
+dummy: all
+
+smbvalid.a:	$(VALIDATE) 
+	$(RM) -f $@
+	$(AR_R) $@ $(VALIDATE)
+	$(RANLIB) $@
+
+all: smbvalid.a
+
+#.c.o:	$(INCLUDES)
+
+clean:
+	$(RM) -f *.o smbvalid.a *~
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/byteorder.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,80 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   SMB Byte handling
+   Copyright (C) Andrew Tridgell 1992-1995
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   This file implements macros for machine independent short and 
+   int manipulation
+*/
+
+#undef CAREFUL_ALIGNMENT
+
+/* we know that the 386 can handle misalignment and has the "right" 
+   byteorder */
+#ifdef __i386__
+#define CAREFUL_ALIGNMENT 0
+#endif
+
+#ifndef CAREFUL_ALIGNMENT
+#define CAREFUL_ALIGNMENT 1
+#endif
+
+#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
+#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
+
+
+#if CAREFUL_ALIGNMENT
+#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
+#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
+#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
+#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
+#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
+#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
+#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
+#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
+#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
+#else
+/* this handles things for architectures like the 386 that can handle
+   alignment errors */
+/*
+   WARNING: This section is dependent on the length of int16 and int32
+   being correct 
+*/
+#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
+#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
+#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
+#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
+#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
+#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
+#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
+#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
+#endif
+
+
+/* now the reverse routines - these are used in nmb packets (mostly) */
+#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
+#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+
+#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
+#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
+#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
+#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/md4.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,172 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   a implementation of MD4 designed for use in the SMB authentication protocol
+   Copyright (C) Andrew Tridgell 1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/* NOTE: This code makes no attempt to be fast! 
+
+   It assumes that a int is at least 32 bits long
+*/
+#include <string.h>
+
+typedef unsigned int uint32;
+
+static uint32 A, B, C, D;
+
+static uint32 F(uint32 X, uint32 Y, uint32 Z)
+{
+	return (X&Y) | ((~X)&Z);
+}
+
+static uint32 G(uint32 X, uint32 Y, uint32 Z)
+{
+	return (X&Y) | (X&Z) | (Y&Z); 
+}
+
+static uint32 H(uint32 X, uint32 Y, uint32 Z)
+{
+	return X^Y^Z;
+}
+
+static uint32 lshift(uint32 x, int s)
+{
+	x &= 0xFFFFFFFF;
+	return ((x<<s)&0xFFFFFFFF) | (x>>(32-s));
+}
+
+#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
+#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + (uint32)0x5A827999,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + (uint32)0x6ED9EBA1,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32 *M)
+{
+	int j;
+	uint32 AA, BB, CC, DD;
+	uint32 X[16];
+
+	for (j=0;j<16;j++)
+		X[j] = M[j];
+
+	AA = A; BB = B; CC = C; DD = D;
+
+        ROUND1(A,B,C,D,  0,  3);  ROUND1(D,A,B,C,  1,  7);  
+	ROUND1(C,D,A,B,  2, 11);  ROUND1(B,C,D,A,  3, 19);
+        ROUND1(A,B,C,D,  4,  3);  ROUND1(D,A,B,C,  5,  7);  
+	ROUND1(C,D,A,B,  6, 11);  ROUND1(B,C,D,A,  7, 19);
+        ROUND1(A,B,C,D,  8,  3);  ROUND1(D,A,B,C,  9,  7);  
+	ROUND1(C,D,A,B, 10, 11);  ROUND1(B,C,D,A, 11, 19);
+        ROUND1(A,B,C,D, 12,  3);  ROUND1(D,A,B,C, 13,  7);  
+	ROUND1(C,D,A,B, 14, 11);  ROUND1(B,C,D,A, 15, 19);	
+
+        ROUND2(A,B,C,D,  0,  3);  ROUND2(D,A,B,C,  4,  5);  
+	ROUND2(C,D,A,B,  8,  9);  ROUND2(B,C,D,A, 12, 13);
+        ROUND2(A,B,C,D,  1,  3);  ROUND2(D,A,B,C,  5,  5);  
+	ROUND2(C,D,A,B,  9,  9);  ROUND2(B,C,D,A, 13, 13);
+        ROUND2(A,B,C,D,  2,  3);  ROUND2(D,A,B,C,  6,  5);  
+	ROUND2(C,D,A,B, 10,  9);  ROUND2(B,C,D,A, 14, 13);
+        ROUND2(A,B,C,D,  3,  3);  ROUND2(D,A,B,C,  7,  5);  
+	ROUND2(C,D,A,B, 11,  9);  ROUND2(B,C,D,A, 15, 13);
+
+	ROUND3(A,B,C,D,  0,  3);  ROUND3(D,A,B,C,  8,  9);  
+	ROUND3(C,D,A,B,  4, 11);  ROUND3(B,C,D,A, 12, 15);
+        ROUND3(A,B,C,D,  2,  3);  ROUND3(D,A,B,C, 10,  9);  
+	ROUND3(C,D,A,B,  6, 11);  ROUND3(B,C,D,A, 14, 15);
+        ROUND3(A,B,C,D,  1,  3);  ROUND3(D,A,B,C,  9,  9);  
+	ROUND3(C,D,A,B,  5, 11);  ROUND3(B,C,D,A, 13, 15);
+        ROUND3(A,B,C,D,  3,  3);  ROUND3(D,A,B,C, 11,  9);  
+	ROUND3(C,D,A,B,  7, 11);  ROUND3(B,C,D,A, 15, 15);
+
+	A += AA; B += BB; C += CC; D += DD;
+	
+	A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
+	C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
+
+	for (j=0;j<16;j++)
+		X[j] = 0;
+}
+
+static void copy64(uint32 *M, unsigned char *in)
+{
+	int i;
+
+	for (i=0;i<16;i++)
+		M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+			(in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out,uint32 x)
+{
+	out[0] = x&0xFF;
+	out[1] = (x>>8)&0xFF;
+	out[2] = (x>>16)&0xFF;
+	out[3] = (x>>24)&0xFF;
+}
+
+/* produce a md4 message digest from data of length n bytes */
+void mdfour(unsigned char *out, unsigned char *in, int n)
+{
+	unsigned char buf[128];
+	uint32 M[16];
+	uint32 b = n * 8;
+	int i;
+
+	A = 0x67452301;
+	B = 0xefcdab89;
+	C = 0x98badcfe;
+	D = 0x10325476;
+
+	while (n > 64) {
+		copy64(M, in);
+		mdfour64(M);
+		in += 64;
+		n -= 64;
+	}
+
+	for (i=0;i<128;i++)
+		buf[i] = 0;
+	memcpy(buf, in, n);
+	buf[n] = 0x80;
+	
+	if (n <= 55) {
+		copy4(buf+56, b);
+		copy64(M, buf);
+		mdfour64(M);
+	} else {
+		copy4(buf+120, b); 
+		copy64(M, buf);
+		mdfour64(M);
+		copy64(M, buf+64);
+		mdfour64(M);
+	}
+
+	for (i=0;i<128;i++)
+		buf[i] = 0;
+	copy64(M, buf);
+
+	copy4(out, A);
+	copy4(out+4, B);
+	copy4(out+8, C);
+	copy4(out+12, D);
+
+	A = B = C = D = 0;
+}
+
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/md4.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1 @@
+void mdfour(unsigned char *out, unsigned char *in, int n);
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-common.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,36 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Common Structures etc Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* A data structure we need */
+
+typedef struct RFCNB_Pkt {
+
+  char * data;			/* The data in this portion */
+  int len;
+  struct RFCNB_Pkt *next;
+
+} RFCNB_Pkt;
+
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-error.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,76 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Error Response Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Error responses */
+
+#define RFCNBE_Bad -1          /* Bad response */
+#define RFCNBE_OK 0
+
+/* these should follow the spec ... is there one ?*/
+
+#define RFCNBE_NoSpace 1       /* Could not allocate space for a struct */
+#define RFCNBE_BadName 2       /* Could not translate a name            */
+#define RFCNBE_BadRead 3       /* Read sys call failed                  */
+#define RFCNBE_BadWrite 4      /* Write Sys call failed                 */
+#define RFCNBE_ProtErr 5       /* Protocol Error                        */
+#define RFCNBE_ConGone 6       /* Connection dropped                    */
+#define RFCNBE_BadHandle 7     /* Handle passed was bad                 */
+#define RFCNBE_BadSocket 8     /* Problems creating socket              */
+#define RFCNBE_ConnectFailed 9 /* Connect failed                        */
+#define RFCNBE_CallRejNLOCN 10 /* Call rejected, not listening on CN    */
+#define RFCNBE_CallRejNLFCN 11 /* Call rejected, not listening for CN   */
+#define RFCNBE_CallRejCNNP  12 /* Call rejected, called name not present */
+#define RFCNBE_CallRejInfRes 13/* Call rejetced, name ok, no resources   */
+#define RFCNBE_CallRejUnSpec 14/* Call rejected, unspecified error      */
+#define RFCNBE_BadParam      15/* Bad parameters passed ...             */
+#define RFCNBE_Timeout       16/* IO Timed out                          */
+
+/* Text strings for the error responses                                 */
+extern char *RFCNB_Error_Strings[];
+/*
+static char *RFCNB_Error_Strings[] = {
+
+  "RFCNBE_OK: Routine completed successfully.",
+  "RFCNBE_NoSpace: No space available for a malloc call.",
+  "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+  "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+  "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+  "RFCNBE_ProtErr: A protocol error has occurred.",
+  "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+  "RFCNBE_BadHandle: Bad connection handle passed.",
+  "RFCNBE_BadSocket: Problems creating socket.",
+  "RFCNBE_ConnectFailed: Connection failed. See errno.",
+  "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+  "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+  "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+  "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+  "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+  "RFCNBE_BadParam: Bad parameters passed to a routine.",
+  "RFCNBE_Timeout: IO Operation timed out ..."
+
+};
+*/
+
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-io.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,408 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
+
+   Version 1.0
+   RFCNB IO Routines ...
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/* #include <features.h> */
+#include "config.h"
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <sys/uio.h>
+#include <sys/signal.h>
+#include <string.h>
+
+int RFCNB_Timeout = 0;    /* Timeout in seconds ... */
+
+void rfcnb_alarm(int sig)
+
+{
+
+  fprintf(stderr, "IO Timed out ...\n");
+
+}
+
+/* Set timeout value and setup signal handling */
+
+int RFCNB_Set_Timeout(int seconds)
+
+{
+  /* If we are on a Bezerkeley system, use sigvec, else sigaction */
+#if HAVE_SIGACTION
+  struct sigaction inact, outact;
+#else
+  struct sigvec invec, outvec;
+#endif
+
+  RFCNB_Timeout = seconds;
+
+  if (RFCNB_Timeout > 0) { /* Set up handler to ignore but not restart */
+
+#if HAVE_SIGACTION
+    inact.sa_handler = (void (*)())rfcnb_alarm;
+    sigemptyset(&inact.sa_mask);
+    inact.sa_flags = 0;    /* Don't restart */
+
+    if (sigaction(SIGALRM, &inact, &outact) < 0)
+      return(-1);
+#else
+    invec.sv_handler = (void (*)())rfcnb_alarm;
+    invec.sv_mask = 0;
+    invec.sv_flags = SV_INTERRUPT;
+
+    if (sigvec(SIGALRM, &invec, &outvec)  < 0)
+      return(-1);
+#endif
+
+  }
+
+  return(0);
+
+}
+
+/* Discard the rest of an incoming packet as we do not have space for it
+   in the buffer we allocated or were passed ...                         */
+
+int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
+
+{ char temp[100];   /* Read into here */
+  int rest, this_read, bytes_read;
+
+  /* len is the amount we should read */
+
+#ifdef RFCNB_DEBUG
+  fprintf(stderr, "Discard_Rest called to discard: %i\n", len);
+#endif
+
+  rest = len;
+
+  while (rest > 0) {
+
+    this_read = (rest > sizeof(temp)?sizeof(temp):rest);
+
+    bytes_read = read(con -> fd, temp, this_read);
+
+    if (bytes_read <= 0) { /* Error so return */
+
+      if (bytes_read < 0) 
+	RFCNB_errno = RFCNBE_BadRead;
+      else
+	RFCNB_errno = RFCNBE_ConGone;
+
+      RFCNB_saved_errno = errno;
+      return(RFCNBE_Bad);
+
+    }
+    
+    rest = rest - bytes_read;
+
+  }
+
+  return(0);
+
+}
+
+
+/* Send an RFCNB packet to the connection.
+
+   We just send each of the blocks linked together ... 
+
+   If we can, try to send it as one iovec ... 
+
+*/
+
+int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+
+{ int len_sent, tot_sent, this_len;
+  struct RFCNB_Pkt *pkt_ptr;
+  char *this_data;
+  int i;
+  struct iovec io_list[10];          /* We should never have more      */
+                                     /* If we do, this will blow up ...*/
+
+  /* Try to send the data ... We only send as many bytes as len claims */
+  /* We should try to stuff it into an IOVEC and send as one write     */
+
+
+  pkt_ptr = pkt;
+  len_sent =  tot_sent = 0;             /* Nothing sent so far */
+  i = 0;
+
+  while ((pkt_ptr != NULL) & (i < 10)) {  /* Watch that magic number! */
+
+    this_len = pkt_ptr -> len;
+    this_data = pkt_ptr -> data;
+    if ((tot_sent + this_len) > len) 
+      this_len = len - tot_sent;        /* Adjust so we don't send too much */
+
+    /* Now plug into the iovec ... */
+
+    io_list[i].iov_len = this_len;
+    io_list[i].iov_base = this_data;
+    i++;
+
+    tot_sent += this_len;
+
+    if (tot_sent == len) break;   /* Let's not send too much */
+
+    pkt_ptr = pkt_ptr -> next;
+
+  }
+
+#ifdef RFCNB_DEBUG
+  fprintf(stderr, "Frags = %i, tot_sent = %i\n", i, tot_sent);
+#endif
+
+  /* Set up an alarm if timeouts are set ... */
+
+  if (RFCNB_Timeout > 0) 
+    alarm(RFCNB_Timeout);
+
+  if ((len_sent = writev(con -> fd, io_list, i)) < 0) { /* An error */
+
+    con -> rfc_errno = errno;
+    if (errno == EINTR)  /* We were interrupted ... */
+      RFCNB_errno = RFCNBE_Timeout;
+    else
+      RFCNB_errno = RFCNBE_BadWrite;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+
+  }
+
+  if (len_sent < tot_sent) { /* Less than we wanted */
+    if (errno == EINTR)      /* We were interrupted */
+      RFCNB_errno = RFCNBE_Timeout;
+    else
+      RFCNB_errno = RFCNBE_BadWrite;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+  }
+
+  if (RFCNB_Timeout > 0)
+    alarm(0);                /* Reset that sucker */
+
+#ifdef RFCNB_DEBUG
+
+  fprintf(stderr, "Len sent = %i ...\n", len_sent);
+  RFCNB_Print_Pkt(stderr, "sent", pkt, len_sent); /* Print what send ... */
+
+#endif
+
+  return(len_sent);
+
+}
+
+/* Read an RFCNB packet off the connection. 
+
+   We read the first 4 bytes, that tells us the length, then read the
+   rest. We should implement a timeout, but we don't just yet 
+
+*/
+
+
+int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
+
+{ int read_len, pkt_len;
+  char hdr[RFCNB_Pkt_Hdr_Len];      /* Local space for the header */
+  struct RFCNB_Pkt *pkt_frag;
+  int more, this_time, offset, frag_len, this_len;
+  BOOL seen_keep_alive = TRUE;
+
+  /* Read that header straight into the buffer */
+
+  if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Trying to read less than a packet:");
+    perror("");
+#endif
+    RFCNB_errno = RFCNBE_BadParam;
+    return(RFCNBE_Bad);
+
+  }
+
+  /* We discard keep alives here ... */
+
+  if (RFCNB_Timeout > 0) 
+    alarm(RFCNB_Timeout);
+
+  while (seen_keep_alive) {
+
+    if ((read_len = read(con -> fd, hdr, sizeof(hdr))) < 0) { /* Problems */
+#ifdef RFCNB_DEBUG
+      fprintf(stderr, "Reading the packet, we got:");
+      perror("");
+#endif
+      if (errno == EINTR)
+	RFCNB_errno = RFCNBE_Timeout;
+      else
+	RFCNB_errno = RFCNBE_BadRead;
+      RFCNB_saved_errno = errno;
+      return(RFCNBE_Bad);
+
+    }
+
+    /* Now we check out what we got */
+
+    if (read_len == 0) { /* Connection closed, send back eof?  */
+
+#ifdef RFCNB_DEBUG
+      fprintf(stderr, "Connection closed reading\n");
+#endif 
+
+      if (errno == EINTR) 
+	RFCNB_errno = RFCNBE_Timeout;
+      else
+	RFCNB_errno = RFCNBE_ConGone;
+      RFCNB_saved_errno = errno;
+      return(RFCNBE_Bad);
+
+    }
+
+    if (RFCNB_Pkt_Type(hdr) == RFCNB_SESSION_KEEP_ALIVE) {
+
+#ifdef RFCNB_DEBUG
+      fprintf(stderr, "RFCNB KEEP ALIVE received\n");
+#endif
+      
+    }
+    else {
+      seen_keep_alive = FALSE;
+    }
+
+  }
+ 
+  /* What if we got less than or equal to a hdr size in bytes? */
+
+  if (read_len < sizeof(hdr)) { /* We got a small packet */
+
+    /* Now we need to copy the hdr portion we got into the supplied packet */
+
+    memcpy(pkt -> data, hdr, read_len);  /*Copy data */
+
+#ifdef RFCNB_DEBUG
+    RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len);
+#endif
+
+    return(read_len);
+
+  }
+
+  /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
+
+  pkt_len = RFCNB_Pkt_Len(hdr);
+
+#ifdef RFCNB_DEBUG
+  fprintf(stderr, "Reading Pkt: Length = %i\n", pkt_len);
+#endif  
+
+  /* Now copy in the hdr */
+
+  memcpy(pkt -> data, hdr, sizeof(hdr));
+
+  /* Get the rest of the packet ... first figure out how big our buf is? */
+  /* And make sure that we handle the fragments properly ... Sure should */
+  /* use an iovec ...                                                    */
+
+  if (len < pkt_len)            /* Only get as much as we have space for */
+    more = len - RFCNB_Pkt_Hdr_Len;
+  else
+    more = pkt_len;
+
+  this_time = 0;
+
+  /* We read for each fragment ... */
+
+  if (pkt -> len == read_len){     /* If this frag was exact size */
+    pkt_frag = pkt -> next;        /* Stick next lot in next frag */
+    offset = 0;                    /* then we start at 0 in next  */
+  }
+  else {
+    pkt_frag = pkt;                /* Otherwise use rest of this frag */
+    offset = RFCNB_Pkt_Hdr_Len;    /* Otherwise skip the header       */
+  }
+
+  frag_len = pkt_frag -> len;
+
+  if (more <= frag_len)     /* If len left to get less than frag space */
+    this_len = more;        /* Get the rest ...                        */
+  else
+    this_len = frag_len - offset;
+
+  while (more > 0) {
+
+    if ((this_time = read(con -> fd, (pkt_frag -> data) + offset, this_len)) <= 0) { /* Problems */
+
+      if (errno == EINTR) {
+
+	RFCNB_errno = RFCNB_Timeout;
+
+      }
+      else {
+	if (this_time < 0)
+	  RFCNB_errno = RFCNBE_BadRead;
+	else
+	  RFCNB_errno = RFCNBE_ConGone;
+      }
+
+      RFCNB_saved_errno = errno;
+      return(RFCNBE_Bad);
+
+    }
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Frag_Len = %i, this_time = %i, this_len = %i, more = %i\n", frag_len,
+                    this_time, this_len, more);
+#endif
+
+    read_len = read_len + this_time;  /* How much have we read ... */
+
+    /* Now set up the next part */
+
+    if (pkt_frag -> next == NULL) break;       /* That's it here */
+
+    pkt_frag = pkt_frag -> next;
+    this_len = pkt_frag -> len;
+    offset = 0;
+
+    more = more - this_time;
+
+  }
+
+#ifdef RFCNB_DEBUG
+  fprintf(stderr,"Pkt Len = %i, read_len = %i\n", pkt_len, read_len);
+  RFCNB_Print_Pkt(stderr, "rcvd", pkt, read_len + sizeof(hdr));
+#endif
+
+  if (read_len < (pkt_len + sizeof(hdr))) {  /* Discard the rest */
+
+    return(RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
+
+  }
+
+  if (RFCNB_Timeout > 0)
+    alarm(0);                /* Reset that sucker */
+
+  return(read_len + sizeof(RFCNB_Hdr));
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-io.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,30 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB IO Routines Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-priv.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,156 @@
+#ifndef __RFCNB_H__
+#define __RFCNB_H__
+
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Defines we need */
+
+typedef unsigned short uint16;
+
+#define GLOBAL extern
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "byteorder.h"
+
+#ifdef RFCNB_PORT
+#define RFCNB_Default_Port RFCNB_PORT
+#else
+#define RFCNB_Default_Port 139
+#endif
+
+#define RFCNB_MAX_STATS 1
+
+/* Protocol defines we need */
+
+#define RFCNB_SESSION_MESSAGE 0
+#define RFCNB_SESSION_REQUEST 0x81
+#define RFCNB_SESSION_ACK 0x82
+#define RFCNB_SESSION_REJ 0x83
+#define RFCNB_SESSION_RETARGET 0x84
+#define RFCNB_SESSION_KEEP_ALIVE 0x85
+
+/* Structures      */
+
+typedef struct redirect_addr * redirect_ptr;
+
+struct redirect_addr {
+
+  struct in_addr ip_addr;
+  int port;
+  redirect_ptr next;
+
+};
+
+typedef struct RFCNB_Con {
+
+  int fd;                     /* File descripter for TCP/IP connection */
+  int rfc_errno;                  /* last error                            */
+  int timeout;		      /* How many milli-secs before IO times out */
+  int redirects;	      /* How many times we were redirected     */
+  struct redirect_addr *redirect_list;  /* First is first address */
+  struct redirect_addr *last_addr;
+
+} RFCNB_Con;
+
+typedef char RFCNB_Hdr[4]; /* The header is 4 bytes long with  */
+                                    /* char[0] as the type, char[1] the */
+			            /* flags, and char[2..3] the length */
+
+/* Macros to extract things from the header. These are for portability
+   between architecture types where we are worried about byte order     */
+
+#define RFCNB_Pkt_Hdr_Len        4
+#define RFCNB_Pkt_Sess_Len       72
+#define RFCNB_Pkt_Retarg_Len     10
+#define RFCNB_Pkt_Nack_Len       5
+#define RFCNB_Pkt_Type_Offset    0
+#define RFCNB_Pkt_Flags_Offset   1
+#define RFCNB_Pkt_Len_Offset     2   /* Length is 2 bytes plus a flag bit */
+#define RFCNB_Pkt_N1Len_Offset   4
+#define RFCNB_Pkt_Called_Offset  5
+#define RFCNB_Pkt_N2Len_Offset   38
+#define RFCNB_Pkt_Calling_Offset 39
+#define RFCNB_Pkt_Error_Offset   4
+#define RFCNB_Pkt_IP_Offset      4
+#define RFCNB_Pkt_Port_Offset    8
+
+/* The next macro isolates the length of a packet, including the bit in the
+   flags                                                                   */
+
+#define RFCNB_Pkt_Len(p)  (PVAL(p, 3) | (PVAL(p, 2) << 8) |     \
+                          ((PVAL(p, RFCNB_Pkt_Flags_Offset) & 0x01) << 16))
+
+#define RFCNB_Put_Pkt_Len(p, v) (p[1] = (((v) >> 16) & 1)); \
+				(p[2] = (((v) >> 8) & 0xFF)); \
+				(p[3] = ((v) & 0xFF));
+
+#define RFCNB_Pkt_Type(p) (CVAL(p, RFCNB_Pkt_Type_Offset))
+
+/*typedef struct RFCNB_Hdr {
+
+  unsigned char type;
+  unsigned char flags;
+  int16 len;
+
+  } RFCNB_Hdr;
+
+typedef struct RFCNB_Sess_Pkt {
+    unsigned char type;
+    unsigned char flags;
+    int16 length;
+    unsigned char n1_len;
+    char called_name[33];
+    unsigned char n2_len;
+    char calling_name[33];
+  } RFCNB_Sess_Pkt;
+
+
+typedef struct RFCNB_Nack_Pkt {
+
+  struct RFCNB_Hdr hdr;
+  unsigned char error;
+ 
+  } RFCNB_Nack_Pkt;
+
+typedef struct RFCNB_Retarget_Pkt {
+
+  struct RFCNB_Hdr hdr;
+  int dest_ip;
+  unsigned char port;
+
+  } RFCNB_Redir_Pkt; */
+
+/* Static variables */
+
+/* Only declare this if not defined */
+
+#ifndef RFCNB_ERRNO
+extern int RFCNB_errno;
+extern int RFCNB_saved_errno;    /* Save this from point of error */
+#endif
+
+#endif /* __RFCNB_H__ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-util.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,537 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Utility Routines ...
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <string.h>
+#include <malloc.h>
+
+#include "std-includes.h"
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+#include <arpa/inet.h>
+
+
+extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
+
+/* Convert name and pad to 16 chars as needed */
+/* Name 1 is a C string with null termination, name 2 may not be */
+/* If SysName is true, then put a <00> on end, else space>       */
+
+void RFCNB_CvtPad_Name(char *name1, char *name2)
+
+{ char c, c1, c2;
+  int i, len;
+
+  len = strlen(name1);
+
+  for (i = 0; i < 16; i++) {
+
+    if (i >= len) {
+
+     c1 = 'C'; c2 = 'A'; /* CA is a space */
+ 
+    } else {
+
+      c = name1[i];
+      c1 = (char)((int)c/16 + (int)'A');
+      c2 = (char)((int)c%16 + (int)'A');
+    }
+
+    name2[i*2] = c1;
+    name2[i*2+1] = c2;
+
+  }
+
+  name2[32] = 0;   /* Put in the nll ...*/
+
+}
+
+/* Converts an Ascii NB Name (16 chars) to an RFCNB Name (32 chars)
+   Uses the encoding in RFC1001. Each nibble of byte is added to 'A'
+   to produce the next byte in the name.
+
+   This routine assumes that AName is 16 bytes long and that NBName has 
+   space for 32 chars, so be careful ... 
+
+*/
+
+void RFCNB_AName_To_NBName(char *AName, char *NBName)
+
+{ char c, c1, c2;
+  int i;
+
+  for (i=0; i < 16; i++) {
+
+    c = AName[i];
+
+    c1 = (char)((c >> 4) + 'A');
+    c2 = (char)((c & 0xF) + 'A');
+
+    NBName[i*2] = c1;
+    NBName[i*2+1] = c2;
+  }
+
+  NBName[32] = 0; /* Put in a null */
+
+}
+
+/* Do the reverse of the above ... */
+
+void RFCNB_NBName_To_AName(char *NBName, char *AName)
+
+{ char c, c1, c2;
+  int i;
+
+  for (i=0; i < 16; i++) {
+
+    c1 = NBName[i*2];
+    c2 = NBName[i*2+1];
+
+    c = (char)(((int)c1 - (int)'A') * 16 + ((int)c2 - (int)'A'));
+
+    AName[i] = c;
+
+  }
+
+  AName[i] = 0;   /* Put a null on the end ... */
+
+}
+
+/* Print a string of bytes in HEX etc */
+
+void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len)
+
+{ char c1, c2, outbuf1[33];
+  unsigned char c;
+  int i, j;
+  struct RFCNB_Pkt *pkt_ptr = pkt;
+  static char Hex_List[17] = "0123456789ABCDEF";
+
+  j = 0;
+
+  /* We only want to print as much as sepcified in Len */
+
+  while (pkt_ptr != NULL) {
+
+    for (i = 0; 
+	 i < ((Len > (pkt_ptr -> len)?pkt_ptr -> len:Len) - Offset); 
+	 i++) {
+
+      c = pkt_ptr -> data[i + Offset];
+      c1 = Hex_List[c >> 4];
+      c2 = Hex_List[c & 0xF];
+
+      outbuf1[j++] = c1; outbuf1[j++] = c2;
+
+      if (j == 32){ /* Print and reset */
+	outbuf1[j] = 0;
+	fprintf(fd, "    %s\n", outbuf1);
+	j = 0;
+      }
+
+    }
+
+    Offset = 0;
+    Len = Len - pkt_ptr -> len;   /* Reduce amount by this much */
+    pkt_ptr = pkt_ptr -> next;
+
+  }
+
+  /* Print last lot in the buffer ... */
+
+  if (j > 0) {
+
+    outbuf1[j] = 0;
+    fprintf(fd, "    %s\n", outbuf1);
+
+  }
+
+  fprintf(fd, "\n");
+
+}
+
+/* Get a packet of size n */
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
+
+{ RFCNB_Pkt *pkt;
+
+  if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
+
+    RFCNB_errno = RFCNBE_NoSpace;
+    RFCNB_saved_errno = errno;
+    return(NULL);
+
+  }
+
+  pkt -> next = NULL;
+  pkt -> len = n;
+
+  if (n == 0) return(pkt);
+
+  if ((pkt -> data = (char *)malloc(n)) == NULL) {
+
+    RFCNB_errno = RFCNBE_NoSpace;
+    RFCNB_saved_errno = errno;
+    free(pkt);
+    return(NULL);
+
+  }
+
+  return(pkt);
+
+}
+
+/* Free up a packet */
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
+
+{ struct RFCNB_Pkt *pkt_next; char *data_ptr;
+
+  while (pkt != NULL) {
+
+    pkt_next = pkt -> next;
+
+    data_ptr = pkt -> data;
+
+    if (data_ptr != NULL)
+      free(data_ptr);
+
+    free(pkt);
+
+    pkt = pkt_next;
+
+  }
+   
+}
+
+/* Print an RFCNB packet */
+
+void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len)
+
+{ char lname[17];
+
+  /* We assume that the first fragment is the RFCNB Header  */
+  /* We should loop through the fragments printing them out */
+
+  fprintf(fd, "RFCNB Pkt %s:", dirn);
+
+  switch (RFCNB_Pkt_Type(pkt -> data)) {
+
+  case RFCNB_SESSION_MESSAGE: 
+
+    fprintf(fd, "SESSION MESSAGE: Length = %i\n", RFCNB_Pkt_Len(pkt -> data));
+    RFCNB_Print_Hex(fd, pkt, RFCNB_Pkt_Hdr_Len, 
+#ifdef RFCNB_PRINT_DATA
+		    RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
+#else
+                    40);
+#endif
+
+  if (Prot_Print_Routine != 0) { /* Print the rest of the packet */
+	
+    Prot_Print_Routine(fd, strcmp(dirn, "sent"), pkt, RFCNB_Pkt_Hdr_Len,
+		       RFCNB_Pkt_Len(pkt -> data) - RFCNB_Pkt_Hdr_Len);
+
+      }
+
+      break;
+
+ case RFCNB_SESSION_REQUEST:
+
+      fprintf(fd, "SESSION REQUEST: Length = %i\n",
+		  RFCNB_Pkt_Len(pkt -> data));
+      RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Called_Offset), lname);
+      fprintf(fd, "  Called Name: %s\n", lname);
+      RFCNB_NBName_To_AName((char *)(pkt -> data + RFCNB_Pkt_Calling_Offset), lname);
+      fprintf(fd, "  Calling Name: %s\n", lname);
+
+      break;
+
+ case RFCNB_SESSION_ACK:
+
+      fprintf(fd, "RFCNB SESSION ACK: Length = %i\n",
+		  RFCNB_Pkt_Len(pkt -> data));
+
+      break;
+
+ case RFCNB_SESSION_REJ:
+      fprintf(fd, "RFCNB SESSION REJECT: Length = %i\n", 
+		  RFCNB_Pkt_Len(pkt -> data));
+
+      if (RFCNB_Pkt_Len(pkt -> data) < 1) {
+	fprintf(fd, "   Protocol Error, short Reject packet!\n");
+      }
+      else {
+	fprintf(fd, "   Error = %x\n", CVAL(pkt -> data, RFCNB_Pkt_Error_Offset));
+      }
+
+      break;
+
+ case RFCNB_SESSION_RETARGET:
+
+      fprintf(fd, "RFCNB SESSION RETARGET: Length = %i\n",
+		  RFCNB_Pkt_Len(pkt -> data));
+
+      /* Print out the IP address etc and the port? */
+
+      break;
+
+ case RFCNB_SESSION_KEEP_ALIVE:
+
+      fprintf(fd, "RFCNB SESSION KEEP ALIVE: Length = %i\n",
+	      RFCNB_Pkt_Len(pkt -> data));
+      break;
+
+    default:
+
+      break;
+  }
+
+}
+
+/* Resolve a name into an address */
+
+int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
+
+{ int addr;         /* Assumes IP4, 32 bit network addresses */
+  struct hostent *hp;
+
+        /* Use inet_addr to try to convert the address */
+
+  if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
+
+        /* Now try a name look up with gethostbyname */
+
+    if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
+
+        /* Try NetBIOS name lookup, how the hell do we do that? */
+
+      RFCNB_errno = RFCNBE_BadName;   /* Is this right? */
+      RFCNB_saved_errno = errno;
+      return(RFCNBE_Bad);
+
+    }
+    else {  /* We got a name */
+
+       memcpy((void *)Dest_IP, (void *)hp -> h_addr_list[0], sizeof(struct in_addr));
+
+    }
+  }
+  else { /* It was an IP address */
+
+    memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
+
+  }
+
+  return 0;
+
+}
+
+/* Disconnect the TCP connection to the server */
+
+int RFCNB_Close(int socket)
+
+{
+
+  close(socket);
+
+  /* If we want to do error recovery, here is where we put it */
+
+  return 0;
+
+}
+
+/* Connect to the server specified in the IP address.
+   Not sure how to handle socket options etc.         */
+
+int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
+
+{ struct sockaddr_in Socket;
+  int fd;
+
+  /* Create a socket */
+
+  if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
+
+    RFCNB_errno = RFCNBE_BadSocket;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+    } 
+
+  bzero((char *)&Socket, sizeof(Socket));
+  memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
+
+  Socket.sin_port = htons(port);
+  Socket.sin_family = PF_INET;
+
+  /* Now connect to the destination */
+
+  if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
+
+    close(fd);
+    RFCNB_errno = RFCNBE_ConnectFailed;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+    }
+
+  return(fd);
+
+}
+
+/* handle the details of establishing the RFCNB session with remote 
+   end 
+
+*/
+
+int RFCNB_Session_Req(struct RFCNB_Con *con, 
+		      char *Called_Name, 
+		      char *Calling_Name,
+		      BOOL *redirect,
+		      struct in_addr *Dest_IP,
+		      int * port)
+
+{ char *sess_pkt;
+
+  /* Response packet should be no more than 9 bytes, make 16 jic */
+
+  char resp[16];
+  int len;
+  struct RFCNB_Pkt *pkt, res_pkt;
+
+  /* We build and send the session request, then read the response */
+
+  pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
+
+  if (pkt == NULL) {
+
+    return(RFCNBE_Bad);  /* Leave the error that RFCNB_Alloc_Pkt gives) */
+
+  }
+
+  sess_pkt = pkt -> data;    /* Get pointer to packet proper */
+
+  sess_pkt[RFCNB_Pkt_Type_Offset]  = RFCNB_SESSION_REQUEST;
+  RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
+  sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
+  sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
+
+  RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
+  RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
+
+  /* Now send the packet */
+
+#ifdef RFCNB_DEBUG
+
+  fprintf(stderr, "Sending packet: ");
+  
+#endif
+
+  if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
+
+    return(RFCNBE_Bad);       /* Should be able to write that lot ... */
+
+    }
+
+#ifdef RFCNB_DEBUG
+
+  fprintf(stderr, "Getting packet.\n");
+
+#endif
+
+  res_pkt.data = resp;
+  res_pkt.len  = sizeof(resp);
+  res_pkt.next = NULL;
+
+  if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
+
+    return(RFCNBE_Bad);
+
+  }
+
+  /* Now analyze the packet ... */
+
+  switch (RFCNB_Pkt_Type(resp)) {
+
+    case RFCNB_SESSION_REJ:         /* Didnt like us ... too bad */
+
+      /* Why did we get rejected ? */
+    
+      switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
+
+      case 0x80: 
+	RFCNB_errno = RFCNBE_CallRejNLOCN;
+	break;
+      case 0x81:
+	RFCNB_errno = RFCNBE_CallRejNLFCN;
+	break;
+      case 0x82:
+	RFCNB_errno = RFCNBE_CallRejCNNP;
+	break;
+      case 0x83:
+	RFCNB_errno = RFCNBE_CallRejInfRes;
+	break;
+      case 0x8F:
+	RFCNB_errno = RFCNBE_CallRejUnSpec;
+	break;
+      default:
+	RFCNB_errno = RFCNBE_ProtErr;
+	break;
+      }
+
+      return(RFCNBE_Bad);
+      break;
+
+    case RFCNB_SESSION_ACK:        /* Got what we wanted ...      */
+
+      return(0);
+      break;
+
+    case RFCNB_SESSION_RETARGET:   /* Go elsewhere                */
+
+      *redirect = TRUE;       /* Copy port and ip addr       */
+
+      memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
+      *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
+
+      return(0);
+      break;
+
+    default:  /* A protocol error */
+
+      RFCNB_errno = RFCNBE_ProtErr;
+      return(RFCNBE_Bad);
+      break;
+    }
+}
+
+
+
+
+
+
+
+
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb-util.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,52 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Utility Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+void RFCNB_CvtPad_Name(char *name1, char *name2);
+
+void RFCNB_AName_To_NBName(char *AName, char *NBName);
+
+void RFCNB_NBName_To_AName(char *NBName, char *AName);
+
+void RFCNB_Print_Hex(FILE *fd, struct RFCNB_Pkt *pkt, int Offset, int Len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Print_Pkt(FILE *fd, char *dirn, struct RFCNB_Pkt *pkt, int len);
+
+int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP);
+
+int RFCNB_Close(int socket);
+
+int RFCNB_IP_Connect(struct in_addr Dest_IP, int port);
+
+int RFCNB_Session_Req(struct RFCNB_Con *con, 
+		      char *Called_Name, 
+		      char *Calling_Name,
+		      BOOL *redirect,
+		      struct in_addr *Dest_IP,
+		      int * port);
+
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/rfcnb.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,55 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   RFCNB Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Error responses */
+
+#include "rfcnb-error.h"
+#include "rfcnb-common.h"
+#include "smblib-priv.h"
+
+/* Defines we need */
+
+#define RFCNB_Default_Port 139
+
+/* Definition of routines we define */
+
+void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+		 int port);
+
+int RFCNB_Send(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Recv(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
+
+int RFCNB_Hangup(void *con_Handle);
+
+void *RFCNB_Listen();
+
+void RFCNB_Get_Error(char *buffer, int buf_len);
+
+struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+
+void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
+
+int RFCNB_Set_Sock_NoDelay(void *con_Handle, BOOL yn);
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/session.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,394 @@
+/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
+
+   Version 1.0
+   Session Routines ...
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <malloc.h>
+#include <string.h>
+
+int RFCNB_errno = 0;
+int RFCNB_saved_errno = 0;
+#define RFCNB_ERRNO
+
+#include "std-includes.h"
+#include <netinet/tcp.h>
+#include "rfcnb-priv.h"
+#include "rfcnb-util.h"
+#include "rfcnb-io.h"
+
+/* global data structures */
+
+static char *RFCNB_Error_Strings[] = {
+
+  "RFCNBE_OK: Routine completed successfully.",
+  "RFCNBE_NoSpace: No space available for a malloc call.",
+  "RFCNBE_BadName: NetBIOS name could not be translated to IP address.",
+  "RFCNBE_BadRead: Read system call returned an error. Check errno.",
+  "RFCNBE_BadWrite: Write system call returned an error. Check errno.",
+  "RFCNBE_ProtErr: A protocol error has occurred.",
+  "RFCNBE_ConGone: Connection dropped during a read or write system call.",
+  "RFCNBE_BadHandle: Bad connection handle passed.",
+  "RFCNBE_BadSocket: Problems creating socket.",
+  "RFCNBE_ConnectFailed: Connection failed. See errno.",
+  "RFCNBE_CallRejNLOCN: Call rejected. Not listening on called name.",
+  "RFCNBE_CallRejNLFCN: Call rejected. Not listening for called name.",
+  "RFCNBE_CallRejCNNP: Call rejected. Called name not present.",
+  "RFCNBE_CallRejInfRes: Call rejected. Name present, but insufficient resources.",
+  "RFCNBE_CallRejUnSpec: Call rejected. Unspecified error.",
+  "RFCNBE_BadParam: Bad parameters passed to a routine.",
+  "RFCNBE_Timeout: IO Operation timed out ..."
+
+};
+
+int RFCNB_Stats[RFCNB_MAX_STATS];
+
+void (*Prot_Print_Routine)() = NULL;      /* Pointer to print routine */
+
+/* Set up a session with a remote name. We are passed Called_Name as a
+   string which we convert to a NetBIOS name, ie space terminated, up to
+   16 characters only if we need to. If Called_Address is not empty, then
+   we use it to connect to the remote end, but put in Called_Name ... Called 
+   Address can be a DNS based name, or a TCP/IP address ...
+*/
+
+void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
+		 int port)
+
+{ struct RFCNB_Con *con;
+  struct in_addr Dest_IP;
+  int Client;
+  BOOL redirect; struct redirect_addr *redir_addr;
+  char *Service_Address;
+
+  /* Now, we really should look up the port in /etc/services ... */
+
+  if (port == 0) port = RFCNB_Default_Port;
+
+  /* Create a connection structure first */
+
+  if ((con = (struct RFCNB_Con *)malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */
+
+    RFCNB_errno = RFCNBE_NoSpace;
+    RFCNB_saved_errno = errno;
+    return(NULL);
+
+    }
+ 
+  con -> fd = -0;             /* no descriptor yet */
+  con -> rfc_errno = 0;           /* no error yet */
+  con -> timeout = 0;         /* no timeout   */
+  con -> redirects = 0;
+  con -> redirect_list = NULL; /* Fix bug still in version 0.50 */
+
+  /* Resolve that name into an IP address */
+
+  Service_Address = Called_Name;
+  if (strcmp(Called_Address, "") != 0) { /* If the Called Address = "" */
+    Service_Address = Called_Address;
+  }
+
+  if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */
+
+    /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
+
+    return(NULL);
+
+    }
+
+  /* Now connect to the remote end */
+
+  redirect = TRUE;     /* Fudge this one so we go once through */
+
+  while (redirect) {   /* Connect and get session info etc */
+
+    redirect = FALSE;  /* Assume all OK */
+
+    /* Build the redirect info. First one is first addr called */
+    /* And tack it onto the list of addresses we called        */
+
+    if ((redir_addr = (struct redirect_addr *)malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */
+      
+      RFCNB_errno = RFCNBE_NoSpace;
+      RFCNB_saved_errno = errno;
+      return(NULL);
+
+    }
+
+    memcpy((char *)&(redir_addr -> ip_addr), (char *)&Dest_IP, sizeof(Dest_IP));
+    redir_addr -> port = port;
+    redir_addr -> next = NULL;
+
+    if (con -> redirect_list == NULL) { /* Stick on head */
+
+      con -> redirect_list = con -> last_addr = redir_addr;
+
+    } else {
+
+      con -> last_addr -> next = redir_addr;
+      con -> last_addr = redir_addr;
+
+    }
+
+    /* Now, make that connection */
+
+    if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */
+
+      /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
+
+      return(NULL);
+
+      }
+
+    con -> fd = Client;
+
+    /* Now send and handle the RFCNB session request              */
+    /* If we get a redirect, we will comeback with redirect true 
+       and a new IP address in DEST_IP                            */
+
+    if ((errno = RFCNB_Session_Req(con, 
+				   Called_Name,
+   				   Calling_Name,
+				   &redirect, &Dest_IP, &port)) < 0) {
+
+      /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
+
+      return(NULL);
+
+      }
+
+    if (redirect) {
+
+      /* We have to close the connection, and then try again */
+
+      (con -> redirects)++;
+
+      RFCNB_Close(con -> fd);  /* Close it */
+
+      }
+    }
+
+  return(con);
+
+}
+
+/* We send a packet to the other end ... for the moment, we treat the 
+   data as a series of pointers to blocks of data ... we should check the
+   length ... */
+
+int RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
+
+{ struct RFCNB_Pkt *pkt; char *hdr;
+  int len;
+
+  /* Plug in the header and send the data */
+
+  pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+  if (pkt == NULL) {
+
+    RFCNB_errno = RFCNBE_NoSpace;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+
+  }
+
+  pkt -> next = udata;   /* The user data we want to send */
+
+  hdr = pkt -> data;
+
+  /* Following crap is for portability across multiple UNIX machines */
+
+  *(hdr + RFCNB_Pkt_Type_Offset)  = RFCNB_SESSION_MESSAGE;
+  RFCNB_Put_Pkt_Len(hdr, Length);
+
+#ifdef RFCNB_DEBUG
+
+  fprintf(stderr, "Sending packet: ");
+  
+#endif
+
+  if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+    /* No need to change RFCNB_errno as it was done by put_pkt ...     */
+
+    return(RFCNBE_Bad);   /* Should be able to write that lot ... */
+    
+  }
+
+  /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
+
+  pkt -> next = NULL;
+
+  RFCNB_Free_Pkt(pkt);
+
+  return(len);
+
+}
+
+/* We pick up a message from the internet ... We have to worry about 
+   non-message packets ...                                           */
+
+int RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
+
+{ struct RFCNB_Pkt *pkt;
+  int ret_len;
+
+  if (con_Handle == NULL){
+
+    RFCNB_errno = RFCNBE_BadHandle;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+
+  }
+
+  /* Now get a packet from below. We allocate a header first */
+
+  /* Plug in the header and send the data */
+
+  pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
+
+  if (pkt == NULL) {
+
+    RFCNB_errno = RFCNBE_NoSpace;
+    RFCNB_saved_errno = errno;
+    return(RFCNBE_Bad);
+
+  }
+
+  pkt -> next = Data;  /* Plug in the data portion */
+
+  if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
+
+#ifdef RFCNB_DEBUG
+    fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
+#endif
+
+    return(RFCNBE_Bad);
+
+  }
+
+  /* We should check that we go a message and not a keep alive */
+
+  pkt -> next = NULL;
+
+  RFCNB_Free_Pkt(pkt);
+
+  return(ret_len);
+
+}
+
+/* We just disconnect from the other end, as there is nothing in the RFCNB */
+/* protocol that specifies any exchange as far as I can see                */
+
+int RFCNB_Hangup(struct RFCNB_Con *con_Handle)
+
+{
+
+  if (con_Handle != NULL) {
+    RFCNB_Close(con_Handle -> fd);  /* Could this fail? */
+    free(con_Handle);
+  }
+
+  return 0;
+
+
+}
+
+/* Set TCP_NODELAY on the socket                                          */
+
+int RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, BOOL yn)
+
+{
+
+  return(setsockopt(con_Handle -> fd, IPPROTO_TCP, TCP_NODELAY, 
+		    (char *)&yn, sizeof(yn)));
+
+}
+
+
+/* Listen for a connection on a port???, when                             */
+/* the connection comes in, we return with the connection                 */
+
+void *RFCNB_Listen()
+
+{
+   fprintf(stderr,"RFCNB_Listen NOT IMPLEMENTED as yet!\n");
+   return NULL;   
+}
+
+/* Pick up the last error response as a string, hmmm, this routine should */
+/* have been different ...                                                */
+
+void RFCNB_Get_Error(char *buffer, int buf_len)
+
+{
+
+  if (RFCNB_saved_errno <= 0) {
+    sprintf(buffer, "%s", RFCNB_Error_Strings[RFCNB_errno]);
+  }
+  else {
+    sprintf(buffer, "%s\n\terrno:%s", RFCNB_Error_Strings[RFCNB_errno],
+	    strerror(RFCNB_saved_errno));
+  }
+
+}
+
+/* Pick up the last error response and returns as a code                 */
+
+int RFCNB_Get_Last_Error()
+
+{
+
+  return(RFCNB_errno);
+
+}
+
+/* Pick up saved errno as well */
+
+int RFCNB_Get_Last_Errno()
+
+{
+
+  return(RFCNB_saved_errno);
+
+}
+
+/* Pick up the last error response and return in string ...             */
+
+void RFCNB_Get_Error_Msg(int code, char *msg_buf, int len)
+
+{
+
+  strncpy(msg_buf, RFCNB_Error_Strings[abs(code)], len);
+
+}
+
+/* Register a higher level protocol print routine */
+
+void RFCNB_Register_Print_Routine(void (*fn)())
+
+{
+
+  Prot_Print_Routine = fn;
+
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smbdes.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,337 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+
+   a partial implementation of DES designed for use in the 
+   SMB authentication protocol
+
+   Copyright (C) Andrew Tridgell 1997
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+/* NOTES: 
+
+   This code makes no attempt to be fast! In fact, it is a very
+   slow implementation 
+
+   This code is NOT a complete DES implementation. It implements only
+   the minimum necessary for SMB authentication, as used by all SMB
+   products (including every copy of Microsoft Windows95 ever sold)
+
+   In particular, it can only do a unchained forward DES pass. This
+   means it is not possible to use this code for encryption/decryption
+   of data, instead it is only useful as a "hash" algorithm.
+
+   There is no entry point into this code that allows normal DES operation.
+
+   I believe this means that this code does not come under ITAR
+   regulations but this is NOT a legal opinion. If you are concerned
+   about the applicability of ITAR regulations to this code then you
+   should confirm it for yourself (and maybe let me know if you come
+   up with a different answer to the one above)
+*/
+
+
+
+static int perm1[56] = {57, 49, 41, 33, 25, 17,  9,
+			 1, 58, 50, 42, 34, 26, 18,
+			10,  2, 59, 51, 43, 35, 27,
+			19, 11,  3, 60, 52, 44, 36,
+			63, 55, 47, 39, 31, 23, 15,
+			 7, 62, 54, 46, 38, 30, 22,
+			14,  6, 61, 53, 45, 37, 29,
+			21, 13,  5, 28, 20, 12,  4};
+
+static int perm2[48] = {14, 17, 11, 24,  1,  5,
+                         3, 28, 15,  6, 21, 10,
+                        23, 19, 12,  4, 26,  8,
+                        16,  7, 27, 20, 13,  2,
+                        41, 52, 31, 37, 47, 55,
+                        30, 40, 51, 45, 33, 48,
+                        44, 49, 39, 56, 34, 53,
+                        46, 42, 50, 36, 29, 32};
+
+static int perm3[64] = {58, 50, 42, 34, 26, 18, 10,  2,
+			60, 52, 44, 36, 28, 20, 12,  4,
+			62, 54, 46, 38, 30, 22, 14,  6,
+			64, 56, 48, 40, 32, 24, 16,  8,
+			57, 49, 41, 33, 25, 17,  9,  1,
+			59, 51, 43, 35, 27, 19, 11,  3,
+			61, 53, 45, 37, 29, 21, 13,  5,
+			63, 55, 47, 39, 31, 23, 15,  7};
+
+static int perm4[48] = {   32,  1,  2,  3,  4,  5,
+                            4,  5,  6,  7,  8,  9,
+                            8,  9, 10, 11, 12, 13,
+                           12, 13, 14, 15, 16, 17,
+                           16, 17, 18, 19, 20, 21,
+                           20, 21, 22, 23, 24, 25,
+                           24, 25, 26, 27, 28, 29,
+                           28, 29, 30, 31, 32,  1};
+
+static int perm5[32] = {      16,  7, 20, 21,
+                              29, 12, 28, 17,
+                               1, 15, 23, 26,
+                               5, 18, 31, 10,
+                               2,  8, 24, 14,
+                              32, 27,  3,  9,
+                              19, 13, 30,  6,
+                              22, 11,  4, 25};
+
+
+static int perm6[64] ={ 40,  8, 48, 16, 56, 24, 64, 32,
+                        39,  7, 47, 15, 55, 23, 63, 31,
+                        38,  6, 46, 14, 54, 22, 62, 30,
+                        37,  5, 45, 13, 53, 21, 61, 29,
+                        36,  4, 44, 12, 52, 20, 60, 28,
+                        35,  3, 43, 11, 51, 19, 59, 27,
+                        34,  2, 42, 10, 50, 18, 58, 26,
+                        33,  1, 41,  9, 49, 17, 57, 25};
+
+
+static int sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+static int sbox[8][4][16] = {
+	{{14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7},
+	 {0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8},
+	 {4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0},
+	 {15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13}},
+
+	{{15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10},
+	 {3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5},
+	 {0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15},
+	 {13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9}},
+
+	{{10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8},
+	 {13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1},
+	 {13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7},
+	 {1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12}},
+
+	{{7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15},
+	 {13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9},
+	 {10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4},
+	 {3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14}},
+
+	{{2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9},
+	 {14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6},
+	 {4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14},
+	 {11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3}},
+
+	{{12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11},
+	 {10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8},
+	 {9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6},
+	 {4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13}},
+
+	{{4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1},
+	 {13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6},
+	 {1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2},
+	 {6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12}},
+
+	{{13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7},
+	 {1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2},
+	 {7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8},
+	 {2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11}}};
+
+static void permute(char *out, char *in, int *p, int n)
+{
+	int i;
+	for (i=0;i<n;i++)
+		out[i] = in[p[i]-1];
+}
+
+static void lshift(char *d, int count, int n)
+{
+	char out[64];
+	int i;
+	for (i=0;i<n;i++)
+		out[i] = d[(i+count)%n];
+	for (i=0;i<n;i++)
+		d[i] = out[i];
+}
+
+static void concat(char *out, char *in1, char *in2, int l1, int l2)
+{
+	while (l1--)
+		*out++ = *in1++;
+	while (l2--)
+		*out++ = *in2++;
+}
+
+static void xor(char *out, char *in1, char *in2, int n)
+{
+	int i;
+	for (i=0;i<n;i++)
+		out[i] = in1[i] ^ in2[i];
+}
+
+static void dohash(char *out, char *in, char *key)
+{
+	int i, j, k;
+	char pk1[56];
+	char c[28];
+	char d[28];
+	char cd[56];
+	char ki[16][48];
+	char pd1[64];
+	char l[32], r[32];
+	char rl[64];
+
+	permute(pk1, key, perm1, 56);
+
+	for (i=0;i<28;i++)
+		c[i] = pk1[i];
+	for (i=0;i<28;i++)
+		d[i] = pk1[i+28];
+
+	for (i=0;i<16;i++) {
+		lshift(c, sc[i], 28);
+		lshift(d, sc[i], 28);
+
+		concat(cd, c, d, 28, 28); 
+		permute(ki[i], cd, perm2, 48); 
+	}
+
+	permute(pd1, in, perm3, 64);
+
+	for (j=0;j<32;j++) {
+		l[j] = pd1[j];
+		r[j] = pd1[j+32];
+	}
+
+	for (i=0;i<16;i++) {
+		char er[48];
+		char erk[48];
+		char b[8][6];
+		char cb[32];
+		char pcb[32];
+		char r2[32];
+
+		permute(er, r, perm4, 48);
+
+		xor(erk, er, ki[i], 48);
+
+		for (j=0;j<8;j++)
+			for (k=0;k<6;k++)
+				b[j][k] = erk[j*6 + k];
+
+		for (j=0;j<8;j++) {
+			int m, n;
+			m = (b[j][0]<<1) | b[j][5];
+
+			n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4]; 
+
+			for (k=0;k<4;k++) 
+				b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0; 
+		}
+
+		for (j=0;j<8;j++)
+			for (k=0;k<4;k++)
+				cb[j*4+k] = b[j][k];
+		permute(pcb, cb, perm5, 32);
+
+		xor(r2, l, pcb, 32);
+
+		for (j=0;j<32;j++)
+			l[j] = r[j];
+
+		for (j=0;j<32;j++)
+			r[j] = r2[j];
+	}
+
+	concat(rl, r, l, 32, 32);
+
+	permute(out, rl, perm6, 64);
+}
+
+static void str_to_key(unsigned char *str,unsigned char *key)
+{
+	int i;
+
+	key[0] = str[0]>>1;
+	key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
+	key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
+	key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
+	key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
+	key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
+	key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
+	key[7] = str[6]&0x7F;
+	for (i=0;i<8;i++) {
+		key[i] = (key[i]<<1);
+	}
+}
+
+
+static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
+{
+	int i;
+	char outb[64];
+	char inb[64];
+	char keyb[64];
+	unsigned char key2[8];
+
+	str_to_key(key, key2);
+
+	for (i=0;i<64;i++) {
+		inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+		keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
+		outb[i] = 0;
+	}
+
+	dohash(outb, inb, keyb);
+
+	for (i=0;i<8;i++) {
+		out[i] = 0;
+	}
+
+	for (i=0;i<64;i++) {
+		if (outb[i])
+			out[i/8] |= (1<<(7-(i%8)));
+	}
+}
+
+void E_P16(unsigned char *p14,unsigned char *p16)
+{
+	unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+	smbhash(p16, sp8, p14);
+	smbhash(p16+8, sp8, p14+7);
+}
+
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+{
+	smbhash(p24, c8, p21);
+	smbhash(p24+8, c8, p21+7);
+	smbhash(p24+16, c8, p21+14);
+}
+
+void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key)
+{
+	unsigned char buf[8];
+
+	smbhash(buf, in, key);
+	smbhash(out, buf, key+9);
+}
+
+void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key)
+{
+	unsigned char buf[8];
+	static unsigned char key2[8];
+
+	smbhash(buf, in, key);
+	key2[0] = key[7];
+	smbhash(out, buf, key2);
+}
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smbdes.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,2 @@
+void E_P16(unsigned char *p14,unsigned char *p16);
+void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smbencrypt.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,200 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   SMB parameters and setup
+   Copyright (C) Andrew Tridgell 1992-1997
+   Modified by Jeremy Allison 1995.
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <string.h>
+#include <ctype.h>
+//#include <arpa/inet.h>
+#include <dirent.h>
+#include <string.h>
+//#include <sys/vfs.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "smblib-priv.h"
+#include "md4.h"
+#include "smbdes.h"
+#define uchar unsigned char
+extern int DEBUGLEVEL;
+
+#include "byteorder.h"
+
+char *StrnCpy(char *dest,char *src,int n);
+void strupper(char *s);
+
+/*
+   This implements the X/Open SMB password encryption
+   It takes a password, a 8 byte "crypt key" and puts 24 bytes of 
+   encrypted password into p24 */
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
+{
+  uchar p14[15], p21[21];
+
+  memset(p21,'\0',21);
+  memset(p14,'\0',14);
+  StrnCpy((char *)p14,(char *)passwd,14);
+
+  strupper((char *)p14);
+  E_P16(p14, p21); 
+  E_P24(p21, c8, p24);
+}
+
+/* Routines for Windows NT MD4 Hash functions. */
+static int _my_wcslen(int16 *str)
+{
+	int len = 0;
+	while(*str++ != 0)
+		len++;
+	return len;
+}
+
+/*
+ * Convert a string into an NT UNICODE string.
+ * Note that regardless of processor type 
+ * this must be in intel (little-endian)
+ * format.
+ */
+ 
+static int _my_mbstowcs(int16 *dst, uchar *src, int len)
+{
+	int i;
+	int16 val;
+ 
+	for(i = 0; i < len; i++) {
+		val = *src;
+		SSVAL(dst,0,val);
+		dst++;
+		src++;
+		if(val == 0)
+			break;
+	}
+	return i;
+}
+
+/* 
+ * Creates the MD4 Hash of the users password in NT UNICODE.
+ */
+ 
+void E_md4hash(uchar *passwd, uchar *p16)
+{
+	int len;
+	int16 wpwd[129];
+	
+	/* Password cannot be longer than 128 characters */
+	len = strlen((char *)passwd);
+	if(len > 128)
+		len = 128;
+	/* Password must be converted to NT unicode */
+	_my_mbstowcs(wpwd, passwd, len);
+	wpwd[len] = 0; /* Ensure string is null terminated */
+	/* Calculate length in bytes */
+	len = _my_wcslen(wpwd) * sizeof(int16);
+
+	mdfour(p16, (unsigned char *)wpwd, len);
+}
+
+/* Does the NT MD4 hash then des encryption. */
+ 
+void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24)
+{
+	uchar p21[21];
+ 
+	memset(p21,'\0',21);
+ 
+	E_md4hash(passwd, p21);    
+	E_P24(p21, c8, p24);
+}
+
+/* Does both the NT and LM owfs of a user's password */
+
+void nt_lm_owf_gen(char *pwd, char *nt_p16, char *p16)
+{
+	char passwd[130];
+	StrnCpy(passwd, pwd, sizeof(passwd)-1);
+
+	/* Calculate the MD4 hash (NT compatible) of the password */
+	memset(nt_p16, '\0', 16);
+	E_md4hash((uchar *)passwd, (uchar *)nt_p16);
+
+	/* Mangle the passwords into Lanman format */
+	passwd[14] = '\0';
+	strupper(passwd);
+
+	/* Calculate the SMB (lanman) hash functions of the password */
+
+	memset(p16, '\0', 16);
+	E_P16((uchar *) passwd, (uchar *)p16);
+
+	/* clear out local copy of user's password (just being paranoid). */
+	bzero(passwd, sizeof(passwd));
+}
+
+/****************************************************************************
+line strncpy but always null terminates. Make sure there is room!
+****************************************************************************/
+char *StrnCpy(char *dest,char *src,int n)
+{
+  char *d = dest;
+  if (!dest) return(NULL);
+  if (!src) {
+    *dest = 0;
+    return(dest);
+  }
+  while (n-- && (*d++ = *src++)) ;
+  *d = 0;
+  return(dest);
+}
+
+void strupper(char *s)
+{
+  while (*s)
+  {
+    /*
+#if !defined(KANJI_WIN95_COMPATIBILITY)
+    if(lp_client_code_page() == KANJI_CODEPAGE)
+    {
+      
+      if (is_shift_jis (*s))
+      {
+        if (is_sj_lower (s[0], s[1]))
+          s[1] = sj_toupper2 (s[1]);
+        s += 2;
+      }
+      else if (is_kana (*s))
+      {
+        s++;
+      }
+      else
+      {
+        if (islower(*s))                           
+	  *s = toupper(*s);
+        s++;
+      }
+    }
+    else
+#endif */ /* KANJI_WIN95_COMPATIBILITY */
+    {
+      if (islower(*s))
+        *s = toupper(*s);
+      s++;
+    }
+  }
+}                      
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smbencrypt.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1 @@
+void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smblib-common.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,189 @@
+#ifndef __SMBLIB_COMMON_H__
+#define __SMBLIB_COMMON_H__
+
+/* UNIX SMBlib NetBIOS implementation
+
+   Version 1.0
+   SMBlib Common Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* To get the error class we want the first 8 bits */
+/* Because we just grab 4bytes from the SMB header, we have to re-order */
+/* here, but it makes the NtStatus part easier in future                */
+
+#define SMBlib_Error_Class(p) (p & 0x000000FF)
+
+/* To get the error code, we want the bottom 16 bits */
+
+#define SMBlib_Error_Code(p) (((unsigned int)p & 0xFFFF0000) >>16)
+
+/* Error CLASS codes and etc ... */
+
+#define SMBC_SUCCESS        0
+#define SMBC_ERRDOS         0x01
+#define SMBC_ERRSRV         0x02
+#define SMBC_ERRHRD         0x03
+#define SMBC_ERRCMD         0xFF
+
+/* Success error codes    */
+
+#define SMBS_BUFFERED       0x54
+#define SMBS_LOGGED         0x55
+#define SMBS_DISPLAYED      0x56
+
+/* ERRDOS Error codes     */
+
+#define SMBD_badfunc        0x01
+#define SMBD_badfile        0x02
+#define SMBD_badpath        0x03
+#define SMBD_nofids         0x04
+#define SMBD_noaccess       0x05
+#define SMBD_badfid         0x06
+#define SMBD_badmcb         0x07
+#define SMBD_nomem          0x08
+#define SMBD_badmem         0x09
+#define SMBD_badenv         0x0A
+#define SMBD_badformat      0x0B
+#define SMBD_badaccess      0x0C
+#define SMBD_baddata        0x0D
+#define SMBD_reserved       0x0E
+#define SMBD_baddrive       0x0F
+#define SMBD_remcd          0x10
+#define SMBD_diffdevice     0x11
+#define SMBD_nofiles        0x12
+#define SMBD_badshare       0x20
+#define SMBD_errlock        0x21
+#define SMBD_filexists      0x50
+
+/* Server errors ... */
+
+#define SMBV_error          0x01         /* Generic error */
+#define SMBV_badpw          0x02
+#define SMBV_badtype        0x03
+#define SMBV_access         0x04
+#define SMBV_invnid         0x05
+#define SMBV_invnetname     0x06
+#define SMBV_invdevice      0x07
+#define SMBV_qfull          0x31
+#define SMBV_qtoobig        0x32
+#define SMBV_qeof           0x33
+#define SMBV_invpfid        0x34
+#define SMBV_paused         0x51
+#define SMBV_msgoff         0x52
+#define SMBV_noroom         0x53
+#define SMBV_rmuns          0x57
+#define SMBV_nosupport      0xFFFF
+
+/* Hardware error codes ... */
+
+#define SMBH_nowrite        0x13
+#define SMBH_badunit        0x14
+#define SMBH_notready       0x15
+#define SMBH_badcmd         0x16
+#define SMBH_data           0x17
+#define SMBH_badreq         0x18
+#define SMBH_seek           0x19
+#define SMBH_badmedia       0x1A
+#define SMBH_badsector      0x1B
+#define SMBH_nopaper        0x1C
+#define SMBH_write          0x1D
+#define SMBH_read           0x1E
+#define SMBH_general        0x1F
+#define SMBH_badshare       0x20
+
+/* Access mode defines ... */
+
+#define SMB_AMODE_WTRU      0x4000
+#define SMB_AMODE_NOCACHE   0x1000
+#define SMB_AMODE_COMPAT    0x0000
+#define SMB_AMODE_DENYRWX   0x0010
+#define SMB_AMODE_DENYW     0x0020
+#define SMB_AMODE_DENYRX    0x0030
+#define SMB_AMODE_DENYNONE  0x0040
+#define SMB_AMODE_OPENR     0x0000
+#define SMB_AMODE_OPENW     0x0001
+#define SMB_AMODE_OPENRW    0x0002
+#define SMB_AMODE_OPENX     0x0003
+#define SMB_AMODE_FCBOPEN   0x00FF
+#define SMB_AMODE_LOCUNKN   0x0000
+#define SMB_AMODE_LOCMSEQ   0x0100
+#define SMB_AMODE_LOCMRAN   0x0200
+#define SMB_AMODE_LOCRAL    0x0300
+
+/* File attribute encoding ... */
+
+#define SMB_FA_ORD          0x00
+#define SMB_FA_ROF          0x01
+#define SMB_FA_HID          0x02
+#define SMB_FA_SYS          0x04
+#define SMB_FA_VOL          0x08
+#define SMB_FA_DIR          0x10
+#define SMB_FA_ARC          0x20
+
+/* Define the protocol types ... */
+
+#define SMB_P_Unknown      -1        /* Hmmm, is this smart? */
+#define SMB_P_Core         0
+#define SMB_P_CorePlus     1
+#define SMB_P_DOSLanMan1   2
+#define SMB_P_LanMan1      3
+#define SMB_P_DOSLanMan2   4 
+#define SMB_P_LanMan2      5
+#define SMB_P_DOSLanMan2_1 6
+#define SMB_P_LanMan2_1    7
+#define SMB_P_NT1          8
+
+/* SMBlib return codes */
+/* We want something that indicates whether or not the return code was a   */
+/* remote error, a local error in SMBlib or returned from lower layer ...  */
+/* Wonder if this will work ...                                            */
+/* SMBlibE_Remote = 1 indicates remote error                               */
+/* SMBlibE_ values < 0 indicate local error with more info available       */
+/* SMBlibE_ values >1 indicate local from SMBlib code errors?              */
+
+#define SMBlibE_Success 0
+#define SMBlibE_Remote  1    /* Remote error, get more info from con        */
+#define SMBlibE_BAD     -1
+#define SMBlibE_LowerLayer 2 /* Lower layer error                           */
+#define SMBlibE_NotImpl 3    /* Function not yet implemented                */
+#define SMBlibE_ProtLow 4    /* Protocol negotiated does not support req    */
+#define SMBlibE_NoSpace 5    /* No space to allocate a structure            */
+#define SMBlibE_BadParam 6   /* Bad parameters                              */
+#define SMBlibE_NegNoProt 7  /* None of our protocols was liked             */
+#define SMBlibE_SendFailed 8 /* Sending an SMB failed                       */
+#define SMBlibE_RecvFailed 9 /* Receiving an SMB failed                     */
+#define SMBlibE_GuestOnly 10 /* Logged in as guest                          */
+#define SMBlibE_CallFailed 11 /* Call remote end failed                     */
+#define SMBlibE_ProtUnknown 12 /* Protocol unknown                          */
+#define SMBlibE_NoSuchMsg  13 /* Keep this up to date                       */
+
+typedef struct {                       /* A structure for a Dirent */
+
+  unsigned char resume_key[21];        /* Don't touch this          */
+  unsigned char file_attributes;       /* Attributes of file        */
+  unsigned int date_time;              /* date and time of last mod */
+  unsigned int size;
+  char filename[13];                   /* The name of the file      */
+
+} SMB_CP_dirent;
+
+#endif /* __SMBLIB_COMMON_H__ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smblib-priv.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,649 @@
+#ifndef __SMBLIB_PRIV_H__
+#define __SMBLIB_PRIV_H__
+
+/* UNIX SMBlib NetBIOS implementation
+
+   Version 1.0
+   SMBlib private Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "std-defines.h"
+#include "smblib-common.h"
+#include <sys/types.h>
+#include <unistd.h>
+
+typedef unsigned short uint16;
+typedef unsigned int   uint32;
+
+#include "byteorder.h"     /* Hmmm ... hot good */
+
+#define max(a,b) (a < b ? b : a)
+
+#define SMB_DEF_IDF 0x424D53FF        /* "\377SMB" */
+ 
+/* Core protocol commands */
+
+#define SMBmkdir      0x00   /* create directory */
+#define SMBrmdir      0x01   /* delete directory */
+#define SMBopen       0x02   /* open file */
+#define SMBcreate     0x03   /* create file */
+#define SMBclose      0x04   /* close file */
+#define SMBflush      0x05   /* flush file */
+#define SMBunlink     0x06   /* delete file */
+#define SMBmv         0x07   /* rename file */
+#define SMBgetatr     0x08   /* get file attributes */
+#define SMBsetatr     0x09   /* set file attributes */
+#define SMBread       0x0A   /* read from file */
+#define SMBwrite      0x0B   /* write to file */
+#define SMBlock       0x0C   /* lock byte range */
+#define SMBunlock     0x0D   /* unlock byte range */
+#define SMBctemp      0x0E   /* create temporary file */
+#define SMBmknew      0x0F   /* make new file */
+#define SMBchkpth     0x10   /* check directory path */
+#define SMBexit       0x11   /* process exit */
+#define SMBlseek      0x12   /* seek */
+#define SMBtcon       0x70   /* tree connect */
+#define SMBtdis       0x71   /* tree disconnect */
+#define SMBnegprot    0x72   /* negotiate protocol */
+#define SMBdskattr    0x80   /* get disk attributes */
+#define SMBsearch     0x81   /* search directory */
+#define SMBsplopen    0xC0   /* open print spool file */
+#define SMBsplwr      0xC1   /* write to print spool file */
+#define SMBsplclose   0xC2   /* close print spool file */
+#define SMBsplretq    0xC3   /* return print queue */
+#define SMBsends      0xD0   /* send single block message */
+#define SMBsendb      0xD1   /* send broadcast message */
+#define SMBfwdname    0xD2   /* forward user name */
+#define SMBcancelf    0xD3   /* cancel forward */
+#define SMBgetmac     0xD4   /* get machine name */
+#define SMBsendstrt   0xD5   /* send start of multi-block message */
+#define SMBsendend    0xD6   /* send end of multi-block message */
+#define SMBsendtxt    0xD7   /* send text of multi-block message */
+
+/* CorePlus protocol                                        */
+
+#define SMBlockread   0x13  /* Lock a range and read it */
+#define SMBwriteunlock 0x14 /* Unlock a range and then write */
+#define SMBreadbraw   0x1a  /* read a block of data without smb header ohead*/
+#define SMBwritebraw  0x1d  /* write a block of data without smb header ohead*/
+#define SMBwritec     0x20  /* secondary write request */
+#define SMBwriteclose 0x2c  /* write a file and then close it */
+
+/* DOS Extended Protocol                                    */
+
+#define SMBreadBraw      0x1A   /* read block raw */
+#define SMBreadBmpx      0x1B   /* read block multiplexed */
+#define SMBreadBs        0x1C   /* read block (secondary response) */
+#define SMBwriteBraw     0x1D   /* write block raw */
+#define SMBwriteBmpx     0x1E   /* write block multiplexed */
+#define SMBwriteBs       0x1F   /* write block (secondary request) */
+#define SMBwriteC        0x20   /* write complete response */
+#define SMBsetattrE      0x22   /* set file attributes expanded */
+#define SMBgetattrE      0x23   /* get file attributes expanded */
+#define SMBlockingX      0x24   /* lock/unlock byte ranges and X */
+#define SMBtrans         0x25   /* transaction - name, bytes in/out */
+#define SMBtranss        0x26   /* transaction (secondary request/response) */
+#define SMBioctl         0x27   /* IOCTL */
+#define SMBioctls        0x28   /* IOCTL  (secondary request/response) */
+#define SMBcopy          0x29   /* copy */
+#define SMBmove          0x2A   /* move */
+#define SMBecho          0x2B   /* echo */
+#define SMBopenX         0x2D   /* open and X */
+#define SMBreadX         0x2E   /* read and X */
+#define SMBwriteX        0x2F   /* write and X */
+#define SMBsesssetupX    0x73   /* Session Set Up & X (including User Logon) */
+#define SMBtconX         0x75   /* tree connect and X */
+#define SMBffirst        0x82   /* find first */
+#define SMBfunique       0x83   /* find unique */
+#define SMBfclose        0x84   /* find close */
+#define SMBinvalid       0xFE   /* invalid command */
+
+/* Any more ? */
+
+#define SMBdatablockID     0x01  /* A data block identifier */
+#define SMBdialectID       0x02  /* A dialect id            */
+#define SMBpathnameID      0x03  /* A pathname ID           */
+#define SMBasciiID         0x04  /* An ascii string ID      */
+#define SMBvariableblockID 0x05  /* A variable block ID     */
+
+/* some other defines we need */
+
+/* Flags defines ... */
+
+#define SMB_FLG2_NON_DOS    0x01 /* We know non dos names             */
+#define SMB_FLG2_EXT_ATR    0x02 /* We know about Extended Attributes */
+#define SMB_FLG2_LNG_NAM    0x04 /* Long names ?                      */
+
+typedef unsigned short WORD;
+typedef unsigned short UWORD;
+typedef unsigned int ULONG;
+typedef unsigned char BYTE;
+typedef unsigned char UCHAR;
+
+/* Some macros to allow access to actual packet data so that we */
+/* can change the underlying representation of packets.         */
+/*                                                              */
+/* The current formats vying for attention are a fragment       */
+/* approach where the SMB header is a fragment linked to the    */
+/* data portion with the transport protocol (rfcnb or whatever) */
+/* being linked on the front.                                   */
+/*                                                              */
+/* The other approach is where the whole packet is one array    */
+/* of bytes with space allowed on the front for the packet      */
+/* headers.                                                     */
+
+#define SMB_Hdr(p) (char *)(p -> data)
+
+/* SMB Hdr def for File Sharing Protocol? From MS and Intel,    */
+/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also  */
+/* applies to LANMAN1.0 as well as the Core Protocol            */
+/* The spec states that wct and bcc must be present, even if 0  */
+
+/* We define these as offsets into a char SMB[] array for the   */
+/* sake of portability                                          */
+
+/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */
+/* the data that follows in the SMB packet, so the code will have to   */
+/* take that into account.                                             */
+
+#define SMB_hdr_idf_offset    0          /* 0xFF,'SMB' 0-3 */
+#define SMB_hdr_com_offset    4          /* BYTE       4   */
+#define SMB_hdr_rcls_offset   5          /* BYTE       5   */
+#define SMB_hdr_reh_offset    6          /* BYTE       6   */
+#define SMB_hdr_err_offset    7          /* WORD       7   */
+#define SMB_hdr_reb_offset    9          /* BYTE       9   */
+#define SMB_hdr_flg_offset    9          /* same as reb ...*/
+#define SMB_hdr_res_offset    10         /* 7 WORDs    10  */
+#define SMB_hdr_res0_offset   10         /* WORD       10  */
+#define SMB_hdr_flg2_offset   10         /* WORD           */
+#define SMB_hdr_res1_offset   12         /* WORD       12  */
+#define SMB_hdr_res2_offset   14
+#define SMB_hdr_res3_offset   16
+#define SMB_hdr_res4_offset   18
+#define SMB_hdr_res5_offset   20
+#define SMB_hdr_res6_offset   22
+#define SMB_hdr_tid_offset    24
+#define SMB_hdr_pid_offset    26
+#define SMB_hdr_uid_offset    28
+#define SMB_hdr_mid_offset    30
+#define SMB_hdr_wct_offset    32
+
+#define SMB_hdr_len           33        /* 33 byte header?      */
+
+#define SMB_hdr_axc_offset    33        /* AndX Command         */
+#define SMB_hdr_axr_offset    34        /* AndX Reserved        */
+#define SMB_hdr_axo_offset    35     /* Offset from start to WCT of AndX cmd */
+
+/* Format of the Negotiate Protocol SMB */
+
+#define SMB_negp_bcc_offset   33
+#define SMB_negp_buf_offset   35        /* Where the buffer starts   */
+#define SMB_negp_len          35        /* plus the data             */
+
+/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */
+/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */
+/* for NT LM 0.12                                                    */
+
+#define SMB_negrCP_idx_offset   33        /* Response to the neg req */
+#define SMB_negrCP_bcc_offset   35
+#define SMB_negrLM_idx_offset   33        /* dialect index           */
+#define SMB_negrLM_sec_offset   35        /* Security mode           */
+#define SMB_sec_user_mask       0x01      /* 0 = share, 1 = user     */
+#define SMB_sec_encrypt_mask    0x02      /* pick out encrypt        */
+#define SMB_negrLM_mbs_offset   37        /* max buffer size         */
+#define SMB_negrLM_mmc_offset   39        /* max mpx count           */
+#define SMB_negrLM_mnv_offset   41        /* max number of VCs       */
+#define SMB_negrLM_rm_offset    43        /* raw mode support bit vec*/
+#define SMB_read_raw_mask       0x01
+#define SMB_write_raw_mask      0x02
+#define SMB_negrLM_sk_offset    45        /* session key, 32 bits    */
+#define SMB_negrLM_st_offset    49        /* Current server time     */
+#define SMB_negrLM_sd_offset    51        /* Current server date     */
+#define SMB_negrLM_stz_offset   53        /* Server Time Zone        */
+#define SMB_negrLM_ekl_offset   55        /* encryption key length   */
+#define SMB_negrLM_res_offset   57        /* reserved                */
+#define SMB_negrLM_bcc_offset   59        /* bcc                     */
+#define SMB_negrLM_len          61        /* 61 bytes ?              */
+#define SMB_negrLM_buf_offset   61        /* Where the fun begins    */
+
+#define SMB_negrNTLM_idx_offset 33        /* Selected protocol       */
+#define SMB_negrNTLM_sec_offset 35        /* Security more           */
+#define SMB_negrNTLM_mmc_offset 36        /* Different format above  */
+#define SMB_negrNTLM_mnv_offset 38        /* Max VCs                 */
+#define SMB_negrNTLM_mbs_offset 40        /* MBS now a long          */
+#define SMB_negrNTLM_mrs_offset 44        /* Max raw size            */
+#define SMB_negrNTLM_sk_offset  48        /* Session Key             */
+#define SMB_negrNTLM_cap_offset 52        /* Capabilities            */
+#define SMB_negrNTLM_stl_offset 56        /* Server time low         */
+#define SMB_negrNTLM_sth_offset 60        /* Server time high        */
+#define SMB_negrNTLM_stz_offset 64        /* Server time zone        */
+#define SMB_negrNTLM_ekl_offset 66        /* Encrypt key len         */
+#define SMB_negrNTLM_bcc_offset 67        /* Bcc                     */
+#define SMB_negrNTLM_len        69
+#define SMB_negrNTLM_buf_offset 69
+
+/* Offsets related to Tree Connect                                      */
+
+#define SMB_tcon_bcc_offset     33
+#define SMB_tcon_buf_offset     35        /* where the data is for tcon */
+#define SMB_tcon_len            35        /* plus the data              */
+
+#define SMB_tconr_mbs_offset    33        /* max buffer size         */
+#define SMB_tconr_tid_offset    35        /* returned tree id        */
+#define SMB_tconr_bcc_offset    37       
+#define SMB_tconr_len           39 
+
+#define SMB_tconx_axc_offset    33        /* And X Command                */
+#define SMB_tconx_axr_offset    34        /* reserved                     */
+#define SMB_tconx_axo_offset    35        /* Next command offset          */
+#define SMB_tconx_flg_offset    37        /* Flags, bit0=1 means disc TID */
+#define SMB_tconx_pwl_offset    39        /* Password length              */
+#define SMB_tconx_bcc_offset    41        /* bcc                          */
+#define SMB_tconx_buf_offset    43        /* buffer                       */
+#define SMB_tconx_len           43        /* up to data ...               */
+
+#define SMB_tconxr_axc_offset   33        /* Where the AndX Command is    */
+#define SMB_tconxr_axr_offset   34        /* Reserved                     */
+#define SMB_tconxr_axo_offset   35        /* AndX offset location         */
+
+/* Offsets related to tree_disconnect                                  */
+
+#define SMB_tdis_bcc_offset     33        /* bcc                     */
+#define SMB_tdis_len            35        /* total len               */
+
+#define SMB_tdisr_bcc_offset    33        /* bcc                     */
+#define SMB_tdisr_len           35
+
+/* Offsets related to Open Request                                     */
+
+#define SMB_open_mod_offset     33        /* Mode to open with       */
+#define SMB_open_atr_offset     35        /* Attributes of file      */
+#define SMB_open_bcc_offset     37        /* bcc                     */
+#define SMB_open_buf_offset     39        /* File name               */
+#define SMB_open_len            39        /* Plus the file name      */
+
+#define SMB_openx_axc_offset    33        /* Next command            */
+#define SMB_openx_axr_offset    34        /* Reserved                */
+#define SMB_openx_axo_offset    35        /* offset of next wct      */
+#define SMB_openx_flg_offset    37        /* Flags, bit0 = need more info */
+                                          /* bit1 = exclusive oplock */
+                                          /* bit2 = batch oplock     */
+#define SMB_openx_mod_offset    39        /* mode to open with       */
+#define SMB_openx_atr_offset    41        /* search attributes       */
+#define SMB_openx_fat_offset    43        /* File attributes         */
+#define SMB_openx_tim_offset    45        /* time and date of creat  */
+#define SMB_openx_ofn_offset    49        /* Open function           */
+#define SMB_openx_als_offset    51        /* Space to allocate on    */
+#define SMB_openx_res_offset    55        /* reserved                */
+#define SMB_openx_bcc_offset    63        /* bcc                     */
+#define SMB_openx_buf_offset    65        /* Where file name goes    */
+#define SMB_openx_len           65
+
+#define SMB_openr_fid_offset    33        /* FID returned            */
+#define SMB_openr_atr_offset    35        /* Attributes opened with  */
+#define SMB_openr_tim_offset    37        /* Last mod time of file   */
+#define SMB_openr_fsz_offset    41        /* File size 4 bytes       */
+#define SMB_openr_acc_offset    45        /* Access allowed          */
+#define SMB_openr_bcc_offset    47
+#define SMB_openr_len           49
+
+#define SMB_openxr_axc_offset   33        /* And X command           */
+#define SMB_openxr_axr_offset   34        /* reserved                */
+#define SMB_openxr_axo_offset   35        /* offset to next command  */
+#define SMB_openxr_fid_offset   37        /* FID returned            */
+#define SMB_openxr_fat_offset   39        /* File attributes returned*/
+#define SMB_openxr_tim_offset   41        /* File creation date etc  */
+#define SMB_openxr_fsz_offset   45        /* Size of file            */
+#define SMB_openxr_acc_offset   49        /* Access granted          */
+
+#define SMB_clos_fid_offset     33        /* FID to close            */
+#define SMB_clos_tim_offset     35        /* Last mod time           */
+#define SMB_clos_bcc_offset     39        /* bcc                     */        
+#define SMB_clos_len            41
+
+/* Offsets related to Write requests                                 */
+
+#define SMB_write_fid_offset    33        /* FID to write            */
+#define SMB_write_cnt_offset    35        /* bytes to write          */
+#define SMB_write_ofs_offset    37        /* location to write to    */
+#define SMB_write_clf_offset    41        /* advisory count left     */
+#define SMB_write_bcc_offset    43        /* bcc = data bytes + 3    */
+#define SMB_write_buf_offset    45        /* Data=0x01, len, data    */
+#define SMB_write_len           45        /* plus the data ...       */
+
+#define SMB_writr_cnt_offset    33        /* Count of bytes written  */
+#define SMB_writr_bcc_offset    35        /* bcc                     */
+#define SMB_writr_len           37
+
+/* Offsets related to read requests */
+
+#define SMB_read_fid_offset     33        /* FID of file to read     */
+#define SMB_read_cnt_offset     35        /* count of words to read  */
+#define SMB_read_ofs_offset     37        /* Where to read from      */
+#define SMB_read_clf_offset     41        /* Advisory count to go    */
+#define SMB_read_bcc_offset     43
+#define SMB_read_len            45
+
+#define SMB_readr_cnt_offset    33        /* Count of bytes returned */
+#define SMB_readr_res_offset    35        /* 4 shorts reserved, 8 bytes */
+#define SMB_readr_bcc_offset    43        /* bcc                     */
+#define SMB_readr_bff_offset    45        /* buffer format char = 0x01 */
+#define SMB_readr_len_offset    46        /* buffer len              */
+#define SMB_readr_len           45        /* length of the readr before data */
+
+/* Offsets for Create file                                           */
+
+#define SMB_creat_atr_offset    33        /* Attributes of new file ... */
+#define SMB_creat_tim_offset    35        /* Time of creation           */
+#define SMB_creat_dat_offset    37        /* 4004BCE :-)                */
+#define SMB_creat_bcc_offset    39        /* bcc                        */
+#define SMB_creat_buf_offset    41
+#define SMB_creat_len           41        /* Before the data            */
+
+#define SMB_creatr_fid_offset   33        /* FID of created file        */
+
+/* Offsets for Delete file                                           */
+
+#define SMB_delet_sat_offset    33        /* search attribites          */
+#define SMB_delet_bcc_offset    35        /* bcc                        */
+#define SMB_delet_buf_offset    37
+#define SMB_delet_len           37
+
+/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols    */
+
+#define SMB_ssetpLM_mbs_offset  37        /* Max buffer Size, allow for AndX */
+#define SMB_ssetpLM_mmc_offset  39        /* max multiplex count             */
+#define SMB_ssetpLM_vcn_offset  41        /* VC number if new VC             */
+#define SMB_ssetpLM_snk_offset  43        /* Session Key                     */
+#define SMB_ssetpLM_pwl_offset  47        /* password length                 */
+#define SMB_ssetpLM_res_offset  49        /* reserved                        */
+#define SMB_ssetpLM_bcc_offset  53        /* bcc                             */
+#define SMB_ssetpLM_len         55        /* before data ...                 */
+#define SMB_ssetpLM_buf_offset  55
+
+#define SMB_ssetpNTLM_mbs_offset 37       /* Max Buffer Size for NT LM 0.12  */
+                                          /* and above                       */
+#define SMB_ssetpNTLM_mmc_offset 39       /* Max Multiplex count             */
+#define SMB_ssetpNTLM_vcn_offset 41       /* VC Number                       */
+#define SMB_ssetpNTLM_snk_offset 43       /* Session key                     */
+#define SMB_ssetpNTLM_cipl_offset 47      /* Case Insensitive PW Len         */
+#define SMB_ssetpNTLM_cspl_offset 49      /* Unicode pw len                  */
+#define SMB_ssetpNTLM_res_offset 51       /* reserved                        */
+#define SMB_ssetpNTLM_cap_offset 55       /* server capabilities             */
+#define SMB_ssetpNTLM_bcc_offset 59       /* bcc                             */
+#define SMB_ssetpNTLM_len        61       /* before data                     */
+#define SMB_ssetpNTLM_buf_offset 61
+
+#define SMB_ssetpr_axo_offset  35         /* Offset of next response ...    */
+#define SMB_ssetpr_act_offset  37         /* action, bit 0 = 1 => guest     */
+#define SMB_ssetpr_bcc_offset  39         /* bcc                            */
+#define SMB_ssetpr_buf_offset  41         /* Native OS etc                  */
+
+/* Offsets for SMB create directory                                         */
+
+#define SMB_creatdir_bcc_offset 33        /* only a bcc here                */
+#define SMB_creatdir_buf_offset 35        /* Where things start             */
+#define SMB_creatdir_len        35
+
+/* Offsets for SMB delete directory                                         */
+
+#define SMB_deletdir_bcc_offset 33        /* only a bcc here                */
+#define SMB_deletdir_buf_offset 35        /* where things start             */
+#define SMB_deletdir_len        35
+
+/* Offsets for SMB check directory                                          */
+
+#define SMB_checkdir_bcc_offset 33        /* Only a bcc here                */
+#define SMB_checkdir_buf_offset 35        /* where things start             */
+#define SMB_checkdir_len        35
+
+/* Offsets for SMB search                                                   */
+
+#define SMB_search_mdc_offset   33        /* Max Dir ents to return         */
+#define SMB_search_atr_offset   35        /* Search attributes              */
+#define SMB_search_bcc_offset   37        /* bcc                            */
+#define SMB_search_buf_offset   39        /* where the action is            */
+#define SMB_search_len          39
+
+#define SMB_searchr_dec_offset  33        /* Dir ents returned              */
+#define SMB_searchr_bcc_offset  35        /* bcc                            */
+#define SMB_searchr_buf_offset  37        /* Where the action starts        */
+#define SMB_searchr_len         37        /* before the dir ents            */
+
+#define SMB_searchr_dirent_len  43        /* 53 bytes                       */
+
+/* Defines for SMB transact and transact2 calls                             */
+
+#define SMB_trans_tpc_offset    33        /* Total param count              */
+#define SMB_trans_tdc_offset    35        /* total Data count               */
+#define SMB_trans_mpc_offset    37        /* Max params bytes to return     */
+#define SMB_trans_mdc_offset    39        /* Max data bytes to return       */
+#define SMB_trans_msc_offset    41        /* Max setup words to return      */
+#define SMB_trans_rs1_offset    42        /* Reserved byte                  */
+#define SMB_trans_flg_offset    43        /* flags                          */
+#define SMB_trans_tmo_offset    45        /* Timeout, long                  */
+#define SMB_trans_rs2_offset    49        /* Next reserved                  */
+#define SMB_trans_pbc_offset    51        /* Param Byte count in buf        */
+#define SMB_trans_pbo_offset    53        /* Offset to param bytes          */
+#define SMB_trans_dbc_offset    55        /* Data byte count in buf         */
+#define SMB_trans_dbo_offset    57        /* Data byte offset               */
+#define SMB_trans_suc_offset    59        /* Setup count - byte             */
+#define SMB_trans_rs3_offset    60        /* Reserved to pad ...            */
+#define SMB_trans_len           61        /* Up to setup, still need bcc    */
+
+#define SMB_transr_tpc_offset   33        /* Total param bytes returned     */
+#define SMB_transr_tdc_offset   35
+#define SMB_transr_rs1_offset   37
+#define SMB_transr_pbc_offset   39
+#define SMB_transr_pbo_offset   41
+#define SMB_transr_pdi_offset   43        /* parameter displacement         */
+#define SMB_transr_dbc_offset   45
+#define SMB_transr_dbo_offset   47
+#define SMB_transr_ddi_offset   49
+#define SMB_transr_suc_offset   51
+#define SMB_transr_rs2_offset   52
+#define SMB_transr_len          53
+
+/* Bit masks for SMB Capabilities ...                       */
+
+#define SMB_cap_raw_mode         0x0001
+#define SMB_cap_mpx_mode         0x0002
+#define SMB_cap_unicode          0x0004
+#define SMB_cap_large_files      0x0008
+#define SMB_cap_nt_smbs          0x0010
+#define SMB_rpc_remote_apis      0x0020
+#define SMB_cap_nt_status        0x0040
+#define SMB_cap_level_II_oplocks 0x0080
+#define SMB_cap_lock_and_read    0x0100
+#define SMB_cap_nt_find          0x0200
+
+/* SMB LANMAN api call defines */
+
+#define SMB_LMapi_SetUserInfo     0x0072
+#define SMB_LMapi_UserPasswordSet 0x0073
+ 
+/* Structures and defines we use in the client interface */
+
+/* The protocols we might support. Perhaps a bit ambitious, as only RFCNB */
+/* has any support so far 0(sometimes called NBT)                         */
+
+typedef enum {SMB_RFCNB, SMB_IPXNB, SMB_NETBEUI, SMB_X25} SMB_Transport_Types;
+
+typedef enum {SMB_Con_FShare, SMB_Con_PShare, SMB_Con_IPC} SMB_Con_Types;
+
+typedef enum {SMB_State_NoState, SMB_State_Stopped, SMB_State_Started} SMB_State_Types;
+
+/* The following two arrays need to be in step!              */
+/* We must make it possible for callers to specify these ... */
+
+
+extern char *SMB_Prots[];
+
+/*
+static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0", 
+			    "MICROSOFT NETWORKS 1.03",
+			    "MICROSOFT NETWORKS 3.0",
+			    "DOS LANMAN1.0",
+			    "LANMAN1.0",
+			    "DOS LM1.2X002",
+			    "LM1.2X002",
+			    "DOS LANMAN2.1",
+			    "LANMAN2.1",
+			    "Samba",
+			    "NT LM 0.12",
+			    "NT LANMAN 1.0",
+			    NULL};
+*/
+extern int SMB_Types[];
+
+/*
+static int SMB_Types[] = {SMB_P_Core,
+                          SMB_P_CorePlus,
+			  SMB_P_DOSLanMan1,
+			  SMB_P_DOSLanMan1,
+	                  SMB_P_LanMan1,
+			  SMB_P_DOSLanMan2,
+		          SMB_P_LanMan2,
+	 	          SMB_P_LanMan2_1,
+		          SMB_P_LanMan2_1,
+		          SMB_P_NT1,
+		          SMB_P_NT1,
+		          SMB_P_NT1,
+		          -1};
+*/
+typedef struct SMB_Status {
+
+  union {
+    struct {
+      unsigned char ErrorClass;
+      unsigned char Reserved;
+      unsigned short Error;
+    } DosError;
+    unsigned int NtStatus;
+  } status;
+} SMB_Status;
+
+typedef struct SMB_Tree_Structure * SMB_Tree_Handle;
+
+typedef struct SMB_Connect_Def * SMB_Handle_Type;
+
+struct SMB_Connect_Def {
+
+  SMB_Handle_Type Next_Con, Prev_Con;          /* Next and previous conn */
+  int protocol;                                /* What is the protocol   */
+  int prot_IDX;                                /* And what is the index  */
+  void *Trans_Connect;                         /* The connection         */
+
+  /* All these strings should be malloc'd */
+
+  char service[80], username[80], password[80], desthost[80], sock_options[80];
+  char address[80], myname[80];
+
+  SMB_Tree_Handle first_tree, last_tree;  /* List of trees on this server */
+
+  int gid;         /* Group ID, do we need it?                      */
+  int mid;         /* Multiplex ID? We might need one per con       */
+  int pid;         /* Process ID                                    */
+
+  int uid;         /* Authenticated user id.                        */
+
+                   /* It is pretty clear that we need to bust some of */
+                   /* these out into a per TCon record, as there may  */
+                   /* be multiple TCon's per server, etc ... later    */
+
+  int port;        /* port to use in case not default, this is a TCPism! */
+
+  int max_xmit;    /* Max xmit permitted by server                  */
+  int Security;    /* 0 = share, 1 = user                           */
+  int Raw_Support; /* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */
+  BOOL encrypt_passwords; /* FALSE = don't                          */ 
+  int MaxMPX, MaxVC, MaxRaw;
+  unsigned int SessionKey, Capabilities;
+  int SvrTZ;                                 /* Server Time Zone */
+  int Encrypt_Key_Len;
+  char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40];
+  char Svr_OS[80], Svr_LMType[80], Svr_PDom[80];
+
+};
+
+#ifndef SMBLIB_DEFAULT_DOMAIN
+#define SMBLIB_DEFAULT_DOMAIN "STAFF"
+#endif
+#define SMBLIB_DEFAULT_OSNAME "UNIX of some type"
+#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit"
+#define SMBLIB_MAX_XMIT 65535
+
+#define SMB_Sec_Mode_Share 0
+#define SMB_Sec_Mode_User  1
+
+/* A Tree_Structure                       */
+
+struct SMB_Tree_Structure {
+
+  SMB_Tree_Handle next, prev;
+  SMB_Handle_Type con;
+  char path[129];
+  char device_type[20];
+  int mbs;                   /* Local MBS */
+  int tid;
+
+};
+
+typedef struct SMB_File_Def SMB_File;
+
+struct SMB_File_Def {
+
+  SMB_Tree_Handle tree;
+  char filename[256];          /* We should malloc this ... */
+  UWORD fid;
+  unsigned int lastmod;
+  unsigned int size;           /* Could blow up if 64bit files supported */
+  UWORD access;
+  off_t fileloc;
+
+};
+
+/* global Variables for the library */
+
+extern SMB_State_Types SMBlib_State;
+
+#ifndef SMBLIB_ERRNO
+extern int SMBlib_errno;
+extern int SMBlib_SMB_Error;          /* last Error             */
+#endif
+
+SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type con, SMB_Tree_Handle tree,
+				char *path, char *password, char *dev);
+
+int SMB_Init();
+void SMB_Get_My_Name(char *name, int len);
+int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[]);
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle);
+
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
+                     char *PassWord, char *UserDomain, int precrypted);
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+int SMB_Get_Last_Error();
+
+#endif /* __SMBLIB_PRIV_H__ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smblib-util.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,819 @@
+/* UNIX SMBlib NetBIOS implementation
+
+   Version 1.0
+   SMBlib Utility Routines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "smblib-priv.h"
+#include <malloc.h>
+
+#include "rfcnb.h"
+
+/* global data structures */
+
+static int SMB_Types[] = {SMB_P_Core,
+                          SMB_P_CorePlus,
+                          SMB_P_DOSLanMan1,
+                          SMB_P_DOSLanMan1,
+                          SMB_P_LanMan1,
+                          SMB_P_DOSLanMan2,
+                          SMB_P_LanMan2,
+                          SMB_P_LanMan2_1,
+                          SMB_P_LanMan2_1,
+                          SMB_P_NT1,
+                          SMB_P_NT1,
+                          SMB_P_NT1,
+                          -1};
+
+static char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
+                            "MICROSOFT NETWORKS 1.03",
+                            "MICROSOFT NETWORKS 3.0",
+                            "DOS LANMAN1.0",
+                            "LANMAN1.0",
+                            "DOS LM1.2X002",
+                            "LM1.2X002",
+                            "DOS LANMAN2.1",
+                            "LANMAN2.1",
+                            "Samba",
+                            "NT LM 0.12",
+                            "NT LANMAN 1.0",
+                            NULL};
+
+/* Print out an SMB pkt in all its gory detail ... */
+
+void SMB_Print_Pkt(FILE fd, RFCNB_Pkt *pkt, BOOL command, int Offset, int Len)
+
+{
+
+  /* Well, just how do we do this ... print it I suppose */
+
+  /* Print out the SMB header ...                        */
+
+  /* Print the command                                   */
+
+  /* Print the other bits in the header                  */
+
+
+  /* etc                                                 */
+
+}
+
+/* Convert a DOS Date_Time to a local host type date time for printing */
+
+char *SMB_DOSTimToStr(int DOS_time)
+
+{ static char SMB_Time_Temp[48];
+  int DOS_sec, DOS_min, DOS_hour, DOS_day, DOS_month, DOS_year;
+
+  SMB_Time_Temp[0] = 0;
+
+  DOS_sec   = (DOS_time & 0x001F) * 2;
+  DOS_min   = (DOS_time & 0x07E0) >> 5;   
+  DOS_hour  = ((DOS_time & 0xF800) >> 11);
+
+  DOS_day   = (DOS_time & 0x001F0000) >> 16;
+  DOS_month = (DOS_time & 0x01E00000) >> 21;
+  DOS_year  = ((DOS_time & 0xFE000000) >> 25) + 80;
+
+  sprintf(SMB_Time_Temp, "%2d/%02d/%2d %2d:%02d:%02d", DOS_day, DOS_month,
+	                 DOS_year, DOS_hour, DOS_min, DOS_sec);
+
+  return(SMB_Time_Temp);
+
+}
+
+/* Convert an attribute byte/word etc to a string ... We return a pointer
+   to a static string which we guarantee is long enough. If verbose is 
+   true, we print out long form of strings ...                            */
+
+char *SMB_AtrToStr(int attribs, BOOL verbose)
+
+{ static char SMB_Attrib_Temp[128];
+
+  SMB_Attrib_Temp[0] = 0;
+
+  if (attribs & SMB_FA_ROF) 
+    strcat(SMB_Attrib_Temp, (verbose?"Read Only ":"R"));
+
+  if (attribs & SMB_FA_HID) 
+    strcat(SMB_Attrib_Temp, (verbose?"Hidden ":"H"));
+
+  if (attribs & SMB_FA_SYS) 
+    strcat(SMB_Attrib_Temp, (verbose?"System ":"S"));
+
+  if (attribs & SMB_FA_VOL) 
+    strcat(SMB_Attrib_Temp, (verbose?"Volume ":"V"));
+
+  if (attribs & SMB_FA_DIR) 
+    strcat(SMB_Attrib_Temp, (verbose?"Directory ":"D"));
+
+  if (attribs & SMB_FA_ARC) 
+    strcat(SMB_Attrib_Temp, (verbose?"Archive ":"A"));
+
+  return(SMB_Attrib_Temp);
+
+}
+
+/* Pick up the Max Buffer Size from the Tree Structure ... */
+
+int SMB_Get_Tree_MBS(SMB_Tree_Handle tree)
+
+{
+  if (tree != NULL) {
+    return(tree -> mbs);
+  }
+  else {
+    return(SMBlibE_BAD);
+  }
+}
+
+/* Pick up the Max buffer size */
+
+int SMB_Get_Max_Buf_Siz(SMB_Handle_Type Con_Handle)
+
+{
+  if (Con_Handle != NULL) {
+    return(Con_Handle -> max_xmit);
+  }
+  else {
+    return(SMBlibE_BAD);
+  }
+
+}
+/* Pickup the protocol index from the connection structure                 */
+
+int SMB_Get_Protocol_IDX(SMB_Handle_Type Con_Handle)
+
+{
+  if (Con_Handle != NULL) {
+    return(Con_Handle -> prot_IDX);
+  }
+  else {
+    return(0xFFFF);  /* Invalid protocol */
+  }
+
+}
+
+/* Pick up the protocol from the connection structure                       */
+
+int SMB_Get_Protocol(SMB_Handle_Type Con_Handle)
+
+{
+  if (Con_Handle != NULL) {
+    return(Con_Handle -> protocol);
+  }
+  else {
+    return(0xFFFF);  /* Invalid protocol */
+  }
+
+}
+
+/* Figure out what protocol was accepted, given the list of dialect strings */
+/* We offered, and the index back from the server. We allow for a user      */
+/* supplied list, and assume that it is a subset of our list                */
+
+int SMB_Figure_Protocol(char *dialects[], int prot_index)
+
+{ int i;
+
+  if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */
+
+    return(SMB_Types[prot_index]);
+  }
+  else { /* Search through SMB_Prots looking for a match */
+
+    for (i = 0; SMB_Prots[i] != NULL; i++) {
+
+      if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */
+
+	return(SMB_Types[i]);
+
+      }
+
+    }
+
+    /* If we got here, then we are in trouble, because the protocol was not */
+    /* One we understand ...                                                */
+
+    return(SMB_P_Unknown);
+
+  }
+
+}
+
+
+/* Negotiate the protocol we will use from the list passed in Prots       */
+/* we return the index of the accepted protocol in NegProt, -1 indicates  */
+/* none acceptible, and our return value is 0 if ok, <0 if problems       */
+
+int SMB_Negotiate(SMB_Handle_Type Con_Handle, char *Prots[])
+
+{
+  struct RFCNB_Pkt *pkt;
+  int prots_len, i, pkt_len, prot, alloc_len;
+  char *p;
+
+  /* Figure out how long the prot list will be and allocate space for it */
+
+  prots_len = 0;
+
+  for (i = 0; Prots[i] != NULL; i++) {
+
+    prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */
+
+  }
+
+  /* The -1 accounts for the one byte smb_buf we have because some systems */
+  /* don't like char msg_buf[]                                             */
+
+  pkt_len = SMB_negp_len + prots_len;
+
+  /* Make sure that the pkt len is long enough for the max response ...   */
+  /* Which is a problem, because the encryption key len eec may be long   */
+
+  if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
+
+    alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
+
+  }
+  else {
+
+    alloc_len = pkt_len;
+
+  }
+
+  pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len);
+
+  if (pkt == NULL) {
+
+    SMBlib_errno = SMBlibE_NoSpace;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Now plug in the bits we need */
+
+  bzero(SMB_Hdr(pkt), SMB_negp_len);
+  SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
+  *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+  *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+  SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
+
+  /* Now copy the prot strings in with the right stuff */
+
+  p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset);
+
+  for (i = 0; Prots[i] != NULL; i++) {
+
+    *p = SMBdialectID;
+    strcpy(p + 1, Prots[i]);
+    p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */
+
+  }
+
+  /* Now send the packet and sit back ... */
+
+  if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
+
+
+#ifdef DEBUG
+    fprintf(stderr, "Error sending negotiate protocol\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Now get the response ... */
+
+  if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) {
+
+#ifdef DEBUG
+    fprintf(stderr, "Error receiving response to negotiate\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */
+    return(SMBlibE_BAD);
+
+  }
+
+  if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
+
+#ifdef DEBUG
+    fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+    SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_Remote;
+    return(SMBlibE_BAD);
+
+  }
+  
+  if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
+
+#ifdef DEBUG
+    fprintf(stderr, "None of our protocols was accepted ... ");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_NegNoProt;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Now, unpack the info from the response, if any and evaluate the proto */
+  /* selected. We must make sure it is one we like ...                     */
+
+  Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
+  Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot);
+
+  if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_ProtUnknown;
+    return(SMBlibE_BAD);
+
+  }
+  
+  switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
+
+  case 0x01:      /* No more info ... */
+
+    break;
+
+  case 13:        /* Up to and including LanMan 2.1 */
+
+    Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
+    Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
+    Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
+
+    Con_Handle -> max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
+    Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
+    Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
+    Con_Handle -> Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
+    Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
+    Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
+    Con_Handle -> Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
+    
+    p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
+    fprintf(stderr, "%8s", (char *)(SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
+    memcpy(Con_Handle->Encrypt_Key, p, 8);
+
+    p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
+
+    strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
+
+    break;
+
+  case 17:        /* NT LM 0.12 and LN LM 1.0 */
+
+    Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
+    Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
+    Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
+
+    Con_Handle -> max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
+    Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
+    Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
+    Con_Handle -> MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
+    Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
+    Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
+    Con_Handle -> Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
+
+    p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset );
+    memcpy(Con_Handle -> Encrypt_Key, p, 8);
+    p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
+
+    strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
+
+    break;
+
+  default:
+
+#ifdef DEBUG
+    fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
+    fprintf(stderr, "  wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
+#endif
+
+    break;
+  }
+
+#ifdef DEBUG
+  fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
+#endif
+
+  RFCNB_Free_Pkt(pkt);
+  return(0);
+
+}
+
+/* Get our hostname */
+
+void SMB_Get_My_Name(char *name, int len)
+
+{ 
+
+  if (gethostname(name, len) < 0) { /* Error getting name */
+
+    strncpy(name, "unknown", len);
+
+    /* Should check the error */
+
+#ifdef DEBUG
+    fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
+    perror("");
+#endif
+
+  }
+
+  /* only keep the portion up to the first "." */
+
+
+}
+
+/* Send a TCON to the remote server ...               */
+
+SMB_Tree_Handle SMB_TreeConnect(SMB_Handle_Type Con_Handle, 
+				SMB_Tree_Handle Tree_Handle,
+				char *path, 
+				char *password,
+				char *device)
+
+{ struct RFCNB_Pkt *pkt;
+  int param_len, pkt_len;
+  char *p;
+  SMB_Tree_Handle tree;
+
+  /* Figure out how much space is needed for path, password, dev ... */
+
+  if ((path == NULL) || (password == NULL) || (device == NULL)) {
+
+#ifdef DEBUG
+    fprintf(stderr, "Bad parameter passed to SMB_TreeConnect\n");
+#endif
+
+    SMBlib_errno = SMBlibE_BadParam;
+    return(NULL);
+
+  }
+
+  /* The + 2 is because of the \0 and the marker ...                    */
+
+  param_len = strlen(path) + 2 + strlen(password) + 2 + strlen(device) + 2;
+
+  /* The -1 accounts for the one byte smb_buf we have because some systems */
+  /* don't like char msg_buf[]                                             */
+
+  pkt_len = SMB_tcon_len + param_len;
+
+  pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+  if (pkt == NULL) {
+
+    SMBlib_errno = SMBlibE_NoSpace;
+    return(NULL); /* Should handle the error */
+
+  }
+
+  /* Now allocate a tree for this to go into ... */
+
+  if (Tree_Handle == NULL) {
+
+    tree = (SMB_Tree_Handle)malloc(sizeof(struct SMB_Tree_Structure));
+
+    if (tree == NULL) {
+    
+      RFCNB_Free_Pkt(pkt);
+      SMBlib_errno = SMBlibE_NoSpace;
+      return(NULL);
+      
+    }
+  }
+  else {
+
+    tree = Tree_Handle;
+
+  }
+
+  tree -> next = tree -> prev = NULL;
+  tree -> con = Con_Handle;
+  strncpy(tree -> path, path, sizeof(tree -> path));
+  strncpy(tree -> device_type, device, sizeof(tree -> device_type));
+
+  /* Now plug in the values ... */
+
+  bzero(SMB_Hdr(pkt), SMB_tcon_len);
+  SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
+  *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtcon;
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+  *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+  SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, param_len);
+
+  /* Now copy the param strings in with the right stuff */
+
+  p = (char *)(SMB_Hdr(pkt) + SMB_tcon_buf_offset);
+  *p = SMBasciiID;
+  strcpy(p + 1, path);
+  p = p + strlen(path) + 2;
+  *p = SMBasciiID;
+  strcpy(p + 1, password);
+  p = p + strlen(password) + 2;
+  *p = SMBasciiID;
+  strcpy(p + 1, device);
+
+  /* Now send the packet and sit back ... */
+
+  if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
+
+#ifdef DEBUG
+    fprintf(stderr, "Error sending TCon request\n");
+#endif
+
+    if (Tree_Handle == NULL)
+      free(tree);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_SendFailed;
+    return(NULL);
+
+  }
+
+  /* Now get the response ... */
+
+  if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+    fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+    if (Tree_Handle == NULL) 
+      free(tree);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_RecvFailed;
+    return(NULL);
+
+  }
+
+  /* Check out the response type ... */
+
+  if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
+
+#ifdef DEBUG
+    fprintf(stderr, "SMB_TCon failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+    if (Tree_Handle == NULL)
+      free(tree);
+    SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_Remote;
+    return(NULL);
+
+  }
+
+  tree -> tid = SVAL(SMB_Hdr(pkt), SMB_tconr_tid_offset);
+  tree -> mbs = SVAL(SMB_Hdr(pkt), SMB_tconr_mbs_offset);
+
+#ifdef DEBUG
+  fprintf(stderr, "TConn succeeded, with TID=%i, Max Xmit=%i\n",
+                 tree -> tid, tree -> mbs);
+#endif
+
+  /* Now link the Tree to the Server Structure ... */
+
+  if (Con_Handle -> first_tree == NULL) {
+
+    Con_Handle -> first_tree = tree;
+    Con_Handle -> last_tree = tree;
+
+  }
+  else {
+
+    Con_Handle -> last_tree -> next = tree;
+    tree -> prev = Con_Handle -> last_tree;
+    Con_Handle -> last_tree = tree;
+
+  }
+
+  RFCNB_Free_Pkt(pkt);
+  return(tree); 
+
+}
+
+int SMB_TreeDisconnect(SMB_Tree_Handle Tree_Handle, BOOL discard)
+
+{ struct RFCNB_Pkt *pkt;
+  int pkt_len;
+
+  pkt_len = SMB_tdis_len;
+
+  pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+  if (pkt == NULL) {
+
+    SMBlib_errno = SMBlibE_NoSpace;
+    return(SMBlibE_BAD); /* Should handle the error */
+
+  }
+
+  /* Now plug in the values ... */
+
+  bzero(SMB_Hdr(pkt), SMB_tdis_len);
+  SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
+  *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBtdis;
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Tree_Handle -> con -> pid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Tree_Handle -> con -> mid);
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Tree_Handle -> con -> uid);
+  *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
+
+  SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, Tree_Handle -> tid);
+  SSVAL(SMB_Hdr(pkt), SMB_tcon_bcc_offset, 0);
+
+  /* Now send the packet and sit back ... */
+
+  if (RFCNB_Send(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0){
+
+#ifdef DEBUG
+    fprintf(stderr, "Error sending TDis request\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_SendFailed;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Now get the response ... */
+
+  if (RFCNB_Recv(Tree_Handle -> con -> Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+    fprintf(stderr, "Error receiving response to TCon\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = -SMBlibE_RecvFailed;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Check out the response type ... */
+
+  if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
+
+#ifdef DEBUG
+    fprintf(stderr, "SMB_TDis failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+    SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_Remote;
+    return(SMBlibE_BAD);
+
+  }
+
+  Tree_Handle -> tid = 0xFFFF;        /* Invalid TID */
+  Tree_Handle -> mbs = 0;             /* Invalid     */
+
+#ifdef DEBUG
+
+  fprintf(stderr, "Tree disconnect successful ...\n");
+
+#endif
+
+  /* What about the tree handle ? */
+
+  if (discard == TRUE) { /* Unlink it and free it ... */
+
+    if (Tree_Handle -> next == NULL)
+      Tree_Handle -> con -> first_tree = Tree_Handle -> prev;
+    else
+      Tree_Handle -> next -> prev = Tree_Handle -> prev;
+
+    if (Tree_Handle -> prev == NULL)
+      Tree_Handle -> con -> last_tree = Tree_Handle -> next;
+    else
+      Tree_Handle -> prev -> next = Tree_Handle -> next;
+
+  }
+
+  RFCNB_Free_Pkt(pkt);
+  return(0);
+
+}
+
+/* Pick up the last LMBlib error ... */
+
+int SMB_Get_Last_Error()
+
+{
+
+  return(SMBlib_errno);
+
+}
+
+/* Pick up the last error returned in an SMB packet          */
+/* We will need macros to extract error class and error code */
+
+int SMB_Get_Last_SMB_Err()
+
+{
+
+  return(SMBlib_SMB_Error);
+
+}
+
+/* Pick up the error message associated with an error from SMBlib  */
+
+/* Keep this table in sync with the message codes in smblib-common.h */
+
+static char *SMBlib_Error_Messages[] = {
+
+  "Request completed sucessfully.",
+  "Server returned a non-zero SMB Error Class and Code.",
+  "A lower layer protocol error occurred.",
+  "Function not yet implemented.",
+  "The protocol negotiated does not support the request.",
+  "No space available for operation.",
+  "One or more bad parameters passed.",
+  "None of the protocols we offered were accepted.",
+  "The attempt to send an SMB request failed. See protocol error info.",
+  "The attempt to get an SMB response failed. See protocol error info.",
+  "The logon request failed, but you were logged in as guest.",
+  "The attempt to call the remote server failed. See protocol error info.",
+  "The protocol dialect specified in a NegProt and accepted by the server is unknown.",
+  /* This next one simplifies error handling */
+  "No such error code.",
+  NULL};
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len)
+
+{
+
+  if (msg >= 0) {
+
+    strncpy(msgbuf, 
+	    SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg],
+	    len - 1);
+    msgbuf[len - 1] = 0; /* Make sure it is a string */
+  }
+  else { /* Add the lower layer message ... */
+
+    char prot_msg[1024];
+
+    msg = -msg;   /* Make it positive */
+
+    strncpy(msgbuf,
+	    SMBlib_Error_Messages[msg>SMBlibE_NoSuchMsg?SMBlibE_NoSuchMsg:msg],
+	    len - 1);
+
+    msgbuf[len - 1] = 0; /* make sure it is a string */
+
+    if (strlen(msgbuf) < len) { /* If there is space, put rest in */
+
+      strncat(msgbuf, "\n\t", len - strlen(msgbuf));
+
+      RFCNB_Get_Error(prot_msg, sizeof(prot_msg) - 1);
+
+      strncat(msgbuf, prot_msg, len - strlen(msgbuf));
+
+    }
+  }
+  return 0;
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smblib.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,586 @@
+/* UNIX SMBlib NetBIOS implementation
+
+   Version 1.0
+   SMBlib Routines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "config.h"
+#include <malloc.h>
+#include <ctype.h>
+
+int SMBlib_errno;
+int SMBlib_SMB_Error;
+#define SMBLIB_ERRNO
+#define uchar unsigned char
+#include "smblib-priv.h"
+
+#include "rfcnb.h"
+#include "smbencrypt.h"
+
+#include <signal.h>
+
+#define DEBUG
+
+SMB_State_Types SMBlib_State;
+
+/* Initialize the SMBlib package     */
+
+int SMB_Init()
+
+{
+
+  SMBlib_State = SMB_State_Started;
+
+  signal(SIGPIPE, SIG_IGN);   /* Ignore these ... */
+
+/* If SMBLIB_Instrument is defines, turn on the instrumentation stuff */
+#ifdef SMBLIB_INSTRUMENT
+
+  SMBlib_Instrument_Init();
+
+#endif
+
+  return 0;
+
+}
+
+int SMB_Term()
+
+{
+
+#ifdef SMBLIB_INSTRUMENT
+
+  SMBlib_Instrument_Term();       /* Clean up and print results */
+
+#endif
+
+  return 0;
+
+}
+
+/* SMB_Create: Create a connection structure and return for later use */
+/* We have other helper routines to set variables                     */
+
+SMB_Handle_Type SMB_Create_Con_Handle()
+
+{
+
+  SMBlib_errno = SMBlibE_NotImpl;
+  return(NULL);
+
+}
+
+int SMBlib_Set_Sock_NoDelay(SMB_Handle_Type Con_Handle, BOOL yn)
+
+{
+
+
+  if (RFCNB_Set_Sock_NoDelay(Con_Handle -> Trans_Connect, yn) < 0) {
+
+#ifdef DEBUG
+#endif
+
+    fprintf(stderr, "Setting no-delay on TCP socket failed ...\n");
+
+  }
+
+  return(0);
+
+}
+
+/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
+/* or anything else ...                                                  */
+
+SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
+				   char *server, char *NTdomain)
+
+{ SMB_Handle_Type con;
+  char called[80], calling[80], *address;
+  int i;
+
+  /* Get a connection structure if one does not exist */
+
+  con = Con_Handle;
+
+  if (Con_Handle == NULL) {
+
+    if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+
+      SMBlib_errno = SMBlibE_NoSpace;
+      return NULL;
+    }
+
+  }
+
+  /* Init some things ... */
+
+  strcpy(con -> service, "");
+  strcpy(con -> username, "");
+  strcpy(con -> password, "");
+  strcpy(con -> sock_options, "");
+  strcpy(con -> address, "");
+  strcpy(con -> desthost, server);
+  strcpy(con -> PDomain, NTdomain);
+  strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
+  strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
+  con -> first_tree = con -> last_tree = NULL; 
+
+  /* ugh. This is horribly broken. */
+/*   SMB_Get_My_Name(con -> myname, sizeof(con -> myname)); */
+	/* hacked by Kinkie */
+	i=gethostname(con->myname,sizeof(con->myname));
+	if (i==-1)
+        {
+		strcpy(con->myname,"unknown");
+        }
+	else {
+		if (NULL!=(address=strchr(con->myname,'.'))) {
+			*address='\0';						/* truncate at first '.' */
+		}
+	}
+	
+
+  con -> port = 0;                    /* No port selected */
+
+  /* Get some things we need for the SMB Header */
+
+  con -> pid = getpid();
+  con -> mid = con -> pid;      /* This will do for now ... */
+  con -> uid = 0;               /* Until we have done a logon, no uid ... */ 
+  con -> gid = getgid();
+
+  /* Now connect to the remote end, but first upper case the name of the
+     service we are going to call, sine some servers want it in uppercase */
+
+  for (i=0; i < strlen(server); i++)
+    called[i] = toupper(server[i]);
+		       
+  called[strlen(server)] = 0;    /* Make it a string */
+
+  for (i=0; i < strlen(con -> myname); i++)
+    calling[i] = toupper(con -> myname[i]);
+		       
+  calling[strlen(con -> myname)] = 0;    /* Make it a string */
+
+  if (strcmp(con -> address, "") == 0)
+    address = con -> desthost;
+  else
+    address = con -> address;
+
+  con -> Trans_Connect = RFCNB_Call(called,
+				    calling,
+				    address, /* Protocol specific */
+				    con -> port);
+
+  /* Did we get one? */
+
+  if (con -> Trans_Connect == NULL) {
+
+    if (Con_Handle == NULL) {
+      Con_Handle = NULL;
+      free(con);
+    }
+    SMBlib_errno = -SMBlibE_CallFailed;
+    return NULL;
+
+  }
+
+  return(con);
+
+}
+
+/* SMB_Connect: Connect to the indicated server                       */
+/* If Con_Handle == NULL then create a handle and connect, otherwise  */
+/* use the handle passed                                              */
+
+char *SMB_Prots_Restrict[] = {"PC NETWORK PROGRAM 1.0",
+			      NULL};
+
+
+SMB_Handle_Type SMB_Connect(SMB_Handle_Type Con_Handle,
+			    SMB_Tree_Handle *tree,
+			    char *service, 
+			    char *username, 
+			    char *password)
+
+{ SMB_Handle_Type con;
+  char *host, *address;
+  char temp[80], called[80], calling[80];
+  int i;
+
+  /* Get a connection structure if one does not exist */
+
+  con = Con_Handle;
+
+  if (Con_Handle == NULL) {
+
+    if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
+
+      SMBlib_errno = SMBlibE_NoSpace;
+      return NULL;
+    }
+
+  }
+
+  /* Init some things ... */
+
+  strcpy(con -> service, service);
+  strcpy(con -> username, username);
+  strcpy(con -> password, password);
+  strcpy(con -> sock_options, "");
+  strcpy(con -> address, "");
+  strcpy(con -> PDomain, SMBLIB_DEFAULT_DOMAIN);
+  strcpy(con -> OSName, SMBLIB_DEFAULT_OSNAME);
+  strcpy(con -> LMType, SMBLIB_DEFAULT_LMTYPE);
+  con -> first_tree = con -> last_tree = NULL;
+
+  SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
+
+  con -> port = 0;                    /* No port selected */
+
+  /* Get some things we need for the SMB Header */
+
+  con -> pid = getpid();
+  con -> mid = con -> pid;      /* This will do for now ... */
+  con -> uid = 0;               /* Until we have done a logon, no uid */
+  con -> gid = getgid();
+
+  /* Now figure out the host portion of the service */
+
+  strcpy(temp, service);
+  host = (char *)strtok(temp, "/\\");     /* Separate host name portion */
+  strcpy(con -> desthost, host);
+
+  /* Now connect to the remote end, but first upper case the name of the
+     service we are going to call, sine some servers want it in uppercase */
+
+  for (i=0; i < strlen(host); i++)
+    called[i] = toupper(host[i]);
+		       
+  called[strlen(host)] = 0;    /* Make it a string */
+
+  for (i=0; i < strlen(con -> myname); i++)
+    calling[i] = toupper(con -> myname[i]);
+		       
+  calling[strlen(con -> myname)] = 0;    /* Make it a string */
+
+  if (strcmp(con -> address, "") == 0)
+    address = con -> desthost;
+  else
+    address = con -> address;
+
+  con -> Trans_Connect = RFCNB_Call(called,
+				    calling,
+				    address, /* Protocol specific */
+				    con -> port);
+
+  /* Did we get one? */
+
+  if (con -> Trans_Connect == NULL) {
+
+    if (Con_Handle == NULL) {
+      free(con);
+      Con_Handle = NULL;
+    }
+    SMBlib_errno = -SMBlibE_CallFailed;
+    return NULL;
+
+  }
+
+  /* Now, negotiate the protocol */
+
+  if (SMB_Negotiate(con, SMB_Prots_Restrict) < 0) {
+
+    /* Hmmm what should we do here ... We have a connection, but could not
+       negotiate ...                                                      */
+
+    return NULL;
+
+  }
+
+  /* Now connect to the service ... */
+
+  if ((*tree = SMB_TreeConnect(con, NULL, service, password, "A:")) == NULL) {
+
+    return NULL;
+
+  }
+
+  return(con);
+
+}
+
+/* Logon to the server. That is, do a session setup if we can. We do not do */
+/* Unicode yet!                                                             */
+
+int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName, 
+		     char *PassWord, char *UserDomain, int precrypted)
+
+{ struct RFCNB_Pkt *pkt;
+  int param_len, pkt_len, pass_len;
+  char *p, pword[128];
+
+  /* First we need a packet etc ... but we need to know what protocol has  */
+  /* been negotiated to figure out if we can do it and what SMB format to  */
+  /* use ...                                                               */
+
+  if (Con_Handle -> protocol < SMB_P_LanMan1) {
+
+    SMBlib_errno = SMBlibE_ProtLow;
+    return(SMBlibE_BAD);
+
+  }
+
+  if (precrypted) {
+      pass_len=24;
+      memcpy(pword, PassWord, 24);
+  } else {
+      strcpy(pword, PassWord);
+      if (Con_Handle -> encrypt_passwords)
+      {
+          pass_len=24;
+          SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
+      } else pass_len=strlen(pword);
+  }
+
+  /* Now build the correct structure */
+
+  if (Con_Handle -> protocol < SMB_P_NT1) {
+
+    param_len = strlen(UserName) + 1 + pass_len + 1 + 
+                strlen(UserDomain) + 1 + 
+	        strlen(Con_Handle -> OSName) + 1;
+
+    pkt_len = SMB_ssetpLM_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+      SMBlib_errno = SMBlibE_NoSpace;
+      fprintf(stderr,"SMB_Logon_server: Couldn't allocate packet\n");
+      return(SMBlibE_BAD); /* Should handle the error */
+    }
+
+    bzero(SMB_Hdr(pkt), SMB_ssetpLM_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
+    *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid);
+    SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
+    SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
+
+    /* Copy  in password, then the rest. Password has a null at end */
+
+    memcpy(p, pword, pass_len);
+
+    p = p + pass_len + 1;
+
+    strcpy(p, UserName);
+    p = p + strlen(UserName);
+    *p = 0;
+
+    p = p + 1;
+
+    strcpy(p, UserDomain);
+    p = p + strlen(UserDomain);
+    *p = 0;
+    p = p + 1;
+
+    strcpy(p, Con_Handle -> OSName);
+    p = p + strlen(Con_Handle -> OSName);
+    *p = 0;
+
+  }
+  else {
+
+    /* We don't admit to UNICODE support ... */
+
+    param_len = strlen(UserName) + 1 + pass_len + 
+                strlen(UserDomain) + 1 + 
+	        strlen(Con_Handle -> OSName) + 1 +
+		strlen(Con_Handle -> LMType) + 1;
+
+    pkt_len = SMB_ssetpNTLM_len + param_len;
+
+    pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
+
+    if (pkt == NULL) {
+
+      SMBlib_errno = SMBlibE_NoSpace;
+      fprintf(stderr,"SMB_Logon_server: Couldn't allocate packet\n");
+      return(-1); /* Should handle the error */
+    }
+
+    bzero(SMB_Hdr(pkt), SMB_ssetpNTLM_len);
+    SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF);  /* Plunk in IDF */
+    *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
+    *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
+    *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF;    /* No extra command */
+    SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
+
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
+    SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
+    SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
+    SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
+    SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
+
+    /* Now copy the param strings in with the right stuff */
+
+    p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
+
+    /* Copy  in password, then the rest. Password has no null at end */
+
+    memcpy(p, pword, pass_len);
+
+    p = p + pass_len;
+
+    strcpy(p, UserName);
+    p = p + strlen(UserName);
+    *p = 0;
+
+    p = p + 1;
+
+    strcpy(p, UserDomain);
+    p = p + strlen(UserDomain);
+  *p = 0;
+    p = p + 1;
+
+    strcpy(p, Con_Handle -> OSName);
+    p = p + strlen(Con_Handle -> OSName);
+    *p = 0;
+    p = p + 1;
+
+    strcpy(p, Con_Handle -> LMType);
+    p = p + strlen(Con_Handle -> LMType);
+    *p = 0;
+
+  }
+
+  /* Now send it and get a response */
+
+  if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
+
+#ifdef DEBUG
+    fprintf(stderr, "Error sending SessSetupX request\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_SendFailed;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Now get the response ... */
+
+  if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
+
+#ifdef DEBUG
+    fprintf(stderr, "Error receiving response to SessSetupAndX\n");
+#endif
+
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_RecvFailed;
+    return(SMBlibE_BAD);
+
+  }
+
+  /* Check out the response type ... */
+
+  if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) {  /* Process error */
+
+#ifdef DEBUG
+    fprintf(stderr, "SMB_SessSetupAndX failed with errorclass = %i, Error Code = %i\n",
+	    CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
+	    SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
+#endif
+
+    SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
+    RFCNB_Free_Pkt(pkt);
+    SMBlib_errno = SMBlibE_Remote;
+    return(SMBlibE_BAD);
+
+  }
+/** @@@ mdz: check for guest login { **/
+       if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
+       {
+               /* do we allow guest login? NO! */
+               return(SMBlibE_BAD);
+ 
+       }
+ /** @@@ mdz: } **/
+
+
+#ifdef DEBUG
+  fprintf(stderr, "SessSetupAndX response. Action = %i\n", 
+          SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset));
+#endif
+
+  /* Now pick up the UID for future reference ... */
+
+  Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
+  RFCNB_Free_Pkt(pkt);
+
+  return(0);
+
+}
+
+
+/* Disconnect from the server, and disconnect all tree connects */
+
+int SMB_Discon(SMB_Handle_Type Con_Handle, BOOL KeepHandle)
+
+{
+
+  /* We just disconnect the connection for now ... */
+  if(Con_Handle!=NULL)  RFCNB_Hangup(Con_Handle -> Trans_Connect);
+
+  if (!KeepHandle)
+    free(Con_Handle);
+
+  return(0);
+
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/smblib.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,98 @@
+/* UNIX SMBlib NetBIOS implementation
+
+   Version 1.0
+   SMBlib Defines
+
+   Copyright (C) Richard Sharpe 1996
+
+*/
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "std-defines.h"
+#include "smblib-common.h"
+
+/* Just define all the entry points */
+
+/* Create a handle to allow us to set/override some parameters ...       */
+
+void *SMB_Create_Con_Handle();
+
+/* Connect to a server, but do not do a tree con etc ... */
+
+void *SMB_Connect_Server(void *Con, char *server, char *NTdomain);
+
+/* Connect to a server and give us back a handle. If Con == NULL, create */
+/* The handle and populate it with defaults                              */
+
+void *SMB_Connect(void *Con, void **tree, 
+		  char *name, char *User, char *Password);
+
+/* Negotiate a protocol                                                  */
+
+int SMB_Negotiate(void *Con_Handle, char *Prots[]);
+
+/* Connect to a tree ...                                                 */
+
+void *SMB_TreeConnect(void *con_handle, void *tree_handle, 
+		      char *path, char *password, char *dev);
+
+/* Disconnect a tree ...                                                 */
+
+int SMB_TreeDisconect(void *tree_handle);
+
+/* Open a file                                                           */
+
+void *SMB_Open(void *tree_handle,
+	       void *file_handle,
+	       char *file_name,
+	       unsigned short mode,
+	       unsigned short search); 
+
+/* Close a file                                                          */
+
+int SMB_Close(void *file_handle);
+
+/* Disconnect from server. Has flag to specify whether or not we keep the */
+/* handle.                                                                */
+
+int SMB_Discon(void *Con, BOOL KeepHandle);
+
+void *SMB_Create(void *Tree_Handle,
+	       void *File_Handle, 
+	       char *file_name, 
+  	       short search);
+
+int SMB_Delete(void *tree, char *file_name, short search);
+
+int SMB_Create_Dir(void *tree, char *dir_name);
+
+int SMB_Delete_Dir(void *tree, char *dir_name);
+
+int SMB_Check_Dir(void *tree, char *dir_name);
+
+int SMB_Get_Last_Error();
+
+int SMB_Get_Last_SMB_Err();
+
+int SMB_Get_Error_Msg(int msg, char *msgbuf, int len);
+
+void *SMB_Logon_And_TCon(void *con, void *tree, char *user, char *pass,
+			 char *service, char *st);
+
+
+#define SMBLIB_DEFAULT_DOMAIN "anydom"
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/std-defines.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,45 @@
+#ifndef __STD_DEFINES__
+#define __STD_DEFINES__
+
+/* RFCNB Standard includes ... */
+/*
+
+   SMBlib Standard Includes
+
+   Copyright (C) 1996, Richard Sharpe
+
+   One day we will conditionalize these on OS types ... */
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#endif /* __STD_DEFINES__ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/std-includes.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,45 @@
+/* RFCNB Standard includes ... */
+/*
+
+   RFCNB Standard Includes
+
+   Copyright (C) 1996, Richard Sharpe
+
+ One day we will conditionalize these on OS types ... */
+
+/*
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define BOOL int
+typedef short int16;
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define TRUE 1
+#define FALSE 0
+
+/* Pick up define for INADDR_NONE */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/valid.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,104 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include "smblib-priv.h"
+#include "valid.h"
+
+SMB_Handle_Type SMB_Connect_Server(void *, char *, char *);
+
+int Valid_User(char *USERNAME,char *PASSWORD,char *SERVER,char *BACKUP, char *DOMAIN)
+{
+	int pass_is_precrypted_p=0;
+  char *SMB_Prots[] = {
+/* 		"PC NETWORK PROGRAM 1.0", */
+/* 		"MICROSOFT NETWORKS 1.03", */
+/* 		"MICROSOFT NETWORKS 3.0", */
+		"LANMAN1.0",
+		"LM1.2X002",
+		"Samba",
+/* 		"NT LM 0.12", */
+/* 		"NT LANMAN 1.0", */
+		NULL};
+  SMB_Handle_Type con;
+
+  SMB_Init();
+  con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+  if (con == NULL) { /* Error ... */
+   con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+   if (con == NULL) {
+   	return(NTV_SERVER_ERROR);   
+   }
+  }
+  if (SMB_Negotiate(con, SMB_Prots) < 0) { /* An error */
+    SMB_Discon(con,0);
+    return(NTV_PROTOCOL_ERROR);
+  }
+  /* Test for a server in share level mode do not authenticate against it */
+  if (con -> Security == 0)
+    {
+      SMB_Discon(con,0);
+      return(NTV_PROTOCOL_ERROR);
+    }
+
+  if (SMB_Logon_Server(con, USERNAME, PASSWORD, DOMAIN, pass_is_precrypted_p) < 0) {
+    SMB_Discon(con,0);
+    return(NTV_LOGON_ERROR);
+  }
+  
+  SMB_Discon(con,0);
+  return(NTV_NO_ERROR);
+}
+
+void *NTLM_Connect(char *SERVER,char *BACKUP, char *DOMAIN, char *nonce)
+{
+  char *SMB_Prots[] = {
+/* 		"PC NETWORK PROGRAM 1.0", */
+/* 		"MICROSOFT NETWORKS 1.03", */
+/* 		"MICROSOFT NETWORKS 3.0", */
+		"LANMAN1.0",
+		"LM1.2X002",
+		"Samba",
+/* 		"NT LM 0.12", */
+/* 		"NT LANMAN 1.0", */
+		NULL};
+  SMB_Handle_Type con;
+
+  SMB_Init();
+  con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
+  if (con == NULL) { /* Error ... */
+   con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
+   if (con == NULL) {
+   	return(NULL);
+   }
+  }
+  if (SMB_Negotiate(con, SMB_Prots) < 0) { /* An error */
+    SMB_Discon(con,0);
+    return(NULL);
+  }
+  /* Test for a server in share level mode do not authenticate against it */
+  if (con -> Security == 0)
+    {
+      SMB_Discon(con,0);
+      return(NULL);
+    }
+
+  memcpy(nonce, con -> Encrypt_Key, 8);
+     
+  return (con);
+}
+
+int NTLM_Auth(void *handle, char *USERNAME,char *PASSWORD,int flag)
+{
+  SMB_Handle_Type con = handle;
+
+  if (SMB_Logon_Server(con, USERNAME, PASSWORD, NULL, flag) < 0) {
+    return(NTV_LOGON_ERROR);
+  }
+  return(NTV_NO_ERROR);
+}
+
+void NTLM_Disconnect(void *handle)
+{
+  SMB_Handle_Type con = handle;
+  SMB_Discon(con,0);
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/NTLMSSP/smbval/valid.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,15 @@
+#ifndef _VALID_H_
+#define _VALID_H_
+/* SMB User verification function */
+
+#define NTV_NO_ERROR 0
+#define NTV_SERVER_ERROR 1
+#define NTV_PROTOCOL_ERROR 2
+#define NTV_LOGON_ERROR 3
+
+int Valid_User(char *USERNAME,char *PASSWORD,char *SERVER, char *BACKUP, char *DOMAIN);
+void *NTLM_Connect(char *SERVER, char *BACKUP, char *DOMAIN, char *nonce);
+int NTLM_Auth(void *handle, char *USERNAME,char *PASSWORD, int flag);
+void NTLM_Disconnect(void *handle);
+
+#endif
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/fakeauth/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,80 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1.2.1.2.2 2001/01/07 02:49:32 rbcollins Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix		= @prefix@
+exec_prefix	= @exec_prefix@
+exec_suffix	= @exec_suffix@
+top_srcdir	= @top_srcdir@
+bindir		= @bindir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+# Gotta love the DOS legacy
+#
+FAKEAUTH_AUTH_EXE	= fakeauth_auth$(exec_suffix)
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+INSTALL		= @INSTALL@
+INSTALL_BIN	= @INSTALL_PROGRAM@
+CRYPTLIB	= @CRYPTLIB@
+AC_CFLAGS	= @CFLAGS@
+LDFLAGS		= @LDFLAGS@
+XTRA_LIBS	= @XTRA_LIBS@
+XTRA_OBJS	= @XTRA_OBJS@
+MV		= @MV@
+RM		= @RM@
+SHELL		= /bin/sh
+
+
+INCLUDE		= -I. -I../../include -I$(top_srcdir)/include
+CFLAGS		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS	= -L../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS		= $(FAKEAUTH_AUTH_EXE)
+OBJS		= fakeauth_auth.o
+
+all:    $(FAKEAUTH_AUTH_EXE)
+
+$(OBJS): $(top_srcdir)/include/version.h
+
+$(FAKEAUTH_AUTH_EXE): $(OBJS)
+	$(CC) $(LDFLAGS) $(OBJS) -o $@ $(AUTH_LIBS)
+
+install-mkdirs:
+	-@if test ! -d $(prefix); then \
+		echo "mkdir $(prefix)"; \
+		mkdir $(prefix); \
+	fi
+	-@if test ! -d $(bindir); then \
+		echo "mkdir $(bindir)"; \
+		mkdir $(bindir); \
+	fi
+
+install: all install-mkdirs
+	@for f in $(PROGS); do \
+		if test -f $(bindir)/$$f; then \
+			echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+			$(MV) $(bindir)/$$f $(bindir)/-$$f; \
+		fi; \
+		echo $(INSTALL_BIN) $$f $(bindir); \
+		$(INSTALL_BIN) $$f $(bindir); \
+		if test -f $(bindir)/-$$f; then \
+			echo $(RM) -f $(bindir)/-$$f; \
+			$(RM) -f $(bindir)/-$$f; \
+		fi; \
+	done
+
+clean: 
+	-rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+	-rm -f Makefile
+
+depend:
+	$(MAKEDEPEND) -I../include -I. -fMakefile *.c
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/fakeauth/fakeauth_auth.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,342 @@
+/*
+ *
+ * AUTHOR: Robert Collins <rbtcollins@hotmail.com>
+ *
+ * Example ntlm authentication program for Squid, based on the
+ * original proxy_auth code from client_side.c, written by
+ * Jon Thackray <jrmt@uk.gdscorp.com>. and the inital ntlm code
+ * Andy Doran.
+ *
+ * This code gets the username and returns it. No validation is done.
+ * and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP
+ * if you can.
+ */
+
+#include "config.h"
+
+#include "ntlm.h"
+#include "util.h"
+#include <ctype.h>
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+
+#define ERR    "ERR\n"
+#define OK     "OK\n"
+
+#if 0
+#define NTLM_STATIC_CHALLENGE "deadbeef"
+#endif
+static char *authenticate_ntlm_domain = "LIFELESSWKS";
+
+/* NTLM authentication by ad@netbsd.org - 07/1999 */
+/* XXX this is not done cleanly... */
+
+/* makes a null-terminated string lower-case. Changes CONTENTS! */
+static void
+lc (char *string)
+{
+  char *p = string, c;
+  while ((c = *p))
+    {
+      *p = tolower (c);
+      p++;
+    }
+}
+
+
+/*
+ * Generates a challenge request. The randomness of the 8 byte 
+ * challenge strings can be guarenteed to be poor at best.
+ */
+void
+ntlmMakeChallenge (struct ntlm_challenge *chal)
+{
+#ifndef NTLM_STATIC_CHALLENGE
+  static unsigned hash;
+  int r;
+#endif
+  char *d;
+  int i;
+
+  memset (chal, 0, sizeof (*chal));
+  memcpy (chal->hdr.signature, "NTLMSSP", 8);
+  chal->flags = WSWAP (0x00018206);
+  chal->hdr.type = WSWAP (NTLM_CHALLENGE);
+  chal->unknown[6] = SSWAP (0x003a);
+
+  d = (char *) chal + 48;
+  i = 0;
+
+  if (authenticate_ntlm_domain != NULL)
+    while (authenticate_ntlm_domain[i++]);
+
+
+  chal->target.offset = WSWAP (48);
+  chal->target.maxlen = SSWAP (i);
+  chal->target.len = chal->target.maxlen;
+
+#ifdef NTLM_STATIC_CHALLENGE
+  memcpy (chal->challenge, NTLM_STATIC_CHALLENGE, 8);
+#else
+  r = (int) rand ();
+  r = (hash ^ r) + r;
+
+  for (i = 0; i < 8; i++)
+    {
+      chal->challenge[i] = r;
+      r = (r >> 2) ^ r;
+    }
+
+  hash = r;
+#endif
+}
+
+/*
+ * Check the vailidity of a request header. Return -1 on error.
+ */
+int
+ntlmCheckHeader (struct ntlmhdr *hdr, int type)
+{
+  /* 
+   * Must be the correct security package and request type. The
+   * 8 bytes compared includes the ASCII 'NUL'. 
+   */
+  if (memcmp (hdr->signature, "NTLMSSP", 8) != 0)
+    {
+      fprintf (stderr, "ntlmCheckHeader: bad header signature\n");
+      return (-1);
+    }
+
+  if (type == NTLM_ANY)
+    return 0;
+
+  if (WSWAP (hdr->type) != type)
+    {
+/* don't report this error - it's ok as we do a if() around this function */
+//      fprintf(stderr, "ntlmCheckHeader: type is %d, wanted %d\n",
+//          WSWAP(hdr->type), type);
+      return (-1);
+    }
+
+  return (0);
+}
+
+/*
+ * Extract a string from an NTLM request and return as ASCII.
+ */
+char *
+ntlmGetString (ntlmhdr * hdr, strhdr * str, int flags)
+{
+  static char buf[512];
+  u_short *s, c;
+  char *d, *sc;
+  int l, o;
+
+  l = SSWAP (str->len);
+  o = WSWAP (str->offset);
+
+  /* Sanity checks. XXX values arbitrarialy chosen */
+  if (l <= 0 || l >= 32 || o >= 256)
+    {
+      fprintf (stderr, "ntlmGetString: insane: l:%d o:%d\n", l, o);
+      return (NULL);
+    }
+
+  if ((flags & 2) == 0)
+    {
+      /* UNICODE string */
+      s = (u_short *) ((char *) hdr + o);
+      d = buf;
+
+      for (l >>= 1; l; s++, l--)
+	{
+	  c = SSWAP (*s);
+	  if (c > 254 || c == '\0' || !isprint (c))
+	    {
+	      fprintf (stderr, "ntlmGetString: bad uni: %04x\n", c);
+	      return (NULL);
+	    }
+	  *d++ = c;
+	  fprintf (stderr, "ntlmGetString: conv: '%c'\n", c);
+	}
+
+      *d = 0;
+    }
+  else
+    {
+      /* ASCII string */
+      sc = (char *) hdr + o;
+      d = buf;
+
+      for (; l; l--)
+	{
+	  if (*sc == '\0' || !isprint (*sc))
+	    {
+	      fprintf (stderr, "ntlmGetString: bad ascii: %04x\n", *sc);
+	      return (NULL);
+	    }
+	  *d++ = *sc++;
+	}
+
+      *d = 0;
+    }
+
+  return (buf);
+}
+
+/*
+ * Decode the strings in an NTLM authentication request
+ */
+int
+ntlmDecodeAuth (struct ntlm_authenticate *auth, char *buf, size_t size)
+{
+  char *p, *origbuf;
+  int s;
+
+  if (!buf)
+    {
+      return 1;
+    }
+  origbuf = buf;
+  if (ntlmCheckHeader (&auth->hdr, NTLM_AUTHENTICATE))
+    {
+
+      fprintf (stderr, "ntlmDecodeAuth: header check fails\n");
+      return -1;
+    }
+/* only on when you need to debug
+    fprintf(stderr,"ntlmDecodeAuth: size of %d\n", size);
+    fprintf(stderr,"ntlmDecodeAuth: flg %08x\n", auth->flags);
+    fprintf(stderr,"ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len);
+*/
+  if ((p = ntlmGetString (&auth->hdr, &auth->domain, 2)) == NULL)
+    p = authenticate_ntlm_domain;
+//      fprintf(stderr,"ntlmDecodeAuth: Domain '%s'.\n",p);
+  if ((s = strlen (p) + 1) >= size)
+    return 1;
+  strcpy (buf, p);
+//      fprintf(stdout,"ntlmDecodeAuth: Domain '%s'.\n",buf);
+
+  size -= s;
+  buf += (s - 1);
+  *buf++ = '\\';		/* Using \ is more consistent with MS-proxy */
+
+  p = ntlmGetString (&auth->hdr, &auth->user, 2);
+  if ((s = strlen (p) + 1) >= size)
+    return 1;
+  while (*p)
+    *buf++ = (*p++);		//tolower
+  *buf++ = '\0';
+  size -= s;
+//      fprintf(stderr, "ntlmDecodeAuth: user: %s%s\n",origbuf, p);
+
+
+  return 0;
+}
+
+
+int
+main ()
+{
+  char buf[256];
+  char user[256], *p, *cleartext;
+  struct ntlm_challenge chal;
+  int len;
+  char *data = NULL;
+
+  setbuf (stdout, NULL);
+  while (fgets (buf, 256, stdin) != NULL)
+    {
+      user[0] = '\0';		/*no usercode */
+
+      if ((p = strchr (buf, '\n')) != NULL)
+	*p = '\0';		/* strip \n */
+#if defined(NTLMHELPPROTOCOLV3) || !defined(NTLMHELPPROTOCOLV2)
+      if        (strncasecmp (buf, "YR" ,2) == 0)
+        {
+            ntlmMakeChallenge (&chal);
+            len =
+                sizeof (chal) - sizeof (chal.pad) +
+                SSWAP (chal.target.maxlen);
+            data = (char *) base64_encode_bin ((char *) &chal, len);
+            printf ("TT %s\n", data);
+      } else if (strncasecmp (buf, "KK ",3) == 0) 
+      {
+          cleartext = (char *) uudecode (buf+3);
+          if (!ntlmCheckHeader ((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE))
+          {
+              if (!ntlmDecodeAuth((struct ntlm_authenticate *) cleartext, user, 256))
+              {
+                  lc (user);
+                  printf ("AF %s\n", user);
+              } else {
+                  lc (user);
+                  printf ("NA invalid credentials%s\n", user);
+              }
+          } else {
+              lc (user);
+              printf ("BH wrong packet type!%s\n", user);
+          }
+      }
+#endif
+#ifdef NTLMHELPPROTOCOLV2
+/* V2 of the protocol */
+      if (strncasecmp (buf, "RESET", 5) == 0)
+	{
+	  printf ("RESET OK\n");
+	}
+      else
+	{
+	  cleartext = (char *) uudecode (buf);
+	  if (!ntlmCheckHeader ((struct ntlmhdr *) cleartext, NTLM_NEGOTIATE))
+	    {
+	      ntlmMakeChallenge (&chal);
+	      len =
+		sizeof (chal) - sizeof (chal.pad) +
+		SSWAP (chal.target.maxlen);
+	      data = (char *) base64_encode_bin ((char *) &chal, len);
+	      printf ("CH %s\n", data);
+	    }
+	  else
+	    if (!ntlmCheckHeader
+		((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE))
+	    {
+	      if (!ntlmDecodeAuth
+		  ((struct ntlm_authenticate *) cleartext, user, 256))
+		{
+		  lc (user);
+		  printf ("OK %s\n", user);
+		}          else
+            {
+              lc (user);
+              printf ("ERR %s\n", user);
+            }
+	    }
+	  else
+	    {
+	      lc (user);
+	      printf ("ERR %s\n", user);
+	    }
+	}
+#endif /*v2*/
+    }
+  exit (0);
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/fakeauth/ntlm.h	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,105 @@
+/*
+ * $Id: ntlm.h,v 1.1.2.3.2.2 2001/01/07 02:49:32 rbcollins Exp $
+ *
+ * AUTHOR: Andy Doran <ad@netbsd.org>
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *  
+ */
+
+#ifndef _NTLM_H_
+#define _NTLM_H_
+
+/* undefine this to have strict protocol adherence. You don't really need
+ * that though */
+#define IGNORANCE_IS_BLISS
+
+#include <sys/types.h>
+
+/* All of this cruft is little endian */
+#ifdef WORDS_BIGENDIAN
+#define SSWAP(x)	(bswap16((x)))
+#define WSWAP(x)	(bswap32((x)))
+#else
+#define SSWAP(x)	(x)
+#define WSWAP(x)	(x)
+#endif
+
+/* NTLM request types that we know about */
+#define NTLM_NEGOTIATE		1
+#define NTLM_CHALLENGE		2
+#define NTLM_AUTHENTICATE	3
+#define NTLM_ANY          0
+
+/* Header proceeding each request */
+typedef struct ntlmhdr {
+	char	signature[8];	/* NTLMSSP */
+	int32_t	type;		/* One of NTLM_* from above */
+} ntlmhdr;
+
+/* String header. String data resides at the end of the request */
+typedef struct strhdr {
+	int16_t	len;		/* Length in bytes */
+	int16_t	maxlen;		/* Allocated space in bytes */
+	int32_t	offset;		/* Offset from start of request */
+} strhdr;
+
+/* Negotiation request sent by client */
+struct ntlm_negotiate {
+	ntlmhdr	hdr;		/* NTLM header */
+	int32_t	flags;		/* Request flags */
+	strhdr	domain;		/* Domain we wish to authenticate in */
+	strhdr	workstation;	/* Client workstation name */
+	char	pad[256];	/* String data */
+};
+
+/* Challenge request sent by server. */
+struct ntlm_challenge {
+	ntlmhdr	hdr;		/* NTLM header */
+	strhdr	target;		/* Authentication target (domain/server ...) */
+	int32_t	flags;		/* Request flags */
+	u_char	challenge[8];	/* Challenge string */
+	int16_t	unknown[8];	/* Some sort of context data */
+	char	pad[256];	/* String data */
+};
+
+/* Authentication request sent by client in response to challenge */
+struct ntlm_authenticate {
+	ntlmhdr	hdr;		/* NTLM header */
+	strhdr	lmresponse;	/* LANMAN challenge response */
+	strhdr	ntresponse;	/* NT challenge response */
+	strhdr	domain;		/* Domain to authenticate against */
+	strhdr	user;		/* Username */
+	strhdr	workstation;	/* Workstation name */
+	strhdr	sessionkey;	/* Session key for server's use */
+	int32_t flags;		/* Request flags */
+	char	pad[256*6];	/* String data */
+};
+
+char	*ntlmGetString(ntlmhdr *hdr, strhdr *str, int flags);
+void	ntlmMakeChallenge(struct ntlm_challenge *chal);
+int	ntlmCheckHeader(struct ntlmhdr *hdr, int type);
+int	ntlmCheckNegotiation(struct ntlm_negotiate *neg);
+int	ntlmAuthenticate(struct ntlm_authenticate *neg);
+
+#endif /* _NTLM_H_ */
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/no_check/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,80 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.in,v 1.1.2.1.2.2 2001/01/07 02:49:32 rbcollins Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+prefix		= @prefix@
+exec_prefix	= @exec_prefix@
+exec_suffix	= @exec_suffix@
+top_srcdir	= @top_srcdir@
+bindir		= @bindir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+# Gotta love the DOS legacy
+#
+NO_CHECK	= no_check
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+INSTALL		= @INSTALL@
+INSTALL_BIN	= @INSTALL_PROGRAM@
+CRYPTLIB	= @CRYPTLIB@
+AC_CFLAGS	= @CFLAGS@
+LDFLAGS		= @LDFLAGS@
+XTRA_LIBS	= @XTRA_LIBS@
+XTRA_OBJS	= @XTRA_OBJS@
+MV		= @MV@
+RM		= @RM@
+SHELL		= /bin/sh
+
+
+INCLUDE		= -I. -I../../include -I$(top_srcdir)/include
+CFLAGS		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+AUTH_LIBS	= -L../../lib -lmiscutil $(CRYPTLIB) $(XTRA_LIBS)
+
+PROGS		= $(NO_CHECK).pl
+OBJS		= $(NO_CHECK)
+
+all:    $(PROGS)
+
+#$(OBJS): 
+
+$(NO_CHECK).pl: $(OBJS)
+	cp $(srcdir)/$(NO_CHECK) ./$(NO_CHECK).pl
+
+install-mkdirs:
+	-@if test ! -d $(prefix); then \
+		echo "mkdir $(prefix)"; \
+		mkdir $(prefix); \
+	fi
+	-@if test ! -d $(bindir); then \
+		echo "mkdir $(bindir)"; \
+		mkdir $(bindir); \
+	fi
+
+install: all install-mkdirs
+	@for f in $(PROGS); do \
+		if test -f $(bindir)/$$f; then \
+			echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+			$(MV) $(bindir)/$$f $(bindir)/-$$f; \
+		fi; \
+		echo $(INSTALL_BIN) $$f $(bindir); \
+		$(INSTALL_BIN) $$f $(bindir); \
+		if test -f $(bindir)/-$$f; then \
+			echo $(RM) -f $(bindir)/-$$f; \
+			$(RM) -f $(bindir)/-$$f; \
+		fi; \
+	done
+
+clean: 
+	-rm -rf *.o *pure_* core $(PROGS)
+
+distclean:     clean
+	-rm -f Makefile
+
+depend:
+	$(MAKEDEPEND) -I../include -I. -fMakefile *.c
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/no_check/README.no_check_ntlm_auth	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,10 @@
+This is a dummy NTLM authentication module for Squid.
+It performs the NTLM challenge, but then it doesn't verify the
+user's credentials, it just takes the client's domain and username
+at face value.
+It's included mostly for demonstration purposes.
+
+(C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+Distributed freely under the terms of the GNU General Public License, 
+version 2. For the licensing terms, see the file COPYING that
+came with Squid.
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/ntlm_auth_modules/no_check/no_check	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,210 @@
+#!/usr/bin/perl
+# (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+#
+# TODO: use command-line arguments
+
+#use MIME::Base64;
+
+$|=1;
+#$authdomain="your_domain_goes_here";
+$challenge="deadbeef";
+
+$authdomain=$ARGV[0] if ($#ARGV >=0);
+
+die ("Edit $0 to configure a domain!") unless (defined($authdomain));
+
+while(<STDIN>) {
+	chop;
+	if ($_ eq "YR") {
+		print "TT ".encode_base64(&make_ntlm_static_challenge);
+		next;
+	}
+	$got=substr($_,3);
+	%res=decode_ntlm_any(decode_base64($got));
+#	print STDERR "got: ".hash_to_string(%res);
+	if (!res) {										# broken NTLM, deny
+		print "BH Couldn't decode NTLM packet\n";
+		next;
+	}
+	if ($res{type} eq "negotiate") { # ok, send a challenge
+		print "BH Squid-helper protocol error: unexpected negotiate-request\n";
+		next;
+	}
+	if ($res{type} eq "challenge") { # Huh? WE are the challengers.
+		print "BH Squid-helper protocol error: unexpected challenge-request\n";
+		next;		
+	}
+	if ($res{type} eq "authentication") {
+		print "AF $res{domain}\\$res{user}\n";
+		next;		
+	}
+	print "BH internal error\n";	# internal error
+}
+
+
+sub make_ntlm_static_challenge {
+	$rv = pack ("a8 V", "NTLMSSP", 0x2);
+	$payload = "";
+
+	$rv .= add_to_data(uc($authdomain),\$payload);
+	$rv .= pack ("V Z8 v8", 0x18206, $challenge,0,0,0,0,0,0,0x3a,0);
+	#flags, challenge, 8 bytes of unknown stuff
+
+	return $rv.$payload;
+}
+
+#gets as argument the decoded authenticate packet.
+#returns either undef (failure to decode) or an hash with the decoded
+# fields.
+sub decode_ntlm_authentication {
+	my ($got)=$_[0];
+	my ($signature, $type, %rv, $hdr, $rest);
+	($signature, $type, $rest) = unpack ("a8 V a*",$got);
+	return unless ($signature eq "NTLMSSP\0");
+	return unless ($type == 0x3);
+	$rv{type}="authentication";
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{lmresponse}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{ntresponse}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{domain}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{user}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{workstation}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{sessionkey}=get_from_data($hdr,$got);
+	$rv{flags}=unpack("V",$rest);
+	return %rv;
+}
+
+#args: len, maxlen, offset
+sub make_ntlm_hdr {
+	return pack ("v v V", @_);
+}
+
+#args: string to add, ref to payload
+# returns ntlm header.
+sub add_to_data {
+	my ($toadd, $pl) = @_;
+	my ($offset);
+#	$toadd.='\0' unless ($toadd[-1]=='\0'); #broken
+	$offset=48+length $pl;  #48 is the length of the header
+	$$pl.=$toadd;
+	return make_ntlm_hdr (length $toadd, length $toadd, $offset);
+}
+
+#args: encoded descriptor, entire decoded packet
+# returns the decoded data
+sub get_from_data {
+	my($desc,$packet) = @_;
+	my($offset,$length, $rv);
+	($length, undef, $offset) = unpack ("v v V", $desc);
+	return unless ($length+$offset <= length $packet);
+	$rv = unpack ("x$offset a$length",$packet);
+	return $rv;
+}
+
+sub hash_to_string {
+	my (%hash) = @_;
+	my ($rv);
+	foreach (sort keys %hash) {
+		$rv.=$_." => ".$hash{$_}."\n";
+	}
+	return $rv;
+}
+
+
+#more decoder functions, added more for debugging purposes
+#than for any real use in the application.
+#args: the base64-decoded packet
+#returns: either undef or an hash describing the packet.
+sub decode_ntlm_negotiate {
+	my($got)=$_[0];
+	my($signature, $type, %rv, $hdr, $rest);
+	($signature, $type, $rest) = unpack ("a8 V a*",$got);
+	return unless ($signature eq "NTLMSSP\0");
+	return unless ($type == 0x1);
+	$rv{type}="negotiate";
+	($rv{flags}, $rest)=unpack("V a*",$rest);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{domain}=get_from_data($hdr,$got);
+	($hdr, $rest) = unpack ("a8 a*", $rest);
+	$rv{workstation}=get_from_data($hdr,$got);
+	return %rv;
+}
+
+sub decode_ntlm_challenge {
+	my($got)=$_[0];
+	my($signature, $type, %rv, $hdr, $rest, $j);
+	($signature, $type, $rest) = unpack ("a8 V a*",$got);
+	return unless ($signature eq "NTLMSSP\0");
+	return unless ($type == 0x2);
+	$rv{type}="challenge";
+	($rv{flags}, $rest)=unpack("V a*",$rest);
+	($rv{challenge}, $rest)=unpack("a8 a*",$rest);
+	for ($j=0;$j<8;$j++) {				# don't shoot on the programmer, please.
+		($rv{"context.$j"},$rest)=unpack("v a*",$rest);
+	}
+	return %rv;
+}
+
+#decodes any NTLMSSP packet.
+#arg: the encoded packet, returns an hash with packet info
+sub decode_ntlm_any {
+	my($got)=$_[0];
+	my ($signature, $type);
+	($signature, $type, undef) = unpack ("a8 V a*",$got);
+	return unless ($signature eq "NTLMSSP\0");
+	return decode_ntlm_negotiate($got) if ($type == 1);
+	return decode_ntlm_challenge($got) if ($type == 2);
+	return decode_ntlm_authentication($got) if ($type == 3);
+	return undef;									# default
+}
+
+
+use integer;
+
+sub encode_base64 ($;$)
+{
+    my $res = "";
+    my $eol = $_[1];
+    $eol = "\n" unless defined $eol;
+    pos($_[0]) = 0;                          # ensure start at the beginning
+    while ($_[0] =~ /(.{1,45})/gs) {
+	$res .= substr(pack('u', $1), 1);
+	chop($res);
+    }
+    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
+    # fix padding at the end
+    my $padding = (3 - length($_[0]) % 3) % 3;
+    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
+    # break encoded string into lines of no more than 76 characters each
+    if (length $eol) {
+	$res =~ s/(.{1,76})/$1$eol/g;
+    }
+    $res;
+}
+
+
+sub decode_base64 ($)
+{
+    local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123]
+
+    my $str = shift;
+    my $res = "";
+
+    $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
+    if (length($str) % 4) {
+	require Carp;
+	Carp::carp("Length of base64 data not a multiple of 4")
+    }
+    $str =~ s/=+$//;                        # remove padding
+    $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
+    while ($str =~ /(.{1,60})/gs) {
+	my $len = chr(32 + length($1)*3/4); # compute length byte
+	$res .= unpack("u", $len . $1 );    # uudecode
+    }
+    $res;
+}
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/ntlm/Makefile.in	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,55 @@
+#
+#  Makefile for the ntlm authentication scheme module for the Squid Object Cache server
+#
+#  $Id$
+#
+
+AUTH		= ntlm
+
+top_srcdir	= @top_srcdir@
+VPATH		= @srcdir@
+
+CC		= @CC@
+MAKEDEPEND	= @MAKEDEPEND@
+AR_R		= @AR_R@
+RANLIB		= @RANLIB@
+AC_CFLAGS	= @CFLAGS@
+SHELL		= /bin/sh
+
+INCLUDE		= -I../../../include -I$(top_srcdir)/include -I$(top_srcdir)/src/
+CFLAGS 		= $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+
+OUT		= ../$(AUTH).a
+
+OBJS	 	= \
+		auth_ntlm.o
+
+
+all: $(OUT)
+
+$(OUT): $(OBJS)
+	@rm -f ../stamp
+	$(AR_R) $(OUT) $(OBJS)
+	$(RANLIB) $(OUT)
+
+$(OBJS): $(top_srcdir)/include/version.h ../../../include/autoconf.h
+
+.c.o:
+	@rm -f ../stamp
+	$(CC) $(CFLAGS) -c $<
+
+clean: 
+	-rm -rf *.o *pure_* core ../$(AUTH).a
+
+distclean:	clean
+	-rm -f Makefile
+	-rm -f Makefile.bak
+	-rm -f tags
+
+install:
+
+tags:
+	ctags *.[ch] $(top_srcdir)/src/*.[ch] $(top_srcdir)/include/*.h $(top_srcdir)/lib/*.[ch]
+
+depend:
+	$(MAKEDEPEND) $(INCLUDE) -fMakefile *.c
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/ntlm/auth_ntlm.c	Wed Feb 14 00:48:10 2007
@@ -0,0 +1,1034 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 29    NTLM Authenticator
+ * AUTHOR: Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ *
+ */
+
+/* The functions in this file handle authentication.
+   They DO NOT perform access control or auditing.
+   See acl.c for access control and client_side.c for auditing */
+
+
+#include "squid.h"
+#include "auth_ntlm.h"
+
+static void
+authenticateStateFree(authenticateStateData * r)
+{
+    cbdataFree(r);
+}
+
+/* NTLM Scheme */
+static HLPSCB authenticateNTLMHandleReply;
+static HLPSCB authenticateNTLMHandleplaceholder;
+static AUTHSACTIVE    authenticateNTLMActive;
+static AUTHSAUTHED    authNTLMAuthenticated;
+static AUTHSAUTHUSER  authenticateNTLMAuthenticateUser;
+static AUTHSFIXERR    authenticateNTLMFixErrorHeader;
+static AUTHSFREE      authenticateNTLMFreeUser;
+static AUTHSDIRECTION authenticateNTLMDirection;
+static AUTHSDECODE authenticateDecodeNTLMAuth;
+static AUTHSDUMP      authNTLMCfgDump;
+static AUTHSFREECONFIG authNTLMFreeConfig;
+static AUTHSINIT       authNTLMInit;
+static AUTHSONCLOSEC authenticateNTLMOnCloseConnection;
+static AUTHSUSERNAME authenticateNTLMUsername;
+static AUTHSREQFREE  authNTLMAURequestFree;
+static AUTHSPARSE    authNTLMParse;
+static AUTHSSTART    authenticateNTLMStart;
+static AUTHSSTATS    authenticateNTLMStats;
+static AUTHSSHUTDOWN authNTLMDone;
+
+/* helper callbacks to handle per server state data */
+static HLPSAVAIL     authenticateNTLMHelperServerAvailable;
+static HLPSONEQ      authenticateNTLMHelperServerOnEmpty;
+
+static statefulhelper *ntlmauthenticators = NULL;
+
+CBDATA_TYPE(authenticateStateData);
+
+static int authntlm_initialised = 0;
+
+MemPool *ntlm_helper_state_pool = NULL;
+MemPool *ntlm_user_pool = NULL;
+MemPool *ntlm_request_pool = NULL;
+static auth_ntlm_config * ntlmConfig = NULL;
+
+static hash_table *proxy_auth_cache = NULL;
+
+/*
+ *
+ * Private Functions
+ *
+ */
+
+void
+authNTLMDone(void)
+{
+//    memPoolDestroy(ufs_state_pool);
+
+    if (ntlmauthenticators)
+        helperStatefulShutdown(ntlmauthenticators);
+    authntlm_initialised = 0;
+    if (!shutting_down)
+        return;
+    helperStatefulFree(ntlmauthenticators);
+    ntlmauthenticators = NULL;
+    memPoolDestroy(ntlm_helper_state_pool);
+    memPoolDestroy(ntlm_request_pool);
+    memPoolDestroy(ntlm_user_pool);
+    
+}
+
+/* free any allocated configuration details */
+void
+authNTLMFreeConfig(authScheme *scheme)
+{
+    if (ntlmConfig==NULL)
+        return;
+    assert(ntlmConfig==scheme->scheme_data);
+    if (ntlmConfig->authenticate)
+        wordlistDestroy(&ntlmConfig->authenticate);
+   xfree(ntlmConfig);
+   ntlmConfig=NULL;
+}
+
+static void
+authNTLMCfgDump(StoreEntry *entry, const char * name, authScheme *scheme)
+{
+   auth_ntlm_config *config=scheme->scheme_data;
+   wordlist *list=config->authenticate;
+   storeAppendPrintf(entry, "%s %s", name, "ntlm");
+   while (list !=NULL)
+   {
+        storeAppendPrintf(entry, " %s", list->key);
+        list = list->next;
+   }
+   storeAppendPrintf(entry, "\n%s %s children %d\n%s %s max_challenge_reuses %d\n%s %s max_challenge_lifetime %d seconds\n",
+        name, "ntlm", config->authenticateChildren,
+        name, "ntlm", config->challengeuses,
+        name, "ntlm", config->challengelifetime);
+
+}
+
+static void
+authNTLMParse(authScheme *scheme, int n_configured, char *param_str)
+{
+    if (scheme->scheme_data==NULL)
+    {
+        assert (ntlmConfig==NULL);
+        /* this is the first param to be found */
+        scheme->scheme_data=xmalloc(sizeof(auth_ntlm_config));
+        memset(scheme->scheme_data, 0, sizeof(auth_ntlm_config));
+        ntlmConfig=scheme->scheme_data;
+        ntlmConfig->authenticateChildren=5;
+        ntlmConfig->challengeuses=0;
+        ntlmConfig->challengelifetime=60;
+    }
+    ntlmConfig=scheme->scheme_data;
+    if (strcasecmp(param_str,"program")==0)
+    {
+        parse_wordlist(&ntlmConfig->authenticate);
+        requirePathnameExists("authparam ntlm program",ntlmConfig->authenticate->key);
+    }
+    else if (strcasecmp(param_str,"children")==0)
+    {
+        parse_int(&ntlmConfig->authenticateChildren);
+    }
+    else if (strcasecmp(param_str,"max_challenge_reuses")==0)
+    {
+        parse_int(&ntlmConfig->challengeuses);
+    }
+    else if (strcasecmp(param_str,"max_challenge_lifetime")==0)
+    {
+        parse_time_t(&ntlmConfig->challengelifetime);
+    }
+    else
+    {
+        debug(28,0)("unrecognised ntlm auth scheme parameter '%s'\n",param_str);
+    }
+}
+
+
+void
+authSchemeSetup_ntlm(authscheme_entry_t *authscheme) {
+#if 0
+static int ntlminit = 0;
+#endif
+    assert(!authntlm_initialised);
+    authscheme->Active            =authenticateNTLMActive;
+    authscheme->parse             =authNTLMParse;
+    authscheme->dump              =authNTLMCfgDump;
+    authscheme->requestFree       =authNTLMAURequestFree;
+    authscheme->freeconfig        =authNTLMFreeConfig;
+    authscheme->init              =authNTLMInit;
+    authscheme->authAuthenticate = authenticateNTLMAuthenticateUser;
+    authscheme->authenticated    = authNTLMAuthenticated;
+    authscheme->authFixHeader=authenticateNTLMFixErrorHeader;
+    authscheme->FreeUser          =authenticateNTLMFreeUser;
+    authscheme->authStart   =authenticateNTLMStart;
+    authscheme->authStats   =authenticateNTLMStats;
+    authscheme->authUserUsername = authenticateNTLMUsername;
+    authscheme->getdirection=authenticateNTLMDirection;
+    authscheme->decodeauth  =authenticateDecodeNTLMAuth;
+    authscheme->donefunc = authNTLMDone;
+    authscheme->oncloseconnection = authenticateNTLMOnCloseConnection;
+}
+
+/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the
+ * config file */
+static void
+authNTLMInit(authScheme *scheme)
+{
+    static int ntlminit = 0;
+    if (ntlmConfig->authenticate)
+    {
+        if (!ntlm_helper_state_pool)
+            ntlm_helper_state_pool = memPoolCreate("NTLM Helper State data", sizeof(ntlm_helper_state_t));
+        if (!ntlm_user_pool)
+            ntlm_user_pool = memPoolCreate("NTLM Scheme User Data", sizeof(ntlm_user_t));
+        if (!ntlm_request_pool)
+            ntlm_request_pool = memPoolCreate("NTLM Scheme Request Data", sizeof(ntlm_request_t));
+        authntlm_initialised = 1;
+        if (ntlmauthenticators == NULL)
+            ntlmauthenticators = helperStatefulCreate("ntlmauthenticator");
+        if (!proxy_auth_cache)
+            proxy_auth_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string);
+        assert(proxy_auth_cache);
+        ntlmauthenticators->cmdline = ntlmConfig->authenticate;
+        ntlmauthenticators->n_to_start = ntlmConfig->authenticateChildren;
+        ntlmauthenticators->ipc_type = IPC_TCP_SOCKET;
+        ntlmauthenticators->datapool=ntlm_helper_state_pool;
+        ntlmauthenticators->IsAvailable=authenticateNTLMHelperServerAvailable;
+        ntlmauthenticators->OnEmptyQueue=authenticateNTLMHelperServerOnEmpty;
+        helperStatefulOpenServers(ntlmauthenticators);
+        /* TODO: In here send the initial YR to preinitialise the challenge cache */
+        /* Think about this... currently we ask when the challenge is needed. Better?*/
+        if (!ntlminit) 
+        {
+            cachemgrRegister("ntlmauthenticator",
+                "User NTLM Authenticator Stats",
+                authenticateNTLMStats, 0, 1);
+            ntlminit++;
+        }
+        CBDATA_INIT_TYPE(authenticateStateData);
+    }
+}
+
+int
+authenticateNTLMActive(){
+    if (authntlm_initialised)
+        return 1;
+    else
+        return 0;
+}
+
+/* NTLM Scheme */
+
+int authenticateNTLMDirection(auth_user_request_t *auth_user_request) {
+    ntlm_request_t * ntlm_request = auth_user_request->scheme_data;
+/* 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");
+            return -2;
+        case AUTHENTICATE_STATE_NEGOTIATE: /* send to helper */
+        case AUTHENTICATE_STATE_RESPONSE: /*send to helper */
+            return -1;
+        case AUTHENTICATE_STATE_CHALLENGE: /* send to client */
+            return 1;
+        case AUTHENTICATE_STATE_DONE: /* do nothing.. */
+            return 0;
+    }
+    return -2;
+}
+
+/*
+ * Send the authenticate error header(s). Note: IE has a bug and the NTLM header
+ * must be first. To ensure that, the configure use --enable-auth=ntlm, anything
+ * else.
+ */
+void
+authenticateNTLMFixErrorHeader(auth_user_request_t *auth_user_request, HttpReply *rep, http_hdr_type type, request_t * request){
+    ntlm_request_t * ntlm_request;
+    if (ntlmConfig->authenticate){
+        /* New request, no user details */
+        if (auth_user_request == NULL) {
+            debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n",type);
+            httpHeaderPutStrf(&rep->header, type, "NTLM");
+            /* drop the connection */
+            httpHeaderDelByName(&rep->header, "keep-alive"); 
+            /* NTLM has problems if the initial connection is not dropped
+               I haven't checked the RFC compliance of this hack - RBCollins*/
+            request->flags.proxy_keepalive = 0;
+        } else {
+            ntlm_request=auth_user_request->scheme_data;
+            switch (ntlm_request->auth_state){
+            case AUTHENTICATE_STATE_NONE:
+                debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM'\n",type);
+                httpHeaderPutStrf(&rep->header, type, "NTLM");
+                /* drop the connection */
+                httpHeaderDelByName(&rep->header, "keep-alive");
+                /* NTLM has problems if the initial connection is not dropped
+                 I haven't checked the RFC compliance of this hack - RBCollins*/
+                request->flags.proxy_keepalive = 0;
+            break;
+            case AUTHENTICATE_STATE_CHALLENGE: 
+                /* we are 'waiting' for a response */
+                /* pass the challenge to the client */
+                debug(29, 9) ("authenticateNTLMFixErrorHeader: Sending type:%d header: 'NTLM %s'\n",type,ntlm_request->authchallenge);
+                httpHeaderPutStrf(&rep->header, type, "NTLM %s", ntlm_request->authchallenge);
+            break;
+            default:
+                debug(29,0)("authenticateNTLMFixErrorHeader: state %d.\n",ntlm_request->auth_state);
+                fatal("unexpected state in AuthenticateNTLMFixErrorHeader.\n");
+            }
+        }
+    }
+}
+
+void
+authNTLMRequestFree(ntlm_request_t * ntlm_request)
+{
+    if (!ntlm_request)
+        return;
+    if (ntlm_request->ntlmnegotiate)
+        xfree(ntlm_request->ntlmnegotiate);
+    if (ntlm_request->authchallenge)
+        xfree(ntlm_request->authchallenge);
+    if (ntlm_request->ntlmauthenticate)
+        xfree(ntlm_request->ntlmauthenticate);
+    memPoolFree(ntlm_request_pool, ntlm_request);
+}
+
+void
+authNTLMAURequestFree(auth_user_request_t * auth_user_request)
+{
+    if (auth_user_request->scheme_data)
+        authNTLMRequestFree((ntlm_request_t *)auth_user_request->scheme_data);
+    auth_user_request->scheme_data=NULL;
+}
+
+void
+authenticateNTLMFreeUser(auth_user_t *auth_user) {
+    dlink_node *link, *tmplink;
+    ntlm_user_t * ntlm_user = auth_user->scheme_data;
+    auth_user_hash_pointer *proxy_auth_hash;
+    
+    debug(29,5) ("authenticateNTLMFreeUser: Clearing NTLM scheme data\n");
+    if (ntlm_user->username)
+        xfree(ntlm_user->username);
+    /* were they linked in by one or more proxy-authenticate headers */
+    link = ntlm_user->proxy_auth_list.head;
+    while (link) {
+        debug(29,9) ("authenticateFreeProxyAuthUser: removing proxy_auth hash entry '%d'\n
+",link->data);
+        proxy_auth_hash = link->data;
+        tmplink=link;
+        link=link->next;
+        dlinkDelete(tmplink, &ntlm_user->proxy_auth_list);
+        hash_remove_link(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+        /* free the key (usually the proxy_auth header) */
+        xfree(proxy_auth_hash->key);
+        memFree(proxy_auth_hash, MEM_AUTH_USER_HASH);
+    }
+    memPoolFree(ntlm_user_pool, ntlm_user);
+    auth_user->scheme_data = NULL; 
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleplaceholder(void *data, void * lastserver, char *reply)
+{
+    authenticateStateData *r = data;
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+    int valid;
+    /* we should only be called for placeholder requests - which have no reply string */
+    assert (reply == NULL); 
+    assert (r->auth_user_request);
+    /* standard callback stuff */
+    valid = cbdataValid(r->data);
+    cbdataUnlock(r->data);
+    /* call authenticateNTLMStart to retry this request */
+    debug(29,9)("authenticateNTLMHandleplaceholder: calling authenticateNTLMStart\n");
+    authenticateNTLMStart(r->auth_user_request, r->handler, r->data);    
+    authenticateStateFree(r);
+    return result;
+}
+
+static stateful_helper_callback_t
+authenticateNTLMHandleReply(void *data, void * lastserver, char *reply)
+{
+#if 0
+    authenticateStatefulStateData *r = data;
+#endif
+    authenticateStateData *r = data;
+    ntlm_helper_state_t * helperstate;
+    int valid;
+    stateful_helper_callback_t result = S_HELPER_UNKNOWN;
+#if 0
+    void *nextserver=NULL;
+#endif
+    char *t = NULL;
+    auth_user_request_t *auth_user_request;
+    auth_user_t *auth_user;
+    ntlm_user_t *ntlm_user;
+    ntlm_request_t *ntlm_request;
+    debug(29, 9) ("authenticateNTLMHandleReply: Helper: '%d' {%s}\n", lastserver, reply ? reply : "<NULL>");
+    valid = cbdataValid(r->data);
+    cbdataUnlock(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 */
+#if 0
+	        result=S_HELPER_RESERVE;
+#endif
+                /* 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;
+#if 0
+                nextserver=lastserver;
+#endif
+	        debug(29,9)("authenticateNTLMHandleReply: helper '%d'\n",lastserver);
+                assert(ntlm_request->auth_state == AUTHENTICATE_STATE_NEGOTIATE);
+//                auth_user->auth_data.ntlm_auth.auth_state = AUTHENTICATE_STATE_CHALLENGE;
+                ntlm_request->authhelper = 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->authhelper = NULL;
+                auth_user->flags.credentials_ok = 1; /* login ok */
+            } 
+            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->authhelper = NULL;
+                auth_user->flags.credentials_ok = 2; /* Login/Usercode failed */
+                debug(29, 4) ("authenticateNTLMHandleReply: Error validating user via NTLM.\n");
+                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->authhelper);
+                ntlm_request->authhelper = 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.\n", lastserver);
+                    /* 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.\n");
+                    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->authhelper = NULL;
+	    }
+        } else {
+            fatal("authenticateNTLMHandleReply: called with no result string\n");
+        }
+        r->handler(r->data, NULL);
+    } else {
+        debug(29,1) ("AuthenticateNTLMHandleReply: invalid callback data. Releasing helper '%d'.\n",lastserver);
+        result=S_HELPER_RELEASE;
+    }
+    authenticateStateFree(r);
+    debug(29,9)("NTLM HandleReply, telling stateful helper : %d\n",result);
+    return result;
+}
+
+#if 0
+static void
+authenticateNTLMStateFree(authenticateNTLMStateData * r)
+{
+    cbdataFree(r);
+}
+#endif
+
+static void
+authenticateNTLMStats(StoreEntry * sentry)
+{
+    storeAppendPrintf(sentry, "NTLM Authenticator Statistics:\n");
+    helperStatefulStats(sentry, ntlmauthenticators);
+}
+
+/* is a particular challenge still valid ? */
+int
+authenticateNTLMValidChallenge(ntlm_helper_state_t *helperstate)
+{
+    if (helperstate->challenge == NULL) return 0;
+    return 1;
+}
+
+/* does our policy call for changing the challenge now? */
+int
+authenticateNTLMChangeChallenge(ntlm_helper_state_t *helperstate)
+{
+    /* don't check for invalid challenges just for expiry choices */
+    /* this is needed because we have to starve the helper until all old
+     * requests have been satisfied */
+    if (helperstate->challengeuses>ntlmConfig->challengeuses) return 1;
+    if (helperstate->renewed+ntlmConfig->challengelifetime>=squid_curtime) return 1;
+    return 0;
+}
+
+/* send the initial data to a stateful ntlm authenticator module */
+static void
+authenticateNTLMStart(auth_user_request_t * auth_user_request, RH * handler, void *data)
+{
+#if 0
+    authenticateStatefulStateData *r = NULL;
+#endif
+    authenticateStateData *r = NULL;
+    helper_stateful_server *server;
+    ntlm_helper_state_t *helperstate;
+    char buf[8192];
+    char *sent_string=NULL;
+    ntlm_user_t * ntlm_user;
+    ntlm_request_t * ntlm_request;
+    auth_user_t * auth_user;
+
+    assert(auth_user_request);
+    auth_user=auth_user_request->auth_user;
+    ntlm_user=auth_user->scheme_data;
+    ntlm_request=auth_user_request->scheme_data;
+    assert(ntlm_user);
+    assert(ntlm_request);
+    assert(handler);
+    assert(data);
+    assert(auth_user->auth_type=AUTH_NTLM);
+    debug(29,9)("authenticateNTLMStart: auth state '%d'\n",ntlm_request->auth_state);
+    switch(ntlm_request->auth_state) {
+        case AUTHENTICATE_STATE_NEGOTIATE:
+            sent_string = xstrdup(ntlm_request->ntlmnegotiate);
+            break;
+        case AUTHENTICATE_STATE_RESPONSE:
+            sent_string = xstrdup(ntlm_request->ntlmauthenticate);
+            assert(ntlm_request->authhelper);
+            debug(29, 9) ("authenticateNTLMStart: Asking NTLMauthenticator '%d'.\n", ntlm_request->authhelper);
+            break;
+        default:
+            fatal("Invalid authenticate state for NTLMStart");
+    }
+
+    while (!xisspace(*sent_string))     /*trim NTLM */
+        sent_string++;
+
+    while (xisspace(*sent_string))      /*trim leading spaces */
+        sent_string++;
+
+    debug(29, 9) ("authenticateNTLMStart: state '%d'\n", ntlm_request->auth_state);
+    debug(29, 9) ("authenticateNTLMStart: '%s'\n", sent_string);
+    if (ntlmConfig->authenticate == NULL) {
+        debug(29, 0) ("authenticateNTLMStart: no NTLM program specified:'%s'\n", sent_string);
+//	handler(data,0, NULL);
+            handler(data, NULL);
+	return;
+    }
+#ifdef NTLMHELPPROTOCOLV2
+    r = CBDATA_ALLOC(authenticateStateData, NULL);
+    r->handler = handler;
+    cbdataLock(data);
+    r->data = data;
+    r->auth_user_request = auth_user_request;
+    snprintf(buf, 8192, "%s\n", sent_string);
+    helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->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(ntlm_request->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);
+            helperstate=server ? helperStatefulServerGetData(server): NULL ;
+            while ((server !=NULL) && 
+                 authenticateNTLMChangeChallenge(helperstate)) 
+            {
+                /* flag this helper for challenge changing */
+                helperstate->starve=1;
+                /* and release the deferred request */
+                helperStatefulReleaseServer(server);
+                server=helperStatefulDefer(ntlmauthenticators);
+                if (server != NULL)
+                    helperstate=helperStatefulServerGetData(server);
+            }
+            if (server==NULL) debug(29,9) ("unable to get a deferred ntlm helper... all helpers are refreshing challenges. Queuing as a placeholder request.\n");
+            
+            ntlm_request->authhelper=server;
+            /* tell the log what helper we have been given */
+            debug(29,9)("authenticateNTLMStart: helper '%d' assigned\n",server);
+            /* valid challenge? */
+            if((server == NULL) || !authenticateNTLMValidChallenge(helperstate))
+            {
+                r = CBDATA_ALLOC(authenticateStateData, NULL);
+                r->handler = handler;
+                cbdataLock(data);
+                r->data = data;
+                r->auth_user_request = auth_user_request;
+                if (server == NULL)
+                {
+                    helperStatefulSubmit(ntlmauthenticators, NULL, authenticateNTLMHandleplaceholder, r, ntlm_request->authhelper);
+                }
+                else
+                {
+                    snprintf(buf, 8192, "YR\n");
+                    helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->authhelper);
+                }
+            } else {
+                /* we have a valid challenge */
+            /* TODO: turn the below into a function and call from here and handlereply */
+            /* increment the challenge uses */
+            helperstate->challengeuses++;
+            /* assign the challenge */
+            ntlm_request->authchallenge =
+                xstrndup(helperstate->challenge, NTLM_CHALLENGE_SZ+5);
+            handler(data, NULL);
+            }
+              
+            break;
+        case AUTHENTICATE_STATE_RESPONSE:
+            r = CBDATA_ALLOC(authenticateStateData, NULL);
+            r->handler = handler;
+            cbdataLock(data);
+            r->data = data;
+            r->auth_user_request = auth_user_request;
+            snprintf(buf, 8192, "KK %s\n", sent_string);
+            helperStatefulSubmit(ntlmauthenticators, buf, authenticateNTLMHandleReply, r, ntlm_request->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,4)("authenticateNTLMHelperServerAvailable: starving - returning 0\n");
+            return 0;
+        }
+        else 
+        {
+            debug(29,4)("authenticateNTLMHelperServerAvailable: not startving - returning 1\n");
+            return 1;
+        }
+    }
+    debug(29,4)("authenticateNTLMHelperServerAvailable: no state data - returning 0\n");
+    return 0;
+}
+
+void
+authenticateNTLMHelperServerOnEmpty(void *data)
+{
+    ntlm_helper_state_t *statedata=data;
+    if (statedata == NULL) return;
+    if (statedata->starve)
+    {
+        /* we have been starving the helper */
+        debug(29,9)("authenticateNTLMHelperServerOnEmpty: resetting challenge details\n");
+        statedata->starve=0;
+        statedata->challengeuses=0;
+        statedata->renewed=0;
+        xfree(statedata->challenge);
+        statedata->challenge=NULL;
+    }
+}
+
+
+/* clear the NTLM helper of being reserved for future requests */
+void
+authenticateNTLMReleasehelper(auth_user_request_t *auth_user_request){
+    ntlm_request_t * ntlm_request;
+    assert(auth_user_request->auth_user->auth_type==AUTH_NTLM);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_request = auth_user_request->scheme_data;
+    debug(29,9) ("authenticateNTLMReleasehelper: releasing helper '%d'\n",ntlm_request->authhelper);
+    helperStatefulReleaseServer(ntlm_request->authhelper);
+    ntlm_request->authhelper=NULL;
+}
+
+/* clear any connection related authentication details */
+void
+authenticateNTLMOnCloseConnection(ConnStateData *conn) {
+    ntlm_request_t * ntlm_request;
+    assert(conn !=NULL);
+    if (conn->auth_user_request != NULL) {
+        assert(conn->auth_user_request->scheme_data != NULL);
+        ntlm_request = conn->auth_user_request->scheme_data;
+        if (ntlm_request->authhelper != NULL)
+            authenticateNTLMReleasehelper(conn->auth_user_request);
+        /* unlock the connection based lock */
+        debug (29,9)("authenticateNTLMOnCloseConnection: Unlocking auth_user from the connection.\n");
+        authenticateAuthUserRequestUnlock(conn->auth_user_request);
+        conn->auth_user_request = NULL;
+    }
+}
+
+/* authenticateUserUsername: return a pointer to the username in the */
+char *
+authenticateNTLMUsername(auth_user_t *auth_user) {
+    ntlm_user_t * ntlm_user=auth_user->scheme_data;
+    if(ntlm_user)
+        return ntlm_user->username;
+    return NULL;
+}
+
+
+/*
+ * Decode an NTLM [Proxy-]Auth string, placing the results in the passed
+ * Auth_user structure.
+ */
+
+void
+authenticateDecodeNTLMAuth(auth_user_request_t *auth_user_request, const char * proxy_auth) 
+{
+    dlink_node * node;
+    assert(auth_user_request->auth_user == NULL);
+    auth_user_request->auth_user=authenticateAuthUserNew("ntlm");
+    auth_user_request->auth_user->auth_type = AUTH_NTLM;
+    auth_user_request->auth_user->scheme_data = memPoolAlloc(ntlm_user_pool);
+    auth_user_request->scheme_data = memPoolAlloc(ntlm_request_pool);
+    /* lock for the auth_user_request link */
+    authenticateAuthUserLock(auth_user_request->auth_user);
+    node=dlinkNodeNew();
+    dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests);
+    
+    /* all we have to do is identify that it's NTLM - the helper does the rest */
+    debug(29, 9) ("authenticateDecodeNTLMAuth: NTLM authentication\n");
+    return;
+}
+
+int authenticateNTLMcmpUsername(ntlm_user_t *u1, ntlm_user_t *u2) 
+{
+    return strcmp(u1->username, u2->username);
+}
+
+void
+authenticateProxyAuthCacheAddLink(const char *key, auth_user_t *auth_user)
+{
+    auth_user_hash_pointer *proxy_auth_hash;
+    ntlm_user_t * ntlm_user;
+    proxy_auth_hash =
+        memAllocate(MEM_AUTH_USER_HASH);
+    proxy_auth_hash->key = xstrdup(key);
+    proxy_auth_hash->auth_user = auth_user;
+    ntlm_user=auth_user->scheme_data;
+    dlinkAddTail(proxy_auth_hash, &proxy_auth_hash->link,
+        &ntlm_user->proxy_auth_list);
+    hash_join(proxy_auth_cache, (hash_link *) proxy_auth_hash);
+}
+
+
+int
+authNTLMAuthenticated(auth_user_request_t * auth_user_request)
+{
+    ntlm_request_t *ntlm_request = auth_user_request->scheme_data;
+    if (ntlm_request->auth_state==AUTHENTICATE_STATE_DONE)
+        return 1;
+    debug (29, 9) ("User not fully authenticated.\n");
+    return 0;
+}
+
+#if 0
+static acl_proxy_auth_user *
+authenticateNTLMAuthenticateUser(void *data, const char * proxy_auth, ConnStateData *conn) {
+#endif
+static void
+authenticateNTLMAuthenticateUser(auth_user_request_t *auth_user_request, request_t *request, ConnStateData *conn, http_hdr_type type) {
+    const char * proxy_auth;
+    auth_user_hash_pointer *usernamehash, *proxy_auth_hash=NULL;
+    auth_user_t * auth_user;
+    ntlm_request_t * ntlm_request;
+    ntlm_user_t * ntlm_user;
+    LOCAL_ARRAY(char, ntlmhash, NTLM_CHALLENGE_SZ * 2);
+    /* get header */
+    proxy_auth = httpHeaderGetStr(&request->header, type);
+    
+    auth_user=auth_user_request->auth_user;
+    assert(auth_user);
+    assert(auth_user->auth_type==AUTH_NTLM);
+    assert(auth_user->scheme_data != NULL);
+    assert(auth_user_request->scheme_data != NULL);
+    ntlm_user=auth_user->scheme_data;
+    ntlm_request=auth_user_request->scheme_data;
+    switch (ntlm_request->auth_state) {
+        case AUTHENTICATE_STATE_NONE:
+            /* we've recieved a negotiate request. pass to a helper */
+            debug(29, 9) ("authenticateNTLMAuthenticateUser: auth state ntlm none. %s\n",
+                proxy_auth);
+            ntlm_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE;
+            ntlm_request->ntlmnegotiate=xstrndup(proxy_auth, NTLM_CHALLENGE_SZ+5);
+            conn->auth_type=AUTH_NTLM;
+            conn->auth_user_request=auth_user_request;
+            /* and lock for the connection duration */
+            debug (29,9)("authenticateNTLMAuthenticateUser: Locking auth_user from the connection.\n");
+            authenticateAuthUserRequestLock(auth_user_request);
+            return;
+            break;
+        case AUTHENTICATE_STATE_NEGOTIATE:
+            ntlm_request->auth_state = AUTHENTICATE_STATE_CHALLENGE;
+            return;
+            break;
+        case AUTHENTICATE_STATE_CHALLENGE:
+            /* we should have recieved a NTLM challenge. pass it to the same 
+             * helper process */
+            debug(29,9) ("authenticateNTLMAuthenticateUser: auth state challenge with header %s.\n", proxy_auth);
+            /* do a cache lookup here. If it matches it's a successful ntlm 
+             * challenge - release the helper and use the existing auth_user 
+             * details. */
+            if (strncmp("NTLM ", proxy_auth, 5) == 0) {
+                 ntlm_request->ntlmauthenticate = xstrdup(proxy_auth);
+            } else {
+                fatal("Incorrect scheme in auth header\n");
+                /* TODO: more fault tolerance.. reset the auth scheme here */
+            }
+             /* cache entries have authenticateauthheaderchallengestring */
+            snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s", 
+                ntlm_request->ntlmauthenticate,
+                ntlm_request->authchallenge);
+            /* see if we already know this user's authenticate */
+            debug(29,9)("aclMatchProxyAuth: cache lookup with key '%s'\n",ntlmhash);
+            assert(proxy_auth_cache!=NULL);
+            proxy_auth_hash = hash_lookup(proxy_auth_cache, ntlmhash);
+            if (!proxy_auth_hash) { /* not in the hash table */
+                debug(29,4)("authenticateNTLMAuthenticateUser: proxy-auth cache miss.\n");
+                ntlm_request->auth_state = AUTHENTICATE_STATE_RESPONSE;
+                /* verify with the ntlm helper */
+            } else {
+                debug(29,4)("authenticateNTLMAuthenticateUser: ntlm proxy-auth cache hit\n");
+                /* throw away the temporary entry */
+                authenticateNTLMReleasehelper(auth_user_request);
+                authenticateAuthUserMerge(auth_user,proxy_auth_hash->auth_user);
+                auth_user = proxy_auth_hash->auth_user;
+                auth_user_request->auth_user=auth_user;
+                ntlm_request->auth_state=AUTHENTICATE_STATE_DONE;
+                /* we found one */
+                debug(29, 9) ("found matching cache entry\n");
+                assert(auth_user->auth_type == AUTH_NTLM);
+                /* get the existing entries details */
+                ntlm_user = auth_user->scheme_data;
+                debug(29, 9) ("Username to be used is %s\n",
+                    ntlm_user->username);
+                auth_user->flags.credentials_ok = 1; /* authenticated ok */
+                /* on ntlm auth we do not unlock the auth_user until the
+                 * connection is dropped. Thank MS for this quirk */
+                auth_user->expiretime = current_time.tv_sec ;
+                auth_user->ip_expiretime = squid_curtime;
+            }
+            return;
+            break;
+        case AUTHENTICATE_STATE_RESPONSE:
+            /* auth-challenge pair cache miss. We've just got the response */
+            /*add to cache and let them through */
+            ntlm_request->auth_state = AUTHENTICATE_STATE_DONE;
+            /* this connection is authenticated */
+            debug(29, 4) ("authenticated\nch    %s\nauth     %s\nauthuser %s\n",
+                ntlm_request->authchallenge,
+                ntlm_request->ntlmauthenticate,
+                ntlm_user->username);
+            /* cache entries have authenticateauthheaderchallengestring */
+            snprintf(ntlmhash, sizeof(ntlmhash) - 1, "%s%s", 
+                ntlm_request->ntlmauthenticate,
+                ntlm_request->authchallenge);
+            /* see if this is an existing user with a different proxy_auth 
+             * string */
+            if ((usernamehash = hash_lookup(proxy_auth_username_cache,
+                ntlm_user->username))) {
+                while ((usernamehash->auth_user->auth_type != 
+                    auth_user->auth_type) && (usernamehash->next) &&
+                    !authenticateNTLMcmpUsername(usernamehash->auth_user->scheme_data, ntlm_user) ) 
+                    usernamehash=usernamehash->next;
+                if (usernamehash->auth_user->auth_type==auth_user->auth_type) {
+                    /*
+                     * add another link from the new proxy_auth to the
+                     * auth_user structure and update the information */
+                     assert(proxy_auth_hash == NULL);
+                     authenticateProxyAuthCacheAddLink(ntlmhash, usernamehash->auth_user);
+                    /* we can't seamlessly recheck the username due to the 
+                     * challenge nature of the protocol. Just free the 
+                     * temporary auth_user */
+                    authenticateAuthUserMerge(auth_user,usernamehash->auth_user);
+                    auth_user = usernamehash->auth_user;
+                    auth_user_request->auth_user=auth_user;
+#if 0
+                    conn->auth_user=auth_user;
+#endif
+                }
+            } else {
+                /* store user in hash's */
+                authenticateUserNameCacheAdd(auth_user);
+                authenticateProxyAuthCacheAddLink(ntlmhash, auth_user);
+            }
+            /* set these to now because this is either a new login from an 
+             * existing user or a new user */
+            auth_user->expiretime = current_time.tv_sec ;
+            auth_user->ip_expiretime = squid_curtime;
+            auth_user->flags.credentials_ok=1; /*authenticated ok */
+            return;
+            break;
+    case AUTHENTICATE_STATE_DONE:
+        fatal("authenticateNTLMAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n");
+#if 0 
+done in acl.c
+    case AUTHENTICATE_STATE_DONE:
+        debug(28, 5) ("aclMatchProxyAuth: connection in state Done. using connec
+tion credentials for the request.\n");
+        /* is it working right? */
+        assert(checklist->auth_user == NULL);
+        assert(checklist->conn->auth_user != NULL);
+        /* we have a valid username. */
+        auth_user = checklist->conn->auth_user;
+        /* store the username in the request for logging */
+        xstrncpy(checklist->request->authuser,
+            auth_user->auth_data.ntlm_auth.username,
+            USER_IDENT_SZ);
+        if (auth_user->expiretime + Config.authenticateTTL > current_time.tv_sec
+)
+        {
+            auth_user->expiretime = current_time.tv_sec;
+        }
+        else{
+            //user passed externa; authentication in every case to get here. f.
+Let it through
+        }
+
+        /* we don't unlock the auth_user until the connection is dropped. Thank
+         * MS for this quirk. */
+            if (authenticateCheckAuthUserIP(checklist->src_addr, auth_user)){
+                /* Once the match is completed we have finished with the
+                 * auth_user structure */
+                /* check to see if we have matched the user-acl before */
+                return aclCacheMatchAcl(&auth_user->proxy_match_cache, acltype,
+                    data, auth_user->auth_data.ntlm_auth.username);
+            } else {
+                    return 0;
+            }
+        break;
+#endif
+    }
+
+    return;
+}
+
--- /dev/null	Wed Feb 14 00:45:56 2007
+++ squid/src/auth/ntlm/auth_ntlm.h	Wed Feb 14 00:48:11 2007
@@ -0,0 +1,64 @@
+/*
+ * auth_ntlm.h
+ * Internal declarations for the ntlm auth module
+ */
+
+#ifndef __AUTH_NTLM_H__
+#define __AUTH_NTLM_H__
+
+#define DefaultAuthenticateChildrenMax  32      /* 32 processes */
+
+/* Generic */
+typedef struct {
+    void *data;
+    auth_user_request_t *auth_user_request;
+    RH *handler;
+} authenticateStateData;
+
+struct _ntlm_user {
+    /* what username did this connection get? */
+    char *username;
+    dlink_list proxy_auth_list;
+};
+
+struct _ntlm_request {
+    /* what negotiate string did the client use? */
+    char *ntlmnegotiate;
+    /* what challenge did we give the client? */
+    char *authchallenge;
+    /* what authenticate string did we get? */
+    char *ntlmauthenticate;
+    /*we need to store the NTLM helper between requests*/
+    helper_stateful_server * authhelper;
+    /* how far through the authentication process are we? */
+    auth_state_t auth_state;
+};
+
+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 */
+    int  challengeuses; /* the number of times this challenge has been issued */
+    time_t renewed;
+};
+
+/* configuration runtime data */
+struct _auth_ntlm_config {
+    int authenticateChildren;
+    wordlist *authenticate;
+    int challengeuses;
+    time_t challengelifetime;
+#if 0
+    char *authenticate_ntlm_default_domain;
+#endif
+};
+
+typedef struct _ntlm_user ntlm_user_t;
+typedef struct _ntlm_request ntlm_request_t;
+typedef struct _ntlm_helper_state_t ntlm_helper_state_t;
+typedef struct _auth_ntlm_config auth_ntlm_config;
+
+extern MemPool *ntlm_helper_state_pool;
+extern MemPool *ntlm_user_pool;
+extern MemPool *ntlm_request_pool;
+
+#endif
