]> git.ozlabs.org Git - ppp.git/commitdiff
Add winbind plugin from Andrew Bartlet.
authorPaul Mackerras <paulus@samba.org>
Thu, 4 Nov 2004 12:00:07 +0000 (12:00 +0000)
committerPaul Mackerras <paulus@samba.org>
Thu, 4 Nov 2004 12:00:07 +0000 (12:00 +0000)
Changes to chap_ms.[ch] needed by winbind.

pppd/chap_ms.c
pppd/chap_ms.h
pppd/plugins/Makefile.linux
pppd/plugins/winbind.c [new file with mode: 0644]

index 16fb3a881e91f7bcaa83f1b8f88a3fe4866d7125..1c4356c7cee829abdbf78020fbcd729c33f54a18 100644 (file)
@@ -74,7 +74,7 @@
  *
  */
 
-#define RCSID  "$Id: chap_ms.c,v 1.31 2004/04/14 02:39:39 carlsonj Exp $"
+#define RCSID  "$Id: chap_ms.c,v 1.32 2004/11/04 12:00:07 paulus Exp $"
 
 #ifdef CHAPMS
 
 static const char rcsid[] = RCSID;
 
 
-static void    ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
 static void    ascii2unicode __P((char[], int, u_char[]));
 static void    NTPasswordHash __P((char *, int, u_char[MD4_SIGNATURE_SIZE]));
 static void    ChallengeResponse __P((u_char *, u_char *, u_char[24]));
 static void    ChapMS_NT __P((u_char *, char *, int, u_char[24]));
 static void    ChapMS2_NT __P((char *, u_char[16], char *, char *, int,
                                u_char[24]));
-static void    GenerateAuthenticatorResponse __P((char*, int, u_char[24],
-                                                  u_char[16], u_char *,
-                                                  char *, u_char[41]));
+static void    GenerateAuthenticatorResponsePlain
+                       __P((char*, int, u_char[24], u_char[16], u_char *,
+                            char *, u_char[41]));
 #ifdef MSLANMAN
 static void    ChapMS_LANMan __P((u_char *, char *, int, MS_ChapResponse *));
 #endif
@@ -469,7 +468,7 @@ ChallengeResponse(u_char *challenge,
 #endif
 }
 
-static void
+void
 ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,
              char *username, u_char Challenge[8])
     
@@ -583,8 +582,8 @@ ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
 #endif
 
 
-static void
-GenerateAuthenticatorResponse(char *secret, int secret_len,
+void
+GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
                              u_char NTResponse[24], u_char PeerChallenge[16],
                              u_char *rchallenge, char *username,
                              u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
@@ -606,20 +605,11 @@ GenerateAuthenticatorResponse(char *secret, int secret_len,
 
     int                i;
     SHA1_CTX   sha1Context;
-    u_char     unicodePassword[MAX_NT_PASSWORD * 2];
-    u_char     PasswordHash[MD4_SIGNATURE_SIZE];
-    u_char     PasswordHashHash[MD4_SIGNATURE_SIZE];
     u_char     Digest[SHA1_SIGNATURE_SIZE];
     u_char     Challenge[8];
 
-    /* Hash (x2) the Unicode version of the secret (== password). */
-    ascii2unicode(secret, secret_len, unicodePassword);
-    NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
-    NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
-                  PasswordHashHash);
-
     SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
+    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
     SHA1_Update(&sha1Context, NTResponse, 24);
     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
     SHA1_Final(Digest, &sha1Context);
@@ -638,6 +628,28 @@ GenerateAuthenticatorResponse(char *secret, int secret_len,
 }
 
 
+static void
+GenerateAuthenticatorResponsePlain
+               (char *secret, int secret_len,
+                u_char NTResponse[24], u_char PeerChallenge[16],
+                u_char *rchallenge, char *username,
+                u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1])
+{
+    u_char     unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char     PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char     PasswordHashHash[MD4_SIGNATURE_SIZE];
+
+    /* Hash (x2) the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash((char *)unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash((char *)PasswordHash, sizeof(PasswordHash),
+                  PasswordHashHash);
+
+    GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
+                                 rchallenge, username, authResponse);
+}
+
+
 #ifdef MPPE
 /*
  * Set mppe_xxxx_key from the NTPasswordHashHash.
@@ -658,6 +670,8 @@ mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE])
     /* Same key in both directions. */
     BCOPY(Digest, mppe_send_key, sizeof(mppe_send_key));
     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
+
+    mppe_keys_set = 1;
 }
 
 /*
@@ -680,14 +694,15 @@ Set_Start_Key(u_char *rchallenge, char *secret, int secret_len)
 
 /*
  * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
+ *
+ * This helper function used in the Winbind module, which gets the
+ * NTHashHash from the server.
  */
-static void
-SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
+void
+mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+              u_char NTResponse[24], int IsServer)
 {
     SHA1_CTX   sha1Context;
-    u_char     unicodePassword[MAX_NT_PASSWORD * 2];
-    u_char     PasswordHash[MD4_SIGNATURE_SIZE];
-    u_char     PasswordHashHash[MD4_SIGNATURE_SIZE];
     u_char     MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */
     u_char     Digest[SHA1_SIGNATURE_SIZE];    /* >= MPPE_MAX_KEY_LEN */
 
@@ -733,13 +748,8 @@ SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
          0x6b, 0x65, 0x79, 0x2e };
     u_char *s;
 
-    /* Hash (x2) the Unicode version of the secret (== password). */
-    ascii2unicode(secret, secret_len, unicodePassword);
-    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
-    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
-
     SHA1_Init(&sha1Context);
-    SHA1_Update(&sha1Context, PasswordHashHash, sizeof(PasswordHashHash));
+    SHA1_Update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
     SHA1_Update(&sha1Context, NTResponse, 24);
     SHA1_Update(&sha1Context, Magic1, sizeof(Magic1));
     SHA1_Final(MasterKey, &sha1Context);
@@ -775,6 +785,24 @@ SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
     SHA1_Final(Digest, &sha1Context);
 
     BCOPY(Digest, mppe_recv_key, sizeof(mppe_recv_key));
+
+    mppe_keys_set = 1;
+}
+
+/*
+ * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
+ */
+static void
+SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer)
+{
+    u_char     unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char     PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char     PasswordHashHash[MD4_SIGNATURE_SIZE];
+    /* Hash (x2) the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
+    mppe_set_keys2(PasswordHashHash, NTResponse, IsServer);
 }
 
 #endif /* MPPE */
@@ -784,9 +812,6 @@ void
 ChapMS(u_char *rchallenge, char *secret, int secret_len,
        MS_ChapResponse *response)
 {
-#if 0
-    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
-#endif
     BZERO(response, sizeof(*response));
 
     ChapMS_NT(rchallenge, secret, secret_len, response->NTResp);
@@ -802,7 +827,6 @@ ChapMS(u_char *rchallenge, char *secret, int secret_len,
 
 #ifdef MPPE
     Set_Start_Key(rchallenge, secret, secret_len);
-    mppe_keys_set = 1;
 #endif
 }
 
@@ -841,13 +865,12 @@ ChapMS2(u_char *rchallenge, u_char *PeerChallenge,
               secret, secret_len, response->NTResp);
 
     /* Generate the Authenticator Response. */
-    GenerateAuthenticatorResponse(secret, secret_len, response->NTResp,
-                                 response->PeerChallenge, rchallenge,
-                                 user, authResponse);
+    GenerateAuthenticatorResponsePlain(secret, secret_len, response->NTResp,
+                                      response->PeerChallenge, rchallenge,
+                                      user, authResponse);
 
 #ifdef MPPE
     SetMasterKeys(secret, secret_len, response->NTResp, authenticator);
-    mppe_keys_set = 1;
 #endif
 }
 
index 4e2ac11b67171f84b7eefd58e3c6434152f89145..73b41de62e592922b4dcd3c63cdae1526b54d6d1 100644 (file)
@@ -27,7 +27,7 @@
  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $Id: chap_ms.h,v 1.10 2003/06/11 23:56:26 paulus Exp $
+ * $Id: chap_ms.h,v 1.11 2004/11/04 12:00:07 paulus Exp $
  */
 
 #ifndef __CHAPMS_INCLUDE__
@@ -94,8 +94,17 @@ void ChapMS2 __P((u_char *, u_char *, char *, char *, int,
                  MS_Chap2Response *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int));
 #ifdef MPPE
 void mppe_set_keys __P((u_char *, u_char[MD4_SIGNATURE_SIZE]));
+void mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+                   u_char NTResponse[24], int IsServer);
 #endif
 
+void   ChallengeHash __P((u_char[16], u_char *, char *, u_char[8]));
+
+void GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+                       u_char NTResponse[24], u_char PeerChallenge[16],
+                       u_char *rchallenge, char *username,
+                       u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]);
+
 void chapms_init(void);
 
 #define __CHAPMS_INCLUDE__
index 80b0ae01da8a07566fe3729b0855e4e046ad6f5a..10bc4f0c7de9641045c57e5c68021783d32ced3a 100644 (file)
@@ -12,7 +12,7 @@ LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
 SUBDIRS := rp-pppoe
 # Uncomment the next line to include the radius authentication plugin
 # SUBDIRS += radius
-PLUGINS := minconn.so passprompt.so passwordfd.so
+PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
 
 # include dependencies if present
 ifeq (.depend,$(wildcard .depend))
diff --git a/pppd/plugins/winbind.c b/pppd/plugins/winbind.c
new file mode 100644 (file)
index 0000000..1abe437
--- /dev/null
@@ -0,0 +1,685 @@
+/***********************************************************************
+*
+* winbind.c
+*
+* WINBIND plugin for pppd.  Performs PAP, CHAP, MS-CHAP, MS-CHAPv2
+* authentication using WINBIND to contact a NT-style PDC.
+* 
+* Based on the structure of the radius module.
+*
+* Copyright (C) 2003 Andrew Bartlet <abartlet@samba.org>
+*
+* Copyright 1999 Paul Mackerras, Alan Curry. 
+* (pipe read code from passpromt.c)
+*
+* Copyright (C) 2002 Roaring Penguin Software Inc.
+*
+* Based on a patch for ipppd, which is:
+*    Copyright (C) 1996, Matjaz Godec <gody@elgo.si>
+*    Copyright (C) 1996, Lars Fenneberg <in5y050@public.uni-hamburg.de>
+*    Copyright (C) 1997, Miguel A.L. Paraz <map@iphil.net>
+*
+* Uses radiusclient library, which is:
+*    Copyright (C) 1995,1996,1997,1998 Lars Fenneberg <lf@elemental.net>
+*    Copyright (C) 2002 Roaring Penguin Software Inc.
+*
+* MPPE support is by Ralf Hofmann, <ralf.hofmann@elvido.net>, with
+* modification from Frank Cusack, <frank@google.com>.
+*
+* Updated on 2003-12-12 to support updated PPP plugin API from latest CVS
+*    Copyright (C) 2003, Sean E. Millichamp <sean at bruenor dot org>
+*
+* This plugin may be distributed according to the terms of the GNU
+* General Public License, version 2 or (at your option) any later version.
+*
+***********************************************************************/
+
+#include "pppd.h"
+#include "chap-new.h"
+#include "chap_ms.h"
+#ifdef MPPE
+#include "md5.h"
+#endif
+#include "fsm.h"
+#include "ipcp.h"
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#define BUF_LEN 1024
+
+#define NOT_AUTHENTICATED 0
+#define AUTHENTICATED 1
+
+static char *ntlm_auth = NULL;
+
+static option_t Options[] = {
+    { "ntlm_auth-helper", o_string, &ntlm_auth },
+    { NULL }
+};
+
+static int
+winbind_secret_check(void);
+
+static int winbind_pap_auth(char *user,
+                          char *passwd,
+                          char **msgp,
+                          struct wordlist **paddrs,
+                          struct wordlist **popts);
+static int winbind_chap_verify(char *user, char *ourname, int id,
+                              struct chap_digest_type *digest,
+                              unsigned char *challenge,
+                              unsigned char *response,
+                              char *message, int message_space);
+static int winbind_allowed_address(u_int32_t addr); 
+
+char pppd_version[] = VERSION;
+
+/**********************************************************************
+* %FUNCTION: plugin_init
+* %ARGUMENTS:
+*  None
+* %RETURNS:
+*  Nothing
+* %DESCRIPTION:
+*  Initializes WINBIND plugin.
+***********************************************************************/
+void
+plugin_init(void)
+{
+    pap_check_hook = winbind_secret_check;
+    pap_auth_hook = winbind_pap_auth;
+
+    chap_check_hook = winbind_secret_check;
+    chap_verify_hook = winbind_chap_verify;
+
+    allowed_address_hook = winbind_allowed_address;
+
+    /* Don't ask the peer for anything other than MS-CHAP or MS-CHAP V2 */
+    chap_mdtype_all &= (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT);
+    
+    add_options(Options);
+
+    info("WINBIND plugin initialized.");
+}
+
+/**
+ Routine to get hex characters and turn them into a 16 byte array.
+ the array can be variable length, and any non-hex-numeric
+ characters are skipped.  "0xnn" or "0Xnn" is specially catered
+ for.
+
+ valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
+
+**/
+
+/* 
+   Unix SMB/CIFS implementation.
+   Samba utility functions
+   
+   Copyright (C) Andrew Tridgell 1992-2001
+   Copyright (C) Simo Sorce      2001-2002
+   Copyright (C) Martin Pool     2003
+   
+   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.
+*/
+
+size_t strhex_to_str(char *p, size_t len, const char *strhex)
+{
+       size_t i;
+       size_t num_chars = 0;
+       unsigned char   lonybble, hinybble;
+       const char     *hexchars = "0123456789ABCDEF";
+       char           *p1 = NULL, *p2 = NULL;
+
+       for (i = 0; i < len && strhex[i] != 0; i++) {
+               if (strncmp(hexchars, "0x", 2) == 0) {
+                       i++; /* skip two chars */
+                       continue;
+               }
+
+               if (!(p1 = strchr(hexchars, toupper(strhex[i]))))
+                       break;
+
+               i++; /* next hex digit */
+
+               if (!(p2 = strchr(hexchars, toupper(strhex[i]))))
+                       break;
+
+               /* get the two nybbles */
+               hinybble = (p1 - hexchars);
+               lonybble = (p2 - hexchars);
+
+               p[num_chars] = (hinybble << 4) | lonybble;
+               num_chars++;
+
+               p1 = NULL;
+               p2 = NULL;
+       }
+       return num_chars;
+}
+
+static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * Encode a base64 string into a malloc()ed string caller to free.
+ *
+ *From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
+ **/
+char * base64_encode(const char *data)
+{
+       int bits = 0;
+       int char_count = 0;
+       size_t out_cnt = 0;
+       size_t len = strlen(data);
+       size_t output_len = strlen(data) * 2;
+       char *result = malloc(output_len); /* get us plenty of space */
+
+       while (len-- && out_cnt < (output_len) - 5) {
+               int c = (unsigned char) *(data++);
+               bits += c;
+               char_count++;
+               if (char_count == 3) {
+                       result[out_cnt++] = b64[bits >> 18];
+                       result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+                       result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+           result[out_cnt++] = b64[bits & 0x3f];
+           bits = 0;
+           char_count = 0;
+       } else {
+           bits <<= 8;
+       }
+    }
+    if (char_count != 0) {
+       bits <<= 16 - (8 * char_count);
+       result[out_cnt++] = b64[bits >> 18];
+       result[out_cnt++] = b64[(bits >> 12) & 0x3f];
+       if (char_count == 1) {
+           result[out_cnt++] = '=';
+           result[out_cnt++] = '=';
+       } else {
+           result[out_cnt++] = b64[(bits >> 6) & 0x3f];
+           result[out_cnt++] = '=';
+       }
+    }
+    result[out_cnt] = '\0';    /* terminate */
+    return result;
+}
+
+unsigned int run_ntlm_auth(const char *username, 
+                          const char *domain, 
+                          const char *full_username,
+                          const char *plaintext_password,
+                          const u_char *challenge,
+                          size_t challenge_length,
+                          const u_char *lm_response, 
+                          size_t lm_response_length,
+                          const u_char *nt_response, 
+                          size_t nt_response_length,
+                          u_char nt_key[16], 
+                          char **error_string) 
+{
+       
+       pid_t forkret;
+        int child_in[2];
+        int child_out[2];
+       int status;
+
+       int authenticated = NOT_AUTHENTICATED; /* not auth */
+       int got_user_session_key = 0; /* not got key */
+
+       char buffer[1024];
+
+       FILE *pipe_in;
+       FILE *pipe_out;
+       
+       int i;
+       char *challenge_hex;
+       char *lm_hex_hash;
+       char *nt_hex_hash;
+       
+        /* Make first child */
+        if (pipe(child_out) == -1) {
+                perror("pipe creation failed for child OUT!");
+        }
+
+        if (pipe(child_in) == -1) {
+                perror("pipe creation failed for child IN!");
+        }
+
+        forkret = fork();
+        if (forkret == -1) {
+                perror("fork failed!");
+               if (error_string) {
+                       *error_string = strdup("fork failed!");
+               }
+
+                return NOT_AUTHENTICATED;
+        } else if (forkret == 0) {
+               /* child - pipe out */
+               if (close(child_out[0]) == -1) {
+                       perror("error closing pipe?!? for child OUT[READFD]");
+                       exit(1);
+               }
+               if (dup2(child_out[1], 1) == -1) {
+                       perror("(child) dup2 of fdout onto STDOUT failed!");
+               }
+               
+               /* Close extra copies */
+               if (close(child_out[1]) == -1) {
+                       perror("error closing pipe?!? for child OUT[WRITEFD]");
+                       exit(1);
+               }
+
+               /* child - pipe in */
+               if (close(child_in[1]) == -1) {
+                       perror("error closing pipe?!? for child IN[WRITEFD]");
+                       exit(1);
+               }
+               if (dup2(child_in[0], 0) == -1) {
+                       perror("(child) dup2 of fdin onto STDIN failed!");
+               }
+               
+               /* Close extra copies */
+               if (close(child_in[0]) == -1) {
+                       perror("error closing pipe?!? for child IN[READFD]");
+                       exit(1);
+               }
+
+               execl("/bin/sh","sh","-c", ntlm_auth,NULL);  
+
+               /* Not reached... */
+               exit(1);
+
+       }
+
+        /* parent */
+        if (close(child_out[1]) == -1) {
+                notice("error closing pipe?!? for child OUT[1]");
+                return NOT_AUTHENTICATED;
+        }
+
+        if (close(child_in[0]) == -1) {
+                notice("error closing pipe?!? for child OUT[1]");
+                return NOT_AUTHENTICATED;
+        }
+
+       /* Need to write the User's info onto the pipe */
+
+       pipe_in = fdopen(child_in[1], "w");
+
+       pipe_out = fdopen(child_out[0], "r");
+
+       /* look for session key coming back */
+
+       if (username) {
+               char *b64_username = base64_encode(username);
+               fprintf(pipe_in, "Username:: %s\n", b64_username);
+               free(b64_username);
+       }
+
+       if (domain) {
+               char *b64_domain = base64_encode(domain);
+               fprintf(pipe_in, "NT-Domain:: %s\n", b64_domain);
+               free(b64_domain);
+       }
+
+       if (full_username) {
+               char *b64_full_username = base64_encode(full_username);
+               fprintf(pipe_in, "Full-Username:: %s\n", b64_full_username);
+               free(b64_full_username);
+       }
+
+       if (plaintext_password) {
+               char *b64_plaintext_password = base64_encode(plaintext_password);
+               fprintf(pipe_in, "Password:: %s\n", b64_plaintext_password);
+               free(b64_plaintext_password);
+       }
+
+       if (challenge_length) {
+               fprintf(pipe_in, "Request-User-Session-Key: yes\n");
+
+               challenge_hex = malloc(challenge_length*2+1);
+               
+               for (i = 0; i < challenge_length; i++)
+                       sprintf(challenge_hex + i * 2, "%02X", challenge[i]);
+               
+               fprintf(pipe_in, "LANMAN-Challenge: %s\n", challenge_hex);
+               free(challenge_hex);
+       }
+       
+       if (lm_response_length) {
+               lm_hex_hash = malloc(lm_response_length*2+1);
+               
+               for (i = 0; i < lm_response_length; i++)
+                       sprintf(lm_hex_hash + i * 2, "%02X", lm_response[i]);
+               
+               fprintf(pipe_in, "LANMAN-response: %s\n", lm_hex_hash);
+               free(lm_hex_hash);
+       }
+       
+       if (nt_response_length) {
+               nt_hex_hash = malloc(nt_response_length*2+1);
+               
+               for (i = 0; i < nt_response_length; i++)
+                       sprintf(nt_hex_hash + i * 2, "%02X", nt_response[i]);
+               
+               fprintf(pipe_in, "NT-response: %s\n", nt_hex_hash);
+               free(nt_hex_hash);
+       }
+       
+       fprintf(pipe_in, ".\n");
+       fflush(pipe_in);
+       
+       while (fgets(buffer, sizeof(buffer)-1, pipe_out) != NULL) {
+               char *message, *parameter;
+               if (buffer[strlen(buffer)-1] != '\n') {
+                       break;
+               }
+               buffer[strlen(buffer)-1] = '\0';
+               message = buffer;
+
+               if (!(parameter = strstr(buffer, ": "))) {
+                       break;
+               }
+               
+               parameter[0] = '\0';
+               parameter++;
+               parameter[0] = '\0';
+               parameter++;
+               
+               if (strcmp(message, ".") == 0) {
+                       /* end of sequence */
+                       break;
+               } else if (strcasecmp(message, "Authenticated") == 0) {
+                       if (strcasecmp(parameter, "Yes") == 0) {
+                               authenticated = AUTHENTICATED;
+                       } else {
+                               notice("Winbind has declined authentication for user!");
+                               authenticated = NOT_AUTHENTICATED;
+                       }
+               } else if (strcasecmp(message, "User-session-key") == 0) {
+                       /* length is the number of characters to parse */
+                       if (nt_key) { 
+                               if (strhex_to_str(nt_key, 32, parameter) == 16) {
+                                       got_user_session_key = 1;
+                               } else {
+                                       notice("NT session key for user was not 16 bytes!");
+                               }
+                       }
+               } else if (strcasecmp(message, "Error") == 0) {
+                       authenticated = NOT_AUTHENTICATED;
+                       if (error_string)
+                               *error_string = strdup(parameter);
+               } else if (strcasecmp(message, "Authentication-Error") == 0) {
+                       authenticated = NOT_AUTHENTICATED;
+                       if (error_string)
+                               *error_string = strdup(parameter);
+               } else {
+                       notice("unrecognised input from ntlm_auth helper - %s: %s", message, parameter); 
+               }
+       }
+
+        /* parent */
+        if (close(child_out[0]) == -1) {
+                notice("error closing pipe?!? for child OUT[0]");
+                return NOT_AUTHENTICATED;
+        }
+
+       /* parent */
+        if (close(child_in[1]) == -1) {
+                notice("error closing pipe?!? for child IN[1]");
+                return NOT_AUTHENTICATED;
+        }
+
+       while ((wait(&status) == -1) && errno == EINTR)
+                ;
+
+       if ((authenticated == AUTHENTICATED) && nt_key && !got_user_session_key) {
+               notice("Did not get user session key, despite being authenticated!");
+               return NOT_AUTHENTICATED;
+       }
+       return authenticated;
+}
+
+/**********************************************************************
+* %FUNCTION: winbind_secret_check
+* %ARGUMENTS:
+*  None
+* %RETURNS:
+*  1 -- we are ALWAYS willing to supply a secret. :-)
+* %DESCRIPTION:
+* Tells pppd that we will try to authenticate the peer, and not to
+* worry about looking in /etc/ppp/ *-secrets
+***********************************************************************/
+static int
+winbind_secret_check(void)
+{
+    return 1;
+}
+
+/**********************************************************************
+* %FUNCTION: winbind_pap_auth
+* %ARGUMENTS:
+*  user -- user-name of peer
+*  passwd -- password supplied by peer
+*  msgp -- Message which will be sent in PAP response
+*  paddrs -- set to a list of possible peer IP addresses
+*  popts -- set to a list of additional pppd options
+* %RETURNS:
+*  1 if we can authenticate, -1 if we cannot.
+* %DESCRIPTION:
+* Performs PAP authentication using WINBIND
+***********************************************************************/
+static int
+winbind_pap_auth(char *user,
+               char *password,
+               char **msgp,
+               struct wordlist **paddrs,
+               struct wordlist **popts)
+{
+       if (run_ntlm_auth(NULL, NULL, user, password, NULL, 0, NULL, 0, NULL, 0, NULL, msgp) == AUTHENTICATED) {
+               return 1;
+       } 
+       return -1;
+}
+
+/**********************************************************************
+* %FUNCTION: winbind_chap_auth
+* %ARGUMENTS:
+*  user -- user-name of peer
+*  remmd -- hash received from peer
+*  remmd_len -- length of remmd
+*  cstate -- pppd's chap_state structure
+* %RETURNS:
+*  AUTHENTICATED (1) if we can authenticate, NOT_AUTHENTICATED (0) if we cannot.
+* %DESCRIPTION:
+* Performs MS-CHAP and MS-CHAPv2 authentication using WINBIND.
+***********************************************************************/
+
+static int 
+winbind_chap_verify(char *user, char *ourname, int id,
+                   struct chap_digest_type *digest,
+                   unsigned char *challenge,
+                   unsigned char *response,
+                   char *message, int message_space)
+{
+       int challenge_len, response_len;
+       char domainname[256];
+       char *domain;
+       char *username;
+       char *p;
+       char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
+
+       /* The first byte of each of these strings contains their length */
+       challenge_len = *challenge++;
+       response_len = *response++;
+       
+       /* remove domain from "domain\username" */
+       if ((username = strrchr(user, '\\')) != NULL)
+               ++username;
+       else
+               username = user;
+       
+       strlcpy(domainname, user, sizeof(domainname));
+       
+       /* remove domain from "domain\username" */
+       if ((p = strrchr(domainname, '\\')) != NULL) {
+               *p = '\0';
+               domain = domainname;
+       } else {
+               domain = NULL;
+       }
+       
+       /*  generate MD based on negotiated type */
+       switch (digest->code) {
+               
+       case CHAP_MICROSOFT:
+       {
+               char *error_string = NULL;
+               u_char *nt_response = NULL;
+               u_char *lm_response = NULL;
+               int nt_response_size = 0;
+               int lm_response_size = 0;
+               MS_ChapResponse *rmd = (MS_ChapResponse *) response;
+               u_char session_key[16];
+               
+               if (response_len != MS_CHAP_RESPONSE_LEN)
+                       break;                  /* not even the right length */
+               
+               /* Determine which part of response to verify against */
+               if (rmd->UseNT[0]) {
+                       nt_response = rmd->NTResp;
+                       nt_response_size = sizeof(rmd->NTResp);
+               } else {
+#ifdef MSLANMAN
+                       lm_response = rmd->LANManResp;
+                       lm_response_size = sizeof(rmd->LANManResp);
+#else
+                       /* Should really propagate this into the error packet. */
+                       notice("Peer request for LANMAN auth not supported");
+                       return NOT_AUTHENTICATED;
+#endif /* MSLANMAN */
+               }
+               
+               /* ship off to winbind, and check */
+               
+               if (run_ntlm_auth(username, 
+                                 domain,
+                                 NULL,
+                                 NULL,
+                                 challenge,
+                                 challenge_len,
+                                 lm_response,
+                                 lm_response ? lm_response_size: 0,
+                                 nt_response,
+                                 nt_response ? nt_response_size: 0,
+                                 session_key,
+                                 &error_string) == AUTHENTICATED) {
+                       mppe_set_keys(challenge, session_key);
+                       slprintf(message, message_space, "Access granted");
+                       return AUTHENTICATED;
+                       
+               } else {
+                       if (error_string) {
+                               notice(error_string);
+                               free(error_string);
+                       }
+                       slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
+                                challenge_len, challenge);
+                       return NOT_AUTHENTICATED;
+               }
+               break;
+       }
+       
+       case CHAP_MICROSOFT_V2:
+       {
+               MS_Chap2Response *rmd = (MS_Chap2Response *) response;
+               u_char Challenge[8];
+               u_char session_key[MD4_SIGNATURE_SIZE];
+               char *error_string = NULL;
+               
+               if (response_len != MS_CHAP2_RESPONSE_LEN)
+                       break;                  /* not even the right length */
+               
+               ChallengeHash(rmd->PeerChallenge, challenge, user, Challenge);
+               
+               /* ship off to winbind, and check */
+               
+               if (run_ntlm_auth(username, 
+                                 domain, 
+                                 NULL,
+                                 NULL,
+                                 Challenge,
+                                 8,
+                                 NULL, 
+                                 0,
+                                 rmd->NTResp,
+                                 sizeof(rmd->NTResp),
+                                 
+                                 session_key,
+                                 &error_string) == AUTHENTICATED) {
+                       
+                       GenerateAuthenticatorResponse(session_key,
+                                                     rmd->NTResp, rmd->PeerChallenge,
+                                                     challenge, user,
+                                                     saresponse);
+                       mppe_set_keys2(session_key, rmd->NTResp, MS_CHAP2_AUTHENTICATOR);
+                       if (rmd->Flags[0]) {
+                               slprintf(message, message_space, "S=%s", saresponse);
+                       } else {
+                               slprintf(message, message_space, "S=%s M=%s",
+                                        saresponse, "Access granted");
+                       }
+                       return AUTHENTICATED;
+                       
+               } else {
+                       if (error_string) {
+                               notice(error_string);
+                               slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
+                                        challenge_len, challenge, error_string);
+                               free(error_string);
+                       } else {
+                               slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
+                                        challenge_len, challenge, "Access denied");
+                       }
+                       return NOT_AUTHENTICATED;
+               }
+               break;
+       }
+       
+       default:
+               error("WINBIND: Challenge type %u unsupported", digest->code);
+       }
+       return NOT_AUTHENTICATED;
+}
+
+static int 
+winbind_allowed_address(u_int32_t addr) 
+{
+       ipcp_options *wo = &ipcp_wantoptions[0];
+       if (wo->hisaddr !=0 && wo->hisaddr == addr) {
+               return 1;
+       }
+       return -1;
+}