2300 lines
49 KiB
C
2300 lines
49 KiB
C
/*
|
|
* main.c - Point-to-Point Protocol main module
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/*
|
|
* There are three scenarios:
|
|
* 1. pppd 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. pppd 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. pppd 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 <stdio.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <syslog.h>
|
|
#include <netdb.h>
|
|
#include <utmp.h>
|
|
|
|
#ifdef sparc
|
|
#include <alloca.h>
|
|
#endif
|
|
|
|
#ifdef STREAMS
|
|
#include <sys/stream.h>
|
|
#include <sys/stropts.h>
|
|
#include <sys/termios.h>
|
|
#else
|
|
#ifdef SGTTY
|
|
#include <sgtty.h>
|
|
#else
|
|
#include <sys/ioctl.h>
|
|
#include <termios.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "callout.h"
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_ppp.h>
|
|
|
|
#ifdef STREAMS
|
|
#include "ppp_str.h"
|
|
#endif
|
|
|
|
# define DEVNAME_SIZE 128 /* Buffer size for /dev filenames */
|
|
|
|
#include <string.h>
|
|
|
|
#ifndef BSD
|
|
#define BSD 43
|
|
#endif /*BSD*/
|
|
|
|
#include "ppp.h"
|
|
#include "magic.h"
|
|
#include "fsm.h"
|
|
#include "lcp.h"
|
|
#include "ipcp.h"
|
|
#include "upap.h"
|
|
#include "chap.h"
|
|
|
|
#include "pppd.h"
|
|
#include "pathnames.h"
|
|
#include "patchlevel.h"
|
|
|
|
|
|
#ifndef TRUE
|
|
#define TRUE (1)
|
|
#endif /*TRUE*/
|
|
|
|
#ifndef FALSE
|
|
#define FALSE (0)
|
|
#endif /*FALSE*/
|
|
|
|
#ifdef PIDPATH
|
|
static char *pidpath = PIDPATH; /* filename in which pid will be */
|
|
/* stored */
|
|
#else
|
|
static char *pidpath = _PATH_PIDFILE;
|
|
#endif /* PIDFILE */
|
|
|
|
static char uinfopath[DEVNAME_SIZE];
|
|
|
|
/* interface vars */
|
|
|
|
char ifname[IFNAMSIZ]; /* Interface name */
|
|
int ifunit; /* Interface unit number */
|
|
|
|
char *progname; /* Name of this program */
|
|
char hostname[MAX_HOSTNAME_LEN]; /* hostname */
|
|
u_char hostname_len; /* hostname length */
|
|
|
|
static pid_t pid; /* Our pid */
|
|
static pid_t pgrpid; /* Process Group ID */
|
|
static char pidfilename[DEVNAME_SIZE];
|
|
|
|
static char devname[DEVNAME_SIZE] = "/dev/tty"; /* Device name */
|
|
static int default_device = TRUE; /* use default device (stdin/out) */
|
|
int fd; /* Device file descriptor */
|
|
int s; /* Socket file descriptor */
|
|
static int initdisc; /* Initial TTY discipline */
|
|
#ifndef STREAMS
|
|
#ifdef SGTTY
|
|
static struct sgttyb initsgttyb; /* Initial TTY sgttyb */
|
|
#else
|
|
static struct termios inittermios; /* Initial TTY TIOCGETA */
|
|
#endif
|
|
#endif
|
|
|
|
static int initfdflags; /* Initial file descriptor flags */
|
|
|
|
u_char outpacket_buf[MTU+DLLHEADERLEN]; /* buffer for outgoing packet */
|
|
static u_char inpacket_buf[MTU+DLLHEADERLEN]; /* buffer for incoming packet */
|
|
|
|
/* configured variables */
|
|
|
|
int debug = 0; /* Debug flag */
|
|
static char user[80]; /* User name */
|
|
static char passwd[80]; /* password */
|
|
static char *connector = NULL; /* "connect" command */
|
|
static int inspeed = 0; /* Input/Output speed */
|
|
static u_long netmask = 0; /* netmask to use on ppp interface */
|
|
static int crtscts = 0; /* use h/w flow control */
|
|
static int nodetach = 0; /* don't fork */
|
|
|
|
/* prototypes */
|
|
static void hup __ARGS((int, int, struct sigcontext *, char *));
|
|
static void intr __ARGS((int, int, struct sigcontext *, char *));
|
|
static void term __ARGS((int, int, struct sigcontext *, char *));
|
|
static void alrm __ARGS((int, int, struct sigcontext *, char *));
|
|
static void io __ARGS((int, int, struct sigcontext *, char *));
|
|
static void incdebug __ARGS((int, int, struct sigcontext *, char *));
|
|
static void nodebug __ARGS((int, int, struct sigcontext *, char *));
|
|
static void getuserpasswd __ARGS((void));
|
|
|
|
static int setdebug __ARGS((int *, char ***));
|
|
static int setpassive __ARGS((int *, char ***));
|
|
static int noopt __ARGS((int *, char ***));
|
|
static int setnovj __ARGS((int *, char ***));
|
|
static int noupap __ARGS((int *, char ***));
|
|
static int requpap __ARGS((int *, char ***));
|
|
static int nochap __ARGS((int *, char ***));
|
|
static int reqchap __ARGS((int *, char ***));
|
|
static int setspeed __ARGS((int *, char ***));
|
|
static int noaccomp __ARGS((int *, char ***));
|
|
static int noasyncmap __ARGS((int *, char ***));
|
|
static int noipaddr __ARGS((int *, char ***));
|
|
static int nomagicnumber __ARGS((int *, char ***));
|
|
static int setasyncmap __ARGS((int *, char ***));
|
|
static int setvjmode __ARGS((int *, char ***));
|
|
static int setmru __ARGS((int *, char ***));
|
|
static int nomru __ARGS((int *, char ***));
|
|
static int nopcomp __ARGS((int *, char ***));
|
|
static int setconnector __ARGS((int *, char ***));
|
|
static int setdomain __ARGS((int *, char ***));
|
|
static int setnetmask __ARGS((int *, char ***));
|
|
static int setcrtscts __ARGS((int *, char ***));
|
|
static int setnodetach __ARGS((int *, char ***));
|
|
static void cleanup __ARGS((int, caddr_t));
|
|
|
|
#ifdef STREAMS
|
|
static void str_restore __ARGS((void));
|
|
extern char *ttyname __ARGS((int));
|
|
#define MAXMODULES 10 /* max number of module names that we can save */
|
|
static struct modlist {
|
|
char modname[FMNAMESZ+1];
|
|
} str_modules[MAXMODULES];
|
|
static int str_module_count = 0;
|
|
#endif
|
|
|
|
/*
|
|
* Valid arguments.
|
|
*/
|
|
static 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 */
|
|
"-detach", setnodetach, /* don't fork */
|
|
"-ip", noipaddr, /* Disable IP address negotiation */
|
|
"-mn", nomagicnumber, /* Disable magic number negotiation */
|
|
"-mru", nomru, /* Disable mru negotiation */
|
|
"-p", setpassive, /* Set passive mode */
|
|
"-pc", nopcomp, /* Disable protocol field compress */
|
|
"+ua", requpap, /* Require UPAP authentication */
|
|
"-ua", noupap, /* Don't allow UPAP authentication */
|
|
"+chap", reqchap, /* Require CHAP authentication */
|
|
"-chap", nochap, /* Don't allow CHAP authentication */
|
|
"-vj", setnovj, /* disable VJ compression */
|
|
"asyncmap", setasyncmap, /* set the desired async map */
|
|
"connect", setconnector, /* A program to set up a connection */
|
|
"crtscts", setcrtscts, /* set h/w flow control */
|
|
"debug", setdebug, /* Increase debugging level */
|
|
"domain", setdomain, /* Add given domain name to hostname*/
|
|
"mru", setmru, /* Set MRU value for negotiation */
|
|
"netmask", setnetmask, /* set netmask */
|
|
"passive", setpassive, /* Set passive mode */
|
|
"vjmode", setvjmode, /* set VJ compression mode */
|
|
NULL
|
|
};
|
|
|
|
|
|
/*
|
|
* PPP Data Link Layer "protocol" table.
|
|
* One entry per supported protocol.
|
|
*/
|
|
static 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 },
|
|
{ CHAP, ChapInit, ChapInput, ChapProtocolReject },
|
|
};
|
|
|
|
|
|
static char *usage = "pppd version %s 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\
|
|
-detach Don't fork to background\n\
|
|
-ip Disable IP address negotiation\n\
|
|
-mn Disable magic number negotiation\n\
|
|
-mru Disable mru negotiation\n\
|
|
-p Set passive mode\n\
|
|
-pc Disable protocol field compression\n\
|
|
+ua <p> Require UPAP authentication and use file <p> for\n\
|
|
remote login data\n\
|
|
-ua Don't allow UPAP authentication\n\
|
|
+chap Require CHAP authentication\n\
|
|
-chap Don't allow CHAP authentication\n\
|
|
-vj disable VJ compression\n\
|
|
connect <p> Invoke shell command <p> to set up the serial line\n\
|
|
crtscts Use hardware RTS/CTS flow control\n\
|
|
debug Increase debugging level\n\
|
|
domain <d> Append domain name <d> to hostname for authentication\n\
|
|
mru <n> Set MRU value to <n> for negotiation\n\
|
|
netmask <n> Set interface netmask to <n>\n\
|
|
passive Set passive mode\n\
|
|
vjmode <m> VJ compression mode {old, rfc1172, rfc1132 (default)}\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";
|
|
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int mask, i;
|
|
struct sigvec sv;
|
|
struct cmd *cmdp;
|
|
FILE *pidfile;
|
|
#ifndef STREAMS
|
|
int pppdisc = PPPDISC;
|
|
#endif
|
|
|
|
/*
|
|
* Initialize syslog system and magic number package.
|
|
*/
|
|
#if BSD >= 43 || defined(sun)
|
|
openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
|
|
setlogmask(LOG_UPTO(LOG_INFO));
|
|
#else
|
|
openlog("pppd", 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();
|
|
|
|
if (gethostname(hostname, MAX_HOSTNAME_LEN) < 0 ) {
|
|
syslog(LOG_ERR, "couldn't get hostname: %m");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* 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, VERSION, PATCHLEVEL, progname);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
syslog(LOG_INFO, "Starting pppd %s patch level %d",
|
|
VERSION, PATCHLEVEL);
|
|
|
|
/*
|
|
* Initialize state.
|
|
*/
|
|
|
|
|
|
#define SETSID
|
|
#ifdef SETSID
|
|
if (default_device) {
|
|
/* No device name was specified... inherit the old controlling
|
|
terminal */
|
|
|
|
if ((pgrpid = getpgrp(0)) < 0) {
|
|
syslog(LOG_ERR, "getpgrp(0): %m");
|
|
exit(1);
|
|
}
|
|
if (pgrpid != pid)
|
|
syslog(LOG_WARNING, "warning... not a process group leader");
|
|
}
|
|
else /*default_device*/
|
|
{
|
|
/* become session leader... */
|
|
|
|
if (!nodetach) {
|
|
/* fork so we're not a process group leader */
|
|
if (pid = fork()) {
|
|
exit(0);
|
|
}
|
|
}
|
|
#ifdef xxx
|
|
else
|
|
/* bag controlling terminal */
|
|
if (ioctl(0, TIOCNOTTY) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCNOTTY): %m");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
/* create new session */
|
|
if ((pgrpid = setsid()) < 0) {
|
|
syslog(LOG_ERR, "setsid(): %m");
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* open i/o device */
|
|
if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
|
|
syslog(LOG_ERR, "open(%s): %m", devname);
|
|
exit(1);
|
|
}
|
|
|
|
/* drop dtr to hang up incase modem is off hook */
|
|
if (!default_device) {
|
|
setdtr(fd, FALSE);
|
|
sleep(1);
|
|
setdtr(fd, TRUE);
|
|
}
|
|
|
|
/* set device to be controlling tty */
|
|
if (ioctl(fd, TIOCSCTTY) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
|
|
exit(1);
|
|
}
|
|
|
|
/* run connection script */
|
|
if (connector) {
|
|
syslog(LOG_INFO, "Connecting with <%s>", connector);
|
|
/* set line speed */
|
|
set_up_tty(fd, 0);
|
|
if (set_up_connection(connector, fd, fd) < 0) {
|
|
syslog(LOG_ERR, "could not set up connection");
|
|
setdtr(fd, FALSE);
|
|
exit(1);
|
|
}
|
|
syslog(LOG_INFO, "Connected...");
|
|
}
|
|
|
|
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
syslog(LOG_ERR, "socket : %m");
|
|
exit(1);
|
|
}
|
|
|
|
/* if we exit, then try and restore the stream */
|
|
#ifdef sun
|
|
on_exit(cleanup, NULL);
|
|
#endif
|
|
|
|
#ifdef STREAMS
|
|
/* go through and save the name of all the modules, then pop em */
|
|
while(1) {
|
|
if(!ioctl(fd, I_LOOK, str_modules[str_module_count].modname))
|
|
MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
|
|
str_modules[str_module_count].modname))
|
|
if(!ioctl(fd, I_POP, 0))
|
|
str_module_count++;
|
|
else
|
|
break;
|
|
}
|
|
|
|
/* set line speed */
|
|
set_up_tty(fd, 1);
|
|
|
|
syslog(LOG_INFO, "about to push modules...");
|
|
|
|
/* now push the async/fcs module */
|
|
if(ioctl(fd, I_PUSH, "pppasync") < 0) {
|
|
syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
|
|
exit(1);
|
|
}
|
|
/* finally, push the ppp_if module that actually handles the */
|
|
/* network interface */
|
|
if(ioctl(fd, I_PUSH, "pppif") < 0) {
|
|
syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
|
|
exit(1);
|
|
}
|
|
if(ioctl(fd, I_SETSIG, S_INPUT) < 0) {
|
|
syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
|
|
exit(1);
|
|
}
|
|
/* read mode, message non-discard mode */
|
|
if(ioctl(fd, I_SRDOPT, RMSGN) < 0) {
|
|
syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
|
|
exit(1);
|
|
}
|
|
/* Flush any waiting messages, or we'll never get SIGPOLL */
|
|
if(ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
|
|
syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
|
|
exit(1);
|
|
}
|
|
/*
|
|
* Find out which interface we were given.
|
|
* (ppp_if handles this ioctl)
|
|
*/
|
|
if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
|
|
syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
|
|
exit(1);
|
|
}
|
|
|
|
/* if debug, set debug flags in driver */
|
|
{
|
|
int flags = debug ? 0x3 : 0;
|
|
syslog(LOG_INFO, "debug 0x%x, flags 0x%x", debug, flags);
|
|
if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
|
|
syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
|
|
}
|
|
}
|
|
|
|
syslog(LOG_INFO, "done pushing modules, ifunit %d", ifunit);
|
|
#else
|
|
/* set line speed */
|
|
set_up_tty(fd, 1);
|
|
|
|
if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
|
|
exit(1);
|
|
}
|
|
if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Find out which interface we were given.
|
|
*/
|
|
if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
|
|
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
syslog(LOG_INFO, "Using interface ppp%d", ifunit);
|
|
(void) sprintf(ifname, "ppp%d", ifunit);
|
|
pid = getpid();
|
|
|
|
(void) sprintf(pidfilename, "%s/%s.pid", pidpath, ifname);
|
|
|
|
/* write pid to file */
|
|
|
|
if ((pidfile = fopen(pidfilename, "w")) != NULL) {
|
|
fprintf(pidfile, "%d\n", pid);
|
|
(void) fclose(pidfile);
|
|
}
|
|
|
|
hostname_len = (u_char) strlen(hostname);
|
|
|
|
MAINDEBUG((LOG_DEBUG, "hostname = %s", hostname))
|
|
|
|
#ifdef SETSID
|
|
if (default_device) {
|
|
int id = tcgetpgrp(fd);
|
|
if (id != pgrpid) {
|
|
syslog(LOG_WARNING,
|
|
"warning: pppd is not the leader of a forground process group");
|
|
}
|
|
}
|
|
else
|
|
if (tcsetpgrp(fd, pgrpid) < 0) {
|
|
syslog(LOG_ERR, "tcsetpgrp(): %m");
|
|
exit(1);
|
|
}
|
|
#else
|
|
/* set process group on tty so we get SIGIO's */
|
|
if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
|
|
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)) {
|
|
syslog(LOG_ERR, "sigvec(SIGHUP)");
|
|
exit(1);
|
|
}
|
|
sv.sv_handler = intr; /* Interrupt */
|
|
sv.sv_mask = mask;
|
|
sv.sv_flags = 0;
|
|
if (sigvec(SIGINT, &sv, NULL)) {
|
|
syslog(LOG_ERR, "sigvec(SIGINT)");
|
|
exit(1);
|
|
}
|
|
sv.sv_handler = term; /* Terminate */
|
|
sv.sv_mask = mask;
|
|
sv.sv_flags = 0;
|
|
if (sigvec(SIGTERM, &sv, NULL)) {
|
|
syslog(LOG_ERR, "sigvec(SIGTERM)");
|
|
exit(1);
|
|
}
|
|
sv.sv_handler = alrm; /* Timeout */
|
|
sv.sv_mask = mask;
|
|
sv.sv_flags = 0;
|
|
if (sigvec(SIGALRM, &sv, NULL)) {
|
|
syslog(LOG_ERR, "sigvec(SIGALRM)");
|
|
exit(1);
|
|
}
|
|
sv.sv_handler = io; /* Input available */
|
|
sv.sv_mask = mask;
|
|
sv.sv_flags = 0;
|
|
if (sigvec(SIGIO, &sv, NULL)) {
|
|
syslog(LOG_ERR, "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)) {
|
|
syslog(LOG_ERR, "sigvec(SIGPOLL)");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __STDC__
|
|
/* Increment debug flag */
|
|
(void) signal(SIGUSR1, (void (*)(int))incdebug);
|
|
/* Reset debug flag */
|
|
(void) signal(SIGUSR2, (void (*)(int))nodebug);
|
|
#else
|
|
/* Increment debug flag */
|
|
(void) signal(SIGUSR1, (void (*)())incdebug);
|
|
/* Reset debug flag */
|
|
(void) signal(SIGUSR2, (void (*)())nodebug);
|
|
#endif
|
|
|
|
/*
|
|
* Record initial device flags, then set device to cause SIGIO
|
|
* signals to be generated.
|
|
*/
|
|
if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
|
|
syslog(LOG_ERR, "fcntl(F_GETFL): %m");
|
|
exit(1);
|
|
}
|
|
if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
|
|
syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* Block all signals, start opening the connection, and wait for
|
|
* incoming signals (reply, timeout, etc.).
|
|
*/
|
|
syslog(LOG_INFO, "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); /* Disallow signals */
|
|
upap_authwithpeer(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
set_up_tty(fd, flow)
|
|
int fd;
|
|
int flow;
|
|
{
|
|
#ifdef STREAMS
|
|
int new_cflag;
|
|
struct termios tios;
|
|
|
|
if(ioctl(fd, TCGETS, (caddr_t) &tios) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TCGETS): %m");
|
|
exit(1);
|
|
}
|
|
|
|
new_cflag = CS8 | CREAD | HUPCL;
|
|
new_cflag |= inspeed ? inspeed : (tios.c_cflag & CBAUD);
|
|
if (flow)
|
|
new_cflag |= crtscts ? CRTSCTS : 0;
|
|
|
|
tios.c_cflag = new_cflag;
|
|
tios.c_iflag = IGNBRK | IGNPAR;
|
|
tios.c_oflag = 0;
|
|
tios.c_lflag = 0;
|
|
|
|
if(ioctl(fd, TCSETS, (caddr_t) &tios) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TCSETS): %m");
|
|
exit(1);
|
|
}
|
|
#else
|
|
#ifdef SGTTY
|
|
struct sgttyb sgttyb;
|
|
|
|
/*
|
|
* Put the tty in raw mode and set the discipline to PPP.
|
|
*/
|
|
if (ioctl(fd, TIOCGETP, &initsgttyb) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
|
|
exit(1);
|
|
}
|
|
|
|
sgttyb = initsgttyb;
|
|
sgttyb.sg_flags = RAW | ANYP;
|
|
if (inspeed)
|
|
sgttyb.sg_ispeed = inspeed;
|
|
|
|
if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
|
|
exit(1);
|
|
}
|
|
#else
|
|
struct termios tios;
|
|
|
|
if (ioctl(fd, TIOCGETA, &tios) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCGETA): %m");
|
|
exit(1);
|
|
}
|
|
|
|
inittermios = tios;
|
|
|
|
tios.c_cflag = CREAD | CS8 | HUPCL;
|
|
if (flow)
|
|
tios.c_cflag |= crtscts ? CRTSCTS : 0;
|
|
tios.c_iflag = IGNBRK | IGNPAR;
|
|
tios.c_oflag = 0;
|
|
tios.c_lflag = 0;
|
|
tios.c_cc[VERASE] = tios.c_cc[VKILL] = 0;
|
|
tios.c_cc[VMIN] = 1;
|
|
tios.c_cc[VTIME] = 0;
|
|
if (inspeed)
|
|
tios.c_ispeed = tios.c_ospeed = inspeed;
|
|
|
|
if (ioctl(fd, TIOCSETA, &tios) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETA): %m");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* quit - Clean up state and exit.
|
|
*/
|
|
void
|
|
quit()
|
|
{
|
|
syslog(LOG_INFO, "Quitting");
|
|
|
|
if (fd == 0)
|
|
return;
|
|
|
|
if (fcntl(fd, F_SETFL, initfdflags) == -1) {
|
|
syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
|
|
exit(1);
|
|
}
|
|
|
|
#ifdef STREAMS
|
|
str_restore();
|
|
#else
|
|
#ifdef SGTTY
|
|
if (ioctl(fd, TIOCSETP, &initsgttyb) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETP)");
|
|
exit(1);
|
|
}
|
|
#else
|
|
if (ioctl(fd, TIOCSETA, &inittermios) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETA)");
|
|
exit(1);
|
|
}
|
|
|
|
#endif
|
|
if (ioctl(fd, TIOCSETD, &initdisc) < 0) {
|
|
syslog(LOG_ERR, "ioctl(TIOCSETD)");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
/* drop dtr to hang up */
|
|
setdtr(fd, FALSE);
|
|
|
|
close(fd);
|
|
fd = 0;
|
|
|
|
exit(0);
|
|
}
|
|
|
|
|
|
static struct callout *callout = NULL; /* Callout list */
|
|
static 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(func, arg, time)
|
|
void (*func)();
|
|
caddr_t arg;
|
|
int time;
|
|
{
|
|
struct itimerval itv;
|
|
struct callout *newp, **oldpp;
|
|
|
|
MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
|
|
(int) func, (int) arg, time))
|
|
|
|
/*
|
|
* Allocate timeout.
|
|
*/
|
|
if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
|
|
syslog(LOG_ERR, "Out of memory in timeout()!");
|
|
exit(1);
|
|
}
|
|
newp->c_arg = arg;
|
|
newp->c_func = func;
|
|
|
|
/*
|
|
* 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;
|
|
MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
|
|
itv.it_value.tv_sec))
|
|
if (setitimer(ITIMER_REAL, &itv, NULL)) {
|
|
syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
|
|
exit(1);
|
|
}
|
|
if (gettimeofday(&schedtime, NULL)) {
|
|
syslog(LOG_ERR, "gettimeofday");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* untimeout - Unschedule a timeout.
|
|
*/
|
|
void untimeout(func, arg)
|
|
void (*func)();
|
|
caddr_t arg;
|
|
{
|
|
|
|
struct itimerval itv;
|
|
struct callout **copp, *freep;
|
|
int reschedule = 0;
|
|
|
|
MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg))
|
|
|
|
/*
|
|
* If the first callout is unscheduled then we have to set a new
|
|
* itimer.
|
|
*/
|
|
if (callout &&
|
|
callout->c_func == func &&
|
|
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 == func &&
|
|
(*copp)->c_arg == arg) {
|
|
freep = *copp;
|
|
*copp = freep->c_next;
|
|
if (*copp)
|
|
(*copp)->c_time += freep->c_time;
|
|
(void) free((char *) 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;
|
|
MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
|
|
itv.it_value.tv_sec))
|
|
if (setitimer(ITIMER_REAL, &itv, NULL)) {
|
|
syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
|
|
exit(1);
|
|
}
|
|
if (gettimeofday(&schedtime, NULL)) {
|
|
syslog(LOG_ERR, "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)) {
|
|
syslog(LOG_ERR, "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;
|
|
|
|
str.len = len;
|
|
str.buf = (caddr_t) p;
|
|
if(putmsg(fd, NULL, &str, 0) < 0) {
|
|
syslog(LOG_ERR, "putmsg");
|
|
exit(1);
|
|
}
|
|
#else
|
|
if (unit != 0) {
|
|
MAINDEBUG((LOG_WARNING, "output: unit != 0!"))
|
|
abort();
|
|
}
|
|
|
|
if (write(fd, p, len) < 0) {
|
|
syslog(LOG_ERR, "write");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
* hup - Catch SIGHUP signal.
|
|
*
|
|
* Indicates that the physical layer has been disconnected.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
hup(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
syslog(LOG_INFO, "Hangup (SIGHUP)");
|
|
adjtimeout(); /* Adjust timeouts */
|
|
lcp_lowerdown(0); /* Reset connection */
|
|
}
|
|
|
|
|
|
/*
|
|
* term - Catch SIGTERM signal.
|
|
*
|
|
* Indicates that we should initiate a graceful disconnect and exit.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
term(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
syslog(LOG_INFO, "Terminate signal received.");
|
|
adjtimeout(); /* Adjust timeouts */
|
|
lcp_close(0); /* Close connection */
|
|
}
|
|
|
|
|
|
/*
|
|
* intr - Catch SIGINT signal (DEL/^C).
|
|
*
|
|
* Indicates that we should initiate a graceful disconnect and exit.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
intr(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
syslog(LOG_INFO, "Interrupt received. Exiting.");
|
|
adjtimeout(); /* Adjust timeouts */
|
|
lcp_close(0); /* Close connection */
|
|
}
|
|
|
|
|
|
/*
|
|
* alrm - Catch SIGALRM signal.
|
|
*
|
|
* Indicates a timeout.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
alrm(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
struct itimerval itv;
|
|
struct callout *freep;
|
|
|
|
MAINDEBUG((LOG_DEBUG, "Alarm"))
|
|
|
|
/*
|
|
* 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);
|
|
(void) free((char *) freep);
|
|
if (callout && 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;
|
|
MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
|
|
itv.it_value.tv_sec))
|
|
if (setitimer(ITIMER_REAL, &itv, NULL)) {
|
|
syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
|
|
exit(1);
|
|
}
|
|
if (gettimeofday(&schedtime, NULL)) {
|
|
syslog(LOG_ERR, "gettimeofday");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* io - Catch SIGIO signal.
|
|
*
|
|
* Indicates that incoming data is available.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
io(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
int len, i;
|
|
u_char *p;
|
|
u_short protocol;
|
|
fd_set fdset;
|
|
struct timeval notime;
|
|
int ready;
|
|
#ifdef STREAMS
|
|
struct strbuf str;
|
|
#endif
|
|
|
|
|
|
MAINDEBUG((LOG_DEBUG, "IO signal received"))
|
|
adjtimeout(); /* Adjust timeouts */
|
|
|
|
/* we do this to see if the SIGIO handler is being invoked for input */
|
|
/* ready, or for the socket buffer hitting the low-water mark. */
|
|
|
|
notime.tv_sec = 0;
|
|
notime.tv_usec = 0;
|
|
|
|
FD_ZERO(&fdset);
|
|
FD_SET(fd, &fdset);
|
|
|
|
if ((ready = select(32, &fdset, (fd_set *) NULL, (fd_set *) NULL,
|
|
¬ime)) == -1) {
|
|
syslog(LOG_ERR, "Error in io() select: %m");
|
|
exit(1);
|
|
}
|
|
|
|
if (ready == 0) {
|
|
MAINDEBUG((LOG_DEBUG, "IO non-input ready SIGIO occured."));
|
|
return;
|
|
}
|
|
|
|
/* Yup, this is for real */
|
|
for (;;) { /* Read all available packets */
|
|
p = inpacket_buf; /* point to beggining of packet buffer */
|
|
|
|
#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) {
|
|
return;
|
|
}
|
|
syslog(LOG_ERR, "getmsg(fd) %m");
|
|
exit(1);
|
|
}
|
|
else if(len)
|
|
MAINDEBUG((LOG_DEBUG, "getmsg returns with length 0x%x",len))
|
|
|
|
if(str.len < 0) {
|
|
MAINDEBUG((LOG_DEBUG, "getmsg short return length %d",
|
|
str.len))
|
|
return;
|
|
}
|
|
|
|
len = str.len;
|
|
#else
|
|
if ((len = read(fd, p, MTU + DLLHEADERLEN)) < 0) {
|
|
if (errno == EWOULDBLOCK) {
|
|
MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"))
|
|
return;
|
|
}
|
|
else {
|
|
syslog(LOG_ERR, "read(fd): %m");
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
if (len == 0) {
|
|
syslog(LOG_ERR, "End of file on fd!");
|
|
exit(1);
|
|
}
|
|
|
|
if (len < DLLHEADERLEN) {
|
|
MAINDEBUG((LOG_INFO, "io(): Received short packet."))
|
|
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) {
|
|
MAINDEBUG((LOG_INFO, "io(): Received non-LCP packet and LCP is not in open state."))
|
|
dumpbuffer(inpacket_buf, len + DLLHEADERLEN, LOG_ERR);
|
|
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)) {
|
|
syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
|
|
protocol);
|
|
p -= DLLHEADERLEN;
|
|
len += DLLHEADERLEN;
|
|
lcp_sprotrej(0, p, len);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* cleanup - clean_up before we exit
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
cleanup(status, arg)
|
|
int status;
|
|
caddr_t arg;
|
|
{
|
|
adjtimeout();
|
|
lcp_lowerdown(0);
|
|
if (unlink(pidfilename) < 0)
|
|
syslog(LOG_WARNING, "unable to unlink pid file: %m");
|
|
}
|
|
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
syslog(LOG_WARNING, "demuxprotrej: Unrecognized Protocol-Reject for protocol %d!", protocol);
|
|
}
|
|
|
|
|
|
/*
|
|
* incdebug - Catch SIGUSR1 signal.
|
|
*
|
|
* Increment debug flag.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
incdebug(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
|
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
|
debug++;
|
|
}
|
|
|
|
|
|
/*
|
|
* nodebug - Catch SIGUSR2 signal.
|
|
*
|
|
* Turn off debugging.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static void
|
|
nodebug(sig, code, scp, addr)
|
|
int sig, code;
|
|
struct sigcontext *scp;
|
|
char *addr;
|
|
{
|
|
setlogmask(LOG_UPTO(LOG_WARNING));
|
|
debug = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* setdebug - Set debug (command line argument).
|
|
*/
|
|
static int
|
|
setdebug(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
debug++;
|
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* noopt - Disable all options.
|
|
*/
|
|
static int
|
|
noopt(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
bzero((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
|
|
bzero((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
|
|
bzero((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
|
|
bzero((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* setconnector - Set a program to connect to a serial line
|
|
*/
|
|
static int
|
|
setconnector(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
|
|
--*argcp, ++*argvp;
|
|
|
|
connector = strdup(**argvp);
|
|
if (connector == NULL) {
|
|
syslog(LOG_ERR, "cannot allocate space for connector string");
|
|
exit(1);
|
|
}
|
|
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* set_up_connection - run a program to initialize the serial connector
|
|
*/
|
|
int set_up_connection(program, in, out)
|
|
char *program;
|
|
int in, out;
|
|
{
|
|
int pid;
|
|
int flags;
|
|
int status;
|
|
|
|
flags = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
|
syslog(LOG_ERR, "fork");
|
|
exit(1);
|
|
}
|
|
|
|
if (pid == 0) {
|
|
(void) setreuid(getuid(), getuid());
|
|
(void) setregid(getgid(), getgid());
|
|
(void) sigsetmask(flags);
|
|
(void) dup2(in, 0);
|
|
(void) dup2(out, 1);
|
|
(void) execl("/bin/sh", "sh", "-c", program, (char *)0);
|
|
syslog(LOG_ERR, "could not exec /bin/sh");
|
|
_exit(99);
|
|
}
|
|
else {
|
|
while (waitpid(pid, &status, 0) != pid) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
syslog(LOG_ERR, "waiting for connection process");
|
|
exit(1);
|
|
}
|
|
(void) sigsetmask(flags);
|
|
}
|
|
return (status == 0 ? 0 : -1);
|
|
}
|
|
|
|
/*
|
|
* noaccomp - Disable Address/Control field compression negotiation.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static 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.
|
|
*/
|
|
static int
|
|
setpassive(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
lcp_wantoptions[0].passive = 1;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* noupap - Disable UPAP authentication.
|
|
*/
|
|
static int
|
|
noupap(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
lcp_allowoptions[0].neg_upap = 0;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* requpap - Require UPAP authentication.
|
|
*/
|
|
static int
|
|
requpap(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
FILE * ufile;
|
|
struct stat sbuf;
|
|
|
|
lcp_wantoptions[0].neg_upap = 1;
|
|
lcp_allowoptions[0].neg_upap = 0;
|
|
--*argcp, ++*argvp;
|
|
strcpy(uinfopath, **argvp);
|
|
--*argcp, ++*argvp;
|
|
|
|
/* open user info file */
|
|
|
|
if ((ufile = fopen(uinfopath, "r")) == NULL) {
|
|
fprintf(stderr, "unable to open user login data file %s\n", uinfopath);
|
|
exit(1);
|
|
};
|
|
|
|
if (fstat(fileno(ufile), &sbuf) < 0) {
|
|
perror("cannot stat user login data file!");
|
|
exit(1);
|
|
}
|
|
if ((sbuf.st_mode & 077) != 0)
|
|
syslog(LOG_WARNING, "Warning - user info file has world and/or group access!\n");
|
|
|
|
/* get username */
|
|
fgets(user, sizeof (user) - 1, ufile);
|
|
if (strlen(user) == 0) {
|
|
fprintf(stderr, "Unable to get user name from user login data file.\n");
|
|
exit(2);
|
|
}
|
|
/* get rid of newline */
|
|
user[strlen(user) - 1] = '\000';
|
|
|
|
fgets(passwd, sizeof(passwd) - 1, ufile);
|
|
|
|
if (strlen(passwd) == 0) {
|
|
fprintf(stderr, "Unable to get password from user login data file.\n");
|
|
exit(2);
|
|
}
|
|
|
|
passwd[strlen(passwd) - 1] = '\000';
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* nochap - Disable CHAP authentication.
|
|
*/
|
|
static int
|
|
nochap(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
lcp_allowoptions[0].neg_chap = 0;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* reqchap - Require CHAP authentication.
|
|
*/
|
|
static int
|
|
reqchap(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
lcp_wantoptions[0].neg_chap = 1;
|
|
lcp_allowoptions[0].neg_chap = 0;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
|
|
/*
|
|
* setvjmode - Set vj compression mode
|
|
*/
|
|
|
|
static int
|
|
setvjmode(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
extern int ipcp_vj_mode;
|
|
|
|
--*argcp, ++*argvp;
|
|
|
|
if (!strcmp(**argvp, "old")) { /* "old" mode */
|
|
ipcp_vj_setmode(IPCP_VJMODE_OLD);
|
|
}
|
|
|
|
else if (!strcmp(**argvp, "rfc1172")) { /* "rfc1172" mode*/
|
|
ipcp_vj_setmode(IPCP_VJMODE_RFC1172);
|
|
}
|
|
|
|
else if (!strcmp(**argvp, "rfc1332")) { /* "rfc1332" default mode */
|
|
ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
|
|
}
|
|
else {
|
|
syslog(LOG_WARNING,
|
|
"Unknown vj compression mode %s. Defaulting to RFC1332", **argvp);
|
|
ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
|
|
}
|
|
--*argcp, ++*argvp;
|
|
|
|
return (1);
|
|
}
|
|
/*
|
|
* setnovj - diable vj compression
|
|
*/
|
|
|
|
static int
|
|
setnovj(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
extern int ipcp_vj_mode;
|
|
|
|
--*argcp, ++*argvp;
|
|
ipcp_wantoptions[0].neg_vj = 0;
|
|
ipcp_allowoptions[0].neg_vj = 0;
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* setdomain - Set domain name to append to hostname
|
|
*/
|
|
static int
|
|
setdomain(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
|
|
--*argcp, ++*argvp;
|
|
|
|
strcat(hostname, **argvp);
|
|
hostname_len = strlen(hostname);
|
|
|
|
--*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 B19200
|
|
{ 19200, B19200 },
|
|
#else
|
|
#ifdef EXTA
|
|
{ 19200, EXTA },
|
|
#endif
|
|
#endif
|
|
#ifdef B38400
|
|
{ 38400, B38400 },
|
|
#else
|
|
#ifdef EXTB
|
|
{ 38400, EXTB },
|
|
#endif
|
|
#endif
|
|
#ifdef B57600
|
|
{ 57600, B57600 },
|
|
#endif
|
|
#ifdef B115200
|
|
{ 115200, B115200 },
|
|
#endif
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static 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.
|
|
*/
|
|
static 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);
|
|
syslog(LOG_ERR, cp);
|
|
exit(1);
|
|
}
|
|
|
|
(void) strcpy(devname, cp);
|
|
default_device = FALSE;
|
|
--*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) {
|
|
syslog(LOG_WARNING, "unknown host: %s", **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) {
|
|
syslog(LOG_WARNING,"unknown host: %s", 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);
|
|
}
|
|
|
|
static int
|
|
setnetmask(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
u_long mask;
|
|
|
|
--*argcp, ++*argvp;
|
|
if ((mask = inet_addr(**argvp)) == -1) {
|
|
fprintf(stderr, "Invalid netmask %s\n", **argvp);
|
|
exit(1);
|
|
}
|
|
|
|
netmask = mask;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
static int
|
|
setcrtscts(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
crtscts = 1;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
static int
|
|
setnodetach(argcp, argvp)
|
|
int *argcp;
|
|
char ***argvp;
|
|
{
|
|
nodetach = 1;
|
|
--*argcp, ++*argvp;
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* getuserpasswd - Get the user name and passwd.
|
|
*/
|
|
static void
|
|
getuserpasswd()
|
|
{
|
|
|
|
upap[0].us_user = user;
|
|
upap[0].us_userlen = strlen(upap[0].us_user);
|
|
|
|
upap[0].us_passwd = passwd;
|
|
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();
|
|
char *tmp_passwd, *tmp_user;
|
|
|
|
/* why alloca.h doesn't define what alloca() returns is a mystery */
|
|
|
|
#ifdef sparc
|
|
char *__builtin_alloca __ARGS((int));
|
|
#else
|
|
char *alloca __ARGS((int));
|
|
#endif /*sparc*/
|
|
tmp_passwd = alloca(passwdlen + 1); /* we best make copies before */
|
|
/* null terminating the string */
|
|
if (tmp_passwd == NULL) {
|
|
syslog(LOG_ERR, "alloca failed");
|
|
exit(1);
|
|
}
|
|
bcopy(passwd, tmp_passwd, passwdlen);
|
|
tmp_passwd[passwdlen] = '\0';
|
|
|
|
tmp_user = alloca(userlen + 1);
|
|
if (tmp_user == NULL) {
|
|
syslog(LOG_ERR, "alloca failed");
|
|
exit(1);
|
|
}
|
|
bcopy(user, tmp_user, userlen);
|
|
tmp_user[userlen] = '\0';
|
|
|
|
if ((pw = getpwnam(tmp_user)) == NULL) {
|
|
*msg = "Login incorrect";
|
|
*msglen = strlen(*msg);
|
|
syslog(LOG_WARNING, "upap login userid '%s' incorrect",tmp_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(tmp_passwd, pw->pw_passwd);
|
|
if (strcmp(epasswd, pw->pw_passwd)) {
|
|
*msg = "Login incorrect";
|
|
*msglen = strlen(*msg);
|
|
syslog(LOG_WARNING, "upap login password '%s' incorrect", tmp_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_WARNING, "%d LOGIN FAILURES ON %s, %s",
|
|
attempts, devname, tmp_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);
|
|
syslog(LOG_INFO, "user %s logged in", tmp_user);
|
|
tty = rindex(devname, '/');
|
|
if (tty == NULL)
|
|
tty = devname;
|
|
else
|
|
tty++;
|
|
logwtmp(tty, tmp_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 {
|
|
syslog(LOG_ERR, "fgets");
|
|
exit(1);
|
|
}
|
|
}
|
|
if ((s = index(buf, ' ')) == NULL)
|
|
continue;
|
|
*s++ = '\0';
|
|
if (!strcmp(user, buf)) {
|
|
rc = 1;
|
|
break;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return (rc);
|
|
}
|
|
/*
|
|
* open "secret" file and return the secret matching the given name.
|
|
* If no secret for a given name is found, use the one for "default".
|
|
*/
|
|
|
|
void
|
|
get_secret(name, secret, secret_len)
|
|
u_char * name;
|
|
u_char * secret;
|
|
int * secret_len;
|
|
{
|
|
FILE * sfile;
|
|
struct stat sbuf;
|
|
u_char fname[256];
|
|
int match_found, default_found;
|
|
|
|
match_found = FALSE;
|
|
default_found = FALSE;
|
|
|
|
if ((sfile = fopen(_PATH_CHAPFILE, "r")) == NULL) {
|
|
syslog(LOG_ERR, "unable to open secret file %s", _PATH_CHAPFILE);
|
|
exit(1);
|
|
};
|
|
|
|
if (fstat(fileno(sfile), &sbuf) < 0) {
|
|
syslog(LOG_ERR, "cannot stat secret file!: %m");
|
|
exit(1);
|
|
}
|
|
if ((sbuf.st_mode & 077) != 0)
|
|
syslog(LOG_WARNING, "Warning - secret file has world and/or group access!");
|
|
|
|
while (!feof(sfile) && !match_found) {
|
|
if (fscanf(sfile, "%s %s", fname, secret) == EOF)
|
|
break;
|
|
if (!strcasecmp((char *)fname, (char *)name)) {
|
|
match_found = TRUE;
|
|
}
|
|
if (!strcasecmp("default", (char *)name)) {
|
|
default_found = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!match_found && !default_found) {
|
|
syslog(LOG_ERR, "No match or default entry found for %s in CHAP secret file! Aborting...", name);
|
|
cleanup(0, NULL); /* shut us down */
|
|
}
|
|
#ifdef UNSECURE
|
|
/* while this is useful for debugging, it is a security hole as well */
|
|
|
|
syslog(LOG_DEBUG, "get_secret: found secret %s", secret);
|
|
#endif /*UNSECURE*/
|
|
fclose(sfile);
|
|
*secret_len = strlen((char *)secret);
|
|
if (*secret_len > MAX_SECRET_LEN) { /* don't let it overflow the buffer */
|
|
syslog(LOG_ERR, "Length of secret for host %s is greater than the maximum %d characters! ", name, MAX_SECRET_LEN);
|
|
cleanup(0, NULL); /* scream and die */
|
|
}
|
|
return;
|
|
}
|
|
/*
|
|
* Return user specified netmask. A value of zero means no netmask has
|
|
* been set.
|
|
*/
|
|
/* ARGSUSED */
|
|
u_long
|
|
GetMask(addr)
|
|
u_long addr;
|
|
{
|
|
return(netmask);
|
|
}
|
|
|
|
#ifdef STREAMS
|
|
/*
|
|
* this module will attempt to reconstruct the stream with the
|
|
* previously popped modules
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
str_restore()
|
|
{
|
|
/*EMPTY*/
|
|
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)) {
|
|
syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
|
|
str_modules[str_module_count-1].modname);
|
|
}
|
|
else {
|
|
MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
|
|
str_modules[str_module_count-1].modname))
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
dumpbuffer(buffer, size, level)
|
|
unsigned char *buffer;
|
|
int size;
|
|
int level;
|
|
{
|
|
register int i;
|
|
char line[256], *p;
|
|
|
|
printf("%d bytes:\n", size);
|
|
while (size > 0)
|
|
{
|
|
p = line;
|
|
sprintf(p, "%08lx: ", buffer);
|
|
p += 10;
|
|
|
|
for (i = 0; i < 8; i++, p += 3)
|
|
if (size - i <= 0)
|
|
sprintf(p, "xx ");
|
|
else
|
|
sprintf(p, "%02x ", buffer[i]);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
if (size - i <= 0)
|
|
*p++ = 'x';
|
|
else
|
|
*p++ = (' ' <= buffer[i] && buffer[i] <= '~') ?
|
|
buffer[i] : '.';
|
|
|
|
*p++ = 0;
|
|
buffer += 8;
|
|
size -= 8;
|
|
|
|
/* syslog(level, "%s\n", line); */
|
|
printf("%s\n", line);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
#ifdef sun
|
|
setdtr(fd, on)
|
|
int fd, on;
|
|
{
|
|
int linestate;
|
|
|
|
ioctl(fd, TIOCMGET, &linestate);
|
|
|
|
if (on)
|
|
linestate |= TIOCM_DTR;
|
|
else
|
|
linestate &= ~TIOCM_DTR;
|
|
|
|
ioctl(fd, TIOCMSET, &linestate);
|
|
}
|
|
#endif
|
|
#ifdef __NetBSD__
|
|
setdtr(fd, on)
|
|
int fd, on;
|
|
{
|
|
int modembits = TIOCM_DTR;
|
|
|
|
if (on)
|
|
ioctl(fd, TIOCMBIS, &modembits);
|
|
else
|
|
ioctl(fd, TIOCMBIC, &modembits);
|
|
}
|
|
#endif
|
|
|
|
#include "ppp.h"
|
|
|
|
char *
|
|
proto_name(proto)
|
|
u_short proto;
|
|
{
|
|
switch (proto) {
|
|
case LCP: return "lcp";
|
|
case UPAP: return "pap";
|
|
case CHAP: return "chap";
|
|
case IPCP: return "ipcp";
|
|
#define LQM 0xc025
|
|
case LQM: return "lqm";
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
#include <varargs.h>
|
|
|
|
char line[256];
|
|
char *p;
|
|
|
|
logf(level, fmt, va_alist)
|
|
int level;
|
|
char *fmt;
|
|
va_dcl
|
|
{
|
|
va_list pvar;
|
|
char buf[256];
|
|
|
|
va_start(pvar);
|
|
vsprintf(buf, fmt, pvar);
|
|
va_end(pvar);
|
|
|
|
p = line + strlen(line);
|
|
strcat(p, buf);
|
|
|
|
if (buf[strlen(buf)-1] == '\n') {
|
|
syslog(level, "%s", line);
|
|
line[0] = 0;
|
|
}
|
|
}
|