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