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