[PATCH] Bring squid-ntlm's winbind helper back from the dead

From: Andrew Bartlett <abartlet@dont-contact.us>
Date: Sat, 09 Feb 2002 14:06:19 +1100

This patch gets the squid-ntlm branch's winbind helper working again,
and adds some appealing new features.

This version works with the current CVS HEAD version of Samba, but I'll
look at getting another alpha out sometime soon.

The first thing I did was to link in -lm, which allows it to compile...

The main new feature in this patch is the ability to run without *any*
command line arguments. All the information that the winbind helper
needs is now available from winbindd itself. This makes winbind ntlm
authentication a simple matter of 'plug and play'.

Secondly, I have added support in Winbindd that gives back error strings
- mostly just the text representation of the NT_STATUS_... error at the
moment, but this should greatly assist debugging in future, as they can
now be printed to the logs.

I also re-indented the source file for my own sainity - feel free to
revert this...

I now use this in production with the Squid-2.5-PRE3 tarball, and it
seems to be working (so far...).

On the Samba side of things, I am going to look into the connection
caching issue - currently we are at on conn per auth, but if we fix that
it would make this *much* faster.

I will also give the plaintext helper a look at some stage.

Andrew Bartlett

(I'm not on the list, so CC me in replies)

-- 
Andrew Bartlett                                 abartlet@pcug.org.au
Manager, Authentication Subsystems, Samba Team  abartlet@samba.org
Student Network Administrator, Hawker College   abartlet@hawkerc.net
http://samba.org     http://build.samba.org     http://hawkerc.net

? Makefile.in
? Makefile
? .deps
? wb_ntlmauth
Index: Makefile.am
===================================================================
RCS file: /cvsroot/squid/squid/src/auth/ntlm/helpers/winbind/Attic/Makefile.am,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 Makefile.am
--- Makefile.am 3 Jan 2002 11:09:28 -0000 1.1.2.5
+++ Makefile.am 9 Feb 2002 02:31:58 -0000
@@ -8,4 +8,4 @@
 wb_ntlmauth_SOURCES = wb_ntlm_auth.c wb_common.c
 INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \
     -I$(top_srcdir)/src
-LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth
\ No newline at end of file
+LDADD = -L$(top_builddir)/lib -lmiscutil -lntlmauth -lm
\ No newline at end of file
Index: wb_ntlm_auth.c
===================================================================
RCS file: /cvsroot/squid/squid/src/auth/ntlm/helpers/winbind/Attic/wb_ntlm_auth.c,v
retrieving revision 1.1.2.14
diff -u -r1.1.2.14 wb_ntlm_auth.c
--- wb_ntlm_auth.c 24 Jan 2002 00:25:03 -0000 1.1.2.14
+++ wb_ntlm_auth.c 9 Feb 2002 02:31:59 -0000
@@ -1,5 +1,6 @@
 /*
  * (C) 2000 Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it>
+ * (C) 2002 Andrew Bartlett <abartlet@samba.org>
  *
  * Distributed freely under the terms of the GNU General Public License,
  * version 2. See the file COPYING for licensing details
@@ -53,28 +54,27 @@
 #endif
 
 void authfail(char *domain, char *user, char *reason) {
- /* TODO: -move away from SEND-type gcc-isms
- * -prepare for protocol extension as soon as rbcollins is ready
- */
- SEND2("NA %s\\%s auth failure because: %s",domain,user,reason);
+ /* TODO: -move away from SEND-type gcc-isms
+ * -prepare for protocol extension as soon as rbcollins is ready
+ */
+ SEND2("NA %s\\%s auth failure because: %s",domain,user,reason);
 }
 
 void authok(const char *domain, const char *user) {
- SEND2("AF %s\\%s",domain,user);
+ SEND2("AF %s\\%s",domain,user);
 }
 
 void sendchallenge(const char * challenge) {
- SEND2("TT %s",challenge);
+ SEND2("TT %s",challenge);
 }
 
 void helperfail(const char *reason) {
- SEND2("BH %s",reason);
+ SEND2("BH %s",reason);
 }
 
 char debug_enabled=0;
 char *myname;
 pid_t mypid;
-char *target_domain;
 
 static void
 lc(char *string)
@@ -86,272 +86,318 @@
         }
 }
 
+static void
+uc(char *string)
+{
+ char *p = string, c;
+ while ((c = *p)) {
+ *p = toupper(c);
+ p++;
+ }
+}
+
 
 
 NSS_STATUS winbindd_request(int req_type,
- struct winbindd_request *request,
- struct winbindd_response *response);
-
+ struct winbindd_request *request,
+ struct winbindd_response *response);
+
 
 static tristate have_urandom = DONTKNOW;
 FILE *urandom_file=NULL;
 
 void init_random() {
- if (have_urandom == DONTKNOW) {
- int result=0;
- struct stat st;
- result=stat(ENTROPY_SOURCE,&st);
- if (result != 0 || ! (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
- debug("Entropy source " ENTROPY_SOURCE " is unavailable\n");
- have_urandom=NO;
- }
- if ((urandom_file = fopen(ENTROPY_SOURCE,"r")) == NULL) {
- unsigned int seed;
- struct timeval t;
- warn("Can't open entropy source " ENTROPY_SOURCE "\n");
- have_urandom=NO;
- gettimeofday(&t,NULL);
- seed=squid_random()*getpid()*t.tv_sec*t.tv_usec;
- squid_srandom(seed);
- } else {
- have_urandom=YES;
- }
- }
+ if (have_urandom == DONTKNOW) {
+ int result=0;
+ struct stat st;
+ result=stat(ENTROPY_SOURCE,&st);
+ if (result != 0 || ! (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
+ debug("Entropy source " ENTROPY_SOURCE " is unavailable\n");
+ have_urandom=NO;
+ }
+ if ((urandom_file = fopen(ENTROPY_SOURCE,"r")) == NULL) {
+ unsigned int seed;
+ struct timeval t;
+ warn("Can't open entropy source " ENTROPY_SOURCE "\n");
+ have_urandom=NO;
+ gettimeofday(&t,NULL);
+ seed=squid_random()*getpid()*t.tv_sec*t.tv_usec;
+ squid_srandom(seed);
+ } else {
+ have_urandom=YES;
+ }
+ }
 }
 
 static unsigned char challenge[CHALLENGE_LEN+1];
 static char *build_challenge(void) {
- size_t gotchars;
- unsigned char j;
- switch (have_urandom) {
- case YES:
- if ((gotchars=fread(&challenge,CHALLENGE_LEN,1,urandom_file))==0) {
- /* couldn't get a challenge. Fall back to random() and friends.
- notice that even a single changed byte is good enough for us */
- have_urandom=NO;
- return build_challenge();
- }
- return challenge;
- case NO:
+ size_t gotchars;
+ unsigned char j;
+ switch (have_urandom) {
+ case YES:
+ if ((gotchars=fread(&challenge,CHALLENGE_LEN,1,urandom_file))==0) {
+ /* couldn't get a challenge. Fall back to random() and friends.
+ notice that even a single changed byte is good enough for us */
+ have_urandom=NO;
+ return build_challenge();
+ }
+ return challenge;
+ case NO:
                 if (!(squid_random()%100)) { /* sometimes */
                         init_random();
                 }
- for (j=0;j<CHALLENGE_LEN;j++)
- challenge[j]=(unsigned char)(squid_random()%256);
- return challenge;
- default:
- warn("Critical internal error. Somebody forgot to initialize "
- "the random system. Exiting.\n");
- exit(1);
- }
+ for (j=0;j<CHALLENGE_LEN;j++)
+ challenge[j]=(unsigned char)(squid_random()%256);
+ return challenge;
+ default:
+ warn("Critical internal error. Somebody forgot to initialize "
+ "the random system. Exiting.\n");
+ exit(1);
+ }
 }
 
 lstring lmhash, nthash;
 static char have_nthash=0; /* simple flag. A tad dirty.. */
-struct winbindd_request request;
-struct winbindd_response response;
 
 void do_authenticate(ntlm_authenticate *auth, int auth_length) {
         lstring tmp;
         int tocopy;
         NSS_STATUS winbindd_result;
- char *domain,*user;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ char *domain,*user;
+
+ memset(&request, 0, sizeof(struct winbindd_request));
+
+ memset(&response, 0, sizeof(struct winbindd_response));
         
         /* domain */
         tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
         if (tmp.str == NULL || tmp.l == 0) { /* no domain supplied */
- authfail("-","-","No domain supplied");
- return;
+ request.data.auth_crap.domain[0]=0;
+ } else {
+ tocopy=min(tmp.l+1,sizeof(fstring));
+ xstrncpy(request.data.auth_crap.domain, tmp.str, tocopy);
         }
- tocopy=min(tmp.l,sizeof(fstring));
- xstrncpy(request.data.auth_crap.domain, tmp.str, tocopy);
- domain=request.data.auth_crap.domain; /* just a shortcut */
-
+
+ domain=request.data.auth_crap.domain; /* just a shortcut */
+
         /* username */
         tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
         if (tmp.str == NULL || tmp.l == 0) {
- authfail(domain,"-","No username in request");
+ authfail(domain,"-","No username in request");
                 return;
         }
- tocopy=min(sizeof(fstring),tmp.l);
+
+ tocopy=min(sizeof(fstring),tmp.l+1);
         xstrncpy(request.data.auth_crap.user,tmp.str,tocopy);
- user=request.data.auth_crap.user;
+ user=request.data.auth_crap.user;
         
         /* now the LM hash */
         lmhash = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
- switch (lmhash.l) {
- case 0:
- warn("No lm hash provided by user %s\\%s\n",domain,user);
- request.data.auth_crap.lm_resp_len=0;
- break;
- case 24:
- memcpy(request.data.auth_crap.lm_resp,lmhash.str,24);
- request.data.auth_crap.lm_resp_len=24;
- break;
- default:
- authfail(domain,user,"Broken LM hash response");
+ switch (lmhash.l) {
+ case 0:
+ warn("No lm hash provided by user %s\\%s\n",domain,user);
+ request.data.auth_crap.lm_resp_len=0;
+ break;
+ case 24:
+ memcpy(request.data.auth_crap.lm_resp,lmhash.str,24);
+ request.data.auth_crap.lm_resp_len=24;
+ break;
+ default:
+ authfail(domain,user,"Broken LM hash response");
                 return;
- }
+ }
   
         nthash = ntlm_fetch_string((char *) auth, auth_length, &auth->ntresponse);
- switch (nthash.l) {
- case 0:
- debug("no nthash\n");
- request.data.auth_crap.nt_resp_len=0;
- break;
- case 24:
- memcpy(request.data.auth_crap.nt_resp,nthash.str,24);
- request.data.auth_crap.nt_resp_len=24;
- default:
- authfail(domain,user,"Broken NT hash response");
- return;
- }
-
- debug("Checking user '%s\\%s' lmhash='%24s', have_nthash=%d, "
- "nthash='%24s'\n",
- domain, user, lmhash.str, have_nthash, nthash.str);
+ switch (nthash.l) {
+ case 0:
+ debug("no nthash\n");
+ request.data.auth_crap.nt_resp_len=0;
+ break;
+ case 24:
+ memcpy(request.data.auth_crap.nt_resp,nthash.str, 24);
+ request.data.auth_crap.nt_resp_len=24;
+ break;
+ default:
+ debug("nthash len = %d\n", nthash.l);
+ authfail(domain,user,"Broken NT hash response");
+ return;
+ }
 
- memset(&response,0,sizeof(struct winbindd_response));
-
- memcpy(request.data.auth_crap.chal,challenge,CHALLENGE_LEN);
+ debug("Checking user '%s\\%s' lmhash len =%d, have_nthash=%d, "
+ "nthash len=%d\n",
+ domain, user, lmhash.l, have_nthash, nthash.l);
+
+ memcpy(request.data.auth_crap.chal, challenge, CHALLENGE_LEN);
 
         winbindd_result = winbindd_request(WINBINDD_PAM_AUTH_CRAP,
- &request, &response);
- debug("winbindd result: %d\n",winbindd_result);
+ &request, &response);
+ debug("winbindd result: %d\n", winbindd_result);
 
         if (winbindd_result==WINBINDD_OK) {
                 lc(domain);
- lc(user);
- authok(domain,user);
+ lc(user);
+ authok(domain,user);
         } else {
- authfail(domain,user,"Authentication error");
+ char error_buf[200];
+ snprintf(error_buf, sizeof(error_buf), "Authentication Failure (%s)", response.data.auth.error_string);
+ authfail(domain, user, error_buf);
         }
         return; /* useless */
 }
 
-void manage_request(void) {
- char buf[BUFFER_SIZE+1];
- char *c, *decoded;
+void manage_request(char *target_domain) {
+ char buf[BUFFER_SIZE+1];
+ char *c, *decoded;
         ntlmhdr *fast_header;
         
   
- if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
- warn("fgets() failed! dying..... errno=%d (%s)\n", errno,
- strerror(errno));
- exit(1); /* BIIG buffer */
- }
+ if (fgets(buf, BUFFER_SIZE, stdin) == NULL) {
+ warn("fgets() failed! dying..... errno=%d (%s)\n", errno,
+ strerror(errno));
+ exit(1); /* BIIG buffer */
+ }
         
- c=memchr(buf,'\n',BUFFER_SIZE);
- if (c)
- *c='\0';
- else {
- warn("No newline in '%s'. Dying.\n",buf);
+ c=memchr(buf,'\n',BUFFER_SIZE);
+ if (c)
+ *c='\0';
+ else {
+ warn("No newline in '%s'. Dying.\n",buf);
                 exit(1);
         }
   
- debug("Got '%s' from squid.\n",buf);
- if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */
- sendchallenge(ntlm_make_challenge(target_domain,NULL,build_challenge(),
- CHALLENGE_LEN));
- return;
- }
- if (strncmp(buf,"KK ",3) != 0 ) { /* not an auth-request */
- helperfail("illegal request received");
- warn("Illegal request received: '%s'\n",buf);
- return;
- }
- /* At this point I'm sure it's a KK */
+ debug("Got '%s' from squid.\n",buf);
+ if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */
+ sendchallenge(ntlm_make_challenge(target_domain, NULL, build_challenge(),
+ CHALLENGE_LEN));
+ return;
+ }
+ if (strncmp(buf,"KK ",3) != 0 ) { /* not an auth-request */
+ helperfail("illegal request received");
+ warn("Illegal request received: '%s'\n",buf);
+ return;
+ }
+ /* At this point I'm sure it's a KK */
         decoded=base64_decode(buf+3);
         if (!decoded) { /* decoding failure, return error */
- authfail("-","-","Auth-format error, base64-decoding error");
+ authfail("-","-","Auth-format error, base64-decoding error");
                 return;
         }
- fast_header = (struct _ntlmhdr *) decoded;
+ fast_header = (struct _ntlmhdr *) decoded;
         
- /* sanity-check: it IS a NTLMSSP packet, isn't it? */
- if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) {
- authfail("-","-","Broken NTLM packet, missing NTLMSSP signature");
+ /* sanity-check: it IS a NTLMSSP packet, isn't it? */
+ if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) {
+ authfail("-","-","Broken NTLM packet, missing NTLMSSP signature");
                 return;
- }
+ }
         /* Understand what we got */
- switch (fast_header->type) {
+ switch (fast_header->type) {
         case NTLM_NEGOTIATE:
- authfail("-","-","Received neg-request while expecting auth packet");
+ authfail("-","-","Received neg-request while expecting auth packet");
                 return;
- case NTLM_CHALLENGE:
- authfail("-","-","Received challenge. Refusing to abide");
+ case NTLM_CHALLENGE:
+ authfail("-","-","Received challenge. Refusing to abide");
                 return;
         case NTLM_AUTHENTICATE:
                 do_authenticate((ntlm_authenticate *) decoded, (strlen(buf)-3)*3/4);
                 return;
         default:
- helperfail("Unknown authentication packet type");
+ helperfail("Unknown authentication packet type");
                 return;
         }
         /* notreached */
         return;
 }
 
-void
-process_options(int argc, char *argv[])
+static char *get_winbind_domain(void)
 {
- int opt;
+ struct winbindd_response response;
+ char *domain;
 
- while (-1 != (opt = getopt(argc,argv,"d"))) {
- switch (opt) {
- case 'd':
- debug_enabled=1;
- break;
- default:
- warn("Unknown option: -%c. Exiting\n",opt);
- exit(1);
- break; /* not reached */
- }
- if (optind < argc-1) {
- warn("I need a domain name to set as auth-target. Exiting\n");
- exit(1);
- return; /* not reached */
- }
- target_domain=argv[optind];
- warn("target domain is %s\n",target_domain);
- }
- return;
+ ZERO_STRUCT(response);
+
+ /* Send off request */
+
+ if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
+ NSS_STATUS_SUCCESS) {
+ warn("could not obtain winbind domain name!\n");
+ exit(1);
+ }
+
+ domain = strdup(response.data.domain_name);
+ uc(domain);
+
+ warn("target domain is %s\n", domain);
+ return domain;
+}
+
+char *process_options(int argc, char *argv[])
+{
+ int opt;
+ char *target_domain = NULL;
+
+ while (-1 != (opt = getopt(argc,argv,"d"))) {
+ switch (opt) {
+ case 'd':
+ debug_enabled=1;
+ break;
+ default:
+ warn("Unknown option: -%c. Exiting\n",opt);
+ exit(1);
+ break; /* not reached */
+ }
+ if (optind >= argc-1) {
+ target_domain=argv[optind];
+ warn("target domain is %s\n",target_domain);
+ }
+ }
+ return target_domain;
 }
 
 void check_winbindd() {
- NSS_STATUS r;
- r=winbindd_request(WINBINDD_INTERFACE_VERSION,&request,&response);
- if (r!=WINBINDD_OK) {
- warn("Can't contact winbindd. Dying\n");
- exit(1);
- }
- if (response.data.interface_version!=WINBIND_INTERFACE_VERSION) {
- warn("Winbind protocol mismatch. Align squid and samba. Dying\n");
- exit(1);
- }
+ NSS_STATUS r;
+ struct winbindd_request request;
+ struct winbindd_response response;
+ r=winbindd_request(WINBINDD_INTERFACE_VERSION,&request,&response);
+ if (r!=WINBINDD_OK) {
+ warn("Can't contact winbindd. Dying\n");
+ exit(1);
+ }
+ if (response.data.interface_version!=WINBIND_INTERFACE_VERSION) {
+ warn("Winbind protocol mismatch. Align squid and samba. Dying\n");
+ exit(1);
+ }
 }
 
 int main (int argc, char ** argv) {
+ char *target_domain;
         if (argc > 0) { /* should always be true */
                 myname=strrchr(argv[0],'/');
                 if (myname==NULL)
                         myname=argv[0];
- else
- myname++;
+ else
+ myname++;
         } else {
                 myname="(unknown)";
         }
         mypid=getpid();
- process_options(argc,argv);
- debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__
- " starting up...\n");
- check_winbindd();
- /* initialize FDescs */
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
- init_random();
- while(1) {
- manage_request();
- }
- return 0;
+ target_domain = process_options(argc,argv);
+ debug("ntlm winbindd auth helper build " __DATE__ ", " __TIME__
+ " starting up...\n");
+
+ check_winbindd();
+
+ if (target_domain == NULL) {
+ target_domain = get_winbind_domain();
+ }
+
+ /* initialize FDescs */
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+ init_random();
+ while(1) {
+ manage_request(target_domain);
+ }
+ return 0;
 }
Index: winbindd_nss.h
===================================================================
RCS file: /cvsroot/squid/squid/src/auth/ntlm/helpers/winbind/Attic/winbindd_nss.h,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 winbindd_nss.h
--- winbindd_nss.h 29 Jan 2002 21:15:59 -0000 1.1.2.3
+++ winbindd_nss.h 9 Feb 2002 02:31:59 -0000
@@ -1,6 +1,5 @@
 /*
- Unix SMB/Netbios implementation.
- Version 2.0
+ Unix SMB/CIFS implementation.
 
    Winbind daemon for ntdom nss module
 
@@ -37,7 +36,7 @@
 
 /* Update this when you change the interface. */
 
-#define WINBIND_INTERFACE_VERSION 3
+#define WINBIND_INTERFACE_VERSION 4
 
 /* Socket commands */
 
@@ -93,6 +92,8 @@
         WINBINDD_INFO, /* Various bit of info. Currently just tidbits */
         WINBINDD_DOMAIN_NAME, /* The domain this winbind server is a member of (lp_workgroup()) */
 
+ WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
+
         /* Placeholder for end of cmd list */
 
         WINBINDD_NUM_CMDS
@@ -198,6 +199,13 @@
                         fstring samba_version;
                 } info;
                 fstring domain_name;
+
+ struct auth_reply {
+ uint32 nt_status;
+ fstring nt_status_string;
+ fstring error_string;
+ int pam_error;
+ } auth;
         } data;
 
         /* Variable length return data */
Received on Fri Feb 08 2002 - 20:10:39 MST

This archive was generated by hypermail pre-2.1.9 : Tue Dec 09 2003 - 16:14:47 MST