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>