X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Foptions.c;h=346430d454f0037d2450e444ba7865ad03c77147;hp=a8ded25a9bc90666c736075c25a8db747e5e8b8c;hb=122606b29e977c437d32c407e640357b43e03e6e;hpb=ba68145197d2cf11987325628a330ee0ca651787 diff --git a/pppd/options.c b/pppd/options.c index a8ded25..346430d 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -18,9 +18,10 @@ */ #ifndef lint -static char rcsid[] = "$Id: options.c,v 1.9 1994/05/25 06:25:48 paulus Exp $"; +static char rcsid[] = "$Id: options.c,v 1.45 1999/01/20 00:00:35 paulus Exp $"; #endif +#include #include #include #include @@ -34,8 +35,12 @@ static char rcsid[] = "$Id: options.c,v 1.9 1994/05/25 06:25:48 paulus Exp $"; #include #include #include +#include +#ifdef PPP_FILTER +#include +#include /* XXX: To get struct pcap */ +#endif -#include "ppp.h" #include "pppd.h" #include "pathnames.h" #include "patchlevel.h" @@ -44,193 +49,174 @@ static char rcsid[] = "$Id: options.c,v 1.9 1994/05/25 06:25:48 paulus Exp $"; #include "ipcp.h" #include "upap.h" #include "chap.h" +#include "ccp.h" + +#include #define FALSE 0 #define TRUE 1 -#ifdef ultrix -char *strdup __ARGS((char *)); +#if defined(ultrix) || defined(NeXT) +char *strdup __P((char *)); #endif #ifndef GIDSET_TYPE -#define GIDSET_TYPE int +#define GIDSET_TYPE gid_t #endif /* - * Prototypes + * Option variables and default values. */ -static int setdebug __ARGS((void)); -static int setkdebug __ARGS((char **)); -static int setpassive __ARGS((void)); -static int setsilent __ARGS((void)); -static int noopt __ARGS((void)); -static int setnovj __ARGS((void)); -static int setnovjccomp __ARGS((void)); -static int setvjslots __ARGS((char **)); -static int reqpap __ARGS((void)); -static int nopap __ARGS((void)); -static int setupapfile __ARGS((char **)); -static int nochap __ARGS((void)); -static int reqchap __ARGS((void)); -static int setspeed __ARGS((char *)); -static int noaccomp __ARGS((void)); -static int noasyncmap __ARGS((void)); -static int noipaddr __ARGS((void)); -static int nomagicnumber __ARGS((void)); -static int setasyncmap __ARGS((char **)); -static int setescape __ARGS((char **)); -static int setmru __ARGS((char **)); -static int setmtu __ARGS((char **)); -static int nomru __ARGS((void)); -static int nopcomp __ARGS((void)); -static int setconnector __ARGS((char **)); -static int setdisconnector __ARGS((char **)); -static int setdomain __ARGS((char **)); -static int setnetmask __ARGS((char **)); -static int setcrtscts __ARGS((void)); -static int setxonxoff __ARGS((void)); -static int setnodetach __ARGS((void)); -static int setmodem __ARGS((void)); -static int setlocal __ARGS((void)); -static int setlock __ARGS((void)); -static int setname __ARGS((char **)); -static int setuser __ARGS((char **)); -static int setremote __ARGS((char **)); -static int setauth __ARGS((void)); -static int readfile __ARGS((char **)); -static int setdefaultroute __ARGS((void)); -static int setproxyarp __ARGS((void)); -static int setpersist __ARGS((void)); -static int setdologin __ARGS((void)); -static int setusehostname __ARGS((void)); -static int setnoipdflt __ARGS((void)); -static int setlcptimeout __ARGS((char **)); -static int setlcpterm __ARGS((char **)); -static int setlcpconf __ARGS((char **)); -static int setlcpfails __ARGS((char **)); -static int setipcptimeout __ARGS((char **)); -static int setipcpterm __ARGS((char **)); -static int setipcpconf __ARGS((char **)); -static int setipcpfails __ARGS((char **)); -static int setpaptimeout __ARGS((char **)); -static int setpapreqs __ARGS((char **)); -static int setchaptimeout __ARGS((char **)); -static int setchapchal __ARGS((char **)); -static int setchapintv __ARGS((char **)); -static int setipcpaccl __ARGS((void)); -static int setipcpaccr __ARGS((void)); -static int setlcpechointv __ARGS((char **)); -static int setlcpechofails __ARGS((char **)); - -static int number_option __ARGS((char *, long *, int)); -static int readable __ARGS((int fd)); +#ifdef PPP_FILTER +int dflag = 0; /* Tell libpcap we want debugging */ +#endif +int debug = 0; /* Debug flag */ +int kdebugflag = 0; /* Tell kernel to print debug messages */ +int default_device = 1; /* Using /dev/tty or equivalent */ +char devnam[MAXPATHLEN] = "/dev/tty"; /* 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 *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. */ +int maxconnect = 0; /* Maximum connect time */ +char user[MAXNAMELEN]; /* Username for PAP */ +char passwd[MAXSECRETLEN]; /* Password for PAP */ +bool persist = 0; /* Reopen link after it goes down */ +char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ +char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ +int explicit_remote = 0; /* User specified explicit remote name */ +bool demand = 0; /* do dial-on-demand */ +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 */ + +extern option_t auth_options[]; + +struct option_info connector_info; +struct option_info disconnector_info; +struct option_info welcomer_info; +struct option_info devnam_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 */ +pcap_t pc; /* Fake struct pcap so we can compile expr */ +#endif /* - * Option variables + * Prototypes */ -extern char *progname; -extern int debug; -extern int kdebugflag; -extern int modem; -extern int lockflag; -extern int crtscts; -extern int nodetach; -extern char *connector; -extern char *disconnector; -extern int inspeed; -extern char devname[]; -extern int default_device; -extern u_long netmask; -extern int detach; -extern char user[]; -extern char passwd[]; -extern int auth_required; -extern int proxyarp; -extern int persist; -extern int uselogin; -extern u_long lcp_echo_interval; -extern u_long lcp_echo_fails; -extern char our_name[]; -extern char remote_name[]; -int usehostname; -int disable_defaultip; +static int setdevname __P((char *, int)); +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 setxonxoff __P((char **)); +static int readfile __P((char **)); +static int callfile __P((char **)); +static int showversion __P((char **)); +static int showhelp __P((char **)); + +#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 readable __P((int fd)); /* * Valid arguments. */ -static struct cmd { - char *cmd_name; - int num_args; - int (*cmd_func)(); -} cmds[] = { - {"-all", 0, noopt}, /* Don't request/allow any options */ - {"-ac", 0, noaccomp}, /* Disable Address/Control compress */ - {"-am", 0, noasyncmap}, /* Disable asyncmap negotiation */ - {"-as", 1, setasyncmap}, /* set the desired async map */ - {"-d", 0, setdebug}, /* Increase debugging level */ - {"-detach", 0, setnodetach}, /* don't fork */ - {"-ip", 0, noipaddr}, /* Disable IP address negotiation */ - {"-mn", 0, nomagicnumber}, /* Disable magic number negotiation */ - {"-mru", 0, nomru}, /* Disable mru negotiation */ - {"-p", 0, setpassive}, /* Set passive mode */ - {"-pc", 0, nopcomp}, /* Disable protocol field compress */ - {"+ua", 1, setupapfile}, /* Get PAP user and password from file */ - {"+pap", 0, reqpap}, /* Require PAP auth from peer */ - {"-pap", 0, nopap}, /* Don't allow UPAP authentication with peer */ - {"+chap", 0, reqchap}, /* Require CHAP authentication from peer */ - {"-chap", 0, nochap}, /* Don't allow CHAP authentication with peer */ - {"-vj", 0, setnovj}, /* disable VJ compression */ - {"-vjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */ - {"vj-max-slots", 1, setvjslots}, /* Set maximum VJ header slots */ - {"asyncmap", 1, setasyncmap}, /* set the desired async map */ - {"escape", 1, setescape}, /* set chars to escape on transmission */ - {"connect", 1, setconnector}, /* A program to set up a connection */ - {"disconnect", 1, setdisconnector}, /* program to disconnect serial dev. */ - {"crtscts", 0, setcrtscts}, /* set h/w flow control */ - {"xonxoff", 0, setxonxoff}, /* set s/w flow control */ - {"-crtscts", 0, setxonxoff}, /* another name for xonxoff */ - {"debug", 0, setdebug}, /* Increase debugging level */ - {"kdebug", 1, setkdebug}, /* Enable kernel-level debugging */ - {"domain", 1, setdomain}, /* Add given domain name to hostname*/ - {"mru", 1, setmru}, /* Set MRU value for negotiation */ - {"mtu", 1, setmtu}, /* Set our MTU */ - {"netmask", 1, setnetmask}, /* set netmask */ - {"passive", 0, setpassive}, /* Set passive mode */ - {"silent", 0, setsilent}, /* Set silent mode */ - {"modem", 0, setmodem}, /* Use modem control lines */ - {"local", 0, setlocal}, /* Don't use modem control lines */ - {"lock", 0, setlock}, /* Lock serial device (with lock file) */ - {"name", 1, setname}, /* Set local name for authentication */ - {"user", 1, setuser}, /* Set username for PAP auth with peer */ - {"usehostname", 0, setusehostname}, /* Must use hostname for auth. */ - {"remotename", 1, setremote}, /* Set remote name for authentication */ - {"auth", 0, setauth}, /* Require authentication from peer */ - {"file", 1, readfile}, /* Take options from a file */ - {"defaultroute", 0, setdefaultroute}, /* Add default route */ - {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */ - {"persist", 0, setpersist}, /* Keep on reopening connection after close */ - {"login", 0, setdologin}, /* Use system password database for UPAP */ - {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */ - {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */ - {"lcp-echo-interval", 1, setlcpechointv}, /* time for lcp echo events */ - {"lcp-restart", 1, setlcptimeout}, /* Set timeout for LCP */ - {"lcp-max-terminate", 1, setlcpterm}, /* Set max #xmits for term-reqs */ - {"lcp-max-configure", 1, setlcpconf}, /* Set max #xmits for conf-reqs */ - {"lcp-max-failure", 1, setlcpfails}, /* Set max #conf-naks for LCP */ - {"ipcp-restart", 1, setipcptimeout}, /* Set timeout for IPCP */ - {"ipcp-max-terminate", 1, setipcpterm}, /* Set max #xmits for term-reqs */ - {"ipcp-max-configure", 1, setipcpconf}, /* Set max #xmits for conf-reqs */ - {"ipcp-max-failure", 1, setipcpfails}, /* Set max #conf-naks for IPCP */ - {"pap-restart", 1, setpaptimeout}, /* Set timeout for UPAP */ - {"pap-max-authreq", 1, setpapreqs}, /* Set max #xmits for auth-reqs */ - {"chap-restart", 1, setchaptimeout}, /* Set timeout for CHAP */ - {"chap-max-challenge", 1, setchapchal}, /* Set max #xmits for challenge */ - {"chap-interval", 1, setchapintv}, /* Set interval for rechallenge */ - {"ipcp-accept-local", 0, setipcpaccl}, /* Accept peer's address for us */ - {"ipcp-accept-remote", 0, setipcpaccr}, /* Accept peer's address for it */ - {NULL, 0, NULL} -}; +option_t general_options[] = { + { "debug", o_int, &debug, + "Increase debugging level", OPT_INC|OPT_NOARG|1 }, + { "-d", o_int, &debug, + "Increase debugging level", OPT_INC|OPT_NOARG|1 }, + { "kdebug", o_int, &kdebugflag, + "Set kernel driver debug level" }, + { "nodetach", o_bool, &nodetach, + "Don't detach from controlling tty", 1 }, + { "-detach", o_bool, &nodetach, + "Don't detach from controlling tty", 1 }, + { "updetach", o_bool, &updetach, + "Detach from controlling tty once link is up", 1 }, + { "holdoff", o_int, &holdoff, + "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, + "Don't request/allow any LCP or IPCP options (useless)" }, + { "connect", o_string, &connector, + "A program to set up a connection", OPT_A2INFO, &connector_info }, + { "disconnect", o_string, &disconnector, + "Program to disconnect serial device", OPT_A2INFO, &disconnector_info }, + { "welcome", o_string, &welcomer, + "Script to welcome client", OPT_A2INFO, &welcomer_info }, + { "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, + "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, + "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, + "Take options from a file" }, + { "call", o_special, callfile, + "Take options from a privileged file" }, + { "persist", o_bool, &persist, + "Keep on reopening connection after close", 1 }, + { "nopersist", o_bool, &persist, + "Turn off persist option" }, + { "demand", o_bool, &demand, + "Dial on demand", 1, &persist }, + { "--version", o_special_noarg, showversion, + "Show version number" }, + { "--help", o_special_noarg, showhelp, + "Show brief listing of options" }, + { "-h", o_special_noarg, showhelp, + "Show brief listing of options" }, + +#ifdef PPP_FILTER + { "pdebug", o_int, &dflag, + "libpcap debugging" }, + { "pass-filter", 1, setpassfilter, + "set filter for packets to pass" }, + { "active-filter", 1, setactivefilter, + "set filter for active pkts" }, +#endif + { NULL } +}; #ifndef IMPLEMENTATION #define IMPLEMENTATION "" @@ -238,7 +224,7 @@ static struct cmd { static char *usage_string = "\ pppd version %s patch level %d%s\n\ -Usage: %s [ arguments ], where arguments are:\n\ +Usage: %s [ options ], where options are:\n\ Communicate over the named device\n\ Set the baud rate to \n\ : Set the local and/or remote interface IP\n\ @@ -251,70 +237,90 @@ Usage: %s [ arguments ], where arguments are:\n\ file Take options from file \n\ modem Use modem control lines\n\ mru Set MRU value to for negotiation\n\ - netmask Set interface netmask to \n\ See pppd(8) for more options.\n\ "; - /* - * parse_args - parse a string of arguments, from the command - * line or from a file. + * parse_args - parse a string of arguments from the command line. */ int parse_args(argc, argv) int argc; char **argv; { - char *arg, *val; - struct cmd *cmdp; + char *arg; + option_t *opt; int ret; + privileged_option = privileged; + option_source = "command line"; while (argc > 0) { arg = *argv++; --argc; /* - * First see if it's a command. + * First see if it's an option in the new option list. */ - for (cmdp = cmds; cmdp->cmd_name; cmdp++) - if (!strcmp(arg, cmdp->cmd_name)) - break; - - if (cmdp->cmd_name != NULL) { - if (argc < cmdp->num_args) { - fprintf(stderr, "Too few parameters for command %s\n", arg); + 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; } - if (!(*cmdp->cmd_func)(argv)) + current_option = arg; + if (!process_option(opt, argv)) return 0; - argc -= cmdp->num_args; - argv += cmdp->num_args; + argc -= n; + argv += n; + continue; + } - } else { - /* - * Maybe a tty name, speed or IP address? - */ - if ((ret = setdevname(arg)) == 0 - && (ret = setspeed(arg)) == 0 - && (ret = setipaddr(arg)) == 0) { - fprintf(stderr, "%s: unrecognized command\n", arg); - usage(); - return 0; - } - if (ret < 0) /* error */ - return 0; + /* + * Maybe a tty name, speed or IP address? + */ + if ((ret = setdevname(arg, 0)) == 0 + && (ret = setspeed(arg)) == 0 + && (ret = setipaddr(arg)) == 0) { + option_error("unrecognized option '%s'", arg); + usage(); + return 0; } + if (ret < 0) /* error */ + return 0; } return 1; } /* - * usage - print out a message telling how to use the program. + * scan_args - scan the command line arguments to get the tty name, + * if specified. */ -usage() +void +scan_args(argc, argv) + int argc; + char **argv; { - fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION, - progname); + char *arg; + option_t *opt; + + privileged_option = privileged; + while (argc > 0) { + arg = *argv++; + --argc; + + /* 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); + } } /* @@ -322,14 +328,17 @@ usage() * and interpret them. */ int -options_from_file(filename, must_exist, check_prot) +options_from_file(filename, must_exist, check_prot, priv) char *filename; int must_exist; int check_prot; + int priv; { FILE *f; int i, newline, ret; - struct cmd *cmdp; + option_t *opt; + int oldpriv; + char *oldsource; char *argv[MAXARGS]; char args[MAXARGS][MAXWORDLEN]; char cmd[MAXWORDLEN]; @@ -337,56 +346,64 @@ options_from_file(filename, must_exist, check_prot) if ((f = fopen(filename, "r")) == NULL) { if (!must_exist && errno == ENOENT) return 1; - perror(filename); + option_error("Can't open options file %s: %m", filename); return 0; } if (check_prot && !readable(fileno(f))) { - fprintf(stderr, "%s: access denied\n", filename); + option_error("Can't open options file %s: access denied", filename); fclose(f); return 0; } + oldpriv = privileged_option; + privileged_option = priv; + oldsource = option_source; + option_source = strdup(filename); + if (option_source == NULL) + option_source = "file"; + ret = 0; while (getword(f, cmd, &newline, filename)) { /* * First see if it's a command. */ - for (cmdp = cmds; cmdp->cmd_name; cmdp++) - if (!strcmp(cmd, cmdp->cmd_name)) - break; - - if (cmdp->cmd_name != NULL) { - for (i = 0; i < cmdp->num_args; ++i) { + 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)) { - fprintf(stderr, - "In file %s: too few parameters for command %s\n", - filename, cmd); - fclose(f); - return 0; + option_error( + "In file %s: too few parameters for option '%s'", + filename, cmd); + goto err; } argv[i] = args[i]; } - if (!(*cmdp->cmd_func)(argv)) { - fclose(f); - return 0; - } + current_option = cmd; + if (!process_option(opt, argv)) + goto err; + continue; + } - } else { - /* - * Maybe a tty name, speed or IP address? - */ - if ((ret = setdevname(cmd)) == 0 - && (ret = setspeed(cmd)) == 0 - && (ret = setipaddr(cmd)) == 0) { - fprintf(stderr, "In file %s: unrecognized command %s\n", - filename, cmd); - fclose(f); - return 0; - } - if (ret < 0) /* error */ - return 0; + /* + * Maybe a tty name, speed or IP address? + */ + if ((i = setdevname(cmd, 0)) == 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 */ + goto err; } - return 1; + ret = 1; + +err: + fclose(f); + privileged_option = oldpriv; + option_source = oldsource; + return ret; } /* @@ -410,7 +427,7 @@ options_from_user() strcpy(path, user); strcat(path, "/"); strcat(path, file); - ret = options_from_file(path, 0, 1); + ret = options_from_file(path, 0, 1, privileged); free(path); return ret; } @@ -422,26 +439,249 @@ options_from_user() int options_for_tty() { - char *dev, *path; + char *dev, *path, *p; int ret; - dev = strrchr(devname, '/'); - if (dev == NULL) - dev = devname; - else - ++dev; + dev = devnam; + if (strncmp(dev, "/dev/", 5) == 0) + dev += 5; if (strcmp(dev, "tty") == 0) return 1; /* don't look for /etc/ppp/options.tty */ path = malloc(strlen(_PATH_TTYOPT) + strlen(dev) + 1); if (path == NULL) novm("tty init file name"); strcpy(path, _PATH_TTYOPT); - strcat(path, dev); - ret = options_from_file(path, 0, 0); + /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */ + for (p = path + strlen(path); *dev != 0; ++dev) + *p++ = (*dev == '/'? '.': *dev); + *p = 0; + ret = options_from_file(path, 0, 0, 1); free(path); return ret; } +/* + * find_option - scan the option lists for the various protocols + * looking for an entry with the given name. + * This could be optimized by using a hash table. + */ +static option_t * +find_option(char *name) +{ + option_t *opt; + int i; + + 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; +} + +/* + * process_option - process one new-style option. + */ +static int +process_option(opt, argv) + option_t *opt; + char **argv; +{ + u_int32_t v; + int iv, a; + char *sv; + int (*parser) __P((char **)); + + if ((opt->flags & OPT_PRIV) && !privileged_option) { + option_error("using the %s option requires root privilege", opt->name); + return 0; + } + if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) { + option_error("%s option is disabled", opt->name); + return 0; + } + + switch (opt->type) { + case o_bool: + v = opt->flags & OPT_VALUE; + *(bool *)(opt->addr) = v; + if (opt->addr2 && (opt->flags & OPT_A2COPY)) + *(bool *)(opt->addr2) = v; + break; + + case o_int: + iv = 0; + if ((opt->flags & OPT_NOARG) == 0) { + if (!int_option(*argv, &iv)) + return 0; + if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit) + || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit)) + && !((opt->flags & OPT_ZEROOK && iv == 0))) { + char *zok = (opt->flags & OPT_ZEROOK)? " zero or": ""; + switch (opt->flags & OPT_LIMITS) { + case OPT_LLIMIT: + option_error("%s value must be%s >= %d", + opt->name, zok, opt->lower_limit); + break; + case OPT_ULIMIT: + option_error("%s value must be%s <= %d", + opt->name, zok, opt->upper_limit); + break; + case OPT_LIMITS: + option_error("%s value must be%s between %d and %d", + opt->name, opt->lower_limit, opt->upper_limit); + break; + } + return 0; + } + } + a = opt->flags & OPT_VALUE; + if (a >= 128) + a -= 256; /* sign extend */ + iv += a; + if (opt->flags & OPT_INC) + iv += *(int *)(opt->addr); + if ((opt->flags & OPT_NOINCR) && !privileged_option) { + int oldv = *(int *)(opt->addr); + if ((opt->flags & OPT_ZEROINF) ? + (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) { + option_error("%s value cannot be increased", opt->name); + return 0; + } + } + *(int *)(opt->addr) = iv; + if (opt->addr2 && (opt->flags & OPT_A2COPY)) + *(int *)(opt->addr2) = iv; + break; + + case o_uint32: + if (opt->flags & OPT_NOARG) { + v = opt->flags & OPT_VALUE; + } else if (!number_option(*argv, &v, 16)) + return 0; + if (opt->flags & OPT_OR) + v |= *(u_int32_t *)(opt->addr); + *(u_int32_t *)(opt->addr) = v; + if (opt->addr2 && (opt->flags & OPT_A2COPY)) + *(u_int32_t *)(opt->addr2) = v; + break; + + case o_string: + if (opt->flags & OPT_STATIC) { + if (opt->upper_limit) { + strncpy((char *)(opt->addr), *argv, opt->upper_limit); + ((char *)(opt->addr))[opt->upper_limit-1] = 0; + } else + strcpy((char *)(opt->addr), *argv); + } else { + sv = strdup(*argv); + if (sv == NULL) + novm("option argument"); + *(char **)(opt->addr) = sv; + } + break; + + case o_special_noarg: + case o_special: + parser = (int (*) __P((char **))) opt->addr; + 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; + } + + return 1; +} + +/* + * n_arguments - tell how many arguments an option takes + */ +static int +n_arguments(option_t *opt) +{ + return (opt->type == o_bool || opt->type == o_special_noarg + || (opt->flags & OPT_NOARG))? 0: 1; +} + +/* + * usage - print out a message telling how to use the program. + */ +void +usage() +{ + if (phase == PHASE_INITIALIZE) + fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION, + progname); +} + +/* + * showhelp - print out usage message and exit. + */ +static int +showhelp(argv) + char **argv; +{ + if (phase == PHASE_INITIALIZE) { + usage(); + exit(0); + } + return 0; +} + +/* + * showversion - print out the version number and exit. + */ +static int +showversion(argv) + char **argv; +{ + if (phase == PHASE_INITIALIZE) { + fprintf(stderr, "pppd version %s patch level %d%s\n", + VERSION, PATCHLEVEL, IMPLEMENTATION); + exit(0); + } + return 0; +} + +/* + * option_error - print a message about an error in an option. + * The message is logged, and also sent to + * stderr if phase == PHASE_INITIALIZE. + */ +void +option_error __V((char *fmt, ...)) +{ + va_list args; + char buf[256]; + +#if __STDC__ + va_start(args, fmt); +#else + char *fmt; + va_start(args); + fmt = va_arg(args, char *); +#endif + vfmtmsg(buf, sizeof(buf), fmt, args); + va_end(args); + if (phase == PHASE_INITIALIZE) + fprintf(stderr, "%s: %s\n", progname, buf); + syslog(LOG_ERR, "%s", buf); +} + /* * readable - check if a file is readable by the real user. */ @@ -472,7 +712,7 @@ readable(fd) /* * Read a word from a file. - * Words are delimited by white-space or by quotes ("). + * Words are delimited by white-space or by quotes (" or '). * Quotes, white-space and \ may be escaped with \. * \ is ignored. */ @@ -484,112 +724,253 @@ getword(f, word, newlinep, filename) char *filename; { int c, len, escape; - int quoted; + int quoted, comment; + int value, digit, got, n; + +#define isoctal(c) ((c) >= '0' && (c) < '8') *newlinep = 0; len = 0; escape = 0; - quoted = 0; + comment = 0; /* - * First skip white-space and comments + * First skip white-space and comments. */ - while ((c = getc(f)) != EOF) { + for (;;) { + c = getc(f); + if (c == EOF) + break; + + /* + * A newline means the end of a comment; backslash-newline + * is ignored. Note that we cannot have escape && comment. + */ + if (c == '\n') { + if (!escape) { + *newlinep = 1; + comment = 0; + } else + escape = 0; + continue; + } + + /* + * Ignore characters other than newline in a comment. + */ + if (comment) + continue; + + /* + * If this character is escaped, we have a word start. + */ + if (escape) + break; + + /* + * If this is the escape character, look at the next character. + */ if (c == '\\') { - /* - * \ is ignored; \ followed by anything else - * starts a word. - */ - if ((c = getc(f)) == '\n') - continue; - word[len++] = '\\'; escape = 1; - break; + continue; } - if (c == '\n') - *newlinep = 1; /* next word starts a line */ - else if (c == '#') { - /* comment - ignore until EOF or \n */ - while ((c = getc(f)) != EOF && c != '\n') - ; - if (c == EOF) - break; - *newlinep = 1; - } else if (!isspace(c)) + + /* + * If this is the start of a comment, ignore the rest of the line. + */ + if (c == '#') { + comment = 1; + continue; + } + + /* + * A non-whitespace character is the start of a word. + */ + if (!isspace(c)) break; } /* - * End of file or error - fail + * Save the delimiter for quoted strings. */ - if (c == EOF) { - if (ferror(f)) { - perror(filename); - die(1); - } - return 0; - } + if (!escape && (c == '"' || c == '\'')) { + quoted = c; + c = getc(f); + } else + quoted = 0; - for (;;) { - /* - * Is this character escaped by \ ? - */ + /* + * Process characters until the end of the word. + */ + while (c != EOF) { if (escape) { - if (c == '\n') - --len; /* ignore \ */ - else if (c == '"' || isspace(c) || c == '\\') - word[len-1] = c; /* put special char in word */ - else { - if (len < MAXWORDLEN-1) - word[len] = c; - ++len; - } + /* + * This character is escaped: backslash-newline is ignored, + * various other characters indicate particular values + * as for C backslash-escapes. + */ escape = 0; - } else if (c == '"') { - quoted = !quoted; - } else if (!quoted && (isspace(c) || c == '#')) { - ungetc(c, f); - break; - } else { + if (c == '\n') { + c = getc(f); + continue; + } + + got = 0; + switch (c) { + case 'a': + value = '\a'; + break; + case 'b': + value = '\b'; + break; + case 'f': + value = '\f'; + break; + case 'n': + value = '\n'; + break; + case 'r': + value = '\r'; + break; + case 's': + value = ' '; + break; + case 't': + value = '\t'; + break; + + default: + if (isoctal(c)) { + /* + * \ddd octal sequence + */ + value = 0; + for (n = 0; n < 3 && isoctal(c); ++n) { + value = (value << 3) + (c & 07); + c = getc(f); + } + got = 1; + break; + } + + if (c == 'x') { + /* + * \x sequence + */ + value = 0; + c = getc(f); + for (n = 0; n < 2 && isxdigit(c); ++n) { + digit = toupper(c) - '0'; + if (digit > 10) + digit += '0' + 10 - 'A'; + value = (value << 4) + digit; + c = getc (f); + } + got = 1; + break; + } + + /* + * Otherwise the character stands for itself. + */ + value = c; + break; + } + + /* + * Store the resulting character for the escape sequence. + */ if (len < MAXWORDLEN-1) - word[len] = c; + word[len] = value; ++len; - if (c == '\\') - escape = 1; + + if (!got) + c = getc(f); + continue; + } - if ((c = getc(f)) == EOF) - break; + + /* + * Not escaped: see if we've reached the end of the word. + */ + if (quoted) { + if (c == quoted) + break; + } else { + if (isspace(c) || c == '#') { + ungetc (c, f); + break; + } + } + + /* + * Backslash starts an escape sequence. + */ + if (c == '\\') { + escape = 1; + c = getc(f); + continue; + } + + /* + * An ordinary character: store it in the word and get another. + */ + if (len < MAXWORDLEN-1) + word[len] = c; + ++len; + + c = getc(f); } - if (ferror(f)) { - perror(filename); - die(1); + /* + * End of the word: check for errors. + */ + if (c == EOF) { + if (ferror(f)) { + if (errno == 0) + errno = EIO; + option_error("Error reading %s: %m", filename); + die(1); + } + /* + * If len is zero, then we didn't find a word before the + * end of the file. + */ + if (len == 0) + return 0; } + /* + * Warn if the word was too long, and append a terminating null. + */ if (len >= MAXWORDLEN) { - word[MAXWORDLEN-1] = 0; - fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n", - progname, filename, word); - } else - word[len] = 0; + option_error("warning: word in file %s too long (%.20s...)", + filename, word); + len = MAXWORDLEN - 1; + } + word[len] = 0; return 1; + +#undef isoctal + } /* - * number_option - parse a numeric parameter for an option + * number_option - parse an unsigned numeric parameter for an option. */ -static int +int number_option(str, valp, base) char *str; - long *valp; + u_int32_t *valp; int base; { char *ptr; - *valp = strtol(str, &ptr, base); + *valp = strtoul(str, &ptr, base); if (ptr == str) { - fprintf(stderr, "%s: invalid number: %s\n", progname, str); + option_error("invalid numeric parameter '%s' for %s option", + str, current_option); return 0; } return 1; @@ -601,12 +982,12 @@ number_option(str, valp, base) * the base is assumed to be 0, and *valp is not changed * if there is an error. */ -static int +int int_option(str, valp) char *str; int *valp; { - long v; + u_int32_t v; if (!number_option(str, &v, 0)) return 0; @@ -616,7 +997,7 @@ int_option(str, valp) /* - * The following procedures execute commands. + * The following procedures parse options. */ /* @@ -626,394 +1007,134 @@ static int readfile(argv) char **argv; { - return options_from_file(*argv, 1, 1); + return options_from_file(*argv, 1, 1, privileged_option); } /* - * setdebug - Set debug (command line argument). + * callfile - take commands from /etc/ppp/peers/. + * Name may not contain /../, start with / or ../, or end in /.. */ static int -setdebug() +callfile(argv) + char **argv; { - debug++; - return (1); + char *fname, *arg, *p; + int l, ok; + + arg = *argv; + ok = 1; + if (arg[0] == '/' || arg[0] == 0) + ok = 0; + else { + for (p = arg; *p != 0; ) { + if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) { + ok = 0; + break; + } + while (*p != '/' && *p != 0) + ++p; + if (*p == '/') + ++p; + } + } + if (!ok) { + option_error("call option value may not contain .. or start with /"); + return 0; + } + + l = strlen(arg) + strlen(_PATH_PEERFILES) + 1; + if ((fname = (char *) malloc(l)) == NULL) + novm("call file name"); + strcpy(fname, _PATH_PEERFILES); + strcat(fname, arg); + + ok = options_from_file(fname, 1, 1, 1); + + free(fname); + return ok; } +#ifdef PPP_FILTER /* - * setkdebug - Set kernel debugging level. + * setpdebug - Set libpcap debugging level. */ static int -setkdebug(argv) +setpdebug(argv) char **argv; { - return int_option(*argv, &kdebugflag); + return int_option(*argv, &dflag); } /* - * noopt - Disable all options. + * setpassfilter - Set the pass filter for packets */ static int -noopt() +setpassfilter(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); -} - -/* - * noaccomp - Disable Address/Control field compression negotiation. - */ -static int -noaccomp() -{ - lcp_wantoptions[0].neg_accompression = 0; - lcp_allowoptions[0].neg_accompression = 0; - return (1); -} - - -/* - * noasyncmap - Disable async map negotiation. - */ -static int -noasyncmap() -{ - lcp_wantoptions[0].neg_asyncmap = 0; - lcp_allowoptions[0].neg_asyncmap = 0; - return (1); -} - - -/* - * noipaddr - Disable IP address negotiation. - */ -static int -noipaddr() -{ - ipcp_wantoptions[0].neg_addr = 0; - ipcp_allowoptions[0].neg_addr = 0; - return (1); -} - - -/* - * nomagicnumber - Disable magic number negotiation. - */ -static int -nomagicnumber() -{ - lcp_wantoptions[0].neg_magicnumber = 0; - lcp_allowoptions[0].neg_magicnumber = 0; - return (1); -} - - -/* - * nomru - Disable mru negotiation. - */ -static int -nomru() -{ - lcp_wantoptions[0].neg_mru = 0; - lcp_allowoptions[0].neg_mru = 0; - return (1); + pc.linktype = DLT_PPP; + pc.snapshot = PPP_HDRLEN; + + if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0) + return 1; + option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc)); + return 0; } - /* - * setmru - Set MRU for negotiation. + * setactivefilter - Set the active filter for packets */ static int -setmru(argv) +setactivefilter(argv) char **argv; { - long mru; - - if (!number_option(*argv, &mru, 0)) - return 0; - lcp_wantoptions[0].mru = mru; - lcp_wantoptions[0].neg_mru = 1; - return (1); + pc.linktype = DLT_PPP; + pc.snapshot = PPP_HDRLEN; + + if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0) + return 1; + option_error("error in active-filter expression: %s\n", pcap_geterr(&pc)); + return 0; } - +#endif /* - * setmru - Set the largest MTU we'll use. + * noopt - Disable all options. */ static int -setmtu(argv) +noopt(argv) char **argv; { - long mtu; - - if (!number_option(*argv, &mtu, 0)) - return 0; - if (mtu < MINMRU || mtu > MAXMRU) { - fprintf(stderr, "mtu option value of %d is too %s\n", mtu, - (mtu < MINMRU? "small": "large")); - return 0; - } - lcp_allowoptions[0].mru = mtu; - return (1); -} - - -/* - * nopcomp - Disable Protocol field compression negotiation. - */ -static int -nopcomp() -{ - lcp_wantoptions[0].neg_pcompression = 0; - lcp_allowoptions[0].neg_pcompression = 0; - return (1); -} - - -/* - * setpassive - Set passive mode (don't give up if we time out sending - * LCP configure-requests). - */ -static int -setpassive() -{ - lcp_wantoptions[0].passive = 1; - return (1); -} - - -/* - * setsilent - Set silent mode (don't start sending LCP configure-requests - * until we get one from the peer). - */ -static int -setsilent() -{ - lcp_wantoptions[0].silent = 1; - return 1; -} - + 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)); -/* - * nopap - Disable PAP authentication with peer. - */ -static int -nopap() -{ - lcp_allowoptions[0].neg_upap = 0; return (1); } - -/* - * reqpap - Require PAP authentication from peer. - */ -static int -reqpap() -{ - lcp_wantoptions[0].neg_upap = 1; - auth_required = 1; -} - - /* - * setupapfile - specifies UPAP info for authenticating with peer. + * setdomain - Set domain name to append to hostname */ static int -setupapfile(argv) +setdomain(argv) char **argv; { - FILE * ufile; - int l; - - lcp_allowoptions[0].neg_upap = 1; - - /* open user info file */ - if ((ufile = fopen(*argv, "r")) == NULL) { - fprintf(stderr, "unable to open user login data file %s\n", *argv); - return 0; - } - check_access(ufile, *argv); - - /* get username */ - if (fgets(user, MAXNAMELEN - 1, ufile) == NULL - || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){ - fprintf(stderr, "Unable to read user login data file %s.\n", *argv); + if (!privileged_option) { + option_error("using the domain option requires root privilege"); return 0; } - fclose(ufile); - - /* get rid of newlines */ - l = strlen(user); - if (l > 0 && user[l-1] == '\n') - user[l-1] = 0; - l = strlen(passwd); - if (l > 0 && passwd[l-1] == '\n') - passwd[l-1] = 0; - - return (1); -} - - -/* - * nochap - Disable CHAP authentication with peer. - */ -static int -nochap() -{ - lcp_allowoptions[0].neg_chap = 0; - return (1); -} - - -/* - * reqchap - Require CHAP authentication from peer. - */ -static int -reqchap() -{ - lcp_wantoptions[0].neg_chap = 1; - auth_required = 1; - return (1); -} - - -/* - * setnovj - disable vj compression - */ -static int -setnovj() -{ - ipcp_wantoptions[0].neg_vj = 0; - ipcp_allowoptions[0].neg_vj = 0; - return (1); -} - - -/* - * setnovjccomp - disable VJ connection-ID compression - */ -static int -setnovjccomp() -{ - ipcp_wantoptions[0].cflag = 0; - ipcp_allowoptions[0].cflag = 0; -} - - -/* - * setvjslots - set maximum number of connection slots for VJ compression - */ -static int -setvjslots(argv) - char **argv; -{ - int value; - - if (!int_option(*argv, &value)) - return 0; - if (value < 2 || value > 16) { - fprintf(stderr, "pppd: vj-max-slots value must be between 2 and 16\n"); - return 0; + gethostname(hostname, MAXNAMELEN); + if (**argv != 0) { + if (**argv != '.') + strncat(hostname, ".", MAXNAMELEN - strlen(hostname)); + strncat(hostname, *argv, MAXNAMELEN - strlen(hostname)); } - ipcp_wantoptions [0].maxslotindex = - ipcp_allowoptions[0].maxslotindex = value - 1; - return 1; -} - - -/* - * setconnector - Set a program to connect to a serial line - */ -static int -setconnector(argv) - char **argv; -{ - connector = strdup(*argv); - if (connector == NULL) - novm("connector string"); - - return (1); -} - -/* - * setdisconnector - Set a program to disconnect from the serial line - */ -static int -setdisconnector(argv) - char **argv; -{ - disconnector = strdup(*argv); - if (disconnector == NULL) - novm("disconnector string"); - - return (1); -} - - -/* - * setdomain - Set domain name to append to hostname - */ -static int -setdomain(argv) - char **argv; -{ - strncat(hostname, *argv, MAXNAMELEN - strlen(hostname)); hostname[MAXNAMELEN-1] = 0; return (1); } -/* - * setasyncmap - add bits to asyncmap (what we request peer to escape). - */ -static int -setasyncmap(argv) - char **argv; -{ - long asyncmap; - - if (!number_option(*argv, &asyncmap, 16)) - return 0; - lcp_wantoptions[0].asyncmap |= asyncmap; - lcp_wantoptions[0].neg_asyncmap = 1; - return(1); -} - - -/* - * setescape - add chars to the set we escape on transmission. - */ -static int -setescape(argv) - char **argv; -{ - int n, ret; - char *p, *endp; - - p = *argv; - ret = 1; - while (*p) { - n = strtol(p, &endp, 16); - if (p == endp) { - fprintf(stderr, "%s: invalid hex number: %s\n", progname, p); - return 0; - } - p = endp; - if (n < 0 || 0x20 <= n && n <= 0x3F || n == 0x5E || n > 0xFF) { - fprintf(stderr, "%s: can't escape character 0x%x\n", n); - ret = 0; - } else - xmit_accm[0][n >> 5] |= 1 << (n & 0x1F); - while (*p == ',' || *p == ' ') - ++p; - } - return ret; -} - - /* * setspeed - Set the speed. */ @@ -1035,14 +1156,17 @@ setspeed(arg) /* * setdevname - Set the device name. */ -int -setdevname(cp) +static int +setdevname(cp, quiet) char *cp; + int quiet; { struct stat statbuf; - char *tty, *ttyname(); char dev[MAXPATHLEN]; - + + if (*cp == 0) + return 0; + if (strncmp("/dev/", cp, 5) != 0) { strcpy(dev, "/dev/"); strncat(dev, cp, MAXPATHLEN - 5); @@ -1054,14 +1178,20 @@ setdevname(cp) * Check if there is a device by this name. */ if (stat(cp, &statbuf) < 0) { - if (errno == ENOENT) + if (errno == ENOENT || quiet) return 0; - syslog(LOG_ERR, cp); + option_error("Couldn't stat %s: %m", cp); return -1; } - - (void) strncpy(devname, cp, MAXPATHLEN); - devname[MAXPATHLEN-1] = 0; + + if (!privileged_option) { + if (!quiet) + option_error("setting the device name requires root privilege"); + return -1; + } + + (void) strncpy(devnam, cp, MAXPATHLEN); + devnam[MAXPATHLEN-1] = 0; default_device = FALSE; return 1; @@ -1071,19 +1201,19 @@ setdevname(cp) /* * setipaddr - Set the IP address */ -int +static int setipaddr(arg) char *arg; { struct hostent *hp; - char *colon, *index(); - u_long local, remote; + char *colon; + u_int32_t local, remote; ipcp_options *wo = &ipcp_wantoptions[0]; /* * IP address pair separated by ":". */ - if ((colon = index(arg, ':')) == NULL) + if ((colon = strchr(arg, ':')) == NULL) return 0; /* @@ -1093,18 +1223,14 @@ setipaddr(arg) *colon = '\0'; if ((local = inet_addr(arg)) == -1) { if ((hp = gethostbyname(arg)) == NULL) { - fprintf(stderr, "unknown host: %s\n", arg); + option_error("unknown host: %s", arg); return -1; } else { - local = *(long *)hp->h_addr; - if (our_name[0] == 0) { - strncpy(our_name, arg, MAXNAMELEN); - our_name[MAXNAMELEN-1] = 0; - } + local = *(u_int32_t *)hp->h_addr; } } if (bad_ip_adrs(local)) { - fprintf(stderr, "bad local IP address %s\n", ip_ntoa(local)); + option_error("bad local IP address %s", ip_ntoa(local)); return -1; } if (local != 0) @@ -1118,10 +1244,10 @@ setipaddr(arg) if (*++colon != '\0') { if ((remote = inet_addr(colon)) == -1) { if ((hp = gethostbyname(colon)) == NULL) { - fprintf(stderr, "unknown host: %s\n", colon); + option_error("unknown host: %s", colon); return -1; } else { - remote = *(long *)hp->h_addr; + remote = *(u_int32_t *)hp->h_addr; if (remote_name[0] == 0) { strncpy(remote_name, colon, MAXNAMELEN); remote_name[MAXNAMELEN-1] = 0; @@ -1129,7 +1255,7 @@ setipaddr(arg) } } if (bad_ip_adrs(remote)) { - fprintf(stderr, "bad remote IP address %s\n", ip_ntoa(remote)); + option_error("bad remote IP address %s", ip_ntoa(remote)); return -1; } if (remote != 0) @@ -1141,79 +1267,46 @@ setipaddr(arg) /* - * setnoipdflt - disable setipdefault() - */ -static int -setnoipdflt() -{ - disable_defaultip = 1; - return 1; -} - - -/* - * setipcpaccl - accept peer's idea of our address - */ -static int -setipcpaccl() -{ - ipcp_wantoptions[0].accept_local = 1; - return 1; -} - - -/* - * setipcpaccr - accept peer's idea of its address + * setnetmask - set the netmask to be used on the interface. */ static int -setipcpaccr() -{ - ipcp_wantoptions[0].accept_remote = 1; - return 1; -} - - -/* - * setipdefault - default our local IP address based on our hostname. - */ -void -setipdefault() +setnetmask(argv) + char **argv; { - struct hostent *hp; - u_long local; - ipcp_options *wo = &ipcp_wantoptions[0]; - - /* - * If local IP address already given, don't bother. - */ - if (wo->ouraddr != 0 || disable_defaultip) - return; + u_int32_t mask, b; + int n, ok; + char *p, *endp; /* - * Look up our hostname (possibly with domain name appended) - * and take the first IP address as our local IP address. - * If there isn't an IP address for our hostname, too bad. + * 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. */ - wo->accept_local = 1; /* don't insist on this default value */ - if ((hp = gethostbyname(hostname)) == NULL) - return; - local = *(long *)hp->h_addr; - if (local != 0 && !bad_ip_adrs(local)) - wo->ouraddr = local; -} - + 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; + } -/* - * setnetmask - set the netmask to be used on the interface. - */ -static int -setnetmask(argv) - char **argv; -{ - u_long mask; + mask = htonl(mask); - if ((mask = inet_addr(*argv)) == -1 || (netmask & ~mask) != 0) { - fprintf(stderr, "Invalid netmask %s\n", *argv); + if (*p != 0 || (netmask & ~mask) != 0) { + option_error("invalid netmask value '%s'", *argv); return 0; } @@ -1221,228 +1314,13 @@ setnetmask(argv) return (1); } -/* - * Return user specified netmask. A value of zero means no netmask has - * been set. - */ -/* ARGSUSED */ -u_long -GetMask(addr) - u_long addr; -{ - return(netmask); -} - - -static int -setcrtscts() -{ - crtscts = 1; - return (1); -} - -static int -setxonxoff() -{ - crtscts = 2; - return (1); -} - -static int -setnodetach() -{ - nodetach = 1; - return (1); -} - -static int -setmodem() -{ - modem = 1; - return 1; -} - -static int -setlocal() -{ - modem = 0; - return 1; -} - -static int -setlock() -{ - lockflag = 1; - return 1; -} - -static int -setusehostname() -{ - usehostname = 1; - return 1; -} - -static int -setname(argv) - char **argv; -{ - if (our_name[0] == 0) { - strncpy(our_name, argv[0], MAXNAMELEN); - our_name[MAXNAMELEN-1] = 0; - } - return 1; -} - -static int -setuser(argv) - char **argv; -{ - strncpy(user, argv[0], MAXNAMELEN); - user[MAXNAMELEN-1] = 0; - return 1; -} - static int -setremote(argv) +setxonxoff(argv) char **argv; { - strncpy(remote_name, argv[0], MAXNAMELEN); - remote_name[MAXNAMELEN-1] = 0; - return 1; -} - -static int -setauth() -{ - auth_required = 1; - return 1; -} - -static int -setdefaultroute() -{ - ipcp_wantoptions[0].default_route = 1; - return 1; -} - -static int -setproxyarp() -{ - ipcp_wantoptions[0].proxy_arp = 1; - return 1; -} - -static int -setpersist() -{ - persist = 1; - return 1; -} - -static int -setdologin() -{ - uselogin = 1; - return 1; -} - -/* - * Functions to set the echo interval for modem-less monitors - */ - -static int -setlcpechointv(argv) - char **argv; -{ - return int_option(*argv, &lcp_echo_interval); -} - -static int -setlcpechofails(argv) - char **argv; -{ - return int_option(*argv, &lcp_echo_fails); -} - -/* - * Functions to set timeouts, max transmits, etc. - */ -static int -setlcptimeout(argv) - char **argv; -{ - return int_option(*argv, &lcp_fsm[0].timeouttime); -} - -static int setlcpterm(argv) - char **argv; -{ - return int_option(*argv, &lcp_fsm[0].maxtermtransmits); -} - -static int setlcpconf(argv) - char **argv; -{ - return int_option(*argv, &lcp_fsm[0].maxconfreqtransmits); -} - -static int setlcpfails(argv) - char **argv; -{ - return int_option(*argv, &lcp_fsm[0].maxnakloops); -} - -static int setipcptimeout(argv) - char **argv; -{ - return int_option(*argv, &ipcp_fsm[0].timeouttime); -} - -static int setipcpterm(argv) - char **argv; -{ - return int_option(*argv, &ipcp_fsm[0].maxtermtransmits); -} - -static int setipcpconf(argv) - char **argv; -{ - return int_option(*argv, &ipcp_fsm[0].maxconfreqtransmits); -} - -static int setipcpfails(argv) - char **argv; -{ - return int_option(*argv, &lcp_fsm[0].maxnakloops); -} - -static int setpaptimeout(argv) - char **argv; -{ - return int_option(*argv, &upap[0].us_timeouttime); -} - -static int setpapreqs(argv) - char **argv; -{ - return int_option(*argv, &upap[0].us_maxtransmits); -} - -static int setchaptimeout(argv) - char **argv; -{ - return int_option(*argv, &chap[0].timeouttime); -} - -static int setchapchal(argv) - char **argv; -{ - return int_option(*argv, &chap[0].max_transmits); -} + lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */ + lcp_wantoptions[0].neg_asyncmap = 1; -static int setchapintv(argv) - char **argv; -{ - return int_option(*argv, &chap[0].chal_interval); + crtscts = -2; + return (1); }