*
* radius.c
*
-* RADIUS plugin for pppd. Performs PAP and CHAP authentication using
-* RADIUS.
+* RADIUS plugin for pppd. Performs PAP, CHAP and MS-CHAP authentication
+* using RADIUS.
*
* Copyright (C) 2002 Roaring Penguin Software Inc.
*
*
***********************************************************************/
static char const RCSID[] =
-"$Id: radius.c,v 1.3 2002/03/01 14:39:18 dfs Exp $";
+"$Id: radius.c,v 1.5 2002/03/04 14:59:51 dfs Exp $";
#include "pppd.h"
#include "chap.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
#include "radiusclient.h"
#include "fsm.h"
#include "ipcp.h"
* %RETURNS:
* CHAP_SUCCESS if we can authenticate, CHAP_FAILURE if we cannot.
* %DESCRIPTION:
-* Performs CHAP authentication using RADIUS
+* Performs CHAP and MS-CHAP authentication using RADIUS
***********************************************************************/
static int
radius_chap_auth(char *user,
UINT4 av_type;
static char radius_msg[BUF_LEN];
int result;
- u_char cpassword[MD5_SIGNATURE_SIZE+1];
+ u_char cpassword[MAX_RESPONSE_LENGTH + 1];
radius_msg[0] = 0;
if (radius_init(radius_msg) < 0) {
return CHAP_FAILURE;
}
- /* we handle md5 digest at the moment */
- if (cstate->chal_type != CHAP_DIGEST_MD5) {
- error("RADIUS: Challenge type not MD5");
+ /* return error for types we can't handle */
+ if ((cstate->chal_type != CHAP_DIGEST_MD5)
+#ifdef CHAPMS
+ && (cstate->chal_type != CHAP_MICROSOFT)
+#endif
+ ) {
+ error("RADIUS: Challenge type %u unsupported", cstate->chal_type);
return CHAP_FAILURE;
}
rc_avpair_add (&send, PW_USER_NAME, rstate.user , 0, VENDOR_NONE);
/*
- * add the CHAP-Password and CHAP-Challenge fields
+ * add the challenge and response fields
*/
+ switch (cstate->chal_type) {
+ case CHAP_DIGEST_MD5:
+ /* CHAP-Challenge and CHAP-Password */
+ cpassword[0] = cstate->chal_id;
+ memcpy(&cpassword[1], remmd, MD5_SIGNATURE_SIZE);
+
+ rc_avpair_add(&send, PW_CHAP_CHALLENGE,
+ cstate->challenge, cstate->chal_len, VENDOR_NONE);
+ rc_avpair_add(&send, PW_CHAP_PASSWORD,
+ cpassword, MD5_SIGNATURE_SIZE + 1, VENDOR_NONE);
+ break;
+
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ {
+ /* MS-CHAP-Challenge and MS-CHAP-Response */
+ MS_ChapResponse *rmd = remmd;
+ u_char *p = cpassword;
+
+ *p++ = cstate->chal_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,
+ cstate->challenge, cstate->chal_len, VENDOR_MICROSOFT);
+ rc_avpair_add(&send, PW_MS_CHAP_RESPONSE,
+ cpassword, MS_CHAP_RESPONSE_LEN + 1, VENDOR_MICROSOFT);
+ break;
+ }
+#endif
- cpassword[0] = cstate->chal_id;
-
- memcpy(&cpassword[1], remmd, MD5_SIGNATURE_SIZE);
-
- rc_avpair_add(&send, PW_CHAP_PASSWORD, cpassword, MD5_SIGNATURE_SIZE + 1, VENDOR_NONE);
-
- rc_avpair_add(&send, PW_CHAP_CHALLENGE, cstate->challenge, cstate->chal_len, VENDOR_NONE);
+ }
/*
* make authentication with RADIUS server
*/
while (vp) {
- switch (vp->attribute) {
- case PW_SERVICE_TYPE:
- /* check for service type */
- /* if not FRAMED then exit */
- if (vp->lvalue != PW_FRAMED) {
- slprintf(msg, BUF_LEN, "RADIUS: wrong service type %ld for %s",
- vp->lvalue, rstate.user);
- return -1;
- }
- break;
- case PW_FRAMED_PROTOCOL:
- /* check for framed protocol type */
- /* if not PPP then also exit */
- if (vp->lvalue != PW_PPP) {
- slprintf(msg, BUF_LEN, "RADIUS: wrong framed protocol %ld for %s",
- vp->lvalue, rstate.user);
- return -1;
- }
- break;
-
- case PW_FRAMED_IP_ADDRESS:
- /* seting up remote IP addresses */
- remote = vp->lvalue;
- if (remote == 0xffffffff) {
- /* 0xffffffff means user should be allowed to select one */
- rstate.any_ip_addr_ok = 1;
- } else if (remote != 0xfffffffe) {
- /* 0xfffffffe means NAS should select an ip address */
- remote = htonl(vp->lvalue);
- if (bad_ip_adrs (remote)) {
- slprintf(msg, BUF_LEN, "RADIUS: bad remote IP address %I for %s",
- remote, rstate.user);
+ if (vp->vendorcode == VENDOR_NONE) {
+ switch (vp->attribute) {
+ case PW_SERVICE_TYPE:
+ /* check for service type */
+ /* if not FRAMED then exit */
+ if (vp->lvalue != PW_FRAMED) {
+ slprintf(msg, BUF_LEN, "RADIUS: wrong service type %ld for %s",
+ vp->lvalue, rstate.user);
return -1;
}
- rstate.choose_ip = 1;
- rstate.ip_addr = remote;
- }
+ break;
+ case PW_FRAMED_PROTOCOL:
+ /* check for framed protocol type */
+ /* if not PPP then also exit */
+ if (vp->lvalue != PW_PPP) {
+ slprintf(msg, BUF_LEN, "RADIUS: wrong framed protocol %ld for %s",
+ vp->lvalue, rstate.user);
+ return -1;
+ }
+ break;
+
+ case PW_FRAMED_IP_ADDRESS:
+ /* seting up remote IP addresses */
+ remote = vp->lvalue;
+ if (remote == 0xffffffff) {
+ /* 0xffffffff means user should be allowed to select one */
+ rstate.any_ip_addr_ok = 1;
+ } else if (remote != 0xfffffffe) {
+ /* 0xfffffffe means NAS should select an ip address */
+ remote = htonl(vp->lvalue);
+ if (bad_ip_adrs (remote)) {
+ slprintf(msg, BUF_LEN, "RADIUS: bad remote IP address %I for %s",
+ remote, rstate.user);
+ return -1;
+ }
+ rstate.choose_ip = 1;
+ rstate.ip_addr = remote;
+ }
break;
+ }
}
vp = vp->next;
}
{
return rstate.user;
}
-