⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x99_pwe.c

📁 free radius编程。完成AAA的实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * x99_pwe.c * $Id: x99_pwe.c,v 1.19 2002/11/04 04:02:02 fcusack Exp $ * *   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Copyright 2001,2002  Google, Inc. *//* * This file implements passcode (password) checking functions for each * supported encoding (PAP, CHAP, etc.).  The current libradius interface * is not sufficient for X9.9 use. */#ifdef FREERADIUS#define _LRAD_MD4_H#define _LRAD_SHA1_H#include "libradius.h"#include "rad_assert.h"#endif#include "x99.h"#include "x99_pwe.h"#include <openssl/des.h>#include <openssl/md4.h>#include <openssl/md5.h>#include <openssl/sha.h>#include <string.h>static const char rcsid[] = "$Id: x99_pwe.c,v 1.19 2002/11/04 04:02:02 fcusack Exp $";/* Attribute IDs for supported password encodings. */static int pwattr[8];/* Initialize the pwattr array for supported password encodings. */voidx99_pwe_init(void){    DICT_ATTR *da;    int i = 0;    /*     * Setup known password types.  These are pairs.     * NB: Increase pwattr array size when adding a type.     *     It should be sized as (number of password types * 2)     */    (void) memset(pwattr, 0, sizeof(pwattr));    /* PAP */    if ((da = dict_attrbyname("User-Password")) != NULL) {	pwattr[i++] = da->attr;	pwattr[i++] = da->attr;    }    /* CHAP */    if ((da = dict_attrbyname("CHAP-Challenge")) != NULL) {	pwattr[i++] = da->attr;	if ((da = dict_attrbyname("CHAP-Password")) != NULL)	    pwattr[i++] = da->attr;	else	    pwattr[--i] = 0;    }#if 0    /* MS-CHAP (recommended not to use) */    if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {	pwattr[i++] = da->attr;	if ((da = dict_attrbyname("MS-CHAP-Response")) != NULL)	    pwattr[i++] = da->attr;	else	    pwattr[--i] = 0;    }#endif /* 0 */    /* MS-CHAPv2 */    if ((da = dict_attrbyname("MS-CHAP-Challenge")) != NULL) {	pwattr[i++] = da->attr;	if ((da = dict_attrbyname("MS-CHAP2-Response")) != NULL)	    pwattr[i++] = da->attr;	else	    pwattr[--i] = 0;    }}/* * Test for password presence in an Access-Request packet. * Returns 0 for "no supported password present", or an non-zero * opaque value that must be used when calling x99_pw_valid. */intx99_pw_present(const REQUEST *request){    int i;    for (i = 0; i < sizeof(pwattr) && pwattr[i]; i += 2) {	if (pairfind(request->packet->vps, pwattr[i]) &&	    pairfind(request->packet->vps, pwattr[i + 1])) {	    DEBUG("rlm_x99_token: pw_present: found password attributes %d, %d",		   pwattr[i], pwattr[i + 1]);	    return i + 1; /* Can't return 0 (indicates failure) */	}    }    return 0;}/* * Test for password validity.  attr must be the return value from * x99_pw_present(). * returns 1 for match, 0 for non-match. * If vps is non-null, then on matches, it will point to vps that * should be added to an Access-Accept packet.  If access is denied, * the caller is responsible for freeing any vps returned. * (vps is used for MPPE atttributes.) */intx99_pw_valid(const REQUEST *request, x99_token_t *inst,	     int attr, const char *password, VALUE_PAIR **vps){    int match = 0;    VALUE_PAIR *chal_vp, *resp_vp;    /*     * A module that does this might want to verify the presence of these.     * This code is self contained to x99, so I know these exist.     */    chal_vp = pairfind(request->packet->vps, pwattr[attr - 1]);    resp_vp = pairfind(request->packet->vps, pwattr[attr]);    /* Prepare for failure return. */    if (vps)	*vps = NULL;    /* If modular, this would actually call the authentication function. */    switch(pwattr[attr]) {    case PW_PASSWORD:	DEBUG("rlm_x99_token: pw_valid: handling PW_PASSWORD");	match = !strcmp(password, resp_vp->strvalue);	break;    case PW_CHAP_PASSWORD:    {	/*	 * See RFC 1994.	 * A CHAP password is MD5(CHAP_ID|SECRET|CHAP_CHALLENGE).       	 * CHAP_ID is a value set by the authenticator (the NAS), and used	 * in the response calculation.  It is available as the first byte	 * of the CHAP-Password attribute.	 * SECRET is the password.	 * CHAP_CHALLENGE is the challenge given to the peer (the user).	 * The CHAP-Challenge Attribute may be missing, in which case the	 * challenge is taken to be the Request Authenticator.  We don't	 * handle this case.	 */	/*                 ID       password    chal */	unsigned char input[1 + MAX_STRING_LEN + 16];	unsigned char output[MD5_DIGEST_LENGTH];	DEBUG("rlm_x99_token: pw_valid: handling PW_CHAP_PASSWORD");	if (1 + strlen(password) + chal_vp->length > sizeof(input)) {	    DEBUG("rlm_x99_token: pw_valid: CHAP-Challenge/password too long");	    match = 0;	    break;	}	if (resp_vp->length != 17) {	    x99_log(X99_LOG_AUTH, "pw_valid: CHAP-Password wrong size");	    match = 0;	    break;	}	input[0] = *(resp_vp->strvalue);	(void) memcpy(&input[1], password, strlen(password));	(void) memcpy(&input[1+strlen(password)], chal_vp->strvalue,		      chal_vp->length);	(void) MD5(input, 1 + strlen(password) + chal_vp->length, output);	match = !memcmp(output, &(resp_vp->strvalue)[1], MD5_DIGEST_LENGTH);    } /* case PW_CHAP_PASSWORD */    break;#if 0    case PW_MS_CHAP_RESPONSE:    {	/*	 * See RFCs 2548, 2433, 3079.	 * An MS-CHAP response is (IDENT|FLAGS|LM_RESPONSE|NT_RESPONSE).	 *                 octets:   1     1       24           24	 * IDENT is not used by RADIUS (it is the PPP MS-CHAP Identifier).	 * FLAGS is 1 to indicate the NT_RESPONSE should be preferred.	 * LM_RESPONSE is the LAN Manager compatible response.	 * NT_RESPONSE is the NT compatible response.	 * Either response may be zero-filled indicating its absence.	 * Use of the LM response has been deprecated (RFC 2433, par. 6),         * so we don't handle it.	 *	 * The NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where	 * CHAL is the 8-octet challenge, and K1, K2, K3 are 7-octet pieces	 * of MD4(unicode(password)), zero-filled to 21 octets.  Sigh.	 */	unsigned char nt_keys[21]; /* sized for 3 DES keys */	unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */	unsigned char output[24];	int password_len, i;	VALUE_PAIR *vp;	DEBUG("rlm_x99_token: pw_valid: handling PW_MS_CHAP_RESPONSE");	if (chal_vp->length != 8) {	    x99_log(X99_LOG_AUTH, "pw_valid: MS-CHAP-Challenge wrong size");	    match = 0;	    break;	}	if (resp_vp->length != 50) {	    x99_log(X99_LOG_AUTH, "pw_valid: MS-CHAP-Response wrong size");	    match = 0;	    break;	}	if ((resp_vp->strvalue)[1] != 1) {	    x99_log(X99_LOG_AUTH,		    "pw_valid: MS-CHAP-Response bad flags (LM not supported)");	    match = 0;	    break;	}	/* This is probably overkill. */	if (strlen(password) > MAX_STRING_LEN) {	    x99_log(X99_LOG_AUTH, "pw_valid: MS-CHAP password too long");	    match = 0;	    break;	}	/*	 * Start by hashing the unicode password.	 * This is broken because unicode chars are machine-ordered,	 * but the spec (RFC 2433) doesn't say how to prepare	 * the password for md4 (other than by example values).	 */	password_len = strlen(password);	for (i = 0; i < password_len; ++i) {	    /* Set the high order 8 bits to 0 (little-endian) */	    input[i * 2] = *password++;	    input[i * 2 + 1] = 0;	}	(void) memset(nt_keys, 0, sizeof(nt_keys));	(void) MD4(input, 2 * password_len, nt_keys);	/* The challenge gets encrypted. */	(void) memcpy(input, chal_vp->strvalue, 8);	/* Convert the password hash to keys, and do the encryptions. */	for (i = 0; i < 3; ++i) {	    des_cblock key;	    des_key_schedule ks;	    x99_key_from_hash(&key, &nt_keys[i * 7]);	    des_set_key_unchecked(&key, ks);	    des_ecb_encrypt((des_cblock *) input,			    (des_cblock *) &output[i * 8],			    ks, DES_ENCRYPT);	}	match = !memcmp(output, resp_vp->strvalue + 26, 24);	if (!match || !vps)	    break;	/*	 * Generate the MS-CHAP-MPPE-Keys attribute if needed.  This is not	 * specified anywhere -- RFC 2548, par. 2.4.1 is the authority but	 * it has typos and omissions that make this unimplementable.  The	 * code here is based on experimental results provided by	 * Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp>.	 * We only support 128-bit keys derived from the NT hash; 40-bit	 * and 56-bit keys are derived from the LM hash, which besides	 * being deprecated, has severe security problems.	 */	/* First, set some related attributes. */	vp = pairmake("MS-MPPE-Encryption-Policy",		      x99_mppe_policy[inst->mschap_mppe_policy], T_OP_EQ);	rad_assert(vp != NULL);	pairadd(vps, vp);	vp = pairmake("MS-MPPE-Encryption-Types",		      x99_mppe_types[inst->mschap_mppe_types], T_OP_EQ);	rad_assert(vp != NULL);	pairadd(vps, vp);	if (inst->mschap_mppe_policy) {	    unsigned char mppe_keys[32];	    /*                    0x    ASCII(mppe_keys)      '\0' */	    char mppe_keys_string[2 + (2 * sizeof(mppe_keys)) + 1];	    unsigned char md5_md[MD5_DIGEST_LENGTH];	    unsigned char encode_buf[AUTH_VECTOR_LEN + MAX_STRING_LEN];	    int secretlen;	    /* Zero the LM-Key sub-field (and padding). */	    (void) memset(mppe_keys, 0, sizeof(mppe_keys));	    /* The NT-Key sub-field is MD4(MD4(unicode(password))). */	    (void) MD4(nt_keys, 16, &mppe_keys[8]);#if 0 /* encoding now handled in lib/radius.c:rad_pwencode() */	    /* Now we must encode the key as User-Password is encoded. */	    secretlen = strlen(request->secret);	    (void) memcpy(encode_buf, request->secret, secretlen);	    (void) memcpy(encode_buf + secretlen, request->packet->vector,			  AUTH_VECTOR_LEN);	    (void) MD5(encode_buf, secretlen + AUTH_VECTOR_LEN, md5_md);	    for (i = 0; i < 16; ++i)		mppe_keys[i] ^= md5_md[i];	    (void) memcpy(encode_buf + secretlen, mppe_keys, MD5_DIGEST_LENGTH);	    (void) MD5(encode_buf, secretlen + MD5_DIGEST_LENGTH, md5_md);	    for (i = 0; i < 16; ++i)		mppe_keys[i + 16] ^= md5_md[i];#endif /* 0 */	    /* Whew.  Now stringify it for pairmake(). */	    mppe_keys_string[0] = '0';	    mppe_keys_string[1] = 'x';	    for (i = 0; i < 32; ++i)		(void) sprintf(&mppe_keys_string[i*2+2], "%02X", mppe_keys[i]);	    vp = pairmake("MS-CHAP-MPPE-Keys", mppe_keys_string, T_OP_EQ);	    rad_assert(vp != NULL);	    pairadd(vps, vp);	} /* if (doing mppe) */    } /* case PW_MS_CHAP_RESPONSE */    break;#endif /* 0 (MS_CHAP) */    case PW_MS_CHAP2_RESPONSE:    {	/*	 * See RFCs 2548, 2759, 3079.	 * An MS-CHAPv2 response is	 *          (IDENT|FLAGS|PEER_CHALLENGE|RESERVED|NT_RESPONSE).	 *   octets:   1     1         16          8        24	 * IDENT is the PPP MS-CHAPv2 Identifier, used in MS-CHAP2-Success.	 * FLAGS is currently unused.	 * PEER_CHALLENGE is a random number, generated by the peer.	 * NT_RESPONSE is (DES(CHAL,K1)|DES(CHAL,K2)|DES(CHAL,K3)), where	 * K1, K2, K3 are 7-octet pieces of MD4(unicode(password)), zero-	 * filled to 21 octets (just as in MS-CHAP); and CHAL is	 * MSB8(SHA(PEER_CHALLENGE|MS_CHAP_CHALLENGE|USERNAME)).	 */	unsigned char nt_keys[21]; /* aka "password_md", sized for 3 DES keys */	unsigned char password_md_md[MD4_DIGEST_LENGTH]; /* for mutual auth */	unsigned char input[MAX_STRING_LEN * 2]; /* doubled for unicode */	unsigned char output[24];	int password_len, i;	VALUE_PAIR *vp;	DEBUG("rlm_x99_token: pw_valid: handling PW_MS_CHAP2_RESPONSE");	if (chal_vp->length != 16) {	    x99_log(X99_LOG_AUTH,"pw_valid: MS-CHAP-Challenge (v2) wrong size");	    match = 0;	    break;	}	if (resp_vp->length != 50) {	    x99_log(X99_LOG_AUTH, "pw_valid: MS-CHAP2-Response wrong size");	    match = 0;	    break;	}	/* This is probably overkill. */	if (strlen(password) > MAX_STRING_LEN) {	    x99_log(X99_LOG_AUTH, "pw_valid: MS-CHAPv2 password too long");	    match = 0;

⌨️ 快捷键说明

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