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 + -
显示快捷键?