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