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