http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / ppp / pppoe / 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.3 2006/09/06 11:01:34 wilson 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 <syslog.h>
29 #include <string.h>
30 #include <pwd.h>
31 // Jack Suen
32 #include <signal.h>
33 #ifdef PLUGIN
34 #include <dlfcn.h>
35 #endif
36 #ifdef PPP_FILTER
37 #include <pcap.h>
38 #include <pcap-int.h>   /* XXX: To get struct pcap */
39 #endif
40
41 #include "pppd.h"
42 #include "pathnames.h"
43 #include "fsm.h"
44 #include "lcp.h"
45
46 extern int DEB_DISC,DEB_DISC2;
47
48 #if defined(ultrix) || defined(NeXT)
49 char *strdup __P((char *));
50 #endif
51
52 static const char rcsid[] = RCSID;
53
54 struct option_value {
55     struct option_value *next;
56     const char *source;
57     char value[1];
58 };
59
60 /*
61  * Option variables and default values.
62  */
63 #ifdef PPP_FILTER
64 int     dflag = 0;              /* Tell libpcap we want debugging */
65 #endif
66 int     DEB_DISC = 0;
67 int     DEB_DISC2 = 0;
68 int     debug = 0;              /* Debug flag */
69 int     kdebugflag = 0;         /* Tell kernel to print debug messages */
70 int     default_device = 1;     /* Using /dev/tty or equivalent */
71 char    devnam[MAXPATHLEN];     /* Device name */
72 bool    nodetach = 1;           /* Don't detach from controlling tty */
73 bool    updetach = 0;           /* Detach once link is up */
74 int     maxconnect = 0;         /* Maximum connect time */
75 char    user[MAXNAMELEN]="";    /* Username for PAP */
76 char    passwd[MAXSECRETLEN]="";        /* Password for PAP */
77 bool    persist = 1;            /* Reopen link after it goes down */
78 char    our_name[MAXNAMELEN];   /* Our name for authentication purposes */
79 bool    demand = 0;             /* do dial-on-demand */
80 char    *ipparam = NULL;        /* Extra parameter for ip up/down scripts */
81 int     idle_time_limit = 0;    /* Disconnect if idle for this many seconds */
82 int     holdoff = 3;            /* # seconds to pause before reconnecting */
83 bool    holdoff_specified;      /* true if a holdoff value has been given */
84 int     log_to_fd = 1;          /* send log messages to this fd too */
85 bool    log_default = 1;        /* log_to_fd is default (stdout) */
86 int     maxfail = 10;           /* max # of unsuccessful connection attempts */
87 char    linkname[MAXPATHLEN];   /* logical name for link */
88 bool    tune_kernel;            /* may alter kernel settings */
89 int     connect_delay = 1000;   /* wait this many ms after connect script */
90 int     req_unit = -1;          /* requested interface unit */
91 bool    multilink = 0;          /* Enable multilink operation */
92 char    *bundle_name = NULL;    /* bundle name for multilink */
93 bool    dump_options;           /* print out option values */
94 bool    dryrun;                 /* print out option values and exit */
95 char    *domain;                /* domain name set by domain option */
96 // cwu
97 int     baud_rate;
98 int     autoscan=0;
99 int     autoscanP2=0;
100 int     ipext=0;
101 int     opflag=0;
102 char    session_path[32]="";
103 char    oldsession[MAXPATHLEN]="";  /* Mac address and session ID of the previous session */
104 int     srvdisc=0;
105 char    req_name[MAXPATHLEN] = "";      /* logical name for link */
106 static char ip_addr[MAXPATHLEN] = ""; /* IP address */
107 //Andy Lin
108 int ppp_session=0;
109
110 extern option_t auth_options[];
111 extern struct stat devstat;
112 extern int setipaddr(char *arg, char **argv, int doit);
113 extern int setdevname_pppoe(const char *cp);
114 extern int setdevname_pppoatm(const char *cp);
115 //Charles 11/30/2003, add for unnumbered PPP (declared in ipcp.c)
116 extern bool unnumbered;
117 extern char wan_IP[];
118 extern char wan_submask[];
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 int  option_priority = OPRIO_CFGFILE; /* priority of the current options */
130 bool devnam_fixed;              /* can no longer change device name */
131
132 static int logfile_fd = -1;     /* fd opened for log file */
133 static char logfile_name[MAXPATHLEN];   /* name of log file */
134
135 #if defined(INCLUDE_MTU_LAN_PPP)
136 int glb_CONFIG_PPP_MTU = 0;
137 #endif
138
139 #ifdef BUILD_DOMAIN_LOCK
140 int wsnCheckStrTail(char *username, char *validDomain);
141 int wsnIsValidPppUser(char *pppUser);
142 #endif
143
144 /*
145  * Prototypes
146  */
147 static int setdomain __P((char **));
148 static int readfile __P((char **));
149 static int callfile __P((char **));
150 static int showversion __P((char **));
151 static int showhelp __P((char **));
152 static void usage __P((void));
153 static int setlogfile __P((char **));
154 #ifdef PLUGIN
155 static int loadplugin __P((char **));
156 #endif
157
158 #ifdef PPP_FILTER
159 static int setpassfilter __P((char **));
160 static int setactivefilter __P((char **));
161 #endif
162
163 static option_t *find_option __P((const char *name));
164 static int process_option __P((option_t *, char *, char **));
165 static int n_arguments __P((option_t *));
166 static int number_option __P((char *, u_int32_t *, int));
167
168 /*
169  * Structure to store extra lists of options.
170  */
171 struct option_list {
172     option_t *options;
173     struct option_list *next;
174 };
175
176 static struct option_list *extra_options = NULL;
177
178 /*
179  * Valid arguments.
180  */
181 option_t general_options[] = {
182     { "debug", o_int, &debug,
183       "Increase debugging level", OPT_INC | OPT_NOARG | 1 },
184     { "-d", o_int, &debug,
185       "Increase debugging level",
186       OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
187
188     { "kdebug", o_int, &kdebugflag,
189       "Set kernel driver debug level", OPT_PRIO },
190
191     { "nodetach", o_bool, &nodetach,
192       "Don't detach from controlling tty", OPT_PRIO | 1 },
193     { "-detach", o_bool, &nodetach,
194       "Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
195     { "updetach", o_bool, &updetach,
196       "Detach from controlling tty once link is up",
197       OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
198
199     { "holdoff", o_int, &holdoff,
200       "Set time in seconds before retrying connection", OPT_PRIO },
201
202     { "idle", o_int, &idle_time_limit,
203       "Set time in seconds before disconnecting idle link", OPT_PRIO },
204
205     { "maxconnect", o_int, &maxconnect,
206       "Set connection time limit",
207       OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
208
209     { "domain", o_special, (void *)setdomain,
210       "Add given domain name to hostname",
211       OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
212
213     { "file", o_special, (void *)readfile,
214       "Take options from a file", OPT_NOPRINT },
215     { "call", o_special, (void *)callfile,
216       "Take options from a privileged file", OPT_NOPRINT },
217
218     { "persist", o_bool, &persist,
219       "Keep on reopening connection after close", OPT_PRIO | 1 },
220     { "nopersist", o_bool, &persist,
221       "Turn off persist option", OPT_PRIOSUB },
222
223     { "demand", o_bool, &demand,
224       "Dial on demand", OPT_INITONLY | 1, &persist },
225
226     { "--version", o_special_noarg, (void *)showversion,
227       "Show version number" },
228     { "--help", o_special_noarg, (void *)showhelp,
229       "Show brief listing of options" },
230     { "-h", o_special_noarg, (void *)showhelp,
231       "Show brief listing of options", OPT_ALIAS },
232
233     { "logfile", o_special, (void *)setlogfile,
234       "Append log messages to this file",
235       OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
236     { "logfd", o_int, &log_to_fd,
237       "Send log messages to this file descriptor",
238       OPT_PRIOSUB | OPT_A2CLR, &log_default },
239     { "nolog", o_int, &log_to_fd,
240       "Don't send log messages to any file",
241       OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
242     { "nologfd", o_int, &log_to_fd,
243       "Don't send log messages to any file descriptor",
244       OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
245
246     { "linkname", o_string, linkname,
247       "Set logical name for link",
248       OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
249
250     { "maxfail", o_int, &maxfail,
251       "Maximum number of unsuccessful connection attempts to allow",
252       OPT_PRIO },
253
254     { "ktune", o_bool, &tune_kernel,
255       "Alter kernel settings as necessary", OPT_PRIO | 1 },
256     { "noktune", o_bool, &tune_kernel,
257       "Don't alter kernel settings", OPT_PRIOSUB },
258
259     { "connect-delay", o_int, &connect_delay,
260       "Maximum time (in ms) to wait after connect script finishes",
261       OPT_PRIO },
262
263     { "unit", o_int, &req_unit,
264       "PPP interface unit number to use if possible",
265       OPT_PRIO | OPT_LLIMIT, 0, 0 },
266
267     { "dump", o_bool, &dump_options,
268       "Print out option values after parsing all options", 1 },
269     { "dryrun", o_bool, &dryrun,
270       "Stop after parsing, printing, and checking options", 1 },
271
272 #ifdef HAVE_MULTILINK
273     { "multilink", o_bool, &multilink,
274       "Enable multilink operation", OPT_PRIO | 1 },
275     { "mp", o_bool, &multilink,
276       "Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
277     { "nomultilink", o_bool, &multilink,
278       "Disable multilink operation", OPT_PRIOSUB | 0 },
279     { "nomp", o_bool, &multilink,
280       "Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
281
282     { "bundle", o_string, &bundle_name,
283       "Bundle name for multilink", OPT_PRIO },
284 #endif /* HAVE_MULTILINK */
285
286 #ifdef PLUGIN
287     { "plugin", o_special, (void *)loadplugin,
288       "Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
289 #endif
290
291 #ifdef PPP_FILTER
292     { "pdebug", o_int, &dflag,
293       "libpcap debugging", OPT_PRIO },
294
295     { "pass-filter", 1, setpassfilter,
296       "set filter for packets to pass", OPT_PRIO },
297
298     { "active-filter", 1, setactivefilter,
299       "set filter for active pkts", OPT_PRIO },
300 #endif
301
302     { NULL }
303 };
304
305 #ifndef IMPLEMENTATION
306 #define IMPLEMENTATION ""
307 #endif
308
309 static char *usage_string = "\
310 pppd version %s\n\
311 Usage: %s [ options ], where options are:\n\
312         <device>        Communicate over the named device\n\
313         <speed>         Set the baud rate to <speed>\n\
314         <loc>:<rem>     Set the local and/or remote interface IP\n\
315                         addresses.  Either one may be omitted.\n\
316         asyncmap <n>    Set the desired async map to hex <n>\n\
317         auth            Require authentication from peer\n\
318         connect <p>     Invoke shell command <p> to set up the serial line\n\
319         crtscts         Use hardware RTS/CTS flow control\n\
320         defaultroute    Add default route through interface\n\
321         file <f>        Take options from file <f>\n\
322         modem           Use modem control lines\n\
323         mru <n>         Set MRU value to <n> for negotiation\n\
324 See pppd(8) for more options.\n\
325 ";
326
327 #ifdef SUPPORT_PPP_SCHEDULE
328         extern int ppp_runonce;
329 #endif
330 extern int isp_1n1;
331
332 // cwu
333 int
334 parse_args(argc, argv)
335     int argc;
336     char **argv;
337 {
338     int opt;
339     int retval, num[3];
340
341     while ((opt = getopt(argc, argv, "nbsxda:e:g:i:ku:p:o:lc:m:f:r:q:RA:w:zjh")) != -1) {
342             switch (opt) {
343 #ifdef SUPPORT_PPP_SCHEDULE
344                 case 'h':
345                         ppp_runonce = 1;
346                         break;
347 #endif
348             //ODM Charles, add for manual conn/disconn
349             case 'n':
350                     demand=1;
351                     ppp_manual=1;
352                     break;
353             //end
354             //Charles 11/30/2003, add unnumbered PPP
355             case 'b':
356                     unnumbered=1;
357                     break;
358             //IP for unnumbered PPP, in a.b.c.d format
359             case 'e':
360                     strncpy(wan_IP, optarg, 16);
361                     break;
362             //subnet mask for unnumbered PPP, in a.b.c.d format
363             case 'g':
364                     strncpy(wan_submask, optarg, 16);
365                     break;
366             case 's':
367                     autoscan = 1;
368                     auth_required = 0;
369             //autoscanP2 = atoi(optarg);
370                     break;
371             case 'x':
372                     ipext = 1;
373                     break;
374             case 'd':
375                     debug = nodetach = 1;
376                     break;
377             case 'a':
378                 ppp_session=PPPOA;
379                     setdevname_pppoatm(optarg);
380                     break;
381             case 'i':
382                 ppp_session=PPPOE;
383                     setdevname_pppoe(optarg);
384                     break;
385             case 'k':
386                     persist = 1;
387                     break;
388             case 'u':
389                     strncpy(user, optarg, MAXNAMELEN);
390                     strncpy(our_name, optarg, MAXNAMELEN);
391 #ifdef BUILD_DOMAIN_LOCK
392                   if(wsnIsValidPppUser(user)==0){ // 0: FALSE
393                       printf("PPP username is out of valid domains.\n");
394                       //strcpy(user, "");
395                       //strcpy(our_name, "");
396                   }
397 #endif
398                     break;
399             case 'p':
400                     strncpy(passwd, optarg, MAXSECRETLEN);
401                     break;
402             case 'o':
403                     idle_time_limit = atoi(optarg);
404                     demand=1;
405                     break;
406             case 'l':
407                     llc_encaps=1;
408                     break;
409             case 'c':
410                     strncpy(req_name, optarg, MAXPATHLEN);
411                     retval = sscanf(req_name, "%d.%d.%d", num, num+1, num+2);
412                     sprintf(req_name, "%d_%d_%d", num[0], num[1], num[2]);
413                     sprintf(session_path, "ppp_%s", req_name);
414                     break;
415             case 'm':
416                     strncpy(oldsession, optarg, MAXPATHLEN);
417                     break;
418             case 'f':
419                     opflag = atoi(optarg);
420                     break;
421             case 'r':
422                     strncpy(pppoe_srv_name, optarg, MAXPATHLEN);
423                     break;
424             case 'q':
425                     strncpy(pppoe_ac_name, optarg, MAXPATHLEN);
426                     break;
427             case 'R':
428                     srvdisc=1;
429                     break;
430 #if defined(INCLUDE_MTU_LAN_PPP)
431                 case 'w':
432                     lcp_allowoptions[0].mru = atoi(optarg);
433                     glb_CONFIG_PPP_MTU = atoi(optarg);
434                     break;        
435 #endif
436                 case 'z':
437                     ppp_addgw = 1;
438                     break;
439                 case 'j':
440                     isp_1n1 = 1;
441                     break;
442             case 'A':
443                     strncpy(ip_addr, optarg, MAXPATHLEN);
444                     ip_addr[strlen(ip_addr)] = ':';
445                     setipaddr (ip_addr, NULL, 1);
446                     break;
447             default:
448                     fprintf(stderr, "usage: %s [-s] [-b] [-d] [-i interface] [-a vcc]  [-u username] [-p passwd] [-o idle] [-m prevmac/prevsid] [-A ipaddr]\n", argv[0]);
449                     return 0;
450             }
451     }
452
453     return 1;
454 }
455
456
457 /*
458 int
459 parse_args(argc, argv)
460     int argc;
461     char **argv;
462 {
463     char *arg;
464     option_t *opt;
465     int n;
466
467     privileged_option = privileged;
468     option_source = "command line";
469     option_priority = OPRIO_CMDLINE;
470     while (argc > 0) {
471         arg = *argv++;
472         --argc;
473         opt = find_option(arg);
474         if (opt == NULL) {
475             option_error("unrecognized option '%s'", arg);
476             usage();
477             return 0;
478         }
479         n = n_arguments(opt);
480         if (argc < n) {
481             option_error("too few parameters for option %s", arg);
482             return 0;
483         }
484         if (!process_option(opt, arg, argv))
485             return 0;
486         argc -= n;
487         argv += n;
488     }
489     return 1;
490 }
491 */
492
493 /*
494  * options_from_file - Read a string of options from a file,
495  * and interpret them.
496  */
497 int
498 options_from_file(filename, must_exist, check_prot, priv)
499     char *filename;
500     int must_exist;
501     int check_prot;
502     int priv;
503 {
504     FILE *f;
505     int i, newline, ret, err;
506     option_t *opt;
507     int oldpriv, n;
508     char *oldsource;
509     char *argv[MAXARGS];
510     char args[MAXARGS][MAXWORDLEN];
511     char cmd[MAXWORDLEN];
512
513     if (check_prot)
514         seteuid(getuid());
515     f = fopen(filename, "r");
516     err = errno;
517     if (check_prot)
518         seteuid(0);
519     if (f == NULL) {
520         errno = err;
521         if (!must_exist) {
522             if (err != ENOENT && err != ENOTDIR)
523                 warn("Warning: can't open options file %s: %m", filename);
524             return 1;
525         }
526         option_error("Can't open options file %s: %m", filename);
527         return 0;
528     }
529
530     oldpriv = privileged_option;
531     privileged_option = priv;
532     oldsource = option_source;
533     option_source = strdup(filename);
534     if (option_source == NULL)
535         option_source = "file";
536     ret = 0;
537     while (getword(f, cmd, &newline, filename)) {
538         opt = find_option(cmd);
539         if (opt == NULL) {
540             option_error("In file %s: unrecognized option '%s'",
541                          filename, cmd);
542             goto err;
543         }
544         n = n_arguments(opt);
545         for (i = 0; i < n; ++i) {
546             if (!getword(f, args[i], &newline, filename)) {
547                 option_error(
548                         "In file %s: too few parameters for option '%s'",
549                         filename, cmd);
550                 goto err;
551             }
552             argv[i] = args[i];
553         }
554         if (!process_option(opt, cmd, argv))
555             goto err;
556     }
557     ret = 1;
558
559 err:
560     fclose(f);
561     privileged_option = oldpriv;
562     option_source = oldsource;
563     return ret;
564 }
565
566 /*
567  * options_from_user - See if the use has a ~/.ppprc file,
568  * and if so, interpret options from it.
569  */
570 int
571 options_from_user()
572 {
573     char *user, *path, *file;
574     int ret;
575     struct passwd *pw;
576     size_t pl;
577
578     pw = getpwuid(getuid());
579     if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
580         return 1;
581     file = _PATH_USEROPT;
582     pl = strlen(user) + strlen(file) + 2;
583     path = malloc(pl);
584     if (path == NULL)
585         novm("init file name");
586     slprintf(path, pl, "%s/%s", user, file);
587     option_priority = OPRIO_CFGFILE;
588     ret = options_from_file(path, 0, 1, privileged);
589     free(path);
590     return ret;
591 }
592
593 /*
594  * options_for_tty - See if an options file exists for the serial
595  * device, and if so, interpret options from it.
596  * We only allow the per-tty options file to override anything from
597  * the command line if it is something that the user can't override
598  * once it has been set by root; this is done by giving configuration
599  * files a lower priority than the command line.
600  */
601 int
602 options_for_tty()
603 {
604     char *dev, *path, *p;
605     int ret;
606     size_t pl;
607
608     dev = devnam;
609     if (strncmp(dev, "/dev/", 5) == 0)
610         dev += 5;
611     if (dev[0] == 0 || strcmp(dev, "tty") == 0)
612         return 1;               /* don't look for /etc/ppp/options.tty */
613     pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
614     path = malloc(pl);
615     if (path == NULL)
616         novm("tty init file name");
617     slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
618     /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
619     for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
620         if (*p == '/')
621             *p = '.';
622     option_priority = OPRIO_CFGFILE;
623     ret = options_from_file(path, 0, 0, 1);
624     free(path);
625     return ret;
626 }
627
628 /*
629  * options_from_list - process a string of options in a wordlist.
630  */
631 int
632 options_from_list(w, priv)
633     struct wordlist *w;
634     int priv;
635 {
636     char *argv[MAXARGS];
637     option_t *opt;
638     int i, n, ret = 0;
639     struct wordlist *w0;
640
641     privileged_option = priv;
642     option_source = "secrets file";
643     option_priority = OPRIO_SECFILE;
644
645     while (w != NULL) {
646         opt = find_option(w->word);
647         if (opt == NULL) {
648             option_error("In secrets file: unrecognized option '%s'",
649                          w->word);
650             goto err;
651         }
652         n = n_arguments(opt);
653         w0 = w;
654         for (i = 0; i < n; ++i) {
655             w = w->next;
656             if (w == NULL) {
657                 option_error(
658                         "In secrets file: too few parameters for option '%s'",
659                         w0->word);
660                 goto err;
661             }
662             argv[i] = w->word;
663         }
664         if (!process_option(opt, w0->word, argv))
665             goto err;
666         w = w->next;
667     }
668     ret = 1;
669
670 err:
671     return ret;
672 }
673
674 /*
675  * match_option - see if this option matches an option_t structure.
676  */
677 static int
678 match_option(name, opt, dowild)
679     char *name;
680     option_t *opt;
681     int dowild;
682 {
683         int (*match) __P((char *, char **, int));
684
685         if (dowild != (opt->type == o_wild))
686                 return 0;
687         if (!dowild)
688                 return strcmp(name, opt->name) == 0;
689         match = (int (*) __P((char *, char **, int))) opt->addr;
690         return (*match)(name, NULL, 0);
691 }
692
693 /*
694  * find_option - scan the option lists for the various protocols
695  * looking for an entry with the given name.
696  * This could be optimized by using a hash table.
697  */
698 static option_t *
699 find_option(name)
700     const char *name;
701 {
702         option_t *opt;
703         struct option_list *list;
704         int i, dowild;
705
706         for (dowild = 0; dowild <= 1; ++dowild) {
707                 for (opt = general_options; opt->name != NULL; ++opt)
708                         if (match_option(name, opt, dowild))
709                                 return opt;
710                 for (opt = auth_options; opt->name != NULL; ++opt)
711                         if (match_option(name, opt, dowild))
712                                 return opt;
713                 for (list = extra_options; list != NULL; list = list->next)
714                         for (opt = list->options; opt->name != NULL; ++opt)
715                                 if (match_option(name, opt, dowild))
716                                         return opt;
717                 for (opt = the_channel->options; opt->name != NULL; ++opt)
718                         if (match_option(name, opt, dowild))
719                                 return opt;
720                 for (i = 0; protocols[i] != NULL; ++i)
721                         if ((opt = protocols[i]->options) != NULL)
722                                 for (; opt->name != NULL; ++opt)
723                                         if (match_option(name, opt, dowild))
724                                                 return opt;
725         }
726         return NULL;
727 }
728
729 /*
730  * process_option - process one new-style option.
731  */
732 static int
733 process_option(opt, cmd, argv)
734     option_t *opt;
735     char *cmd;
736     char **argv;
737 {
738     u_int32_t v;
739     int iv, a;
740     char *sv;
741     int (*parser) __P((char **));
742     int (*wildp) __P((char *, char **, int));
743     char *optopt = (opt->type == o_wild)? "": " option";
744     int prio = option_priority;
745     option_t *mainopt = opt;
746
747     if ((opt->flags & OPT_PRIVFIX) && privileged_option)
748         prio += OPRIO_ROOT;
749     while (mainopt->flags & OPT_PRIOSUB)
750         --mainopt;
751     if (mainopt->flags & OPT_PRIO) {
752         if (prio < mainopt->priority) {
753             /* new value doesn't override old */
754             if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
755                 option_error("%s%s set in %s cannot be overridden\n",
756                              opt->name, optopt, mainopt->source);
757                 return 0;
758             }
759             return 1;
760         }
761         if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
762             warn("%s%s from %s overrides command line",
763                  opt->name, optopt, option_source);
764     }
765
766     if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
767         option_error("%s%s cannot be changed after initialization",
768                      opt->name, optopt);
769         return 0;
770     }
771     if ((opt->flags & OPT_PRIV) && !privileged_option) {
772         option_error("using the %s%s requires root privilege",
773                      opt->name, optopt);
774         return 0;
775     }
776     if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
777         option_error("%s%s is disabled", opt->name, optopt);
778         return 0;
779     }
780     if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
781         option_error("the %s%s may not be changed in %s",
782                      opt->name, optopt, option_source);
783         return 0;
784     }
785
786     switch (opt->type) {
787     case o_bool:
788         v = opt->flags & OPT_VALUE;
789         *(bool *)(opt->addr) = v;
790         if (opt->addr2 && (opt->flags & OPT_A2COPY))
791             *(bool *)(opt->addr2) = v;
792         break;
793
794     case o_int:
795         iv = 0;
796         if ((opt->flags & OPT_NOARG) == 0) {
797             if (!int_option(*argv, &iv))
798                 return 0;
799             if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
800                  || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
801                 && !((opt->flags & OPT_ZEROOK && iv == 0))) {
802                 char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
803                 switch (opt->flags & OPT_LIMITS) {
804                 case OPT_LLIMIT:
805                     option_error("%s value must be%s >= %d",
806                                  opt->name, zok, opt->lower_limit);
807                     break;
808                 case OPT_ULIMIT:
809                     option_error("%s value must be%s <= %d",
810                                  opt->name, zok, opt->upper_limit);
811                     break;
812                 case OPT_LIMITS:
813                     option_error("%s value must be%s between %d and %d",
814                                 opt->name, opt->lower_limit, opt->upper_limit);
815                     break;
816                 }
817                 return 0;
818             }
819         }
820         a = opt->flags & OPT_VALUE;
821         if (a >= 128)
822             a -= 256;           /* sign extend */
823         iv += a;
824         if (opt->flags & OPT_INC)
825             iv += *(int *)(opt->addr);
826         if ((opt->flags & OPT_NOINCR) && !privileged_option) {
827             int oldv = *(int *)(opt->addr);
828             if ((opt->flags & OPT_ZEROINF) ?
829                 (oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
830                 option_error("%s value cannot be increased", opt->name);
831                 return 0;
832             }
833         }
834         *(int *)(opt->addr) = iv;
835         if (opt->addr2 && (opt->flags & OPT_A2COPY))
836             *(int *)(opt->addr2) = iv;
837         break;
838
839     case o_uint32:
840         if (opt->flags & OPT_NOARG) {
841             v = opt->flags & OPT_VALUE;
842             if (v & 0x80)
843                     v |= 0xffffff00U;
844         } else if (!number_option(*argv, &v, 16))
845             return 0;
846         if (opt->flags & OPT_OR)
847             v |= *(u_int32_t *)(opt->addr);
848         *(u_int32_t *)(opt->addr) = v;
849         if (opt->addr2 && (opt->flags & OPT_A2COPY))
850             *(u_int32_t *)(opt->addr2) = v;
851         break;
852
853     case o_string:
854         if (opt->flags & OPT_STATIC) {
855             strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
856         } else {
857             sv = strdup(*argv);
858             if (sv == NULL)
859                 novm("option argument");
860             *(char **)(opt->addr) = sv;
861         }
862         break;
863
864     case o_special_noarg:
865     case o_special:
866         parser = (int (*) __P((char **))) opt->addr;
867         if (!(*parser)(argv))
868             return 0;
869         if (opt->flags & OPT_A2LIST) {
870             struct option_value *ovp, **pp;
871
872             ovp = malloc(sizeof(*ovp) + strlen(*argv));
873             if (ovp != 0) {
874                 strcpy(ovp->value, *argv);
875                 ovp->source = option_source;
876                 ovp->next = NULL;
877                 pp = (struct option_value **) &opt->addr2;
878                 while (*pp != 0)
879                     pp = &(*pp)->next;
880                 *pp = ovp;
881             }
882         }
883         break;
884
885     case o_wild:
886         wildp = (int (*) __P((char *, char **, int))) opt->addr;
887         if (!(*wildp)(cmd, argv, 1))
888             return 0;
889         break;
890     }
891
892     if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
893                 |OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST)) == 0)
894         *(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
895
896     mainopt->source = option_source;
897     mainopt->priority = prio;
898     mainopt->winner = opt - mainopt;
899
900     return 1;
901 }
902
903 /*
904  * override_value - if the option priorities would permit us to
905  * override the value of option, return 1 and update the priority
906  * and source of the option value.  Otherwise returns 0.
907  */
908 int
909 override_value(option, priority, source)
910     const char *option;
911     int priority;
912     const char *source;
913 {
914         option_t *opt;
915
916         opt = find_option(option);
917         if (opt == NULL)
918                 return 0;
919         while (opt->flags & OPT_PRIOSUB)
920                 --opt;
921         if ((opt->flags & OPT_PRIO) && priority < opt->priority)
922                 return 0;
923         opt->priority = priority;
924         opt->source = source;
925         opt->winner = -1;
926         return 1;
927 }
928
929 /*
930  * n_arguments - tell how many arguments an option takes
931  */
932 static int
933 n_arguments(opt)
934     option_t *opt;
935 {
936         return (opt->type == o_bool || opt->type == o_special_noarg
937                 || (opt->flags & OPT_NOARG))? 0: 1;
938 }
939
940 /*2
941  * add_options - add a list of options to the set we grok.
942  */
943 void
944 add_options(opt)
945     option_t *opt;
946 {
947     struct option_list *list;
948
949     list = malloc(sizeof(*list));
950     if (list == 0)
951         novm("option list entry");
952     list->options = opt;
953     list->next = extra_options;
954     extra_options = list;
955 }
956
957 /*
958  * remove_option - permanently remove an option from consideration...
959  * for use by modules to remove choices which no longer make sense.
960  * returns true if found an option
961  */
962 int
963 remove_option(name)
964     char *name;
965 {
966     option_t *o;
967     o = find_option(name);
968     if (o == NULL)
969         return 0;
970     o->name = "";
971     return 1;
972 }
973
974 /*
975  * check_options - check that options are valid and consistent.
976  */
977 void
978 check_options()
979 {
980         if (logfile_fd >= 0 && logfile_fd != log_to_fd)
981                 close(logfile_fd);
982 }
983
984 /*
985  * print_option - print out an option and its value
986  */
987 static void
988 print_option(opt, mainopt, printer, arg)
989     option_t *opt, *mainopt;
990     void (*printer) __P((void *, char *, ...));
991     void *arg;
992 {
993         int i, v;
994         char *p;
995
996         if (opt->flags & OPT_NOPRINT)
997                 return;
998         switch (opt->type) {
999         case o_bool:
1000                 v = opt->flags & OPT_VALUE;
1001                 if (*(bool *)opt->addr != v)
1002                         /* this can happen legitimately, e.g. lock
1003                            option turned off for default device */
1004                         break;
1005                 printer(arg, "%s", opt->name);
1006                 break;
1007         case o_int:
1008                 v = opt->flags & OPT_VALUE;
1009                 if (v >= 128)
1010                         v -= 256;
1011                 i = *(int *)opt->addr;
1012                 if (opt->flags & OPT_NOARG) {
1013                         printer(arg, "%s", opt->name);
1014                         if (i != v) {
1015                                 if (opt->flags & OPT_INC) {
1016                                         for (; i > v; i -= v)
1017                                                 printer(arg, " %s", opt->name);
1018                                 } else
1019                                         printer(arg, " # oops: %d not %d\n",
1020                                                 i, v);
1021                         }
1022                 } else {
1023                         printer(arg, "%s %d", opt->name, i);
1024                 }
1025                 break;
1026         case o_uint32:
1027                 printer(arg, "%s", opt->name);
1028                 if ((opt->flags & OPT_NOARG) == 0)
1029                         printer(arg, " %x", *(u_int32_t *)opt->addr);
1030                 break;
1031
1032         case o_string:
1033                 if (opt->flags & OPT_HIDE) {
1034                         p = "??????";
1035                 } else {
1036                         p = (char *) opt->addr;
1037                         if ((opt->flags & OPT_STATIC) == 0)
1038                                 p = *(char **)p;
1039                 }
1040                 printer(arg, "%s %q", opt->name, p);
1041                 break;
1042
1043         case o_special:
1044         case o_special_noarg:
1045         case o_wild:
1046                 if (opt->type != o_wild) {
1047                         printer(arg, "%s", opt->name);
1048                         if (n_arguments(opt) == 0)
1049                                 break;
1050                         printer(arg, " ");
1051                 }
1052                 if (opt->flags & OPT_A2PRINTER) {
1053                         void (*oprt) __P((option_t *,
1054                                           void ((*)__P((void *, char *, ...))),
1055                                           void *));
1056                         oprt = opt->addr2;
1057                         (*oprt)(opt, printer, arg);
1058                 } else if (opt->flags & OPT_A2STRVAL) {
1059                         p = (char *) opt->addr2;
1060                         if ((opt->flags & OPT_STATIC) == 0)
1061                                 p = *(char **)p;
1062                         printer("%q", p);
1063                 } else if (opt->flags & OPT_A2LIST) {
1064                         struct option_value *ovp;
1065
1066                         ovp = (struct option_value *) opt->addr2;
1067                         for (;;) {
1068                                 printer(arg, "%q", ovp->value);
1069                                 if ((ovp = ovp->next) == NULL)
1070                                         break;
1071                                 printer(arg, "\t\t# (from %s)\n%s ",
1072                                         ovp->source, opt->name);
1073                         }
1074                 } else {
1075                         printer(arg, "xxx # [don't know how to print value]");
1076                 }
1077                 break;
1078
1079         default:
1080                 printer(arg, "# %s value (type %d)", opt->name, opt->type);
1081                 break;
1082         }
1083         printer(arg, "\t\t# (from %s)\n", mainopt->source);
1084 }
1085
1086 /*
1087  * print_option_list - print out options in effect from an
1088  * array of options.
1089  */
1090 static void
1091 print_option_list(opt, printer, arg)
1092     option_t *opt;
1093     void (*printer) __P((void *, char *, ...));
1094     void *arg;
1095 {
1096         while (opt->name != NULL) {
1097                 if (opt->priority != OPRIO_DEFAULT
1098                     && opt->winner != (short int) -1)
1099                         print_option(opt + opt->winner, opt, printer, arg);
1100                 do {
1101                         ++opt;
1102                 } while (opt->flags & OPT_PRIOSUB);
1103         }
1104 }
1105
1106 /*
1107  * print_options - print out what options are in effect.
1108  */
1109 void
1110 print_options(printer, arg)
1111     void (*printer) __P((void *, char *, ...));
1112     void *arg;
1113 {
1114         struct option_list *list;
1115         int i;
1116
1117         printer(arg, "pppd options in effect:\n");
1118         print_option_list(general_options, printer, arg);
1119         print_option_list(auth_options, printer, arg);
1120         for (list = extra_options; list != NULL; list = list->next)
1121                 print_option_list(list->options, printer, arg);
1122         print_option_list(the_channel->options, printer, arg);
1123         for (i = 0; protocols[i] != NULL; ++i)
1124                 print_option_list(protocols[i]->options, printer, arg);
1125 }
1126
1127 /*
1128  * usage - print out a message telling how to use the program.
1129  */
1130 static void
1131 usage()
1132 {
1133     if (phase == PHASE_INITIALIZE)
1134         fprintf(stderr, usage_string, VERSION, progname);
1135 }
1136
1137 /*
1138  * showhelp - print out usage message and exit.
1139  */
1140 static int
1141 showhelp(argv)
1142     char **argv;
1143 {
1144     if (phase == PHASE_INITIALIZE) {
1145         usage();
1146         exit(0);
1147     }
1148     return 0;
1149 }
1150
1151 /*
1152  * showversion - print out the version number and exit.
1153  */
1154 static int
1155 showversion(argv)
1156     char **argv;
1157 {
1158     if (phase == PHASE_INITIALIZE) {
1159         fprintf(stderr, "pppd version %s\n", VERSION);
1160         exit(0);
1161     }
1162     return 0;
1163 }
1164
1165 /*
1166  * option_error - print a message about an error in an option.
1167  * The message is logged, and also sent to
1168  * stderr if phase == PHASE_INITIALIZE.
1169  */
1170 void
1171 option_error __V((char *fmt, ...))
1172 {
1173     va_list args;
1174     char buf[1024];
1175
1176 #if defined(__STDC__)
1177     va_start(args, fmt);
1178 #else
1179     char *fmt;
1180     va_start(args);
1181     fmt = va_arg(args, char *);
1182 #endif
1183     vslprintf(buf, sizeof(buf), fmt, args);
1184     va_end(args);
1185     if (phase == PHASE_INITIALIZE)
1186         fprintf(stderr, "%s: %s\n", progname, buf);
1187     syslog(LOG_ERR, "%s", buf);
1188 }
1189
1190 #if 0
1191 /*
1192  * readable - check if a file is readable by the real user.
1193  */
1194 int
1195 readable(fd)
1196     int fd;
1197 {
1198     uid_t uid;
1199     int i;
1200     struct stat sbuf;
1201
1202     uid = getuid();
1203     if (uid == 0)
1204         return 1;
1205     if (fstat(fd, &sbuf) != 0)
1206         return 0;
1207     if (sbuf.st_uid == uid)
1208         return sbuf.st_mode & S_IRUSR;
1209     if (sbuf.st_gid == getgid())
1210         return sbuf.st_mode & S_IRGRP;
1211     for (i = 0; i < ngroups; ++i)
1212         if (sbuf.st_gid == groups[i])
1213             return sbuf.st_mode & S_IRGRP;
1214     return sbuf.st_mode & S_IROTH;
1215 }
1216 #endif
1217
1218 /*
1219  * Read a word from a file.
1220  * Words are delimited by white-space or by quotes (" or ').
1221  * Quotes, white-space and \ may be escaped with \.
1222  * \<newline> is ignored.
1223  */
1224 int
1225 getword(f, word, newlinep, filename)
1226     FILE *f;
1227     char *word;
1228     int *newlinep;
1229     char *filename;
1230 {
1231     int c, len, escape;
1232     int quoted, comment;
1233     int value, digit, got, n;
1234
1235 #define isoctal(c) ((c) >= '0' && (c) < '8')
1236
1237     *newlinep = 0;
1238     len = 0;
1239     escape = 0;
1240     comment = 0;
1241
1242     /*
1243      * First skip white-space and comments.
1244      */
1245     for (;;) {
1246         c = getc(f);
1247         if (c == EOF)
1248             break;
1249
1250         /*
1251          * A newline means the end of a comment; backslash-newline
1252          * is ignored.  Note that we cannot have escape && comment.
1253          */
1254         if (c == '\n') {
1255             if (!escape) {
1256                 *newlinep = 1;
1257                 comment = 0;
1258             } else
1259                 escape = 0;
1260             continue;
1261         }
1262
1263         /*
1264          * Ignore characters other than newline in a comment.
1265          */
1266         if (comment)
1267             continue;
1268
1269         /*
1270          * If this character is escaped, we have a word start.
1271          */
1272         if (escape)
1273             break;
1274
1275         /*
1276          * If this is the escape character, look at the next character.
1277          */
1278         if (c == '\\') {
1279             escape = 1;
1280             continue;
1281         }
1282
1283         /*
1284          * If this is the start of a comment, ignore the rest of the line.
1285          */
1286         if (c == '#') {
1287             comment = 1;
1288             continue;
1289         }
1290
1291         /*
1292          * A non-whitespace character is the start of a word.
1293          */
1294         if (!isspace(c))
1295             break;
1296     }
1297
1298     /*
1299      * Save the delimiter for quoted strings.
1300      */
1301     if (!escape && (c == '"' || c == '\'')) {
1302         quoted = c;
1303         c = getc(f);
1304     } else
1305         quoted = 0;
1306
1307     /*
1308      * Process characters until the end of the word.
1309      */
1310     while (c != EOF) {
1311         if (escape) {
1312             /*
1313              * This character is escaped: backslash-newline is ignored,
1314              * various other characters indicate particular values
1315              * as for C backslash-escapes.
1316              */
1317             escape = 0;
1318             if (c == '\n') {
1319                 c = getc(f);
1320                 continue;
1321             }
1322
1323             got = 0;
1324             switch (c) {
1325             case 'a':
1326                 value = '\a';
1327                 break;
1328             case 'b':
1329                 value = '\b';
1330                 break;
1331             case 'f':
1332                 value = '\f';
1333                 break;
1334             case 'n':
1335                 value = '\n';
1336                 break;
1337             case 'r':
1338                 value = '\r';
1339                 break;
1340             case 's':
1341                 value = ' ';
1342                 break;
1343             case 't':
1344                 value = '\t';
1345                 break;
1346
1347             default:
1348                 if (isoctal(c)) {
1349                     /*
1350                      * \ddd octal sequence
1351                      */
1352                     value = 0;
1353                     for (n = 0; n < 3 && isoctal(c); ++n) {
1354                         value = (value << 3) + (c & 07);
1355                         c = getc(f);
1356                     }
1357                     got = 1;
1358                     break;
1359                 }
1360
1361                 if (c == 'x') {
1362                     /*
1363                      * \x<hex_string> sequence
1364                      */
1365                     value = 0;
1366                     c = getc(f);
1367                     for (n = 0; n < 2 && isxdigit(c); ++n) {
1368                         digit = toupper(c) - '0';
1369                         if (digit > 10)
1370                             digit += '0' + 10 - 'A';
1371                         value = (value << 4) + digit;
1372                         c = getc (f);
1373                     }
1374                     got = 1;
1375                     break;
1376                 }
1377
1378                 /*
1379                  * Otherwise the character stands for itself.
1380                  */
1381                 value = c;
1382                 break;
1383             }
1384
1385             /*
1386              * Store the resulting character for the escape sequence.
1387              */
1388             if (len < MAXWORDLEN-1)
1389                 word[len] = value;
1390             ++len;
1391
1392             if (!got)
1393                 c = getc(f);
1394             continue;
1395
1396         }
1397
1398         /*
1399          * Not escaped: see if we've reached the end of the word.
1400          */
1401         if (quoted) {
1402             if (c == quoted)
1403                 break;
1404         } else {
1405             if (isspace(c) || c == '#') {
1406                 ungetc (c, f);
1407                 break;
1408             }
1409         }
1410
1411         /*
1412          * Backslash starts an escape sequence.
1413          */
1414         if (c == '\\') {
1415             escape = 1;
1416             c = getc(f);
1417             continue;
1418         }
1419
1420         /*
1421          * An ordinary character: store it in the word and get another.
1422          */
1423         if (len < MAXWORDLEN-1)
1424             word[len] = c;
1425         ++len;
1426
1427         c = getc(f);
1428     }
1429
1430     /*
1431      * End of the word: check for errors.
1432      */
1433     if (c == EOF) {
1434         if (ferror(f)) {
1435             if (errno == 0)
1436                 errno = EIO;
1437             option_error("Error reading %s: %m", filename);
1438             die(1);
1439         }
1440         /*
1441          * If len is zero, then we didn't find a word before the
1442          * end of the file.
1443          */
1444         if (len == 0)
1445             return 0;
1446     }
1447
1448     /*
1449      * Warn if the word was too long, and append a terminating null.
1450      */
1451     if (len >= MAXWORDLEN) {
1452         option_error("warning: word in file %s too long (%.20s...)",
1453                      filename, word);
1454         len = MAXWORDLEN - 1;
1455     }
1456     word[len] = 0;
1457
1458     return 1;
1459
1460 #undef isoctal
1461
1462 }
1463
1464 /*
1465  * number_option - parse an unsigned numeric parameter for an option.
1466  */
1467 static int
1468 number_option(str, valp, base)
1469     char *str;
1470     u_int32_t *valp;
1471     int base;
1472 {
1473     char *ptr;
1474
1475     *valp = strtoul(str, &ptr, base);
1476     if (ptr == str) {
1477         option_error("invalid numeric parameter '%s' for %s option",
1478                      str, current_option);
1479         return 0;
1480     }
1481     return 1;
1482 }
1483
1484
1485 /*
1486  * int_option - like number_option, but valp is int *,
1487  * the base is assumed to be 0, and *valp is not changed
1488  * if there is an error.
1489  */
1490 int
1491 int_option(str, valp)
1492     char *str;
1493     int *valp;
1494 {
1495     u_int32_t v;
1496
1497     if (!number_option(str, &v, 0))
1498         return 0;
1499     *valp = (int) v;
1500     return 1;
1501 }
1502
1503
1504 /*
1505  * The following procedures parse options.
1506  */
1507
1508 /*
1509  * readfile - take commands from a file.
1510  */
1511 static int
1512 readfile(argv)
1513     char **argv;
1514 {
1515     return options_from_file(*argv, 1, 1, privileged_option);
1516 }
1517
1518 /*
1519  * callfile - take commands from /etc/ppp/peers/<name>.
1520  * Name may not contain /../, start with / or ../, or end in /..
1521  */
1522 static int
1523 callfile(argv)
1524     char **argv;
1525 {
1526     char *fname, *arg, *p;
1527     int l, ok;
1528
1529     arg = *argv;
1530     ok = 1;
1531     if (arg[0] == '/' || arg[0] == 0)
1532         ok = 0;
1533     else {
1534         for (p = arg; *p != 0; ) {
1535             if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
1536                 ok = 0;
1537                 break;
1538             }
1539             while (*p != '/' && *p != 0)
1540                 ++p;
1541             if (*p == '/')
1542                 ++p;
1543         }
1544     }
1545     if (!ok) {
1546         option_error("call option value may not contain .. or start with /");
1547         return 0;
1548     }
1549
1550     l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
1551     if ((fname = (char *) malloc(l)) == NULL)
1552         novm("call file name");
1553     slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
1554
1555     ok = options_from_file(fname, 1, 1, 1);
1556
1557     free(fname);
1558     return ok;
1559 }
1560
1561 #ifdef PPP_FILTER
1562 /*
1563  * setpassfilter - Set the pass filter for packets
1564  */
1565 static int
1566 setpassfilter(argv)
1567     char **argv;
1568 {
1569     pc.linktype = DLT_PPP;
1570     pc.snapshot = PPP_HDRLEN;
1571
1572     if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
1573         return 1;
1574     option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
1575     return 0;
1576 }
1577
1578 /*
1579  * setactivefilter - Set the active filter for packets
1580  */
1581 static int
1582 setactivefilter(argv)
1583     char **argv;
1584 {
1585     pc.linktype = DLT_PPP;
1586     pc.snapshot = PPP_HDRLEN;
1587
1588     if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
1589         return 1;
1590     option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
1591     return 0;
1592 }
1593 #endif
1594
1595 /*
1596  * setdomain - Set domain name to append to hostname
1597  */
1598 static int
1599 setdomain(argv)
1600     char **argv;
1601 {
1602     gethostname(hostname, MAXNAMELEN);
1603     if (**argv != 0) {
1604         if (**argv != '.')
1605             strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
1606         domain = hostname + strlen(hostname);
1607         strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
1608     }
1609     hostname[MAXNAMELEN-1] = 0;
1610     return (1);
1611 }
1612
1613
1614 static int
1615 setlogfile(argv)
1616     char **argv;
1617 {
1618     int fd, err;
1619
1620     if (!privileged_option)
1621         seteuid(getuid());
1622     fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
1623     if (fd < 0 && errno == EEXIST)
1624         fd = open(*argv, O_WRONLY | O_APPEND);
1625     err = errno;
1626     if (!privileged_option)
1627         seteuid(0);
1628     if (fd < 0) {
1629         errno = err;
1630         option_error("Can't open log file %s: %m", *argv);
1631         return 0;
1632     }
1633     strlcpy(logfile_name, *argv, sizeof(logfile_name));
1634     if (logfile_fd >= 0)
1635         close(logfile_fd);
1636     logfile_fd = fd;
1637     log_to_fd = fd;
1638     log_default = 0;
1639     return 1;
1640 }
1641
1642 #ifdef PLUGIN
1643 static int
1644 loadplugin(argv)
1645     char **argv;
1646 {
1647     char *arg = *argv;
1648     void *handle;
1649     const char *err;
1650     void (*init) __P((void));
1651     char *path = arg;
1652     const char *vers;
1653
1654     if (strchr(arg, '/') == 0) {
1655         const char *base = _PATH_PLUGIN;
1656         int l = strlen(base) + strlen(arg) + 2;
1657         path = malloc(l);
1658         if (path == 0)
1659             novm("plugin file path");
1660         strlcpy(path, base, l);
1661         strlcat(path, "/", l);
1662         strlcat(path, arg, l);
1663     }
1664     handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
1665     if (handle == 0) {
1666         err = dlerror();
1667         if (err != 0)
1668             option_error("%s", err);
1669         option_error("Couldn't load plugin %s", arg);
1670         goto err;
1671     }
1672     init = (void (*)(void))dlsym(handle, "plugin_init");
1673     if (init == 0) {
1674         option_error("%s has no initialization entry point", arg);
1675         goto errclose;
1676     }
1677     vers = (const char *) dlsym(handle, "pppd_version");
1678     if (vers == 0) {
1679         warn("Warning: plugin %s has no version information", arg);
1680     } else if (strcmp(vers, VERSION) != 0) {
1681         option_error("Plugin %s is for pppd version %s, this is %s",
1682                      vers, VERSION);
1683         goto errclose;
1684     }
1685     info("Plugin %s loaded.", arg);
1686     (*init)();
1687     return 1;
1688
1689  errclose:
1690     dlclose(handle);
1691  err:
1692     if (path != arg)
1693         free(path);
1694     return 0;
1695 }
1696 #endif /* PLUGIN */
1697
1698 #ifdef BUILD_DOMAIN_LOCK
1699 int wsnCheckStrTail(char *username, char *validDomain){
1700     char *ptr=NULL;
1701     unsigned int domainLen=strlen(validDomain);
1702
1703     if(strlen(username) < domainLen){
1704         //printf("Length of ppp username [%s] is less than valid domain name [%s].\n", username, validDomain);
1705         return 0; // 0: FALSE
1706     }
1707     
1708     ptr = username + strlen(username) - domainLen;
1709     //printf("check string..., orig = [%s], tail = [%s]\n", username, ptr);
1710
1711     if(strcmp(ptr, validDomain)==0)
1712         return 1; // 1: TRUE
1713     else
1714         return 0; // 0: FALSE
1715     
1716 }
1717
1718 /***************************************************************************
1719 // Function Name: wsnIsValidPppUser().
1720 // Description  : check whether the ppp username is valid or not.
1721 // Valid domain:    @hgxx.btclick.com
1722                             @hgxx.btinternet.com
1723                             @hgx.btinternet.com
1724                             @hgx.btclick.com
1725                             @btbroadband.com
1726                             @btinternet.com
1727                             ras@teleworker
1728                             @speedtest_domain
1729                             @startup_domain
1730 // Parameters   : ppp username.
1731 // Returns      : TRUE: valid  FALSE:invalid
1732 ****************************************************************************/
1733 int wsnIsValidPppUser(char *pppUser){
1734     char *domainPtr=NULL;
1735     char *chrDigit;
1736
1737     if(wsnCheckStrTail(pppUser, "@dataone"))
1738         return 1; // 1: TRUE
1739     if(wsnCheckStrTail(pppUser, "@touchtelindia.net"))
1740         return 1; // 1: TRUE
1741     if(wsnCheckStrTail(pppUser, "@startup_domain"))
1742         return 1; // 1: TRUE
1743     if(wsnCheckStrTail(pppUser, "@speedtest_domain"))
1744         return 1; // 1: TRUE
1745     if(wsnCheckStrTail(pppUser, "ras@teleworker"))
1746         return 1; // 1: TRUE
1747     if(wsnCheckStrTail(pppUser, "@btinternet.com"))
1748         return 1; // 1: TRUE
1749     if(wsnCheckStrTail(pppUser, "@btbroadband.com"))
1750         return 1; // 1: TRUE
1751     
1752     if(wsnCheckStrTail(pppUser, ".btclick.com")){
1753          domainPtr = pppUser + strlen(pppUser) - strlen(".btclick.com");
1754         chrDigit = domainPtr-1;
1755         if(isdigit(chrDigit[0])==0){
1756             //printf("char [%c] is not a digit.\n", chrDigit[0]);
1757             return 0; // 0: FALSE
1758         }
1759         chrDigit--;
1760         if(isdigit(chrDigit[0])==0){
1761             domainPtr = chrDigit - strlen("@hg") + 1;
1762             if(strncmp(domainPtr, "@hg", strlen("@hg"))==0)
1763                 return 1; // 1: TRUE        
1764         }else{
1765             domainPtr = chrDigit - strlen("@hg");
1766             if(strncmp(domainPtr, "@hg", strlen("@hg"))==0)
1767                 return 1; // 1: TRUE          
1768         }
1769     }
1770
1771     if(wsnCheckStrTail(pppUser, ".btinternet.com")){
1772          domainPtr = pppUser + strlen(pppUser) - strlen(".btinternet.com");
1773         chrDigit = domainPtr - 1;
1774         if(isdigit(chrDigit[0])==0){
1775             //printf("char [%c] is not a digit.\n", chrDigit[0]);
1776             return 0; // 0: FALSE
1777         }
1778         chrDigit--;
1779         if(isdigit(chrDigit[0])==0){
1780             domainPtr = chrDigit - strlen("@hg") + 1;
1781             if(strncmp(domainPtr, "@hg", strlen("@hg"))==0)
1782                 return 1; // 1: TRUE       
1783         }else{
1784             domainPtr = chrDigit - strlen("@hg");
1785             if(strncmp(domainPtr, "@hg", strlen("@hg"))==0)
1786                 return 1; // 1: TRUE         
1787         }
1788     }
1789
1790     //printf("Invalid domain = [%s]\n", pppUser);
1791     return 0; // 0: FALSE
1792 }
1793 #endif