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