* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#ifndef lint
-static const char rcsid[] = "$Id: options.c,v 1.61 1999/08/12 04:17:07 paulus Exp $";
-#endif
+#define RCSID "$Id: options.c,v 1.76 2000/08/01 01:38:30 paulus Exp $"
#include <ctype.h>
#include <stdio.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#ifdef PLUGIN
+#include <dlfcn.h>
+#endif
#ifdef PPP_FILTER
#include <pcap.h>
#include <pcap-int.h> /* XXX: To get struct pcap */
char *strdup __P((char *));
#endif
+static const char rcsid[] = RCSID;
+
/*
* Option variables and default values.
*/
int kdebugflag = 0; /* Tell kernel to print debug messages */
int default_device = 1; /* Using /dev/tty or equivalent */
char devnam[MAXPATHLEN]; /* Device name */
-int crtscts = 0; /* Use hardware flow control */
-bool modem = 1; /* Use modem control lines */
-int inspeed = 0; /* Input/Output speed requested */
u_int32_t netmask = 0; /* IP netmask to set on interface */
-bool lockflag = 0; /* Create lock file to lock the serial dev */
bool nodetach = 0; /* Don't detach from controlling tty */
bool updetach = 0; /* Detach once link is up */
-char *initializer = NULL; /* Script to initialize physical link */
-char *connector = NULL; /* Script to establish physical link */
-char *disconnector = NULL; /* Script to disestablish physical link */
-char *welcomer = NULL; /* Script to run after phys link estab. */
-char *ptycommand = NULL; /* Command to run on other side of pty */
int maxconnect = 0; /* Maximum connect time */
char user[MAXNAMELEN]; /* Username for PAP */
char passwd[MAXSECRETLEN]; /* Password for PAP */
char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
int holdoff = 30; /* # seconds to pause before reconnecting */
-bool notty = 0; /* Stdin/out is not a tty */
-char *record_file = NULL; /* File to record chars sent/received */
-int using_pty = 0;
-bool sync_serial = 0; /* Device is synchronous serial device */
+bool holdoff_specified; /* true if a holdoff value has been given */
int log_to_fd = 1; /* send log messages to this fd too */
-int maxfail; /* max # of unsuccessful connection attempts */
+int maxfail = 10; /* max # of unsuccessful connection attempts */
+char linkname[MAXPATHLEN]; /* logical name for link */
+bool tune_kernel; /* may alter kernel settings */
+int connect_delay = 1000; /* wait this many ms after connect script */
+int req_unit = -1; /* requested interface unit */
+bool multilink = 0; /* Enable multilink operation */
+char *bundle_name = NULL; /* bundle name for multilink */
extern option_t auth_options[];
extern struct stat devstat;
-extern int prepass; /* Doing pre-pass to find device name */
struct option_info initializer_info;
-struct option_info connector_info;
-struct option_info disconnector_info;
+struct option_info connect_script_info;
+struct option_info disconnect_script_info;
struct option_info welcomer_info;
struct option_info devnam_info;
struct option_info ptycommand_info;
int privileged_option; /* set iff the current option came from root */
char *option_source; /* string saying where the option came from */
bool log_to_file; /* log_to_fd is a file opened by us */
+bool log_to_specific_fd; /* log_to_fd was specified by user option */
+bool no_override; /* don't override previously-set options */
/*
* Prototypes
static int noopt __P((char **));
static int setdomain __P((char **));
static int setnetmask __P((char **));
-static int setxonxoff __P((char **));
static int readfile __P((char **));
static int callfile __P((char **));
static int showversion __P((char **));
static int showhelp __P((char **));
static void usage __P((void));
static int setlogfile __P((char **));
+#ifdef PLUGIN
+static int loadplugin __P((char **));
+#endif
#ifdef PPP_FILTER
static int setpassfilter __P((char **));
static int setactivefilter __P((char **));
#endif
-
static option_t *find_option __P((char *name));
static int process_option __P((option_t *, char **));
static int n_arguments __P((option_t *));
static int number_option __P((char *, u_int32_t *, int));
+/*
+ * Structure to store extra lists of options.
+ */
+struct option_list {
+ option_t *options;
+ struct option_list *next;
+};
+
+static struct option_list *extra_options = NULL;
+
/*
* Valid arguments.
*/
"Set time in seconds before retrying connection" },
{ "idle", o_int, &idle_time_limit,
"Set time in seconds before disconnecting idle link" },
- { "lock", o_bool, &lockflag,
- "Lock serial device with UUCP-style lock file", 1 },
- { "-all", o_special_noarg, noopt,
+ { "-all", o_special_noarg, (void *)noopt,
"Don't request/allow any LCP or IPCP options (useless)" },
- { "init", o_string, &initializer,
- "A program to initialize the device",
- OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
- { "connect", o_string, &connector,
- "A program to set up a connection",
- OPT_A2INFO | OPT_PRIVFIX, &connector_info },
- { "disconnect", o_string, &disconnector,
- "Program to disconnect serial device",
- OPT_A2INFO | OPT_PRIVFIX, &disconnector_info },
- { "welcome", o_string, &welcomer,
- "Script to welcome client",
- OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
- { "pty", o_string, &ptycommand,
- "Script to run on pseudo-tty master side",
- OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
- { "notty", o_bool, ¬ty,
- "Input/output is not a tty", OPT_DEVNAM | 1 },
- { "record", o_string, &record_file,
- "Record characters sent/received to file" },
{ "maxconnect", o_int, &maxconnect,
"Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
- { "crtscts", o_int, &crtscts,
- "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
- { "nocrtscts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
- { "-crtscts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
- { "cdtrcts", o_int, &crtscts,
- "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
- { "nocdtrcts", o_int, &crtscts,
- "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
- { "xonxoff", o_special_noarg, setxonxoff,
- "Set software (XON/XOFF) flow control" },
- { "domain", o_special, setdomain,
+ { "domain", o_special, (void *)setdomain,
"Add given domain name to hostname" },
{ "mtu", o_int, &lcp_allowoptions[0].mru,
"Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
- { "netmask", o_special, setnetmask,
+ { "netmask", o_special, (void *)setnetmask,
"set netmask" },
- { "modem", o_bool, &modem,
- "Use modem control lines", 1 },
- { "local", o_bool, &modem,
- "Don't use modem control lines" },
- { "file", o_special, readfile,
+ { "file", o_special, (void *)readfile,
"Take options from a file", OPT_PREPASS },
- { "call", o_special, callfile,
+ { "call", o_special, (void *)callfile,
"Take options from a privileged file", OPT_PREPASS },
{ "persist", o_bool, &persist,
"Keep on reopening connection after close", 1 },
"Turn off persist option" },
{ "demand", o_bool, &demand,
"Dial on demand", OPT_INITONLY | 1, &persist },
- { "--version", o_special_noarg, showversion,
+ { "--version", o_special_noarg, (void *)showversion,
"Show version number" },
- { "--help", o_special_noarg, showhelp,
+ { "--help", o_special_noarg, (void *)showhelp,
"Show brief listing of options" },
- { "-h", o_special_noarg, showhelp,
+ { "-h", o_special_noarg, (void *)showhelp,
"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" },
- { "logfile", o_special, setlogfile,
+ "Send log messages to this file descriptor",
+ 0, &log_to_specific_fd },
+ { "logfile", o_special, (void *)setlogfile,
"Append log messages to this file" },
{ "nolog", o_int, &log_to_fd,
"Don't send log messages to any file",
{ "nologfd", o_int, &log_to_fd,
"Don't send log messages to any file descriptor",
OPT_NOARG | OPT_VAL(-1) },
+ { "linkname", o_string, linkname,
+ "Set logical name for link",
+ OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
{ "maxfail", o_int, &maxfail,
"Maximum number of unsuccessful connection attempts to allow" },
+ { "ktune", o_bool, &tune_kernel,
+ "Alter kernel settings as necessary", 1 },
+ { "noktune", o_bool, &tune_kernel,
+ "Don't alter kernel settings", 0 },
+ { "connect-delay", o_int, &connect_delay,
+ "Maximum time (in ms) to wait after connect script finishes" },
+ { "unit", o_int, &req_unit,
+ "PPP interface unit number to use if possible", OPT_LLIMIT, 0, 0 },
+#ifdef HAVE_MULTILINK
+ { "multilink", o_bool, &multilink,
+ "Enable multilink operation", 1 },
+ { "nomultilink", o_bool, &multilink,
+ "Disable multilink operation", 0 },
+ { "mp", o_bool, &multilink,
+ "Enable multilink operation", 1 },
+ { "nomp", o_bool, &multilink,
+ "Disable multilink operation", 0 },
+ { "bundle", o_string, &bundle_name,
+ "Bundle name for multilink" },
+#endif /* HAVE_MULTILINK */
+#ifdef PLUGIN
+ { "plugin", o_special, (void *)loadplugin,
+ "Load a plug-in module into pppd", OPT_PRIV },
+#endif
#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)
if (check_prot)
seteuid(0);
if (f == NULL) {
- if (!must_exist && err == ENOENT)
- return 1;
errno = err;
+ if (!must_exist) {
+ if (err != ENOENT && err != ENOTDIR)
+ warn("Warning: can't open options file %s: %m", filename);
+ return 1;
+ }
option_error("Can't open options file %s: %m", filename);
return 0;
}
argv[i] = args[i];
}
current_option = cmd;
- if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
+ if ((opt->flags & OPT_DEVEQUIV) && no_override) {
option_error("the %s option may not be used in the %s file",
cmd, filename);
goto err;
/*
* options_for_tty - See if an options file exists for the serial
* device, and if so, interpret options from it.
+ * We only allow the per-tty options file to override anything from
+ * the command line if it is something that the user can't override
+ * once it has been set by root.
*/
int
options_for_tty()
for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
if (*p == '/')
*p = '.';
+ no_override = 1;
ret = options_from_file(path, 0, 0, 1);
+ no_override = 0;
free(path);
return ret;
}
char *name;
{
option_t *opt;
+ struct option_list *list;
int i;
+ for (list = extra_options; list != NULL; list = list->next)
+ for (opt = list->options; opt->name != NULL; ++opt)
+ if (strcmp(name, opt->name) == 0)
+ return opt;
for (opt = general_options; opt->name != NULL; ++opt)
if (strcmp(name, opt->name) == 0)
return opt;
char *sv;
int (*parser) __P((char **));
- if ((opt->flags & OPT_PREPASS) == 0 && prepass)
- return 1;
+ if (no_override && (opt->flags & OPT_SEENIT)) {
+ struct option_info *ip = (struct option_info *) opt->addr2;
+ if (!(privileged && (opt->flags & OPT_PRIVFIX)))
+ return 1;
+ if (!ip || ip->priv)
+ return 1;
+ warn("%s option from per-tty file overrides command line", opt->name);
+ }
if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
option_error("it's too late to use the %s option", opt->name);
return 0;
return 0;
}
}
+ opt->flags |= OPT_SEENIT;
switch (opt->type) {
case o_bool:
|| (opt->flags & OPT_NOARG))? 0: 1;
}
+/*
+ * add_options - add a list of options to the set we grok.
+ */
+void
+add_options(opt)
+ option_t *opt;
+{
+ struct option_list *list;
+
+ list = malloc(sizeof(*list));
+ if (list == 0)
+ novm("option list entry");
+ list->options = opt;
+ list->next = extra_options;
+ extra_options = list;
+}
+
/*
* usage - print out a message telling how to use the program.
*/
va_list args;
char buf[256];
-#if __STDC__
+#if defined(__STDC__)
va_start(args, fmt);
#else
char *fmt;
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)
}
#ifdef PPP_FILTER
-/*
- * setpdebug - Set libpcap debugging level.
- */
-static int
-setpdebug(argv)
- char **argv;
-{
- return int_option(*argv, &dflag);
-}
-
/*
* setpassfilter - Set the pass filter for packets
*/
char *ptr;
int spd;
+ if (no_override && inspeed != 0)
+ return 1;
spd = strtol(arg, &ptr, 0);
if (ptr == arg || *ptr != 0 || spd == 0)
return 0;
- inspeed = spd;
+ if (!no_override || inspeed == 0)
+ inspeed = spd;
return 1;
}
if (phase != PHASE_INITIALIZE) {
option_error("device name cannot be changed after initialization");
return -1;
- } else if (devnam_fixed) {
+ }
+ if (no_override) {
option_error("per-tty options file may not specify device name");
return -1;
}
char *colon;
u_int32_t local, remote;
ipcp_options *wo = &ipcp_wantoptions[0];
-
+ static int seen_local = 0, seen_remote = 0;
+
/*
* IP address pair separated by ":".
*/
if ((colon = strchr(arg, ':')) == NULL)
return 0;
- if (prepass)
- return 1;
/*
* If colon first character, then no local addr.
*/
- if (colon != arg) {
+ if (colon != arg && !(no_override && seen_local)) {
*colon = '\0';
- if ((local = inet_addr(arg)) == -1) {
+ if ((local = inet_addr(arg)) == (u_int32_t) -1) {
if ((hp = gethostbyname(arg)) == NULL) {
option_error("unknown host: %s", arg);
return -1;
if (local != 0)
wo->ouraddr = local;
*colon = ':';
+ seen_local = 1;
}
/*
* If colon last character, then no remote addr.
*/
- if (*++colon != '\0') {
- if ((remote = inet_addr(colon)) == -1) {
+ if (*++colon != '\0' && !(no_override && seen_remote)) {
+ if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
if ((hp = gethostbyname(colon)) == NULL) {
option_error("unknown host: %s", colon);
return -1;
}
if (remote != 0)
wo->hisaddr = remote;
+ seen_remote = 1;
}
return 1;
setnetmask(argv)
char **argv;
{
- u_int32_t mask, b;
- int n, ok;
- char *p, *endp;
+ u_int32_t mask;
+ int n;
+ char *p;
/*
* Unfortunately, if we use inet_addr, we can't tell whether
* a result of all 1s is an error or a valid 255.255.255.255.
*/
p = *argv;
- ok = 0;
- mask = 0;
- for (n = 3;; --n) {
- b = strtoul(p, &endp, 0);
- if (endp == p)
- break;
- if (b < 0 || b > 255) {
- if (n == 3) {
- /* accept e.g. 0xffffff00 */
- p = endp;
- mask = b;
- }
- break;
- }
- mask |= b << (n * 8);
- p = endp;
- if (*p != '.' || n == 0)
- break;
- ++p;
- }
+ n = parse_dotted_ip(p, &mask);
mask = htonl(mask);
- if (*p != 0 || (netmask & ~mask) != 0) {
+ if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
option_error("invalid netmask value '%s'", *argv);
return 0;
}
return (1);
}
-static int
-setxonxoff(argv)
- char **argv;
+int
+parse_dotted_ip(p, vp)
+ char *p;
+ u_int32_t *vp;
{
- lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
- lcp_wantoptions[0].neg_asyncmap = 1;
+ int n;
+ u_int32_t v, b;
+ char *endp, *p0 = p;
- crtscts = -2;
- return (1);
+ v = 0;
+ for (n = 3;; --n) {
+ b = strtoul(p, &endp, 0);
+ if (endp == p)
+ return 0;
+ if (b > 255) {
+ if (n < 3)
+ return 0;
+ /* accept e.g. 0xffffff00 */
+ *vp = b;
+ return endp - p0;
+ }
+ v |= b << (n * 8);
+ p = endp;
+ if (n == 0)
+ break;
+ if (*p != '.')
+ return 0;
+ ++p;
+ }
+ *vp = v;
+ return p - p0;
}
static int
if (!privileged_option)
seteuid(getuid());
- fd = open(*argv, O_WRONLY | O_APPEND);
+ fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
+ if (fd < 0 && errno == EEXIST)
+ fd = open(*argv, O_WRONLY | O_APPEND);
err = errno;
if (!privileged_option)
seteuid(0);
log_to_file = 1;
return 1;
}
+
+#ifdef PLUGIN
+static int
+loadplugin(argv)
+ char **argv;
+{
+ char *arg = *argv;
+ void *handle;
+ const char *err;
+ void (*init) __P((void));
+
+ handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
+ if (handle == 0) {
+ err = dlerror();
+ if (err != 0)
+ option_error("%s", err);
+ option_error("Couldn't load plugin %s", arg);
+ return 0;
+ }
+ init = (void (*)(void))dlsym(handle, "plugin_init");
+ if (init == 0) {
+ option_error("%s has no initialization entry point", arg);
+ dlclose(handle);
+ return 0;
+ }
+ info("Plugin %s loaded.", arg);
+ (*init)();
+ return 1;
+}
+#endif /* PLUGIN */