*/
#ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.6 1994/04/11 07:15:13 paulus Exp $";
+static char rcsid[] = "$Id: main.c,v 1.13 1994/05/27 01:02:14 paulus Exp $";
#endif
#define SETSID
#include <stdio.h>
+#include <string.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <netdb.h>
#include <utmp.h>
+#include <pwd.h>
+#include <sys/wait.h>
/*
* If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
* /etc/ppp/options exists.
*/
#ifndef REQ_SYSOPTIONS
-#define REQ_SYSOPTIONS 0
-#endif
-
-#ifdef STREAMS
-#undef SGTTY
+#define REQ_SYSOPTIONS 1
#endif
#ifdef SGTTY
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
-
-#include "callout.h"
-
#include <net/if.h>
-#include <net/if_ppp.h>
-
-#include <string.h>
-
-#ifndef BSD
-#define BSD 43
-#endif /*BSD*/
+#include "callout.h"
#include "ppp.h"
#include "magic.h"
#include "fsm.h"
char hostname[MAXNAMELEN]; /* Our hostname */
char our_name[MAXNAMELEN];
char remote_name[MAXNAMELEN];
+static char pidfilename[MAXPATHLEN];
static pid_t pid; /* Our pid */
static pid_t pgrpid; /* Process Group ID */
-static char pidfilename[MAXPATHLEN];
+uid_t uid; /* Our real user-id */
char devname[MAXPATHLEN] = "/dev/tty"; /* Device name */
int default_device = TRUE; /* use default device (stdin/out) */
-int fd; /* Device file descriptor */
+int fd = -1; /* Device file descriptor */
int s; /* Socket file descriptor */
+int phase; /* where the link is at */
+
#ifdef SGTTY
static struct sgttyb initsgttyb; /* Initial TTY sgttyb */
#else
static u_char inpacket_buf[MTU+DLLHEADERLEN]; /* buffer for incoming packet */
int hungup; /* terminal has been hung up */
+static int n_children; /* # child processes still running */
/* configured variables */
int debug = 0; /* Debug flag */
+int kdebugflag = 0; /* Kernel debugging flag */
char user[MAXNAMELEN]; /* username for PAP */
char passwd[MAXSECRETLEN]; /* password for PAP */
char *connector = NULL; /* "connect" command */
+char *disconnector = NULL; /* "disconnect" command */
int inspeed = 0; /* Input/Output speed requested */
int baud_rate; /* bits/sec currently used */
u_long netmask = 0; /* netmask to use on ppp interface */
int persist = 0; /* re-initiate on termination */
int answer = 0; /* wait for incoming call */
int uselogin = 0; /* check PAP info against /etc/passwd */
+int lockflag = 0; /* lock the serial device */
/* 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 hup __ARGS((int));
+static void intr __ARGS((int));
+static void term __ARGS((int));
+static void alrm __ARGS((int));
+static void io __ARGS((int));
+static void chld __ARGS((int));
static void incdebug __ARGS((int));
static void nodebug __ARGS((int));
void establish_ppp __ARGS((void));
+void reap_kids __ARGS((void));
void cleanup __ARGS((int, caddr_t));
void die __ARGS((int));
void novm __ARGS((char *));
void (*) (void *, char *, ...), void *));
void pr_log __ARGS((void *, char *, ...));
-#ifdef STREAMS
extern char *ttyname __ARGS((int));
-#endif
extern char *getlogin __ARGS((void));
/*
char *argv[];
{
int mask, i;
- struct sigvec sv;
+ struct sigaction sa;
struct cmd *cmdp;
FILE *pidfile;
char *p;
+ struct passwd *pw;
- /*
- * 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
- p = ttyname(fileno(stdin));
+ p = ttyname(0);
if (p)
strcpy(devname, p);
-#endif
- magic_init();
-
if (gethostname(hostname, MAXNAMELEN) < 0 ) {
- syslog(LOG_ERR, "couldn't get hostname: %m");
+ perror("couldn't get hostname");
die(1);
}
hostname[MAXNAMELEN-1] = 0;
pid = getpid();
+ uid = getuid();
if (!ppp_available()) {
fprintf(stderr, "Sorry - PPP is not available on this system\n");
progname = *argv;
- if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS) ||
+ if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS, 0) ||
!options_from_user() ||
- !parse_args(argc-1, argv+1))
+ !parse_args(argc-1, argv+1) ||
+ !options_for_tty())
die(1);
check_auth_options();
setipdefault();
+ /*
+ * Initialize syslog system and magic number package.
+ */
+#if !defined(ultrix)
+ 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
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+
+ magic_init();
+
p = getlogin();
- if (p == NULL)
- p = "(unknown)";
+ if (p == NULL) {
+ pw = getpwuid(uid);
+ if (pw != NULL && pw->pw_name != NULL)
+ p = pw->pw_name;
+ else
+ p = "(unknown)";
+ }
syslog(LOG_NOTICE, "pppd %s.%d started by %s, uid %d",
- VERSION, PATCHLEVEL, p, getuid());
+ VERSION, PATCHLEVEL, p, uid);
#ifdef SETSID
/*
}
#endif
+ if (lockflag && !default_device)
+ if (lock(devname) < 0)
+ die(1);
+
/* Get an internet socket for doing socket ioctl's on. */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "socket : %m");
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGALRM);
sigaddset(&mask, SIGIO);
+ sigaddset(&mask, SIGCHLD);
#ifdef STREAMS
sigaddset(&mask, SIGPOLL);
#endif
#define SIGNAL(s, handler) { \
- sv.sv_handler = handler; \
- if (sigvec(s, &sv, NULL) < 0) { \
- syslog(LOG_ERR, "sigvec(%d): %m", s); \
+ sa.sa_handler = handler; \
+ if (sigaction(s, &sa, NULL) < 0) { \
+ syslog(LOG_ERR, "sigaction(%d): %m", s); \
die(1); \
} \
}
- sv.sv_mask = mask;
- sv.sv_flags = 0;
+ sa.sa_mask = mask;
+ sa.sa_flags = 0;
SIGNAL(SIGHUP, hup); /* Hangup */
SIGNAL(SIGINT, intr); /* Interrupt */
SIGNAL(SIGTERM, term); /* Terminate */
SIGNAL(SIGALRM, alrm); /* Timeout */
SIGNAL(SIGIO, io); /* Input available */
+ SIGNAL(SIGCHLD, chld); /* Death of child process */
#ifdef STREAMS
SIGNAL(SIGPOLL, io); /* Input available */
#endif
}
hungup = 0;
+#ifdef TIOCSCTTY
/* set device to be controlling tty */
if (!default_device && ioctl(fd, TIOCSCTTY) < 0) {
syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
die(1);
}
-
- /* set line speed, flow control, etc. */
- set_up_tty(fd);
+#endif /* TIOCSCTTY */
/* run connection script */
if (connector) {
- syslog(LOG_INFO, "Connecting with <%s>", connector);
+ MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector));
+
+ /* set line speed, flow control, etc.; set CLOCAL for now */
+ set_up_tty(fd, 1);
/* drop dtr to hang up in case modem is off hook */
if (!default_device && modem) {
setdtr(fd, TRUE);
}
- if (set_up_connection(connector, fd, fd) < 0) {
+ if (device_script(connector, fd, fd) < 0) {
syslog(LOG_ERR, "could not set up connection");
setdtr(fd, FALSE);
die(1);
sleep(1); /* give it time to set up its terminal */
}
+ /* set line speed, flow control, etc.; clear CLOCAL if modem option */
+ set_up_tty(fd, 0);
+
/* set up the serial device as a ppp interface */
establish_ppp();
syslog(LOG_ERR, "fcntl(F_GETFL): %m");
die(1);
}
+
+#ifdef _linux_ /* This is a kludge for Linux. FIXME !!! -- later. */
+#undef FASYNC
+#define FASYNC 0
+#endif
+
if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
die(1);
sigprocmask(SIG_BLOCK, &mask, NULL); /* Block signals now */
lcp_lowerup(0); /* XXX Well, sort of... */
lcp_open(0); /* Start protocol */
- for (;;) {
+ for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; )
sigpause(0); /* Wait for next signal */
- reap_kids(); /* Don't leave dead kids lying around */
+
+ /*
+ * Run disconnector script, if requested
+ */
+ if (disconnector) {
+ if (device_script(disconnector, fd, fd) < 0) {
+ syslog(LOG_WARNING, "disconnect script failed");
+ die(1);
+ }
+
+ syslog(LOG_INFO, "Disconnected...");
}
+
+ quit();
}
#if B9600 == 9600
/*
* set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
- * at the requested speed, etc.
+ * at the requested speed, etc. If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
*/
-set_up_tty(fd)
- int fd;
+set_up_tty(fd, local)
+ int fd, local;
{
#ifndef SGTTY
- int speed;
+ int speed, x;
struct termios tios;
if (tcgetattr(fd, &tios) < 0) {
if (!restore_term)
inittermios = tios;
+#ifdef CRTSCTS
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CRTSCTS);
- tios.c_cflag |= CS8 | CREAD | HUPCL;
- if (crtscts)
+ if (crtscts == 1)
tios.c_cflag |= CRTSCTS;
- if (!modem)
+#else
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+#endif /* CRTSCTS */
+
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (local || !modem)
tios.c_cflag |= CLOCAL;
tios.c_iflag = IGNBRK | IGNPAR;
tios.c_oflag = 0;
tios.c_lflag = 0;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
+
+ if (crtscts == 2) {
+ tios.c_iflag |= IXOFF;
+ tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
+ tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
+ }
+
speed = translate_speed(inspeed);
if (speed) {
cfsetospeed(&tios, speed);
die(1);
}
+#ifdef ultrix
+ x = 0;
+ if (ioctl(fd, (crtscts || modem)? TIOCMODEM: TIOCNMODEM, &x) < 0)
+ syslog(LOG_WARNING, "TIOC(N)MODEM: %m");
+ if (ioctl(fd, (local || !modem)? TIOCNCAR: TIOCCAR) < 0)
+ syslog(LOG_WARNING, "TIOC(N)CAR: %m");
+#endif
+
#else /* SGTTY */
int speed;
struct sgttyb sgttyb;
restore_term = TRUE;
}
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+setdtr(fd, on)
+int fd, on;
+{
+ int modembits = TIOCM_DTR;
+
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+}
+
/*
* quit - Clean up state and exit.
int status;
caddr_t arg;
{
- if (fd != 0) {
+ if (fd >= 0) {
/* drop dtr to hang up */
if (modem)
setdtr(fd, FALSE);
- if (fcntl(fd, F_SETFL, initfdflags) < 0)
- syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_WARNING, "fcntl(F_SETFL, fdflags): %m");
+ initfdflags = -1;
disestablish_ppp();
if (restore_term) {
#ifndef SGTTY
if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
- syslog(LOG_ERR, "tcsetattr: %m");
+ syslog(LOG_WARNING, "tcsetattr: %m");
#else
if (ioctl(fd, TIOCSETP, &initsgttyb) < 0)
- syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+ syslog(LOG_WARNING, "ioctl(TIOCSETP): %m");
#endif
}
close(fd);
- fd = 0;
+ fd = -1;
}
if (pidfilename[0] != 0 && unlink(pidfilename) < 0)
syslog(LOG_WARNING, "unable to unlink pid file: %m");
pidfilename[0] = 0;
+
+ if (lockflag && !default_device)
+ unlock();
}
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.",
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in timeout.",
itv.it_value.tv_sec));
if (setitimer(ITIMER_REAL, &itv, NULL)) {
syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
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.",
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in untimeout.",
itv.it_value.tv_sec));
if (setitimer(ITIMER_REAL, &itv, NULL)) {
syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
*
* Indicates that the physical layer has been disconnected.
*/
-/*ARGSUSED*/
static void
-hup(sig, code, scp, addr)
- int sig, code;
- struct sigcontext *scp;
- char *addr;
+hup(sig)
+ int sig;
{
syslog(LOG_INFO, "Hangup (SIGHUP)");
*
* 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;
+term(sig)
+ int sig;
{
syslog(LOG_INFO, "Terminating link.");
persist = 0; /* don't try to restart */
*
* 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;
+intr(sig)
+ int sig;
{
syslog(LOG_INFO, "Interrupt received: terminating link");
persist = 0; /* don't try to restart */
*
* Indicates a timeout.
*/
-/*ARGSUSED*/
static void
-alrm(sig, code, scp, addr)
- int sig, code;
- struct sigcontext *scp;
- char *addr;
+alrm(sig)
+ int sig;
{
struct itimerval itv;
- struct callout *freep;
+ struct callout *freep, *list, *last;
MAINDEBUG((LOG_DEBUG, "Alarm"));
+ if (callout == NULL)
+ return;
/*
- * Call and free first scheduled timeout and any that were scheduled
- * for the same time.
+ * Get the first scheduled timeout and any that were scheduled
+ * for the same time as a list, and remove them all from callout
+ * list.
*/
- 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;
- }
-
+ list = last = callout;
+ while (last->c_next != NULL && last->c_next->c_time == 0)
+ last = last->c_next;
+ callout = last->c_next;
+ last->c_next = NULL;
+
/*
* Set a new itimer if there are more timeouts scheduled.
*/
itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
itv.it_value.tv_usec = 0;
itv.it_value.tv_sec = callout->c_time;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in alrm.",
itv.it_value.tv_sec));
if (setitimer(ITIMER_REAL, &itv, NULL)) {
syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
die(1);
}
}
+
+ /*
+ * Now call all the timeout routines scheduled for this time.
+ */
+ while (list) {
+ (*list->c_func)(list->c_arg);
+ freep = list;
+ list = list->c_next;
+ (void) free((char *) freep);
+ }
+
+}
+
+
+/*
+ * chld - Catch SIGCHLD signal.
+ * Calls reap_kids to get status for any dead kids.
+ */
+static void
+chld(sig)
+ int sig;
+{
+ reap_kids();
}
*
* Indicates that incoming data is available.
*/
-/*ARGSUSED*/
static void
-io(sig, code, scp, addr)
- int sig, code;
- struct sigcontext *scp;
- char *addr;
+io(sig)
+ int sig;
{
int len, i;
u_char *p;
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");
- die(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 beginning of packet buffer */
return;
if (len == 0) {
- syslog(LOG_ERR, "End of file on fd!");
- die(1);
+ MAINDEBUG((LOG_DEBUG, "End of file on fd!"));
+ lcp_lowerdown(0);
+ return;
}
if (debug /*&& (debugflags & DBG_INPACKET)*/)
/*
- * set_up_connection - run a program to initialize the serial connector
+ * device_script - run a program to connect or disconnect the
+ * serial device.
*/
int
-set_up_connection(program, in, out)
+device_script(program, in, out)
char *program;
int in, out;
{
sigprocmask(SIG_BLOCK, &mask, &mask);
pid = fork();
-
+
if (pid < 0) {
syslog(LOG_ERR, "fork: %m");
die(1);
}
-
+
if (pid == 0) {
setreuid(getuid(), getuid());
setregid(getgid(), getgid());
/* NOTREACHED */
}
- while (waitpid(pid, &status, 0) != pid) {
+ while (waitpid(pid, &status, 0) < 0) {
if (errno == EINTR)
continue;
- syslog(LOG_ERR, "waiting for connection process: %m");
+ syslog(LOG_ERR, "waiting for (dis)connection process: %m");
die(1);
}
sigprocmask(SIG_SETMASK, &mask, NULL);
/*
- * Return user specified netmask. A value of zero means no netmask has
- * been set.
+ * run-program - execute a program with given arguments,
+ * but don't wait for it.
+ * If the program can't be executed, logs an error unless
+ * must_exist is 0 and the program file doesn't exist.
*/
-/* ARGSUSED */
-u_long
-GetMask(addr)
- u_long addr;
+int
+run_program(prog, args, must_exist)
+ char *prog;
+ char **args;
+ int must_exist;
{
- return(netmask);
+ int pid;
+
+ pid = fork();
+ if (pid == -1) {
+ syslog(LOG_ERR, "can't fork to run %s: %m", prog);
+ return -1;
+ }
+ if (pid == 0) {
+ execv(prog, args);
+ if (must_exist || errno != ENOENT)
+ syslog(LOG_WARNING, "can't execute %s: %m", prog);
+ _exit(-1);
+ }
+ MAINDEBUG((LOG_DEBUG, "Script %s started; pid = %d", prog, pid));
+ ++n_children;
+ return 0;
}
+
/*
- * setdtr - control the DTR line on the serial port.
- * This is called from die(), so it shouldn't call die().
+ * reap_kids - get status from any dead child processes,
+ * and log a message for abnormal terminations.
*/
-setdtr(fd, on)
-int fd, on;
+void
+reap_kids()
{
- int modembits = TIOCM_DTR;
+ int pid, status;
- ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+ if (n_children == 0)
+ return;
+ if ((pid = waitpid(-1, &status, WNOHANG)) == -1) {
+ if (errno != ECHILD)
+ syslog(LOG_ERR, "waitpid: %m");
+ return;
+ }
+ if (pid > 0) {
+ --n_children;
+ if (WIFSIGNALED(status)) {
+ syslog(LOG_WARNING, "child process %d terminated with signal %d",
+ pid, WTERMSIG(status));
+ }
+ }
}
+
/*
* log_packet - format a packet and log it.
*/