From f0cdd9c021c8363d4dd01289993300ab9de404d3 Mon Sep 17 00:00:00 2001 From: Brian Somers Date: Sat, 6 Feb 1999 02:54:47 +0000 Subject: [PATCH] Decouple pap & chap output routines from the corresponding input routines and take advantage of the new init/continue interface in libradius. This allows a timely response on other links in an MP setup while RADIUS requests are in progress as well as the ability to handle other data from the peer in parallel. It should also make the future addition of PAM support trivial. While I'm in there, validate pap & chap header IDs if ``idcheck'' is enabled (the default) for other FSM packet types. NOTE: This involved integrating the generation of chap challenges and the validation of chap responses (and commenting what's going on in those routines). I currently have no way of testing ppps ability to respond to M$Chap CHALLENGEs correctly, so if someone could do the honours, it'd be much appreciated (it *looks* ok!). Sponsored by: Internet Business Solutions Ltd., Switzerland --- usr.sbin/ppp/auth.c | 69 ++++-- usr.sbin/ppp/auth.h | 27 ++- usr.sbin/ppp/bundle.c | 17 +- usr.sbin/ppp/ccp.c | 3 +- usr.sbin/ppp/chap.c | 490 +++++++++++++++++++++----------------- usr.sbin/ppp/chap.h | 10 +- usr.sbin/ppp/datalink.c | 49 ++-- usr.sbin/ppp/datalink.h | 4 +- usr.sbin/ppp/descriptor.h | 3 +- usr.sbin/ppp/hdlc.c | 6 +- usr.sbin/ppp/ipcp.c | 5 +- usr.sbin/ppp/link.c | 3 +- usr.sbin/ppp/main.c | 4 +- usr.sbin/ppp/mbuf.c | 9 +- usr.sbin/ppp/pap.c | 214 ++++++++++------- usr.sbin/ppp/pap.h | 7 +- usr.sbin/ppp/radius.c | 357 ++++++++++++++++++--------- usr.sbin/ppp/radius.h | 16 +- usr.sbin/ppp/vjcomp.c | 3 +- 19 files changed, 789 insertions(+), 507 deletions(-) diff --git a/usr.sbin/ppp/auth.c b/usr.sbin/ppp/auth.c index ceeb8137367f..ea1a07db6b4b 100644 --- a/usr.sbin/ppp/auth.c +++ b/usr.sbin/ppp/auth.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: auth.c,v 1.36 1999/02/01 13:42:24 brian Exp $ + * $Id: auth.c,v 1.37 1999/02/02 09:35:17 brian Exp $ * * TODO: * o Implement check against with registered IP addresses. @@ -208,11 +208,6 @@ auth_Validate(struct bundle *bundle, const char *name, char *vector[5]; char buff[LINE_LEN]; -#ifndef NORADIUS - if (*bundle->radius.cfg.file) - return radius_Authenticate(&bundle->radius, bundle, name, key, NULL); -#endif - fp = OpenSecret(SECRETFILE); if (fp != NULL) { while (fgets(buff, sizeof buff, fp)) { @@ -278,8 +273,9 @@ AuthTimeout(void *vauthp) timer_Stop(&authp->authtimer); if (--authp->retry > 0) { + authp->id++; + (*authp->fn.req)(authp); timer_Start(&authp->authtimer); - (*authp->ChallengeFunc)(authp, ++authp->id, authp->physical); } else { log_Printf(LogPHASE, "Auth: No response from server\n"); datalink_AuthNotOk(authp->physical->dl); @@ -287,26 +283,28 @@ AuthTimeout(void *vauthp) } void -auth_Init(struct authinfo *authinfo) +auth_Init(struct authinfo *authp, struct physical *p, auth_func req, + auth_func success, auth_func failure) { - memset(authinfo, '\0', sizeof(struct authinfo)); - authinfo->cfg.fsmretry = DEF_FSMRETRY; + memset(authp, '\0', sizeof(struct authinfo)); + authp->cfg.fsmretry = DEF_FSMRETRY; + authp->fn.req = req; + authp->fn.success = success; + authp->fn.failure = failure; + authp->physical = p; } void -auth_StartChallenge(struct authinfo *authp, struct physical *physical, - void (*chal)(struct authinfo *, int, struct physical *)) +auth_StartReq(struct authinfo *authp) { - authp->ChallengeFunc = chal; - authp->physical = physical; timer_Stop(&authp->authtimer); authp->authtimer.func = AuthTimeout; authp->authtimer.name = "auth"; authp->authtimer.load = authp->cfg.fsmretry * SECTICKS; - authp->authtimer.arg = (void *) authp; + authp->authtimer.arg = (void *)authp; authp->retry = 3; authp->id = 1; - (*authp->ChallengeFunc)(authp, authp->id, physical); + (*authp->fn.req)(authp); timer_Start(&authp->authtimer); } @@ -314,5 +312,42 @@ void auth_StopTimer(struct authinfo *authp) { timer_Stop(&authp->authtimer); - authp->physical = NULL; +} + +struct mbuf * +auth_ReadHeader(struct authinfo *authp, struct mbuf *bp) +{ + int len; + + len = mbuf_Length(bp); + if (len >= sizeof authp->in.hdr) { + bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr); + if (len >= ntohs(authp->in.hdr.length)) + return bp; + } + + mbuf_Free(bp); + return NULL; +} + +struct mbuf * +auth_ReadName(struct authinfo *authp, struct mbuf *bp, int len) +{ + if (len > sizeof authp->in.name - 1) + log_Printf(LogERROR, "auth_ReadName: Name too long (%d) !\n", len); + else { + int mlen = mbuf_Length(bp); + + if (len > mlen) + log_Printf(LogERROR, "auth_ReadName: Short packet !\n"); + else { + bp = mbuf_Read(bp, (u_char *)authp->in.name, len); + authp->in.name[len] = '\0'; + return bp; + } + } + + *authp->in.name = '\0'; + mbuf_Free(bp); + return NULL; } diff --git a/usr.sbin/ppp/auth.h b/usr.sbin/ppp/auth.h index cf4bb3e009df..db17ff05c438 100644 --- a/usr.sbin/ppp/auth.h +++ b/usr.sbin/ppp/auth.h @@ -15,16 +15,26 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: auth.h,v 1.13 1999/02/01 13:42:24 brian Exp $ + * $Id: auth.h,v 1.14 1999/02/02 09:35:17 brian Exp $ * * TODO: */ struct physical; struct bundle; +struct authinfo; +typedef void (*auth_func)(struct authinfo *); struct authinfo { - void (*ChallengeFunc)(struct authinfo *, int, struct physical *); + struct { + auth_func req; + auth_func success; + auth_func failure; + } fn; + struct { + struct fsmheader hdr; + char name[AUTHLEN]; + } in; struct pppTimer authtimer; int retry; int id; @@ -34,16 +44,19 @@ struct authinfo { } cfg; }; -extern const char *Auth2Nam(u_short); +#define auth_Failure(a) (*a->fn.failure)(a); +#define auth_Success(a) (*a->fn.success)(a); -extern void auth_Init(struct authinfo *); +extern const char *Auth2Nam(u_short); +extern void auth_Init(struct authinfo *, struct physical *, + auth_func, auth_func, auth_func); extern void auth_StopTimer(struct authinfo *); -extern void auth_StartChallenge(struct authinfo *, struct physical *, - void (*)(struct authinfo *, int, - struct physical *)); +extern void auth_StartReq(struct authinfo *); extern int auth_Validate(struct bundle *, const char *, const char *, struct physical *); extern char *auth_GetSecret(struct bundle *, const char *, int, struct physical *); extern int auth_SetPhoneList(const char *, char *, int); extern int auth_Select(struct bundle *, const char *); +extern struct mbuf *auth_ReadHeader(struct authinfo *, struct mbuf *); +extern struct mbuf *auth_ReadName(struct authinfo *, struct mbuf *, int); diff --git a/usr.sbin/ppp/bundle.c b/usr.sbin/ppp/bundle.c index 681cafdecce0..56973fdae84b 100644 --- a/usr.sbin/ppp/bundle.c +++ b/usr.sbin/ppp/bundle.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bundle.c,v 1.43 1999/01/06 00:08:03 brian Exp $ + * $Id: bundle.c,v 1.44 1999/01/28 01:56:30 brian Exp $ */ #include @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -558,6 +557,10 @@ bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) } } +#ifndef NORADIUS + result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); +#endif + /* Which links need a select() ? */ for (dl = bundle->links; dl; dl = dl->next) result += descriptor_UpdateSet(&dl->desc, r, w, e, n); @@ -582,6 +585,11 @@ bundle_IsSet(struct descriptor *d, const fd_set *fdset) if (descriptor_IsSet(&dl->desc, fdset)) return 1; +#ifndef NORADIUS + if (descriptor_IsSet(&bundle->radius.desc, fdset)) + return 1; +#endif + if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) return 1; @@ -601,6 +609,11 @@ bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, if (descriptor_IsSet(&dl->desc, fdset)) descriptor_Read(&dl->desc, bundle, fdset); +#ifndef NORADIUS + if (descriptor_IsSet(&bundle->radius.desc, fdset)) + descriptor_Read(&bundle->radius.desc, bundle, fdset); +#endif + if (FD_ISSET(bundle->dev.fd, fdset)) { struct tun_data tun; int n, pri; diff --git a/usr.sbin/ppp/ccp.c b/usr.sbin/ppp/ccp.c index 4e15b1d93cb6..eabcf7639b7e 100644 --- a/usr.sbin/ppp/ccp.c +++ b/usr.sbin/ppp/ccp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ccp.c,v 1.40 1998/08/26 18:07:56 brian Exp $ + * $Id: ccp.c,v 1.41 1999/01/28 01:56:30 brian Exp $ * * TODO: * o Support other compression protocols @@ -30,7 +30,6 @@ #include #include -#include #include #include "defs.h" diff --git a/usr.sbin/ppp/chap.c b/usr.sbin/ppp/chap.c index a53915567894..895b34ecca52 100644 --- a/usr.sbin/ppp/chap.c +++ b/usr.sbin/ppp/chap.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.c,v 1.38 1999/01/28 01:56:31 brian Exp $ + * $Id: chap.c,v 1.39 1999/01/29 22:46:31 brian Exp $ * * TODO: */ @@ -29,10 +29,10 @@ #ifdef HAVE_DES #include +#include #endif #include #include -#include #include #include "mbuf.h" @@ -71,10 +71,11 @@ static const char *chapcodes[] = { "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE" }; +#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1) static void ChapOutput(struct physical *physical, u_int code, u_int id, - const u_char * ptr, int count, const char *text) + const u_char *ptr, int count, const char *text) { int plen; struct fsmheader lh; @@ -96,258 +97,311 @@ ChapOutput(struct physical *physical, u_int code, u_int id, hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp); } -void -chap_SendChallenge(struct authinfo *auth, int chapid, struct physical *physical) +static char * +chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, int MSChap) { - struct chap *chap = auth2chap(auth); + char *result, *digest; + size_t nlen, klen; + + nlen = strlen(name); + klen = strlen(key); + +#ifdef HAVE_DES + if (MSChap) { + char expkey[AUTHLEN << 2]; + MD4_CTX MD4context; + int f; + + if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL) + return result; + + digest = result; /* this is the response */ + *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ + memset(digest, '\0', 24); + digest += 24; + + for (f = klen; f; f--) { + expkey[2*f-2] = key[f-1]; + expkey[2*f-1] = 0; + } + + /* + * ----------- + * answer = | k\0e\0y\0 | + * ----------- + */ + MD4Init(&MD4context); + MD4Update(&MD4context, expkey, klen << 1); + MD4Final(digest, &MD4context); + memcpy(digest + 25, name, nlen); + + /* + * ``result'' is: + * ---- --------- -------------------- ------ + * result = | 49 | 24 * \0 | digest (pad to 25) | name | + * ---- --------- -------------------- ------ + */ + chap_MS(digest, challenge + 1, *challenge); + + /* + * ---- --------- ---------------- --- ---------- + * result = | 49 | 24 * \0 | 24 byte digest | 1 | authname | + * ---- --------- ---------------- --- ---------- + */ + } else +#endif + if ((result = malloc(nlen + 17)) != NULL) { + /* Normal MD5 stuff */ + MD5_CTX MD5context; + + digest = result; + *digest++ = 16; /* value size */ + + MD5Init(&MD5context); +log_Printf(LogPHASE, "Build with 0x%x, %s & %.*s\n", id, key, *challenge, challenge+1); + MD5Update(&MD5context, &id, 1); + MD5Update(&MD5context, key, klen); + MD5Update(&MD5context, challenge + 1, *challenge); + MD5Final(digest, &MD5context); + + memcpy(digest + 16, name, nlen); + /* + * ---- -------- ------ + * result = | 16 | digest | name | + * ---- -------- ------ + */ + } + + return result; +} + +static void +chap_Challenge(struct authinfo *authp) +{ + struct chap *chap = auth2chap(authp); int len, i; char *cp; randinit(); - cp = chap->challenge_data; + cp = chap->challenge; #ifndef NORADIUS - if (*physical->dl->bundle->radius.cfg.file) { + if (*authp->physical->dl->bundle->radius.cfg.file) { /* For radius, our challenge is 16 readable NUL terminated bytes :*/ - *cp++ = chap->challenge_len = 16; - for (i = 0; i < chap->challenge_len; i++) + *cp++ = 16; + for (i = 0; i < 16; i++) *cp++ = (random() % 10) + '0'; } else #endif { - *cp++ = chap->challenge_len = random() % (CHAPCHALLENGELEN-16) + 16; - for (i = 0; i < chap->challenge_len; i++) + *cp++ = random() % (CHAPCHALLENGELEN-16) + 16; + for (i = 0; i < *chap->challenge; i++) *cp++ = random() & 0xff; } - len = strlen(physical->dl->bundle->cfg.auth.name); - memcpy(cp, physical->dl->bundle->cfg.auth.name, len); + len = strlen(authp->physical->dl->bundle->cfg.auth.name); + memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len); cp += len; - ChapOutput(physical, CHAP_CHALLENGE, chapid, chap->challenge_data, - cp - chap->challenge_data, NULL); + ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge, + cp - chap->challenge, NULL); } static void -RecvChapTalk(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, - struct physical *physical) +chap_Success(struct authinfo *authp) { - int valsize, len, arglen, keylen, namelen, success; - char *cp, *argp, *ap, *name, *digest; - char *keyp; - MD5_CTX MD5context; /* context for MD5 */ - char answer[CHAPDIGESTLEN]; - char cdigest[16]; -#ifdef HAVE_DES - int ix; - MD4_CTX MD4context; /* context for MD4 */ -#endif + datalink_GotAuthname(authp->physical->dl, authp->in.name); + ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL); + authp->physical->link.lcp.auth_ineed = 0; + if (Enabled(authp->physical->dl->bundle, OPT_UTMP)) + physical_Login(authp->physical, authp->in.name); - len = ntohs(chp->length); - log_Printf(LogDEBUG, "RecvChapTalk: length: %d\n", len); - arglen = len - sizeof(struct fsmheader); - cp = (char *) MBUF_CTOP(bp); - valsize = *cp++ & 255; - name = cp + valsize; - namelen = arglen - valsize - 1; - name[namelen] = 0; - - log_Printf(LogPHASE, "Chap Input: %s (from %s)\n", - chapcodes[chp->code], name); - - switch (chp->code) { - case CHAP_CHALLENGE: - keyp = bundle->cfg.auth.key; - keylen = strlen(bundle->cfg.auth.key); - name = bundle->cfg.auth.name; - namelen = strlen(bundle->cfg.auth.name); - -#ifdef HAVE_DES - if (physical->dl->chap.using_MSChap) - argp = malloc(1 + namelen + MS_CHAP_RESPONSE_LEN); - else -#endif - argp = malloc(1 + valsize + namelen + 16); - - if (argp == NULL) { - ChapOutput(physical, CHAP_FAILURE, chp->id, "Out of memory!", 14, NULL); - return; - } -#ifdef HAVE_DES - if (physical->dl->chap.using_MSChap) { - digest = argp; /* this is the response */ - *digest++ = MS_CHAP_RESPONSE_LEN; /* 49 */ - memset(digest, '\0', 24); - digest += 24; - - ap = answer; /* this is the challenge */ - memcpy(ap, keyp, keylen); - ap += 2 * keylen; - memcpy(ap, cp, valsize); - log_DumpBuff(LogDEBUG, "recv", ap, valsize); - ap += valsize; - for (ix = keylen; ix > 0 ; ix--) { - answer[2*ix-2] = answer[ix-1]; - answer[2*ix-1] = 0; - } - MD4Init(&MD4context); - MD4Update(&MD4context, answer, 2 * keylen); - MD4Final(digest, &MD4context); - memcpy(digest + 25, name, namelen); - ap += 2 * keylen; - chap_MS(digest, answer + 2 * keylen, valsize); - log_DumpBuff(LogDEBUG, "answer", digest, 24); - ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, - namelen + MS_CHAP_RESPONSE_LEN + 1, name); - } else { -#endif - digest = argp; - *digest++ = 16; /* value size */ - ap = answer; - *ap++ = chp->id; - memcpy(ap, keyp, keylen); - ap += keylen; - memcpy(ap, cp, valsize); - log_DumpBuff(LogDEBUG, "recv", ap, valsize); - ap += valsize; - MD5Init(&MD5context); - MD5Update(&MD5context, answer, ap - answer); - MD5Final(digest, &MD5context); - log_DumpBuff(LogDEBUG, "answer", digest, 16); - memcpy(digest + 16, name, namelen); - ap += namelen; - /* Send answer to the peer */ - ChapOutput(physical, CHAP_RESPONSE, chp->id, argp, namelen + 17, name); -#ifdef HAVE_DES - } -#endif - free(argp); - if (*name == '\0') - log_Printf(LogWARN, "Sending empty CHAP authname!\n"); - break; - case CHAP_RESPONSE: + if (authp->physical->link.lcp.auth_iwait == 0) /* - * Get a secret key corresponds to the peer + * Either I didn't need to authenticate, or I've already been + * told that I got the answer right. */ - success = 0; -#ifndef NORADIUS - if (*bundle->radius.cfg.file) { - char chapname[AUTHLEN], chal[17]; - - if (namelen > AUTHLEN - 1) - namelen = AUTHLEN - 1; - strncpy(chapname, name, namelen); - chapname[namelen] = '\0'; - *answer = chp->id; - strncpy(answer+1, cp, 16); - answer[17] = '\0'; - strncpy(chal, physical->dl->chap.challenge_data + 1, 16); - chal[16] = '\0'; - - if (radius_Authenticate(&bundle->radius, bundle, chapname, answer, chal)) - success = 1; /* And there was much rejoicing ! */ - - } else -#endif - if ((keyp = auth_GetSecret(bundle, name, namelen, physical))) { - /* Compute correct digest value */ - keylen = strlen(keyp); - ap = answer; - *ap++ = chp->id; - memcpy(ap, keyp, keylen); - ap += keylen; - MD5Init(&MD5context); - MD5Update(&MD5context, answer, ap - answer); - MD5Update(&MD5context, physical->dl->chap.challenge_data + 1, - physical->dl->chap.challenge_len); - MD5Final(cdigest, &MD5context); - log_DumpBuff(LogDEBUG, "got", cp, 16); - log_DumpBuff(LogDEBUG, "expect", cdigest, 16); - - /* - * Compare with the response - */ - if (memcmp(cp, cdigest, 16) == 0) - success = 1; - } - - if (success) { - datalink_GotAuthname(physical->dl, name, namelen); - ChapOutput(physical, CHAP_SUCCESS, chp->id, "Welcome!!", 10, NULL); - physical->link.lcp.auth_ineed = 0; - if (Enabled(bundle, OPT_UTMP)) - physical_Login(physical, name); - - if (physical->link.lcp.auth_iwait == 0) - /* - * Either I didn't need to authenticate, or I've already been - * told that I got the answer right. - */ - datalink_AuthOk(physical->dl); - } else { - /* - * Peer is not registerd, or response digest is wrong. - */ - ChapOutput(physical, CHAP_FAILURE, chp->id, "Invalid!!", 9, NULL); - datalink_AuthNotOk(physical->dl); - break; - } - } + datalink_AuthOk(authp->physical->dl); } static void -RecvChapResult(struct bundle *bundle, struct fsmheader *chp, struct mbuf *bp, - struct physical *physical) +chap_Failure(struct authinfo *authp) { - int len; - - len = ntohs(chp->length); - log_Printf(LogDEBUG, "RecvChapResult: length: %d\n", len); - if (chp->code == CHAP_SUCCESS) { - if (physical->link.lcp.auth_iwait == PROTO_CHAP) { - physical->link.lcp.auth_iwait = 0; - if (physical->link.lcp.auth_ineed == 0) - /* - * We've succeeded in our ``login'' - * If we're not expecting the peer to authenticate (or he already - * has), proceed to network phase. - */ - datalink_AuthOk(physical->dl); - } - } else { - /* CHAP failed - it's not going to get any better */ - log_Printf(LogPHASE, "Chap Input: Giving up after name/key FAILURE\n"); - datalink_AuthNotOk(physical->dl); - } + ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL); + datalink_AuthNotOk(authp->physical->dl); } void -chap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) +chap_Init(struct chap *chap, struct physical *p) { - int len = mbuf_Length(bp); - struct fsmheader *chp; + auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure); + *chap->challenge = 0; + chap->using_MSChap = 0; +} - if (len >= sizeof(struct fsmheader)) { - chp = (struct fsmheader *) MBUF_CTOP(bp); - if (len >= ntohs(chp->length)) { - if (chp->code < 1 || chp->code > 4) - chp->code = 0; - bp->offset += sizeof(struct fsmheader); - bp->cnt -= sizeof(struct fsmheader); +void +chap_Input(struct physical *p, struct mbuf *bp) +{ + struct chap *chap = &p->dl->chap; + char *name, *key, *ans, *myans; + int len, nlen; + u_char alen; - switch (chp->code) { - case CHAP_RESPONSE: - auth_StopTimer(&physical->dl->chap.auth); - /* Fall into.. */ + if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL) + log_Printf(LogERROR, "Chap Input: Truncated header !\n"); + else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE) + log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n", + chap->auth.in.hdr.code); + else { + len = mbuf_Length(bp); + ans = NULL; + + if (chap->auth.in.hdr.code != CHAP_CHALLENGE && + chap->auth.id != chap->auth.in.hdr.id && + Enabled(p->dl->bundle, OPT_IDCHECK)) { + /* Wrong conversation dude ! */ + log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n", + chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id, + chap->auth.id); + mbuf_Free(bp); + return; + } + chap->auth.id = chap->auth.in.hdr.id; /* We respond with this id */ + + switch (chap->auth.in.hdr.code) { case CHAP_CHALLENGE: - RecvChapTalk(bundle, chp, bp, physical); - break; + bp = mbuf_Read(bp, chap->challenge, 1); + len -= *chap->challenge + 1; + if (len < 0) { + log_Printf(LogERROR, "Chap Input: Truncated challenge !\n"); + mbuf_Free(bp); + return; + } + bp = mbuf_Read(bp, chap->challenge + 1, *chap->challenge); + bp = auth_ReadName(&chap->auth, bp, len); + break; + + case CHAP_RESPONSE: + auth_StopTimer(&chap->auth); + bp = mbuf_Read(bp, &alen, 1); + len -= alen + 1; + if (len < 0) { + log_Printf(LogERROR, "Chap Input: Truncated response !\n"); + mbuf_Free(bp); + return; + } + if ((ans = malloc(alen + 2)) == NULL) { + log_Printf(LogERROR, "Chap Input: Out of memory !\n"); + mbuf_Free(bp); + return; + } + *ans = chap->auth.id; + bp = mbuf_Read(bp, ans + 1, alen); + ans[alen+1] = '\0'; + bp = auth_ReadName(&chap->auth, bp, len); + break; + case CHAP_SUCCESS: case CHAP_FAILURE: - log_Printf(LogPHASE, "Chap Input: %s\n", chapcodes[chp->code]); - RecvChapResult(bundle, chp, bp, physical); - break; - } + /* chap->auth.in.name is already set up at CHALLENGE time */ + if ((ans = malloc(len + 1)) == NULL) { + log_Printf(LogERROR, "Chap Input: Out of memory !\n"); + mbuf_Free(bp); + return; + } + bp = mbuf_Read(bp, ans, len); + ans[len] = '\0'; + break; } + + switch (chap->auth.in.hdr.code) { + case CHAP_CHALLENGE: + case CHAP_RESPONSE: + if (*chap->auth.in.name) + log_Printf(LogPHASE, "Chap Input: %s (from %s)\n", + chapcodes[chap->auth.in.hdr.code], chap->auth.in.name); + else + log_Printf(LogPHASE, "Chap Input: %s\n", + chapcodes[chap->auth.in.hdr.code]); + break; + + case CHAP_SUCCESS: + case CHAP_FAILURE: + if (*ans) + log_Printf(LogPHASE, "Chap Input: %s (%s)\n", + chapcodes[chap->auth.in.hdr.code], ans); + else + log_Printf(LogPHASE, "Chap Input: %s\n", + chapcodes[chap->auth.in.hdr.code]); + break; + } + + switch (chap->auth.in.hdr.code) { + case CHAP_CHALLENGE: + name = p->dl->bundle->cfg.auth.name; + nlen = strlen(name); + key = p->dl->bundle->cfg.auth.key; + myans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, 0); + if (myans) { + ChapOutput(p, CHAP_RESPONSE, chap->auth.id, myans, + *myans + 1 + nlen, name); + free(myans); + } else + ChapOutput(p, CHAP_FAILURE, chap->auth.id, "Out of memory!", + 14, NULL); + break; + + case CHAP_RESPONSE: + name = chap->auth.in.name; + nlen = strlen(name); +#ifndef NORADIUS + if (*p->dl->bundle->radius.cfg.file) { + chap->challenge[*chap->challenge+1] = '\0'; +log_Printf(LogPHASE, "Challenge %s, answer is %d bytes starting with %d\n", chap->challenge+1, alen+1, *ans); + radius_Authenticate(&p->dl->bundle->radius, &chap->auth, + chap->auth.in.name, ans, chap->challenge + 1); + } else +#endif + { + key = auth_GetSecret(p->dl->bundle, name, nlen, p); + if (key) { + myans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, + chap->using_MSChap); + if (myans == NULL) + key = NULL; + else { + if (memcmp(myans, ans, 1 + *myans)) + key = NULL; + free(myans); + } + } + + if (key) + chap_Success(&chap->auth); + else + chap_Failure(&chap->auth); + } + + break; + + case CHAP_SUCCESS: + if (p->link.lcp.auth_iwait == PROTO_CHAP) { + p->link.lcp.auth_iwait = 0; + if (p->link.lcp.auth_ineed == 0) + /* + * We've succeeded in our ``login'' + * If we're not expecting the peer to authenticate (or he already + * has), proceed to network phase. + */ + datalink_AuthOk(p->dl); + } + break; + + case CHAP_FAILURE: + datalink_AuthNotOk(p->dl); + break; + } + free(ans); } + mbuf_Free(bp); } diff --git a/usr.sbin/ppp/chap.h b/usr.sbin/ppp/chap.h index c5043543aa16..0aaea8891998 100644 --- a/usr.sbin/ppp/chap.h +++ b/usr.sbin/ppp/chap.h @@ -15,14 +15,13 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.h,v 1.9.2.6 1998/05/01 19:24:05 brian Exp $ + * $Id: chap.h,v 1.10 1998/05/21 21:44:27 brian Exp $ * * TODO: */ struct mbuf; struct physical; -struct bundle; #define CHAP_CHALLENGE 1 #define CHAP_RESPONSE 2 @@ -31,12 +30,11 @@ struct bundle; struct chap { struct authinfo auth; - char challenge_data[80]; - int challenge_len; + char challenge[CHAPCHALLENGELEN + AUTHLEN]; unsigned using_MSChap : 1; /* A combination of MD4 & DES */ }; #define auth2chap(a) ((struct chap *)(a)) -extern void chap_Input(struct bundle *, struct mbuf *, struct physical *); -extern void chap_SendChallenge(struct authinfo *, int, struct physical *); +extern void chap_Init(struct chap *, struct physical *); +extern void chap_Input(struct physical *, struct mbuf *); diff --git a/usr.sbin/ppp/datalink.c b/usr.sbin/ppp/datalink.c index 7aa88cf7e0cb..3b52c04ccba8 100644 --- a/usr.sbin/ppp/datalink.c +++ b/usr.sbin/ppp/datalink.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: datalink.c,v 1.27 1999/02/01 13:42:24 brian Exp $ + * $Id: datalink.c,v 1.28 1999/02/02 09:35:17 brian Exp $ */ #include @@ -469,7 +469,7 @@ datalink_LayerUp(void *v, struct fsm *fp) struct datalink *dl = (struct datalink *)v; if (fp->proto == PROTO_LCP) { - datalink_GotAuthname(dl, "", 0); + datalink_GotAuthname(dl, ""); dl->physical->link.lcp.auth_ineed = dl->physical->link.lcp.want_auth; dl->physical->link.lcp.auth_iwait = dl->physical->link.lcp.his_auth; if (dl->physical->link.lcp.his_auth || dl->physical->link.lcp.want_auth) { @@ -479,21 +479,19 @@ datalink_LayerUp(void *v, struct fsm *fp) Auth2Nam(dl->physical->link.lcp.his_auth), Auth2Nam(dl->physical->link.lcp.want_auth)); if (dl->physical->link.lcp.his_auth == PROTO_PAP) - auth_StartChallenge(&dl->pap, dl->physical, pap_SendChallenge); + auth_StartReq(&dl->pap); if (dl->physical->link.lcp.want_auth == PROTO_CHAP) - auth_StartChallenge(&dl->chap.auth, dl->physical, chap_SendChallenge); + auth_StartReq(&dl->chap.auth); } else datalink_AuthOk(dl); } } void -datalink_GotAuthname(struct datalink *dl, const char *name, int len) +datalink_GotAuthname(struct datalink *dl, const char *name) { - if (len >= sizeof dl->peer.authname) - len = sizeof dl->peer.authname - 1; - strncpy(dl->peer.authname, name, len); - dl->peer.authname[len] = '\0'; + strncpy(dl->peer.authname, name, sizeof dl->peer.authname - 1); + dl->peer.authname[sizeof dl->peer.authname - 1] = '\0'; } void @@ -724,14 +722,14 @@ datalink_Create(const char *name, struct bundle *bundle, int type) dl->fsmp.LayerFinish = datalink_LayerFinish; dl->fsmp.object = dl; - auth_Init(&dl->pap); - auth_Init(&dl->chap.auth); - if ((dl->physical = modem_Create(dl, type)) == NULL) { free(dl->name); free(dl); return NULL; } + + pap_Init(&dl->pap, dl->physical); + chap_Init(&dl->chap, dl->physical); cbcp_Init(&dl->cbcp, dl->physical); chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); @@ -774,17 +772,18 @@ datalink_Clone(struct datalink *odl, const char *name) dl->parent = odl->parent; memcpy(&dl->fsmp, &odl->fsmp, sizeof dl->fsmp); dl->fsmp.object = dl; - auth_Init(&dl->pap); - dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; - - auth_Init(&dl->chap.auth); - dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; if ((dl->physical = modem_Create(dl, PHYS_INTERACTIVE)) == NULL) { free(dl->name); free(dl); return NULL; } + pap_Init(&dl->pap, dl->physical); + dl->pap.cfg.fsmretry = odl->pap.cfg.fsmretry; + + chap_Init(&dl->chap, dl->physical); + dl->chap.auth.cfg.fsmretry = odl->chap.auth.cfg.fsmretry; + memcpy(&dl->physical->cfg, &odl->physical->cfg, sizeof dl->physical->cfg); memcpy(&dl->physical->link.lcp.cfg, &odl->physical->link.lcp.cfg, sizeof dl->physical->link.lcp.cfg); @@ -1180,14 +1179,6 @@ iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, dl->fsmp.LayerFinish = datalink_LayerFinish; dl->fsmp.object = dl; - retry = dl->pap.cfg.fsmretry; - auth_Init(&dl->pap); - dl->pap.cfg.fsmretry = retry; - - retry = dl->chap.auth.cfg.fsmretry; - auth_Init(&dl->chap.auth); - dl->chap.auth.cfg.fsmretry = retry; - dl->physical = iov2modem(dl, iov, niov, maxiov, fd); if (!dl->physical) { @@ -1195,6 +1186,14 @@ iov2datalink(struct bundle *bundle, struct iovec *iov, int *niov, int maxiov, free(dl); dl = NULL; } else { + retry = dl->pap.cfg.fsmretry; + pap_Init(&dl->pap, dl->physical); + dl->pap.cfg.fsmretry = retry; + + retry = dl->chap.auth.cfg.fsmretry; + chap_Init(&dl->chap, dl->physical); + dl->chap.auth.cfg.fsmretry = retry; + cbcp_Init(&dl->cbcp, dl->physical); chat_Init(&dl->chat, dl->physical, NULL, 1, NULL); diff --git a/usr.sbin/ppp/datalink.h b/usr.sbin/ppp/datalink.h index 40801997e31b..e02e26420822 100644 --- a/usr.sbin/ppp/datalink.h +++ b/usr.sbin/ppp/datalink.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: datalink.h,v 1.4 1998/06/15 19:05:19 brian Exp $ + * $Id: datalink.h,v 1.5 1998/08/07 18:42:48 brian Exp $ */ #define DATALINK_CLOSED (0) @@ -123,7 +123,7 @@ extern struct datalink *iov2datalink(struct bundle *, struct iovec *, int *, int, int); extern int datalink2iov(struct datalink *, struct iovec *, int *, int, pid_t); extern struct datalink *datalink_Destroy(struct datalink *); -extern void datalink_GotAuthname(struct datalink *, const char *, int); +extern void datalink_GotAuthname(struct datalink *, const char *); extern void datalink_Up(struct datalink *, int, int); extern void datalink_Close(struct datalink *, int); extern void datalink_Down(struct datalink *, int); diff --git a/usr.sbin/ppp/descriptor.h b/usr.sbin/ppp/descriptor.h index 98cda53f1795..a4f43a3c07f0 100644 --- a/usr.sbin/ppp/descriptor.h +++ b/usr.sbin/ppp/descriptor.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: descriptor.h,v 1.3 1998/05/23 22:24:34 brian Exp $ + * $Id: descriptor.h,v 1.4 1998/06/24 19:33:31 brian Exp $ */ #define PHYSICAL_DESCRIPTOR (1) @@ -33,6 +33,7 @@ #define DATALINK_DESCRIPTOR (5) #define BUNDLE_DESCRIPTOR (6) #define MPSERVER_DESCRIPTOR (7) +#define RADIUS_DESCRIPTOR (8) struct bundle; diff --git a/usr.sbin/ppp/hdlc.c b/usr.sbin/ppp/hdlc.c index ce5db4616517..bca157db9704 100644 --- a/usr.sbin/ppp/hdlc.c +++ b/usr.sbin/ppp/hdlc.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: hdlc.c,v 1.36 1998/08/07 18:42:48 brian Exp $ + * $Id: hdlc.c,v 1.37 1999/01/28 01:56:32 brian Exp $ * * TODO: */ @@ -393,7 +393,7 @@ hdlc_DecodePacket(struct bundle *bundle, u_short proto, struct mbuf * bp, break; case PROTO_PAP: if (p) - pap_Input(bundle, bp, p); + pap_Input(p, bp); else { log_Printf(LogERROR, "DecodePacket: PAP: Not a physical link !\n"); mbuf_Free(bp); @@ -418,7 +418,7 @@ hdlc_DecodePacket(struct bundle *bundle, u_short proto, struct mbuf * bp, break; case PROTO_CHAP: if (p) - chap_Input(bundle, bp, p); + chap_Input(p, bp); else { log_Printf(LogERROR, "DecodePacket: CHAP: Not a physical link !\n"); mbuf_Free(bp); diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c index a2c337ea2b3c..a4309948befc 100644 --- a/usr.sbin/ppp/ipcp.c +++ b/usr.sbin/ppp/ipcp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ipcp.c,v 1.69 1999/01/28 01:56:32 brian Exp $ + * $Id: ipcp.c,v 1.70 1999/02/02 20:27:12 brian Exp $ * * TODO: * o More RFC1772 backward compatibility @@ -30,10 +30,7 @@ #include #include #include -#include -#include #include -#include #include #include diff --git a/usr.sbin/ppp/link.c b/usr.sbin/ppp/link.c index 68672a533c85..c3a7453ff4d2 100644 --- a/usr.sbin/ppp/link.c +++ b/usr.sbin/ppp/link.c @@ -23,14 +23,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: link.c,v 1.5 1998/08/25 17:48:42 brian Exp $ + * $Id: link.c,v 1.6 1998/08/26 18:07:56 brian Exp $ * */ #include #include -#include #include #include "defs.h" diff --git a/usr.sbin/ppp/main.c b/usr.sbin/ppp/main.c index d37c91db0be6..de93fbb84c5d 100644 --- a/usr.sbin/ppp/main.c +++ b/usr.sbin/ppp/main.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: main.c,v 1.148 1999/01/28 01:56:33 brian Exp $ + * $Id: main.c,v 1.149 1999/02/02 09:35:29 brian Exp $ * * TODO: */ @@ -516,6 +516,8 @@ DoLoop(struct bundle *bundle) break; } + log_Printf(LogTIMER, "Select returns %d\n", i); + sig_Handle(); if (i <= 0) diff --git a/usr.sbin/ppp/mbuf.c b/usr.sbin/ppp/mbuf.c index 9601689343c2..fa9440685e47 100644 --- a/usr.sbin/ppp/mbuf.c +++ b/usr.sbin/ppp/mbuf.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: mbuf.c,v 1.21 1998/08/21 18:10:15 brian Exp $ + * $Id: mbuf.c,v 1.22 1998/08/25 17:48:42 brian Exp $ * */ #include @@ -114,13 +114,8 @@ mbuf_Read(struct mbuf * bp, u_char * ptr, int len) bp->cnt -= nb; len -= nb; bp->offset += nb; - if (bp->cnt == 0) { -#ifdef notdef - bp = bp->next; -#else + if (bp->cnt == 0) bp = mbuf_FreeSeg(bp); -#endif - } } return (bp); } diff --git a/usr.sbin/ppp/pap.c b/usr.sbin/ppp/pap.c index a87cc8233481..10be5776d5e1 100644 --- a/usr.sbin/ppp/pap.c +++ b/usr.sbin/ppp/pap.c @@ -18,7 +18,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pap.c,v 1.29 1999/02/01 13:42:25 brian Exp $ + * $Id: pap.c,v 1.30 1999/02/02 09:35:17 brian Exp $ * * TODO: */ @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include "mbuf.h" @@ -63,41 +63,41 @@ #include "datalink.h" static const char *papcodes[] = { "???", "REQUEST", "SUCCESS", "FAILURE" }; +#define MAXPAPCODE (sizeof papcodes / sizeof papcodes[0] - 1) -void -pap_SendChallenge(struct authinfo *auth, int papid, struct physical *physical) +static void +pap_Req(struct authinfo *authp) { + struct bundle *bundle = authp->physical->dl->bundle; struct fsmheader lh; struct mbuf *bp; u_char *cp; int namelen, keylen, plen; - namelen = strlen(physical->dl->bundle->cfg.auth.name); - keylen = strlen(physical->dl->bundle->cfg.auth.key); + namelen = strlen(bundle->cfg.auth.name); + keylen = strlen(bundle->cfg.auth.key); plen = namelen + keylen + 2; - log_Printf(LogDEBUG, "pap_SendChallenge: namelen = %d, keylen = %d\n", - namelen, keylen); - log_Printf(LogPHASE, "Pap Output: %s ********\n", - physical->dl->bundle->cfg.auth.name); - if (*physical->dl->bundle->cfg.auth.name == '\0') + log_Printf(LogDEBUG, "pap_Req: namelen = %d, keylen = %d\n", namelen, keylen); + log_Printf(LogPHASE, "Pap Output: %s ********\n", bundle->cfg.auth.name); + if (*bundle->cfg.auth.name == '\0') log_Printf(LogWARN, "Sending empty PAP authname!\n"); lh.code = PAP_REQUEST; - lh.id = papid; + lh.id = authp->id; lh.length = htons(plen + sizeof(struct fsmheader)); bp = mbuf_Alloc(plen + sizeof(struct fsmheader), MB_FSM); memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader)); cp = MBUF_CTOP(bp) + sizeof(struct fsmheader); *cp++ = namelen; - memcpy(cp, physical->dl->bundle->cfg.auth.name, namelen); + memcpy(cp, bundle->cfg.auth.name, namelen); cp += namelen; *cp++ = keylen; - memcpy(cp, physical->dl->bundle->cfg.auth.key, keylen); + memcpy(cp, bundle->cfg.auth.key, keylen); - hdlc_Output(&physical->link, PRI_LINK, PROTO_PAP, bp); + hdlc_Output(&authp->physical->link, PRI_LINK, PROTO_PAP, bp); } static void -SendPapCode(int id, int code, const char *message, struct physical *physical) +SendPapCode(struct authinfo *authp, int code, const char *message) { struct fsmheader lh; struct mbuf *bp; @@ -105,7 +105,7 @@ SendPapCode(int id, int code, const char *message, struct physical *physical) int plen, mlen; lh.code = code; - lh.id = id; + lh.id = authp->id; mlen = strlen(message); plen = mlen + 1; lh.length = htons(plen + sizeof(struct fsmheader)); @@ -115,90 +115,124 @@ SendPapCode(int id, int code, const char *message, struct physical *physical) *cp++ = mlen; memcpy(cp, message, mlen); log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]); - hdlc_Output(&physical->link, PRI_LINK, PROTO_PAP, bp); + + hdlc_Output(&authp->physical->link, PRI_LINK, PROTO_PAP, bp); } -/* - * Validate given username and passwrd against with secret table - */ -static int -PapValidate(struct bundle *bundle, u_char *name, u_char *key, - struct physical *physical) +static void +pap_Success(struct authinfo *authp) { - int nlen, klen; + datalink_GotAuthname(authp->physical->dl, authp->in.name); + SendPapCode(authp, PAP_ACK, "Greetings!!"); + authp->physical->link.lcp.auth_ineed = 0; + if (Enabled(authp->physical->dl->bundle, OPT_UTMP)) + physical_Login(authp->physical, authp->in.name); - nlen = *name++; - klen = *key; - *key++ = 0; - key[klen] = 0; - log_Printf(LogDEBUG, "PapValidate: name %s (%d), key %s (%d)\n", - name, nlen, key, klen); + if (authp->physical->link.lcp.auth_iwait == 0) + /* + * Either I didn't need to authenticate, or I've already been + * told that I got the answer right. + */ + datalink_AuthOk(authp->physical->dl); +} - return auth_Validate(bundle, name, key, physical); +static void +pap_Failure(struct authinfo *authp) +{ + SendPapCode(authp, PAP_NAK, "Login incorrect"); + datalink_AuthNotOk(authp->physical->dl); } void -pap_Input(struct bundle *bundle, struct mbuf *bp, struct physical *physical) +pap_Init(struct authinfo *pap, struct physical *p) { - int len = mbuf_Length(bp); - struct fsmheader *php; - u_char *cp; + auth_Init(pap, p, pap_Req, pap_Success, pap_Failure); +} - if (len >= sizeof(struct fsmheader)) { - php = (struct fsmheader *) MBUF_CTOP(bp); - if (len >= ntohs(php->length)) { - if (php->code < PAP_REQUEST || php->code > PAP_NAK) - php->code = 0; - switch (php->code) { - case PAP_REQUEST: - cp = (u_char *) (php + 1); - log_Printf(LogPHASE, "Pap Input: %s (%.*s)\n", - papcodes[php->code], *cp, cp + 1); - if (PapValidate(bundle, cp, cp + *cp + 1, physical)) { - datalink_GotAuthname(physical->dl, cp+1, *cp); - SendPapCode(php->id, PAP_ACK, "Greetings!!", physical); - physical->link.lcp.auth_ineed = 0; - if (Enabled(bundle, OPT_UTMP)) - physical_Login(physical, cp + 1); +void +pap_Input(struct physical *p, struct mbuf *bp) +{ + struct authinfo *authp = &p->dl->pap; + u_char nlen, klen, *key; - if (physical->link.lcp.auth_iwait == 0) - /* - * Either I didn't need to authenticate, or I've already been - * told that I got the answer right. - */ - datalink_AuthOk(physical->dl); - } else { - SendPapCode(php->id, PAP_NAK, "Login incorrect", physical); - datalink_AuthNotOk(physical->dl); - } - break; - case PAP_ACK: - auth_StopTimer(&physical->dl->pap); - cp = (u_char *) (php + 1); - len = *cp++; - cp[len] = 0; - log_Printf(LogPHASE, "Pap Input: %s (%s)\n", papcodes[php->code], cp); - if (physical->link.lcp.auth_iwait == PROTO_PAP) { - physical->link.lcp.auth_iwait = 0; - if (physical->link.lcp.auth_ineed == 0) - /* - * We've succeeded in our ``login'' - * If we're not expecting the peer to authenticate (or he already - * has), proceed to network phase. - */ - datalink_AuthOk(physical->dl); - } - break; - case PAP_NAK: - auth_StopTimer(&physical->dl->pap); - cp = (u_char *) (php + 1); - len = *cp++; - cp[len] = 0; - log_Printf(LogPHASE, "Pap Input: %s (%s)\n", papcodes[php->code], cp); - datalink_AuthNotOk(physical->dl); - break; - } - } + if ((bp = auth_ReadHeader(authp, bp)) == NULL) + return; + + if (authp->in.hdr.code == 0 || authp->in.hdr.code > MAXPAPCODE) { + log_Printf(LogPHASE, "Pap Input: %d: Bad PAP code !\n", authp->in.hdr.code); + mbuf_Free(bp); + return; } + + if (authp->in.hdr.code != PAP_REQUEST && authp->id != authp->in.hdr.id && + Enabled(p->dl->bundle, OPT_IDCHECK)) { + /* Wrong conversation dude ! */ + log_Printf(LogPHASE, "Pap Input: %s dropped (got id %d, not %d)\n", + papcodes[authp->in.hdr.code], authp->in.hdr.id, authp->id); + mbuf_Free(bp); + return; + } + authp->id = authp->in.hdr.id; /* We respond with this id */ + + if (bp) { + bp = mbuf_Read(bp, &nlen, 1); + bp = auth_ReadName(authp, bp, nlen); + } + + log_Printf(LogPHASE, "Pap Input: %s (%s)\n", + papcodes[authp->in.hdr.code], authp->in.name); + + switch (authp->in.hdr.code) { + case PAP_REQUEST: + if (bp == NULL) { + log_Printf(LogPHASE, "Pap Input: No key given !\n"); + break; + } + bp = mbuf_Read(bp, &klen, 1); + if (mbuf_Length(bp) < klen) { + log_Printf(LogERROR, "Pap Input: Truncated key !\n"); + break; + } + if ((key = malloc(klen+1)) == NULL) { + log_Printf(LogERROR, "Pap Input: Out of memory !\n"); + break; + } + bp = mbuf_Read(bp, key, klen); + key[klen] = '\0'; + +#ifndef NORADIUS + if (*p->dl->bundle->radius.cfg.file) + radius_Authenticate(&p->dl->bundle->radius, authp, authp->in.name, + key, NULL); + else +#endif + if (auth_Validate(p->dl->bundle, authp->in.name, key, p)) + pap_Success(authp); + else + pap_Failure(authp); + + free(key); + break; + + case PAP_ACK: + auth_StopTimer(authp); + if (p->link.lcp.auth_iwait == PROTO_PAP) { + p->link.lcp.auth_iwait = 0; + if (p->link.lcp.auth_ineed == 0) + /* + * We've succeeded in our ``login'' + * If we're not expecting the peer to authenticate (or he already + * has), proceed to network phase. + */ + datalink_AuthOk(p->dl); + } + break; + + case PAP_NAK: + auth_StopTimer(authp); + datalink_AuthNotOk(p->dl); + break; + } + mbuf_Free(bp); } diff --git a/usr.sbin/ppp/pap.h b/usr.sbin/ppp/pap.h index ac08b8ba905b..bef82927b451 100644 --- a/usr.sbin/ppp/pap.h +++ b/usr.sbin/ppp/pap.h @@ -15,7 +15,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pap.h,v 1.7 1999/02/01 13:42:25 brian Exp $ + * $Id: pap.h,v 1.8 1999/02/02 09:35:17 brian Exp $ * * TODO: */ @@ -27,7 +27,6 @@ struct mbuf; struct physical; struct authinfo; -struct bundle; -extern void pap_Input(struct bundle *, struct mbuf *, struct physical *); -extern void pap_SendChallenge(struct authinfo *, int, struct physical *); +extern void pap_Init(struct authinfo *, struct physical *); +extern void pap_Input(struct physical *, struct mbuf *); diff --git a/usr.sbin/ppp/radius.c b/usr.sbin/ppp/radius.c index b60605aeb5cc..1228b67210a8 100644 --- a/usr.sbin/ppp/radius.c +++ b/usr.sbin/ppp/radius.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: radius.c,v 1.1 1999/01/28 01:56:34 brian Exp $ + * $Id: radius.c,v 1.2 1999/01/29 22:46:31 brian Exp $ * */ @@ -36,10 +36,10 @@ #include #include -#include #include #include #include +#include #include #include "defs.h" @@ -58,143 +58,86 @@ #include "route.h" #include "command.h" #include "filter.h" -#include "server.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #include "radius.h" +#include "auth.h" +#include "async.h" +#include "physical.h" +#include "chat.h" +#include "cbcp.h" +#include "chap.h" +#include "datalink.h" #include "bundle.h" -void -radius_Init(struct radius *r) +/* + * rad_continue_send_request() has given us `got' (non-zero). Deal with it. + */ +static void +radius_Process(struct radius *r, int got) { - r->valid = 0; - *r->cfg.file = '\0';; -} - -void -radius_Destroy(struct radius *r) -{ - r->valid = 0; - route_DeleteAll(&r->routes); -} - -int -radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name, - const char *key, const char *challenge) -{ - struct rad_handle *h; - sigset_t alrm, prevset; - const void *data; - int got, len, argc, addrs; char *argv[MAXARGS], *nuke; + struct bundle *bundle; + int len, argc, addrs; struct in_range dest; struct in_addr gw; + const void *data; - radius_Destroy(r); - - if (!*r->cfg.file) - return 0; - - if ((h = rad_open()) == NULL) { - log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); - return 0; - } - - if (rad_config(h, r->cfg.file) != 0) { - log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(h)); - rad_close(h); - return 0; - } - - if (rad_create_request(h, RAD_ACCESS_REQUEST) != 0) { - log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(h)); - rad_close(h); - return 0; - } - - if (rad_put_string(h, RAD_USER_NAME, name) != 0 || - rad_put_int(h, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || - rad_put_int(h, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { - log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(h)); - rad_close(h); - return 0; - } - - if (challenge != NULL) { /* CHAP */ - if (rad_put_string(h, RAD_CHAP_PASSWORD, key) != 0 || - rad_put_string(h, RAD_CHAP_CHALLENGE, challenge) != 0) { - log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", rad_strerror(h)); - rad_close(h); - return 0; - } - } else if (rad_put_string(h, RAD_USER_PASSWORD, key) != 0) { /* PAP */ - /* We're talking PAP */ - log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(h)); - rad_close(h); - return 0; - } - - /* - * Having to do this is bad news. The right way is to grab the - * descriptor that rad_send_request() selects on and add it to - * our own selection list (making a full ``struct descriptor''), - * then to ``continue'' the call when the descriptor is ready. - * This requires altering libradius.... - */ - sigemptyset(&alrm); - sigaddset(&alrm, SIGALRM); - sigprocmask(SIG_BLOCK, &alrm, &prevset); - got = rad_send_request(h); - sigprocmask(SIG_SETMASK, &prevset, NULL); + r->cx.fd = -1; /* Stop select()ing */ switch (got) { case RAD_ACCESS_ACCEPT: + log_Printf(LogPHASE, "Radius: ACCEPT received\n"); break; + case RAD_ACCESS_REJECT: + log_Printf(LogPHASE, "Radius: REJECT received\n"); + auth_Failure(r->cx.auth); + rad_close(r->cx.rad); + return; + case RAD_ACCESS_CHALLENGE: /* we can't deal with this (for now) ! */ - log_Printf(LogPHASE, "Can't handle radius CHALLENGEs !\n"); - rad_close(h); - return 0; + log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); + auth_Failure(r->cx.auth); + rad_close(r->cx.rad); + return; case -1: - log_Printf(LogPHASE, "radius: %s\n", rad_strerror(h)); - rad_close(h); - return 0; + log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad)); + auth_Failure(r->cx.auth); + rad_close(r->cx.rad); + return; default: log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", - got, rad_strerror(h)); - rad_close(h); - return 0; - - case RAD_ACCESS_REJECT: - log_Printf(LogPHASE, "radius: Rejected !\n"); - rad_close(h); - return 0; + got, rad_strerror(r->cx.rad)); + auth_Failure(r->cx.auth); + rad_close(r->cx.rad); + return; } /* So we've been accepted ! Let's see what we've got in our reply :-I */ r->ip.s_addr = r->mask.s_addr = INADDR_NONE; r->mtu = 0; r->vj = 0; - while ((got = rad_get_attr(h, &data, &len)) > 0) { + while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { switch (got) { case RAD_FRAMED_IP_ADDRESS: r->ip = rad_cvt_addr(data); - log_Printf(LogDEBUG, "radius: Got IP %s\n", inet_ntoa(r->ip)); + log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); break; case RAD_FRAMED_IP_NETMASK: r->mask = rad_cvt_addr(data); - log_Printf(LogDEBUG, "radius: Got MASK %s\n", inet_ntoa(r->mask)); + log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); break; case RAD_FRAMED_MTU: r->mtu = rad_cvt_int(data); - log_Printf(LogDEBUG, "radius: Got MTU %lu\n", r->mtu); + log_Printf(LogPHASE, " MTU %lu\n", r->mtu); break; case RAD_FRAMED_ROUTING: @@ -206,7 +149,7 @@ radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name, case RAD_FRAMED_COMPRESSION: r->vj = rad_cvt_int(data) == 1 ? 1 : 0; - log_Printf(LogDEBUG, "radius: Got VJ %sabled\n", r->vj ? "en" : "dis"); + log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); break; case RAD_FRAMED_ROUTE: @@ -218,11 +161,13 @@ radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name, */ if ((nuke = rad_cvt_string(data, len)) == NULL) { - log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(h)); - rad_close(h); - return 0; + log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; } + log_Printf(LogPHASE, " Route: %s\n", nuke); + bundle = r->cx.auth->physical->dl->bundle; dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; dest.width = 0; argc = command_Interpret(nuke, strlen(nuke), argv); @@ -260,18 +205,208 @@ radius_Authenticate(struct radius *r, struct bundle *bundle, const char *name, } if (got == -1) { - log_Printf(LogERROR, "rad_get_attr: %s\n", rad_strerror(h)); - rad_close(h); - return 0; + log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", + rad_strerror(r->cx.rad)); + auth_Failure(r->cx.auth); + rad_close(r->cx.rad); + } else { + r->valid = 1; + auth_Success(r->cx.auth); + rad_close(r->cx.rad); } - - rad_close(h); - r->valid = 1; - log_Printf(LogPHASE, "radius: SUCCESS\n"); - - return 1; } +/* + * We've either timed out or select()ed on the read descriptor + */ +static void +radius_Continue(struct radius *r, int sel) +{ + struct timeval tv; + int got; + + timer_Stop(&r->cx.timer); + if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { + log_Printf(LogPHASE, "Radius: Request re-sent\n"); + r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; + timer_Start(&r->cx.timer); + return; + } + + radius_Process(r, got); +} + +/* + * Time to call rad_continue_send_request() - timed out. + */ +static void +radius_Timeout(void *v) +{ + radius_Continue((struct radius *)v, 0); +} + +/* + * Time to call rad_continue_send_request() - something to read. + */ +static void +radius_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + radius_Continue(descriptor2radius(d), 1); +} + +/* + * Behave as a struct descriptor (descriptor.h) + */ +static int +radius_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) +{ + struct radius *rad = descriptor2radius(d); + + if (r && rad->cx.fd != -1) { + FD_SET(rad->cx.fd, r); + if (*n < rad->cx.fd + 1) + *n = rad->cx.fd + 1; + log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); + return 1; + } + + return 0; +} + +/* + * Behave as a struct descriptor (descriptor.h) + */ +static int +radius_IsSet(struct descriptor *d, const fd_set *fdset) +{ + struct radius *r = descriptor2radius(d); + + return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); +} + +/* + * Behave as a struct descriptor (descriptor.h) + */ +static int +radius_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) +{ + /* We never want to write here ! */ + log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); + return 0; +} + +/* + * Initialise ourselves + */ +void +radius_Init(struct radius *r) +{ + r->valid = 0; + r->cx.fd = -1; + *r->cfg.file = '\0';; + r->desc.type = RADIUS_DESCRIPTOR; + r->desc.UpdateSet = radius_UpdateSet; + r->desc.IsSet = radius_IsSet; + r->desc.Read = radius_Read; + r->desc.Write = radius_Write; + memset(&r->cx.timer, '\0', sizeof r->cx.timer); +} + +/* + * Forget everything and go back to initialised state. + */ +void +radius_Destroy(struct radius *r) +{ + r->valid = 0; + timer_Stop(&r->cx.timer); + route_DeleteAll(&r->routes); + if (r->cx.fd != -1) { + r->cx.fd = -1; + rad_close(r->cx.rad); + } +} + +/* + * Start an authentication request to the RADIUS server. + */ +void +radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, + const char *key, const char *challenge) +{ + struct timeval tv; + int got; + + if (!*r->cfg.file) + return; + + if (r->cx.fd != -1) + /* + * We assume that our name/key/challenge is the same as last time, + * and just continue to wait for the RADIUS server(s). + */ + return; + + radius_Destroy(r); + + if ((r->cx.rad = rad_open()) == NULL) { + log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); + return; + } + + if (rad_config(r->cx.rad, r->cfg.file) != 0) { + log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; + } + + if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { + log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; + } + + if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || + rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || + rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { + log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; + } + + if (challenge != NULL) { + /* We're talking CHAP */ + if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 || + rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) { + log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", + rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; + } + } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) { + /* We're talking PAP */ + log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); + rad_close(r->cx.rad); + return; + } + + if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) + radius_Process(r, got); + else { + log_Printf(LogPHASE, "Radius: Request sent\n"); + log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); + r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; + r->cx.timer.func = radius_Timeout; + r->cx.timer.name = "radius"; + r->cx.timer.arg = r; + r->cx.auth = authp; + timer_Start(&r->cx.timer); + } +} + +/* + * How do things look at the moment ? + */ void radius_Show(struct radius *r, struct prompt *p) { diff --git a/usr.sbin/ppp/radius.h b/usr.sbin/ppp/radius.h index 0b02f21fc0a6..37cf7b8b7b86 100644 --- a/usr.sbin/ppp/radius.h +++ b/usr.sbin/ppp/radius.h @@ -23,10 +23,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id:$ + * $Id: radius.h,v 1.1 1999/01/28 01:56:34 brian Exp $ */ struct radius { + struct descriptor desc; /* We're a sort of (selectable) descriptor */ + struct { + int fd; /* We're selecting on this */ + struct rad_handle *rad; /* Using this to talk to our lib */ + struct pppTimer timer; /* for this long */ + struct authinfo *auth; /* Tell this about success/failure */ + } cx; unsigned valid : 1; /* Is this structure valid ? */ unsigned vj : 1; /* FRAMED Compression */ struct in_addr ip; /* FRAMED IP */ @@ -38,11 +45,14 @@ struct radius { } cfg; }; +#define descriptor2radius(d) \ + ((d)->type == RADIUS_DESCRIPTOR ? (struct radius *)(d) : NULL) + struct bundle; extern void radius_Init(struct radius *); extern void radius_Destroy(struct radius *); extern void radius_Show(struct radius *, struct prompt *); -extern int radius_Authenticate(struct radius *, struct bundle *, const char *, - const char *, const char *); +extern void radius_Authenticate(struct radius *, struct authinfo *, + const char *, const char *, const char *); diff --git a/usr.sbin/ppp/vjcomp.c b/usr.sbin/ppp/vjcomp.c index e402c033a24a..ee5100ad1121 100644 --- a/usr.sbin/ppp/vjcomp.c +++ b/usr.sbin/ppp/vjcomp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: vjcomp.c,v 1.23 1998/08/26 18:07:57 brian Exp $ + * $Id: vjcomp.c,v 1.24 1999/01/28 01:56:34 brian Exp $ * * TODO: */ @@ -28,7 +28,6 @@ #include #include -#include #include "mbuf.h" #include "log.h"