Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / options.c
blobf3b2ed55d96824584f1da9d804b5c3187994e4f7
1 /*
2 * options.c - handles option processing for PPP.
4 * Copyright (c) 2000-2001 by Sun Microsystems, Inc.
5 * All rights reserved.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies.
11 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
15 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
18 * Copyright (c) 1989 Carnegie Mellon University.
19 * All rights reserved.
21 * Redistribution and use in source and binary forms are permitted
22 * provided that the above copyright notice and this paragraph are
23 * duplicated in all such forms and that any documentation,
24 * advertising materials, and other materials related to such
25 * distribution and use acknowledge that the software was developed
26 * by Carnegie Mellon University. The name of the
27 * University may not be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34 #include <ctype.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <syslog.h>
41 #include <string.h>
42 #include <netdb.h>
43 #include <pwd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #ifdef PLUGIN
49 #include <dlfcn.h>
50 #endif /* PLUGIN */
51 #ifdef PPP_FILTER
52 #include <pcap.h>
53 #include <pcap-int.h> /* XXX: To get struct pcap */
54 #endif /* PPP_FILTER */
56 #include "pppd.h"
57 #include "pathnames.h"
58 #include "patchlevel.h"
59 #include "fsm.h"
60 #include "lcp.h"
61 #include "ipcp.h"
63 #if defined(ultrix) || defined(NeXT)
64 char *strdup __P((char *));
65 #endif
68 * Option variables and default values.
70 #ifdef PPP_FILTER
71 int dflag = 0; /* Tell libpcap we want debugging */
72 #endif /* PPP_FILTER */
73 int debug = 0; /* Debug flag */
74 int kdebugflag = 0; /* Tell kernel to print debug messages */
75 int default_device = 1; /* Using /dev/tty or equivalent */
76 char devnam[MAXPATHLEN]; /* Device name */
77 int crtscts = 0; /* Use hardware flow control */
78 bool modem = 1; /* Use modem control lines */
79 int inspeed = 0; /* Input/Output speed requested */
80 u_int32_t netmask = 0; /* IP netmask to set on interface */
81 bool lockflag = 0; /* Create lock file to lock the serial dev */
82 bool nodetach = 0; /* Don't detach from controlling tty */
83 bool updetach = 0; /* Detach once link is up */
84 char *initializer = NULL; /* Script to initialize physical link */
85 char *connect_script = NULL; /* Script to establish physical link */
86 char *disconnect_script = NULL; /* Script to disestablish physical link */
87 char *welcomer = NULL; /* Script to run after phys link estab. */
88 char *ptycommand = NULL; /* Command to run on other side of pty */
89 int maxconnect = 0; /* Maximum connect time */
90 char user[MAXNAMELEN]; /* Username for PAP */
91 char passwd[MAXSECRETLEN]; /* Password for PAP */
92 bool persist = 0; /* Reopen link after it goes down */
93 char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
94 bool demand = 0; /* do dial-on-demand */
95 char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
96 int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
97 int holdoff = 30; /* # seconds to pause before reconnecting */
98 bool holdoff_specified; /* true if a holdoff value has been given */
99 bool notty = 0; /* Stdin/out is not a tty */
100 char *pty_socket = NULL; /* Socket to connect to pty */
101 char *record_file = NULL; /* File to record chars sent/received */
102 int using_pty = 0;
103 bool sync_serial = 0; /* Device is synchronous serial device */
104 int log_to_fd = 1; /* send log messages to this fd too */
105 int maxfail = 10; /* max # of unsuccessful connection attempts */
106 char linkname[MAXPATHLEN]; /* logical name for link */
107 bool tune_kernel; /* may alter kernel settings */
108 int connect_delay = 1000; /* wait this many ms after connect script */
109 int max_data_rate; /* max bytes/sec through charshunt */
110 int req_unit = -1; /* requested interface unit */
111 bool multilink = 0; /* Enable multilink operation */
112 char *bundle_name = NULL; /* bundle name for multilink */
113 bool direct_tty = 0; /* use standard input directly; not a tty */
115 /* Maximum depth of include files; prevents looping. */
116 #define MAXFILENESTING 10
118 struct option_info initializer_info;
119 struct option_info connect_script_info;
120 struct option_info disconnect_script_info;
121 struct option_info welcomer_info;
122 struct option_info devnam_info;
123 struct option_info ptycommand_info;
124 struct option_info ipsrc_info;
125 struct option_info ipdst_info;
126 struct option_info speed_info;
128 #ifdef PPP_FILTER
129 struct bpf_program pass_filter;/* Filter program for packets to pass */
130 struct bpf_program active_filter; /* Filter program for link-active pkts */
131 pcap_t pc; /* Fake struct pcap so we can compile expr */
132 #endif /* PPP_FILTER */
134 char *current_option; /* the name of the option being parsed */
135 bool privileged_option; /* set iff the current option came from root */
136 char *option_source = NULL; /* string saying where the option came from */
137 int option_line = 0; /* line number in file */
138 bool log_to_file; /* log_to_fd is a file opened by us */
139 bool log_to_specific_fd; /* log_to_fd was specified by user option */
142 * Prototypes.
144 static int setdevname __P((char *));
145 static int setipaddr __P((char *));
146 static int setspeed __P((char *));
147 static int noopt __P((char **, option_t *));
148 static int setdomain __P((char **, option_t *));
149 static int setnetmask __P((char **, option_t *));
150 static int setxonxoff __P((char **, option_t *));
151 static int readfile __P((char **, option_t *));
152 static int callfile __P((char **, option_t *));
153 static int showversion __P((char **, option_t *));
154 static int showhelp __P((char **, option_t *));
155 static int showalloptions __P((char **, option_t *));
156 static void usage __P((void));
157 static int setlogfile __P((char **, option_t *));
158 #ifdef PLUGIN
159 static int loadplugin __P((char **, option_t *));
160 #endif
161 #ifdef PPP_FILTER
162 static int setpassfilter __P((char **, option_t *));
163 static int setactivefilter __P((char **, option_t *));
164 #endif /* PPP_FILTER */
165 static option_t *find_option __P((char *name));
166 static int process_option __P((option_t *opt, char **argv, int sline));
167 static int n_arguments __P((option_t *opt));
168 static int number_option __P((char *str, u_int32_t *valp, int base));
169 static u_int32_t opt_hash __P((const void *key));
170 static int opt_compare __P((const void *p1, const void *p2));
172 typedef struct _opt_t {
173 option_t *p;
174 } opt_t;
176 typedef struct _hashentry_t {
177 struct _hashentry_t *next;
178 opt_t opt;
179 } hashentry_t;
182 * A prime number describing the size of hash table.
184 #define OPTHASH_TBLSIZE 101
187 * Chained hash table containing pointers to available options.
189 static hashentry_t *hash_tbl[OPTHASH_TBLSIZE] = { NULL };
192 * Total number of entries in the hash table.
194 int hash_tblcnt = 0;
197 * Valid arguments.
199 option_t general_options[] = {
200 { "debug", o_int, &debug,
201 "Increase debugging level", OPT_INC|OPT_NOARG|1 },
202 { "-d", o_int, &debug,
203 "Increase debugging level", OPT_INC|OPT_NOARG|1 },
204 { "kdebug", o_int, &kdebugflag,
205 "Set kernel driver debug level" },
206 { "nodetach", o_bool, &nodetach,
207 "Don't detach from controlling tty", 1 },
208 { "-detach", o_bool, &nodetach,
209 "Don't detach from controlling tty", 1 },
210 { "updetach", o_bool, &updetach,
211 "Detach from controlling tty once link is up", 1 },
212 { "holdoff", o_int, &holdoff,
213 "Set time in seconds before retrying connection" },
214 { "idle", o_int, &idle_time_limit,
215 "Set time in seconds before disconnecting idle link" },
216 { "lock", o_bool, &lockflag,
217 "Lock serial device with UUCP-style lock file", 1 },
218 { "-all", o_special_noarg, (void *)noopt,
219 "Don't request/allow any LCP or IPCP options (useless)" },
220 { "init", o_string, &initializer,
221 "A program to initialize the device",
222 OPT_A2INFO | OPT_PRIVFIX, &initializer_info },
223 { "connect", o_string, &connect_script,
224 "A program to set up a connection",
225 OPT_A2INFO | OPT_PRIVFIX, &connect_script_info },
226 { "disconnect", o_string, &disconnect_script,
227 "Program to disconnect serial device",
228 OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info },
229 { "welcome", o_string, &welcomer,
230 "Script to welcome client",
231 OPT_A2INFO | OPT_PRIVFIX, &welcomer_info },
232 { "pty", o_string, &ptycommand,
233 "Script to run on pseudo-tty master side",
234 OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info },
235 { "notty", o_bool, &notty,
236 "Input/output is not a tty", OPT_DEVNAM | 1 },
237 { "directtty", o_bool, &direct_tty,
238 "Use standard input as tty without checking", OPT_DEVNAM | 1 },
239 { "socket", o_string, &pty_socket,
240 "Send and receive over socket, arg is host:port", OPT_DEVNAM },
241 { "record", o_string, &record_file,
242 "Record characters sent/received to file" },
243 { "maxconnect", o_int, &maxconnect,
244 "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF },
245 { "crtscts", o_int, &crtscts,
246 "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) },
247 { "nocrtscts", o_int, &crtscts,
248 "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
249 { "-crtscts", o_int, &crtscts,
250 "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
251 { "cdtrcts", o_int, &crtscts,
252 "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) },
253 { "nocdtrcts", o_int, &crtscts,
254 "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) },
255 { "xonxoff", o_special_noarg, (void *)setxonxoff,
256 "Set software (XON/XOFF) flow control" },
257 { "domain", o_special, (void *)setdomain,
258 "Add given domain name to hostname" },
259 { "netmask", o_special, (void *)setnetmask,
260 "set netmask" },
261 { "modem", o_bool, &modem,
262 "Use modem control lines", 1 },
263 { "local", o_bool, &modem,
264 "Don't use modem control lines" },
265 { "file", o_special, (void *)readfile,
266 "Take options from a file", OPT_PREPASS },
267 { "call", o_special, (void *)callfile,
268 "Take options from a privileged file", OPT_PREPASS },
269 { "persist", o_bool, &persist,
270 "Keep on reopening connection after close", 1 },
271 { "nopersist", o_bool, &persist,
272 "Turn off persist option" },
273 { "demand", o_bool, &demand,
274 "Dial on demand", OPT_INITONLY | 1, &persist },
275 { "--version", o_special_noarg, (void *)showversion,
276 "Show version number" },
277 { "--help", o_special_noarg, (void *)showhelp,
278 "Show brief listing of options" },
279 { "-h", o_special_noarg, (void *)showhelp,
280 "Show brief listing of options" },
281 { "options", o_special_noarg, (void *)showalloptions,
282 "Show full listing of options" },
283 { "sync", o_bool, &sync_serial,
284 "Use synchronous HDLC serial encoding", 1 },
285 { "logfd", o_int, &log_to_fd,
286 "Send log messages to this file descriptor",
287 0, &log_to_specific_fd },
288 { "logfile", o_special, (void *)setlogfile,
289 "Append log messages to this file" },
290 { "nolog", o_int, &log_to_fd,
291 "Don't send log messages to any file",
292 OPT_NOARG | OPT_VAL(-1) },
293 { "nologfd", o_int, &log_to_fd,
294 "Don't send log messages to any file descriptor",
295 OPT_NOARG | OPT_VAL(-1) },
296 { "linkname", o_string, linkname,
297 "Set logical name for link",
298 OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
299 { "maxfail", o_int, &maxfail,
300 "Number of unsuccessful connection attempts to allow" },
301 { "ktune", o_bool, &tune_kernel,
302 "Alter kernel settings as necessary", 1 },
303 { "noktune", o_bool, &tune_kernel,
304 "Don't alter kernel settings", 0 },
305 { "connect-delay", o_int, &connect_delay,
306 "Maximum wait time (msec) after connect script finishes" },
307 { "datarate", o_int, &max_data_rate,
308 "Max data rate in bytes/sec for pty, notty, or record" },
309 { "unit", o_int, &req_unit,
310 "PPP interface unit number to use if possible", OPT_LLIMIT, 0, 0 },
311 #ifdef HAVE_MULTILINK
312 { "multilink", o_bool, &multilink,
313 "Enable multilink operation", 1 },
314 { "nomultilink", o_bool, &multilink,
315 "Disable multilink operation", 0 },
316 { "mp", o_bool, &multilink,
317 "Enable multilink operation", 1 },
318 { "nomp", o_bool, &multilink,
319 "Disable multilink operation", 0 },
320 { "bundle", o_string, &bundle_name,
321 "Bundle name for multilink" },
322 #endif /* HAVE_MULTILINK */
323 #ifdef PLUGIN
324 { "plugin", o_special, (void *)loadplugin,
325 "Load a plug-in module into pppd", OPT_PRIV },
326 #endif /* PLUGIN */
327 #ifdef PPP_FILTER
328 { "pdebug", o_int, &dflag,
329 "libpcap debugging" },
330 { "pass-filter", o_special, setpassfilter,
331 "set filter for packets to pass" },
332 { "active-filter", o_special, setactivefilter,
333 "set filter for active pkts" },
334 #endif /* PPP_FILTER */
335 { NULL }
339 * This string gets printed out when "options" is given on the command
340 * line. Following this string, all of the available options and
341 * their descriptions are printed out as well. Certain options which
342 * are not available as part of the option_t structure are placed in
343 * the "dummy" option structure.
345 static const char pre_allopt_string[] = "\
346 pppd version %s.%d%s\n\
347 Usage: %s [ options ], where options are:\n\n\
350 /* Do not call add_options() on this structure */
351 static option_t dummy_options[] = {
352 { "<device>", o_special_noarg, NULL,
353 "Communicate over the named device" },
354 { "<speed>", o_special_noarg, NULL,
355 "Set the baud rate to <speed>" },
356 { "[<loc>]:[<rem>]", o_special_noarg, NULL,
357 "Set the local and/or remote interface IP addresses" },
358 { NULL }
361 static const char post_allopt_string[] = "\
363 Notes:\
364 \t<n>\tinteger type argument\n\
365 \t<s>\tstring type argument\n\
366 \t<r>\tspecial type argument\n\
367 \t(!)\tprivileged option available only when pppd is executed by root\n\
368 \t\tor when found in the privileged option files (/etc/ppp/options,\n\
369 \t\t/etc/ppp/options.ttyname, /etc/ppp/peers/name, or following\n\
370 \t\t\"--\" in /etc/ppp/pap-secrets or /etc/ppp/chap-secrets).\n\
371 \t(#)\tdisabled option\n\
373 Please see the pppd man page for details.\n";
376 * parse_args - parse a string of arguments from the command line. If prepass
377 * is true, we are scanning for the device name and only processing a few
378 * options, so error messages are suppressed. Returns 1 upon successful
379 * processing of options, and 0 otherwise.
382 parse_args(argc, argv)
383 int argc;
384 char **argv;
386 char *arg;
387 option_t *opt;
388 int ret;
390 privileged_option = privileged;
391 option_source = "command line";
392 option_line = 0;
393 while (argc > 0) {
394 arg = *argv++;
395 --argc;
398 * First check to see if it's a known option name. If so, parse the
399 * argument(s) and set the option.
401 opt = find_option(arg);
402 if (opt != NULL) {
403 int n = n_arguments(opt);
404 if (argc < n) {
405 option_error("too few parameters for option '%s'", arg);
406 return (0);
408 current_option = arg;
409 if (!process_option(opt, argv, 0))
410 return (0);
411 argc -= n;
412 argv += n;
413 continue;
417 * Maybe a tty name, speed or IP address ?
419 if (((ret = setdevname(arg)) == 0) &&
420 ((ret = setspeed(arg)) == 0) &&
421 ((ret = setipaddr(arg)) == 0) && !prepass) {
422 option_error("unrecognized option '%s'", arg);
423 usage();
424 return (0);
426 if (ret < 0) /* error */
427 return (0);
429 return (1);
433 * options_from_file - read a string of options from a file, and
434 * interpret them. Returns 1 upon successful processing of options,
435 * and 0 otherwise.
438 options_from_file
439 #ifdef __STDC__
440 (char *filename, bool must_exist, bool check_prot, bool priv)
441 #else
442 (filename, must_exist, check_prot, priv)
443 char *filename;
444 bool must_exist;
445 bool check_prot;
446 bool priv;
447 #endif
449 FILE *f;
450 int i, newline, ret, err;
451 option_t *opt;
452 bool oldpriv;
453 int oldline, sline;
454 char *oldsource;
455 char *argv[MAXARGS];
456 char args[MAXARGS][MAXWORDLEN];
457 char cmd[MAXWORDLEN];
458 static bool firsterr = 1;
459 static int nestlevel = 0;
461 if (nestlevel >= MAXFILENESTING) {
462 option_error("file nesting too deep");
463 return (0);
465 if (check_prot)
466 (void) seteuid(getuid());
467 errno = 0;
468 f = fopen(filename, "r");
469 err = errno;
470 if (check_prot)
471 (void) seteuid(0);
472 if (f == NULL) {
473 if (!must_exist && err == ENOENT)
474 return (1);
475 errno = err;
476 option_error("Can't open options file %s: %m", filename);
477 return (0);
480 nestlevel++;
481 oldpriv = privileged_option;
482 privileged_option = priv;
483 oldsource = option_source;
485 * strdup() is used here because the pointer might refer to the
486 * caller's automatic (stack) storage, and the option_info array
487 * records the source file name.
489 option_source = strdup(filename);
490 oldline = option_line;
491 option_line = 1;
492 if (option_source == NULL)
493 option_source = "file";
494 ret = 0;
495 while (getword(f, cmd, &newline, filename)) {
496 sline = option_line;
498 * First see if it's a command.
500 opt = find_option(cmd);
501 if (opt != NULL) {
502 int n = n_arguments(opt);
503 for (i = 0; i < n; ++i) {
504 if (!getword(f, args[i], &newline, filename)) {
505 option_error("too few parameters for option '%s'", cmd);
506 goto err;
508 argv[i] = args[i];
510 current_option = cmd;
511 if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
512 option_error("the '%s' option may not be used here", cmd);
513 goto err;
515 if (!process_option(opt, argv, sline))
516 goto err;
517 continue;
521 * Maybe a tty name, speed or IP address ?
523 if (((i = setdevname(cmd)) == 0) &&
524 ((i = setspeed(cmd)) == 0) &&
525 ((i = setipaddr(cmd)) == 0)) {
526 option_error("unrecognized option '%s'", cmd);
527 goto err;
529 if (i < 0) /* error */
530 goto err;
532 ret = 1;
534 err:
535 (void) fclose(f);
536 /* We assume here that we abort all processing on the first error. */
537 if (firsterr)
538 firsterr = 0;
539 else if (!prepass && !ret)
540 option_error("error in included file");
542 * Cannot free option_source because it might be referenced in one
543 * or more option_info structures now.
545 privileged_option = oldpriv;
546 option_source = oldsource;
547 option_line = oldline;
548 nestlevel--;
549 return (ret);
553 * options_from_user - see if the user has a ~/.ppprc file, and if so,
554 * interpret options from it. Returns 1 upon successful processing of
555 * options, and 0 otherwise.
558 options_from_user()
560 char *user, *path, *file;
561 int ret;
562 struct passwd *pw;
563 size_t pl;
565 pw = getpwuid(getuid());
566 if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == '\0')
567 return (1);
568 file = _PATH_USEROPT;
569 pl = strlen(user) + strlen(file) + 2;
570 path = malloc(pl);
571 if (path == NULL)
572 novm("init file name");
573 (void) slprintf(path, pl, "%s/%s", user, file);
574 ret = options_from_file(path, 0, 1, privileged);
575 free(path);
576 return (ret);
580 * options_for_tty - see if an options file exists for the serial device, and
581 * if so, interpret options from it. Returns 1 upon successful processing of
582 * options, and 0 otherwise.
585 options_for_tty()
587 char *dev, *path, *p;
588 int ret;
589 size_t pl;
591 dev = devnam;
592 if (strncmp(dev, "/dev/", 5) == 0)
593 dev += 5;
594 if (dev[0] == '\0' || strcmp(dev, "tty") == 0)
595 return (1); /* don't look for /etc/ppp/options.tty */
596 pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
597 path = malloc(pl);
598 if (path == NULL)
599 novm("tty init file name");
600 (void) slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
601 /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
602 for (p = path + strlen(_PATH_TTYOPT); *p != '\0'; ++p)
603 if (*p == '/')
604 *p = '.';
605 ret = options_from_file(path, 0, 0, 1);
606 free(path);
607 return (ret);
611 * options_from_list - process a string of options in a wordlist. Returns 1
612 * upon successful processing of options, and 0 otherwise.
615 options_from_list
616 #ifdef __STDC__
617 (struct wordlist *w, bool priv)
618 #else
619 (w, priv)
620 struct wordlist *w;
621 bool priv;
622 #endif
624 char *argv[MAXARGS];
625 option_t *opt;
626 int i, ret = 0;
628 privileged_option = priv;
630 /* Caller is expected to set option_source and option_line. */
632 while (w != NULL) {
634 * First see if it's a command.
636 opt = find_option(w->word);
637 if (opt != NULL) {
638 int n = n_arguments(opt);
639 struct wordlist *w0 = w;
640 for (i = 0; i < n; ++i) {
641 w = w->next;
642 if (w == NULL) {
643 option_error("too few parameters for option '%s'",
644 w0->word);
645 goto err;
647 argv[i] = w->word;
649 current_option = w0->word;
650 if (!process_option(opt, argv, option_line))
651 goto err;
652 continue;
656 * Options from the {p,ch}ap-secrets files can't change the device
657 * name nor the speed. Therefore, calls to setdevname() and
658 * setspeed() were removed.
660 if ((i = setipaddr(w->word)) == 0) {
661 option_error("unrecognized option '%s'", w->word);
662 goto err;
664 if (i < 0) /* error */
665 goto err;
667 ret = 1;
669 err:
670 return (ret);
674 * find_option - scan the option lists for the various protocols looking for an
675 * entry with the given name. Returns a pointer to the matching option_t
676 * structure upon successful processing of options, and NULL otherwise.
678 static option_t *
679 find_option(name)
680 char *name;
682 hashentry_t *bucket;
684 bucket = hash_tbl[opt_hash(name)];
685 for (; bucket != NULL; bucket = bucket->next) {
686 if (bucket->opt.p->name != NULL) {
687 if ((strcmp(bucket->opt.p->name, name) == 0) &&
688 !(bucket->opt.p->flags & OPT_DISABLE)) {
689 return (bucket->opt.p);
693 return (NULL);
697 * process_option - process one new-style option (something other than a
698 * port name, bit rate, or IP address). Returns 1 upon successful
699 * processing of options, and 0 otherwise.
701 static int
702 process_option(opt, argv, sline)
703 option_t *opt;
704 char **argv;
705 int sline;
707 u_int32_t v;
708 int iv, a;
709 char *sv;
710 int (*parser) __P((char **, option_t *));
712 if ((opt->flags & OPT_PREPASS) == 0 && prepass)
713 return (1);
714 if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
715 option_error("it's too late to use the '%s' option", opt->name);
716 return (0);
718 if ((opt->flags & OPT_PRIV) && !privileged_option) {
719 option_error("using the '%s' option requires root privilege",
720 opt->name);
721 return (0);
723 if ((opt->flags & OPT_ENABLE) && !privileged_option &&
724 *(bool *)(opt->addr2) == 0) {
725 option_error("'%s' option is disabled", opt->name);
726 return (0);
728 if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
729 struct option_info *ip = (struct option_info *) opt->addr2;
730 if ((ip != NULL) && ip->priv) {
731 option_error("'%s' option cannot be overridden", opt->name);
732 return (0);
736 switch (opt->type) {
737 case o_bool:
738 v = opt->flags & OPT_VALUE;
739 *(bool *)(opt->addr) = (v != 0);
740 if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
741 *(bool *)(opt->addr2) = (v != 0);
742 break;
744 case o_int:
745 iv = 0;
746 if ((opt->flags & OPT_NOARG) == 0) {
747 if (!int_option(*argv, &iv))
748 return (0);
749 if ((((opt->flags & OPT_LLIMIT) && (iv < opt->lower_limit)) ||
750 ((opt->flags & OPT_ULIMIT) && (iv > opt->upper_limit))) &&
751 !((opt->flags & OPT_ZEROOK) && (iv == 0))) {
752 char *zok = (opt->flags & OPT_ZEROOK) ? " zero or" : "";
753 switch (opt->flags & OPT_LIMITS) {
754 case OPT_LLIMIT:
755 option_error("%s value must be%s >= %d",
756 opt->name, zok, opt->lower_limit);
757 break;
758 case OPT_ULIMIT:
759 option_error("%s value must be%s <= %d",
760 opt->name, zok, opt->upper_limit);
761 break;
762 case OPT_LIMITS:
763 option_error("%s value must be%s between %d and %d",
764 opt->name, zok, opt->lower_limit, opt->upper_limit);
765 break;
767 return (0);
770 a = opt->flags & OPT_VALUE;
771 if (a >= 128)
772 a -= 256; /* sign extend */
773 iv += a;
774 if (opt->flags & OPT_INC)
775 iv += *(int *)(opt->addr);
776 if ((opt->flags & OPT_NOINCR) && !privileged_option) {
777 int oldv = *(int *)(opt->addr);
779 if ((opt->flags & OPT_ZEROINF) && (iv == 0)) {
780 if (oldv > 0) {
781 option_error("%s value cannot be set to infinity; limited to %d",
782 opt->name, oldv);
783 return (0);
785 } else if (iv > oldv) {
786 option_error("%s value cannot be increased beyond %d",
787 opt->name, oldv);
788 return (0);
791 *(int *)(opt->addr) = iv;
792 if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
793 *(int *)(opt->addr2) = iv;
794 break;
796 case o_uint32:
797 if (opt->flags & OPT_NOARG) {
798 v = opt->flags & OPT_VALUE;
799 } else if (!number_option(*argv, &v, 16))
800 return (0);
801 if (opt->flags & OPT_OR)
802 v |= *(u_int32_t *)(opt->addr);
803 *(u_int32_t *)(opt->addr) = v;
804 if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY))
805 *(u_int32_t *)(opt->addr2) = v;
806 break;
808 case o_string:
809 if (opt->flags & OPT_STATIC) {
810 (void) strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
811 if ((opt->addr2 != NULL) && (opt->flags & OPT_A2COPY)) {
812 (void) strlcpy((char *)(opt->addr2), *argv, opt->upper_limit);
814 } else {
815 sv = strdup(*argv);
816 if (sv == NULL)
817 novm("option argument");
818 *(char **)(opt->addr) = sv;
819 if (opt->addr2 != NULL && (opt->flags & OPT_A2COPY))
820 *(char **)(opt->addr2) = sv;
822 break;
824 case o_special_noarg:
825 case o_special:
826 parser = (int (*) __P((char **, option_t *))) opt->addr;
827 if (!(*parser)(argv, opt))
828 return (0);
829 break;
832 if (opt->addr2 != NULL) {
833 if (opt->flags & OPT_A2INFO) {
834 struct option_info *ip = (struct option_info *) opt->addr2;
835 ip->priv = privileged_option;
836 ip->source = option_source;
837 ip->line = sline;
838 } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
839 *(bool *)(opt->addr2) = 1;
842 return (1);
846 * n_arguments - tell how many arguments an option takes. Returns 1 upon
847 * successful processing of options, and 0 otherwise.
849 static int
850 n_arguments(opt)
851 option_t *opt;
853 return ((opt->type == o_bool || opt->type == o_special_noarg ||
854 (opt->flags & OPT_NOARG)) ? 0 : 1);
858 * opt_hash - a hash function that works quite well for strings. Returns
859 * the hash key of the supplied string.
861 static u_int32_t
862 opt_hash(key)
863 const void *key;
865 register const char *ptr;
866 register u_int32_t val;
868 val = 0;
869 ptr = key;
870 while (*ptr != '\0') {
871 int tmp;
872 val = (val << 4) + (*ptr);
873 tmp = val & 0xf0000000;
874 if (tmp) {
875 val ^= (tmp >> 24);
876 val ^= tmp;
878 ptr++;
880 return (val % OPTHASH_TBLSIZE);
884 * add_options - add a list of options to the chained hash table.
885 * Also detect duplicate options, and if found, disable the older
886 * definition and log it as an error.
888 void
889 add_options(opt)
890 option_t *opt;
892 register option_t *sopt;
893 register hashentry_t *bucket;
894 register u_int32_t loc;
895 hashentry_t *he;
897 /* fill hash-table */
898 for (sopt = opt; sopt->name != NULL; ++sopt, hash_tblcnt++) {
900 /* first, allocate a hash entry */
901 he = (hashentry_t *)malloc(sizeof(*he));
902 if (he == NULL) {
903 novm("option hash table entry");
905 he->opt.p = sopt;
906 he->next = NULL;
909 * fill the chained hash table and take care of any collisions or
910 * duplicate items.
912 loc = opt_hash(sopt->name);
913 bucket = hash_tbl[loc];
914 if (bucket != NULL) {
915 for (;;) {
916 if (!(bucket->opt.p->flags & OPT_DISABLE) &&
917 strcmp(sopt->name, bucket->opt.p->name) == 0) {
918 info("option '%s' redefined; old definition disabled",
919 sopt->name);
920 bucket->opt.p->flags |= OPT_DISABLE;
922 if (bucket->next == NULL)
923 break;
924 bucket = bucket->next;
926 bucket->next = he;
927 } else {
928 hash_tbl[loc] = he;
934 * remove_option - disable an option. Returns the option_t structure
935 * of the disabled option, or NULL if the option name is invalid or if
936 * the option has already been disabled.
938 option_t *
939 remove_option(name)
940 char *name;
942 option_t *opt;
944 if ((opt = find_option(name)) != NULL) {
945 opt->flags |= OPT_DISABLE;
947 return (opt);
951 * opt_compare - a compare function supplied to the quicksort routine.
952 * Returns an integer less than, equal to, or greater than zero to indicate
953 * if the first argument is considered less than, equal to, or greater
954 * than the second argument.
956 static int
957 opt_compare(p1, p2)
958 const void *p1;
959 const void *p2;
961 opt_t *o1 = (opt_t *)p1;
962 opt_t *o2 = (opt_t *)p2;
964 return (strcmp(o1->p->name, o2->p->name));
967 /*ARGSUSED*/
968 static int
969 showalloptions(argv, topt)
970 char **argv;
971 option_t *topt;
973 #define MAXOPTSTRLEN 257
974 #define PRINTOPTIONS() { \
975 (void) slprintf(opt_str, sizeof(opt_str), "%s", opt->name); \
976 if ((opt->type == o_int || opt->type == o_uint32) && \
977 !(opt->flags & OPT_NOARG)) { \
978 (void) strlcat(opt_str, " <n>", sizeof(opt_str)); \
979 } else if (opt->type == o_string) { \
980 (void) strlcat(opt_str, " <s>", sizeof(opt_str)); \
981 } else if (opt->type == o_special) { \
982 (void) strlcat(opt_str, " <r>", sizeof(opt_str)); \
984 if (opt->flags & OPT_PRIV) { \
985 (void) strlcat(opt_str, " (!)", sizeof(opt_str)); \
986 } else if (opt->flags & OPT_DISABLE) { \
987 (void) strlcat(opt_str, " (#)", sizeof(opt_str)); \
989 (void) printf("%-26s%s\n", opt_str, opt->description); \
992 char opt_str[MAXOPTSTRLEN];
993 option_t *opt;
994 hashentry_t *bucket;
995 int i, sofar;
996 opt_t *sopt;
998 if (phase != PHASE_INITIALIZE) {
999 return (0);
1001 (void) printf(pre_allopt_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
1002 progname);
1003 for (opt = dummy_options; opt->name != NULL; ++opt) {
1004 PRINTOPTIONS();
1007 sopt = malloc(sizeof(*sopt) * hash_tblcnt);
1008 if (sopt == NULL) {
1009 novm("sorted option table");
1012 sofar = 0;
1013 for (i = 0; i < OPTHASH_TBLSIZE; i++) {
1014 for (bucket = hash_tbl[i]; bucket != NULL; bucket = bucket->next) {
1015 if (sofar >= hash_tblcnt) {
1016 fatal("options hash table corrupted; size mismatch");
1018 sopt[sofar++].p = bucket->opt.p;
1022 qsort((void *)sopt, sofar, sizeof(sopt[0]), opt_compare);
1023 for (i = 0; i < sofar; i++) {
1024 opt = sopt[i].p;
1025 PRINTOPTIONS();
1028 (void) printf(post_allopt_string);
1029 (void) free(sopt);
1031 #undef MAXOPTSTRLEN
1032 #undef PRINTOPTIONS
1033 return (0);
1037 * usage - print out a message telling how to use the program.
1038 * This string gets printed out when either "--help" or an invalid option
1039 * is specified.
1041 static void
1042 usage()
1044 static const char usage_string[] = "\
1045 pppd version %s.%d%s\n\
1046 Usage: %s [ options ], where options are:\n\
1047 \t<device>\tCommunicate over the named device\n\
1048 \t<speed>\t\tSet the baud rate to <speed>\n\
1049 \t<loc>:<rem>\tSet the local and/or remote interface IP\n\
1050 \t\t\taddresses. Either one may be omitted.\n\
1051 \tnoauth\t\tDon't require authentication from peer\n\
1052 \tconnect <p>\tInvoke shell command <p> to set up the serial line\n\
1053 \tdefaultroute\tAdd default route through interface\n\
1054 Use \"%s options\" or \"man pppd\" for more options.\n\
1057 if (phase == PHASE_INITIALIZE)
1058 (void) fprintf(stderr, usage_string, VERSION, PATCHLEVEL,
1059 IMPLEMENTATION, progname, progname);
1063 * showhelp - print out usage message and exit program upon success, or
1064 * return 0 otherwise.
1066 /*ARGSUSED*/
1067 static int
1068 showhelp(argv, opt)
1069 char **argv;
1070 option_t *opt;
1072 if (phase == PHASE_INITIALIZE) {
1073 usage();
1074 exit(0);
1076 return (0);
1080 * showversion - print out the version number and exit program upon success,
1081 * or return 0 otherwise.
1083 /*ARGSUSED*/
1084 static int
1085 showversion(argv, opt)
1086 char **argv;
1087 option_t *opt;
1089 if (phase == PHASE_INITIALIZE) {
1090 (void) fprintf(stderr, "pppd version %s.%d%s\n", VERSION, PATCHLEVEL,
1091 IMPLEMENTATION);
1092 exit(0);
1094 return (0);
1098 * option_error - print a message about an error in an option. The message is
1099 * logged, and also sent to stderr if phase == PHASE_INITIALIZE.
1101 void
1102 option_error __V((char *fmt, ...))
1104 va_list args;
1105 char buf[256];
1106 int i, err;
1108 #if defined(__STDC__)
1109 va_start(args, fmt);
1110 #else
1111 char *fmt;
1112 va_start(args);
1113 fmt = va_arg(args, char *);
1114 #endif
1115 if (prepass) {
1116 va_end(args);
1117 return;
1119 err = errno;
1120 if (option_source == NULL) {
1121 i = 0;
1122 } else if (option_line <= 0) {
1123 (void) strlcpy(buf, option_source, sizeof (buf));
1124 i = strlen(buf);
1125 } else {
1126 i = slprintf(buf, sizeof(buf), "%s:%d", option_source, option_line);
1128 if (i != 0) {
1129 (void) strlcat(buf, ": ", sizeof (buf));
1130 i += 2;
1132 errno = err;
1133 (void) vslprintf(buf + i, sizeof (buf) - i, fmt, args);
1134 va_end(args);
1135 if ((phase == PHASE_INITIALIZE) && !detached)
1136 (void) fprintf(stderr, "%s: %s\n", progname, buf);
1137 syslog(LOG_ERR, "%s", buf);
1141 * getword - read a word from a file. Words are delimited by white-space or by
1142 * quotes (" or '). Quotes, white-space and \ may be escaped with \.
1143 * \<newline> is ignored. Returns 1 upon successful processing of options,
1144 * and 0 otherwise.
1147 getword(f, word, newlinep, filename)
1148 FILE *f;
1149 char *word;
1150 int *newlinep;
1151 char *filename;
1153 int c, len, escape;
1154 int quoted, comment;
1155 int value, digit, got, n;
1157 #define isoctal(c) ((c) >= '0' && (c) < '8')
1159 *newlinep = 0;
1160 len = 0;
1161 escape = 0;
1162 comment = 0;
1165 * First skip white-space and comments.
1167 for (;;) {
1168 c = getc(f);
1169 if (c == EOF)
1170 break;
1173 * A newline means the end of a comment; backslash-newline
1174 * is ignored. Note that we cannot have escape && comment.
1176 if (c == '\n') {
1177 option_line++;
1178 if (!escape) {
1179 *newlinep = 1;
1180 comment = 0;
1181 } else
1182 escape = 0;
1183 continue;
1187 * Ignore characters other than newline in a comment.
1189 if (comment)
1190 continue;
1193 * If this character is escaped, we have a word start.
1195 if (escape)
1196 break;
1199 * If this is the escape character, look at the next character.
1201 if (c == '\\') {
1202 escape = 1;
1203 continue;
1207 * If this is the start of a comment, ignore the rest of the line.
1209 if (c == '#') {
1210 comment = 1;
1211 continue;
1215 * A non-whitespace character is the start of a word.
1217 if (!isspace(c))
1218 break;
1222 * Save the delimiter for quoted strings.
1224 if (!escape && (c == '"' || c == '\'')) {
1225 quoted = c;
1226 c = getc(f);
1227 } else
1228 quoted = 0;
1231 * Process characters until the end of the word.
1233 while (c != EOF) {
1234 if (escape) {
1236 * This character is escaped: backslash-newline is ignored,
1237 * various other characters indicate particular values
1238 * as for C backslash-escapes.
1240 escape = 0;
1241 if (c == '\n') {
1242 c = getc(f);
1243 continue;
1246 got = 0;
1247 switch (c) {
1248 case 'a':
1249 value = '\a';
1250 break;
1251 case 'b':
1252 value = '\b';
1253 break;
1254 case 'f':
1255 value = '\f';
1256 break;
1257 case 'n':
1258 value = '\n';
1259 break;
1260 case 'r':
1261 value = '\r';
1262 break;
1263 case 's':
1264 value = ' ';
1265 break;
1266 case 't':
1267 value = '\t';
1268 break;
1270 default:
1271 if (isoctal(c)) {
1273 * \ddd octal sequence
1275 value = 0;
1276 for (n = 0; n < 3 && isoctal(c); ++n) {
1277 value = (value << 3) + (c & 07);
1278 c = getc(f);
1280 got = 1;
1281 break;
1284 if (c == 'x') {
1286 * \x<hex_string> sequence
1288 value = 0;
1289 c = getc(f);
1290 for (n = 0; n < 2 && isxdigit(c); ++n) {
1291 digit = (islower(c) ? toupper(c) : c) - '0';
1292 if (digit > 10 || digit < 0) /* allow non-ASCII */
1293 digit += '0' + 10 - 'A';
1294 value = (value << 4) + digit;
1295 c = getc (f);
1297 got = 1;
1298 break;
1302 * Otherwise the character stands for itself.
1304 value = c;
1305 break;
1309 * Store the resulting character for the escape sequence.
1311 if (len < MAXWORDLEN) {
1312 word[len] = value;
1313 ++len;
1316 if (!got)
1317 c = getc(f);
1318 continue;
1323 * Not escaped: see if we've reached the end of the word.
1325 if (quoted) {
1326 if (c == quoted)
1327 break;
1328 } else {
1329 if (isspace(c) || c == '#') {
1330 (void) ungetc (c, f);
1331 break;
1336 * Backslash starts an escape sequence.
1338 if (c == '\\') {
1339 escape = 1;
1340 c = getc(f);
1341 continue;
1345 * An ordinary character: store it in the word and get another.
1347 if (len < MAXWORDLEN) {
1348 word[len] = c;
1349 ++len;
1352 c = getc(f);
1356 * End of the word: check for errors.
1358 if (c == EOF) {
1359 if (ferror(f)) {
1360 if (errno == 0)
1361 errno = EIO;
1362 option_error("Error reading %s: %m", filename);
1363 die(1);
1366 * If len is zero, then we didn't find a word before the
1367 * end of the file.
1369 if (len == 0)
1370 return (0);
1374 * Warn if the word was too long, and append a terminating null.
1376 if (len >= MAXWORDLEN) {
1377 option_error("warning: word in file %s too long (%.20s...)",
1378 filename, word);
1379 len = MAXWORDLEN - 1;
1381 word[len] = '\0';
1383 return (1);
1385 #undef isoctal
1390 * number_option - parse an unsigned numeric parameter for an option.
1391 * Returns 1 upon successful processing of options, and 0 otherwise.
1393 static int
1394 number_option(str, valp, base)
1395 char *str;
1396 u_int32_t *valp;
1397 int base;
1399 char *ptr;
1401 *valp = strtoul(str, &ptr, base);
1402 if (ptr == str || *ptr != '\0') {
1403 option_error("invalid numeric parameter '%s' for '%s' option",
1404 str, current_option);
1405 return (0);
1407 return (1);
1411 * save_source - store option source, line, and privilege into an
1412 * option_info structure.
1414 void
1415 save_source(info)
1416 struct option_info *info;
1418 info->priv = privileged_option;
1419 info->source = option_source;
1420 info->line = option_line;
1424 * set_source - set option source, line, and privilege from an
1425 * option_info structure.
1427 void
1428 set_source(info)
1429 struct option_info *info;
1431 privileged_option = info->priv;
1432 option_source = info->source;
1433 option_line = info->line;
1437 * name_source - return string containing option source and line. Can
1438 * be used as part of an option_error call.
1440 const char *
1441 name_source(info)
1442 struct option_info *info;
1444 static char buf[MAXPATHLEN];
1446 if (info->source == NULL)
1447 return "none";
1448 if (info->line <= 0)
1449 return info->source;
1450 (void) slprintf(buf, sizeof (buf), "%s:%d", info->source, info->line);
1451 return (const char *)buf;
1455 * int_option - like number_option, but valp is int *, the base is assumed to
1456 * be 0, and *valp is not changed if there is an error. Returns 1 upon
1457 * successful processing of options, and 0 otherwise.
1460 int_option(str, valp)
1461 char *str;
1462 int *valp;
1464 u_int32_t v;
1466 if (!number_option(str, &v, 0))
1467 return (0);
1468 *valp = (int) v;
1469 return (1);
1474 * The following procedures parse options.
1478 * readfile - take commands from a file.
1480 /*ARGSUSED*/
1481 static int
1482 readfile(argv, opt)
1483 char **argv;
1484 option_t *opt;
1486 return (options_from_file(*argv, 1, 1, privileged_option));
1490 * callfile - take commands from /etc/ppp/peers/<name>. Name may not contain
1491 * /../, start with / or ../, or end in /. Returns 1 upon successful
1492 * processing of options, and 0 otherwise.
1494 /*ARGSUSED*/
1495 static int
1496 callfile(argv, opt)
1497 char **argv;
1498 option_t *opt;
1500 char *fname, *arg, *p;
1501 int l, ok;
1503 arg = *argv;
1504 ok = 1;
1505 if (arg[0] == '/' || arg[0] == '\0')
1506 ok = 0;
1507 else {
1508 for (p = arg; *p != '\0'; ) {
1509 if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) {
1510 ok = 0;
1511 break;
1513 while (*p != '/' && *p != '\0')
1514 ++p;
1515 if (*p == '/')
1516 ++p;
1519 if (!ok) {
1520 option_error("call option value may not contain .. or start with /");
1521 return (0);
1524 l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1525 if ((fname = (char *) malloc(l)) == NULL)
1526 novm("call file name");
1527 (void) slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1529 ok = options_from_file(fname, 1, 1, 1);
1531 free(fname);
1532 return (ok);
1535 #ifdef PPP_FILTER
1537 * setpdebug - set libpcap debugging level. Returns 1 upon successful
1538 * processing of options, and 0 otherwise.
1540 static int
1541 setpdebug(argv)
1542 char **argv;
1544 return (int_option(*argv, &dflag));
1548 * setpassfilter - set the pass filter for packets. Returns 1 upon successful
1549 * processing of options, and 0 otherwise.
1551 /*ARGSUSED*/
1552 static int
1553 setpassfilter(argv, opt)
1554 char **argv;
1555 option_t *opt;
1557 pc.linktype = DLT_PPP;
1558 pc.snapshot = PPP_HDRLEN;
1560 if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1561 return (1);
1562 option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1563 return (0);
1567 * setactivefilter - set the active filter for packets. Returns 1 upon
1568 * successful processing of options, and 0 otherwise.
1570 /*ARGSUSED*/
1571 static int
1572 setactivefilter(argv, opt)
1573 char **argv;
1574 option_t *opt;
1576 pc.linktype = DLT_PPP;
1577 pc.snapshot = PPP_HDRLEN;
1579 if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1580 return (1);
1581 option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1582 return (0);
1584 #endif /* PPP_FILTER */
1587 * noopt - disable all options. Returns 1 upon successful processing of
1588 * options, and 0 otherwise.
1590 /*ARGSUSED*/
1591 static int
1592 noopt(argv, opt)
1593 char **argv;
1594 option_t *opt;
1596 BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
1597 BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
1598 BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
1599 BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
1601 return (1);
1605 * setdomain - set domain name to append to hostname. Returns 1 upon
1606 * successful processing of options, and 0 otherwise.
1608 /*ARGSUSED*/
1609 static int
1610 setdomain(argv, opt)
1611 char **argv;
1612 option_t *opt;
1614 if (!privileged_option) {
1615 option_error("using the domain option requires root privilege");
1616 return (0);
1618 (void) gethostname(hostname, MAXHOSTNAMELEN+1);
1619 if (**argv != '\0') {
1620 if (**argv != '.')
1621 (void) strncat(hostname, ".", MAXHOSTNAMELEN - strlen(hostname));
1622 (void) strncat(hostname, *argv, MAXHOSTNAMELEN - strlen(hostname));
1624 hostname[MAXHOSTNAMELEN] = '\0';
1625 return (1);
1630 * setspeed - set the speed. Returns 1 upon successful processing of options,
1631 * and 0 otherwise.
1633 static int
1634 setspeed(arg)
1635 char *arg;
1637 char *ptr;
1638 int spd;
1640 if (prepass)
1641 return (1);
1642 spd = strtol(arg, &ptr, 0);
1643 if (ptr == arg || *ptr != '\0' || spd <= 0)
1644 return (0);
1645 inspeed = spd;
1646 save_source(&speed_info);
1647 return (1);
1652 * setdevname - set the device name. Returns 1 upon successful processing of
1653 * options, 0 when the device does not exist, and -1 when an error is
1654 * encountered.
1656 static int
1657 setdevname(cp)
1658 char *cp;
1660 struct stat statbuf;
1661 char dev[MAXPATHLEN];
1663 if (*cp == '\0')
1664 return (0);
1666 if (strncmp("/dev/", cp, 5) != 0) {
1667 (void) strlcpy(dev, "/dev/", sizeof(dev));
1668 (void) strlcat(dev, cp, sizeof(dev));
1669 cp = dev;
1673 * Check if there is a character device by this name.
1675 if (stat(cp, &statbuf) < 0) {
1676 if (errno == ENOENT) {
1677 return (0);
1679 option_error("Couldn't stat '%s': %m", cp);
1680 return (-1);
1682 if (!S_ISCHR(statbuf.st_mode)) {
1683 option_error("'%s' is not a character device", cp);
1684 return (-1);
1687 if (phase != PHASE_INITIALIZE) {
1688 option_error("device name cannot be changed after initialization");
1689 return (-1);
1690 } else if (devnam_fixed) {
1691 option_error("per-tty options file may not specify device name");
1692 return (-1);
1695 if (devnam_info.priv && !privileged_option) {
1696 option_error("device name %s from %s cannot be overridden",
1697 devnam, name_source(&devnam_info));
1698 return (-1);
1701 (void) strlcpy(devnam, cp, sizeof(devnam));
1702 devstat = statbuf;
1703 default_device = 0;
1704 save_source(&devnam_info);
1706 return (1);
1711 * setipaddr - set the IP address. Returns 1 upon successful processing of
1712 * options, 0 when the argument does not contain a `:', and -1 for error.
1714 static int
1715 setipaddr(arg)
1716 char *arg;
1718 struct hostent *hp;
1719 char *colon;
1720 u_int32_t local, remote;
1721 ipcp_options *wo = &ipcp_wantoptions[0];
1724 * IP address pair separated by ":".
1726 if ((colon = strchr(arg, ':')) == NULL)
1727 return (0);
1728 if (prepass)
1729 return (1);
1732 * If colon first character, then no local addr.
1734 if (colon != arg) {
1735 *colon = '\0';
1736 if ((local = inet_addr(arg)) == (u_int32_t) -1) {
1737 if ((hp = gethostbyname(arg)) == NULL) {
1738 option_error("unknown host: %s", arg);
1739 return (-1);
1740 } else {
1741 BCOPY(hp->h_addr, &local, sizeof(local));
1744 if (bad_ip_adrs(local)) {
1745 option_error("bad local IP address %I", local);
1746 return (-1);
1748 if (local != 0) {
1749 save_source(&ipsrc_info);
1750 wo->ouraddr = local;
1752 *colon = ':';
1756 * If colon last character, then no remote addr.
1758 if (*++colon != '\0') {
1759 if ((remote = inet_addr(colon)) == (u_int32_t) -1) {
1760 if ((hp = gethostbyname(colon)) == NULL) {
1761 option_error("unknown host: %s", colon);
1762 return (-1);
1763 } else {
1764 BCOPY(hp->h_addr, &remote, sizeof(remote));
1765 if (remote_name[0] == '\0')
1766 (void) strlcpy(remote_name, colon, sizeof(remote_name));
1769 if (bad_ip_adrs(remote)) {
1770 option_error("bad remote IP address %I", remote);
1771 return (-1);
1773 if (remote != 0) {
1774 save_source(&ipdst_info);
1775 wo->hisaddr = remote;
1779 return (1);
1784 * setnetmask - set the netmask to be used on the interface. Returns 1 upon
1785 * successful processing of options, and 0 otherwise.
1787 /*ARGSUSED*/
1788 static int
1789 setnetmask(argv, opt)
1790 char **argv;
1791 option_t *opt;
1793 u_int32_t mask;
1794 int n;
1795 char *p;
1798 * Unfortunately, if we use inet_addr, we can't tell whether
1799 * a result of all 1s is an error or a valid 255.255.255.255.
1801 p = *argv;
1802 n = parse_dotted_ip(p, &mask);
1804 mask = htonl(mask);
1806 if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
1807 option_error("invalid netmask value '%s'", *argv);
1808 return (0);
1811 netmask = mask;
1812 return (1);
1816 * parse_dotted_ip - parse and convert the IP address string to make
1817 * sure it conforms to the dotted notation. Returns the length of
1818 * processed characters upon success, and 0 otherwise. If successful,
1819 * the converted IP address number is stored in vp, in the host byte
1820 * order.
1823 parse_dotted_ip(cp, vp)
1824 register char *cp;
1825 u_int32_t *vp;
1827 register u_int32_t val, base, n;
1828 register char c;
1829 char *cp0 = cp;
1830 u_char parts[3], *pp = parts;
1832 if ((*cp == '\0') || (vp == NULL))
1833 return (0); /* disallow null string in cp */
1834 *vp = 0;
1835 again:
1837 * Collect number up to ``.''. Values are specified as for C:
1838 * 0x=hex, 0=octal, other=decimal.
1840 val = 0; base = 10;
1841 if (*cp == '0') {
1842 if (*++cp == 'x' || *cp == 'X')
1843 base = 16, cp++;
1844 else
1845 base = 8;
1847 while ((c = *cp) != '\0') {
1848 if (isdigit(c)) {
1849 if ((c - '0') >= base)
1850 break;
1851 val = (val * base) + (c - '0');
1852 cp++;
1853 continue;
1855 if (base == 16 && isxdigit(c)) {
1856 val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
1857 cp++;
1858 continue;
1860 break;
1862 if (*cp == '.') {
1864 * Internet format:
1865 * a.b.c.d
1866 * a.b.c (with c treated as 16-bits)
1867 * a.b (with b treated as 24 bits)
1869 if ((pp >= parts + 3) || (val > 0xff)) {
1870 return (0);
1872 *pp++ = (u_char)val;
1873 cp++;
1874 goto again;
1877 * Check for trailing characters.
1879 if (*cp != '\0' && !isspace(*cp)) {
1880 return (0);
1883 * Concoct the address according to the number of parts specified.
1885 n = pp - parts;
1886 switch (n) {
1887 case 0: /* a -- 32 bits */
1888 break;
1889 case 1: /* a.b -- 8.24 bits */
1890 if (val > 0xffffff)
1891 return (0);
1892 val |= parts[0] << 24;
1893 break;
1894 case 2: /* a.b.c -- 8.8.16 bits */
1895 if (val > 0xffff)
1896 return (0);
1897 val |= (parts[0] << 24) | (parts[1] << 16);
1898 break;
1899 case 3: /* a.b.c.d -- 8.8.8.8 bits */
1900 if (val > 0xff)
1901 return (0);
1902 val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
1903 break;
1904 default:
1905 return (0);
1907 *vp = val;
1908 return (cp - cp0);
1912 * setxonxoff - modify the asyncmap to include escaping XON and XOFF
1913 * characters used for software flow control. Returns 1 upon successful
1914 * processing of options, and 0 otherwise.
1916 /*ARGSUSED*/
1917 static int
1918 setxonxoff(argv, opt)
1919 char **argv;
1920 option_t *opt;
1922 int xonxoff = 0x000A0000;
1924 lcp_wantoptions[0].neg_asyncmap = 1;
1925 lcp_wantoptions[0].asyncmap |= xonxoff; /* escape ^S and ^Q */
1926 lcp_allowoptions[0].asyncmap |= xonxoff;
1927 xmit_accm[0][0] |= xonxoff;
1928 xmit_accm[0][4] |= xonxoff; /* escape 0x91 and 0x93 as well */
1930 crtscts = -2;
1931 return (1);
1935 * setlogfile - open (or create) a file used for logging purposes. Returns 1
1936 * upon success, and 0 otherwise.
1938 /*ARGSUSED*/
1939 static int
1940 setlogfile(argv, opt)
1941 char **argv;
1942 option_t *opt;
1944 int fd, err;
1946 if (!privileged_option)
1947 (void) seteuid(getuid());
1948 fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1949 if (fd < 0 && errno == EEXIST)
1950 fd = open(*argv, O_WRONLY | O_APPEND);
1951 err = errno;
1952 if (!privileged_option)
1953 (void) seteuid(0);
1954 if (fd < 0) {
1955 errno = err;
1956 option_error("Can't open log file %s: %m", *argv);
1957 return (0);
1959 if (log_to_file && log_to_fd >= 0)
1960 (void) close(log_to_fd);
1961 log_to_fd = fd;
1962 log_to_file = 1;
1963 early_log = 0;
1964 return (1);
1967 #ifdef PLUGIN
1969 * loadplugin - load and initialize the plugin. Returns 1 upon successful
1970 * processing of the plugin, and 0 otherwise.
1972 /*ARGSUSED*/
1973 static int
1974 loadplugin(argv, opt)
1975 char **argv;
1976 option_t *opt;
1978 char *arg = *argv;
1979 void *handle;
1980 const char *err;
1981 void (*init) __P((void));
1983 handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
1984 if (handle == NULL) {
1985 err = dlerror();
1986 if (err != NULL)
1987 option_error("%s", err);
1988 option_error("Couldn't load plugin %s", arg);
1989 return (0);
1991 init = (void (*)(void))dlsym(handle, "plugin_init");
1992 if (init == NULL) {
1993 option_error("%s has no initialization entry point", arg);
1994 (void) dlclose(handle);
1995 return (0);
1997 info("Plugin %s loaded.", arg);
1998 (*init)();
1999 return (1);
2001 #endif /* PLUGIN */