📄 radius.c
字号:
/************************************************************************* radius.c** RADIUS plugin for pppd. Performs PAP, CHAP, MS-CHAP, MS-CHAPv2* authentication using RADIUS.** 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>.** This plugin may be distributed according to the terms of the GNU* General Public License, version 2 or (at your option) any later version.************************************************************************/static char const RCSID[] ="$Id: radius.c,v 1.28 2004/11/14 10:27:57 paulus Exp $";#include "pppd.h"#include "chap-new.h"#ifdef CHAPMS#include "chap_ms.h"#ifdef MPPE#include "md5.h"#endif#endif#include "radiusclient.h"#include "fsm.h"#include "ipcp.h"#include <syslog.h>#include <sys/types.h>#include <sys/time.h>#include <string.h>#include <netinet/in.h>#include <stdlib.h>#define BUF_LEN 1024#define MD5_HASH_SIZE 16static char *config_file = NULL;static int add_avp(char **);static struct avpopt { char *vpstr; struct avpopt *next;} *avpopt = NULL;static bool portnummap = 0;static option_t Options[] = { { "radius-config-file", o_string, &config_file }, { "avpair", o_special, add_avp }, { "map-to-ttyname", o_bool, &portnummap, "Set Radius NAS-Port attribute value via libradiusclient library", OPT_PRIO | 1 }, { "map-to-ifname", o_bool, &portnummap, "Set Radius NAS-Port attribute to number as in interface name (Default)", OPT_PRIOSUB | 0 }, { NULL }};static int radius_secret_check(void);static int radius_pap_auth(char *user, char *passwd, char **msgp, struct wordlist **paddrs, struct wordlist **popts);static int radius_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 void radius_ip_up(void *opaque, int arg);static void radius_ip_down(void *opaque, int arg);static void make_username_realm(char *user);static int radius_setparams(VALUE_PAIR *vp, char *msg, REQUEST_INFO *req_info, struct chap_digest_type *digest, unsigned char *challenge, char *message, int message_space);static void radius_choose_ip(u_int32_t *addrp);static int radius_init(char *msg);static int get_client_port(char *ifname);static int radius_allowed_address(u_int32_t addr);static void radius_acct_interim(void *);#ifdef MPPEstatic int radius_setmppekeys(VALUE_PAIR *vp, REQUEST_INFO *req_info, unsigned char *);static int radius_setmppekeys2(VALUE_PAIR *vp, REQUEST_INFO *req_info);#endif#ifndef MAXSESSIONID#define MAXSESSIONID 32#endif#ifndef MAXCLASSLEN#define MAXCLASSLEN 500#endifstruct radius_state { int accounting_started; int initialized; int client_port; int choose_ip; int any_ip_addr_ok; int done_chap_once; u_int32_t ip_addr; char user[MAXNAMELEN]; char config_file[MAXPATHLEN]; char session_id[MAXSESSIONID + 1]; time_t start_time; int acct_interim_interval; SERVER *authserver; /* Authentication server to use */ SERVER *acctserver; /* Accounting server to use */ int class_len; char class[MAXCLASSLEN]; VALUE_PAIR *avp; /* Additional (user supplied) vp's to send to server */};void (*radius_attributes_hook)(VALUE_PAIR *) = NULL;/* The pre_auth_hook MAY set authserver and acctserver if it wants. In that case, they override the values in the radiusclient.conf file */void (*radius_pre_auth_hook)(char const *user, SERVER **authserver, SERVER **acctserver) = NULL;static struct radius_state rstate;char pppd_version[] = VERSION;/*********************************************************************** %FUNCTION: plugin_init* %ARGUMENTS:* None* %RETURNS:* Nothing* %DESCRIPTION:* Initializes RADIUS plugin.***********************************************************************/voidplugin_init(void){ pap_check_hook = radius_secret_check; pap_auth_hook = radius_pap_auth; chap_check_hook = radius_secret_check; chap_verify_hook = radius_chap_verify; ip_choose_hook = radius_choose_ip; allowed_address_hook = radius_allowed_address; add_notifier(&ip_up_notifier, radius_ip_up, NULL); add_notifier(&ip_down_notifier, radius_ip_down, NULL); memset(&rstate, 0, sizeof(rstate)); strlcpy(rstate.config_file, "/etc/radiusclient/radiusclient.conf", sizeof(rstate.config_file)); add_options(Options); info("RADIUS plugin initialized.");}/*********************************************************************** %FUNCTION: add_avp* %ARGUMENTS:* argv -- the <attribute=value> pair to add* %RETURNS:* 1* %DESCRIPTION:* Adds an av pair to be passed on to the RADIUS server on each request.***********************************************************************/static intadd_avp(char **argv){ struct avpopt *p = malloc(sizeof(struct avpopt)); /* Append to a list of vp's for later parsing */ p->vpstr = strdup(*argv); p->next = avpopt; avpopt = p; return 1;}/*********************************************************************** %FUNCTION: radius_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 intradius_secret_check(void){ return 1;}/*********************************************************************** %FUNCTION: radius_choose_ip* %ARGUMENTS:* addrp -- where to store the IP address* %RETURNS:* Nothing* %DESCRIPTION:* If RADIUS server has specified an IP address, it is stored in *addrp.***********************************************************************/static voidradius_choose_ip(u_int32_t *addrp){ if (rstate.choose_ip) { *addrp = rstate.ip_addr; }}/*********************************************************************** %FUNCTION: radius_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 RADIUS***********************************************************************/static intradius_pap_auth(char *user, char *passwd, char **msgp, struct wordlist **paddrs, struct wordlist **popts){ VALUE_PAIR *send, *received; UINT4 av_type; int result; static char radius_msg[BUF_LEN]; radius_msg[0] = 0; *msgp = radius_msg; if (radius_init(radius_msg) < 0) { return 0; } /* Put user with potentially realm added in rstate.user */ make_username_realm(user); if (radius_pre_auth_hook) { radius_pre_auth_hook(rstate.user, &rstate.authserver, &rstate.acctserver); } send = NULL; received = NULL; /* Hack... the "port" is the ppp interface number. Should really be the tty */ rstate.client_port = get_client_port(portnummap ? devnam : ifname); av_type = PW_FRAMED; rc_avpair_add(&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE); av_type = PW_PPP; rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE); rc_avpair_add(&send, PW_USER_NAME, rstate.user , 0, VENDOR_NONE); rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0, VENDOR_NONE); if (*remote_number) { rc_avpair_add(&send, PW_CALLING_STATION_ID, remote_number, 0, VENDOR_NONE); } else if (ipparam) rc_avpair_add(&send, PW_CALLING_STATION_ID, ipparam, 0, VENDOR_NONE); /* Add user specified vp's */ if (rstate.avp) rc_avpair_insert(&send, NULL, rc_avpair_copy(rstate.avp)); if (rstate.authserver) { result = rc_auth_using_server(rstate.authserver, rstate.client_port, send, &received, radius_msg, NULL); } else { result = rc_auth(rstate.client_port, send, &received, radius_msg, NULL); } if (result == OK_RC) { if (radius_setparams(received, radius_msg, NULL, NULL, NULL, NULL, 0) < 0) { result = ERROR_RC; } } /* free value pairs */ rc_avpair_free(received); rc_avpair_free(send); return (result == OK_RC) ? 1 : 0;}/*********************************************************************** %FUNCTION: radius_chap_verify* %ARGUMENTS:* user -- name of the peer* ourname -- name for this machine* id -- the ID byte in the challenge* digest -- points to the structure representing the digest type* challenge -- the challenge string we sent (length in first byte)* response -- the response (hash) the peer sent back (length in 1st byte)* message -- space for a message to be returned to the peer* message_space -- number of bytes available at *message.* %RETURNS:* 1 if the response is good, 0 if it is bad* %DESCRIPTION:* Performs CHAP, MS-CHAP and MS-CHAPv2 authentication using RADIUS.***********************************************************************/static intradius_chap_verify(char *user, char *ourname, int id, struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space){ VALUE_PAIR *send, *received; UINT4 av_type; static char radius_msg[BUF_LEN]; int result; int challenge_len, response_len; u_char cpassword[MAX_RESPONSE_LEN + 1];#ifdef MPPE /* Need the RADIUS secret and Request Authenticator to decode MPPE */ REQUEST_INFO request_info, *req_info = &request_info;#else REQUEST_INFO *req_info = NULL;#endif challenge_len = *challenge++; response_len = *response++; radius_msg[0] = 0; if (radius_init(radius_msg) < 0) { error("%s", radius_msg); return 0; } /* return error for types we can't handle */ if ((digest->code != CHAP_MD5)#ifdef CHAPMS && (digest->code != CHAP_MICROSOFT) && (digest->code != CHAP_MICROSOFT_V2)#endif ) { error("RADIUS: Challenge type %u unsupported", digest->code); return 0; } /* Put user with potentially realm added in rstate.user */ if (!rstate.done_chap_once) { make_username_realm(user); rstate.client_port = get_client_port (portnummap ? devnam : ifname); if (radius_pre_auth_hook) { radius_pre_auth_hook(rstate.user, &rstate.authserver, &rstate.acctserver); } } send = received = NULL; av_type = PW_FRAMED; rc_avpair_add (&send, PW_SERVICE_TYPE, &av_type, 0, VENDOR_NONE); av_type = PW_PPP; rc_avpair_add (&send, PW_FRAMED_PROTOCOL, &av_type, 0, VENDOR_NONE); rc_avpair_add (&send, PW_USER_NAME, rstate.user , 0, VENDOR_NONE); /* * add the challenge and response fields */ switch (digest->code) { case CHAP_MD5: /* CHAP-Challenge and CHAP-Password */ if (response_len != MD5_HASH_SIZE) return 0; cpassword[0] = id; memcpy(&cpassword[1], response, MD5_HASH_SIZE); rc_avpair_add(&send, PW_CHAP_CHALLENGE, challenge, challenge_len, VENDOR_NONE); rc_avpair_add(&send, PW_CHAP_PASSWORD, cpassword, MD5_HASH_SIZE + 1, VENDOR_NONE); break;#ifdef CHAPMS case CHAP_MICROSOFT: { /* MS-CHAP-Challenge and MS-CHAP-Response */ MS_ChapResponse *rmd = (MS_ChapResponse *) response; u_char *p = cpassword; if (response_len != MS_CHAP_RESPONSE_LEN) return 0; *p++ = id; /* The idiots use a different field order in RADIUS than PPP */ memcpy(p, rmd->UseNT, sizeof(rmd->UseNT)); p += sizeof(rmd->UseNT); memcpy(p, rmd->LANManResp, sizeof(rmd->LANManResp)); p += sizeof(rmd->LANManResp); memcpy(p, rmd->NTResp, sizeof(rmd->NTResp)); rc_avpair_add(&send, PW_MS_CHAP_CHALLENGE, challenge, challenge_len, VENDOR_MICROSOFT); rc_avpair_add(&send, PW_MS_CHAP_RESPONSE, cpassword, MS_CHAP_RESPONSE_LEN + 1, VENDOR_MICROSOFT); break; } case CHAP_MICROSOFT_V2: { /* MS-CHAP-Challenge and MS-CHAP2-Response */ MS_Chap2Response *rmd = (MS_Chap2Response *) response;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -