From af32d6370eba9545f813546a7902575d834a0f85 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 4 Nov 2004 12:00:07 +0000 Subject: [PATCH] Add winbind plugin from Andrew Bartlet. Changes to chap_ms.[ch] needed by winbind. --- pppd/chap_ms.c | 97 +++-- pppd/chap_ms.h | 11 +- pppd/plugins/Makefile.linux | 2 +- pppd/plugins/winbind.c | 685 ++++++++++++++++++++++++++++++++++++ 4 files changed, 756 insertions(+), 39 deletions(-) create mode 100644 pppd/plugins/winbind.c diff --git a/pppd/chap_ms.c b/pppd/chap_ms.c index 16fb3a8..1c4356c 100644 --- a/pppd/chap_ms.c +++ b/pppd/chap_ms.c @@ -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 @@ -97,16 +97,15 @@ 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 } diff --git a/pppd/chap_ms.h b/pppd/chap_ms.h index 4e2ac11..73b41de 100644 --- a/pppd/chap_ms.h +++ b/pppd/chap_ms.h @@ -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__ diff --git a/pppd/plugins/Makefile.linux b/pppd/plugins/Makefile.linux index 80b0ae0..10bc4f0 100644 --- a/pppd/plugins/Makefile.linux +++ b/pppd/plugins/Makefile.linux @@ -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 index 0000000..1abe437 --- /dev/null +++ b/pppd/plugins/winbind.c @@ -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 +* +* 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 +* Copyright (C) 1996, Lars Fenneberg +* Copyright (C) 1997, Miguel A.L. Paraz +* +* Uses radiusclient library, which is: +* Copyright (C) 1995,1996,1997,1998 Lars Fenneberg +* Copyright (C) 2002 Roaring Penguin Software Inc. +* +* MPPE support is by Ralf Hofmann, , with +* modification from Frank Cusack, . +* +* Updated on 2003-12-12 to support updated PPP plugin API from latest CVS +* Copyright (C) 2003, Sean E. Millichamp +* +* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- 2.39.2