so the per-tty options file gets processed correctly.
Moved stuff out of options.c into other files (e.g. setipaddr)
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: ipcp.c,v 1.55 2000/06/30 04:54:20 paulus Exp $"
+#define RCSID "$Id: ipcp.c,v 1.56 2001/02/22 03:15:16 paulus Exp $"
/*
* TODO:
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/types.h>
ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+u_int32_t netmask = 0; /* IP netmask to set on interface */
+
bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */
/* Hook for a plugin to know when IP protocol has come up */
static int setvjslots __P((char **));
static int setdnsaddr __P((char **));
static int setwinsaddr __P((char **));
+static int setnetmask __P((char **));
+static int setipaddr __P((char *, char **, int));
static option_t ipcp_option_list[] = {
{ "noip", o_bool, &ipcp_protent.enabled_flag,
{ "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
"Disable VJ connection-ID compression", OPT_A2COPY,
&ipcp_allowoptions[0].cflag },
- { "vj-max-slots", 1, (void *)setvjslots,
+ { "vj-max-slots", o_special, (void *)setvjslots,
"Set maximum VJ header slots" },
{ "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
"Accept peer's address for us", 1 },
&ipcp_wantoptions[0].proxy_arp },
{ "usepeerdns", o_bool, &usepeerdns,
"Ask peer for DNS address(es)", 1 },
+ { "netmask", o_special, (void *)setnetmask,
+ "set netmask" },
+ { "IP addresses", o_wild, (void *) &setipaddr,
+ "set local and remote IP addresses", OPT_NOARG | OPT_MULTIPART },
{ NULL }
};
return (1);
}
+/*
+ * setipaddr - Set the IP address
+ * If doit is 0, the call is to check whether this option is
+ * potentially an IP address specification.
+ */
+static int
+setipaddr(arg, argv, doit)
+ char *arg;
+ char **argv;
+ int doit;
+{
+ struct hostent *hp;
+ char *colon;
+ u_int32_t local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+ static int prio_local = 0, prio_remote = 0;
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = strchr(arg, ':')) == NULL)
+ return 0;
+ if (!doit)
+ return 1;
+
+ /*
+ * If colon first character, then no local addr.
+ */
+ if (colon != arg && option_priority >= prio_local) {
+ *colon = '\0';
+ if ((local = inet_addr(arg)) == (u_int32_t) -1) {
+ if ((hp = gethostbyname(arg)) == NULL) {
+ option_error("unknown host: %s", arg);
+ return 0;
+ }
+ local = *(u_int32_t *)hp->h_addr;
+ }
+ if (bad_ip_adrs(local)) {
+ option_error("bad local IP address %s", ip_ntoa(local));
+ return 0;
+ }
+ if (local != 0)
+ wo->ouraddr = local;
+ *colon = ':';
+ prio_local = option_priority;
+ }
+
+ /*
+ * If colon last character, then no remote addr.
+ */
+ if (*++colon != '\0' && option_priority >= prio_remote) {
+ if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
+ if ((hp = gethostbyname(colon)) == NULL) {
+ option_error("unknown host: %s", colon);
+ return 0;
+ }
+ remote = *(u_int32_t *)hp->h_addr;
+ if (remote_name[0] == 0)
+ strlcpy(remote_name, colon, sizeof(remote_name));
+ }
+ if (bad_ip_adrs(remote)) {
+ option_error("bad remote IP address %s", ip_ntoa(remote));
+ return 0;
+ }
+ if (remote != 0)
+ wo->hisaddr = remote;
+ prio_remote = option_priority;
+ }
+
+ return 1;
+}
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(argv)
+ char **argv;
+{
+ 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;
+ n = parse_dotted_ip(p, &mask);
+
+ mask = htonl(mask);
+
+ if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
+ option_error("invalid netmask value '%s'", *argv);
+ return 0;
+ }
+
+ netmask = mask;
+ return (1);
+}
+
+int
+parse_dotted_ip(p, vp)
+ char *p;
+ u_int32_t *vp;
+{
+ int n;
+ u_int32_t v, b;
+ char *endp, *p0 = p;
+
+ 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;
+}
+
/*
* ipcp_init - Initialize IPCP.
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id: ipv6cp.c,v 1.11 2000/08/05 06:46:47 paulus Exp $
+ * $Id: ipv6cp.c,v 1.12 2001/02/22 03:15:16 paulus Exp $
*/
-#define RCSID "$Id: ipv6cp.c,v 1.11 2000/08/05 06:46:47 paulus Exp $"
+#define RCSID "$Id: ipv6cp.c,v 1.12 2001/02/22 03:15:16 paulus Exp $"
/*
* TODO:
static option_t ipv6cp_option_list[] = {
{ "ipv6", o_special, (void *)setifaceid,
- "Set interface identifiers for IPV6" },
+ "Set interface identifiers for IPV6", OPT_MULTIPART },
{ "noipv6", o_bool, &ipv6cp_protent.enabled_flag,
"Disable IPv6 and IPv6CP" },
{ "-ipv6", o_bool, &ipv6cp_protent.enabled_flag,
setifaceid(argv)
char **argv;
{
- char *comma, *arg;
+ char *comma, *arg, c;
ipv6cp_options *wo = &ipv6cp_wantoptions[0];
struct in6_addr addr;
-
+ static int prio_local, prio_remote;
+
#define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \
(((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) )
* If comma first character, then no local identifier
*/
if (comma != arg) {
+ c = *comma;
*comma = '\0';
if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) {
option_error("Illegal interface identifier (local): %s", arg);
return 0;
}
-
- eui64_copy(addr.s6_addr32[2], wo->ourid);
- wo->opt_local = 1;
- *comma = ',';
+
+ if (option_priority >= prio_local) {
+ eui64_copy(addr.s6_addr32[2], wo->ourid);
+ wo->opt_local = 1;
+ prio_local = option_priority;
+ }
+ *comma = c;
}
/*
option_error("Illegal interface identifier (remote): %s", comma);
return 0;
}
- eui64_copy(addr.s6_addr32[2], wo->hisid);
- wo->opt_remote = 1;
+ if (option_priority >= prio_remote) {
+ eui64_copy(addr.s6_addr32[2], wo->hisid);
+ wo->opt_remote = 1;
+ prio_remote = option_priority;
+ }
}
ipv6cp_protent.enabled_flag = 1;
#ifdef IPX_CHANGE
-#define RCSID "$Id: ipxcp.c,v 1.18 1999/08/24 05:31:09 paulus Exp $"
+#define RCSID "$Id: ipxcp.c,v 1.19 2001/02/22 03:15:20 paulus Exp $"
/*
* TODO:
"Accept peer IPX network number", 1,
&ipxcp_allowoptions[0].accept_network },
{ "ipx-node", o_special, setipxnode,
- "Set IPX node number" },
+ "Set IPX node number", OPT_MULTIPART },
{ "ipxcp-accept-local", o_bool, &ipxcp_wantoptions[0].accept_local,
"Accept our IPX address", 1,
&ipxcp_allowoptions[0].accept_local },
char **argv;
{
char *end;
-
- memset (&ipxcp_wantoptions[0].our_node[0], 0, 6);
- memset (&ipxcp_wantoptions[0].his_node[0], 0, 6);
-
- end = setipxnodevalue (*argv, &ipxcp_wantoptions[0].our_node[0]);
- if (*end == ':')
- end = setipxnodevalue (++end, &ipxcp_wantoptions[0].his_node[0]);
+ int have_his = 0;
+ u_char our_node[6];
+ u_char his_node[6];
+ static int prio_our, prio_his;
+
+ memset (our_node, 0, 6);
+ memset (his_node, 0, 6);
+
+ end = setipxnodevalue (*argv, our_node);
+ if (*end == ':') {
+ have_his = 1;
+ end = setipxnodevalue (++end, his_node);
+ }
if (*end == '\0') {
ipxcp_wantoptions[0].neg_node = 1;
+ if (option_priority >= prio_our) {
+ memcpy(&ipxcp_wantoptions[0].our_node[0], our_node, 6);
+ prio_our = option_priority;
+ }
+ if (have_his && option_priority >= prio_his) {
+ memcpy(&ipxcp_wantoptions[0].his_node[0], his_node, 6);
+ prio_his = option_priority;
+ }
return 1;
}
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: options.c,v 1.77 2000/12/27 23:25:55 paulus Exp $"
+#define RCSID "$Id: options.c,v 1.78 2001/02/22 03:15:20 paulus Exp $"
#include <ctype.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
-#include <termios.h>
#include <syslog.h>
#include <string.h>
-#include <netdb.h>
#include <pwd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#ifdef PLUGIN
#include <dlfcn.h>
#endif
#include "pppd.h"
#include "pathnames.h"
#include "patchlevel.h"
-#include "fsm.h"
-#include "lcp.h"
-#include "ipcp.h"
-#include "upap.h"
-#include "chap.h"
-#include "ccp.h"
-
-#include <net/ppp-comp.h>
#if defined(ultrix) || defined(NeXT)
char *strdup __P((char *));
int kdebugflag = 0; /* Tell kernel to print debug messages */
int default_device = 1; /* Using /dev/tty or equivalent */
char devnam[MAXPATHLEN]; /* Device name */
-u_int32_t netmask = 0; /* IP netmask to set on interface */
bool nodetach = 0; /* Don't detach from controlling tty */
bool updetach = 0; /* Detach once link is up */
int maxconnect = 0; /* Maximum connect time */
extern option_t auth_options[];
extern struct stat devstat;
-struct option_info initializer_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;
-
#ifdef PPP_FILTER
struct bpf_program pass_filter;/* Filter program for packets to pass */
struct bpf_program active_filter; /* Filter program for link-active pkts */
char *current_option; /* the name of the option being parsed */
int privileged_option; /* set iff the current option came from root */
char *option_source; /* string saying where the option came from */
+int option_priority = OPRIO_CFGFILE; /* priority of the current options */
+bool devnam_fixed; /* can no longer change device name */
+
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 setdevname __P((char *));
-static int setipaddr __P((char *));
-static int setspeed __P((char *));
-static int noopt __P((char **));
static int setdomain __P((char **));
-static int setnetmask __P((char **));
static int readfile __P((char **));
static int callfile __P((char **));
static int showversion __P((char **));
#endif
static option_t *find_option __P((char *name));
-static int process_option __P((option_t *, char **));
+static int process_option __P((option_t *, char *, char **));
static int n_arguments __P((option_t *));
static int number_option __P((char *, u_int32_t *, int));
"Set time in seconds before retrying connection" },
{ "idle", o_int, &idle_time_limit,
"Set time in seconds before disconnecting idle link" },
- { "-all", o_special_noarg, (void *)noopt,
- "Don't request/allow any LCP or IPCP options (useless)" },
{ "maxconnect", o_int, &maxconnect,
"Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
{ "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, (void *)setnetmask,
- "set netmask" },
+ "Add given domain name to hostname", OPT_PRIV },
{ "file", o_special, (void *)readfile,
- "Take options from a file", OPT_PREPASS },
+ "Take options from a file" },
{ "call", o_special, (void *)callfile,
- "Take options from a privileged file", OPT_PREPASS },
+ "Take options from a privileged file" },
{ "persist", o_bool, &persist,
"Keep on reopening connection after close", 1 },
{ "nopersist", o_bool, &persist,
{
char *arg;
option_t *opt;
- int ret;
+ int n;
privileged_option = privileged;
option_source = "command line";
+ option_priority = OPRIO_CMDLINE;
while (argc > 0) {
arg = *argv++;
--argc;
-
- /*
- * First see if it's an option in the new option list.
- */
opt = find_option(arg);
- if (opt != NULL) {
- int n = n_arguments(opt);
- if (argc < n) {
- option_error("too few parameters for option %s", arg);
- return 0;
- }
- current_option = arg;
- if (!process_option(opt, argv))
- return 0;
- argc -= n;
- argv += n;
- continue;
- }
-
- /*
- * Maybe a tty name, speed or IP address?
- */
- if ((ret = setdevname(arg)) == 0
- && (ret = setspeed(arg)) == 0
- && (ret = setipaddr(arg)) == 0) {
+ if (opt == NULL) {
option_error("unrecognized option '%s'", arg);
usage();
return 0;
}
- if (ret < 0) /* error */
+ n = n_arguments(opt);
+ if (argc < n) {
+ option_error("too few parameters for option %s", arg);
return 0;
- }
- 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
-scan_args(argc, argv)
- int argc;
- char **argv;
-{
- char *arg;
- option_t *opt;
-
- privileged_option = privileged;
- while (argc > 0) {
- arg = *argv++;
- --argc;
-
- if (strcmp(arg, "notty") == 0 || strcmp(arg, "pty") == 0)
- using_pty = 1;
-
- /* Skip options and their arguments */
- opt = find_option(arg);
- if (opt != NULL) {
- int n = n_arguments(opt);
- argc -= n;
- argv += n;
- continue;
}
-
- /* Check if it's a tty name and copy it if so */
- (void) setdevname(arg, 1);
+ if (!process_option(opt, arg, argv))
+ return 0;
+ argc -= n;
+ argv += n;
}
+ return 1;
}
-#endif
/*
* options_from_file - Read a string of options from a file,
FILE *f;
int i, newline, ret, err;
option_t *opt;
- int oldpriv;
+ int oldpriv, n;
char *oldsource;
char *argv[MAXARGS];
char args[MAXARGS][MAXWORDLEN];
option_source = "file";
ret = 0;
while (getword(f, cmd, &newline, filename)) {
- /*
- * First see if it's a command.
- */
opt = find_option(cmd);
- if (opt != NULL) {
- int n = n_arguments(opt);
- for (i = 0; i < n; ++i) {
- if (!getword(f, args[i], &newline, filename)) {
- option_error(
+ if (opt == NULL) {
+ option_error("In file %s: unrecognized option '%s'",
+ filename, cmd);
+ goto err;
+ }
+ n = n_arguments(opt);
+ for (i = 0; i < n; ++i) {
+ if (!getword(f, args[i], &newline, filename)) {
+ option_error(
"In file %s: too few parameters for option '%s'",
filename, cmd);
- goto err;
- }
- argv[i] = args[i];
- }
- current_option = cmd;
- if ((opt->flags & OPT_DEVEQUIV) && no_override) {
- option_error("the %s option may not be used in the %s file",
- cmd, filename);
goto err;
}
- if (!process_option(opt, argv))
- goto err;
- continue;
+ argv[i] = args[i];
}
-
- /*
- * Maybe a tty name, speed or IP address?
- */
- if ((i = setdevname(cmd)) == 0
- && (i = setspeed(cmd)) == 0
- && (i = setipaddr(cmd)) == 0) {
- option_error("In file %s: unrecognized option '%s'",
- filename, cmd);
- goto err;
- }
- if (i < 0) /* error */
+ if (!process_option(opt, cmd, argv))
goto err;
}
ret = 1;
if (path == NULL)
novm("init file name");
slprintf(path, pl, "%s/%s", user, file);
+ option_priority = OPRIO_CFGFILE;
ret = options_from_file(path, 0, 1, privileged);
free(path);
return ret;
* 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.
+ * once it has been set by root; this is done by giving configuration
+ * files a lower priority than the command line.
*/
int
options_for_tty()
for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
if (*p == '/')
*p = '.';
- no_override = 1;
+ option_priority = OPRIO_CFGFILE;
ret = options_from_file(path, 0, 0, 1);
- no_override = 0;
free(path);
return ret;
}
{
char *argv[MAXARGS];
option_t *opt;
- int i, ret = 0;
+ int i, n, ret = 0;
+ struct wordlist *w0;
privileged_option = priv;
option_source = "secrets file";
+ option_priority = OPRIO_SECFILE;
while (w != NULL) {
- /*
- * First see if it's a command.
- */
opt = find_option(w->word);
- if (opt != NULL) {
- int n = n_arguments(opt);
- struct wordlist *w0 = w;
- for (i = 0; i < n; ++i) {
- w = w->next;
- if (w == NULL) {
- option_error(
- "In secrets file: too few parameters for option '%s'",
- w0->word);
- goto err;
- }
- argv[i] = w->word;
- }
- current_option = w0->word;
- if (!process_option(opt, argv))
- goto err;
- continue;
- }
-
- /*
- * Maybe a tty name, speed or IP address?
- */
- if ((i = setdevname(w->word)) == 0
- && (i = setspeed(w->word)) == 0
- && (i = setipaddr(w->word)) == 0) {
+ if (opt == NULL) {
option_error("In secrets file: unrecognized option '%s'",
w->word);
goto err;
}
- if (i < 0) /* error */
+ n = n_arguments(opt);
+ w0 = w;
+ for (i = 0; i < n; ++i) {
+ w = w->next;
+ if (w == NULL) {
+ option_error(
+ "In secrets file: too few parameters for option '%s'",
+ w0->word);
+ goto err;
+ }
+ argv[i] = w->word;
+ }
+ if (!process_option(opt, w0->word, argv))
goto err;
}
ret = 1;
return ret;
}
+/*
+ * match_option - see if this option matches an option_t structure.
+ */
+static int
+match_option(name, opt, dowild)
+ char *name;
+ option_t *opt;
+ int dowild;
+{
+ int (*match) __P((char *, char **, int));
+
+ if (dowild != (opt->type == o_wild))
+ return 0;
+ if (!dowild)
+ return strcmp(name, opt->name) == 0;
+ match = (int (*) __P((char *, char **, int))) opt->addr;
+ return (*match)(name, NULL, 0);
+}
+
/*
* find_option - scan the option lists for the various protocols
* looking for an entry with the given name.
find_option(name)
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;
- for (opt = auth_options; opt->name != NULL; ++opt)
- if (strcmp(name, opt->name) == 0)
- return opt;
- for (i = 0; protocols[i] != NULL; ++i)
- if ((opt = protocols[i]->options) != NULL)
- for (; opt->name != NULL; ++opt)
- if (strcmp(name, opt->name) == 0)
- return opt;
- return NULL;
+ option_t *opt;
+ struct option_list *list;
+ int i, dowild;
+
+ for (dowild = 0; dowild <= 1; ++dowild) {
+ for (opt = general_options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (opt = auth_options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (list = extra_options; list != NULL; list = list->next)
+ for (opt = list->options; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ for (i = 0; protocols[i] != NULL; ++i)
+ if ((opt = protocols[i]->options) != NULL)
+ for (; opt->name != NULL; ++opt)
+ if (match_option(name, opt, dowild))
+ return opt;
+ }
+ return NULL;
}
/*
* process_option - process one new-style option.
*/
static int
-process_option(opt, argv)
+process_option(opt, cmd, argv)
option_t *opt;
+ char *cmd;
char **argv;
{
u_int32_t v;
int iv, a;
char *sv;
int (*parser) __P((char **));
-
- 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)
+ int (*wildp) __P((char *, char **, int));
+ char *optopt = (opt->type == o_wild)? "": " option";
+ int prio = option_priority;
+
+ if ((opt->flags & OPT_PRIVFIX) && privileged_option)
+ prio += OPRIO_ROOT;
+ /* Multipart options (like the local:remote IP address option)
+ need to keep a separate priority value for each part,
+ so we let the parser function handle that. */
+ if ((opt->flags & OPT_MULTIPART) == 0) {
+ if (prio < opt->priority) {
+ /* new value doesn't override old */
+ if (prio == OPRIO_CMDLINE && opt->priority > OPRIO_ROOT) {
+ option_error("%s%s set in %s cannot be overridden\n",
+ opt->name, optopt, opt->source);
+ return 0;
+ }
return 1;
- warn("%s option from per-tty file overrides command line", opt->name);
+ }
+ if (prio > OPRIO_ROOT && opt->priority == OPRIO_CMDLINE)
+ warn("%s%s from %s overrides command line",
+ opt->name, optopt, option_source);
}
+
if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
- option_error("it's too late to use the %s option", opt->name);
+ option_error("%s%s cannot be changed after initialization",
+ opt->name, optopt);
return 0;
}
if ((opt->flags & OPT_PRIV) && !privileged_option) {
- option_error("using the %s option requires root privilege", opt->name);
+ option_error("using the %s%s requires root privilege",
+ opt->name, optopt);
return 0;
}
if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
- option_error("%s option is disabled", opt->name);
+ option_error("%s%s is disabled", opt->name, optopt);
return 0;
}
- if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
- struct option_info *ip = (struct option_info *) opt->addr2;
- if (ip && ip->priv) {
- option_error("%s option cannot be overridden", opt->name);
- return 0;
- }
+ if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
+ option_error("the %s%s may not be changed in %s",
+ opt->name, optopt, option_source);
+ return 0;
}
- opt->flags |= OPT_SEENIT;
switch (opt->type) {
case o_bool:
if (!(*parser)(argv))
return 0;
break;
- }
- if (opt->addr2) {
- if (opt->flags & OPT_A2INFO) {
- struct option_info *ip = (struct option_info *) opt->addr2;
- ip->priv = privileged_option;
- ip->source = option_source;
- } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
- *(bool *)(opt->addr2) = 1;
+ case o_wild:
+ wildp = (int (*) __P((char *, char **, int))) opt->addr;
+ if (!(*wildp)(cmd, argv, 1))
+ return 0;
+ break;
}
+ if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
+ *(bool *)(opt->addr2) = 1;
+
+ opt->source = option_source;
+ opt->priority = prio;
+
return 1;
}
n_arguments(opt)
option_t *opt;
{
- return (opt->type == o_bool || opt->type == o_special_noarg
- || (opt->flags & OPT_NOARG))? 0: 1;
+ return (opt->type == o_bool || opt->type == o_special_noarg
+ || (opt->flags & OPT_NOARG))? 0: 1;
}
/*
}
#endif
-/*
- * noopt - Disable all options.
- */
-static int
-noopt(argv)
- char **argv;
-{
- 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));
-
- return (1);
-}
-
/*
* setdomain - Set domain name to append to hostname
*/
setdomain(argv)
char **argv;
{
- if (!privileged_option) {
- option_error("using the domain option requires root privilege");
- return 0;
- }
gethostname(hostname, MAXNAMELEN);
if (**argv != 0) {
if (**argv != '.')
}
-/*
- * setspeed - Set the speed.
- */
-static int
-setspeed(arg)
- char *arg;
-{
- 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;
- if (!no_override || inspeed == 0)
- inspeed = spd;
- return 1;
-}
-
-
-/*
- * setdevname - Set the device name.
- */
-static int
-setdevname(cp)
- char *cp;
-{
- struct stat statbuf;
- char dev[MAXPATHLEN];
-
- if (*cp == 0)
- return 0;
-
- if (strncmp("/dev/", cp, 5) != 0) {
- strlcpy(dev, "/dev/", sizeof(dev));
- strlcat(dev, cp, sizeof(dev));
- cp = dev;
- }
-
- /*
- * Check if there is a character device by this name.
- */
- if (stat(cp, &statbuf) < 0) {
- 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 (phase != PHASE_INITIALIZE) {
- option_error("device name cannot be changed after initialization");
- return -1;
- }
- if (no_override) {
- option_error("per-tty options file may not specify device name");
- return -1;
- }
-
- if (devnam_info.priv && !privileged_option) {
- 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;
-
- return 1;
-}
-
-
-/*
- * setipaddr - Set the IP address
- */
-static int
-setipaddr(arg)
- char *arg;
-{
- struct hostent *hp;
- 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 colon first character, then no local addr.
- */
- if (colon != arg && !(no_override && seen_local)) {
- *colon = '\0';
- if ((local = inet_addr(arg)) == (u_int32_t) -1) {
- if ((hp = gethostbyname(arg)) == NULL) {
- option_error("unknown host: %s", arg);
- return -1;
- } else {
- local = *(u_int32_t *)hp->h_addr;
- }
- }
- if (bad_ip_adrs(local)) {
- option_error("bad local IP address %s", ip_ntoa(local));
- return -1;
- }
- if (local != 0)
- wo->ouraddr = local;
- *colon = ':';
- seen_local = 1;
- }
-
- /*
- * If colon last character, then no remote addr.
- */
- 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;
- } else {
- remote = *(u_int32_t *)hp->h_addr;
- if (remote_name[0] == 0)
- strlcpy(remote_name, colon, sizeof(remote_name));
- }
- }
- if (bad_ip_adrs(remote)) {
- option_error("bad remote IP address %s", ip_ntoa(remote));
- return -1;
- }
- if (remote != 0)
- wo->hisaddr = remote;
- seen_remote = 1;
- }
-
- return 1;
-}
-
-
-/*
- * setnetmask - set the netmask to be used on the interface.
- */
-static int
-setnetmask(argv)
- char **argv;
-{
- 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;
- n = parse_dotted_ip(p, &mask);
-
- mask = htonl(mask);
-
- if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
- option_error("invalid netmask value '%s'", *argv);
- return 0;
- }
-
- netmask = mask;
- return (1);
-}
-
-int
-parse_dotted_ip(p, vp)
- char *p;
- u_int32_t *vp;
-{
- int n;
- u_int32_t v, b;
- char *endp, *p0 = p;
-
- 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
setlogfile(argv)
char **argv;
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id: pppd.h,v 1.56 2000/07/06 11:17:03 paulus Exp $
+ * $Id: pppd.h,v 1.57 2001/02/22 03:15:21 paulus Exp $
*/
/*
o_int,
o_uint32,
o_string,
+ o_wild,
};
typedef struct {
void *addr2;
int upper_limit;
int lower_limit;
+ const char *source;
+ int priority;
} option_t;
/* Values for flags */
#define OPT_ZEROOK 0x10000 /* 0 value is OK even if not within limits */
#define OPT_NOINCR 0x20000 /* value mustn't be increased */
#define OPT_ZEROINF 0x40000 /* with OPT_NOINCR, 0 == infinity */
-#define OPT_A2INFO 0x100000 /* addr2 -> option_info to update */
+#define OPT_MULTIPART 0x80000 /* optionally sets multiple variables */
#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_PRIVFIX 0x800000 /* user can't override if set by root */
#define OPT_INITONLY 0x2000000 /* option can only be set in init phase */
#define OPT_DEVEQUIV 0x4000000 /* equiv to device name */
-#define OPT_DEVNAM (OPT_PREPASS | OPT_INITONLY | OPT_DEVEQUIV)
-#define OPT_SEENIT 0x10000000 /* have seen this option already */
+#define OPT_DEVNAM (OPT_INITONLY | OPT_DEVEQUIV)
#define OPT_VAL(x) ((x) & OPT_VALUE)
+/* Values for priority */
+#define OPRIO_DEFAULT 0 /* a default value */
+#define OPRIO_CFGFILE 1 /* value from a configuration file */
+#define OPRIO_CMDLINE 2 /* value from the command line */
+#define OPRIO_SECFILE 3 /* value from options in a secrets file */
+#define OPRIO_ROOT 100 /* added to priority if OPT_PRIVFIX && root */
+
#ifndef GIDSET_TYPE
#define GIDSET_TYPE gid_t
#endif
extern bool log_to_specific_fd; /* log_to_fd was specified by user */
extern char *no_ppp_msg; /* message to print if ppp not in kernel */
extern volatile int status; /* exit status for pppd */
-extern int devnam_fixed; /* can no longer change devnam */
+extern bool devnam_fixed; /* can no longer change devnam */
extern int unsuccess; /* # unsuccessful connection attempts */
extern int do_callback; /* set if we want to do callback next */
extern int doing_callback; /* set if this is a callback */
extern struct notifier *exitnotify; /* for notification that we're exiting */
extern struct notifier *sigreceived; /* notification of received signal */
extern int listen_time; /* time to listen first (ms) */
+extern char *current_option; /* option we're processing now */
+extern int option_priority; /* priority of current options */
/* Values for do_callback and doing_callback */
#define CALLBACK_DIALIN 1 /* we are expecting the call back */
void die __P((int)); /* Cleanup and exit */
void quit __P((void)); /* like die(1) */
void novm __P((char *)); /* Say we ran out of memory, and die */
-void timeout __P((void (*func)(void *), void *arg, int t));
- /* Call func(arg) after t seconds */
+void timeout __P((void (*func)(void *), void *arg, int s, int us));
+ /* Call func(arg) after s.us seconds */
void untimeout __P((void (*func)(void *), void *arg));
/* Cancel call to func(arg) */
void record_child __P((int, char *, void (*) (void *), void *));
int int_option __P((char *, int *));
/* Simplified number_option for decimal ints */
void add_options __P((option_t *)); /* Add extra options */
-int parse_dotted_ip __P((char *, u_int32_t *));
-
-/*
- * This structure is used to store information about certain
- * options, such as where the option value came from (/etc/ppp/options,
- * command line, etc.) and whether it came from a privileged source.
- */
-
-struct option_info {
- int priv; /* was value set by sysadmin? */
- char *source; /* where option came from */
-};
-extern struct option_info devnam_info;
-extern struct option_info initializer_info;
-extern struct option_info connect_script_info;
-extern struct option_info disconnect_script_info;
-extern struct option_info welcomer_info;
-extern struct option_info ptycommand_info;
+int parse_dotted_ip __P((char *, u_int32_t *));
/*
* Hooks to enable plugins to change various things.
* System dependent definitions for user-level 4.3BSD UNIX implementation.
*/
-#define TIMEOUT(r, f, t) timeout((r), (f), (t))
+#define TIMEOUT(r, f, t) timeout((r), (f), (t), 0)
#define UNTIMEOUT(r, f) untimeout((r), (f))
#define BCOPY(s, d, l) memcpy(d, s, l)
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: tty.c,v 1.3 2000/07/24 14:58:15 paulus Exp $"
+#define RCSID "$Id: tty.c,v 1.4 2001/02/22 03:15:21 paulus Exp $"
#include <stdio.h>
#include <ctype.h>
#include "fsm.h"
#include "lcp.h"
+static int setdevname __P((char *, char **, int));
+static int setspeed __P((char *, char **, int));
static int setxonxoff __P((char **));
static void finish_tty __P((void));
static int start_charshunt __P((int, int));
/* option descriptors */
option_t tty_options[] = {
+ /* device name must be first, or change connect_tty() below! */
+ { "device name", o_wild, (void *) &setdevname,
+ "Serial port device name", OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG },
+ { "tty speed", o_wild, (void *) &setspeed,
+ "Baud rate for serial port", OPT_NOARG },
{ "lock", o_bool, &lockflag,
"Lock serial device with UUCP-style lock file", 1 },
{ "nolock", o_bool, &lockflag,
"Don't lock serial device", OPT_PRIV },
{ "init", o_string, &initializer,
- "A program to initialize the device",
- OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
+ "A program to initialize the device", OPT_PRIVFIX },
{ "connect", o_string, &connect_script,
- "A program to set up a connection",
- OPT_A2INFO | OPT_PRIVFIX, &connect_script_info },
+ "A program to set up a connection", OPT_PRIVFIX },
{ "disconnect", o_string, &disconnect_script,
- "Program to disconnect serial device",
- OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info },
+ "Program to disconnect serial device", OPT_PRIVFIX },
{ "welcome", o_string, &welcomer,
- "Script to welcome client",
- OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
+ "Script to welcome client", OPT_PRIVFIX },
{ "pty", o_string, &ptycommand,
- "Script to run on pseudo-tty master side",
- OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
+ "Script to run on pseudo-tty master side", OPT_PRIVFIX | OPT_DEVNAM },
{ "notty", o_bool, ¬ty,
"Input/output is not a tty", OPT_DEVNAM | 1 },
{ "socket", o_string, &pty_socket,
{ NULL }
};
+
+/*
+ * setspeed - Set the serial port baud rate.
+ * If doit is 0, the call is to check whether this option is
+ * potentially a speed value.
+ */
+static int
+setspeed(arg, argv, doit)
+ char *arg;
+ char **argv;
+ int doit;
+{
+ char *ptr;
+ int spd;
+
+ spd = strtol(arg, &ptr, 0);
+ if (ptr == arg || *ptr != 0 || spd == 0)
+ return 0;
+ if (doit)
+ inspeed = spd;
+ return 1;
+}
+
+
+/*
+ * setdevname - Set the device name.
+ * If doit is 0, the call is to check whether this option is
+ * potentially a device name.
+ */
+static int
+setdevname(cp, argv, doit)
+ char *cp;
+ char **argv;
+ int doit;
+{
+ struct stat statbuf;
+ char dev[MAXPATHLEN];
+
+ if (*cp == 0)
+ return 0;
+
+ if (strncmp("/dev/", cp, 5) != 0) {
+ strlcpy(dev, "/dev/", sizeof(dev));
+ strlcat(dev, cp, sizeof(dev));
+ cp = dev;
+ }
+
+ /*
+ * Check if there is a character device by this name.
+ */
+ if (stat(cp, &statbuf) < 0) {
+ if (!doit)
+ return errno != ENOENT;
+ option_error("Couldn't stat %s: %m", cp);
+ return 0;
+ }
+ if (!S_ISCHR(statbuf.st_mode)) {
+ if (doit)
+ option_error("%s is not a character device", cp);
+ return 0;
+ }
+
+ if (doit) {
+ strlcpy(devnam, cp, sizeof(devnam));
+ devstat = statbuf;
+ default_device = 0;
+ }
+
+ return 1;
+}
+
static int
setxonxoff(argv)
char **argv;
for (;;) {
/* If the user specified the device name, become the
user before opening it. */
- int err;
- if (!devnam_info.priv && !privopen)
+ int err, prio;
+
+ prio = privopen? OPRIO_ROOT: tty_options[0].priority;
+ if (prio < OPRIO_ROOT)
seteuid(uid);
ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
err = errno;
- if (!devnam_info.priv && !privopen)
+ if (prio < OPRIO_ROOT)
seteuid(0);
if (ttyfd >= 0)
break;
warn("Welcome script failed");
}
+ /*
+ * If we are initiating this connection, wait for a short
+ * time for something from the peer. This can avoid bouncing
+ * our packets off his tty before he has it set up.
+ */
if (connector != NULL || ptycommand != NULL)
listen_time = connect_delay;