home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3
/
hamradioversion3.0examsandprograms1992.iso
/
packet
/
n17jsrc
/
ppppap.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-24
|
17KB
|
747 lines
/*
* PPPPAP.C -- Password Authentication Protocol for PPP
*
* This implementation of PPP is declared to be in the public domain.
*
* Jan 91 Bill_Simpson@um.cc.umich.edu
* Computer Systems Consulting Services
*
* Acknowledgements and correction history may be found in PPP.C
*/
#include <stdio.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "session.h"
#include "socket.h"
#include "ppp.h"
#include "pppfsm.h"
#include "ppppap.h"
#include "cmdparse.h"
#include "files.h"
static int dopap_user __ARGS((int argc, char *argv[], void *p));
static void pap_input __ARGS((int mustask, void *v1, void *v2));
static void pap_pwdlookup __ARGS((struct pap_s *pap_p));
static void pap_getpassword __ARGS((struct fsm_s *fsm_p, int mustask));
static struct mbuf *pap_makereq __ARGS((struct fsm_s *fsm_p));
static int pap_verify __ARGS((char *username, char *password));
static void pap_shutdown __ARGS((struct fsm_s *fsm_p));
static void pap_opening __ARGS((struct fsm_s *fsm_p, int flag));
static int pap_request __ARGS((struct fsm_s *fsm_p,
struct config_hdr *hdr,
struct mbuf *data));
static int pap_check __ARGS((struct fsm_s *fsm_p,
struct config_hdr *hdr,
struct mbuf *data));
static void pap_timeout __ARGS((void *vp));
static void pap_reset __ARGS((struct fsm_s *fsm_p));
static void pap_free __ARGS((struct fsm_s *fsm_p));
static void pap_init __ARGS((struct ppp_s *ppp_p));
static struct fsm_constant_s pap_constants = {
"Pap",
PPP_PAP_PROTOCOL,
0x000E, /* codes 1-3 recognized */
Pap,
PAP_REQ_TRY,
PAP_FAIL_MAX,
0,
PAP_TIMEOUT * 1000L,
pap_free,
fsm_no_action, /* pap_reset, */
fsm_no_action, /* pap_starting, */
fsm_no_action, /* pap_opening, */
fsm_no_action, /* pap_closing, */
fsm_no_action, /* pap_stopping, */
pap_makereq,
fsm_no_check, /* pap_request, */
fsm_no_check, /* pap_ack, */
fsm_no_check, /* pap_nak, */
fsm_no_check, /* pap_reject */
};
/****************************************************************************/
/* "ppp <iface> pap" subcommands */
static struct cmds Papcmds[] = {
"timeout", doppp_timeout, 0, 0, NULLCHAR,
"try", doppp_try, 0, 0, NULLCHAR,
"user", dopap_user, 0, 0, NULLCHAR,
NULLCHAR,
};
int
doppp_pap(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct iface *ifp = p;
register struct ppp_s *ppp_p = ifp->extension;
pap_init(ppp_p);
return subcmd(Papcmds, argc, argv, &(ppp_p->fsm[Pap]));
}
/* Set user/password */
int
dopap_user(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct fsm_s *fsm_p = p;
register struct pap_s *pap_p = fsm_p->pdv;
if (argc < 2) {
tprintf("%s\n",
(pap_p->username == NULLCHAR) ? "None" : pap_p->username);
return 0;
}
free(pap_p->username);
pap_p->username = NULLCHAR;
free(pap_p->password);
pap_p->password = NULLCHAR;
if (stricmp(argv[1],"none") != 0) {
pap_p->username = strdup(argv[1]);
if (argc > 2) {
pap_p->password = strdup(argv[2]);
} else {
pap_getpassword( fsm_p, FALSE);
}
}
return 0;
}
/****************************************************************************/
/* Bring up a session on the console for for the username/password.
* Return a NULLCHAR in either username or password if aborted.
*/
static void
pap_input(mustask, v1, v2)
int mustask;
void *v1;
void *v2;
{
struct iface *iface = v1;
struct pap_s *pap_p = v2;
char buf[21];
struct session *sp;
/* Allocate a session control block */
if((sp = newsession("PPP/PAP Auth",PPPPASS,0)) == NULLSESSION){
tprintf("Too many sessions\n");
return;
}
if (mustask)
tprintf("\n%s: PPP/PAP Password Authentication Failed;"
" enter ID and password again\n",
iface->name);
else
tprintf("\n%s: PPP/PAP Password Authentication Required\n",
iface->name);
tprintf("%s: PPP/PAP user: ",iface->name);
usflush(sp->output);
/* Only ask for the user if it is unknown */
if (pap_p->username == NULLCHAR) {
if (recvline(sp->input,buf,20) < 0) {
pap_p->username = NULLCHAR;
} else {
rip(buf);
pap_p->username = strdup(buf);
}
} else {
tprintf("%s\n",pap_p->username);
}
if (pap_p->username != NULLCHAR) {
/* turn off echo */
sp->ttystate.echo = 0;
tprintf("%s: PPP/PAP Password: ",iface->name);
usflush(sp->output);
if (recvline(sp->input,buf,20) < 0)
pap_p->password = NULLCHAR;
else {
rip(buf);
pap_p->password = strdup(buf);
}
tprintf("\n");
/* Turn echo back on */
sp->ttystate.echo = 1;
}
freesession(sp);
psignal(pap_p,0);
}
/* Check the FTP userfile for this user; get password if available */
static void
pap_pwdlookup(pap_p)
struct pap_s *pap_p;
{
char *buf;
char *password;
int permission;
if ( pap_p->username == NULLCHAR )
return;
if ( (buf = userlookup( pap_p->username, &password, NULLCHARP,
&permission, NULL )) == NULLCHAR )
return;
/* Check permissions for this user */
if ( (permission & PPP_PWD_LOOKUP) == 0 ) {
/* Not in ftpuser file for password lookup */
free(buf);
return;
}
/* Save the password from this userfile record */
pap_p->password = strdup(password);
free(buf);
}
/* Get user ID and password
* Return a NULLCHAR in either username or password if undefined
*/
static void
pap_getpassword(fsm_p,mustask)
struct fsm_s *fsm_p;
int mustask;
{
struct pap_s *pap_p = fsm_p->pdv;
if (mustask) {
free(pap_p->username);
pap_p->username = NULLCHAR;
free(pap_p->password);
pap_p->password = NULLCHAR;
} else if ( pap_p->username != NULLCHAR
&& pap_p->password == NULLCHAR) {
pap_pwdlookup(pap_p);
}
if ((pap_p->username == NULLCHAR)
|| (pap_p->password == NULLCHAR)) {
char *ifn = if_name( fsm_p->ppp_p->iface, " PAP" );
newproc( ifn,
256, pap_input, mustask, fsm_p->ppp_p->iface, pap_p, 0);
free( ifn );
pwait( fsm_p->pdv );
}
}
/*******************************************/
/* Verify user and password sent by remote host */
static int
pap_verify(username,password)
char *username;
char *password;
{
int privs;
char *path;
int anony = 0;
/* Use same login as FTP server */
path = mallocw(128);
privs = userlogin(username,password,&path,128,&anony);
free(path);
/* Check privs for this user */
if (privs == -1) {
log(-1,"PAP: username/password incorrect or not found: %s",
username);
return -1;
}
if ((privs & PPP_ACCESS_PRIV) == 0) {
log(-1,"PAP: no permission for PPP access: %s",
username);
return -1;
}
return 0;
}
/****************************************************************************/
/* Build a request to send to remote host */
static struct mbuf *
pap_makereq(fsm_p)
struct fsm_s *fsm_p;
{
struct pap_s *pap_p = fsm_p->pdv;
struct mbuf *req_bp = NULLBUF;
register char *cp;
int len;
PPP_DEBUG_ROUTINES("pap_makereq()");
if ( pap_p->username == NULLCHAR
|| pap_p->password == NULLCHAR ) {
fsm_log( fsm_p, "NULL username or password" );
return NULLBUF;
}
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1, " making user id %s", pap_p->username);
#endif
/* Get buffer for authenticate request packet */
len = 2 + strlen(pap_p->username) + strlen(pap_p->password);
if ((req_bp = alloc_mbuf(len)) == NULLBUF)
return NULLBUF;
/* Load user id and password for authenticate packet */
cp = req_bp->data;
*cp++ = (char)strlen(pap_p->username);
if ( strlen(pap_p->username) > 0 )
cp = stpcpy(cp, pap_p->username);
*cp++ = (char)strlen(pap_p->password);
if ( strlen(pap_p->password) > 0 )
cp = stpcpy(cp, pap_p->password);
req_bp->cnt += len;
return(req_bp);
}
/****************************************************************************/
/* abandon PAP attempt; shutdown LCP layer */
static void
pap_shutdown(fsm_p)
struct fsm_s *fsm_p;
{
struct ppp_s *ppp_p = fsm_p->ppp_p;
PPP_DEBUG_ROUTINES("pap_shutdown()");
if (PPPtrace > 1)
fsm_log( fsm_p, "Failed; close PPP connection" );
ppp_p->phase = pppTERMINATE;
psignal(ppp_p, 0);
}
/* Configuration negotiation complete */
static void
pap_opening(fsm_p, flag)
struct fsm_s *fsm_p;
int flag;
{
register struct ppp_s *ppp_p = fsm_p->ppp_p;
fsm_log(fsm_p, "Open");
stop_timer(&(fsm_p->timer));
if ( !((fsm_p->flags &= ~flag) & (PPP_AP_LOCAL | PPP_AP_REMOTE)) ) {
fsm_p->state = fsmOPENED;
}
if ( !((ppp_p->flags &= ~flag) & (PPP_AP_LOCAL | PPP_AP_REMOTE)) ) {
ppp_p->phase = pppREADY;
psignal(ppp_p, 0);
}
}
/****************************************************************************/
/* Check request from remote host */
static int
pap_request(fsm_p, hdr, data)
struct fsm_s *fsm_p;
struct config_hdr *hdr;
struct mbuf *data;
{
struct pap_s *pap_p = fsm_p->pdv;
struct mbuf *reply_bp;
int result;
char *message;
int mess_length;
char *username = NULLCHAR;
int userlen;
char *password = NULLCHAR;
int passwordlen;
PPP_DEBUG_ROUTINES("pap_request()");
/* Extract userID/password sent by remote host */
if ( (userlen = pullchar(&data)) != -1 ) {
register int i;
register char *cp;
cp = username = mallocw(userlen+1);
for ( i = userlen; i-- > 0; ) {
*cp++ = PULLCHAR(&data);
}
*cp = '\0';
}
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1," checking user: %s", username);
#endif
if ( (passwordlen = pullchar(&data)) != -1 ) {
register int i;
register char *cp;
cp = password = mallocw(passwordlen+1);
for ( i = passwordlen; i-- > 0; ) {
*cp++ = PULLCHAR(&data);
}
*cp = '\0';
}
#ifdef PPP_DEBUG_OPTIONS
if (PPPtrace & PPP_DEBUG_OPTIONS)
log(-1," checking password: %s", password);
#endif
if (pap_verify(username,password) == 0) {
free( pap_p->peername );
pap_p->peername = strdup(username);
result = CONFIG_ACK;
message = " Welcome";
} else {
result = CONFIG_NAK;
message = " Invalid username or password";
}
/* the space at the beginning of the message is crucial */
mess_length = strlen(message);
reply_bp = qdata(message,mess_length);
reply_bp->data[0] = (char)(mess_length - 1);
fsm_send(fsm_p, result, hdr->id, reply_bp);
if (result == CONFIG_NAK) {
if ( fsm_p->retry_nak > 0 ) {
fsm_p->retry_nak--;
} else {
pap_shutdown(fsm_p);
}
}
free_p(data);
free(username);
free(password);
return (result != CONFIG_ACK);
}
/* Check acknowledgement from remote host */
static int
pap_check(fsm_p, hdr, data)
struct fsm_s *fsm_p;
struct config_hdr *hdr;
struct mbuf *data;
{
struct pap_s *pap_p = fsm_p->pdv;
char *message;
int mess_length;
int full_length;
int len;
PPP_DEBUG_ROUTINES("pap_check()");
/* ID field must match last request we sent */
if (hdr->id != fsm_p->lastid) {
PPP_DEBUG_CHECKS("PAP: wrong ID");
tprintf ("id mismatch hdrid=%d, lastid=%d\n",
hdr->id, fsm_p->lastid);
free_p(data);
return -1;
}
/* Log ASCII message from remote host, if any */
if ( (mess_length = pullchar(&data)) != -1 ) {
message = mallocw( mess_length+1 );
full_length = len_p(data);
len = dqdata(data, message, mess_length);
message[len] = '\0';
free( pap_p->message );
pap_p->message = message;
if (PPPtrace) {
log(-1,"%s: PPP/PAP %s %s: %s",
fsm_p->ppp_p->iface->name,
(len < mess_length) ? "Short"
: (mess_length < full_length) ? "Long"
: "Valid",
(hdr->code == CONFIG_ACK) ? "Ack" : "Nak",
message);
}
return (len < mess_length || mess_length < full_length);
}
free_p(data);
PPP_DEBUG_CHECKS( "PAP: missing message count" );
return -1;
}
/************************************************************************/
/* E V E N T P R O C E S S I N G */
/************************************************************************/
/* Process incoming packet */
void
pap_proc(fsm_p,bp)
struct fsm_s *fsm_p;
struct mbuf *bp;
{
struct pap_s *pap_p = fsm_p->pdv;
struct config_hdr hdr;
PPPtrace = fsm_p->ppp_p->trace;
ntohcnf(&hdr, &bp);
if (PPPtrace > 1)
log(-1, "%s: PPP/%s Recv,"
" option: %s, id: %d, len: %d",
fsm_p->ppp_p->iface->name,
fsm_p->pdc->name,
fsmCodes[hdr.code],
hdr.id, hdr.len);
hdr.len -= CONFIG_HDR_LEN; /* Length includes envelope */
trim_mbuf(&bp, hdr.len); /* Trim off padding */
switch(hdr.code) {
case CONFIG_REQ:
if ( pap_request(fsm_p, &hdr, bp) == 0) {
pap_opening(fsm_p, PPP_AP_LOCAL);
}
break;
case CONFIG_ACK:
if (pap_check(fsm_p, &hdr, bp) == 0) {
pap_opening(fsm_p, PPP_AP_REMOTE);
}
break;
case CONFIG_NAK:
if (pap_check(fsm_p, &hdr, bp) == 0) {
/* Must have sent a bad user or password */
/* Get the password again */
pap_getpassword(fsm_p, TRUE);
if (pap_p->username == NULLCHAR
|| pap_p->password == NULLCHAR) {
pap_shutdown(fsm_p);
} else {
fsm_sendreq(fsm_p);
}
}
break;
default:
if (PPPtrace)
log(-1, "%s: PPP/Pap: Unknown packet type: %d;"
" dropping packet",
fsm_p->ppp_p->iface->name,
hdr.code);
free_p(bp);
break;
}
}
/* Timeout while waiting for reply from remote host */
static void
pap_timeout(vp)
void *vp;
{
struct fsm_s *fsm_p = (struct fsm_s *)vp;
PPPtrace = fsm_p->ppp_p->trace;
fsm_log( fsm_p, "Timeout" );
if (fsm_p->retry > 0) {
fsm_sendreq(fsm_p);
} else {
fsm_log(fsm_p, "Request retry exceeded");
pap_shutdown(fsm_p);
}
}
/************************************************************************/
/* I N I T I A L I Z A T I O N */
/************************************************************************/
/* Reset state machine */
static void
pap_reset(fsm_p)
struct fsm_s *fsm_p;
{
PPP_DEBUG_ROUTINES("pap_reset()");
fsm_p->state = fsmCLOSED;
fsm_p->retry = fsm_p->try_req;
fsm_p->retry_nak = fsm_p->try_nak;
}
/* Initialize state machine for local */
int
pap_local(ppp_p)
struct ppp_s *ppp_p;
{
struct fsm_s *fsm_p = &(ppp_p->fsm[Pap]);
if (ppp_p->fsm[Pap].pdv == NULL)
pap_init(ppp_p);
PPPtrace = fsm_p->ppp_p->trace;
PPP_DEBUG_ROUTINES("pap_local()");
pap_reset(fsm_p);
fsm_p->state = fsmLISTEN;
fsm_p->flags |= PPP_AP_LOCAL;
return 0;
}
/* Initialize state machine for remote */
int
pap_remote(ppp_p)
struct ppp_s *ppp_p;
{
struct fsm_s *fsm_p = &(ppp_p->fsm[Pap]);
struct pap_s *pap_p = fsm_p->pdv;
if (ppp_p->fsm[Pap].pdv == NULL)
pap_init(ppp_p);
PPPtrace = fsm_p->ppp_p->trace;
PPP_DEBUG_ROUTINES("pap_remote()");
/* We need to send REQ to remote host */
/* Get the user and password we will send */
if ((pap_p->username == NULLCHAR)
|| (pap_p->password == NULLCHAR)) {
pap_getpassword(fsm_p, FALSE);
if ((pap_p->username == NULLCHAR)
|| (pap_p->password == NULLCHAR)) {
return -1;
}
}
pap_reset(fsm_p);
fsm_p->state = fsmREQ_Sent;
fsm_p->flags |= PPP_AP_REMOTE;
return(fsm_sendreq(fsm_p));
}
void
pap_down(fsm_p)
struct fsm_s *fsm_p;
{
if ( fsm_p->pdv == NULL )
return;
PPPtrace = fsm_p->ppp_p->trace;
fsm_log(fsm_p, "Down");
fsm_p->flags = FALSE;
switch ( fsm_p->state ) {
case fsmREQ_Sent:
stop_timer(&(fsm_p->timer));
/* fallthru */
case fsmOPENED:
case fsmLISTEN:
case fsmTERM_Sent:
fsm_p->state = fsmCLOSED;
break;
case fsmCLOSED:
/* Already closed; nothing to do */
break;
}
}
static void
pap_free(fsm_p)
struct fsm_s *fsm_p;
{
struct pap_s *pap_p = fsm_p->pdv;
free( pap_p->username );
free( pap_p->password );
free( pap_p->peername );
free( pap_p->message );
}
/* Initialize configuration structure */
static void
pap_init(ppp_p)
struct ppp_s *ppp_p;
{
struct fsm_s *fsm_p;
struct timer *t;
PPPtrace = ppp_p->trace;
PPP_DEBUG_ROUTINES("pap_init()");
if (ppp_p->fsm[Pap].pdv != NULL)
return; /* already initialized */
fsm_p = &(ppp_p->fsm[Pap]);
fsm_p->ppp_p = ppp_p;
fsm_p->pdc = &pap_constants;
fsm_p->pdv = callocw(1,sizeof(struct pap_s));
fsm_p->try_req = fsm_p->pdc->try_req;
fsm_p->try_nak = fsm_p->pdc->try_nak;
fsm_p->try_terminate = fsm_p->pdc->try_terminate;
pap_reset(fsm_p);
/* Initialize timer */
t = &(fsm_p->timer);
t->func = (void (*)())pap_timeout;
t->arg = (void *)fsm_p;
set_timer(t, fsm_p->pdc->timeout);
fsm_timer(fsm_p);
stop_timer(t);
}