chap_ms.c

来自「自己精简过的PPPD代码。在嵌入中应用可以更好的发挥。比原先的小了很多」· C语言 代码 · 共 941 行 · 第 1/2 页

C
941
字号
/* * chap_ms.c - Microsoft MS-CHAP compatible implementation. * * Copyright (c) 1995 Eric Rosenquist.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The name(s) of the authors of this software must not be used to *    endorse or promote products derived from this software without *    prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *//* * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 * *   Implemented LANManager type password response to MS-CHAP challenges. *   Now pppd provides both NT style and LANMan style blocks, and the *   prefered is set by option "ms-lanman". Default is to use NT. *   The hash text (StdText) was taken from Win95 RASAPI32.DLL. * *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 *//* * Modifications by Frank Cusack, frank@google.com, March 2002. * *   Implemented MS-CHAPv2 functionality, heavily based on sample *   implementation in RFC 2759.  Implemented MPPE functionality, *   heavily based on sample implementation in RFC 3079. * * Copyright (c) 2002 Google, Inc.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in *    the documentation and/or other materials provided with the *    distribution. * * 3. The name(s) of the authors of this software must not be used to *    endorse or promote products derived from this software without *    prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */#define RCSID	"$Id: chap_ms.c,v 1.36 2006/05/21 11:56:40 paulus Exp $"#ifdef CHAPMS#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <sys/types.h>#include <sys/time.h>#include <unistd.h>#include "pppd.h"#include "chap-new.h"#include "chap_ms.h"#include "md4.h"#include "sha1.h"#include "pppcrypt.h"#include "magic.h"static const char rcsid[] = RCSID;static void	ascii2unicode __P((char[], int, u_char[]));static void	NTPasswordHash __P((u_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((u_char *, u_char[16], char *, char *, int,				u_char[24]));static void	GenerateAuthenticatorResponsePlain			__P((char*, int, u_char[24], u_char[16], u_char *,			     char *, u_char[41]));#ifdef MSLANMANstatic void	ChapMS_LANMan __P((u_char *, char *, int, u_char *));#endif#ifdef MPPEstatic void	Set_Start_Key __P((u_char *, char *, int));static void	SetMasterKeys __P((char *, int, u_char[24], int));#endif#ifdef MSLANMANbool	ms_lanman = 0;    	/* Use LanMan password instead of NT */			  	/* Has meaning only with MS-CHAP challenges */#endif#ifdef MPPEu_char mppe_send_key[MPPE_MAX_KEY_LEN];u_char mppe_recv_key[MPPE_MAX_KEY_LEN];int mppe_keys_set = 0;		/* Have the MPPE keys been set? */#ifdef DEBUGMPPEKEY/* For MPPE debug *//* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */static char *mschap_challenge = NULL;/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */static char *mschap2_peer_challenge = NULL;#endif#include "fsm.h"		/* Need to poke MPPE options */#include "ccp.h"#include <net/ppp-comp.h>#endif/* * Command-line options. */static option_t chapms_option_list[] = {#ifdef MSLANMAN	{ "ms-lanman", o_bool, &ms_lanman,	  "Use LanMan passwd when using MS-CHAP", 1 },#endif#ifdef DEBUGMPPEKEY	{ "mschap-challenge", o_string, &mschap_challenge,	  "specify CHAP challenge" },	{ "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,	  "specify CHAP peer challenge" },#endif	{ NULL }};/* * chapms_generate_challenge - generate a challenge for MS-CHAP. * For MS-CHAP the challenge length is fixed at 8 bytes. * The length goes in challenge[0] and the actual challenge starts * at challenge[1]. */static voidchapms_generate_challenge(unsigned char *challenge){	*challenge++ = 8;#ifdef DEBUGMPPEKEY	if (mschap_challenge && strlen(mschap_challenge) == 8)		memcpy(challenge, mschap_challenge, 8);	else#endif		random_bytes(challenge, 8);}static voidchapms2_generate_challenge(unsigned char *challenge){	*challenge++ = 16;#ifdef DEBUGMPPEKEY	if (mschap_challenge && strlen(mschap_challenge) == 16)		memcpy(challenge, mschap_challenge, 16);	else#endif		random_bytes(challenge, 16);}static intchapms_verify_response(int id, char *name,		       unsigned char *secret, int secret_len,		       unsigned char *challenge, unsigned char *response,		       char *message, int message_space){	unsigned char md[MS_CHAP_RESPONSE_LEN];	int diff;	int challenge_len, response_len;	challenge_len = *challenge++;	/* skip length, is 8 */	response_len = *response++;	if (response_len != MS_CHAP_RESPONSE_LEN)		goto bad;#ifndef MSLANMAN	if (!response[MS_CHAP_USENT]) {		/* Should really propagate this into the error packet. */		notice("Peer request for LANMAN auth not supported");		goto bad;	}#endif	/* Generate the expected response. */	ChapMS(challenge, (char *)secret, secret_len, md);#ifdef MSLANMAN	/* Determine which part of response to verify against */	if (!response[MS_CHAP_USENT])		diff = memcmp(&response[MS_CHAP_LANMANRESP],			      &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);	else#endif		diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],			      MS_CHAP_NTRESP_LEN);	if (diff == 0) {		slprintf(message, message_space, "Access granted");		return 1;	} bad:	/* See comments below for MS-CHAP V2 */	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",		 challenge_len, challenge);	return 0;}static intchapms2_verify_response(int id, char *name,			unsigned char *secret, int secret_len,			unsigned char *challenge, unsigned char *response,			char *message, int message_space){	unsigned char md[MS_CHAP2_RESPONSE_LEN];	char saresponse[MS_AUTH_RESPONSE_LENGTH+1];	int challenge_len, response_len;	challenge_len = *challenge++;	/* skip length, is 16 */	response_len = *response++;	if (response_len != MS_CHAP2_RESPONSE_LEN)		goto bad;	/* not even the right length */	/* Generate the expected response and our mutual auth. */	ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name,		(char *)secret, secret_len, md,		(unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);	/* compare MDs and send the appropriate status */	/*	 * Per RFC 2759, success message must be formatted as	 *     "S=<auth_string> M=<message>"	 * where	 *     <auth_string> is the Authenticator Response (mutual auth)	 *     <message> is a text message	 *	 * However, some versions of Windows (win98 tested) do not know	 * about the M=<message> part (required per RFC 2759) and flag	 * it as an error (reported incorrectly as an encryption error	 * to the user).  Since the RFC requires it, and it can be	 * useful information, we supply it if the peer is a conforming	 * system.  Luckily (?), win98 sets the Flags field to 0x04	 * (contrary to RFC requirements) so we can use that to	 * distinguish between conforming and non-conforming systems.	 *	 * Special thanks to Alex Swiridov <say@real.kharkov.ua> for	 * help debugging this.	 */	if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],		   MS_CHAP2_NTRESP_LEN) == 0) {		if (response[MS_CHAP2_FLAGS])			slprintf(message, message_space, "S=%s", saresponse);		else			slprintf(message, message_space, "S=%s M=%s",				 saresponse, "Access granted");		return 1;	} bad:	/*	 * Failure message must be formatted as	 *     "E=e R=r C=c V=v M=m"	 * where	 *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)	 *     r = retry (we use 1, ok to retry)	 *     c = challenge to use for next response, we reuse previous	 *     v = Change Password version supported, we use 0	 *     m = text message	 *	 * The M=m part is only for MS-CHAPv2.  Neither win2k nor	 * win98 (others untested) display the message to the user anyway.	 * They also both ignore the E=e code.	 *	 * Note that it's safe to reuse the same challenge as we don't	 * actually accept another response based on the error message	 * (and no clients try to resend a response anyway).	 *	 * Basically, this whole bit is useless code, even the small	 * implementation here is only because of overspecification.	 */	slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",		 challenge_len, challenge, "Access denied");	return 0;}static voidchapms_make_response(unsigned char *response, int id, char *our_name,		     unsigned char *challenge, char *secret, int secret_len,		     unsigned char *private){	challenge++;	/* skip length, should be 8 */	*response++ = MS_CHAP_RESPONSE_LEN;	ChapMS(challenge, secret, secret_len, response);}static voidchapms2_make_response(unsigned char *response, int id, char *our_name,		      unsigned char *challenge, char *secret, int secret_len,		      unsigned char *private){	challenge++;	/* skip length, should be 16 */	*response++ = MS_CHAP2_RESPONSE_LEN;	ChapMS2(challenge,#ifdef DEBUGMPPEKEY		mschap2_peer_challenge,#else		NULL,#endif		our_name, secret, secret_len, response, private,		MS_CHAP2_AUTHENTICATEE);}static intchapms2_check_success(unsigned char *msg, int len, unsigned char *private){	if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||	    strncmp((char *)msg, "S=", 2) != 0) {		/* Packet does not start with "S=" */		error("MS-CHAPv2 Success packet is badly formed.");		return 0;	}	msg += 2;	len -= 2;	if (len < MS_AUTH_RESPONSE_LENGTH	    || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) {		/* Authenticator Response did not match expected. */		error("MS-CHAPv2 mutual authentication failed.");		return 0;	}	/* Authenticator Response matches. */	msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */	len -= MS_AUTH_RESPONSE_LENGTH;	if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {		msg += 3; /* Eat the delimiter */	} else if (len) {		/* Packet has extra text which does not begin " M=" */		error("MS-CHAPv2 Success packet is badly formed.");		return 0;	}	return 1;}static voidchapms_handle_failure(unsigned char *inp, int len){	int err;	char *p, *msg;	/* We want a null-terminated string for strxxx(). */	msg = malloc(len + 1);	if (!msg) {		notice("Out of memory in chapms_handle_failure");		return;	}	BCOPY(inp, msg, len);	msg[len] = 0;	p = msg;	/*	 * Deal with MS-CHAP formatted failure messages; just print the	 * M=<message> part (if any).  For MS-CHAP we're not really supposed	 * to use M=<message>, but it shouldn't hurt.  See	 * chapms[2]_verify_response.	 */	if (!strncmp(p, "E=", 2))		err = strtol(p+2, NULL, 10); /* Remember the error code. */	else		goto print_msg; /* Message is badly formatted. */	if (len && ((p = strstr(p, " M=")) != NULL)) {		/* M=<message> field found. */		p += 3;	} else {		/* No M=<message>; use the error code. */		switch (err) {		case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:			p = "E=646 Restricted logon hours";			break;		case MS_CHAP_ERROR_ACCT_DISABLED:			p = "E=647 Account disabled";			break;		case MS_CHAP_ERROR_PASSWD_EXPIRED:			p = "E=648 Password expired";			break;		case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:			p = "E=649 No dialin permission";			break;		case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:			p = "E=691 Authentication failure";			break;		case MS_CHAP_ERROR_CHANGING_PASSWORD:			/* Should never see this, we don't support Change Password. */			p = "E=709 Error changing password";			break;		default:			free(msg);			error("Unknown MS-CHAP authentication failure: %.*v",			      len, inp);			return;		}	}print_msg:	if (p != NULL)		error("MS-CHAP authentication failed: %v", p);	free(msg);}static voidChallengeResponse(u_char *challenge,		  u_char PasswordHash[MD4_SIGNATURE_SIZE],		  u_char response[24]){    u_char    ZPasswordHash[21];    BZERO(ZPasswordHash, sizeof(ZPasswordHash));    BCOPY(PasswordHash, ZPasswordHash, MD4_SIGNATURE_SIZE);#if 0    dbglog("ChallengeResponse - ZPasswordHash %.*B",	   sizeof(ZPasswordHash), ZPasswordHash);#endif    (void) DesSetkey(ZPasswordHash + 0);    DesEncrypt(challenge, response + 0);    (void) DesSetkey(ZPasswordHash + 7);    DesEncrypt(challenge, response + 8);    (void) DesSetkey(ZPasswordHash + 14);    DesEncrypt(challenge, response + 16);#if 0    dbglog("ChallengeResponse - response %.24B", response);#endif}voidChallengeHash(u_char PeerChallenge[16], u_char *rchallenge,	      char *username, u_char Challenge[8])    

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?