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