Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 03 Nov 2002 15:34:56 +0100
From:      Michael Bretterklieber <mbretter@inode.at>
To:        freebsd-net@freebsd.org, Archie Cobbs <archie@dellroad.org>
Cc:        Brendan Bank <brendan@gnarst.net>
Subject:   mpd radius - request for review
Message-ID:  <3DC53410.8000602@inode.at>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------090203030406080803080701
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

now I finished the work for radius-mpd-integration.

It would be great if my code will be reviewed and integrated into 
"official" mpd.
If there are any bugs or dirty hacks in my code, then let me know.

I tested the code successfuly against freeradius and Microsoft Radius 
(Windows 2000).
All auth-types are supported (pap, chap-md5, mschap v1 and mschap v2), 
also mppe works.

Here are the new config-params:

set radius config /etc/radius.conf
or
set radius retries 3
set radius timeout 3
set radius server localhost testing123
=> configures radius (thanks to Brendan Bank).

set bundle enable radius-auth  => enables Radius Auth
set bundle enable radius-fallback => enables fallback to mpd.secret if 
radius-auth not succeeded

set ipcp enable radius-ip => let the radius-server assign the ip for the 
user

with "show radius" all radius-related params are printed out.

After the code has being integrated into mpd I would like continue 
implementing more features:
- MPPE Types and Policy
- Let mpd use other radius-params.
- Accounting

If the code is to bad for integration into mpd, no problem, because then 
it was only a good exercise for me.

I attached the patches and also 2 new files for mpd 3.10.


bye,
-- 
------------------------------- ----------------------------------
Michael Bretterklieber - Michael.Bretterklieber@jawa.at
JAWA Management Software GmbH - http://www.jawa.at
Liebenauer Hauptstr. 200 -------------- privat ------------
A-8041 GRAZ GSM: ++43-(0)676-93 96 698
Tel: ++43-(0)316-403274-12 E-mail: mbretter@inode.at
Fax: ++43-(0)316-403274-10 http://www.inode.at/mbretter
------------------------------- ----------------------------------
"...the number of UNIX installations has grown to 10, with more
expected..." - Dennis Ritchie and Ken Thompson, June 1972

--------------090203030406080803080701
Content-Type: text/plain;
 name="mpd_radius.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="mpd_radius.diff"

Index: Makefile
===================================================================
RCS file: /cvsrep/mpd/src/Makefile,v
retrieving revision 1.4
retrieving revision 1.8
diff -r1.4 -r1.8
1c1
< # $Id: Makefile,v 1.4 2002/10/26 12:26:03 mbretter Exp $
---
> # $Id: Makefile,v 1.8 2002/11/03 14:09:20 mbretter Exp $
43a44
> 
48a50,52
> RADIUS=			yes
> LDADD+=		-lradius
> 
84c88
< 		vars.c custom.c
---
> 		vars.c custom.c radius.c
Index: bund.c
===================================================================
RCS file: /cvsrep/mpd/src/bund.c,v
retrieving revision 1.3
diff -r1.3 bund.c
129c129,131
<     { 0,	0,			NULL		},
---
>     { 0,	BUND_CONF_RADIUSAUTH,	"radius-auth"	},
> 		{ 0,	BUND_CONF_RADIUSFALLBACK,	"radius-fallback"	},
> 		{ 0,	0,			NULL		},
595,598c597,600
< 	if ((sb = gBundles[k]) != NULL) {
< 	  printf(BUND_FMT, sb->name);
< 	  BundShowLinks(sb);
< 	}
---
> 				if ((sb = gBundles[k]) != NULL) {
> 					printf(BUND_FMT, sb->name);
> 					BundShowLinks(sb);
> 				}
605,610c607,612
< 	bund = sb;
< 	if (lnk->bund != bund)
< 	  lnk = bund->links[0];
<       } else
< 	printf("Bundle \"%s\" not defined.\n", av[0]);
<       break;
---
> 				bund = sb;
> 				if (lnk->bund != bund)
> 					lnk = bund->links[0];
> 			} else
> 				printf("Bundle \"%s\" not defined.\n", av[0]);
> 		break;
714a717,719
> 	
> 	Disable(&bund->conf.options, BUND_CONF_RADIUSAUTH);
> 	Disable(&bund->conf.options, BUND_CONF_RADIUSFALLBACK);
Index: bund.h
===================================================================
RCS file: /cvsrep/mpd/src/bund.h,v
retrieving revision 1.4
diff -r1.4 bund.h
22a23
> #include "radius.h"
40a42,43
> 		BUND_CONF_RADIUSAUTH,	/* enable radius auth */
> 		BUND_CONF_RADIUSFALLBACK,	/* enable fallback to mpd.secret */
134a138,140
> 
>     /* radius */
>     struct radius radius;
Index: ccp_mppc.c
===================================================================
RCS file: /cvsrep/mpd/src/ccp_mppc.c,v
retrieving revision 1.2
retrieving revision 1.4
diff -r1.2 -r1.4
595a596,604
> 	if (bund->radius.valid == 1) {
> 		if (dir == COMP_DIR_XMIT) {
> 			memcpy(mppc->xmit_key0, bund->radius.mppe.sendkey, MPPE_KEY_LEN);
> 		} else {
> 			memcpy(mppc->recv_key0, bund->radius.mppe.recvkey, MPPE_KEY_LEN);
> 		}
> 		return;
> 	}
> 
Index: chap.c
===================================================================
RCS file: /cvsrep/mpd/src/chap.c,v
retrieving revision 1.3
retrieving revision 1.8
diff -r1.3 -r1.8
18a19
> #include "radius.h"
30,42d30
<   struct mschapvalue {
<     u_char	lmHash[24];
<     u_char	ntHash[24];
<     u_char	useNT;
<   };
< 
<   struct mschapv2value {
<     u_char	peerChal[16];
<     u_char	reserved[8];
<     u_char	ntHash[24];
<     u_char	flags;
<   };
< 
77c65
<     case AUTH_SELF_TO_PEER:	/* Just wait for peer's challenge */
---
>     case AUTH_SELF_TO_PEER:	/* Just wait for peer's  */
285a274
> 	int		radRes = RAD_NACK;
322c311
< 	if (ChapParsePkt(bp, len, peer_name, chap_value, &chap_value_size) < 0)
---
> 	if (ChapParsePkt(bp, len, peer_name, chap_value, &chap_value_size) < 0) {
323a313,314
> 	}
> 		Log(LG_AUTH, (" DEBUG CHAP_CHALLENGE: peer_name = %s", peer_name));
458a450
> 	Log(LG_AUTH, (" DEBUG CHAP_RESPONSE: peer_name = %s", peer_name));
468,474d459
< 	/* Get peer's secret key */
< 	Log(LG_AUTH, (" Peer name: \"%s\"", peer_name));
< 	if (AuthGetData(peer_name, &auth, 1, &whyFail) < 0) {
< 	  Log(LG_AUTH, (" Can't get credentials for \"%s\"", peer_name));
< 	  goto badResponse;
< 	}
< 
479,498c464,504
< 	/* Get expected hash value */
< 	if ((hash_value_size = ChapHash(chap->recv_alg, hash_value, chp.id,
< 	    peer_name, auth.password, chap->chal_data, chap->chal_len,
< 	    0)) < 0) {
< 	  Log(LG_AUTH, (" Hash failure"));
< 	  whyFail = AUTH_FAIL_INVALID_PACKET;
< 	  goto badResponse;
< 	}
< 
< 	/* Compare with peer's response */
< 	if (chap->chal_len == 0
< 	    || !ChapHashAgree(chap->recv_alg, hash_value, hash_value_size,
< 	      chap_value, chap_value_size)) {
< 	  Log(LG_AUTH, (" Invalid response"));
< 	  whyFail = AUTH_FAIL_INVALID_LOGIN;
< badResponse:
< 	  failMesg = AuthFailMsg(PROTO_CHAP, chap->recv_alg, whyFail);
< 	  ChapOutput(CHAP_FAILURE, chp.id, failMesg, strlen(failMesg));
< 	  AuthFinish(AUTH_PEER_TO_SELF, FALSE, NULL);
< 	  break;
---
> 	if (Enabled(&bund->conf.options, BUND_CONF_RADIUSAUTH)) {
> 		radRes = RadiusCHAPAuthenticate(peer_name, chap_value, chap_value_size, chap->chal_data, chap->chal_len, chp.id, chap->recv_alg);
> 		if (radRes == RAD_NACK && !Enabled(&bund->conf.options, BUND_CONF_RADIUSFALLBACK)) {
> 			whyFail = AUTH_FAIL_INVALID_LOGIN;
> 			goto badResponse;
> 		}
> 		
> 		if (radRes == RAD_ACK) RadiusSetAuth(&auth);
> 	}
> 
> 	if ((radRes == RAD_NACK && Enabled(&bund->conf.options, BUND_CONF_RADIUSFALLBACK)) ||
> 			!Enabled(&bund->conf.options, BUND_CONF_RADIUSAUTH)) {
> 
> 		/* Get peer's secret key */
> 		Log(LG_AUTH, (" Peer name: \"%s\"", peer_name));
> 		if (AuthGetData(peer_name, &auth, 1, &whyFail) < 0) {
> 			Log(LG_AUTH, (" Can't get credentials for \"%s\"", peer_name));
> 			goto badResponse;
> 		}
> 
> 		/* Get expected hash value */
> 		if ((hash_value_size = ChapHash(chap->recv_alg, hash_value, chp.id,
> 				peer_name, auth.password, chap->chal_data, chap->chal_len,
> 				0)) < 0) {
> 			Log(LG_AUTH, (" Hash failure"));
> 			whyFail = AUTH_FAIL_INVALID_PACKET;
> 			goto badResponse;
> 		}
> 
> 		/* Compare with peer's response */
> 		if (chap->chal_len == 0
> 				|| !ChapHashAgree(chap->recv_alg, hash_value, hash_value_size,
> 					chap_value, chap_value_size)) {
> 			Log(LG_AUTH, (" Invalid response"));
> 			whyFail = AUTH_FAIL_INVALID_LOGIN;
> 	badResponse:
> 			failMesg = AuthFailMsg(PROTO_CHAP, chap->recv_alg, whyFail);
> 			ChapOutput(CHAP_FAILURE, chp.id, failMesg, strlen(failMesg));
> 			AuthFinish(AUTH_PEER_TO_SELF, FALSE, NULL);
> 			break;
> 		}
513a520
> #ifdef MICROSOFT_CHAP
520,525c527,537
< 	  /* Generate MS-CHAPv2 'authenticator response' */
< 	  GenerateAuthenticatorResponse(auth.password, pv->ntHash,
< 	    pv->peerChal, chap->chal_data, peer_name, authresp);
< 	  for (i = 0; i < 20; i++)
< 	    sprintf(hex + (i * 2), "%02X", authresp[i]);
< 	  snprintf(ackMesg, sizeof(ackMesg), "S=%s", hex);
---
> 		if (radRes == RAD_ACK) {
> 			strcpy(ackMesg, bund->radius.mschapv2resp);
> 		} else {
> 			/* Generate MS-CHAPv2 'authenticator response' */
> 			GenerateAuthenticatorResponse(auth.password, pv->ntHash,
> 				pv->peerChal, chap->chal_data, peer_name, authresp);
> 			for (i = 0; i < 20; i++)
> 				sprintf(hex + (i * 2), "%02X", authresp[i]);
> 			snprintf(ackMesg, sizeof(ackMesg), "S=%s", hex);
> 		}
> #endif
526a539
> 
Index: chap.h
===================================================================
RCS file: /cvsrep/mpd/src/chap.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -r1.1.1.1 -r1.2
57a58,70
> 	struct mschapvalue {
>     u_char	lmHash[24];
>     u_char	ntHash[24];
>     u_char	useNT;
>   };
> 
>   struct mschapv2value {
>     u_char	peerChal[16];
>     u_char	reserved[8];
>     u_char	ntHash[24];
>     u_char	flags;
>   };
> 	
Index: command.c
===================================================================
RCS file: /cvsrep/mpd/src/command.c,v
retrieving revision 1.3
retrieving revision 1.5
diff -r1.3 -r1.5
17a18
> #include "radius.h"
90a92,93
> 		{ "radius",				"radius status",
> 	RadStat, AdmitBund, NULL },
116a120,121
> 		{ "radius ...",			"Set radius configuration",
> 	CMD_SUBMENU, AdmitBund, (void *) RadiusSetCmds },
Index: ipcp.c
===================================================================
RCS file: /cvsrep/mpd/src/ipcp.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -r1.2 -r1.3
68,77d67
<   /* Configuration options */
<   enum {
<     IPCP_CONF_VJCOMP,
<     IPCP_CONF_REQPRIDNS,
<     IPCP_CONF_REQSECDNS,
<     IPCP_CONF_REQPRINBNS,
<     IPCP_CONF_REQSECNBNS,
<     IPCP_CONF_PRETENDIP,
<   };
< 
142a133
> 		{ 0,	IPCP_CONF_RADIUSIP,	"radius-ip"	},
Index: ipcp.h
===================================================================
RCS file: /cvsrep/mpd/src/ipcp.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -r1.1.1.1 -r1.2
25a26,37
>  
>    /* Configuration options */
>   enum {
>     IPCP_CONF_VJCOMP,
>     IPCP_CONF_REQPRIDNS,
>     IPCP_CONF_REQSECDNS,
>     IPCP_CONF_REQPRINBNS,
>     IPCP_CONF_REQSECNBNS,
>     IPCP_CONF_PRETENDIP,
> 		IPCP_CONF_RADIUSIP,
>   };
> 
Index: log.c
===================================================================
RCS file: /cvsrep/mpd/src/log.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -r1.3 -r1.4
119a120,122
> #ifdef LG_RADIUS
>     ADD_OPT(RADIUS,	"Radius authentication events")
> #endif
Index: log.h
===================================================================
RCS file: /cvsrep/mpd/src/log.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -r1.3 -r1.4
44c44,45
<     LG_I_CONSOLE
---
>     LG_I_CONSOLE,
>     LG_I_RADIUS
69a71
>   #define LG_RADIUS		(1 << LG_I_RADIUS)
85a88
> 			        | LG_RADIUS		\
Index: mbuf.c
===================================================================
RCS file: /cvsrep/mpd/src/mbuf.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -r1.3 -r1.4
57a58
>     { MB_RADIUS,	"RADIUS" },
Index: mbuf.h
===================================================================
RCS file: /cvsrep/mpd/src/mbuf.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -r1.3 -r1.4
58a59
>     MB_RADIUS,
Index: pap.c
===================================================================
RCS file: /cvsrep/mpd/src/pap.c,v
retrieving revision 1.4
retrieving revision 1.9
diff -r1.4 -r1.9
15a16
> #include "radius.h"
159a161
> 	int		radRes = RAD_NACK;
190,194c192,199
< 	/* Get auth data for this system */
< 	Log(LG_AUTH, (" Peer name: \"%s\"", name));
< 	if (AuthGetData(name, &auth, 1, &whyFail) < 0) {
< 	  Log(LG_AUTH, (" Can't get credentials for \"%s\"", name));
< 	  goto badRequest;
---
> 	if (Enabled(&bund->conf.options, BUND_CONF_RADIUSAUTH)) {
> 		radRes = RadiusPAPAuthenticate(name, pass);
> 		if (radRes == RAD_NACK && !Enabled(&bund->conf.options, BUND_CONF_RADIUSFALLBACK)) {
> 			whyFail = AUTH_FAIL_INVALID_LOGIN;
> 			goto badRequest;
> 		}
> 		
> 		if (radRes == RAD_ACK) RadiusSetAuth(&auth);		
197,206c202,203
< 	/* Do name & password match? */
< 	if (strcmp(auth.authname, name) || strcmp(auth.password, pass)) {
< 	  Log(LG_AUTH, (" Invalid response"));
< 	  whyFail = AUTH_FAIL_INVALID_LOGIN;
< badRequest:
< 	  failMesg = AuthFailMsg(PROTO_PAP, 0, whyFail);
< 	  PapOutput(PAP_NAK, php.id, failMesg, strlen(failMesg), 1);
< 	  AuthFinish(AUTH_PEER_TO_SELF, FALSE, NULL);
< 	  break;
< 	}
---
> 	if ((radRes == RAD_NACK && Enabled(&bund->conf.options, BUND_CONF_RADIUSFALLBACK)) ||
> 			!Enabled(&bund->conf.options, BUND_CONF_RADIUSAUTH)) {
207a205,223
> 		/* Get auth data for this system */
> 		Log(LG_AUTH, (" Peer name: \"%s\"", name));
> 		if (AuthGetData(name, &auth, 1, &whyFail) < 0) {
> 			Log(LG_AUTH, (" Can't get credentials for \"%s\"", name));
> 			goto badRequest;
> 		}
> 
> 		/* Do name & password match? */
> 		if (strcmp(auth.authname, name) || strcmp(auth.password, pass)) {
> 			Log(LG_AUTH, (" Invalid response"));
> 			whyFail = AUTH_FAIL_INVALID_LOGIN;
> 	badRequest:
> 			failMesg = AuthFailMsg(PROTO_PAP, 0, whyFail);
> 			PapOutput(PAP_NAK, php.id, failMesg, strlen(failMesg), 1);
> 			AuthFinish(AUTH_PEER_TO_SELF, FALSE, NULL);
> 			break;
> 		}
> 
> 	}

--------------090203030406080803080701
Content-Type: text/plain;
 name="radius.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="radius.c"

/*
 * radius.c
 *
 * Written by Michael Bretterklieber <mbretter@jawa.at>
 * Written by Brendan Bank <brendan@gnarst.net>
 * Copyright (c) Brendan Bank 2002
 */

#include "radius.h"
#include "pptp.h"
#include "chap.h"
#include <radlib.h>
#include <radlib_vs.h>
#include <md5.h>

/* Global variables */

	static int RadiusSetCommand(int ac, char *av[], void *arg);
	static int RadiusAddServer (void);
	static void RadiusInit(void);
	static void RadiusMPPEExtractKey(const void *mangled, size_t mlen, u_char *buf, size_t *len);
	static const char * RadiusMPPEPolicyname(int policy);
	static const char * RadiusMPPETypesname(int types);

/* Set menu options */

  enum {
    SET_SERVER,
    SET_TIMEOUT,
    SET_RETRIES,
		SET_CONFIG
  };

/*
 * GLOBAL VARIABLES
 */
 
  const struct cmdtab RadiusSetCmds[] =
	{
		{ "server <name> <secret> [auth port] [acct port]",
		"Set radius server parameters" ,
			RadiusSetCommand, NULL, (void *) SET_SERVER },
		{ "timeout <seconds>",               	"Set timeout in seconds",
			RadiusSetCommand, NULL, (void *) SET_TIMEOUT },
		{ "retries <# retries>",              	"set number of retries",
			RadiusSetCommand, NULL, (void *) SET_RETRIES },
		{ "config <path to radius.conf>",				"set path to config file for libradius",
			RadiusSetCommand, NULL, (void *) SET_CONFIG },
		{ NULL },
  };

/* Set menu options */
static int
RadiusSetCommand(int ac, char *av[], void *arg)
{
	static char function[] = "RadiusSetCommand";
	RadConf const conf = &bund->radius.conf;
	RadServe_Conf server;
	RadServe_Conf t_server;
	int val, count;

	/* Log(LG_RADIUS, ("[%s] %s: started",	lnk->name, function)); */

	if (ac == 0)
	    return(-1);

  	switch ((int) arg) {

			case SET_SERVER:
				if (ac > 4 || ac < 2) {
					return(-1);
				}

				count = 0;
				for ( t_server = conf->server ; t_server ;
					t_server = t_server->next) {
					count++;
				}
				if (count > RADIUS_MAX_SERVERS) {
					Log(LG_RADIUS, ("[%s] %s: cannot configure more than %d servers",
						lnk->name, function, RADIUS_MAX_SERVERS));
					return (-1);
				}

				server = Malloc(MB_RADIUS, sizeof(*server));
				server->auth_port = 1645;
				server->acct_port = 1646;
				server->next = NULL;

				if (strlen(av[0]) > 255) {
					Log(LG_ERR, ("Hostname too long!. > 255 char."));
					return(-1);
				}
				if (strlen(av[1]) > 127) {
					Log(LG_ERR, ("Shared Secret too long! > 127 char."));
					return(-1);
				}

				if (ac > 2 && atoi(av[2]) < 65535 && atoi(av[2]) > 1) {
					server->auth_port = atoi (av[2]);

				} else if ( ac > 2 ) {
					Log(LG_ERR, ("Auth Port number too high > 65535"));
					return(-1);
				}

				if (ac > 3 && atoi(av[3]) < 65535 && atoi(av[3]) > 1) {
					server->acct_port = atoi (av[3]);
				} else if ( ac > 3 ) {
					Log(LG_ERR, ("Acct Port number too high > 65535"));
					return(-1);
				}

				server->hostname = Malloc(MB_RADIUS, strlen(av[0]) + 1);
				server->sharedsecret = Malloc(MB_RADIUS, strlen(av[1]) + 1);

				sprintf(server->hostname, "%s" , av[0]);
				sprintf(server->sharedsecret, "%s" , av[1]);

				if (conf->server != NULL)
					server->next = conf->server;

				conf->server = server;

				break;

			case SET_TIMEOUT:
				val = atoi(*av);
					if (val <= 0)
						Log(LG_ERR, ("Timeout must be positive."));
					else
						conf->radius_timeout = val;
				break;

			case SET_RETRIES:
				val = atoi(*av);
				if (val <= 0)
					Log(LG_ERR, ("Retries must be positive."));
				else
				conf->radius_retries = val;
				break;

			case SET_CONFIG:
				if (strlen(av[0]) > PATH_MAX)
					Log(LG_ERR, (" PATH_MAX exceeded for config file."));
				else
					strcpy(conf->file, av[0]);
				break;

			default:
				assert(0);
		}

		return 0;
}

void RadiusInit(void) {
	struct radius *rad = &bund->radius;

	if (rad->radh != NULL) rad_close(rad->radh);
	memset(rad, 0, sizeof(struct radius) - sizeof(struct radiusconf));
}

extern int
RadiusAuthenticate(const char *name, const char *password, int passlen,
        const char *challenge, int challenge_size, u_char chapid, int auth_type)
{
	static char function[] = "RadiusAuthenticate";
	struct radius *rad = &bund->radius;
	char     host[MAXHOSTNAMELEN];
	struct in_addr          peer_ip;
	char	*peeripname;
	int res;
	struct chap_response chapres;
	struct mschap_response mschapres;
	struct mschapv2_response mschap2res;
	struct mschapv2value *mschapv2;
	struct mschapvalue *mschapv;

	RadiusInit();

	if (gethostname(host, sizeof (host)) == -1) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: gethostname() failed", lnk->name, function));
		return (RAD_NACK);
	}

	if (name == NULL || password == NULL) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: name or password NULL", lnk->name, function));
		return (RAD_NACK);
	}

	rad->radh = rad_open();
	if (rad->radh == NULL) {
		Log(LG_RADIUS, ("[%s] RADIUS: rad_open failed", lnk->name));
		return (RAD_NACK);
	}

	if (strlen(bund->radius.conf.file)) {
		Log(LG_RADIUS, ("[%s] RADIUS: using %s", lnk->name, bund->radius.conf.file));
		if (rad_config(rad->radh, bund->radius.conf.file) != 0) {
			Log(LG_RADIUS, ("[%s] RADIUS: rad_config: %s", lnk->name, rad_strerror(rad->radh)));
			rad_close(rad->radh);
			return (RAD_NACK);
		}
	}

	if (RadiusAddServer() == RAD_NACK) {
		rad_close(rad->radh);
		return (RAD_NACK);
	}

	if (rad_create_request(rad->radh, RAD_ACCESS_REQUEST) == -1) {
		Log(LG_RADIUS, ("[%s] RADIUS: rad_create_request: %s", lnk->name, rad_strerror(rad->radh)));
		return (RAD_NACK);
	}

	if (rad_put_string(rad->radh, RAD_USER_NAME, name) == -1) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(username) failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
		rad_close(rad->radh);
		return (RAD_NACK);
	}

	switch (auth_type) {

		case CHAP_ALG_MSOFT:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) peer name: %s", lnk->name, function, name));
 			if (passlen != 49) {
    		Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv1) unrecognised key length %d/%d", lnk->name, function, passlen, 49));
        rad_close(rad->radh);
        return RAD_NACK;
      }

			if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE, challenge, challenge_size) == -1)	{
				Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s", lnk->name,
					function, rad_strerror(rad->radh)));
				rad_close(rad->radh);
				return (RAD_NACK);
			}

			mschapv = (struct mschapvalue *)password;
			mschapres.ident = chapid;
      mschapres.flags = 0x01;
      memcpy(mschapres.lm_response, mschapv->lmHash, 24);
      memcpy(mschapres.nt_response, mschapv->ntHash, 24);

			if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_RESPONSE, &mschapres, sizeof mschapres) == -1)	{
				Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_RESPONSE) failed %s", lnk->name,
					function, rad_strerror(rad->radh)));
				rad_close(rad->radh);
				return (RAD_NACK);
			}
			break;

		case CHAP_ALG_MSOFTv2:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) peer name: %s", lnk->name, function, name));
			if (passlen != sizeof(*mschapv2)) {
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MSOFTv2) unrecognised key length %d/%d", lnk->name, function, passlen, sizeof(*mschapv2)));
        rad_close(rad->radh);
        return RAD_NACK;
      }

			if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP_CHALLENGE, challenge, challenge_size) == -1)	{
				Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP_CHALLENGE) failed %s", lnk->name,
					function, rad_strerror(rad->radh)));
				rad_close(rad->radh);
				return (RAD_NACK);
			}

			mschapv2 = (struct mschapv2value *)password;
			mschap2res.ident = chapid;
      mschap2res.flags = mschapv2->flags;
      memcpy(mschap2res.response, mschapv2->ntHash, sizeof mschap2res.response);
      memset(mschap2res.reserved, '\0', sizeof mschap2res.reserved);
      memcpy(mschap2res.pchallenge, mschapv2->peerChal, sizeof mschap2res.pchallenge);

			if (rad_put_vendor_attr(rad->radh, RAD_VENDOR_MICROSOFT, RAD_MICROSOFT_MS_CHAP2_RESPONSE, &mschap2res, sizeof mschap2res) == -1)	{
				Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_vendor_attr(RAD_MICROSOFT_MS_CHAP2_RESPONSE) failed %s", lnk->name,
					function, rad_strerror(rad->radh)));
				rad_close(rad->radh);
				return (RAD_NACK);
			}
      break;

		case CHAP_ALG_MD5:

			/* Radius wants the CHAP Ident in the first byte of the CHAP-Password */
			chapres.ident = chapid;
			memcpy(chapres.response, password, passlen);
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_CHAP (MD5) peer name: %s", lnk->name, function, name));
			if (rad_put_attr(rad->radh, RAD_CHAP_PASSWORD, &chapres, passlen + 1) == -1 ||
				rad_put_attr(rad->radh, RAD_CHAP_CHALLENGE, challenge, challenge_size) == -1) {
				Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s", lnk->name,
					function, rad_strerror(rad->radh)));
				rad_close(rad->radh);
				return (RAD_NACK);
			}
			break;

		case RADIUS_PAP:
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS_PAP DEBUG: peer name: %s",	lnk->name, function, name));
				if (rad_put_string(rad->radh, RAD_USER_PASSWORD, password) == -1) {
					Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(password) failed %s", lnk->name,
						function, rad_strerror(rad->radh)));
					rad_close(rad->radh);
					return (RAD_NACK);
				}
			break;

		default:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RADIUS auth type unkown", lnk->name, function));
			rad_close(rad->radh);
			return (RAD_NACK);
			break;
	}

	if (rad_put_string(rad->radh, RAD_NAS_IDENTIFIER, host) == -1)	{
		Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(host) failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
		rad_close(rad->radh);
		return (RAD_NACK);
	}
	if (rad_put_int(rad->radh, RAD_SERVICE_TYPE, RAD_FRAMED) == -1) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_SERVICE_TYPE) failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
		rad_close(rad->radh);
		return (RAD_NACK);
	}
	if (rad_put_int(rad->radh, RAD_FRAMED_PROTOCOL, RAD_PPP) == -1) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_FRAMED_PROTOCOL) failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
		rad_close(rad->radh);
		return (RAD_NACK);
	}

	peer_ip = PptpGetPeerIp();
	peeripname = inet_ntoa(peer_ip);

	if (peeripname != NULL) {
		if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, inet_ntoa(peer_ip)) == -1) {
			Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_int(RAD_SERVICE_TYPE) failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
			rad_close(rad->radh);
			return (RAD_NACK);
		}
	}

	switch (rad_send_request(rad->radh)) {

		case RAD_ACCESS_ACCEPT:
			rad->valid = 1;
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCESS_ACCEPT for user %s", lnk->name, function, name));
			break;

		case RAD_ACCESS_REJECT:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_ACCESS_REJECT for user %s", lnk->name, function, name));
			rad_close(rad->radh);
			return(RAD_NACK);
			break;

		case -1:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_send_request failed %s", lnk->name,
			function, rad_strerror(rad->radh)));
			return(RAD_NACK);
			break;
		default:
			Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_send_request: unexpected "
			"return value %s", lnk->name, function, rad_strerror(rad->radh)));
			rad_close(rad->radh);
			return(RAD_NACK);
		}

		// Remember authname
		strncpy(rad->authname, name, AUTH_MAX_AUTHNAME);
		res = RadiusGetParams();
		if (res == RAD_NACK) rad->valid = 0;
		rad_close(rad->radh);
		return(res);
}

int
RadiusPAPAuthenticate(const char *name, const char *password) {

	return (RadiusAuthenticate(name, password, 0, NULL, NULL, 0, RADIUS_PAP));
}

int
RadiusCHAPAuthenticate(const char *name, const char *password, int passlen,
        const char *challenge, int challenge_size, u_char chapid, int chap_type) {

	return (RadiusAuthenticate(name, password, passlen, challenge, challenge_size, chapid, chap_type));
}


int
RadiusGetParams() {
	char	function[] = "RadiusGetParams";
	struct radius *rad = &bund->radius;
	int res;
	size_t len;
  const void *data;
	u_int32_t vendor;

	while ((res = rad_get_attr(rad->radh, &data, &len)) > 0) {

		switch (res) {

      case RAD_FRAMED_IP_ADDRESS:
        rad->ip = rad_cvt_addr(data);
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_IP_ADDRESS: %s ",
					lnk->name, function, inet_ntoa(rad->ip)));
        break;

			case RAD_FRAMED_IP_NETMASK:
        rad->mask = rad_cvt_addr(data);
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_IP_NETMASK: %s ",
					lnk->name, function, inet_ntoa(rad->mask)));
        break;

			case RAD_SESSION_TIMEOUT:
        rad->sessiontime = rad_cvt_int(data);
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_SESSION_TIMEOUT: %lu ",
					lnk->name, function, rad->sessiontime));
        break;

			case RAD_FRAMED_MTU:
        rad->mtu = rad_cvt_int(data);
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_MTU: %lu ",
					lnk->name, function, rad->mtu));
        break;

			case RAD_FRAMED_COMPRESSION:
				rad->vj = rad_cvt_int(data) == 1 ? 1 : 0;
				Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_FRAMED_COMPRESSION: %d ",
					lnk->name, function, rad->vj));
				break;

			case RAD_VENDOR_SPECIFIC:
        if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) {
					Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_get_vendor_attr failed: %s ",
						lnk->name, function, rad_strerror(rad->radh)));
          return RAD_NACK;
        }

				switch (vendor) {

					case RAD_VENDOR_MICROSOFT:
						switch (res) {

              case RAD_MICROSOFT_MS_CHAP_ERROR:
								return RAD_NACK;
                break;

              /* this was taken from userland ppp */
							case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
                free(rad->mschapv2resp);
                if (len == 0)
                  rad->mschapv2resp = NULL;
                else {
                  if (len < 3 || ((const char *)data)[1] != '=') {
                    /*
                     * Only point at the String field if we don't think the
                     * peer has misformatted the response.
                     */
                    ((const char *)data)++;
                    len--;
                  } else
										Log(LG_RADIUS, ("[%s] RADIUS: %s: Warning: The MS-CHAP2-Success attribute is mis-formatted. Compensating",
											lnk->name, function));
                  if ((rad->mschapv2resp = rad_cvt_string((const char *)data, len)) == NULL) {
										Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_cvt_string failed: %s",
											lnk->name, function, rad_strerror(rad->radh)));
										return RAD_NACK;
                  }
									Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_CHAP2_SUCCESS: %s",
											lnk->name, function, rad->mschapv2resp));
                }
                break;

							case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
								Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_RECV_KEY",
									lnk->name, function));
								RadiusMPPEExtractKey(data, len, rad->mppe.recvkey, &rad->mppe.recvkeylen);
                break;

							case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
								Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_SEND_KEY",
									lnk->name, function));
								RadiusMPPEExtractKey(data, len, rad->mppe.sendkey, &rad->mppe.sendkeylen);
                break;

							case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
								rad->mppe.policy = rad_cvt_int(data);
								Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY: %d (%s)",
									lnk->name, function, rad->mppe.policy, RadiusMPPEPolicyname(rad->mppe.policy)));
                break;

              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
                rad->mppe.types = rad_cvt_int(data);
								Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES: %d (%s)",
									lnk->name, function, rad->mppe.types, RadiusMPPETypesname(rad->mppe.types)));
                break;

              default:
								Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MICROSOFT vendor specific attribute: %d ",
									lnk->name, function, res));
                break;
            }
				}
				break;

			default:
				Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping attribute: %d ", lnk->name, function, res));
				break;
		}
	}

	return RAD_ACK;
}

int
RadiusAddServer (void) {
	RadConf       const c = &bund->radius.conf;
	RadServe_Conf s;
	char	function[] = "RadiusAddServer";
	int i;
	struct radius *rad = &bund->radius;

	if (c->server == NULL)
		return (RAD_ACK);

	s = c->server;
	i = 1;
	while (s) {

		Log(LG_RADIUS, ("[%s] RADIUS: %s Adding %s", lnk->name, function, s->hostname));
		if (rad_add_server (rad->radh, s->hostname,
				s->auth_port,
				s->sharedsecret,
				c->radius_timeout,
				c->radius_retries) == -1) {
			Log(LG_RADIUS, ("[%s] RADIUS: %s error: %s", lnk->name, function, rad_strerror(rad->radh)));
			return (RAD_NACK);
		}

		s = s->next;
	}

	return (RAD_ACK);
}

void
RadiusSetAuth(AuthData auth) {
	char	function[] = "RadiusSetAuth";
	strncpy(auth->authname, bund->radius.authname, AUTH_MAX_AUTHNAME);

	if (Enabled(&bund->ipcp.conf.options, IPCP_CONF_RADIUSIP)) {

		Log(LG_RADIUS, ("[%s] RADIUS: %s: Trying to use IP-address from radius-server",
			lnk->name, function));

		if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.255") == 0) {
			/* the peer can choose an address */
			Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that the peer can choose an address",
				lnk->name, function));
			auth->range.ipaddr.s_addr = 0;
			auth->range.width = 0;
			auth->range_valid = 1;

		} else if (strcmp(inet_ntoa(bund->radius.ip), "255.255.255.254") == 0) {

			/* we should choose the ip */
			Log(LG_RADIUS, ("[%s] RADIUS: %s: server says that we should choose an address",
				lnk->name, function));
			auth->range_valid = 0;

		} else {

			/* or use IP from Radius-server */
			Log(LG_RADIUS, ("[%s] RADIUS: %s: using this IP: %s",
				lnk->name, function, inet_ntoa(bund->radius.ip)));
			memcpy(&auth->range.ipaddr, &bund->radius.ip, sizeof(struct in_addr));
			auth->range_valid = 1;
			auth->range.width = 32;
		}
	}
}

int
RadStat(int ac, char *av[], void *arg) {
	RadConf       const conf = &bund->radius.conf;
	RadServe_Conf server;
	int i;

	printf("\tTimeout     : %d\n", conf->radius_timeout);
	printf("\tRetries     : %d\n", conf->radius_retries);
	printf("\tConfig-file : %s\n", conf->file);
	if (conf->server != NULL) {

		server = conf->server;
		i = 1;

		while (server) {
			printf("\t---------------  Radius Server %d ---------------\n", i);
			printf("\thostname   : %s\n", server->hostname);
			printf("\tsecret     : *********\n");
			printf("\tauth port  : %d\n", server->auth_port);
			printf("\tacct port  : %d\n", server->acct_port);
			i++;
			server = server->next;
		}

	}

	printf("\t---------------  Radius Data ---------------\n");
	printf("\tAuthname        : %s\n", bund->radius.authname);
	printf("\tIP              : %s\n", inet_ntoa(bund->radius.ip));
	printf("\tMASK            : %s\n", inet_ntoa(bund->radius.mask));
	printf("\tMTU             : %lu\n", bund->radius.mtu);
	printf("\tSessiontimeout  : %lu\n", bund->radius.sessiontime);
	printf("\tVJ              : %d\n", bund->radius.vj);
	printf("\tMPPE Types      : %s\n", RadiusMPPETypesname(bund->radius.mppe.types));
	printf("\tMPPE Policy     : %s\n", RadiusMPPEPolicyname(bund->radius.mppe.policy));

	return (0);
}

/* This algorithm was been taken from userland-ppp */
/* For exact description see RFC2548 */
static void
RadiusMPPEExtractKey(const void *mangled, size_t mlen, u_char *buf, size_t *len)
{
	char	function[] = "RadiusExtractMPPEKey";
  char R[AUTH_LEN];		/* variable names as per rfc2548 */
  const char *S;
  u_char b[16];
  const u_char *A, *C;
  MD5_CTX Context;
  int Slen, i, Clen, Ppos;
  u_char *P;

  if (mlen % 16 != SALT_LEN) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot interpret mangled data of length %ld",
						lnk->name, function, (u_long)mlen));
    buf = NULL;
    *len = 0;
    return;
  }

	/* We need the RADIUS Request-Authenticator */
  if (rad_request_authenticator(bund->radius.radh, R, sizeof R) != AUTH_LEN) {
		Log(LG_RADIUS, ("[%s] RADIUS: %s: Cannot obtain the RADIUS request authenticator",
			lnk->name, function));
    buf = NULL;
    *len = 0;
    return;
  }

  A = (const u_char *)mangled;			/* Salt comes first */
  C = (const u_char *)mangled + SALT_LEN;	/* Then the ciphertext */
  Clen = mlen - SALT_LEN;
  S = rad_server_secret(bund->radius.radh);		/* We need the RADIUS secret */
  Slen = strlen(S);
  P = alloca(Clen);				/* We derive our plaintext */

  MD5Init(&Context);
  MD5Update(&Context, S, Slen);
  MD5Update(&Context, R, AUTH_LEN);
  MD5Update(&Context, A, SALT_LEN);
  MD5Final(b, &Context);
  Ppos = 0;

  while (Clen) {
    Clen -= 16;

    for (i = 0; i < 16; i++)
      P[Ppos++] = C[i] ^ b[i];

    if (Clen) {
      MD5Init(&Context);
      MD5Update(&Context, S, Slen);
      MD5Update(&Context, C, 16);
      MD5Final(b, &Context);
    }

    C += 16;
  }

  /*
   * The resulting plain text consists of a one-byte length, the text and
   * maybe some padding.
   */
  *len = *P;
  if (*len > mlen - 1) {
		Log(LG_RADIUS, ("[%s] RADIUS %s: Mangled data seems to be garbage %d %d",
			lnk->name, function, *len, mlen-1));
    buf = NULL;
    *len = 0;
    return;
  }

	if (*len > MPPE_KEY_LEN) {
		Log(LG_RADIUS, ("[%s] RADIUS %s: Key to long (%d) for me max. %d",
			lnk->name, function, *len, MPPE_KEY_LEN));
    buf = NULL;
    *len = 0;
		return;
	}

  memcpy(buf, P + 1, *len);
}

static const char *
RadiusMPPEPolicyname(int policy) {
  switch(policy) {
		case MPPE_POLICY_ALLOWED:
			return "Allowed";
		case MPPE_POLICY_REQUIRED:
			return "Required";
		default:
			return "Unknown Policy";
  }

}

static const char *
RadiusMPPETypesname(int types) {
	static char res[30];

	if (types == 0) {
		sprintf(res, "no encryption required");
		return res;
	}

	if (types & MPPE_TYPE_40BIT) sprintf (res, "40 ");
	if (types & MPPE_TYPE_56BIT) sprintf (&res[strlen(res)], "56 ");
	if (types & MPPE_TYPE_128BIT) sprintf (&res[strlen(res)], "128 ");

	if (strlen(res) == 0) {
		sprintf (res, "unknown types");
	} else {
		sprintf (&res[strlen(res)], "bit");
	}

	return res;

}
--------------090203030406080803080701
Content-Type: text/plain;
 name="radius.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="radius.h"


/*
 * radius.h
 *
 * Written by Brendan Bank <brendan@gnarst.net>
 * Copyright (c) Brendan Bank 2002
 */

#include "ppp.h"
#include "auth.h"
#include "ccp_mppc.h"
#include <radlib.h>

#ifndef _RADIUS_H_
#define _RADIUS_H_


#define RADIUS_CHAP 1
#define RADIUS_PAP  2
#define RADIUS_MAX_SERVERS  10

#define RAD_NACK 0
#define RAD_ACK	1

/* for mppe-keys */
#define AUTH_LEN 16
#define	SALT_LEN	2

#define	MPPE_POLICY_ALLOWED	1
#define	MPPE_POLICY_REQUIRED	2

#define	MPPE_TYPE_0BIT		0	/* No encryption required */
#define	MPPE_TYPE_40BIT		2
#define	MPPE_TYPE_128BIT	4
#define	MPPE_TYPE_56BIT		8

/*
 * FUNCTIONS
 */

	extern int RadiusAuthenticate(const char *name, const char *password, int passlen,
		const char *challenge, int challenge_size, u_char chapid, int auth_type);
	extern int RadiusPAPAuthenticate(const char *name, const char *password);
	extern int RadiusCHAPAuthenticate(const char *name, const char *password, int passlen,
		const char *challenge, int challenge_size, u_char chapid, int chap_type);
	extern int RadiusGetParams(void);
	extern void RadiusSetAuth(AuthData auth);
	extern const struct cmdtab      RadiusSetCmds[];
	extern int     RadStat(int ac, char *av[], void *arg);

  struct radiusserver_conf {
    char	*hostname;
    char	*sharedsecret;
    int		auth_port;
    int		acct_port;
		struct	radiusserver_conf *next;
  };

  typedef struct radiusserver_conf *RadServe_Conf;

  /* Configuration for a radius server */

  struct radiusconf {
		int radius_timeout;
		int radius_retries;
		char	file[PATH_MAX];
		struct radiusserver_conf *server;
  };

  typedef struct radiusconf *RadConf;
	
	struct radius {
		struct rad_handle *radh;		/* RadLib Handle */
		short valid;								/* Auth was successful */
		char	authname[AUTH_MAX_AUTHNAME];
		unsigned vj : 1;              /* FRAMED Compression */
		struct in_addr ip;            /* FRAMED IP */
		struct in_addr mask;          /* FRAMED Netmask */
		unsigned long mtu;            /* FRAMED MTU */
		unsigned long sessiontime;    /* Session-Timeout */
    char *filterid;               /* FRAMED Filter Id */
		char *mschapv2resp;						/* Response String for MSCHAPv2 */
		struct {
			int policy;			/* MPPE_POLICY_* */
			int types;			/* MPPE_TYPE_*BIT bitmask */
			u_char recvkey[MPPE_KEY_LEN];
			size_t recvkeylen;
			u_char sendkey[MPPE_KEY_LEN];
			size_t sendkeylen;
		} mppe;
		struct radiusconf conf;
	};

	struct chap_response {
  	u_char ident;
  	u_char response[CHAP_MAX_VAL];
	};

	struct mschap_response {
  	u_char ident;
  	u_char flags;
  	u_char lm_response[24];
  	u_char nt_response[24];
	};

	struct mschapv2_response {
		u_char ident;
		u_char flags;
		u_char pchallenge[16];
		u_char reserved[8];
		u_char response[24];
	};


#endif

--------------090203030406080803080701--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3DC53410.8000602>