This is ppp.c in view mode; [Download] [Up]
/*
* ppp.c - Point-to-Point Protocol.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* 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 Carnegie Mellon University. The name of the
* University 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.
*/
/*
* TODO:
* Don't prompt for passwd on /dev/tty (go into server mode).
* Might want to choose IP addresses from config file based on user id
* if the server, or based on remote host if tip'd client.
* Way to set asyncmap.
* Wait for tty queue to empty before exiting in quit.
*/
/*
* There are three scenarios:
* 1. ppp used as daemon started from /etc/rc or perhaps /etc/ttys.
* a. server
* b. authentication necessary
* c. want to use constant local ip addr
* d. want to use constant remote ip addr, constant ip addr based on
* authenticated user, or request ip addr
* 2. ppp used on /dev/tty after remote login.
* a. server
* b. no authentication necessary or allowed
* c. want to use constant local ip addr
* d. want to use constant remote ip addr, constant ip addr based on
* authenticated user, or request ip addr
* 3. ppp used on line after tip'ing out.
* a. client
* b. remote end may request authentication
* c. want to use constant local ip addr or request ip addr
* d. want to use constant remote ip addr based on tip'd host, or
* request remote ip addr
*/
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#ifndef STREAMS
#include <sgtty.h>
#endif
#include <pwd.h>
#include <syslog.h>
#include <netdb.h>
#include <utmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/callout.h>
#include <net/if.h>
#ifdef STREAMS
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/termios.h>
#include <sys/conf.h>
#endif
# define DEVNAME_SIZE 128 /* Buffer size for /dev/* filenames */
#ifdef sun
/*
* Get definition of SUNOS
*/
#include <pixrect/pr_impl_util.h>
#endif
#include "magic.h"
#include "ppp.h"
#include "fsm.h"
#include "lcp.h"
#include "ipcp.h"
#include "upap.h"
#include "patchlevel.h"
#ifdef __NeXT__
struct callout {
int c_time; /* incremental time */
void *c_arg; /* argument to routine */
func c_func; /* routine */
struct callout *c_next;
};
#endif
#define PPPHOSTS "/etc/hosts.ppp"
int dial = 0;
char dial_cmd[256];
int debug = 0; /* Debug flag */
int fsm_debug = 0; /* FSM debug flag */
int lcp_debug = 0; /* LCP debug flag */
int ipcp_debug = 0; /* IPCP debug flag */
int upap_debug = 0; /* UPAP debug flag */
char *progname; /* Name of this program */
char devname[DEVNAME_SIZE] = "/dev/tty"; /* Device name */
char ifname[IFNAMSIZ]; /* Interface name */
int ifunit; /* Interface unit number */
char inspeed = 0, outspeed = 0; /* Input/Output speed */
int fd; /* Device file descriptor */
int s; /* Socket file descriptor */
int initdisc; /* Initial TTY discipline */
#ifndef STREAMS
struct sgttyb initsgttyb; /* Initial TTY sgttyb */
#endif
int initfdflags; /* Initial file descriptor flags */
#ifdef __NeXT__
int pid; /* Our pid */
#else
pid_t pid; /* Our pid */
#endif
#ifdef sun
pid_t pgrpid; /* Process Group ID */
#endif
char user[80]; /* User name */
void hup(), intr(), term(), alrm(), io(), incdebug(), nodebug();
int setdebug(), setpassive(), noopt(), novj(), noupap(), requpap();
int setspeed(), noaccomp(), noasyncmap(), noipaddr(), nomagicnumber();
int setasyncmap(), setold(), setdial();
int setmru(), nomru(), nopcomp();
void getuserpasswd();
#ifdef STREAMS
extern char *ttyname();
#define MAXMODULES 10 /* max number of module names that we can save */
struct modlist {
char modname[FMNAMESZ+1];
} str_modules[MAXMODULES];
int str_module_count = 0;
#endif
/*
* Valid arguments.
*/
struct cmd {
char *cmd_name;
int (*cmd_func)();
} cmds[] = {
"-all", noopt, /* Don't request/allow any options */
"-ac", noaccomp, /* Disable Address/Control compress */
"-am", noasyncmap, /* Disable asyncmap negotiation */
"-as", setasyncmap, /* set the desired async map */
"-d", setdebug, /* Increase debugging level */
"debug", setdebug, /* Increase debugging level */
"-ip", noipaddr, /* Disable IP address negotiation */
"-mn", nomagicnumber, /* Disable magic number negotiation */
"-mru", nomru, /* Disable mru negotiation */
"mru", setmru, /* Set MRU value for negotiation */
"-p", setpassive, /* Set passive mode */
"-pc", nopcomp, /* Disable protocol field compress */
"passive", setpassive, /* Set passive mode */
"+ua", requpap, /* Require UPAP authentication */
"-ua", noupap, /* Don't allow UPAP authentication */
"-vj", novj, /* Disable VJ compression */
"dial", setdial, /* Use dial to dialup */
"old", setold, /* Backward compatibility mode */
#if 0
"local", setlocalipaddr,
"remote", setremoteipaddr,
"test", enabletestline,
#endif
NULL
};
/*
* PPP Data Link Layer "protocol" table.
* One entry per supported protocol.
*/
struct protent {
u_short protocol;
void (*init)();
void (*input)();
void (*protrej)();
} prottbl[] = {
{ LCP, lcp_init, lcp_input, lcp_protrej },
{ IPCP, ipcp_init, ipcp_input, ipcp_protrej },
{ UPAP, upap_init, upap_input, upap_protrej },
};
char *usage = "PPP patch level %d\n\
Usage: %s [ arguments ], where arguments are:\n\
-all Don't request/allow any options\n\
-ac Disable Address/Control compression\n\
-am Disable asyncmap negotiation\n\
-as <n> Set the desired async map to hex <n>\n\
-d Increase debugging level\n\
debug Increase debugging level\n\
-ip Disable IP address negotiation\n\
-mn Disable magic number negotiation\n\
-mru Disable mru negotiation\n\
mru <n> Set MRU value to <n> for negotiation\n\
-p Set passive mode\n\
-pc Disable protocol field compression\n\
passive Set passive mode\n\
+ua Require UPAP authentication\n\
-ua Don't allow UPAP authentication\n\
-vj Disable VJ compression\n\
old Backward compatibility mode for use with old PPP versions\n\
dial <cmd> Dial using cmd (stdin/out is the device)\n\
<device> Communicate over the named device\n\
<speed> Set the baud rate to <speed>\n\
<loc>:<rem> Set the local and/or remote interface IP\n\
addresses. Either one may be omitted.\n";
#ifdef STREAMS
str_restore(ecode)
int ecode; /* called by exit */
/*
this module will attempt to reconstruct the stream with the previously popped
modules
*/
{
while(ioctl(fd, I_POP, 0) == 0); /* pop any we pushed */
for(; str_module_count > 0; str_module_count--) {
if(ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
if(debug)
fprintf(stderr,
"str_restore: couldn't push module %s\n",
str_modules[str_module_count-1].modname);
}
else {
if(debug)
fprintf(stderr,
"str_restore: pushed module %s\n",
str_modules[str_module_count-1].modname);
}
}
}
#endif
main(argc, argv)
int argc;
char *argv[];
{
int mask, i;
#ifdef STREAMS
struct termios tios;
#else
int pppdisc = PPPDISC;
struct sgttyb sgttyb;
#endif
struct sigvec sv;
struct cmd *cmdp;
pid = getpid();
/*
* Initialize syslog system and magic number package.
*/
#if BSD >= 43
openlog("ppp", LOG_PID | LOG_NDELAY, LOG_DAEMON);
setlogmask(LOG_UPTO(LOG_WARNING));
#else
openlog("ppp", LOG_PID);
#define LOG_UPTO(x) (x)
#define setlogmask(x) (x)
#endif
#ifdef STREAMS
if (ttyname(fileno(stdin)))
strcpy(devname, ttyname(fileno(stdin)));
#endif
magic_init();
/*
* Initialize to the standard option set and then parse the command
* line arguments.
*/
for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
(*prottbl[i].init)(0);
progname = *argv;
for (argc--, argv++; argc; ) {
/*
* First see if it's a command.
*/
for (cmdp = cmds; cmdp->cmd_name; cmdp++)
if (!strcmp(*argv, cmdp->cmd_name) &&
(*cmdp->cmd_func)(&argc, &argv))
break;
/*
* Maybe a tty name, speed or IP address?
*/
if (cmdp->cmd_name == NULL &&
!setdevname(&argc, &argv) &&
!setspeed(&argc, &argv) &&
!setipaddr(&argc, &argv)) {
fprintf(stderr, usage, PATCHLEVEL, progname);
exit(1);
}
}
/*
* Initialize state.
*/
#if defined(sun) && defined(SUNOS) && SUNOS >= 41
if ((pgrpid = setsid()) < 0)
pgrpid = getpgrp(0);
#endif
#ifdef __NeXT__
if (strcmp(devname, "/dev/tty"))
{
int f;
if ((f = open ("/dev/tty", O_RDWR)) != -1) {
ioctl (f, TIOCNOTTY, (char *)0);
close (f);
}
}
#endif
if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
perror(devname);
exit(1);
}
#ifdef __NeXT__
if (ioctl (fd, TIOCSPGRP, &pid) == -1)
{
perror("TIOCSPGRP");
_exit(1);
}
dup2(fd, 0);
dup2(fd, 1);
setpgrp (0, pid);
#endif
if (dial)
{
char cmd[1024];
sprintf(cmd, "%s %d", dial_cmd, getpid());
if (system(cmd))
{
fprintf(stderr, "dial command '%s' failed\n", cmd);
exit(1);
}
}
#if defined(sun) && defined(SUNOS) && SUNOS >= 41
if (getpid() != pgrpid && tcsetpgrp(fd, pgrpid) < 0) {
perror("ppp: tcsetpgrp()");
exit(1);
}
#endif
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("ppp: socket");
exit(1);
}
#ifdef STREAMS
while(1) { /* go through and save the name of all the modules, then pop em */
if(!ioctl(fd, I_LOOK, str_modules[str_module_count].modname))
if(debug)
fprintf(stderr,
"popped stream module : %s\n",
str_modules[str_module_count].modname);
if(!ioctl(fd, I_POP, 0))
str_module_count++;
else
break;
}
on_exit(str_restore,NULL); /* if we exit, then try and restore the stream */
if(ioctl(fd, TCGETS, (caddr_t) &tios) < 0) {
perror("ppp: ioctl(TCGETS)");
exit(1);
}
tios.c_cflag = CRTSCTS | (inspeed ? inspeed : (tios.c_cflag & CBAUD));
tios.c_cflag |= CS8|CREAD|HUPCL;
tios.c_iflag = IGNBRK;
if(ioctl(fd, TCSETS, (caddr_t) &tios) < 0) {
perror("ppp: ioctl(TCSETS)");
exit(1);
}
/* now push the async/fcs module */
if(ioctl(fd, I_PUSH, "pppasync") < 0) {
perror("ppp: ioctl(I_PUSH, ppp_async)");
exit(1);
}
/* finally, push the ppp_if module that actually handles the network interface */
if(ioctl(fd, I_PUSH, "pppif") < 0) {
perror("ppp: ioctl(I_PUSH, ppp_if)");
exit(1);
}
if(ioctl(fd, I_SETSIG, S_INPUT) < 0) {
perror("ppp: ioctl(I_SETSIG, S_INPUT)");
exit(1);
}
/* read mode, message non-discard mode */
if(ioctl(fd, I_SRDOPT, RMSGN) < 0) {
perror("ppp: ioctl(I_SRDOPT, RMSGN)");
exit(1);
}
/* Flush any waiting messages, or we'll never get SIGPOLL */
if(ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
perror("ppp: ioctl(I_FLUSH, FLUSHRW)");
exit(1);
}
#else
/*
* Put the tty in raw mode and set the discipline to PPP.
*/
if (ioctl(fd, TIOCGETP, &initsgttyb) < 0) {
perror("ppp: ioctl(TIOCGETP)");
exit(1);
}
sgttyb = initsgttyb;
sgttyb.sg_flags = RAW | ANYP;
if (inspeed)
sgttyb.sg_ispeed = inspeed;
if (outspeed)
sgttyb.sg_ospeed = outspeed;
if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
perror("ppp: ioctl(TIOCSETP)");
exit(1);
}
if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
perror("ppp: ioctl(TIOCGETD)");
exit(1);
}
if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
perror("ppp: ioctl(TIOCSETD)");
exit(1);
}
#endif
/*
* Find out which interface we were given.
*/
#ifdef STREAMS
if (ioctl(fd, SIOCGETU, &ifunit) < 0) { /* in streams, ppp_if handles this ioctl */
perror("ppp: ioctl(SIOCGETU)");
exit(1);
}
#else
if (ioctl(fd, TIOCGETD, &ifunit) < 0) {
perror("ppp: ioctl(TIOCGETD)");
exit(1);
}
#endif
sprintf(ifname, "ppp%d", ifunit);
if (debug)
fprintf(stderr, "Interface %s.\n", ifname);
if (debug)
fprintf(stderr, "Pid %d.\n", pid);
# if !defined(sun) || !defined(SUNOS) || SUNOS < 41
if (ioctl(fd, TIOCSPGRP, &pid) < 0) {
perror("ppp: ioctl(TIOCSPGRP)");
exit(1);
}
# endif
/*
* Compute mask of all interesting signals and install signal handlers
* for each. Only one signal handler may be active at a time. Therefore,
* all other signals should be masked when any handler is executing.
*/
mask = sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGALRM) |
sigmask(SIGIO);
#ifdef STREAMS
mask |= sigmask(SIGPOLL);
#endif
sv.sv_handler = hup; /* Hangup */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGHUP, &sv, NULL)) {
perror("ppp: sigvec(SIGHUP)");
exit(1);
}
sv.sv_handler = intr; /* Interrupt */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGINT, &sv, NULL)) {
perror("ppp: sigvec(SIGINT)");
exit(1);
}
sv.sv_handler = term; /* Terminate */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGTERM, &sv, NULL)) {
perror("ppp: sigvec(SIGTERM)");
exit(1);
}
sv.sv_handler = alrm; /* Timeout */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGALRM, &sv, NULL)) {
perror("ppp: sigvec(SIGALRM)");
exit(1);
}
sv.sv_handler = io; /* Input available */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGIO, &sv, NULL)) {
perror("ppp: sigvec(SIGIO)");
exit(1);
}
#ifdef STREAMS
sv.sv_handler = io; /* Input available */
sv.sv_mask = mask;
sv.sv_flags = 0;
if (sigvec(SIGPOLL, &sv, NULL)) {
perror("ppp: sigvec(SIGPOLL)");
exit(1);
}
#endif
(void) signal(SIGUSR1, incdebug); /* Increment debug flag */
(void) signal(SIGUSR2, nodebug); /* Reset debug flag */
/*
* Record initial device flags, then set device to cause SIGIO
* signals to be generated.
*/
if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
perror("ppp: fcnt(F_GETFL)");
exit(1);
}
if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
perror("ppp: fcnt(F_SETFL, FNDELAY | FASYNC)");
exit(1);
}
/*
* Block all signals, start opening the connection, and wait for
* incoming signals (reply, timeout, etc.).
*/
syslog (LOG_DEBUG, "connect: %s %s", ifname, devname);
sigblock(mask); /* Block signals now */
lcp_lowerup(0); /* XXX Well, sort of... */
if (lcp_wantoptions[0].passive)
lcp_passiveopen(0); /* Start protocol in passive mode */
else
lcp_activeopen(0); /* Start protocol in active mode */
for (;;) {
sigpause(0); /* Wait for next signal */
/* Need to read user/passwd? */
if (upap[0].us_flags & UPAPF_UPPENDING) {
sigsetmask(0); /* Allow other signals to occur */
getuserpasswd(); /* Get user and passwd */
upap[0].us_flags &= ~UPAPF_UPPENDING;
upap[0].us_flags |= UPAPF_UPVALID;
sigsetmask(mask); /* Diallow signals */
upap_authwithpeer(0);
}
}
}
/*
* quit - Clean up state and exit.
*/
void quit()
{
if (fcntl(fd, F_SETFL, initfdflags) == -1) {
perror("ppp: fcnt(F_SETFL, fdflags)");
exit(1);
}
#ifndef STREAMS
if (ioctl(fd, TIOCSETP, &initsgttyb) < 0) {
perror("ppp: ioctl(TIOCSETP)");
exit(1);
}
if (ioctl(fd, TIOCSETD, &initdisc) < 0) {
perror("ppp: ioctl(TIOCSETD)");
exit(1);
}
#else
if(ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
perror("ppp: quit ioctl(I_FLUSH,FLUSHRW)");
}
str_restore(-1);
#endif
close(fd);
if (dial)
{
char lockfile[256];
strcpy(lockfile, LCK_DIR);
strcat(lockfile, "/LCK..");
if (rindex(devname, '/'))
strcat(lockfile, rindex(devname , '/') + 1);
else
strcat(lockfile, devname);
fprintf(stderr,"Unlinking %s\n", lockfile);
unlink(lockfile);
}
exit(0);
}
struct callout *callout = NULL; /* Callout list */
struct timeval schedtime; /* Time last timeout was set */
/*
* timeout - Schedule a timeout.
*
* Note that this timeout takes the number of seconds, NOT hz (as in
* the kernel).
*/
void timeout(func1, arg, time)
int (*func1)();
caddr_t arg;
int time;
{
struct itimerval itv;
struct callout *newp, **oldpp;
if (debug > 2)
fprintf(stderr, "Timeout %x:%x in %d seconds.\n",
(int) func1, (int) arg, time);
/*
* Allocate timeout.
*/
if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
fprintf(stderr, "ppp: Out of memory!\n");
exit(1);
}
newp->c_arg = arg;
newp->c_func = func1;
/*
* Find correct place to link it in and decrement its time by the
* amount of time used by preceding timeouts.
*/
for (oldpp = &callout;
*oldpp && (*oldpp)->c_time <= time;
oldpp = &(*oldpp)->c_next)
time -= (*oldpp)->c_time;
newp->c_time = time;
newp->c_next = *oldpp;
if (*oldpp)
(*oldpp)->c_time -= time;
*oldpp = newp;
/*
* If this is now the first callout then we have to set a new
* itimer.
*/
if (callout == newp) {
itv.it_interval.tv_sec = itv.it_interval.tv_usec =
itv.it_value.tv_usec = 0;
itv.it_value.tv_sec = callout->c_time;
if (debug > 2)
fprintf(stderr, "Setting itimer for %d seconds.\n",
itv.it_value.tv_sec);
if (setitimer(ITIMER_REAL, &itv, NULL)) {
perror("ppp: setitimer(ITIMER_REAL)");
exit(1);
}
if (gettimeofday(&schedtime, NULL)) {
perror("ppp: gettimeofday");
exit(1);
}
}
}
/*
* untimeout - Unschedule a timeout.
*/
void untimeout(func1, arg)
int (*func1)();
caddr_t arg;
{
struct itimerval itv;
struct callout **copp, *freep;
int reschedule = 0;
if (debug > 2)
fprintf(stderr, "Untimeout %x:%x.\n", (int) func1, (int) arg);
/*
* If the first callout is unscheduled then we have to set a new
* itimer.
*/
if (callout &&
callout->c_func == func1 &&
callout->c_arg == arg)
reschedule = 1;
/*
* Find first matching timeout. Add its time to the next timeouts
* time.
*/
for (copp = &callout; *copp; copp = &(*copp)->c_next)
if ((*copp)->c_func == func1 &&
(*copp)->c_arg == arg) {
freep = *copp;
*copp = freep->c_next;
if (*copp)
(*copp)->c_time += freep->c_time;
free(freep);
break;
}
if (reschedule) {
itv.it_interval.tv_sec = itv.it_interval.tv_usec =
itv.it_value.tv_usec = 0;
itv.it_value.tv_sec = callout ? callout->c_time : 0;
if (debug > 2)
fprintf(stderr, "Setting itimer for %d seconds.\n",
itv.it_value.tv_sec);
if (setitimer(ITIMER_REAL, &itv, NULL)) {
perror("ppp: setitimer(ITIMER_REAL)");
exit(1);
}
if (gettimeofday(&schedtime, NULL)) {
perror("ppp: gettimeofday");
exit(1);
}
}
}
/*
* adjtimeout - Decrement the first timeout by the amount of time since
* it was scheduled.
*/
void adjtimeout()
{
struct timeval tv;
int timediff;
if (callout == NULL)
return;
/*
* Make sure that the clock hasn't been warped dramatically.
* Account for recently expired, but blocked timer by adding
* small fudge factor.
*/
if (gettimeofday(&tv, NULL)) {
perror("ppp: gettimeofday");
exit(1);
}
timediff = tv.tv_sec - schedtime.tv_sec;
if (timediff < 0 ||
timediff > callout->c_time + 1)
return;
callout->c_time -= timediff; /* OK, Adjust time */
}
/*
* output - Output PPP packet.
*/
void output(unit, p, len)
int unit;
u_char *p;
int len;
{
#ifdef STREAMS
struct strbuf str;
#endif
if (unit != 0) {
fprintf(stderr, "ppp: output: unit != 0!\n");
abort();
}
#ifdef STREAMS
str.len = len;
str.buf = (caddr_t) p;
if(putmsg(fd, NULL, &str, 0) < 0) {
perror("ppp: putmsg");
exit(1);
}
#else
if (write(fd, p, len) < 0) {
perror("ppp: write");
exit(1);
}
#endif
free(p);
}
/*
* hup - Catch SIGHUP signal.
*
* Indicates that the physical layer has been disconnected.
*/
void hup()
{
if (debug > 1)
fprintf(stderr, "Hangup\n");
adjtimeout(); /* Adjust timeouts */
lcp_lowerdown(0); /* Reset connection */
}
/*
* term - Catch SIGTERM signal.
*
* Indicates that we should initiate a graceful disconnect and exit.
*/
void term()
{
if (debug > 1)
fprintf(stderr, "Terminate\n");
adjtimeout(); /* Adjust timeouts */
lcp_close(0); /* Close connection */
}
/*
* intr - Catch SIGINT signal (DEL/^C).
*
* Indicates that we should initiate a graceful disconnect and exit.
*/
void intr()
{
if (debug > 1)
fprintf(stderr, "Interrupt\n");
adjtimeout(); /* Adjust timeouts */
lcp_close(0); /* Close connection */
}
/*
* alrm - Catch SIGALRM signal.
*
* Indicates a timeout.
*/
void alrm()
{
struct itimerval itv;
struct callout *freep;
if (debug > 1)
fprintf(stderr, "Alarm\n");
/*
* Call and free first scheduled timeout and any that were scheduled
* for the same time.
*/
while (callout) {
freep = callout; /* Remove entry before calling */
callout = freep->c_next;
(*freep->c_func)(freep->c_arg);
free(freep);
if (callout->c_time)
break;
}
/*
* Set a new itimer if there are more timeouts scheduled.
*/
if (callout) {
itv.it_interval.tv_sec = itv.it_interval.tv_usec =
itv.it_value.tv_usec = 0;
itv.it_value.tv_sec = callout->c_time;
if (debug > 2)
fprintf(stderr, "Setting itimer for %d seconds.\n",
itv.it_value.tv_sec);
if (setitimer(ITIMER_REAL, &itv, NULL)) {
perror("ppp: setitimer(ITIMER_REAL)");
exit(1);
}
if (gettimeofday(&schedtime, NULL)) {
perror("ppp: gettimeofday");
exit(1);
}
}
}
/*
* io - Catch SIGIO signal.
*
* Indicates that incoming data is available.
*/
void io()
{
int len, i;
u_char *p;
u_short protocol;
#ifdef STREAMS
struct strbuf str;
#endif
if (debug > 1)
fprintf(stderr, "IO\n");
adjtimeout(); /* Adjust timeouts */
for (;;) { /* Read all available packets */
p = (u_char *) malloc(MTU + DLLHEADERLEN);
#ifdef STREAMS
str.maxlen = MTU+DLLHEADERLEN;
str.buf = (caddr_t) p;
i = 0;
len = getmsg(fd, NULL, &str, &i);
if(len < 0) {
if(errno == EAGAIN || errno == EWOULDBLOCK) {
if(debug > 2)
perror("ppp: getmsg(fd)");
return;
}
perror("ppp: getmsg(fd)");
exit(1);
}
else if(len && debug > 2)
fprintf(stderr, "ppp: getmsg returns 0x%x\n",len);
if(str.len < 0) {
if(debug > 2)
fprintf(stderr, "ppp: getmsg short return length %d\n",
str.len);
return;
}
len = str.len;
#else
if ((len = read(fd, p, MTU + DLLHEADERLEN)) < 0) {
if (errno == EWOULDBLOCK) {
if (debug > 2)
perror("ppp: read(fd)");
return;
}
else {
perror("ppp: read(fd)");
exit(1);
}
}
else
#endif
if (len == 0) {
fprintf(stderr, "ppp: End of file on fd!\n");
exit(1);
}
if (len < DLLHEADERLEN) {
if (debug)
fprintf(stderr, "ppp: input: Received short packet.\n");
return;
}
p += 2; /* Skip address and control */
GETSHORT(protocol, p);
len -= DLLHEADERLEN;
/*
* Toss all non-LCP packets unless LCP is OPEN.
*/
if (protocol != LCP &&
lcp_fsm[0].state != OPEN) {
free(p - DLLHEADERLEN);
return;
}
/*
* Upcall the proper protocol input routine.
*/
for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
if (prottbl[i].protocol == protocol) {
(*prottbl[i].input)(0, p, len);
break;
}
if (i == sizeof (prottbl) / sizeof (struct protent)) {
if (debug)
fprintf(stderr,
"ppp: input: Unknown protocol (%x) received!\n",
protocol);
p -= DLLHEADERLEN;
len += DLLHEADERLEN;
lcp_sprotrej(0, p, len);
}
}
}
/*
* demuxprotrej - Demultiplex a Protocol-Reject.
*/
void demuxprotrej(unit, protocol)
int unit;
u_short protocol;
{
int i;
/*
* Upcall the proper Protocol-Reject routine.
*/
for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
if (prottbl[i].protocol == protocol) {
(*prottbl[i].protrej)(unit);
return;
}
if (debug)
fprintf(stderr,
"ppp: demuxprotrej: Unrecognized Protocol-Reject!\n");
}
/*
* incdebug - Catch SIGUSR1 signal.
*
* Increment debug flag.
*/
void incdebug()
{
debug++;
}
/*
* nodebug - Catch SIGUSR2 signal.
*
* Turn off debugging.
*/
void nodebug()
{
debug = 0;
}
/*
* setdebug - Set debug (command line argument).
*/
int setdebug(argcp, argvp)
int *argcp;
char ***argvp;
{
debug++;
fsm_debug++;
lcp_debug++;
ipcp_debug++;
upap_debug++;
--*argcp, ++*argvp;
return (1);
}
/*
* setdial - Set dial (command line argument).
*/
int setdial(argcp, argvp)
int *argcp;
char ***argvp;
{
dial++;
--*argcp, ++*argvp;
strncpy(dial_cmd, **argvp, 256);
--*argcp, ++*argvp;
return (1);
}
/*
* noopt - Disable all options.
*/
int noopt(argcp, argvp)
int *argcp;
char ***argvp;
{
bzero(&lcp_wantoptions[0], sizeof (struct lcp_options));
bzero(&lcp_allowoptions[0], sizeof (struct lcp_options));
bzero(&ipcp_wantoptions[0], sizeof (struct ipcp_options));
bzero(&ipcp_allowoptions[0], sizeof (struct ipcp_options));
--*argcp, ++*argvp;
return (1);
}
/*
* noaccomp - Disable Address/Control field compression negotiation.
*/
int noaccomp(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_accompression = 0;
lcp_allowoptions[0].neg_accompression = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* noasyncmap - Disable async map negotiation.
*/
int noasyncmap(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_asyncmap = 0;
lcp_allowoptions[0].neg_asyncmap = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* noipaddr - Disable IP address negotiation.
*/
int noipaddr(argcp, argvp)
int *argcp;
char ***argvp;
{
ipcp_wantoptions[0].neg_addrs = 0;
ipcp_allowoptions[0].neg_addrs = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* nomagicnumber - Disable magic number negotiation.
*/
int nomagicnumber(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_magicnumber = 0;
lcp_allowoptions[0].neg_magicnumber = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* nomru - Disable mru negotiation.
*/
int nomru(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_mru = 0;
lcp_allowoptions[0].neg_mru = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* setmru - Set MRU for negotiation.
*/
int setmru(argcp, argvp)
int *argcp;
char ***argvp;
{
--*argcp, ++*argvp;
lcp_wantoptions[0].mru = atoi(**argvp);
--*argcp, ++*argvp;
return (1);
}
/*
* nopcomp - Disable Protocol field compression negotiation.
*/
int nopcomp(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_pcompression = 0;
lcp_allowoptions[0].neg_pcompression = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* setpassive - Set passive mode.
*/
int setpassive(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].passive = 1;
--*argcp, ++*argvp;
return (1);
}
/*
* noupap - Disable UPAP authentication.
*/
int noupap(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_allowoptions[0].neg_upap = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* requpap - Require UPAP authentication.
*/
int requpap(argcp, argvp)
int *argcp;
char ***argvp;
{
lcp_wantoptions[0].neg_upap = 1;
lcp_allowoptions[0].neg_upap = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* novj - Disable Van Jacobson style IP header compression.
*/
int novj(argcp, argvp)
int *argcp;
char ***argvp;
{
ipcp_wantoptions[0].neg_vj = 0;
ipcp_allowoptions[0].neg_vj = 0;
--*argcp, ++*argvp;
return (1);
}
/*
* setold - Set backward compatibility mode
*/
int setold(argcp, argvp)
int *argcp;
char ***argvp;
{
extern short ip_vj_comp;
ip_vj_comp = 0x0037;
--*argcp, ++*argvp;
return (1);
}
/*
* Valid speeds.
*/
struct speed {
int speed_int, speed_val;
} speeds[] = {
#ifdef B50
{ 50, B50 },
#endif
#ifdef B75
{ 75, B75 },
#endif
#ifdef B110
{ 110, B110 },
#endif
#ifdef B150
{ 150, B150 },
#endif
#ifdef B200
{ 200, B200 },
#endif
#ifdef B300
{ 300, B300 },
#endif
#ifdef B600
{ 600, B600 },
#endif
#ifdef B1200
{ 1200, B1200 },
#endif
#ifdef B1800
{ 1800, B1800 },
#endif
#ifdef B2000
{ 2000, B2000 },
#endif
#ifdef B2400
{ 2400, B2400 },
#endif
#ifdef B3600
{ 3600, B3600 },
#endif
#ifdef B4800
{ 4800, B4800 },
#endif
#ifdef B7200
{ 7200, B7200 },
#endif
#ifdef B9600
{ 9600, B9600 },
#endif
#ifdef EXTA
{ 19200, EXTA },
#endif
#ifdef EXTB
{ 38400, EXTB },
#endif
{ 0, 0 }
};
int
setasyncmap(argcp, argvp)
int *argcp;
char ***argvp;
{
unsigned long asyncmap;
asyncmap = 0xffffffff;
++*argvp;
sscanf(**argvp,"%lx",&asyncmap);
++*argvp;
lcp_wantoptions[0].asyncmap = asyncmap;
*argcp -= 2;
return(1);
}
/*
* setspeed - Set the speed.
*/
int setspeed(argcp, argvp)
int *argcp;
char ***argvp;
{
int speed;
struct speed *speedp;
speed = atoi(**argvp);
for (speedp = speeds; speedp->speed_int; speedp++)
if (speed == speedp->speed_int) {
inspeed = speedp->speed_val;
--*argcp, ++*argvp;
return (1);
}
return (0);
}
/*
* setdevname - Set the device name.
*/
int setdevname(argcp, argvp)
int *argcp;
char ***argvp;
{
char dev[DEVNAME_SIZE];
char *cp = **argvp;
struct stat statbuf;
char *tty, *ttyname();
if (strncmp("/dev/", cp, sizeof ("/dev/") - 1)) {
(void) sprintf(dev, "/dev/%s", cp);
cp = dev;
}
/*
* Check if there is a device by this name.
*/
if (stat(cp, &statbuf) < 0) {
if (errno == ENOENT)
return (0);
perror(cp);
exit(1);
}
strcpy(devname, cp);
--*argcp, ++*argvp;
/*
* If we haven't already decided to require authentication,
* or we are running ppp on the control terminal, then we can
* allow authentication to be requested.
*/
if ((tty = ttyname(fileno(stdin))) == NULL)
tty = ""; /* running from init means no stdin. Null kills strcmp -KWK */
if (lcp_wantoptions[0].neg_upap == 0 &&
strcmp(devname, "/dev/tty") &&
strcmp(devname, tty)) {
lcp_wantoptions[0].neg_upap = 0;
lcp_allowoptions[0].neg_upap = 1;
}
return (1);
}
/*
* setipaddr - Set the IP address
*/
int setipaddr(argcp, argvp)
int *argcp;
char ***argvp;
{
u_long local, remote;
struct hostent *hp;
char *colon, *index();
/*
* IP address pair separated by ":".
*/
if ((colon = index(**argvp, ':')) == NULL)
return (0);
/*
* If colon first character, then no local addr.
*/
if (colon == **argvp) {
local = 0l;
++colon;
}
else {
*colon++ = '\0';
if ((local = inet_addr(**argvp)) == -1) {
if ((hp = gethostbyname(**argvp)) == NULL) {
fprintf(stderr, "unknown host: %s\n", **argvp);
goto ret;
}
bcopy(hp->h_addr, (char *) &local, hp->h_length);
}
}
/*
* If colon last character, then no remote addr.
*/
if (*colon == '\0')
remote = 0l;
else {
if ((remote = inet_addr(colon)) == -1) {
if ((hp = gethostbyname(colon)) == NULL) {
fprintf(stderr, "unknown host: %s\n", colon);
goto ret;
}
bcopy(hp->h_addr, (char *) &remote, hp->h_length);
}
}
ipcp_wantoptions[0].neg_addrs = 1;
ipcp_wantoptions[0].ouraddr = local;
ipcp_wantoptions[0].hisaddr = remote;
ret:
--*argcp, ++*argvp;
return (1);
}
/*
* getuserpasswd - Get the user name and passwd.
*/
void getuserpasswd()
{
struct passwd *pw, *getpwuid();
char *getlogin(), *getpass();
/*
* Prompt for user name with a default value. Default is
* the last value if any, or the login name or the user name.
*/
if (upap[0].us_user == NULL &&
(upap[0].us_user = getlogin()) == NULL &&
(pw = getpwuid(getuid())) != NULL)
upap[0].us_user = pw->pw_name;
printf("Login (%s): ", upap[0].us_user);
fgets(user, sizeof (user) - 1, stdin);
user[strlen(user) - 1] = '\0';
if (user[0] != '\0') /* Choosing the default? */
upap[0].us_user = user;
upap[0].us_userlen = strlen(upap[0].us_user);
upap[0].us_passwd = getpass("Password: ");
upap[0].us_passwdlen = strlen(upap[0].us_passwd);
}
/*
* login - Check the user name and passwd and login the user.
*
* returns:
* UPAP_AUTHNAK: Login failed.
* UPAP_AUTHACK: Login succeeded.
* In either case, msg points to an appropriate message.
*/
u_char login(user, userlen, passwd, passwdlen, msg, msglen)
char *user;
int userlen;
char *passwd;
int passwdlen;
char **msg;
int *msglen;
{
struct passwd *pw;
char *epasswd, *crypt();
static int attempts = 0;
char *tty, *rindex();
*(user + userlen) = '\0';
*(passwd + passwdlen) = '\0';
if ((pw = getpwnam(user)) == NULL) {
*msg = "Login incorrect";
*msglen = strlen(*msg);
if(debug > 2)
fprintf(stderr,"ppp: upap login userid '%s' incorrect\n",user);
return (UPAP_AUTHNAK);
}
/*
* XXX If no passwd, let them login without one.
*/
if (pw->pw_passwd == '\0') {
*msg = "Login ok";
*msglen = strlen(*msg);
return (UPAP_AUTHACK);
}
epasswd = crypt(passwd, pw->pw_passwd);
if (strcmp(epasswd, pw->pw_passwd)) {
*msg = "Login incorrect";
*msglen = strlen(*msg);
if(debug > 2)
fprintf(stderr, "ppp: upap login password '%s' incorrect\n",
passwd);
/*
* Frustrate passwd stealer programs.
* Allow 10 tries, but start backing off after 3 (stolen from login).
* On 10'th, drop the connection.
*/
if (attempts++ >= 10) {
syslog(LOG_NOTICE, "%d LOGIN FAILURES ON %s, %s",
attempts, devname, user);
lcp_close(0); /* Drop DTR? */
}
if (attempts > 3)
sleep((u_int) (attempts - 3) * 5);
return (UPAP_AUTHNAK);
}
attempts = 0; /* Reset count */
*msg = "Login ok";
*msglen = strlen(*msg);
if(debug > 2)
fprintf(stderr,"ppp: upap login and password OK\n");
tty = rindex(devname, '/');
if (tty == NULL)
tty = devname;
else
tty++;
logwtmp(tty, user, ""); /* Add wtmp login entry */
return (UPAP_AUTHACK);
}
/*
* logout - Logout the user.
*/
void logout()
{
char *tty;
tty = rindex(devname, '/');
if (tty == NULL)
tty = devname;
else
tty++;
logwtmp(tty, "", ""); /* Add wtmp logout entry */
}
/*
* getuseropt - Get the options from /etc/hosts.ppp for this user.
*/
int getuseropt(user)
char *user;
{
char buf[1024], *s;
FILE *fp;
int rc = 0;
if ((fp = fopen(PPPHOSTS, "r")) == NULL)
return (0);;
/*
* Loop till we find an entry for this user.
*/
for (;;) {
if (fgets(buf, sizeof (buf), fp) == NULL) {
if (feof(fp))
break;
else {
perror("fgets");
exit(1);
}
}
if ((s = index(buf, ' ')) == NULL)
continue;
*s++ = '\0';
if (!strcmp(user, buf)) {
rc = 1;
break;
}
}
fclose(fp);
return (rc);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.