*/
#ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.33 1996/05/28 00:49:10 paulus Exp $";
+static char rcsid[] = "$Id: main.c,v 1.39 1996/10/08 06:43:49 paulus Exp $";
#endif
#include <stdio.h>
#include "pathnames.h"
#include "patchlevel.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
#if defined(SUNOS4)
extern char *strerror();
#endif
#include "ipxcp.h"
#endif /* IPX_CHANGE */
-/*
- * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
- * /etc/ppp/options exists.
- */
-#ifndef REQ_SYSOPTIONS
-#define REQ_SYSOPTIONS 1
-#endif
-
/* interface vars */
char ifname[IFNAMSIZ]; /* Interface name */
int ifunit; /* Interface unit number */
static char default_devnam[MAXPATHLEN]; /* name of default device */
static pid_t pid; /* Our pid */
static uid_t uid; /* Our real user-id */
+static int conn_running; /* we have a [dis]connector running */
int ttyfd = -1; /* Serial port file descriptor */
mode_t tty_mode = -1; /* Original access permissions to tty */
+int baud_rate; /* Actual bits/second for serial device */
+int hungup; /* terminal has been hung up */
+int privileged; /* we're running as real uid root */
+int need_holdoff; /* need holdoff period before restarting */
int phase; /* where the link is at */
int kill_link;
int open_ccp_flag;
+int redirect_stderr; /* Connector's stderr should go to file */
u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
-int hungup; /* terminal has been hung up */
static int n_children; /* # child processes still running */
-int baud_rate; /* Actual bits/second for serial device */
-
static int locked; /* lock() has succeeded */
char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
#define O_NONBLOCK O_NDELAY
#endif
-#ifdef PRIMITIVE_SYSLOG
+#ifdef ULTRIX
#define setlogmask(x)
#endif
&lcp_protent,
&pap_protent,
&chap_protent,
+#ifdef CBCP_SUPPORT
+ &cbcp_protent,
+#endif
&ipcp_protent,
&ccp_protent,
#ifdef IPX_CHANGE
strcpy(default_devnam, devnam);
/* Initialize syslog facilities */
-#ifdef PRIMITIVE_SYSLOG
+#ifdef ULTRIX
openlog("pppd", LOG_PID);
#else
openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
#endif
if (gethostname(hostname, MAXNAMELEN) < 0 ) {
- syslog(LOG_ERR, "couldn't get hostname: %m");
+ option_error("Couldn't get hostname: %m");
die(1);
}
hostname[MAXNAMELEN-1] = 0;
uid = getuid();
+ privileged = uid == 0;
/*
* Initialize to the standard option set, then parse, in order,
- * the system options file, the user's options file, and the command
- * line arguments.
+ * the system options file, the user's options file,
+ * the tty's options file, and the command line arguments.
*/
for (i = 0; (protp = protocols[i]) != NULL; ++i)
(*protp->init)(0);
progname = *argv;
- if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS, 0) ||
- !options_for_tty() ||
- !options_from_user() ||
- !parse_args(argc-1, argv+1))
+ if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
+ || !options_from_user())
+ exit(1);
+ scan_args(argc-1, argv+1); /* look for tty name on command line */
+ if (!options_for_tty()
+ || !parse_args(argc-1, argv+1))
exit(1);
if (!ppp_available()) {
- fprintf(stderr, no_ppp_msg);
+ option_error(no_ppp_msg);
exit(1);
}
+ /*
+ * Check that we are running as root.
+ */
+ if (geteuid() != 0) {
+ option_error("must be root to run %s, since it is not setuid-root",
+ argv[0]);
+ die(1);
+ }
+
/*
* Check that the options given are valid and consistent.
*/
if (protp->check_options != NULL)
(*protp->check_options)();
if (demand && connector == 0) {
- fprintf(stderr, "%s: connect script required for demand-dialling\n",
- progname);
+ option_error("connect script required for demand-dialling\n");
exit(1);
}
*/
if (!default_device && strcmp(devnam, default_devnam) == 0)
default_device = 1;
+ redirect_stderr = !nodetach || default_device;
/*
* Initialize system-dependent stuff and magic number package.
for (;;) {
+ need_holdoff = 1;
+
if (demand) {
/*
* Don't do anything until we see some activity.
get_input();
if (kill_link) {
lcp_close(0, "User request");
- phase = PHASE_TERMINATE;
kill_link = 0;
}
if (open_ccp_flag) {
if (phase == PHASE_NETWORK) {
ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
- ccp_open(0);
+ (*ccp_protent.open)(0);
}
open_ccp_flag = 0;
}
}
if (!demand) {
- if (unlink(pidfilename) < 0 && errno != ENOENT)
+ if (pidfilename[0] != 0
+ && unlink(pidfilename) < 0 && errno != ENOENT)
syslog(LOG_WARNING, "unable to delete pid file: %m");
pidfilename[0] = 0;
}
if (demand)
demand_discard();
- if (holdoff > 0) {
+ if (holdoff > 0 && need_holdoff) {
phase = PHASE_HOLDOFF;
TIMEOUT(holdoff_end, NULL, holdoff);
do {
caddr_t arg;
{
syslog(LOG_INFO, "Connect time expired");
-
- phase = PHASE_TERMINATE;
lcp_close(0, "Connect time expired"); /* Close connection */
}
return tvp;
}
-
+
+
+/*
+ * kill_my_pg - send a signal to our process group, and ignore it ourselves.
+ */
+static void
+kill_my_pg(sig)
+ int sig;
+{
+ struct sigaction act, oldact;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigaction(sig, &act, &oldact);
+ kill(-getpgrp(), sig);
+ sigaction(sig, &oldact, NULL);
+}
+
/*
* hup - Catch SIGHUP signal.
{
syslog(LOG_INFO, "Hangup (SIGHUP)");
kill_link = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
}
syslog(LOG_INFO, "Terminating on signal %d.", sig);
persist = 0; /* don't try to restart */
kill_link = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
}
int sig;
{
syslog(LOG_ERR, "Fatal signal %d", sig);
+ if (conn_running)
+ kill_my_pg(SIGTERM);
die(1);
}
int status;
int errfd;
+ conn_running = 1;
pid = fork();
if (pid < 0) {
+ conn_running = 0;
syslog(LOG_ERR, "Failed to create child process: %m");
die(1);
}
if (pid == 0) {
sys_close();
closelog();
- dup2(in, 0);
- dup2(out, 1);
- errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
- if (errfd >= 0)
- dup2(errfd, 2);
+ if (in == out) {
+ if (in != 0) {
+ dup2(in, 0);
+ close(in);
+ }
+ dup2(0, 1);
+ } else {
+ if (out == 0)
+ out = dup(out);
+ if (in != 0) {
+ dup2(in, 0);
+ close(in);
+ }
+ if (out != 1) {
+ dup2(out, 1);
+ close(out);
+ }
+ }
+ if (redirect_stderr) {
+ close(2);
+ errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ if (errfd >= 0 && errfd != 2) {
+ dup2(errfd, 2);
+ close(errfd);
+ }
+ }
setuid(getuid());
setgid(getgid());
execl("/bin/sh", "sh", "-c", program, (char *)0);
syslog(LOG_ERR, "error waiting for (dis)connection process: %m");
die(1);
}
+ conn_running = 0;
return (status == 0 ? 0 : -1);
}
}
static void
-#if __STDC__
-pr_log(void *arg, char *fmt, ...)
-#else
-pr_log(va_alist)
- va_dcl
-#endif
+pr_log __V((void *arg, char *fmt, ...))
{
int n;
va_list pvar;
printer(arg, "\"");
for (; len > 0; --len) {
c = *p++;
- if (' ' <= c && c <= '~')
+ if (' ' <= c && c <= '~') {
+ if (c == '\\' || c == '"')
+ printer(arg, "\\");
printer(arg, "%c", c);
- else
- printer(arg, "\\%.3o", c);
+ } else {
+ switch (c) {
+ case '\n':
+ printer(arg, "\\n");
+ break;
+ case '\r':
+ printer(arg, "\\r");
+ break;
+ case '\t':
+ printer(arg, "\\t");
+ break;
+ default:
+ printer(arg, "\\%.3o", c);
+ }
+ }
}
printer(arg, "\"");
}
/*
* vfmtmsg - like fmtmsg, takes a va_list instead of a list of args.
*/
+#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
+
int
-vfmtmsg(char *buf, int buflen, char *fmt, va_list args)
+vfmtmsg(buf, buflen, fmt, args)
+ char *buf;
+ int buflen;
+ char *fmt;
+ va_list args;
{
int c, i, n;
- int width, prec;
- int base, len, neg;
+ int width, prec, fillch;
+ int base, len, neg, quoted;
unsigned long val;
char *str, *f, *buf0;
- va_list a;
+ unsigned char *p;
+ void *a;
char num[32];
- static char hexchars[16] = "0123456789abcdef";
+ time_t t;
+ static char hexchars[] = "0123456789abcdef";
buf0 = buf;
--buflen;
break;
c = *++fmt;
width = prec = 0;
- while (isdigit(c)) {
- width = width * 10 + c - '0';
+ fillch = ' ';
+ if (c == '0') {
+ fillch = '0';
c = *++fmt;
}
- if (c == '.') {
+ if (c == '*') {
+ width = va_arg(args, int);
c = *++fmt;
+ } else {
while (isdigit(c)) {
- prec = prec * 10 + c - '0';
+ width = width * 10 + c - '0';
c = *++fmt;
}
}
+ if (c == '.') {
+ c = *++fmt;
+ if (c == '*') {
+ prec = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ prec = prec * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ }
str = 0;
base = 0;
neg = 0;
break;
case 'r':
f = va_arg(args, char *);
- a = va_arg(args, va_list);
+ /*
+ * XXX We assume a va_list is either a pointer or an array, so
+ * what gets passed for a va_list is like a void * in some sense.
+ */
+ a = va_arg(args, void *);
n = vfmtmsg(buf, buflen + 1, f, a);
buf += n;
buflen -= n;
continue;
+ case 't':
+ time(&t);
+ str = ctime(&t);
+ str += 4; /* chop off the day name */
+ str[15] = 0; /* chop off year and newline */
+ break;
+ case 'v': /* "visible" string */
+ case 'q': /* quoted string */
+ quoted = c == 'q';
+ p = va_arg(args, unsigned char *);
+ if (fillch == '0' && prec > 0) {
+ n = prec;
+ } else {
+ n = strlen((char *)p);
+ if (prec > 0 && prec < n)
+ n = prec;
+ }
+ while (n > 0 && buflen > 0) {
+ c = *p++;
+ --n;
+ if (!quoted && c >= 0x80) {
+ OUTCHAR('M');
+ OUTCHAR('-');
+ c -= 0x80;
+ }
+ if (quoted && (c == '"' || c == '\\'))
+ OUTCHAR('\\');
+ if (c < 0x20 || 0x7f <= c && c < 0xa0) {
+ if (quoted) {
+ OUTCHAR('\\');
+ switch (c) {
+ case '\t': OUTCHAR('t'); break;
+ case '\n': OUTCHAR('n'); break;
+ case '\b': OUTCHAR('b'); break;
+ case '\f': OUTCHAR('f'); break;
+ default:
+ OUTCHAR('x');
+ OUTCHAR(hexchars[c >> 4]);
+ OUTCHAR(hexchars[c & 0xf]);
+ }
+ } else {
+ if (c == '\t')
+ OUTCHAR(c);
+ else {
+ OUTCHAR('^');
+ OUTCHAR(c ^ 0x40);
+ }
+ }
+ } else
+ OUTCHAR(c);
+ }
+ continue;
default:
*buf++ = '%';
if (c != '%')
if ((n = width - len) > 0) {
buflen -= n;
for (; n > 0; --n)
- *buf++ = ' ';
+ *buf++ = fillch;
}
}
if (len > buflen)