--------------------- 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 , + * 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 + * 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 +#endif /* HAVE_STRING_H */ +#if HAVE_STDLIB_H +#include +#endif /* HAVE_STDLIB_H */ +#ifdef HAVE_UNISTD_H +#include +#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) (Almresponse); + 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 , + * 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 +#endif +#if HAVE_SYS_TIME_H +#include +#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 + + +/* Debugging stuff */ + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#ifdef DEBUG +#include +#include +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 + * 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 +#endif + + +#if HAVE_GETOPT_H +#include +#endif + + + +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#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;jstatus!=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;jdomain=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;jstatus == 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 + +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<>(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 */ +#include "config.h" +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include +#include +#include + +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 +#include + +#include "std-includes.h" +#include "rfcnb-priv.h" +#include "rfcnb-util.h" +#include "rfcnb-io.h" +#include + + +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 +#include + +int RFCNB_errno = 0; +int RFCNB_saved_errno = 0; +#define RFCNB_ERRNO + +#include "std-includes.h" +#include +#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>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 +#include +//#include +#include +#include +//#include +#include +#include + +#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 +#include + +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__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 + +#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 +#include + +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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#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 + * + * Example ntlm authentication program for Squid, based on the + * original proxy_auth code from client_side.c, written by + * Jon Thackray . 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 + +#if HAVE_STDIO_H +#include +#endif +#if HAVE_STDLIB_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_CRYPT_H +#include +#endif +#if HAVE_PWD_H +#include +#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 + * + * 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 + +/* 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 +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 +# +# 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() { + 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 : ""); + 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