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