*/
#ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.51 1999/04/12 06:24:44 paulus Exp $";
+static char rcsid[] = "$Id: auth.c,v 1.52 1999/05/12 06:19:46 paulus Exp $";
#endif
#include <stdio.h>
if (!wo->neg_upap || !null_login(unit)) {
warn("peer refused to authenticate: terminating link");
lcp_close(unit, "peer refused to authenticate");
+ status = EXIT_PEER_AUTH_FAILED;
return;
}
}
* Authentication failure: take the link down
*/
lcp_close(unit, "Authentication failed");
+ status = EXIT_PEER_AUTH_FAILED;
}
/*
* At this point we consider that the link has come up successfully.
*/
need_holdoff = 0;
+ status = EXIT_OK;
if (idle_time_limit > 0)
TIMEOUT(check_idle, NULL, idle_time_limit);
/* link is idle: shut it down. */
notice("Terminating connection due to lack of activity.");
lcp_close(0, "Link inactive");
+ status = EXIT_IDLE_TIMEOUT;
} else {
TIMEOUT(check_idle, NULL, idle_time_limit - itime);
}
{
info("Connect time expired");
lcp_close(0, "Connect time expired"); /* Close connection */
+ status = EXIT_CONNECT_TIME;
}
/*
*/
#ifndef lint
-static char rcsid[] = "$Id: cbcp.c,v 1.6 1999/03/16 22:54:38 paulus Exp $";
+static char rcsid[] = "$Id: cbcp.c,v 1.7 1999/05/12 06:19:46 paulus Exp $";
#endif
#include <stdio.h>
if (address[0])
dbglog("peer will call: %s", address);
}
+ if (type == CB_CONF_NO)
+ return;
}
cbcp_up(us);
{
persist = 0;
lcp_close(0, "Call me back, please");
+ status = EXIT_CALLBACK;
}
*/
#ifndef lint
-static char rcsid[] = "$Id: lcp.c,v 1.38 1999/04/16 11:35:43 paulus Exp $";
+static char rcsid[] = "$Id: lcp.c,v 1.39 1999/05/12 06:19:47 paulus Exp $";
#endif
/*
info("No response to %d echo-requests", lcp_echos_pending);
notice("Serial link appears to be disconnected.");
lcp_close(f->unit, "Peer not responding");
+ status = EXIT_PEER_DEAD;
}
}
*/
#ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.77 1999/04/28 02:45:44 paulus Exp $";
+static char rcsid[] = "$Id: main.c,v 1.78 1999/05/12 06:19:47 paulus Exp $";
#endif
#include <stdio.h>
#include "cbcp.h"
#endif
-#if defined(SUNOS4)
-extern char *strerror();
-#endif
-
#ifdef IPX_CHANGE
#include "ipxcp.h"
#endif /* IPX_CHANGE */
int privileged; /* we're running as real uid root */
int need_holdoff; /* need holdoff period before restarting */
int detached; /* have detached from terminal */
-int log_to_fd; /* send log messages to this fd too */
+struct stat devstat; /* result of stat() on devnam */
+int prepass = 0; /* doing prepass to find device name */
+volatile int status; /* exit status for pppd */
static int fd_ppp = -1; /* fd for talking PPP */
static int fd_loop; /* fd for getting demand-dial packets */
static int got_sigchld; /* set if we have received a SIGCHLD */
static int locked; /* lock() has succeeded */
+static int privopen; /* don't lock, open device as root */
char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
struct timeval now;
phase = PHASE_INITIALIZE;
- log_to_fd = -1;
/*
* Ensure that fds 0, 1, 2 are open, to /dev/null if nowhere else.
progname = *argv;
+ prepass = 0;
if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
|| !options_from_user())
- exit(1);
- using_pty = notty || ptycommand != NULL;
- scan_args(argc-1, argv+1); /* look for tty name on command line */
+ exit(EXIT_OPTION_ERROR);
+
+ /* scan command line and options files to find device name */
+ prepass = 1;
+ parse_args(argc-1, argv+1);
+ prepass = 0;
/*
* Work out the device name, if it hasn't already been specified.
*/
- if (!using_pty) {
- p = isatty(0)? ttyname(0): NULL;
- if (p != NULL) {
- if (default_device)
- strlcpy(devnam, p, sizeof(devnam));
- else if (strcmp(devnam, p) == 0)
- default_device = 1;
+ using_pty = notty || ptycommand != NULL;
+ if (!using_pty && default_device) {
+ char *p;
+ if (!isatty(0) || (p = ttyname(0)) == NULL) {
+ option_error("no device specified and stdin is not a tty");
+ exit(EXIT_OPTION_ERROR);
}
+ strlcpy(devnam, p, sizeof(devnam));
+ if (stat(devnam, &devstat) < 0)
+ fatal("Couldn't stat default device %s: %m", devnam);
}
/*
* Parse the tty options file and the command line.
+ * The per-tty options file should not change
+ * ptycommand, notty or devnam.
*/
- if (!options_for_tty()
- || !parse_args(argc-1, argv+1))
- exit(1);
+ if (!using_pty) {
+ int save_defdev = default_device;
+
+ default_device = 1;
+ if (!options_for_tty())
+ exit(EXIT_OPTION_ERROR);
+ if (notty || ptycommand != NULL) {
+ option_error("%s option may not be used in per-tty options file",
+ notty? "notty": "pty");
+ exit(EXIT_OPTION_ERROR);
+ }
+ if (!default_device) {
+ option_error("per-tty options file may not specify device name");
+ exit(EXIT_OPTION_ERROR);
+ }
+ default_device = save_defdev;
+ }
+
+ if (!parse_args(argc-1, argv+1))
+ exit(EXIT_OPTION_ERROR);
/*
* 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]);
- exit(1);
+ exit(EXIT_NOT_ROOT);
}
if (!ppp_available()) {
option_error(no_ppp_msg);
- exit(1);
+ exit(EXIT_NO_KERNEL_SUPPORT);
}
/*
* Check that the options given are valid and consistent.
*/
if (!sys_check_options())
- exit(1);
+ exit(EXIT_OPTION_ERROR);
auth_check_options();
for (i = 0; (protp = protocols[i]) != NULL; ++i)
if (protp->check_options != NULL)
(*protp->check_options)();
if (demand && connector == 0) {
option_error("connect script is required for demand-dialling\n");
- exit(1);
+ exit(EXIT_OPTION_ERROR);
}
if (using_pty) {
if (!default_device) {
option_error("%s option precludes specifying device name",
notty? "notty": "pty");
- exit(1);
+ exit(EXIT_OPTION_ERROR);
}
if (ptycommand != NULL && notty) {
option_error("pty option is incompatible with notty option");
- exit(1);
+ exit(EXIT_OPTION_ERROR);
}
default_device = notty;
lockflag = 0;
modem = 0;
+ if (notty && log_to_fd <= 1)
+ log_to_fd = -1;
} else {
- if (devnam[0] == 0) {
- option_error("no device specified and stdin is not a tty");
- exit(1);
+ /*
+ * If the user has specified a device which is the same as
+ * the one on stdin, pretend they didn't specify any.
+ * If the device is already open read/write on stdin,
+ * we assume we don't need to lock it, and we can open it as root.
+ */
+ if (fstat(0, &statbuf) >= 0 && S_ISCHR(statbuf.st_mode)
+ && statbuf.st_rdev == devstat.st_rdev) {
+ default_device = 1;
+ fdflags = fcntl(0, F_GETFL);
+ if (fdflags != -1 && (fdflags & O_ACCMODE) == O_RDWR)
+ privopen = 1;
}
}
if (default_device)
nodetach = 1;
- else
- log_to_fd = 1; /* default to stdout */
+
+ /*
+ * Don't send log messages to the serial port, it tends to
+ * confuse the peer. :-)
+ */
+ if (log_to_fd >= 0 && fstat(log_to_fd, &statbuf) >= 0
+ && S_ISCHR(statbuf.st_mode) && statbuf.st_rdev == devstat.st_rdev)
+ log_to_fd = -1;
script_setenv("DEVICE", devnam);
need_holdoff = 1;
ttyfd = -1;
real_ttyfd = -1;
+ status = EXIT_OK;
if (demand) {
/*
if (ptycommand != NULL || notty || record_file != NULL) {
if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {
error("Couldn't allocate pseudo-tty");
+ status = EXIT_FATAL_ERROR;
goto fail;
}
set_up_tty(pty_slave, 1);
/*
* Lock the device if we've been asked to.
*/
- if (lockflag && !default_device) {
+ status = EXIT_LOCK_FAILED;
+ if (lockflag && !privopen) {
if (lock(devnam) < 0)
goto fail;
locked = 1;
/* If the user specified the device name, become the
user before opening it. */
int err;
- if (!devnam_info.priv && !default_device)
+ if (!devnam_info.priv && !privopen)
seteuid(uid);
ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
- if (!devnam_info.priv && !default_device)
+ if (!devnam_info.priv && !privopen)
seteuid(0);
if (ttyfd >= 0)
break;
errno = err;
- if (err != EINTR)
+ if (err != EINTR) {
error("Failed to open %s: %m", devnam);
+ status = EXIT_OPEN_FAILED;
+ }
if (!persist || err != EINTR)
goto fail;
}
* If the notty and/or record option was specified,
* start up the character shunt now.
*/
+ status = EXIT_PTYCMD_FAILED;
if (ptycommand != NULL) {
if (record_file != NULL) {
int ipipe[2], opipe[2], ok;
if (device_script(connector, ttyfd, ttyfd, 0) < 0) {
error("Connect script failed");
+ status = EXIT_CONNECT_FAILED;
goto fail;
}
if (kill_link)
for (;;) {
if ((i = open(devnam, O_RDWR)) >= 0)
break;
- if (errno != EINTR)
+ if (errno != EINTR) {
error("Failed to reopen %s: %m", devnam);
+ status = EXIT_OPEN_FAILED;
+ }
if (!persist || errno != EINTR || hungup || kill_link)
goto fail;
}
/* set up the serial device as a ppp interface */
fd_ppp = establish_ppp(ttyfd);
- if (fd_ppp < 0)
+ if (fd_ppp < 0) {
+ status = EXIT_FATAL_ERROR;
goto disconnect;
+ }
if (!demand) {
lcp_open(0); /* Start protocol */
open_ccp_flag = 0;
add_fd(fd_ppp);
+ status = EXIT_NEGOTIATION_FAILED;
for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) {
if (sigsetjmp(sigjmp, 1) == 0) {
sigprocmask(SIG_BLOCK, &mask, NULL);
reap_kids(1);
}
- die(0);
+ die(status);
return 0;
}
if (len == 0) {
notice("Modem hangup");
hungup = 1;
+ status = EXIT_HANGUP;
lcp_lowerdown(0); /* serial link is no longer available */
link_terminated(0);
return;
{
info("Hangup (SIGHUP)");
kill_link = 1;
+ if (status != EXIT_HANGUP)
+ status = EXIT_USER_REQUEST;
if (conn_running)
/* Send the signal to the [dis]connector process(es) also */
kill_my_pg(sig);
info("Terminating on signal %d.", sig);
persist = 0; /* don't try to restart */
kill_link = 1;
+ status = EXIT_USER_REQUEST;
if (conn_running)
/* Send the signal to the [dis]connector process(es) also */
kill_my_pg(sig);
kill_my_pg(SIGTERM);
if (charshunt_pid)
kill(charshunt_pid, SIGTERM);
- die(1);
+ die(127);
}
*/
#ifndef lint
-static char rcsid[] = "$Id: options.c,v 1.57 1999/04/12 06:24:47 paulus Exp $";
+static char rcsid[] = "$Id: options.c,v 1.58 1999/05/12 06:19:48 paulus Exp $";
#endif
#include <ctype.h>
char *record_file = NULL; /* File to record chars sent/received */
int using_pty = 0;
bool sync_serial = 0; /* Device is synchronous serial device */
+int log_to_fd = 1; /* send log messages to this fd too */
extern option_t auth_options[];
+extern struct stat devstat;
+extern int prepass; /* Doing pre-pass to find device name */
struct option_info connector_info;
struct option_info disconnector_info;
/*
* Prototypes
*/
-static int setdevname __P((char *, int));
+static int setdevname __P((char *));
static int setipaddr __P((char *));
static int setspeed __P((char *));
static int noopt __P((char **));
OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
{ "pty", o_string, &ptycommand,
"Script to run on pseudo-tty master side",
- OPT_A2INFO | OPT_PRIVFIX, &ptycommand_info },
+ OPT_A2INFO | OPT_PRIVFIX | OPT_PREPASS, &ptycommand_info },
{ "notty", o_bool, ¬ty,
- "Input/output is not a tty", 1 },
+ "Input/output is not a tty", OPT_PREPASS | 1 },
{ "record", o_string, &record_file,
"Record characters sent/received to file" },
{ "maxconnect", o_int, &maxconnect,
{ "local", o_bool, &modem,
"Don't use modem control lines" },
{ "file", o_special, readfile,
- "Take options from a file" },
+ "Take options from a file", OPT_PREPASS },
{ "call", o_special, callfile,
- "Take options from a privileged file" },
+ "Take options from a privileged file", OPT_PREPASS },
{ "persist", o_bool, &persist,
"Keep on reopening connection after close", 1 },
{ "nopersist", o_bool, &persist,
"Show brief listing of options" },
{ "sync", o_bool, &sync_serial,
"Use synchronous HDLC serial encoding", 1 },
+ { "logfd", o_int, &log_to_fd,
+ "Send log messages to this file descriptor" },
+ { "nologfd", o_int, &log_to_fd,
+ "Don't send log messages to any file descriptor",
+ OPT_NOARG | OPT_VAL(-1) },
#ifdef PPP_FILTER
{ "pdebug", o_int, &dflag,
/*
* parse_args - parse a string of arguments from the command line.
+ * If prepass is true, we are scanning for the device name and only
+ * processing a few options, so error messages are suppressed.
*/
int
parse_args(argc, argv)
/*
* Maybe a tty name, speed or IP address?
*/
- if ((ret = setdevname(arg, 0)) == 0
+ if ((ret = setdevname(arg)) == 0
&& (ret = setspeed(arg)) == 0
&& (ret = setipaddr(arg)) == 0) {
option_error("unrecognized option '%s'", arg);
return 1;
}
+#if 0
/*
* scan_args - scan the command line arguments to get the tty name,
* if specified. Also checks whether the notty or pty option was given.
(void) setdevname(arg, 1);
}
}
+#endif
/*
* options_from_file - Read a string of options from a file,
/*
* Maybe a tty name, speed or IP address?
*/
- if ((i = setdevname(cmd, 0)) == 0
+ if ((i = setdevname(cmd)) == 0
&& (i = setspeed(cmd)) == 0
&& (i = setipaddr(cmd)) == 0) {
option_error("In file %s: unrecognized option '%s'",
char *sv;
int (*parser) __P((char **));
+ if (prepass && (opt->flags & OPT_PREPASS) == 0)
+ return 1;
+
if ((opt->flags & OPT_PRIV) && !privileged_option) {
option_error("using the %s option requires root privilege", opt->name);
return 0;
va_start(args);
fmt = va_arg(args, char *);
#endif
+ if (prepass) {
+ va_end(args);
+ return;
+ }
vslprintf(buf, sizeof(buf), fmt, args);
va_end(args);
if (phase == PHASE_INITIALIZE)
* setdevname - Set the device name.
*/
static int
-setdevname(cp, quiet)
+setdevname(cp)
char *cp;
- int quiet;
{
struct stat statbuf;
char dev[MAXPATHLEN];
}
/*
- * Check if there is a device by this name.
+ * Check if there is a character device by this name.
*/
if (stat(cp, &statbuf) < 0) {
- if (errno == ENOENT || quiet)
+ if (errno == ENOENT)
return 0;
option_error("Couldn't stat %s: %m", cp);
return -1;
}
+ if (!S_ISCHR(statbuf.st_mode)) {
+ option_error("%s is not a character device", cp);
+ return -1;
+ }
if (devnam_info.priv && !privileged_option) {
- if (!quiet)
- option_error("device name cannot be overridden");
+ option_error("device name cannot be overridden");
return -1;
}
strlcpy(devnam, cp, sizeof(devnam));
+ devstat = statbuf;
default_device = 0;
devnam_info.priv = privileged_option;
devnam_info.source = option_source;
*/
if ((colon = strchr(arg, ':')) == NULL)
return 0;
+ if (prepass)
+ return 1;
/*
* If colon first character, then no local addr.
-/* $Id: patchlevel.h,v 1.40 1999/04/16 11:49:30 paulus Exp $ */
+/* $Id: patchlevel.h,v 1.41 1999/05/12 06:19:48 paulus Exp $ */
#define PATCHLEVEL 8
#define VERSION "2.3"
-#define IMPLEMENTATION "alpha"
-#define DATE "16 April 1999"
+#define IMPLEMENTATION ""
+#define DATE "12 May 1999"
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id: pppd.h,v 1.38 1999/04/12 06:24:47 paulus Exp $
+ * $Id: pppd.h,v 1.39 1999/05/12 06:19:49 paulus Exp $
*/
/*
#include <varargs.h>
#define __V(x) (va_alist) va_dcl
#define const
+#define volatile
#endif
/*
#define OPT_A2COPY 0x200000 /* addr2 -> second location to rcv value */
#define OPT_ENABLE 0x400000 /* use *addr2 as enable for option */
#define OPT_PRIVFIX 0x800000 /* can't be overridden if noauth */
+#define OPT_PREPASS 0x1000000/* do this opt in pre-pass to find device */
#define OPT_VAL(x) ((x) & OPT_VALUE)
extern int using_pty; /* using pty as device (notty or pty opt.) */
extern int log_to_fd; /* logging to this fd as well as syslog */
extern char *no_ppp_msg; /* message to print if ppp not in kernel */
+extern volatile int status; /* exit status for pppd */
/*
* Variables set by command-line options.
PUTCHAR(PPP_UI, p); \
PUTSHORT(t, p); }
+/*
+ * Exit status values.
+ */
+#define EXIT_OK 0
+#define EXIT_FATAL_ERROR 1
+#define EXIT_OPTION_ERROR 2
+#define EXIT_NOT_ROOT 3
+#define EXIT_NO_KERNEL_SUPPORT 4
+#define EXIT_USER_REQUEST 5
+#define EXIT_LOCK_FAILED 6
+#define EXIT_OPEN_FAILED 7
+#define EXIT_CONNECT_FAILED 8
+#define EXIT_PTYCMD_FAILED 9
+#define EXIT_NEGOTIATION_FAILED 10
+#define EXIT_PEER_AUTH_FAILED 11
+#define EXIT_IDLE_TIMEOUT 12
+#define EXIT_CONNECT_TIME 13
+#define EXIT_CALLBACK 14
+#define EXIT_PEER_DEAD 15
+#define EXIT_HANGUP 16
+/*
+ * Debug macros. Slightly useful for finding bugs in pppd, not particularly
+ * useful for finding out why your connection isn't being established.
+ */
#ifdef DEBUGALL
#define DEBUGMAIN 1
#define DEBUGFSM 1