1 | /* |
---|
2 | * options.c - handles option processing for PPP. |
---|
3 | * |
---|
4 | * Copyright (c) 1989 Carnegie Mellon University. |
---|
5 | * All rights reserved. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms are permitted |
---|
8 | * provided that the above copyright notice and this paragraph are |
---|
9 | * duplicated in all such forms and that any documentation, |
---|
10 | * advertising materials, and other materials related to such |
---|
11 | * distribution and use acknowledge that the software was developed |
---|
12 | * by Carnegie Mellon University. The name of the |
---|
13 | * University may not be used to endorse or promote products derived |
---|
14 | * from this software without specific prior written permission. |
---|
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
---|
16 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
---|
17 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
---|
18 | */ |
---|
19 | |
---|
20 | #define RCSID "$Id$" |
---|
21 | |
---|
22 | #include <ctype.h> |
---|
23 | #include <stdio.h> |
---|
24 | #include <errno.h> |
---|
25 | #include <unistd.h> |
---|
26 | #include <fcntl.h> |
---|
27 | #include <stdlib.h> |
---|
28 | #include <termios.h> |
---|
29 | #include <string.h> |
---|
30 | #include <netdb.h> |
---|
31 | #include <pwd.h> |
---|
32 | #include <sys/types.h> |
---|
33 | #include <sys/stat.h> |
---|
34 | #include <netinet/in.h> |
---|
35 | #include <arpa/inet.h> |
---|
36 | #ifdef PLUGIN |
---|
37 | #include <dlfcn.h> |
---|
38 | #endif |
---|
39 | #ifdef PPP_FILTER |
---|
40 | #include <pcap.h> |
---|
41 | #include <pcap-int.h> /* XXX: To get struct pcap */ |
---|
42 | #endif |
---|
43 | |
---|
44 | #include "pppd.h" |
---|
45 | #include "pathnames.h" |
---|
46 | #include "patchlevel.h" |
---|
47 | #include "fsm.h" |
---|
48 | #include "lcp.h" |
---|
49 | #include "ipcp.h" |
---|
50 | #include "upap.h" |
---|
51 | #include "chap.h" |
---|
52 | #include "ccp.h" |
---|
53 | |
---|
54 | #include <net/ppp-comp.h> |
---|
55 | |
---|
56 | #if defined(ultrix) || defined(NeXT) |
---|
57 | char *strdup __P((char *)); |
---|
58 | #endif |
---|
59 | |
---|
60 | static const char rcsid[] = RCSID; |
---|
61 | |
---|
62 | /* |
---|
63 | * Option variables and default values. |
---|
64 | */ |
---|
65 | #ifdef PPP_FILTER |
---|
66 | int dflag = 0; /* Tell libpcap we want debugging */ |
---|
67 | #endif |
---|
68 | int debug = 0; /* Debug flag */ |
---|
69 | int kdebugflag = 0; /* Tell kernel to print debug messages */ |
---|
70 | int default_device = 1; /* Using /dev/tty or equivalent */ |
---|
71 | char devnam[MAXPATHLEN]; /* Device name */ |
---|
72 | int crtscts = 0; /* Use hardware flow control */ |
---|
73 | bool modem = 1; /* Use modem control lines */ |
---|
74 | int inspeed = 0; /* Input/Output speed requested */ |
---|
75 | u_int32_t netmask = 0; /* IP netmask to set on interface */ |
---|
76 | bool lockflag = 0; /* Create lock file to lock the serial dev */ |
---|
77 | bool nodetach = 0; /* Don't detach from controlling tty */ |
---|
78 | bool updetach = 0; /* Detach once link is up */ |
---|
79 | char *initializer = NULL; /* Script to initialize physical link */ |
---|
80 | char *connect_script = NULL; /* Script to establish physical link */ |
---|
81 | char *disconnect_script = NULL; /* Script to disestablish physical link */ |
---|
82 | char *welcomer = NULL; /* Script to run after phys link estab. */ |
---|
83 | char *ptycommand = NULL; /* Command to run on other side of pty */ |
---|
84 | int maxconnect = 0; /* Maximum connect time */ |
---|
85 | char user[MAXNAMELEN]; /* Username for PAP */ |
---|
86 | char passwd[MAXSECRETLEN]; /* Password for PAP */ |
---|
87 | bool persist = 0; /* Reopen link after it goes down */ |
---|
88 | char our_name[MAXNAMELEN]; /* Our name for authentication purposes */ |
---|
89 | bool demand = 0; /* do dial-on-demand */ |
---|
90 | char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ |
---|
91 | int idle_time_limit = 0; /* Disconnect if idle for this many seconds */ |
---|
92 | int holdoff = 30; /* # seconds to pause before reconnecting */ |
---|
93 | bool holdoff_specified; /* true if a holdoff value has been given */ |
---|
94 | bool notty = 0; /* Stdin/out is not a tty */ |
---|
95 | char *record_file = NULL; /* File to record chars sent/received */ |
---|
96 | int using_pty = 0; |
---|
97 | bool sync_serial = 0; /* Device is synchronous serial device */ |
---|
98 | int log_to_fd = 1; /* send log messages to this fd too */ |
---|
99 | int maxfail = 10; /* max # of unsuccessful connection attempts */ |
---|
100 | char linkname[MAXPATHLEN]; /* logical name for link */ |
---|
101 | bool tune_kernel; /* may alter kernel settings */ |
---|
102 | int connect_delay = 1000; /* wait this many ms after connect script */ |
---|
103 | |
---|
104 | extern option_t auth_options[]; |
---|
105 | extern struct stat devstat; |
---|
106 | extern int prepass; /* Doing pre-pass to find device name */ |
---|
107 | |
---|
108 | struct option_info initializer_info; |
---|
109 | struct option_info connect_script_info; |
---|
110 | struct option_info disconnect_script_info; |
---|
111 | struct option_info welcomer_info; |
---|
112 | struct option_info devnam_info; |
---|
113 | struct option_info ptycommand_info; |
---|
114 | |
---|
115 | #ifdef PPP_FILTER |
---|
116 | struct bpf_program pass_filter;/* Filter program for packets to pass */ |
---|
117 | struct bpf_program active_filter; /* Filter program for link-active pkts */ |
---|
118 | pcap_t pc; /* Fake struct pcap so we can compile expr */ |
---|
119 | #endif |
---|
120 | |
---|
121 | char *current_option; /* the name of the option being parsed */ |
---|
122 | int privileged_option; /* set iff the current option came from root */ |
---|
123 | char *option_source; /* string saying where the option came from */ |
---|
124 | bool log_to_file; /* log_to_fd is a file opened by us */ |
---|
125 | |
---|
126 | /* |
---|
127 | * Prototypes |
---|
128 | */ |
---|
129 | static int setdevname __P((char *)); |
---|
130 | static int setipaddr __P((char *)); |
---|
131 | static int setspeed __P((char *)); |
---|
132 | static int noopt __P((char **)); |
---|
133 | static int setdomain __P((char **)); |
---|
134 | static int setnetmask __P((char **)); |
---|
135 | static int setxonxoff __P((char **)); |
---|
136 | static int readfile __P((char **)); |
---|
137 | static int callfile __P((char **)); |
---|
138 | static void usage __P((void)); |
---|
139 | static int setlogfile __P((char **)); |
---|
140 | #ifdef PLUGIN |
---|
141 | static int loadplugin __P((char **)); |
---|
142 | #endif |
---|
143 | |
---|
144 | #ifdef PPP_FILTER |
---|
145 | static int setpassfilter __P((char **)); |
---|
146 | static int setactivefilter __P((char **)); |
---|
147 | #endif |
---|
148 | |
---|
149 | static option_t *find_option __P((char *name)); |
---|
150 | static int process_option __P((option_t *, char **)); |
---|
151 | static int n_arguments __P((option_t *)); |
---|
152 | static int number_option __P((char *, u_int32_t *, int)); |
---|
153 | |
---|
154 | /* |
---|
155 | * Structure to store extra lists of options. |
---|
156 | */ |
---|
157 | struct option_list { |
---|
158 | option_t *options; |
---|
159 | struct option_list *next; |
---|
160 | }; |
---|
161 | |
---|
162 | static struct option_list *extra_options = NULL; |
---|
163 | |
---|
164 | /* |
---|
165 | * Valid arguments. |
---|
166 | */ |
---|
167 | option_t general_options[] = { |
---|
168 | { "debug", o_int, &debug, |
---|
169 | "Increase debugging level", OPT_INC|OPT_NOARG|1 }, |
---|
170 | { "-d", o_int, &debug, |
---|
171 | "Increase debugging level", OPT_INC|OPT_NOARG|1 }, |
---|
172 | { "kdebug", o_int, &kdebugflag, |
---|
173 | "Set kernel driver debug level" }, |
---|
174 | { "nodetach", o_bool, &nodetach, |
---|
175 | "Don't detach from controlling tty", 1 }, |
---|
176 | { "-detach", o_bool, &nodetach, |
---|
177 | "Don't detach from controlling tty", 1 }, |
---|
178 | { "updetach", o_bool, &updetach, |
---|
179 | "Detach from controlling tty once link is up", 1 }, |
---|
180 | { "holdoff", o_int, &holdoff, |
---|
181 | "Set time in seconds before retrying connection" }, |
---|
182 | { "idle", o_int, &idle_time_limit, |
---|
183 | "Set time in seconds before disconnecting idle link" }, |
---|
184 | { "lock", o_bool, &lockflag, |
---|
185 | "Lock serial device with UUCP-style lock file", 1 }, |
---|
186 | { "-all", o_special_noarg, noopt, |
---|
187 | "Don't request/allow any LCP or IPCP options (useless)" }, |
---|
188 | { "init", o_string, &initializer, |
---|
189 | "A program to initialize the device", |
---|
190 | OPT_A2INFO | OPT_PRIVFIX, &initializer_info }, |
---|
191 | { "connect", o_string, &connect_script, |
---|
192 | "A program to set up a connection", |
---|
193 | OPT_A2INFO | OPT_PRIVFIX, &connect_script_info }, |
---|
194 | { "disconnect", o_string, &disconnect_script, |
---|
195 | "Program to disconnect serial device", |
---|
196 | OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info }, |
---|
197 | { "welcome", o_string, &welcomer, |
---|
198 | "Script to welcome client", |
---|
199 | OPT_A2INFO | OPT_PRIVFIX, &welcomer_info }, |
---|
200 | { "pty", o_string, &ptycommand, |
---|
201 | "Script to run on pseudo-tty master side", |
---|
202 | OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info }, |
---|
203 | { "notty", o_bool, ¬ty, |
---|
204 | "Input/output is not a tty", OPT_DEVNAM | 1 }, |
---|
205 | { "record", o_string, &record_file, |
---|
206 | "Record characters sent/received to file" }, |
---|
207 | { "maxconnect", o_int, &maxconnect, |
---|
208 | "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF }, |
---|
209 | { "crtscts", o_int, &crtscts, |
---|
210 | "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) }, |
---|
211 | { "nocrtscts", o_int, &crtscts, |
---|
212 | "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, |
---|
213 | { "-crtscts", o_int, &crtscts, |
---|
214 | "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, |
---|
215 | { "cdtrcts", o_int, &crtscts, |
---|
216 | "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) }, |
---|
217 | { "nocdtrcts", o_int, &crtscts, |
---|
218 | "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, |
---|
219 | { "xonxoff", o_special_noarg, setxonxoff, |
---|
220 | "Set software (XON/XOFF) flow control" }, |
---|
221 | { "domain", o_special, setdomain, |
---|
222 | "Add given domain name to hostname" }, |
---|
223 | { "mtu", o_int, &lcp_allowoptions[0].mru, |
---|
224 | "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, |
---|
225 | { "netmask", o_special, setnetmask, |
---|
226 | "set netmask" }, |
---|
227 | { "modem", o_bool, &modem, |
---|
228 | "Use modem control lines", 1 }, |
---|
229 | { "local", o_bool, &modem, |
---|
230 | "Don't use modem control lines" }, |
---|
231 | { "file", o_special, readfile, |
---|
232 | "Take options from a file", OPT_PREPASS }, |
---|
233 | { "call", o_special, callfile, |
---|
234 | "Take options from a privileged file", OPT_PREPASS }, |
---|
235 | { "persist", o_bool, &persist, |
---|
236 | "Keep on reopening connection after close", 1 }, |
---|
237 | { "nopersist", o_bool, &persist, |
---|
238 | "Turn off persist option" }, |
---|
239 | { "demand", o_bool, &demand, |
---|
240 | "Dial on demand", OPT_INITONLY | 1, &persist }, |
---|
241 | { "sync", o_bool, &sync_serial, |
---|
242 | "Use synchronous HDLC serial encoding", 1 }, |
---|
243 | { "logfd", o_int, &log_to_fd, |
---|
244 | "Send log messages to this file descriptor" }, |
---|
245 | { "logfile", o_special, setlogfile, |
---|
246 | "Append log messages to this file" }, |
---|
247 | { "nolog", o_int, &log_to_fd, |
---|
248 | "Don't send log messages to any file", |
---|
249 | OPT_NOARG | OPT_VAL(-1) }, |
---|
250 | { "nologfd", o_int, &log_to_fd, |
---|
251 | "Don't send log messages to any file descriptor", |
---|
252 | OPT_NOARG | OPT_VAL(-1) }, |
---|
253 | { "linkname", o_string, linkname, |
---|
254 | "Set logical name for link", |
---|
255 | OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN }, |
---|
256 | { "maxfail", o_int, &maxfail, |
---|
257 | "Maximum number of unsuccessful connection attempts to allow" }, |
---|
258 | { "ktune", o_bool, &tune_kernel, |
---|
259 | "Alter kernel settings as necessary", 1 }, |
---|
260 | { "noktune", o_bool, &tune_kernel, |
---|
261 | "Don't alter kernel settings", 0 }, |
---|
262 | { "connect-delay", o_int, &connect_delay, |
---|
263 | "Maximum time (in ms) to wait after connect script finishes" }, |
---|
264 | #ifdef PLUGIN |
---|
265 | { "plugin", o_special, loadplugin, |
---|
266 | "Load a plug-in module into pppd", OPT_PRIV }, |
---|
267 | #endif |
---|
268 | |
---|
269 | #ifdef PPP_FILTER |
---|
270 | { "pdebug", o_int, &dflag, |
---|
271 | "libpcap debugging" }, |
---|
272 | { "pass-filter", 1, setpassfilter, |
---|
273 | "set filter for packets to pass" }, |
---|
274 | { "active-filter", 1, setactivefilter, |
---|
275 | "set filter for active pkts" }, |
---|
276 | #endif |
---|
277 | |
---|
278 | { NULL } |
---|
279 | }; |
---|
280 | |
---|
281 | #ifndef IMPLEMENTATION |
---|
282 | #define IMPLEMENTATION "" |
---|
283 | #endif |
---|
284 | |
---|
285 | static char *usage_string = "\ |
---|
286 | pppd version %s.%d%s\n\ |
---|
287 | Usage: %s [ options ], where options are:\n\ |
---|
288 | <device> Communicate over the named device\n\ |
---|
289 | <speed> Set the baud rate to <speed>\n\ |
---|
290 | <loc>:<rem> Set the local and/or remote interface IP\n\ |
---|
291 | addresses. Either one may be omitted.\n\ |
---|
292 | asyncmap <n> Set the desired async map to hex <n>\n\ |
---|
293 | auth Require authentication from peer\n\ |
---|
294 | connect <p> Invoke shell command <p> to set up the serial line\n\ |
---|
295 | crtscts Use hardware RTS/CTS flow control\n\ |
---|
296 | defaultroute Add default route through interface\n\ |
---|
297 | file <f> Take options from file <f>\n\ |
---|
298 | modem Use modem control lines\n\ |
---|
299 | mru <n> Set MRU value to <n> for negotiation\n\ |
---|
300 | See pppd(8) for more options.\n\ |
---|
301 | "; |
---|
302 | |
---|
303 | /* |
---|
304 | * parse_args - parse a string of arguments from the command line. |
---|
305 | * If prepass is true, we are scanning for the device name and only |
---|
306 | * processing a few options, so error messages are suppressed. |
---|
307 | */ |
---|
308 | int |
---|
309 | parse_args(argc, argv) |
---|
310 | int argc; |
---|
311 | char **argv; |
---|
312 | { |
---|
313 | char *arg; |
---|
314 | option_t *opt; |
---|
315 | int ret; |
---|
316 | |
---|
317 | privileged_option = privileged; |
---|
318 | option_source = "command line"; |
---|
319 | while (argc > 0) { |
---|
320 | arg = *argv++; |
---|
321 | --argc; |
---|
322 | |
---|
323 | /* |
---|
324 | * First see if it's an option in the new option list. |
---|
325 | */ |
---|
326 | opt = find_option(arg); |
---|
327 | if (opt != NULL) { |
---|
328 | int n = n_arguments(opt); |
---|
329 | if (argc < n) { |
---|
330 | option_error("too few parameters for option %s", arg); |
---|
331 | return 0; |
---|
332 | } |
---|
333 | current_option = arg; |
---|
334 | if (!process_option(opt, argv)) |
---|
335 | return 0; |
---|
336 | argc -= n; |
---|
337 | argv += n; |
---|
338 | continue; |
---|
339 | } |
---|
340 | |
---|
341 | /* |
---|
342 | * Maybe a tty name, speed or IP address? |
---|
343 | */ |
---|
344 | if ((ret = setdevname(arg)) == 0 |
---|
345 | && (ret = setspeed(arg)) == 0 |
---|
346 | && (ret = setipaddr(arg)) == 0 |
---|
347 | && !prepass) { |
---|
348 | option_error("unrecognized option '%s'", arg); |
---|
349 | usage(); |
---|
350 | return 0; |
---|
351 | } |
---|
352 | if (ret < 0) /* error */ |
---|
353 | return 0; |
---|
354 | } |
---|
355 | return 1; |
---|
356 | } |
---|
357 | |
---|
358 | #if 0 |
---|
359 | /* |
---|
360 | * scan_args - scan the command line arguments to get the tty name, |
---|
361 | * if specified. Also checks whether the notty or pty option was given. |
---|
362 | */ |
---|
363 | void |
---|
364 | scan_args(argc, argv) |
---|
365 | int argc; |
---|
366 | char **argv; |
---|
367 | { |
---|
368 | char *arg; |
---|
369 | option_t *opt; |
---|
370 | |
---|
371 | privileged_option = privileged; |
---|
372 | while (argc > 0) { |
---|
373 | arg = *argv++; |
---|
374 | --argc; |
---|
375 | |
---|
376 | if (strcmp(arg, "notty") == 0 || strcmp(arg, "pty") == 0) |
---|
377 | using_pty = 1; |
---|
378 | |
---|
379 | /* Skip options and their arguments */ |
---|
380 | opt = find_option(arg); |
---|
381 | if (opt != NULL) { |
---|
382 | int n = n_arguments(opt); |
---|
383 | argc -= n; |
---|
384 | argv += n; |
---|
385 | continue; |
---|
386 | } |
---|
387 | |
---|
388 | /* Check if it's a tty name and copy it if so */ |
---|
389 | (void) setdevname(arg, 1); |
---|
390 | } |
---|
391 | } |
---|
392 | #endif |
---|
393 | |
---|
394 | /* |
---|
395 | * options_from_file - Read a string of options from a file, |
---|
396 | * and interpret them. |
---|
397 | */ |
---|
398 | int |
---|
399 | options_from_file(filename, must_exist, check_prot, priv) |
---|
400 | char *filename; |
---|
401 | int must_exist; |
---|
402 | int check_prot; |
---|
403 | int priv; |
---|
404 | { |
---|
405 | FILE *f; |
---|
406 | int i, newline, ret, err; |
---|
407 | option_t *opt; |
---|
408 | int oldpriv; |
---|
409 | char *oldsource; |
---|
410 | char *argv[MAXARGS]; |
---|
411 | char args[MAXARGS][MAXWORDLEN]; |
---|
412 | char cmd[MAXWORDLEN]; |
---|
413 | |
---|
414 | f = fopen(filename, "r"); |
---|
415 | err = errno; |
---|
416 | if (f == NULL) { |
---|
417 | if (!must_exist && err == ENOENT) |
---|
418 | return 1; |
---|
419 | errno = err; |
---|
420 | option_error("Can't open options file %s: %m", filename); |
---|
421 | return 0; |
---|
422 | } |
---|
423 | |
---|
424 | oldpriv = privileged_option; |
---|
425 | privileged_option = priv; |
---|
426 | oldsource = option_source; |
---|
427 | option_source = strdup(filename); |
---|
428 | if (option_source == NULL) |
---|
429 | option_source = "file"; |
---|
430 | ret = 0; |
---|
431 | while (getword(f, cmd, &newline, filename)) { |
---|
432 | /* |
---|
433 | * First see if it's a command. |
---|
434 | */ |
---|
435 | opt = find_option(cmd); |
---|
436 | if (opt != NULL) { |
---|
437 | int n = n_arguments(opt); |
---|
438 | for (i = 0; i < n; ++i) { |
---|
439 | if (!getword(f, args[i], &newline, filename)) { |
---|
440 | option_error( |
---|
441 | "In file %s: too few parameters for option '%s'", |
---|
442 | filename, cmd); |
---|
443 | goto err; |
---|
444 | } |
---|
445 | argv[i] = args[i]; |
---|
446 | } |
---|
447 | current_option = cmd; |
---|
448 | if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) { |
---|
449 | option_error("the %s option may not be used in the %s file", |
---|
450 | cmd, filename); |
---|
451 | goto err; |
---|
452 | } |
---|
453 | if (!process_option(opt, argv)) |
---|
454 | goto err; |
---|
455 | continue; |
---|
456 | } |
---|
457 | |
---|
458 | /* |
---|
459 | * Maybe a tty name, speed or IP address? |
---|
460 | */ |
---|
461 | if ((i = setdevname(cmd)) == 0 |
---|
462 | && (i = setspeed(cmd)) == 0 |
---|
463 | && (i = setipaddr(cmd)) == 0) { |
---|
464 | option_error("In file %s: unrecognized option '%s'", |
---|
465 | filename, cmd); |
---|
466 | goto err; |
---|
467 | } |
---|
468 | if (i < 0) /* error */ |
---|
469 | goto err; |
---|
470 | } |
---|
471 | ret = 1; |
---|
472 | |
---|
473 | err: |
---|
474 | fclose(f); |
---|
475 | privileged_option = oldpriv; |
---|
476 | option_source = oldsource; |
---|
477 | return ret; |
---|
478 | } |
---|
479 | |
---|
480 | /* |
---|
481 | * options_from_user - See if the use has a ~/.ppprc file, |
---|
482 | * and if so, interpret options from it. |
---|
483 | */ |
---|
484 | int |
---|
485 | options_from_user() |
---|
486 | { |
---|
487 | return 0; |
---|
488 | } |
---|
489 | |
---|
490 | /* |
---|
491 | * options_for_tty - See if an options file exists for the serial |
---|
492 | * device, and if so, interpret options from it. |
---|
493 | */ |
---|
494 | int |
---|
495 | options_for_tty() |
---|
496 | { |
---|
497 | char *dev, *path, *p; |
---|
498 | int ret; |
---|
499 | size_t pl; |
---|
500 | |
---|
501 | dev = devnam; |
---|
502 | if (strncmp(dev, "/dev/", 5) == 0) |
---|
503 | dev += 5; |
---|
504 | if (dev[0] == 0 || strcmp(dev, "tty") == 0) |
---|
505 | return 1; /* don't look for /etc/ppp/options.tty */ |
---|
506 | pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1; |
---|
507 | path = malloc(pl); |
---|
508 | if (path == NULL) |
---|
509 | novm("tty init file name"); |
---|
510 | slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev); |
---|
511 | /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */ |
---|
512 | for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p) |
---|
513 | if (*p == '/') |
---|
514 | *p = '.'; |
---|
515 | ret = options_from_file(path, 0, 0, 1); |
---|
516 | free(path); |
---|
517 | return ret; |
---|
518 | } |
---|
519 | |
---|
520 | /* |
---|
521 | * options_from_list - process a string of options in a wordlist. |
---|
522 | */ |
---|
523 | int |
---|
524 | options_from_list(w, priv) |
---|
525 | struct wordlist *w; |
---|
526 | int priv; |
---|
527 | { |
---|
528 | char *argv[MAXARGS]; |
---|
529 | option_t *opt; |
---|
530 | int i, ret = 0; |
---|
531 | |
---|
532 | privileged_option = priv; |
---|
533 | option_source = "secrets file"; |
---|
534 | |
---|
535 | while (w != NULL) { |
---|
536 | /* |
---|
537 | * First see if it's a command. |
---|
538 | */ |
---|
539 | opt = find_option(w->word); |
---|
540 | if (opt != NULL) { |
---|
541 | int n = n_arguments(opt); |
---|
542 | struct wordlist *w0 = w; |
---|
543 | for (i = 0; i < n; ++i) { |
---|
544 | w = w->next; |
---|
545 | if (w == NULL) { |
---|
546 | option_error( |
---|
547 | "In secrets file: too few parameters for option '%s'", |
---|
548 | w0->word); |
---|
549 | goto err; |
---|
550 | } |
---|
551 | argv[i] = w->word; |
---|
552 | } |
---|
553 | current_option = w0->word; |
---|
554 | if (!process_option(opt, argv)) |
---|
555 | goto err; |
---|
556 | w = w->next; |
---|
557 | continue; |
---|
558 | } |
---|
559 | |
---|
560 | /* |
---|
561 | * Maybe a tty name, speed or IP address? |
---|
562 | */ |
---|
563 | if ((i = setdevname(w->word)) == 0 |
---|
564 | && (i = setspeed(w->word)) == 0 |
---|
565 | && (i = setipaddr(w->word)) == 0) { |
---|
566 | option_error("In secrets file: unrecognized option '%s'", |
---|
567 | w->word); |
---|
568 | goto err; |
---|
569 | } |
---|
570 | if (i < 0) /* error */ |
---|
571 | goto err; |
---|
572 | w = w->next; |
---|
573 | } |
---|
574 | ret = 1; |
---|
575 | |
---|
576 | err: |
---|
577 | return ret; |
---|
578 | } |
---|
579 | |
---|
580 | /* |
---|
581 | * find_option - scan the option lists for the various protocols |
---|
582 | * looking for an entry with the given name. |
---|
583 | * This could be optimized by using a hash table. |
---|
584 | */ |
---|
585 | static option_t * |
---|
586 | find_option(name) |
---|
587 | char *name; |
---|
588 | { |
---|
589 | option_t *opt; |
---|
590 | struct option_list *list; |
---|
591 | int i; |
---|
592 | |
---|
593 | for (list = extra_options; list != NULL; list = list->next) |
---|
594 | for (opt = list->options; opt->name != NULL; ++opt) |
---|
595 | if (strcmp(name, opt->name) == 0) |
---|
596 | return opt; |
---|
597 | for (opt = general_options; opt->name != NULL; ++opt) |
---|
598 | if (strcmp(name, opt->name) == 0) |
---|
599 | return opt; |
---|
600 | for (opt = auth_options; opt->name != NULL; ++opt) |
---|
601 | if (strcmp(name, opt->name) == 0) |
---|
602 | return opt; |
---|
603 | for (i = 0; protocols[i] != NULL; ++i) |
---|
604 | if ((opt = protocols[i]->options) != NULL) |
---|
605 | for (; opt->name != NULL; ++opt) |
---|
606 | if (strcmp(name, opt->name) == 0) |
---|
607 | return opt; |
---|
608 | return NULL; |
---|
609 | } |
---|
610 | |
---|
611 | /* |
---|
612 | * process_option - process one new-style option. |
---|
613 | */ |
---|
614 | static int |
---|
615 | process_option(opt, argv) |
---|
616 | option_t *opt; |
---|
617 | char **argv; |
---|
618 | { |
---|
619 | u_int32_t v; |
---|
620 | int iv, a; |
---|
621 | char *sv; |
---|
622 | int (*parser) __P((char **)); |
---|
623 | |
---|
624 | if ((opt->flags & OPT_PREPASS) == 0 && prepass) |
---|
625 | return 1; |
---|
626 | if ((opt->flags & OPT_INITONLY) && pppd_phase != PHASE_INITIALIZE) { |
---|
627 | option_error("it's too late to use the %s option", opt->name); |
---|
628 | return 0; |
---|
629 | } |
---|
630 | if ((opt->flags & OPT_PRIV) && !privileged_option) { |
---|
631 | option_error("using the %s option requires root privilege", opt->name); |
---|
632 | return 0; |
---|
633 | } |
---|
634 | if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) { |
---|
635 | option_error("%s option is disabled", opt->name); |
---|
636 | return 0; |
---|
637 | } |
---|
638 | if ((opt->flags & OPT_PRIVFIX) && !privileged_option) { |
---|
639 | struct option_info *ip = (struct option_info *) opt->addr2; |
---|
640 | if (ip && ip->priv) { |
---|
641 | option_error("%s option cannot be overridden", opt->name); |
---|
642 | return 0; |
---|
643 | } |
---|
644 | } |
---|
645 | |
---|
646 | switch (opt->type) { |
---|
647 | case o_bool: |
---|
648 | v = opt->flags & OPT_VALUE; |
---|
649 | *(bool *)(opt->addr) = v; |
---|
650 | if (opt->addr2 && (opt->flags & OPT_A2COPY)) |
---|
651 | *(bool *)(opt->addr2) = v; |
---|
652 | break; |
---|
653 | |
---|
654 | case o_int: |
---|
655 | iv = 0; |
---|
656 | if ((opt->flags & OPT_NOARG) == 0) { |
---|
657 | if (!int_option(*argv, &iv)) |
---|
658 | return 0; |
---|
659 | if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit) |
---|
660 | || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit)) |
---|
661 | && !((opt->flags & OPT_ZEROOK && iv == 0))) { |
---|
662 | char *zok = (opt->flags & OPT_ZEROOK)? " zero or": ""; |
---|
663 | switch (opt->flags & OPT_LIMITS) { |
---|
664 | case OPT_LLIMIT: |
---|
665 | option_error("%s value must be%s >= %d", |
---|
666 | opt->name, zok, opt->lower_limit); |
---|
667 | break; |
---|
668 | case OPT_ULIMIT: |
---|
669 | option_error("%s value must be%s <= %d", |
---|
670 | opt->name, zok, opt->upper_limit); |
---|
671 | break; |
---|
672 | case OPT_LIMITS: |
---|
673 | option_error("%s value must be%s between %d and %d", |
---|
674 | opt->name, opt->lower_limit, opt->upper_limit); |
---|
675 | break; |
---|
676 | } |
---|
677 | return 0; |
---|
678 | } |
---|
679 | } |
---|
680 | a = opt->flags & OPT_VALUE; |
---|
681 | if (a >= 128) |
---|
682 | a -= 256; /* sign extend */ |
---|
683 | iv += a; |
---|
684 | if (opt->flags & OPT_INC) |
---|
685 | iv += *(int *)(opt->addr); |
---|
686 | if ((opt->flags & OPT_NOINCR) && !privileged_option) { |
---|
687 | int oldv = *(int *)(opt->addr); |
---|
688 | if ((opt->flags & OPT_ZEROINF) ? |
---|
689 | (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) { |
---|
690 | option_error("%s value cannot be increased", opt->name); |
---|
691 | return 0; |
---|
692 | } |
---|
693 | } |
---|
694 | *(int *)(opt->addr) = iv; |
---|
695 | if (opt->addr2 && (opt->flags & OPT_A2COPY)) |
---|
696 | *(int *)(opt->addr2) = iv; |
---|
697 | break; |
---|
698 | |
---|
699 | case o_uint32: |
---|
700 | if (opt->flags & OPT_NOARG) { |
---|
701 | v = opt->flags & OPT_VALUE; |
---|
702 | } else if (!number_option(*argv, &v, 16)) |
---|
703 | return 0; |
---|
704 | if (opt->flags & OPT_OR) |
---|
705 | v |= *(u_int32_t *)(opt->addr); |
---|
706 | *(u_int32_t *)(opt->addr) = v; |
---|
707 | if (opt->addr2 && (opt->flags & OPT_A2COPY)) |
---|
708 | *(u_int32_t *)(opt->addr2) = v; |
---|
709 | break; |
---|
710 | |
---|
711 | case o_string: |
---|
712 | if (opt->flags & OPT_STATIC) { |
---|
713 | strlcpy((char *)(opt->addr), *argv, opt->upper_limit); |
---|
714 | } else { |
---|
715 | sv = strdup(*argv); |
---|
716 | if (sv == NULL) |
---|
717 | novm("option argument"); |
---|
718 | if ( *(char **)(opt->addr) != NULL ) { |
---|
719 | free((void *)*(char **)(opt->addr)); |
---|
720 | *(char **)(opt->addr) = NULL; |
---|
721 | } |
---|
722 | *(char **)(opt->addr) = sv; |
---|
723 | } |
---|
724 | break; |
---|
725 | |
---|
726 | case o_special_noarg: |
---|
727 | case o_special: |
---|
728 | parser = (int (*) __P((char **))) opt->addr; |
---|
729 | if (!(*parser)(argv)) |
---|
730 | return 0; |
---|
731 | break; |
---|
732 | } |
---|
733 | |
---|
734 | if (opt->addr2) { |
---|
735 | if (opt->flags & OPT_A2INFO) { |
---|
736 | struct option_info *ip = (struct option_info *) opt->addr2; |
---|
737 | ip->priv = privileged_option; |
---|
738 | ip->source = option_source; |
---|
739 | } else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0) |
---|
740 | *(bool *)(opt->addr2) = 1; |
---|
741 | } |
---|
742 | |
---|
743 | return 1; |
---|
744 | } |
---|
745 | |
---|
746 | /* |
---|
747 | * n_arguments - tell how many arguments an option takes |
---|
748 | */ |
---|
749 | static int |
---|
750 | n_arguments(opt) |
---|
751 | option_t *opt; |
---|
752 | { |
---|
753 | return (opt->type == o_bool || opt->type == o_special_noarg |
---|
754 | || (opt->flags & OPT_NOARG))? 0: 1; |
---|
755 | } |
---|
756 | |
---|
757 | /* |
---|
758 | * add_options - add a list of options to the set we grok. |
---|
759 | */ |
---|
760 | void |
---|
761 | add_options(opt) |
---|
762 | option_t *opt; |
---|
763 | { |
---|
764 | struct option_list *list; |
---|
765 | |
---|
766 | list = malloc(sizeof(*list)); |
---|
767 | if (list == 0) |
---|
768 | novm("option list entry"); |
---|
769 | list->options = opt; |
---|
770 | list->next = extra_options; |
---|
771 | extra_options = list; |
---|
772 | } |
---|
773 | |
---|
774 | /* |
---|
775 | * usage - print out a message telling how to use the program. |
---|
776 | */ |
---|
777 | static void |
---|
778 | usage() |
---|
779 | { |
---|
780 | if (pppd_phase == PHASE_INITIALIZE) |
---|
781 | fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION, |
---|
782 | "rtems_pppd"); |
---|
783 | } |
---|
784 | |
---|
785 | /* |
---|
786 | * option_error - print a message about an error in an option. |
---|
787 | * The message is logged, and also sent to |
---|
788 | * stderr if pppd_phase == PHASE_INITIALIZE. |
---|
789 | */ |
---|
790 | void |
---|
791 | option_error __V((char *fmt, ...)) |
---|
792 | { |
---|
793 | va_list args; |
---|
794 | char buf[256]; |
---|
795 | |
---|
796 | #if defined(__STDC__) |
---|
797 | va_start(args, fmt); |
---|
798 | #else |
---|
799 | char *fmt; |
---|
800 | va_start(args); |
---|
801 | fmt = va_arg(args, char *); |
---|
802 | #endif |
---|
803 | if (prepass) { |
---|
804 | va_end(args); |
---|
805 | return; |
---|
806 | } |
---|
807 | vslprintf(buf, sizeof(buf), fmt, args); |
---|
808 | va_end(args); |
---|
809 | |
---|
810 | fprintf(stderr, "pppd: %s\n", buf); |
---|
811 | } |
---|
812 | |
---|
813 | /* |
---|
814 | * Read a word from a file. |
---|
815 | * Words are delimited by white-space or by quotes (" or '). |
---|
816 | * Quotes, white-space and \ may be escaped with \. |
---|
817 | * \<newline> is ignored. |
---|
818 | */ |
---|
819 | int |
---|
820 | getword(f, word, newlinep, filename) |
---|
821 | FILE *f; |
---|
822 | char *word; |
---|
823 | int *newlinep; |
---|
824 | char *filename; |
---|
825 | { |
---|
826 | int c, len, escape; |
---|
827 | int quoted, comment; |
---|
828 | int value, digit, got, n; |
---|
829 | |
---|
830 | #define isoctal(c) ((c) >= '0' && (c) < '8') |
---|
831 | |
---|
832 | *newlinep = 0; |
---|
833 | len = 0; |
---|
834 | escape = 0; |
---|
835 | comment = 0; |
---|
836 | |
---|
837 | /* |
---|
838 | * First skip white-space and comments. |
---|
839 | */ |
---|
840 | for (;;) { |
---|
841 | c = getc(f); |
---|
842 | if (c == EOF) |
---|
843 | break; |
---|
844 | |
---|
845 | /* |
---|
846 | * A newline means the end of a comment; backslash-newline |
---|
847 | * is ignored. Note that we cannot have escape && comment. |
---|
848 | */ |
---|
849 | if (c == '\n') { |
---|
850 | if (!escape) { |
---|
851 | *newlinep = 1; |
---|
852 | comment = 0; |
---|
853 | } else |
---|
854 | escape = 0; |
---|
855 | continue; |
---|
856 | } |
---|
857 | |
---|
858 | /* |
---|
859 | * Ignore characters other than newline in a comment. |
---|
860 | */ |
---|
861 | if (comment) |
---|
862 | continue; |
---|
863 | |
---|
864 | /* |
---|
865 | * If this character is escaped, we have a word start. |
---|
866 | */ |
---|
867 | if (escape) |
---|
868 | break; |
---|
869 | |
---|
870 | /* |
---|
871 | * If this is the escape character, look at the next character. |
---|
872 | */ |
---|
873 | if (c == '\\') { |
---|
874 | escape = 1; |
---|
875 | continue; |
---|
876 | } |
---|
877 | |
---|
878 | /* |
---|
879 | * If this is the start of a comment, ignore the rest of the line. |
---|
880 | */ |
---|
881 | if (c == '#') { |
---|
882 | comment = 1; |
---|
883 | continue; |
---|
884 | } |
---|
885 | |
---|
886 | /* |
---|
887 | * A non-whitespace character is the start of a word. |
---|
888 | */ |
---|
889 | if (!isspace(c)) |
---|
890 | break; |
---|
891 | } |
---|
892 | |
---|
893 | /* |
---|
894 | * Save the delimiter for quoted strings. |
---|
895 | */ |
---|
896 | if (!escape && (c == '"' || c == '\'')) { |
---|
897 | quoted = c; |
---|
898 | c = getc(f); |
---|
899 | } else |
---|
900 | quoted = 0; |
---|
901 | |
---|
902 | /* |
---|
903 | * Process characters until the end of the word. |
---|
904 | */ |
---|
905 | while (c != EOF) { |
---|
906 | if (escape) { |
---|
907 | /* |
---|
908 | * This character is escaped: backslash-newline is ignored, |
---|
909 | * various other characters indicate particular values |
---|
910 | * as for C backslash-escapes. |
---|
911 | */ |
---|
912 | escape = 0; |
---|
913 | if (c == '\n') { |
---|
914 | c = getc(f); |
---|
915 | continue; |
---|
916 | } |
---|
917 | |
---|
918 | got = 0; |
---|
919 | switch (c) { |
---|
920 | case 'a': |
---|
921 | value = '\a'; |
---|
922 | break; |
---|
923 | case 'b': |
---|
924 | value = '\b'; |
---|
925 | break; |
---|
926 | case 'f': |
---|
927 | value = '\f'; |
---|
928 | break; |
---|
929 | case 'n': |
---|
930 | value = '\n'; |
---|
931 | break; |
---|
932 | case 'r': |
---|
933 | value = '\r'; |
---|
934 | break; |
---|
935 | case 's': |
---|
936 | value = ' '; |
---|
937 | break; |
---|
938 | case 't': |
---|
939 | value = '\t'; |
---|
940 | break; |
---|
941 | |
---|
942 | default: |
---|
943 | if (isoctal(c)) { |
---|
944 | /* |
---|
945 | * \ddd octal sequence |
---|
946 | */ |
---|
947 | value = 0; |
---|
948 | for (n = 0; n < 3 && isoctal(c); ++n) { |
---|
949 | value = (value << 3) + (c & 07); |
---|
950 | c = getc(f); |
---|
951 | } |
---|
952 | got = 1; |
---|
953 | break; |
---|
954 | } |
---|
955 | |
---|
956 | if (c == 'x') { |
---|
957 | /* |
---|
958 | * \x<hex_string> sequence |
---|
959 | */ |
---|
960 | value = 0; |
---|
961 | c = getc(f); |
---|
962 | for (n = 0; n < 2 && isxdigit(c); ++n) { |
---|
963 | digit = toupper(c) - '0'; |
---|
964 | if (digit > 10) |
---|
965 | digit += '0' + 10 - 'A'; |
---|
966 | value = (value << 4) + digit; |
---|
967 | c = getc (f); |
---|
968 | } |
---|
969 | got = 1; |
---|
970 | break; |
---|
971 | } |
---|
972 | |
---|
973 | /* |
---|
974 | * Otherwise the character stands for itself. |
---|
975 | */ |
---|
976 | value = c; |
---|
977 | break; |
---|
978 | } |
---|
979 | |
---|
980 | /* |
---|
981 | * Store the resulting character for the escape sequence. |
---|
982 | */ |
---|
983 | if (len < MAXWORDLEN-1) |
---|
984 | word[len] = value; |
---|
985 | ++len; |
---|
986 | |
---|
987 | if (!got) |
---|
988 | c = getc(f); |
---|
989 | continue; |
---|
990 | |
---|
991 | } |
---|
992 | |
---|
993 | /* |
---|
994 | * Not escaped: see if we've reached the end of the word. |
---|
995 | */ |
---|
996 | if (quoted) { |
---|
997 | if (c == quoted) |
---|
998 | break; |
---|
999 | } else { |
---|
1000 | if (isspace(c) || c == '#') { |
---|
1001 | ungetc (c, f); |
---|
1002 | break; |
---|
1003 | } |
---|
1004 | } |
---|
1005 | |
---|
1006 | /* |
---|
1007 | * Backslash starts an escape sequence. |
---|
1008 | */ |
---|
1009 | if (c == '\\') { |
---|
1010 | escape = 1; |
---|
1011 | c = getc(f); |
---|
1012 | continue; |
---|
1013 | } |
---|
1014 | |
---|
1015 | /* |
---|
1016 | * An ordinary character: store it in the word and get another. |
---|
1017 | */ |
---|
1018 | if (len < MAXWORDLEN-1) |
---|
1019 | word[len] = c; |
---|
1020 | ++len; |
---|
1021 | |
---|
1022 | c = getc(f); |
---|
1023 | } |
---|
1024 | |
---|
1025 | /* |
---|
1026 | * End of the word: check for errors. |
---|
1027 | */ |
---|
1028 | if (c == EOF) { |
---|
1029 | if (ferror(f)) { |
---|
1030 | if (errno == 0) |
---|
1031 | errno = EIO; |
---|
1032 | option_error("Error reading %s: %m", filename); |
---|
1033 | die(1); |
---|
1034 | } |
---|
1035 | /* |
---|
1036 | * If len is zero, then we didn't find a word before the |
---|
1037 | * end of the file. |
---|
1038 | */ |
---|
1039 | if (len == 0) |
---|
1040 | return 0; |
---|
1041 | } |
---|
1042 | |
---|
1043 | /* |
---|
1044 | * Warn if the word was too long, and append a terminating null. |
---|
1045 | */ |
---|
1046 | if (len >= MAXWORDLEN) { |
---|
1047 | option_error("warning: word in file %s too long (%.20s...)", |
---|
1048 | filename, word); |
---|
1049 | len = MAXWORDLEN - 1; |
---|
1050 | } |
---|
1051 | word[len] = 0; |
---|
1052 | |
---|
1053 | return 1; |
---|
1054 | |
---|
1055 | #undef isoctal |
---|
1056 | |
---|
1057 | } |
---|
1058 | |
---|
1059 | /* |
---|
1060 | * number_option - parse an unsigned numeric parameter for an option. |
---|
1061 | */ |
---|
1062 | static int |
---|
1063 | number_option(str, valp, base) |
---|
1064 | char *str; |
---|
1065 | u_int32_t *valp; |
---|
1066 | int base; |
---|
1067 | { |
---|
1068 | char *ptr; |
---|
1069 | |
---|
1070 | *valp = strtoul(str, &ptr, base); |
---|
1071 | if (ptr == str) { |
---|
1072 | option_error("invalid numeric parameter '%s' for %s option", |
---|
1073 | str, current_option); |
---|
1074 | return 0; |
---|
1075 | } |
---|
1076 | return 1; |
---|
1077 | } |
---|
1078 | |
---|
1079 | |
---|
1080 | /* |
---|
1081 | * int_option - like number_option, but valp is int *, |
---|
1082 | * the base is assumed to be 0, and *valp is not changed |
---|
1083 | * if there is an error. |
---|
1084 | */ |
---|
1085 | int |
---|
1086 | int_option(str, valp) |
---|
1087 | char *str; |
---|
1088 | int *valp; |
---|
1089 | { |
---|
1090 | u_int32_t v; |
---|
1091 | |
---|
1092 | if (!number_option(str, &v, 0)) |
---|
1093 | return 0; |
---|
1094 | *valp = (int) v; |
---|
1095 | return 1; |
---|
1096 | } |
---|
1097 | |
---|
1098 | |
---|
1099 | /* |
---|
1100 | * The following procedures parse options. |
---|
1101 | */ |
---|
1102 | |
---|
1103 | /* |
---|
1104 | * readfile - take commands from a file. |
---|
1105 | */ |
---|
1106 | static int |
---|
1107 | readfile(argv) |
---|
1108 | char **argv; |
---|
1109 | { |
---|
1110 | return options_from_file(*argv, 1, 1, privileged_option); |
---|
1111 | } |
---|
1112 | |
---|
1113 | /* |
---|
1114 | * callfile - take commands from /etc/ppp/peers/<name>. |
---|
1115 | * Name may not contain /../, start with / or ../, or end in /.. |
---|
1116 | */ |
---|
1117 | static int |
---|
1118 | callfile(argv) |
---|
1119 | char **argv; |
---|
1120 | { |
---|
1121 | char *fname, *arg, *p; |
---|
1122 | int l, ok; |
---|
1123 | |
---|
1124 | arg = *argv; |
---|
1125 | ok = 1; |
---|
1126 | if (arg[0] == '/' || arg[0] == 0) |
---|
1127 | ok = 0; |
---|
1128 | else { |
---|
1129 | for (p = arg; *p != 0; ) { |
---|
1130 | if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) { |
---|
1131 | ok = 0; |
---|
1132 | break; |
---|
1133 | } |
---|
1134 | while (*p != '/' && *p != 0) |
---|
1135 | ++p; |
---|
1136 | if (*p == '/') |
---|
1137 | ++p; |
---|
1138 | } |
---|
1139 | } |
---|
1140 | if (!ok) { |
---|
1141 | option_error("call option value may not contain .. or start with /"); |
---|
1142 | return 0; |
---|
1143 | } |
---|
1144 | |
---|
1145 | l = strlen(arg) + strlen(_PATH_PEERFILES) + 1; |
---|
1146 | if ((fname = (char *) malloc(l)) == NULL) |
---|
1147 | novm("call file name"); |
---|
1148 | slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg); |
---|
1149 | |
---|
1150 | ok = options_from_file(fname, 1, 1, 1); |
---|
1151 | |
---|
1152 | free(fname); |
---|
1153 | return ok; |
---|
1154 | } |
---|
1155 | |
---|
1156 | #ifdef PPP_FILTER |
---|
1157 | /* |
---|
1158 | * setpdebug - Set libpcap debugging level. |
---|
1159 | */ |
---|
1160 | static int |
---|
1161 | setpdebug(argv) |
---|
1162 | char **argv; |
---|
1163 | { |
---|
1164 | return int_option(*argv, &dflag); |
---|
1165 | } |
---|
1166 | |
---|
1167 | /* |
---|
1168 | * setpassfilter - Set the pass filter for packets |
---|
1169 | */ |
---|
1170 | static int |
---|
1171 | setpassfilter(argv) |
---|
1172 | char **argv; |
---|
1173 | { |
---|
1174 | pc.linktype = DLT_PPP; |
---|
1175 | pc.snapshot = PPP_HDRLEN; |
---|
1176 | |
---|
1177 | if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0) |
---|
1178 | return 1; |
---|
1179 | option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc)); |
---|
1180 | return 0; |
---|
1181 | } |
---|
1182 | |
---|
1183 | /* |
---|
1184 | * setactivefilter - Set the active filter for packets |
---|
1185 | */ |
---|
1186 | static int |
---|
1187 | setactivefilter(argv) |
---|
1188 | char **argv; |
---|
1189 | { |
---|
1190 | pc.linktype = DLT_PPP; |
---|
1191 | pc.snapshot = PPP_HDRLEN; |
---|
1192 | |
---|
1193 | if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0) |
---|
1194 | return 1; |
---|
1195 | option_error("error in active-filter expression: %s\n", pcap_geterr(&pc)); |
---|
1196 | return 0; |
---|
1197 | } |
---|
1198 | #endif |
---|
1199 | |
---|
1200 | /* |
---|
1201 | * noopt - Disable all options. |
---|
1202 | */ |
---|
1203 | static int |
---|
1204 | noopt(argv) |
---|
1205 | char **argv; |
---|
1206 | { |
---|
1207 | BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); |
---|
1208 | BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); |
---|
1209 | BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options)); |
---|
1210 | BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options)); |
---|
1211 | |
---|
1212 | return (1); |
---|
1213 | } |
---|
1214 | |
---|
1215 | /* |
---|
1216 | * setdomain - Set domain name to append to hostname |
---|
1217 | */ |
---|
1218 | static int |
---|
1219 | setdomain(argv) |
---|
1220 | char **argv; |
---|
1221 | { |
---|
1222 | if (!privileged_option) { |
---|
1223 | option_error("using the domain option requires root privilege"); |
---|
1224 | return 0; |
---|
1225 | } |
---|
1226 | gethostname(hostname, MAXNAMELEN); |
---|
1227 | if (**argv != 0) { |
---|
1228 | if (**argv != '.') |
---|
1229 | strncat(hostname, ".", MAXNAMELEN - strlen(hostname)); |
---|
1230 | strncat(hostname, *argv, MAXNAMELEN - strlen(hostname)); |
---|
1231 | } |
---|
1232 | hostname[MAXNAMELEN-1] = 0; |
---|
1233 | return (1); |
---|
1234 | } |
---|
1235 | |
---|
1236 | |
---|
1237 | /* |
---|
1238 | * setspeed - Set the speed. |
---|
1239 | */ |
---|
1240 | static int |
---|
1241 | setspeed(arg) |
---|
1242 | char *arg; |
---|
1243 | { |
---|
1244 | int spd; |
---|
1245 | int ret = (int )1; |
---|
1246 | speed_t spdValue = (speed_t)0; |
---|
1247 | char *ptr; |
---|
1248 | |
---|
1249 | if ( !prepass ) { |
---|
1250 | spd = strtol(arg, &ptr, 0); |
---|
1251 | if (ptr == arg || *ptr != 0 || spd == 0) { |
---|
1252 | ret = (int)0; |
---|
1253 | } |
---|
1254 | else { |
---|
1255 | switch ( spd ) { |
---|
1256 | case 2400: |
---|
1257 | spdValue = B2400; |
---|
1258 | break; |
---|
1259 | case 4800: |
---|
1260 | spdValue = B4800; |
---|
1261 | break; |
---|
1262 | case 9600: |
---|
1263 | spdValue = B9600; |
---|
1264 | break; |
---|
1265 | case 19200: |
---|
1266 | spdValue = B19200; |
---|
1267 | break; |
---|
1268 | case 38400: |
---|
1269 | spdValue = B38400; |
---|
1270 | break; |
---|
1271 | case 57600: |
---|
1272 | spdValue = B57600; |
---|
1273 | break; |
---|
1274 | case 115200: |
---|
1275 | spdValue = B115200; |
---|
1276 | break; |
---|
1277 | default: |
---|
1278 | ret = (int)0; |
---|
1279 | break; |
---|
1280 | } |
---|
1281 | |
---|
1282 | if ( spdValue ) { |
---|
1283 | inspeed = spdValue; |
---|
1284 | } |
---|
1285 | } |
---|
1286 | } |
---|
1287 | |
---|
1288 | return ( ret ); |
---|
1289 | } |
---|
1290 | |
---|
1291 | |
---|
1292 | /* |
---|
1293 | * setdevname - Set the device name. |
---|
1294 | */ |
---|
1295 | static int |
---|
1296 | setdevname(cp) |
---|
1297 | char *cp; |
---|
1298 | { |
---|
1299 | struct stat statbuf; |
---|
1300 | char dev[MAXPATHLEN]; |
---|
1301 | |
---|
1302 | if (*cp == 0) |
---|
1303 | return 0; |
---|
1304 | |
---|
1305 | if (strncmp("/dev/", cp, 5) != 0) { |
---|
1306 | strlcpy(dev, "/dev/", sizeof(dev)); |
---|
1307 | strlcat(dev, cp, sizeof(dev)); |
---|
1308 | cp = dev; |
---|
1309 | } |
---|
1310 | |
---|
1311 | /* |
---|
1312 | * Check if there is a character device by this name. |
---|
1313 | */ |
---|
1314 | if (stat(cp, &statbuf) < 0) { |
---|
1315 | if (errno == ENOENT) |
---|
1316 | return 0; |
---|
1317 | option_error("Couldn't stat %s: %m", cp); |
---|
1318 | return -1; |
---|
1319 | } |
---|
1320 | if (!S_ISCHR(statbuf.st_mode)) { |
---|
1321 | option_error("%s is not a character device", cp); |
---|
1322 | return -1; |
---|
1323 | } |
---|
1324 | |
---|
1325 | if (pppd_phase != PHASE_INITIALIZE) { |
---|
1326 | option_error("device name cannot be changed after initialization"); |
---|
1327 | return -1; |
---|
1328 | } else if (devnam_fixed) { |
---|
1329 | option_error("per-tty options file may not specify device name"); |
---|
1330 | return -1; |
---|
1331 | } |
---|
1332 | |
---|
1333 | if (devnam_info.priv && !privileged_option) { |
---|
1334 | option_error("device name cannot be overridden"); |
---|
1335 | return -1; |
---|
1336 | } |
---|
1337 | |
---|
1338 | strlcpy(devnam, cp, sizeof(devnam)); |
---|
1339 | devstat = statbuf; |
---|
1340 | default_device = 0; |
---|
1341 | devnam_info.priv = privileged_option; |
---|
1342 | devnam_info.source = option_source; |
---|
1343 | |
---|
1344 | return 1; |
---|
1345 | } |
---|
1346 | |
---|
1347 | |
---|
1348 | /* |
---|
1349 | * setipaddr - Set the IP address |
---|
1350 | */ |
---|
1351 | static int |
---|
1352 | setipaddr(arg) |
---|
1353 | char *arg; |
---|
1354 | { |
---|
1355 | struct hostent *hp; |
---|
1356 | char *colon; |
---|
1357 | u_int32_t local, remote; |
---|
1358 | ipcp_options *wo = &ipcp_wantoptions[0]; |
---|
1359 | |
---|
1360 | /* |
---|
1361 | * IP address pair separated by ":". |
---|
1362 | */ |
---|
1363 | if ((colon = strchr(arg, ':')) == NULL) |
---|
1364 | return 0; |
---|
1365 | if (prepass) |
---|
1366 | return 1; |
---|
1367 | |
---|
1368 | /* |
---|
1369 | * If colon first character, then no local addr. |
---|
1370 | */ |
---|
1371 | if (colon != arg) { |
---|
1372 | *colon = '\0'; |
---|
1373 | if ((local = inet_addr(arg)) == (u_int32_t) -1) { |
---|
1374 | if ((hp = gethostbyname(arg)) == NULL) { |
---|
1375 | option_error("unknown host: %s", arg); |
---|
1376 | return -1; |
---|
1377 | } else { |
---|
1378 | local = *(u_int32_t *)hp->h_addr; |
---|
1379 | } |
---|
1380 | } |
---|
1381 | if (bad_ip_adrs(local)) { |
---|
1382 | option_error("bad local IP address %s", ip_ntoa(local)); |
---|
1383 | return -1; |
---|
1384 | } |
---|
1385 | if (local != 0) |
---|
1386 | wo->ouraddr = local; |
---|
1387 | *colon = ':'; |
---|
1388 | } |
---|
1389 | |
---|
1390 | /* |
---|
1391 | * If colon last character, then no remote addr. |
---|
1392 | */ |
---|
1393 | if (*++colon != '\0') { |
---|
1394 | if ((remote = inet_addr(colon)) == (u_int32_t) -1) { |
---|
1395 | if ((hp = gethostbyname(colon)) == NULL) { |
---|
1396 | option_error("unknown host: %s", colon); |
---|
1397 | return -1; |
---|
1398 | } else { |
---|
1399 | remote = *(u_int32_t *)hp->h_addr; |
---|
1400 | if (remote_name[0] == 0) |
---|
1401 | strlcpy(remote_name, colon, sizeof(remote_name)); |
---|
1402 | } |
---|
1403 | } |
---|
1404 | if (bad_ip_adrs(remote)) { |
---|
1405 | option_error("bad remote IP address %s", ip_ntoa(remote)); |
---|
1406 | return -1; |
---|
1407 | } |
---|
1408 | if (remote != 0) |
---|
1409 | wo->hisaddr = remote; |
---|
1410 | } |
---|
1411 | |
---|
1412 | return 1; |
---|
1413 | } |
---|
1414 | |
---|
1415 | |
---|
1416 | /* |
---|
1417 | * setnetmask - set the netmask to be used on the interface. |
---|
1418 | */ |
---|
1419 | static int |
---|
1420 | setnetmask(argv) |
---|
1421 | char **argv; |
---|
1422 | { |
---|
1423 | u_int32_t mask, b; |
---|
1424 | int n, ok; |
---|
1425 | char *p, *endp; |
---|
1426 | |
---|
1427 | /* |
---|
1428 | * Unfortunately, if we use inet_addr, we can't tell whether |
---|
1429 | * a result of all 1s is an error or a valid 255.255.255.255. |
---|
1430 | */ |
---|
1431 | p = *argv; |
---|
1432 | ok = 0; |
---|
1433 | mask = 0; |
---|
1434 | for (n = 3;; --n) { |
---|
1435 | b = strtoul(p, &endp, 0); |
---|
1436 | if (endp == p) |
---|
1437 | break; |
---|
1438 | if (b > 255) { |
---|
1439 | if (n == 3) { |
---|
1440 | /* accept e.g. 0xffffff00 */ |
---|
1441 | p = endp; |
---|
1442 | mask = b; |
---|
1443 | } |
---|
1444 | break; |
---|
1445 | } |
---|
1446 | mask |= b << (n * 8); |
---|
1447 | p = endp; |
---|
1448 | if (*p != '.' || n == 0) |
---|
1449 | break; |
---|
1450 | ++p; |
---|
1451 | } |
---|
1452 | |
---|
1453 | mask = htonl(mask); |
---|
1454 | |
---|
1455 | if (*p != 0 || (netmask & ~mask) != 0) { |
---|
1456 | option_error("invalid netmask value '%s'", *argv); |
---|
1457 | return 0; |
---|
1458 | } |
---|
1459 | |
---|
1460 | netmask = mask; |
---|
1461 | return (1); |
---|
1462 | } |
---|
1463 | |
---|
1464 | static int |
---|
1465 | setxonxoff(argv) |
---|
1466 | char **argv; |
---|
1467 | { |
---|
1468 | lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */ |
---|
1469 | lcp_wantoptions[0].neg_asyncmap = 1; |
---|
1470 | |
---|
1471 | crtscts = -2; |
---|
1472 | return (1); |
---|
1473 | } |
---|
1474 | |
---|
1475 | static int |
---|
1476 | setlogfile(argv) |
---|
1477 | char **argv; |
---|
1478 | { |
---|
1479 | int fd, err; |
---|
1480 | |
---|
1481 | fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644); |
---|
1482 | if (fd < 0 && errno == EEXIST) |
---|
1483 | fd = open(*argv, O_WRONLY | O_APPEND); |
---|
1484 | err = errno; |
---|
1485 | if (fd < 0) { |
---|
1486 | errno = err; |
---|
1487 | option_error("Can't open log file %s: %m", *argv); |
---|
1488 | return 0; |
---|
1489 | } |
---|
1490 | if (log_to_file && log_to_fd >= 0) |
---|
1491 | close(log_to_fd); |
---|
1492 | log_to_fd = fd; |
---|
1493 | log_to_file = 1; |
---|
1494 | return 1; |
---|
1495 | } |
---|
1496 | |
---|
1497 | #ifdef PLUGIN |
---|
1498 | static int |
---|
1499 | loadplugin(argv) |
---|
1500 | char **argv; |
---|
1501 | { |
---|
1502 | char *arg = *argv; |
---|
1503 | void *handle; |
---|
1504 | const char *err; |
---|
1505 | void (*init) __P((void)); |
---|
1506 | |
---|
1507 | handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW); |
---|
1508 | if (handle == 0) { |
---|
1509 | err = dlerror(); |
---|
1510 | if (err != 0) |
---|
1511 | option_error("%s", err); |
---|
1512 | option_error("Couldn't load plugin %s", arg); |
---|
1513 | return 0; |
---|
1514 | } |
---|
1515 | init = dlsym(handle, "plugin_init"); |
---|
1516 | if (init == 0) { |
---|
1517 | option_error("%s has no initialization entry point", arg); |
---|
1518 | dlclose(handle); |
---|
1519 | return 0; |
---|
1520 | } |
---|
1521 | info("Plugin %s loaded.", arg); |
---|
1522 | (*init)(); |
---|
1523 | return 1; |
---|
1524 | } |
---|
1525 | #endif /* PLUGIN */ |
---|