eb6e5e05f9
0.81.1 of the i4b code - namely support of the I4B_VR_REQ ioctl via the i4brbchX device. Ppp controls the phone number, but idle timers and SYNC/RAW decisions are still made by isdnd (in isdnd.rc). This involves a new datalink state machine phase. The ``wait for carrier'' phase happens after dialing but before logging in. The whole dial state should really be abstracted so that each device type can deal with it in its own way (thinking about PPPoE) - but that'll have to wait. The ``set cd'' symantics remain the same for tty devices, but we now delay until we either get CD or timeout waiting (at which time we drop the link if we require CD). For i4b devices we always insist on carrier. Thanks to hm@ for his help, and especially for pointing out that I *don't* need to re-implement isdnd (that was a huge waste of time !) :-]
260 lines
7.2 KiB
C
260 lines
7.2 KiB
C
/*
|
|
* PPP PAP Module
|
|
*
|
|
* Written by Toshiharu OHNO (tony-o@iij.ad.jp)
|
|
*
|
|
* Copyright (C) 1993-94, Internet Initiative Japan, Inc.
|
|
* All rights reserverd.
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that the above copyright notice and this paragraph are
|
|
* duplicated in all such forms and that any documentation,
|
|
* advertising materials, and other materials related to such
|
|
* distribution and use acknowledge that the software was developed
|
|
* by the Internet Initiative Japan, Inc. The name of the
|
|
* IIJ may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* $Id: pap.c,v 1.36 1999/06/02 15:59:07 brian Exp $
|
|
*
|
|
* TODO:
|
|
*/
|
|
#include <sys/param.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/ip.h>
|
|
#include <sys/un.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h> /* strlen/memcpy */
|
|
#include <termios.h>
|
|
|
|
#include "layer.h"
|
|
#include "mbuf.h"
|
|
#include "log.h"
|
|
#include "defs.h"
|
|
#include "timer.h"
|
|
#include "fsm.h"
|
|
#include "lcp.h"
|
|
#include "auth.h"
|
|
#include "pap.h"
|
|
#include "lqr.h"
|
|
#include "hdlc.h"
|
|
#include "proto.h"
|
|
#include "async.h"
|
|
#include "throughput.h"
|
|
#include "ccp.h"
|
|
#include "link.h"
|
|
#include "descriptor.h"
|
|
#include "physical.h"
|
|
#include "iplist.h"
|
|
#include "slcompress.h"
|
|
#include "ipcp.h"
|
|
#include "filter.h"
|
|
#include "mp.h"
|
|
#ifndef NORADIUS
|
|
#include "radius.h"
|
|
#endif
|
|
#include "bundle.h"
|
|
#include "chat.h"
|
|
#include "chap.h"
|
|
#include "cbcp.h"
|
|
#include "datalink.h"
|
|
|
|
static const char *papcodes[] = { "???", "REQUEST", "SUCCESS", "FAILURE" };
|
|
#define MAXPAPCODE (sizeof papcodes / sizeof papcodes[0] - 1)
|
|
|
|
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(bundle->cfg.auth.name);
|
|
keylen = strlen(bundle->cfg.auth.key);
|
|
plen = namelen + keylen + 2;
|
|
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 = authp->id;
|
|
lh.length = htons(plen + sizeof(struct fsmheader));
|
|
bp = mbuf_Alloc(plen + sizeof(struct fsmheader), MB_PAPOUT);
|
|
memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
|
|
cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
|
|
*cp++ = namelen;
|
|
memcpy(cp, bundle->cfg.auth.name, namelen);
|
|
cp += namelen;
|
|
*cp++ = keylen;
|
|
memcpy(cp, bundle->cfg.auth.key, keylen);
|
|
link_PushPacket(&authp->physical->link, bp, bundle, PRI_LINK, PROTO_PAP);
|
|
}
|
|
|
|
static void
|
|
SendPapCode(struct authinfo *authp, int code, const char *message)
|
|
{
|
|
struct fsmheader lh;
|
|
struct mbuf *bp;
|
|
u_char *cp;
|
|
int plen, mlen;
|
|
|
|
lh.code = code;
|
|
lh.id = authp->id;
|
|
mlen = strlen(message);
|
|
plen = mlen + 1;
|
|
lh.length = htons(plen + sizeof(struct fsmheader));
|
|
bp = mbuf_Alloc(plen + sizeof(struct fsmheader), MB_PAPOUT);
|
|
memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
|
|
cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
|
|
*cp++ = mlen;
|
|
memcpy(cp, message, mlen);
|
|
log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]);
|
|
|
|
link_PushPacket(&authp->physical->link, bp, authp->physical->dl->bundle,
|
|
PRI_LINK, PROTO_PAP);
|
|
}
|
|
|
|
static void
|
|
pap_Success(struct authinfo *authp)
|
|
{
|
|
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);
|
|
|
|
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);
|
|
}
|
|
|
|
static void
|
|
pap_Failure(struct authinfo *authp)
|
|
{
|
|
SendPapCode(authp, PAP_NAK, "Login incorrect");
|
|
datalink_AuthNotOk(authp->physical->dl);
|
|
}
|
|
|
|
void
|
|
pap_Init(struct authinfo *pap, struct physical *p)
|
|
{
|
|
auth_Init(pap, p, pap_Req, pap_Success, pap_Failure);
|
|
}
|
|
|
|
struct mbuf *
|
|
pap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
|
|
{
|
|
struct physical *p = link2physical(l);
|
|
struct authinfo *authp = &p->dl->pap;
|
|
u_char nlen, klen, *key;
|
|
|
|
if (p == NULL) {
|
|
log_Printf(LogERROR, "pap_Input: Not a physical link - dropped\n");
|
|
mbuf_Free(bp);
|
|
return NULL;
|
|
}
|
|
|
|
if (bundle_Phase(bundle) != PHASE_NETWORK &&
|
|
bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
|
|
log_Printf(LogPHASE, "Unexpected pap input - dropped !\n");
|
|
mbuf_Free(bp);
|
|
return NULL;
|
|
}
|
|
|
|
if ((bp = auth_ReadHeader(authp, bp)) == NULL &&
|
|
ntohs(authp->in.hdr.length) == 0) {
|
|
log_Printf(LogWARN, "Pap Input: Truncated header !\n");
|
|
return NULL;
|
|
}
|
|
|
|
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 NULL;
|
|
}
|
|
|
|
if (authp->in.hdr.code != PAP_REQUEST && authp->id != authp->in.hdr.id &&
|
|
Enabled(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 NULL;
|
|
}
|
|
mbuf_SetType(bp, MB_PAPIN);
|
|
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 (*bundle->radius.cfg.file)
|
|
radius_Authenticate(&bundle->radius, authp, authp->in.name,
|
|
key, NULL);
|
|
else
|
|
#endif
|
|
if (auth_Validate(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);
|
|
return NULL;
|
|
}
|