1993-11-11 11:56:47 +08:00
|
|
|
/*
|
|
|
|
* options.c - handles option processing for PPP.
|
|
|
|
*
|
2002-12-05 07:03:33 +08:00
|
|
|
* Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
|
1993-11-11 11:56:47 +08:00
|
|
|
*
|
2002-12-05 07:03:33 +08:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* 3. The name "Carnegie Mellon University" must not be used to
|
|
|
|
* endorse or promote products derived from this software without
|
|
|
|
* prior written permission. For permission or any legal
|
|
|
|
* details, please contact
|
|
|
|
* Office of Technology Transfer
|
|
|
|
* Carnegie Mellon University
|
|
|
|
* 5000 Forbes Avenue
|
|
|
|
* Pittsburgh, PA 15213-3890
|
|
|
|
* (412) 268-4387, fax: (412) 268-7395
|
|
|
|
* tech-transfer@andrew.cmu.edu
|
|
|
|
*
|
|
|
|
* 4. Redistributions of any form whatsoever must retain the following
|
|
|
|
* acknowledgment:
|
|
|
|
* "This product includes software developed by Computing Services
|
|
|
|
* at Carnegie Mellon University (http://www.cmu.edu/computing/)."
|
|
|
|
*
|
|
|
|
* CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
|
|
|
|
* THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
* AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
|
|
|
|
* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
|
|
|
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
|
|
|
|
Use autoconf/automake to configure and make ppp
This change brings in autoconf/automake scripts to configure the ppp project. Current change doesn't eliminate the previous build system, but the new script autogen.sh will overwrite configure, and generate the basic Makefile.in and Makefile files.
Features can now be enabled by command line:
* Microsoft Extensions,
- MSCHAP
- MPPE
- MS LAN Manager support
* IPXCP protocol
* CBCP protocol
* PAM support
* EAP-TLS support
* EAP-SRP support
* Max session lifetime by byte count
* Plugins
* Packet activity filter support
* Multilink
* IPv6 support
Control linkage with
* OpenSSL (-lssl -lcrypto)
* systemd (-lsystemd)
* libatm (-latm)
* libsrp (-lsrp)
* pam (-lpam)
Also, the configure script is made sensitive to features of OpenSSL. Like the presence or absence of DES, SHA, MD4 and MD5 crypto support. In the cases where either of these are missing, the support will be directly compiled into pppd and plugins.
In addition, package maintainers can now control the installation paths with standard --prefix=, or --localstatedir=, or --sysconfdir= to configure. On top of that, they can now control the following directories:
* runtime directory w/--with-runtime-dir
* logfile directory w/--with-logfile-dir
* plugin directory w/--with-plugin-dir
In the case where automake isn't the right solution, namely: SunOS kernel module build, the original Makefile infrastructure is preserved and reused.
Care was taken to only cosmetically touchup the source files in this change. This means:
* Insert HAVE_CONFIG_H and include config.h in all .c files.
* Change HAS_SHADOW to HAVE_SHADOW_H
* Change HAVE_LOGWTMP to HAVE_UTMP_H
* Introduce HAVE_CRYPT_H into the source code where appropriate
* Added ifdef MPPE where appropriate
* USE_SRP required a few changes as it didn't compile
* Touchup some compile warning in pppstats directory on SunOS
Introduced a new pppdconf.h file that exports the appropriate defines to a module that wants to provide a module that pppd can dynamically load. This will define/undef features like MPPE, CHAPMS such that the project doesn't have to guess what features pppd is compiled with.
Signed-off-by: Eivind Næss <eivnaes@yahoo.com>
2021-06-25 07:07:26 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
1996-04-04 12:00:24 +08:00
|
|
|
#include <ctype.h>
|
2020-12-29 13:08:24 +08:00
|
|
|
#include <stdarg.h>
|
1993-11-11 11:56:47 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
1999-07-21 08:24:32 +08:00
|
|
|
#include <fcntl.h>
|
1993-11-11 11:56:47 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <string.h>
|
1994-05-18 14:34:15 +08:00
|
|
|
#include <pwd.h>
|
1999-09-11 20:09:00 +08:00
|
|
|
#ifdef PLUGIN
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
2004-10-28 08:15:08 +08:00
|
|
|
|
1997-04-30 13:55:54 +08:00
|
|
|
#ifdef PPP_FILTER
|
|
|
|
#include <pcap.h>
|
2004-10-28 08:15:08 +08:00
|
|
|
/*
|
2005-07-13 20:31:36 +08:00
|
|
|
* There have been 3 or 4 different names for this in libpcap CVS, but
|
|
|
|
* this seems to be what they have settled on...
|
|
|
|
* For older versions of libpcap, use DLT_PPP - but that means
|
2004-10-28 08:15:08 +08:00
|
|
|
* we lose the inbound and outbound qualifiers.
|
|
|
|
*/
|
2005-07-13 20:31:36 +08:00
|
|
|
#ifndef DLT_PPP_PPPD
|
|
|
|
#ifdef DLT_PPP_WITHDIRECTION
|
|
|
|
#define DLT_PPP_PPPD DLT_PPP_WITHDIRECTION
|
|
|
|
#else
|
|
|
|
#define DLT_PPP_PPPD DLT_PPP
|
2004-10-28 08:15:08 +08:00
|
|
|
#endif
|
1997-04-30 13:55:54 +08:00
|
|
|
#endif
|
2005-07-13 20:31:36 +08:00
|
|
|
#endif /* PPP_FILTER */
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
#include "pppd.h"
|
|
|
|
#include "pathnames.h"
|
1995-04-24 13:54:44 +08:00
|
|
|
|
|
|
|
#if defined(ultrix) || defined(NeXT)
|
2020-12-29 13:08:24 +08:00
|
|
|
char *strdup(char *);
|
1994-04-18 12:07:48 +08:00
|
|
|
#endif
|
1993-11-11 11:56:47 +08:00
|
|
|
|
1999-08-13 14:46:23 +08:00
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
struct option_value {
|
|
|
|
struct option_value *next;
|
|
|
|
const char *source;
|
|
|
|
char value[1];
|
|
|
|
};
|
|
|
|
|
1994-09-01 08:13:16 +08:00
|
|
|
/*
|
|
|
|
* Option variables and default values.
|
|
|
|
*/
|
|
|
|
int debug = 0; /* Debug flag */
|
|
|
|
int kdebugflag = 0; /* Tell kernel to print debug messages */
|
|
|
|
int default_device = 1; /* Using /dev/tty or equivalent */
|
1999-03-22 13:55:40 +08:00
|
|
|
char devnam[MAXPATHLEN]; /* Device name */
|
1998-11-07 14:59:32 +08:00
|
|
|
bool nodetach = 0; /* Don't detach from controlling tty */
|
|
|
|
bool updetach = 0; /* Detach once link is up */
|
2013-03-02 17:25:28 +08:00
|
|
|
bool master_detach; /* Detach when we're (only) multilink master */
|
Use systemd's sd_notify with option up_sdnotify
This adds an up_sdnotify option so that systemd services of
Type=notify can have pppd send the READY=1 signal to systemd
once a network protocol (typically IP) is up.
To use up_sdnotify, pppd must be compiled with SYSTEMD=y.
up_sdnotify is safe as a non-priveleged option because systemd will
ignore any notifications that it is not expecting. If systemd starts
pppd in a unit-file that is Type=notify, then (and only then) will it
handle the READY=1 signal. If systemd didn't start the process, it
ignroes any notifications unless the signaling process was started by a
service that systemd is monitoring (directly or indirectly, such as a
grandchild process in the same cgroup as a process that systemd started)
AND that service is Type=notify, AND that service is explicitly
configured to allow other processes to send a notification on behalf of
that service by setting NotifyAccess=all.
Also, the socket used is defined in an environment variable provided and
deleted by systemd, allowing system and user services to use a different
socket. I really don't think there's any way to use that socket (even via
the sd_notify api of their library) to gain elevated privileges.
Another reason that up_sdnotify is a non-priveleged option is for cases
where ppp should be started as a system service under a non-priveleged
account. There may be other issues with running ppp under other
accounts, but systemd does not require root--or other privileged--access
in order to use the notification feature. Instead the security for this
feature is provided at the process level in that systemd knows which
processes it did and did not start, and which processes those processes
started (ie other processes in the systemd unit's cgroup), as explained
above.
Signed-off-by: Jacob Floyd <cognifloyd@gmail.com>
2017-03-11 13:25:23 +08:00
|
|
|
#ifdef SYSTEMD
|
|
|
|
bool up_sdnotify = 0; /* Notify systemd once link is up */
|
|
|
|
#endif
|
1995-12-18 11:49:06 +08:00
|
|
|
int maxconnect = 0; /* Maximum connect time */
|
1994-09-01 08:13:16 +08:00
|
|
|
char user[MAXNAMELEN]; /* Username for PAP */
|
|
|
|
char passwd[MAXSECRETLEN]; /* Password for PAP */
|
1998-11-07 14:59:32 +08:00
|
|
|
bool persist = 0; /* Reopen link after it goes down */
|
1994-09-01 08:13:16 +08:00
|
|
|
char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
|
1998-11-07 14:59:32 +08:00
|
|
|
bool demand = 0; /* do dial-on-demand */
|
1995-04-24 13:54:44 +08:00
|
|
|
char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
|
1996-01-02 07:00:42 +08:00
|
|
|
int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
|
|
|
|
int holdoff = 30; /* # seconds to pause before reconnecting */
|
1999-09-11 20:09:00 +08:00
|
|
|
bool holdoff_specified; /* true if a holdoff value has been given */
|
1999-05-12 14:19:49 +08:00
|
|
|
int log_to_fd = 1; /* send log messages to this fd too */
|
2001-03-08 13:11:16 +08:00
|
|
|
bool log_default = 1; /* log_to_fd is default (stdout) */
|
1999-08-12 12:25:10 +08:00
|
|
|
int maxfail = 10; /* max # of unsuccessful connection attempts */
|
1999-08-13 09:57:37 +08:00
|
|
|
char linkname[MAXPATHLEN]; /* logical name for link */
|
1999-09-11 20:09:00 +08:00
|
|
|
bool tune_kernel; /* may alter kernel settings */
|
1999-12-23 09:28:52 +08:00
|
|
|
int connect_delay = 1000; /* wait this many ms after connect script */
|
2000-03-27 14:03:07 +08:00
|
|
|
int req_unit = -1; /* requested interface unit */
|
2020-12-30 18:37:44 +08:00
|
|
|
char path_ipup[MAXPATHLEN]; /* pathname of ip-up script */
|
|
|
|
char path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
|
2021-08-01 02:47:21 +08:00
|
|
|
char req_ifname[IFNAMSIZ]; /* requested interface name */
|
2000-03-27 14:03:07 +08:00
|
|
|
bool multilink = 0; /* Enable multilink operation */
|
2000-04-04 15:06:53 +08:00
|
|
|
char *bundle_name = NULL; /* bundle name for multilink */
|
2001-03-08 13:11:16 +08:00
|
|
|
bool dump_options; /* print out option values */
|
|
|
|
bool dryrun; /* print out option values and exit */
|
|
|
|
char *domain; /* domain name set by domain option */
|
2004-11-04 17:46:50 +08:00
|
|
|
int child_wait = 5; /* # seconds to wait for children at exit */
|
2010-08-23 21:59:56 +08:00
|
|
|
struct userenv *userenv_list; /* user environment variables */
|
2014-06-03 16:53:47 +08:00
|
|
|
int dfl_route_metric = -1; /* metric of the default route to set over the PPP link */
|
1994-09-01 08:13:16 +08:00
|
|
|
|
2002-07-13 14:24:36 +08:00
|
|
|
#ifdef MAXOCTETS
|
|
|
|
unsigned int maxoctets = 0; /* default - no limit */
|
|
|
|
int maxoctets_dir = 0; /* default - sum of traffic */
|
|
|
|
int maxoctets_timeout = 1; /* default 1 second */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
extern option_t auth_options[];
|
1999-05-12 14:19:49 +08:00
|
|
|
extern struct stat devstat;
|
1997-04-30 13:55:54 +08:00
|
|
|
|
|
|
|
#ifdef PPP_FILTER
|
|
|
|
struct bpf_program pass_filter;/* Filter program for packets to pass */
|
|
|
|
struct bpf_program active_filter; /* Filter program for link-active pkts */
|
|
|
|
#endif
|
1996-08-28 14:41:35 +08:00
|
|
|
|
2010-08-23 21:59:56 +08:00
|
|
|
static option_t *curopt; /* pointer to option being processed */
|
1999-05-14 09:09:04 +08:00
|
|
|
char *current_option; /* the name of the option being parsed */
|
|
|
|
int privileged_option; /* set iff the current option came from root */
|
|
|
|
char *option_source; /* string saying where the option came from */
|
2001-02-22 11:15:21 +08:00
|
|
|
int option_priority = OPRIO_CFGFILE; /* priority of the current options */
|
|
|
|
bool devnam_fixed; /* can no longer change device name */
|
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
static int logfile_fd = -1; /* fd opened for log file */
|
|
|
|
static char logfile_name[MAXPATHLEN]; /* name of log file */
|
1999-05-14 09:09:04 +08:00
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
|
|
|
* Prototypes
|
|
|
|
*/
|
2020-12-29 13:08:24 +08:00
|
|
|
static int setdomain(char **);
|
|
|
|
static int readfile(char **);
|
|
|
|
static int callfile(char **);
|
|
|
|
static int showversion(char **);
|
|
|
|
static int showhelp(char **);
|
|
|
|
static void usage(void);
|
|
|
|
static int setlogfile(char **);
|
1999-09-11 20:09:00 +08:00
|
|
|
#ifdef PLUGIN
|
2020-12-29 13:08:24 +08:00
|
|
|
static int loadplugin(char **);
|
1999-09-11 20:09:00 +08:00
|
|
|
#endif
|
1997-04-30 13:55:54 +08:00
|
|
|
|
|
|
|
#ifdef PPP_FILTER
|
2020-12-29 13:08:24 +08:00
|
|
|
static int setpassfilter(char **);
|
|
|
|
static int setactivefilter(char **);
|
1997-04-30 13:55:54 +08:00
|
|
|
#endif
|
1994-09-21 14:47:37 +08:00
|
|
|
|
2002-07-13 14:24:36 +08:00
|
|
|
#ifdef MAXOCTETS
|
2020-12-29 13:08:24 +08:00
|
|
|
static int setmodir(char **);
|
2002-07-13 14:24:36 +08:00
|
|
|
#endif
|
|
|
|
|
2020-12-29 13:08:24 +08:00
|
|
|
static int user_setenv(char **);
|
|
|
|
static void user_setprint(option_t *, printer_func, void *);
|
|
|
|
static int user_unsetenv(char **);
|
|
|
|
static void user_unsetprint(option_t *, printer_func, void *);
|
2010-08-23 21:59:56 +08:00
|
|
|
|
2020-12-29 13:08:24 +08:00
|
|
|
static option_t *find_option(char *name);
|
|
|
|
static int process_option(option_t *, char *, char **);
|
|
|
|
static int n_arguments(option_t *);
|
|
|
|
static int number_option(char *, u_int32_t *, int);
|
1995-04-24 13:54:44 +08:00
|
|
|
|
1999-09-11 20:09:00 +08:00
|
|
|
/*
|
|
|
|
* Structure to store extra lists of options.
|
|
|
|
*/
|
|
|
|
struct option_list {
|
|
|
|
option_t *options;
|
|
|
|
struct option_list *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct option_list *extra_options = NULL;
|
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
|
|
|
* Valid arguments.
|
|
|
|
*/
|
1998-11-07 14:59:32 +08:00
|
|
|
option_t general_options[] = {
|
|
|
|
{ "debug", o_int, &debug,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Increase debugging level", OPT_INC | OPT_NOARG | 1 },
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "-d", o_int, &debug,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Increase debugging level",
|
|
|
|
OPT_ALIAS | OPT_INC | OPT_NOARG | 1 },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "kdebug", o_int, &kdebugflag,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Set kernel driver debug level", OPT_PRIO },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "nodetach", o_bool, &nodetach,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Don't detach from controlling tty", OPT_PRIO | 1 },
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "-detach", o_bool, &nodetach,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Don't detach from controlling tty", OPT_ALIAS | OPT_PRIOSUB | 1 },
|
Use systemd's sd_notify with option up_sdnotify
This adds an up_sdnotify option so that systemd services of
Type=notify can have pppd send the READY=1 signal to systemd
once a network protocol (typically IP) is up.
To use up_sdnotify, pppd must be compiled with SYSTEMD=y.
up_sdnotify is safe as a non-priveleged option because systemd will
ignore any notifications that it is not expecting. If systemd starts
pppd in a unit-file that is Type=notify, then (and only then) will it
handle the READY=1 signal. If systemd didn't start the process, it
ignroes any notifications unless the signaling process was started by a
service that systemd is monitoring (directly or indirectly, such as a
grandchild process in the same cgroup as a process that systemd started)
AND that service is Type=notify, AND that service is explicitly
configured to allow other processes to send a notification on behalf of
that service by setting NotifyAccess=all.
Also, the socket used is defined in an environment variable provided and
deleted by systemd, allowing system and user services to use a different
socket. I really don't think there's any way to use that socket (even via
the sd_notify api of their library) to gain elevated privileges.
Another reason that up_sdnotify is a non-priveleged option is for cases
where ppp should be started as a system service under a non-priveleged
account. There may be other issues with running ppp under other
accounts, but systemd does not require root--or other privileged--access
in order to use the notification feature. Instead the security for this
feature is provided at the process level in that systemd knows which
processes it did and did not start, and which processes those processes
started (ie other processes in the systemd unit's cgroup), as explained
above.
Signed-off-by: Jacob Floyd <cognifloyd@gmail.com>
2017-03-11 13:25:23 +08:00
|
|
|
#ifdef SYSTEMD
|
|
|
|
{ "up_sdnotify", o_bool, &up_sdnotify,
|
|
|
|
"Notify systemd once link is up (implies nodetach)",
|
|
|
|
OPT_PRIOSUB | OPT_A2COPY | 1, &nodetach },
|
|
|
|
#endif
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "updetach", o_bool, &updetach,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Detach from controlling tty once link is up",
|
|
|
|
OPT_PRIOSUB | OPT_A2CLR | 1, &nodetach },
|
|
|
|
|
2013-03-02 17:25:28 +08:00
|
|
|
{ "master_detach", o_bool, &master_detach,
|
|
|
|
"Detach when we're multilink master but have no link", 1 },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "holdoff", o_int, &holdoff,
|
2004-11-10 06:33:35 +08:00
|
|
|
"Set time in seconds before retrying connection",
|
|
|
|
OPT_PRIO, &holdoff_specified },
|
2001-03-08 13:11:16 +08:00
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "idle", o_int, &idle_time_limit,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Set time in seconds before disconnecting idle link", OPT_PRIO },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "maxconnect", o_int, &maxconnect,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Set connection time limit",
|
|
|
|
OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
|
|
|
|
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "domain", o_special, (void *)setdomain,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Add given domain name to hostname",
|
|
|
|
OPT_PRIO | OPT_PRIV | OPT_A2STRVAL, &domain },
|
|
|
|
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "file", o_special, (void *)readfile,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Take options from a file", OPT_NOPRINT },
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "call", o_special, (void *)callfile,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Take options from a privileged file", OPT_NOPRINT },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "persist", o_bool, &persist,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Keep on reopening connection after close", OPT_PRIO | 1 },
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "nopersist", o_bool, &persist,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Turn off persist option", OPT_PRIOSUB },
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ "demand", o_bool, &demand,
|
1999-07-21 08:24:32 +08:00
|
|
|
"Dial on demand", OPT_INITONLY | 1, &persist },
|
2001-03-08 13:11:16 +08:00
|
|
|
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "--version", o_special_noarg, (void *)showversion,
|
1998-11-07 14:59:32 +08:00
|
|
|
"Show version number" },
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "--help", o_special_noarg, (void *)showhelp,
|
1998-11-07 14:59:32 +08:00
|
|
|
"Show brief listing of options" },
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "-h", o_special_noarg, (void *)showhelp,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Show brief listing of options", OPT_ALIAS },
|
|
|
|
|
|
|
|
{ "logfile", o_special, (void *)setlogfile,
|
|
|
|
"Append log messages to this file",
|
|
|
|
OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, &logfile_name },
|
1999-05-12 14:19:49 +08:00
|
|
|
{ "logfd", o_int, &log_to_fd,
|
2000-04-13 20:05:16 +08:00
|
|
|
"Send log messages to this file descriptor",
|
2001-03-08 13:11:16 +08:00
|
|
|
OPT_PRIOSUB | OPT_A2CLR, &log_default },
|
1999-07-21 08:24:32 +08:00
|
|
|
{ "nolog", o_int, &log_to_fd,
|
|
|
|
"Don't send log messages to any file",
|
2001-03-08 13:11:16 +08:00
|
|
|
OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) },
|
1999-05-12 14:19:49 +08:00
|
|
|
{ "nologfd", o_int, &log_to_fd,
|
|
|
|
"Don't send log messages to any file descriptor",
|
2001-03-08 13:11:16 +08:00
|
|
|
OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) },
|
|
|
|
|
1999-08-13 09:57:37 +08:00
|
|
|
{ "linkname", o_string, linkname,
|
|
|
|
"Set logical name for link",
|
2001-03-08 13:11:16 +08:00
|
|
|
OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXPATHLEN },
|
|
|
|
|
1999-08-12 12:17:07 +08:00
|
|
|
{ "maxfail", o_int, &maxfail,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Maximum number of unsuccessful connection attempts to allow",
|
|
|
|
OPT_PRIO },
|
|
|
|
|
1999-09-11 20:09:00 +08:00
|
|
|
{ "ktune", o_bool, &tune_kernel,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Alter kernel settings as necessary", OPT_PRIO | 1 },
|
1999-09-11 20:09:00 +08:00
|
|
|
{ "noktune", o_bool, &tune_kernel,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Don't alter kernel settings", OPT_PRIOSUB },
|
|
|
|
|
1999-12-23 09:28:52 +08:00
|
|
|
{ "connect-delay", o_int, &connect_delay,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Maximum time (in ms) to wait after connect script finishes",
|
|
|
|
OPT_PRIO },
|
|
|
|
|
2000-03-27 14:03:07 +08:00
|
|
|
{ "unit", o_int, &req_unit,
|
2001-03-08 13:11:16 +08:00
|
|
|
"PPP interface unit number to use if possible",
|
|
|
|
OPT_PRIO | OPT_LLIMIT, 0, 0 },
|
|
|
|
|
2016-08-23 14:10:21 +08:00
|
|
|
{ "ifname", o_string, req_ifname,
|
|
|
|
"Set PPP interface name",
|
2021-08-01 02:47:21 +08:00
|
|
|
OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, IFNAMSIZ },
|
2016-08-23 14:10:21 +08:00
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
{ "dump", o_bool, &dump_options,
|
|
|
|
"Print out option values after parsing all options", 1 },
|
|
|
|
{ "dryrun", o_bool, &dryrun,
|
|
|
|
"Stop after parsing, printing, and checking options", 1 },
|
|
|
|
|
2004-11-04 17:46:50 +08:00
|
|
|
{ "child-timeout", o_int, &child_wait,
|
2004-11-10 06:33:35 +08:00
|
|
|
"Number of seconds to wait for child processes at exit",
|
|
|
|
OPT_PRIO },
|
2004-11-04 17:46:50 +08:00
|
|
|
|
2010-08-23 21:59:56 +08:00
|
|
|
{ "set", o_special, (void *)user_setenv,
|
|
|
|
"Set user environment variable",
|
|
|
|
OPT_A2PRINTER | OPT_NOPRINT, (void *)user_setprint },
|
|
|
|
{ "unset", o_special, (void *)user_unsetenv,
|
|
|
|
"Unset user environment variable",
|
|
|
|
OPT_A2PRINTER | OPT_NOPRINT, (void *)user_unsetprint },
|
|
|
|
|
2014-06-03 16:53:47 +08:00
|
|
|
{ "defaultroute-metric", o_int, &dfl_route_metric,
|
|
|
|
"Metric to use for the default route (Linux only; -1 for default behavior)",
|
|
|
|
OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 },
|
2010-08-23 21:59:56 +08:00
|
|
|
|
2020-12-30 18:37:44 +08:00
|
|
|
{ "ip-up-script", o_string, path_ipup,
|
|
|
|
"Set pathname of ip-up script",
|
|
|
|
OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
|
|
|
|
{ "ip-down-script", o_string, path_ipdown,
|
|
|
|
"Set pathname of ip-down script",
|
|
|
|
OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
|
|
|
|
|
2000-03-27 14:03:07 +08:00
|
|
|
#ifdef HAVE_MULTILINK
|
|
|
|
{ "multilink", o_bool, &multilink,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Enable multilink operation", OPT_PRIO | 1 },
|
2000-03-27 14:03:07 +08:00
|
|
|
{ "mp", o_bool, &multilink,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Enable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 1 },
|
|
|
|
{ "nomultilink", o_bool, &multilink,
|
|
|
|
"Disable multilink operation", OPT_PRIOSUB | 0 },
|
2000-03-27 14:03:07 +08:00
|
|
|
{ "nomp", o_bool, &multilink,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Disable multilink operation", OPT_PRIOSUB | OPT_ALIAS | 0 },
|
|
|
|
|
2000-04-04 15:06:53 +08:00
|
|
|
{ "bundle", o_string, &bundle_name,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Bundle name for multilink", OPT_PRIO },
|
2000-03-27 14:03:07 +08:00
|
|
|
#endif /* HAVE_MULTILINK */
|
2001-03-08 13:11:16 +08:00
|
|
|
|
1999-09-11 20:09:00 +08:00
|
|
|
#ifdef PLUGIN
|
2000-04-15 09:27:13 +08:00
|
|
|
{ "plugin", o_special, (void *)loadplugin,
|
2001-03-08 13:11:16 +08:00
|
|
|
"Load a plug-in module into pppd", OPT_PRIV | OPT_A2LIST },
|
1999-09-11 20:09:00 +08:00
|
|
|
#endif
|
1995-12-18 11:49:06 +08:00
|
|
|
|
1997-04-30 13:55:54 +08:00
|
|
|
#ifdef PPP_FILTER
|
2005-07-09 12:58:36 +08:00
|
|
|
{ "pass-filter", o_special, setpassfilter,
|
2001-03-08 13:11:16 +08:00
|
|
|
"set filter for packets to pass", OPT_PRIO },
|
|
|
|
|
2005-07-09 12:58:36 +08:00
|
|
|
{ "active-filter", o_special, setactivefilter,
|
2001-03-08 13:11:16 +08:00
|
|
|
"set filter for active pkts", OPT_PRIO },
|
1997-04-30 13:55:54 +08:00
|
|
|
#endif
|
|
|
|
|
2002-07-13 14:24:36 +08:00
|
|
|
#ifdef MAXOCTETS
|
|
|
|
{ "maxoctets", o_int, &maxoctets,
|
|
|
|
"Set connection traffic limit",
|
|
|
|
OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
|
|
|
|
{ "mo", o_int, &maxoctets,
|
|
|
|
"Set connection traffic limit",
|
|
|
|
OPT_ALIAS | OPT_PRIO | OPT_LLIMIT | OPT_NOINCR | OPT_ZEROINF },
|
|
|
|
{ "mo-direction", o_special, setmodir,
|
|
|
|
"Set direction for limit traffic (sum,in,out,max)" },
|
|
|
|
{ "mo-timeout", o_int, &maxoctets_timeout,
|
|
|
|
"Check for traffic limit every N seconds", OPT_PRIO | OPT_LLIMIT | 1 },
|
|
|
|
#endif
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
{ NULL }
|
1993-11-11 11:56:47 +08:00
|
|
|
};
|
|
|
|
|
1994-05-24 19:24:32 +08:00
|
|
|
#ifndef IMPLEMENTATION
|
|
|
|
#define IMPLEMENTATION ""
|
|
|
|
#endif
|
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
static char *usage_string = "\
|
2001-03-08 13:11:16 +08:00
|
|
|
pppd version %s\n\
|
1996-05-27 08:04:47 +08:00
|
|
|
Usage: %s [ options ], where options are:\n\
|
1993-11-11 11:56:47 +08:00
|
|
|
<device> Communicate over the named device\n\
|
|
|
|
<speed> Set the baud rate to <speed>\n\
|
|
|
|
<loc>:<rem> Set the local and/or remote interface IP\n\
|
|
|
|
addresses. Either one may be omitted.\n\
|
|
|
|
asyncmap <n> Set the desired async map to hex <n>\n\
|
|
|
|
auth Require authentication from peer\n\
|
|
|
|
connect <p> Invoke shell command <p> to set up the serial line\n\
|
|
|
|
crtscts Use hardware RTS/CTS flow control\n\
|
|
|
|
defaultroute Add default route through interface\n\
|
|
|
|
file <f> Take options from file <f>\n\
|
|
|
|
modem Use modem control lines\n\
|
|
|
|
mru <n> Set MRU value to <n> for negotiation\n\
|
|
|
|
See pppd(8) for more options.\n\
|
|
|
|
";
|
|
|
|
|
|
|
|
/*
|
1996-08-28 14:41:35 +08:00
|
|
|
* parse_args - parse a string of arguments from the command line.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
parse_args(int argc, char **argv)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
1996-04-04 12:00:24 +08:00
|
|
|
char *arg;
|
1998-11-07 14:59:32 +08:00
|
|
|
option_t *opt;
|
2001-02-22 11:15:21 +08:00
|
|
|
int n;
|
1993-11-11 11:56:47 +08:00
|
|
|
|
1996-08-28 14:41:35 +08:00
|
|
|
privileged_option = privileged;
|
|
|
|
option_source = "command line";
|
2001-02-22 11:15:21 +08:00
|
|
|
option_priority = OPRIO_CMDLINE;
|
1993-11-11 11:56:47 +08:00
|
|
|
while (argc > 0) {
|
|
|
|
arg = *argv++;
|
|
|
|
--argc;
|
1998-11-07 14:59:32 +08:00
|
|
|
opt = find_option(arg);
|
2001-02-22 11:15:21 +08:00
|
|
|
if (opt == NULL) {
|
1998-11-07 14:59:32 +08:00
|
|
|
option_error("unrecognized option '%s'", arg);
|
|
|
|
usage();
|
|
|
|
return 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
n = n_arguments(opt);
|
|
|
|
if (argc < n) {
|
|
|
|
option_error("too few parameters for option %s", arg);
|
1998-11-07 14:59:32 +08:00
|
|
|
return 0;
|
1996-07-01 09:18:23 +08:00
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
if (!process_option(opt, arg, argv))
|
|
|
|
return 0;
|
|
|
|
argc -= n;
|
|
|
|
argv += n;
|
1996-07-01 09:18:23 +08:00
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
return 1;
|
1996-07-01 09:18:23 +08:00
|
|
|
}
|
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
|
|
|
* options_from_file - Read a string of options from a file,
|
|
|
|
* and interpret them.
|
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
options_from_file(char *filename, int must_exist, int check_prot, int priv)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
|
|
|
FILE *f;
|
1999-04-12 14:24:53 +08:00
|
|
|
int i, newline, ret, err;
|
1998-11-07 14:59:32 +08:00
|
|
|
option_t *opt;
|
2001-02-22 11:15:21 +08:00
|
|
|
int oldpriv, n;
|
1998-11-07 14:59:32 +08:00
|
|
|
char *oldsource;
|
2006-06-18 19:26:00 +08:00
|
|
|
uid_t euid;
|
1993-11-11 11:56:47 +08:00
|
|
|
char *argv[MAXARGS];
|
|
|
|
char args[MAXARGS][MAXWORDLEN];
|
|
|
|
char cmd[MAXWORDLEN];
|
|
|
|
|
2006-06-18 19:26:00 +08:00
|
|
|
euid = geteuid();
|
2006-06-04 15:04:57 +08:00
|
|
|
if (check_prot && seteuid(getuid()) == -1) {
|
|
|
|
option_error("unable to drop privileges to open %s: %m", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
1999-03-06 19:28:11 +08:00
|
|
|
f = fopen(filename, "r");
|
1999-04-12 14:24:53 +08:00
|
|
|
err = errno;
|
2006-06-18 19:26:00 +08:00
|
|
|
if (check_prot && seteuid(euid) == -1)
|
2006-06-04 15:04:57 +08:00
|
|
|
fatal("unable to regain privileges");
|
1999-03-06 19:28:11 +08:00
|
|
|
if (f == NULL) {
|
1999-04-12 14:24:53 +08:00
|
|
|
errno = err;
|
2000-06-30 12:54:23 +08:00
|
|
|
if (!must_exist) {
|
|
|
|
if (err != ENOENT && err != ENOTDIR)
|
|
|
|
warn("Warning: can't open options file %s: %m", filename);
|
|
|
|
return 1;
|
|
|
|
}
|
1996-05-27 08:04:47 +08:00
|
|
|
option_error("Can't open options file %s: %m", filename);
|
1994-05-01 19:45:53 +08:00
|
|
|
return 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
1994-05-18 14:34:15 +08:00
|
|
|
|
1996-08-28 14:41:35 +08:00
|
|
|
oldpriv = privileged_option;
|
|
|
|
privileged_option = priv;
|
1998-11-07 14:59:32 +08:00
|
|
|
oldsource = option_source;
|
|
|
|
option_source = strdup(filename);
|
|
|
|
if (option_source == NULL)
|
|
|
|
option_source = "file";
|
1996-08-28 14:41:35 +08:00
|
|
|
ret = 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
while (getword(f, cmd, &newline, filename)) {
|
1998-11-07 14:59:32 +08:00
|
|
|
opt = find_option(cmd);
|
2001-02-22 11:15:21 +08:00
|
|
|
if (opt == NULL) {
|
|
|
|
option_error("In file %s: unrecognized option '%s'",
|
|
|
|
filename, cmd);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
n = n_arguments(opt);
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
if (!getword(f, args[i], &newline, filename)) {
|
|
|
|
option_error(
|
1996-05-27 08:04:47 +08:00
|
|
|
"In file %s: too few parameters for option '%s'",
|
|
|
|
filename, cmd);
|
1999-07-21 08:24:32 +08:00
|
|
|
goto err;
|
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
argv[i] = args[i];
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
if (!process_option(opt, cmd, argv))
|
1998-11-07 14:59:32 +08:00
|
|
|
goto err;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
1996-08-28 14:41:35 +08:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
err:
|
|
|
|
fclose(f);
|
|
|
|
privileged_option = oldpriv;
|
1998-11-07 14:59:32 +08:00
|
|
|
option_source = oldsource;
|
1996-08-28 14:41:35 +08:00
|
|
|
return ret;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* options_from_user - See if the use has a ~/.ppprc file,
|
|
|
|
* and if so, interpret options from it.
|
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
options_from_user(void)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
|
|
|
char *user, *path, *file;
|
|
|
|
int ret;
|
1994-05-18 14:34:15 +08:00
|
|
|
struct passwd *pw;
|
1999-03-12 14:07:24 +08:00
|
|
|
size_t pl;
|
1993-11-11 11:56:47 +08:00
|
|
|
|
1999-03-06 19:28:11 +08:00
|
|
|
pw = getpwuid(getuid());
|
1994-05-18 14:34:15 +08:00
|
|
|
if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0)
|
1994-05-24 19:24:32 +08:00
|
|
|
return 1;
|
1994-05-18 14:34:15 +08:00
|
|
|
file = _PATH_USEROPT;
|
1999-03-12 14:07:24 +08:00
|
|
|
pl = strlen(user) + strlen(file) + 2;
|
|
|
|
path = malloc(pl);
|
1993-11-11 11:56:47 +08:00
|
|
|
if (path == NULL)
|
|
|
|
novm("init file name");
|
1999-03-12 14:07:24 +08:00
|
|
|
slprintf(path, pl, "%s/%s", user, file);
|
2001-02-22 11:15:21 +08:00
|
|
|
option_priority = OPRIO_CFGFILE;
|
1996-08-28 14:41:35 +08:00
|
|
|
ret = options_from_file(path, 0, 1, privileged);
|
1993-11-11 11:56:47 +08:00
|
|
|
free(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
1994-05-18 14:34:15 +08:00
|
|
|
/*
|
|
|
|
* options_for_tty - See if an options file exists for the serial
|
|
|
|
* device, and if so, interpret options from it.
|
2000-06-30 12:54:23 +08:00
|
|
|
* We only allow the per-tty options file to override anything from
|
|
|
|
* the command line if it is something that the user can't override
|
2001-02-22 11:15:21 +08:00
|
|
|
* once it has been set by root; this is done by giving configuration
|
|
|
|
* files a lower priority than the command line.
|
1994-05-18 14:34:15 +08:00
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
options_for_tty(void)
|
1994-05-18 14:34:15 +08:00
|
|
|
{
|
1996-01-18 11:35:38 +08:00
|
|
|
char *dev, *path, *p;
|
1994-05-18 14:34:15 +08:00
|
|
|
int ret;
|
1999-03-12 14:07:24 +08:00
|
|
|
size_t pl;
|
1994-05-18 14:34:15 +08:00
|
|
|
|
1996-01-18 11:35:38 +08:00
|
|
|
dev = devnam;
|
2004-01-13 12:02:07 +08:00
|
|
|
if ((p = strstr(dev, "/dev/")) != NULL)
|
|
|
|
dev = p + 5;
|
1999-03-22 13:55:40 +08:00
|
|
|
if (dev[0] == 0 || strcmp(dev, "tty") == 0)
|
1994-05-18 14:34:15 +08:00
|
|
|
return 1; /* don't look for /etc/ppp/options.tty */
|
1999-03-12 14:07:24 +08:00
|
|
|
pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
|
|
|
|
path = malloc(pl);
|
1994-05-18 14:34:15 +08:00
|
|
|
if (path == NULL)
|
|
|
|
novm("tty init file name");
|
1999-03-12 14:07:24 +08:00
|
|
|
slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
|
1996-01-18 11:35:38 +08:00
|
|
|
/* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
|
1999-03-12 14:07:24 +08:00
|
|
|
for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
|
|
|
|
if (*p == '/')
|
|
|
|
*p = '.';
|
2001-02-22 11:15:21 +08:00
|
|
|
option_priority = OPRIO_CFGFILE;
|
1996-08-28 14:41:35 +08:00
|
|
|
ret = options_from_file(path, 0, 0, 1);
|
1994-05-18 14:34:15 +08:00
|
|
|
free(path);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
1999-07-21 08:24:32 +08:00
|
|
|
/*
|
|
|
|
* options_from_list - process a string of options in a wordlist.
|
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
options_from_list(struct wordlist *w, int priv)
|
1999-07-21 08:24:32 +08:00
|
|
|
{
|
|
|
|
char *argv[MAXARGS];
|
|
|
|
option_t *opt;
|
2001-02-22 11:15:21 +08:00
|
|
|
int i, n, ret = 0;
|
|
|
|
struct wordlist *w0;
|
1999-07-21 08:24:32 +08:00
|
|
|
|
|
|
|
privileged_option = priv;
|
|
|
|
option_source = "secrets file";
|
2001-02-22 11:15:21 +08:00
|
|
|
option_priority = OPRIO_SECFILE;
|
1999-07-21 08:24:32 +08:00
|
|
|
|
|
|
|
while (w != NULL) {
|
|
|
|
opt = find_option(w->word);
|
2001-02-22 11:15:21 +08:00
|
|
|
if (opt == NULL) {
|
1999-07-21 08:24:32 +08:00
|
|
|
option_error("In secrets file: unrecognized option '%s'",
|
|
|
|
w->word);
|
|
|
|
goto err;
|
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
n = n_arguments(opt);
|
|
|
|
w0 = w;
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
|
|
w = w->next;
|
|
|
|
if (w == NULL) {
|
|
|
|
option_error(
|
|
|
|
"In secrets file: too few parameters for option '%s'",
|
|
|
|
w0->word);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
argv[i] = w->word;
|
|
|
|
}
|
|
|
|
if (!process_option(opt, w0->word, argv))
|
1999-07-21 08:24:32 +08:00
|
|
|
goto err;
|
2001-03-13 06:56:12 +08:00
|
|
|
w = w->next;
|
1999-07-21 08:24:32 +08:00
|
|
|
}
|
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
err:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2001-02-22 11:15:21 +08:00
|
|
|
/*
|
|
|
|
* match_option - see if this option matches an option_t structure.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
match_option(char *name, option_t *opt, int dowild)
|
2001-02-22 11:15:21 +08:00
|
|
|
{
|
2020-12-29 13:08:24 +08:00
|
|
|
int (*match)(char *, char **, int);
|
2001-02-22 11:15:21 +08:00
|
|
|
|
|
|
|
if (dowild != (opt->type == o_wild))
|
|
|
|
return 0;
|
|
|
|
if (!dowild)
|
|
|
|
return strcmp(name, opt->name) == 0;
|
2020-12-29 13:08:24 +08:00
|
|
|
match = (int (*)(char *, char **, int)) opt->addr;
|
2001-02-22 11:15:21 +08:00
|
|
|
return (*match)(name, NULL, 0);
|
|
|
|
}
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
/*
|
|
|
|
* find_option - scan the option lists for the various protocols
|
|
|
|
* looking for an entry with the given name.
|
|
|
|
* This could be optimized by using a hash table.
|
|
|
|
*/
|
|
|
|
static option_t *
|
2020-12-29 13:08:24 +08:00
|
|
|
find_option(char *name)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
2001-02-22 11:15:21 +08:00
|
|
|
option_t *opt;
|
|
|
|
struct option_list *list;
|
|
|
|
int i, dowild;
|
|
|
|
|
|
|
|
for (dowild = 0; dowild <= 1; ++dowild) {
|
|
|
|
for (opt = general_options; opt->name != NULL; ++opt)
|
|
|
|
if (match_option(name, opt, dowild))
|
|
|
|
return opt;
|
|
|
|
for (opt = auth_options; opt->name != NULL; ++opt)
|
|
|
|
if (match_option(name, opt, dowild))
|
|
|
|
return opt;
|
|
|
|
for (list = extra_options; list != NULL; list = list->next)
|
|
|
|
for (opt = list->options; opt->name != NULL; ++opt)
|
|
|
|
if (match_option(name, opt, dowild))
|
|
|
|
return opt;
|
2001-03-08 13:11:16 +08:00
|
|
|
for (opt = the_channel->options; opt->name != NULL; ++opt)
|
|
|
|
if (match_option(name, opt, dowild))
|
|
|
|
return opt;
|
2001-02-22 11:15:21 +08:00
|
|
|
for (i = 0; protocols[i] != NULL; ++i)
|
|
|
|
if ((opt = protocols[i]->options) != NULL)
|
|
|
|
for (; opt->name != NULL; ++opt)
|
|
|
|
if (match_option(name, opt, dowild))
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
return NULL;
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process_option - process one new-style option.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
process_option(option_t *opt, char *cmd, char **argv)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
|
|
|
u_int32_t v;
|
|
|
|
int iv, a;
|
|
|
|
char *sv;
|
2020-12-29 13:08:24 +08:00
|
|
|
int (*parser)(char **);
|
|
|
|
int (*wildp)(char *, char **, int);
|
2001-02-22 11:15:21 +08:00
|
|
|
char *optopt = (opt->type == o_wild)? "": " option";
|
|
|
|
int prio = option_priority;
|
2001-03-08 13:11:16 +08:00
|
|
|
option_t *mainopt = opt;
|
2001-02-22 11:15:21 +08:00
|
|
|
|
2002-10-27 21:00:13 +08:00
|
|
|
current_option = opt->name;
|
2001-02-22 11:15:21 +08:00
|
|
|
if ((opt->flags & OPT_PRIVFIX) && privileged_option)
|
|
|
|
prio += OPRIO_ROOT;
|
2001-03-08 13:11:16 +08:00
|
|
|
while (mainopt->flags & OPT_PRIOSUB)
|
|
|
|
--mainopt;
|
|
|
|
if (mainopt->flags & OPT_PRIO) {
|
|
|
|
if (prio < mainopt->priority) {
|
2001-02-22 11:15:21 +08:00
|
|
|
/* new value doesn't override old */
|
2001-03-08 13:11:16 +08:00
|
|
|
if (prio == OPRIO_CMDLINE && mainopt->priority > OPRIO_ROOT) {
|
2001-02-22 11:15:21 +08:00
|
|
|
option_error("%s%s set in %s cannot be overridden\n",
|
2001-03-08 13:11:16 +08:00
|
|
|
opt->name, optopt, mainopt->source);
|
2001-02-22 11:15:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2000-06-30 12:54:23 +08:00
|
|
|
return 1;
|
2001-02-22 11:15:21 +08:00
|
|
|
}
|
2001-03-08 13:11:16 +08:00
|
|
|
if (prio > OPRIO_ROOT && mainopt->priority == OPRIO_CMDLINE)
|
2001-02-22 11:15:21 +08:00
|
|
|
warn("%s%s from %s overrides command line",
|
|
|
|
opt->name, optopt, option_source);
|
2000-06-30 12:54:23 +08:00
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
|
1999-07-21 08:24:32 +08:00
|
|
|
if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) {
|
2001-02-22 11:15:21 +08:00
|
|
|
option_error("%s%s cannot be changed after initialization",
|
|
|
|
opt->name, optopt);
|
1999-07-21 08:24:32 +08:00
|
|
|
return 0;
|
|
|
|
}
|
1998-11-07 14:59:32 +08:00
|
|
|
if ((opt->flags & OPT_PRIV) && !privileged_option) {
|
2001-02-22 11:15:21 +08:00
|
|
|
option_error("using the %s%s requires root privilege",
|
|
|
|
opt->name, optopt);
|
1998-11-07 14:59:32 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
|
2001-02-22 11:15:21 +08:00
|
|
|
option_error("%s%s is disabled", opt->name, optopt);
|
1998-11-07 14:59:32 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2001-02-22 11:15:21 +08:00
|
|
|
if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
|
|
|
|
option_error("the %s%s may not be changed in %s",
|
|
|
|
opt->name, optopt, option_source);
|
|
|
|
return 0;
|
1999-03-12 14:07:24 +08:00
|
|
|
}
|
1998-11-07 14:59:32 +08:00
|
|
|
|
|
|
|
switch (opt->type) {
|
|
|
|
case o_bool:
|
|
|
|
v = opt->flags & OPT_VALUE;
|
|
|
|
*(bool *)(opt->addr) = v;
|
|
|
|
if (opt->addr2 && (opt->flags & OPT_A2COPY))
|
|
|
|
*(bool *)(opt->addr2) = v;
|
2002-03-01 22:39:19 +08:00
|
|
|
else if (opt->addr2 && (opt->flags & OPT_A2CLR))
|
|
|
|
*(bool *)(opt->addr2) = 0;
|
|
|
|
else if (opt->addr2 && (opt->flags & OPT_A2CLRB))
|
|
|
|
*(u_char *)(opt->addr2) &= ~v;
|
2002-04-02 21:55:00 +08:00
|
|
|
else if (opt->addr2 && (opt->flags & OPT_A2OR))
|
|
|
|
*(u_char *)(opt->addr2) |= v;
|
1998-11-07 14:59:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case o_int:
|
|
|
|
iv = 0;
|
|
|
|
if ((opt->flags & OPT_NOARG) == 0) {
|
|
|
|
if (!int_option(*argv, &iv))
|
|
|
|
return 0;
|
|
|
|
if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
|
|
|
|
|| ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
|
|
|
|
&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
|
|
|
|
char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
|
|
|
|
switch (opt->flags & OPT_LIMITS) {
|
|
|
|
case OPT_LLIMIT:
|
|
|
|
option_error("%s value must be%s >= %d",
|
|
|
|
opt->name, zok, opt->lower_limit);
|
|
|
|
break;
|
|
|
|
case OPT_ULIMIT:
|
|
|
|
option_error("%s value must be%s <= %d",
|
|
|
|
opt->name, zok, opt->upper_limit);
|
|
|
|
break;
|
|
|
|
case OPT_LIMITS:
|
|
|
|
option_error("%s value must be%s between %d and %d",
|
2002-09-14 16:05:27 +08:00
|
|
|
opt->name, zok, opt->lower_limit, opt->upper_limit);
|
1998-11-07 14:59:32 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a = opt->flags & OPT_VALUE;
|
|
|
|
if (a >= 128)
|
|
|
|
a -= 256; /* sign extend */
|
|
|
|
iv += a;
|
|
|
|
if (opt->flags & OPT_INC)
|
|
|
|
iv += *(int *)(opt->addr);
|
|
|
|
if ((opt->flags & OPT_NOINCR) && !privileged_option) {
|
|
|
|
int oldv = *(int *)(opt->addr);
|
|
|
|
if ((opt->flags & OPT_ZEROINF) ?
|
|
|
|
(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
|
|
|
|
option_error("%s value cannot be increased", opt->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*(int *)(opt->addr) = iv;
|
|
|
|
if (opt->addr2 && (opt->flags & OPT_A2COPY))
|
|
|
|
*(int *)(opt->addr2) = iv;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case o_uint32:
|
|
|
|
if (opt->flags & OPT_NOARG) {
|
|
|
|
v = opt->flags & OPT_VALUE;
|
2001-03-08 13:11:16 +08:00
|
|
|
if (v & 0x80)
|
|
|
|
v |= 0xffffff00U;
|
1998-11-07 14:59:32 +08:00
|
|
|
} else if (!number_option(*argv, &v, 16))
|
|
|
|
return 0;
|
|
|
|
if (opt->flags & OPT_OR)
|
|
|
|
v |= *(u_int32_t *)(opt->addr);
|
|
|
|
*(u_int32_t *)(opt->addr) = v;
|
|
|
|
if (opt->addr2 && (opt->flags & OPT_A2COPY))
|
|
|
|
*(u_int32_t *)(opt->addr2) = v;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case o_string:
|
|
|
|
if (opt->flags & OPT_STATIC) {
|
1999-03-19 09:27:43 +08:00
|
|
|
strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
|
1998-11-07 14:59:32 +08:00
|
|
|
} else {
|
2014-08-01 15:32:15 +08:00
|
|
|
char **optptr = (char **)(opt->addr);
|
1998-11-07 14:59:32 +08:00
|
|
|
sv = strdup(*argv);
|
|
|
|
if (sv == NULL)
|
|
|
|
novm("option argument");
|
2014-08-01 15:32:15 +08:00
|
|
|
if (*optptr)
|
|
|
|
free(*optptr);
|
|
|
|
*optptr = sv;
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
2020-03-21 12:13:42 +08:00
|
|
|
/* obfuscate original argument for things like password */
|
|
|
|
if (opt->flags & OPT_HIDE) {
|
|
|
|
memset(*argv, '?', strlen(*argv));
|
|
|
|
*argv = "********";
|
|
|
|
}
|
1998-11-07 14:59:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case o_special_noarg:
|
|
|
|
case o_special:
|
2020-12-29 13:08:24 +08:00
|
|
|
parser = (int (*)(char **)) opt->addr;
|
2010-08-23 21:59:56 +08:00
|
|
|
curopt = opt;
|
1998-11-07 14:59:32 +08:00
|
|
|
if (!(*parser)(argv))
|
|
|
|
return 0;
|
2001-03-08 13:11:16 +08:00
|
|
|
if (opt->flags & OPT_A2LIST) {
|
2008-06-03 20:07:13 +08:00
|
|
|
struct option_value *ovp, *pp;
|
2001-03-08 13:11:16 +08:00
|
|
|
|
|
|
|
ovp = malloc(sizeof(*ovp) + strlen(*argv));
|
|
|
|
if (ovp != 0) {
|
|
|
|
strcpy(ovp->value, *argv);
|
|
|
|
ovp->source = option_source;
|
|
|
|
ovp->next = NULL;
|
2008-06-03 20:07:13 +08:00
|
|
|
if (opt->addr2 == NULL) {
|
|
|
|
opt->addr2 = ovp;
|
|
|
|
} else {
|
|
|
|
for (pp = opt->addr2; pp->next != NULL; pp = pp->next)
|
|
|
|
;
|
|
|
|
pp->next = ovp;
|
|
|
|
}
|
2001-03-08 13:11:16 +08:00
|
|
|
}
|
|
|
|
}
|
1998-11-07 14:59:32 +08:00
|
|
|
break;
|
|
|
|
|
2001-02-22 11:15:21 +08:00
|
|
|
case o_wild:
|
2020-12-29 13:08:24 +08:00
|
|
|
wildp = (int (*)(char *, char **, int)) opt->addr;
|
2001-02-22 11:15:21 +08:00
|
|
|
if (!(*wildp)(cmd, argv, 1))
|
|
|
|
return 0;
|
|
|
|
break;
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
|
|
|
|
2008-06-15 14:53:06 +08:00
|
|
|
/*
|
|
|
|
* If addr2 wasn't used by any flag (OPT_A2COPY, etc.) but is set,
|
|
|
|
* treat it as a bool and set/clear it based on the OPT_A2CLR bit.
|
|
|
|
*/
|
2001-03-08 13:11:16 +08:00
|
|
|
if (opt->addr2 && (opt->flags & (OPT_A2COPY|OPT_ENABLE
|
2002-04-02 21:55:00 +08:00
|
|
|
|OPT_A2PRINTER|OPT_A2STRVAL|OPT_A2LIST|OPT_A2OR)) == 0)
|
2001-03-08 13:11:16 +08:00
|
|
|
*(bool *)(opt->addr2) = !(opt->flags & OPT_A2CLR);
|
2001-02-22 11:15:21 +08:00
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
mainopt->source = option_source;
|
|
|
|
mainopt->priority = prio;
|
|
|
|
mainopt->winner = opt - mainopt;
|
2001-02-22 11:15:21 +08:00
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
/*
|
|
|
|
* override_value - if the option priorities would permit us to
|
|
|
|
* override the value of option, return 1 and update the priority
|
|
|
|
* and source of the option value. Otherwise returns 0.
|
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
override_value(char *option, int priority, const char *source)
|
2001-03-08 13:11:16 +08:00
|
|
|
{
|
|
|
|
option_t *opt;
|
|
|
|
|
|
|
|
opt = find_option(option);
|
|
|
|
if (opt == NULL)
|
|
|
|
return 0;
|
|
|
|
while (opt->flags & OPT_PRIOSUB)
|
|
|
|
--opt;
|
|
|
|
if ((opt->flags & OPT_PRIO) && priority < opt->priority)
|
|
|
|
return 0;
|
|
|
|
opt->priority = priority;
|
|
|
|
opt->source = source;
|
|
|
|
opt->winner = -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
/*
|
|
|
|
* n_arguments - tell how many arguments an option takes
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
n_arguments(option_t *opt)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
2001-02-22 11:15:21 +08:00
|
|
|
return (opt->type == o_bool || opt->type == o_special_noarg
|
|
|
|
|| (opt->flags & OPT_NOARG))? 0: 1;
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
|
|
|
|
1999-09-11 20:09:00 +08:00
|
|
|
/*
|
|
|
|
* add_options - add a list of options to the set we grok.
|
|
|
|
*/
|
|
|
|
void
|
2020-12-29 13:08:24 +08:00
|
|
|
add_options(option_t *opt)
|
1999-09-11 20:09:00 +08:00
|
|
|
{
|
|
|
|
struct option_list *list;
|
|
|
|
|
|
|
|
list = malloc(sizeof(*list));
|
|
|
|
if (list == 0)
|
|
|
|
novm("option list entry");
|
|
|
|
list->options = opt;
|
|
|
|
list->next = extra_options;
|
|
|
|
extra_options = list;
|
|
|
|
}
|
|
|
|
|
2001-03-08 13:11:16 +08:00
|
|
|
/*
|
|
|
|
* check_options - check that options are valid and consistent.
|
|
|
|
*/
|
|
|
|
void
|
2020-12-29 13:08:24 +08:00
|
|
|
check_options(void)
|
2001-03-08 13:11:16 +08:00
|
|
|
{
|
|
|
|
if (logfile_fd >= 0 && logfile_fd != log_to_fd)
|
|
|
|
close(logfile_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print_option - print out an option and its value
|
|
|
|
*/
|
|
|
|
static void
|
2020-12-29 13:08:24 +08:00
|
|
|
print_option(option_t *opt, option_t *mainopt, printer_func printer, void *arg)
|
2001-03-08 13:11:16 +08:00
|
|
|
{
|
|
|
|
int i, v;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (opt->flags & OPT_NOPRINT)
|
|
|
|
return;
|
|
|
|
switch (opt->type) {
|
|
|
|
case o_bool:
|
|
|
|
v = opt->flags & OPT_VALUE;
|
|
|
|
if (*(bool *)opt->addr != v)
|
2001-03-13 06:56:12 +08:00
|
|
|
/* this can happen legitimately, e.g. lock
|
|
|
|
option turned off for default device */
|
|
|
|
break;
|
2001-03-08 13:11:16 +08:00
|
|
|
printer(arg, "%s", opt->name);
|
|
|
|
break;
|
|
|
|
case o_int:
|
|
|
|
v = opt->flags & OPT_VALUE;
|
|
|
|
if (v >= 128)
|
|
|
|
v -= 256;
|
|
|
|
i = *(int *)opt->addr;
|
|
|
|
if (opt->flags & OPT_NOARG) {
|
|
|
|
printer(arg, "%s", opt->name);
|
|
|
|
if (i != v) {
|
|
|
|
if (opt->flags & OPT_INC) {
|
|
|
|
for (; i > v; i -= v)
|
|
|
|
printer(arg, " %s", opt->name);
|
|
|
|
} else
|
|
|
|
printer(arg, " # oops: %d not %d\n",
|
|
|
|
i, v);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printer(arg, "%s %d", opt->name, i);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case o_uint32:
|
|
|
|
printer(arg, "%s", opt->name);
|
|
|
|
if ((opt->flags & OPT_NOARG) == 0)
|
|
|
|
printer(arg, " %x", *(u_int32_t *)opt->addr);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case o_string:
|
|
|
|
if (opt->flags & OPT_HIDE) {
|
|
|
|
p = "??????";
|
|
|
|
} else {
|
|
|
|
p = (char *) opt->addr;
|
|
|
|
if ((opt->flags & OPT_STATIC) == 0)
|
|
|
|
p = *(char **)p;
|
|
|
|
}
|
|
|
|
printer(arg, "%s %q", opt->name, p);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case o_special:
|
|
|
|
case o_special_noarg:
|
|
|
|
case o_wild:
|
|
|
|
if (opt->type != o_wild) {
|
|
|
|
printer(arg, "%s", opt->name);
|
|
|
|
if (n_arguments(opt) == 0)
|
|
|
|
break;
|
|
|
|
printer(arg, " ");
|
|
|
|
}
|
|
|
|
if (opt->flags & OPT_A2PRINTER) {
|
2020-12-29 13:08:24 +08:00
|
|
|
void (*oprt)(option_t *, printer_func, void *);
|
|
|
|
oprt = (void (*)(option_t *, printer_func, void *))
|
|
|
|
opt->addr2;
|
2001-03-08 13:11:16 +08:00
|
|
|
(*oprt)(opt, printer, arg);
|
|
|
|
} else if (opt->flags & OPT_A2STRVAL) {
|
|
|
|
p = (char *) opt->addr2;
|
|
|
|
if ((opt->flags & OPT_STATIC) == 0)
|
|
|
|
p = *(char **)p;
|
2018-06-13 18:38:53 +08:00
|
|
|
printer(arg, "%q", p);
|
2001-03-08 13:11:16 +08:00
|
|
|
} else if (opt->flags & OPT_A2LIST) {
|
|
|
|
struct option_value *ovp;
|
|
|
|
|
|
|
|
ovp = (struct option_value *) opt->addr2;
|
|
|
|
for (;;) {
|
|
|
|
printer(arg, "%q", ovp->value);
|
|
|
|
if ((ovp = ovp->next) == NULL)
|
|
|
|
break;
|
|
|
|
printer(arg, "\t\t# (from %s)\n%s ",
|
|
|
|
ovp->source, opt->name);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
printer(arg, "xxx # [don't know how to print value]");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2002-07-13 14:24:36 +08:00
|
|
|
printer(arg, "# %s value (type %d\?\?)", opt->name, opt->type);
|
2001-03-08 13:11:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
printer(arg, "\t\t# (from %s)\n", mainopt->source);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print_option_list - print out options in effect from an
|
|
|
|
* array of options.
|
|
|
|
*/
|
|
|
|
static void
|
2020-12-29 13:08:24 +08:00
|
|
|
print_option_list(option_t *opt, printer_func printer, void *arg)
|
2001-03-08 13:11:16 +08:00
|
|
|
{
|
|
|
|
while (opt->name != NULL) {
|
|
|
|
if (opt->priority != OPRIO_DEFAULT
|
|
|
|
&& opt->winner != (short int) -1)
|
|
|
|
print_option(opt + opt->winner, opt, printer, arg);
|
|
|
|
do {
|
|
|
|
++opt;
|
|
|
|
} while (opt->flags & OPT_PRIOSUB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* print_options - print out what options are in effect.
|
|
|
|
*/
|
|
|
|
void
|
2020-12-29 13:08:24 +08:00
|
|
|
print_options(printer_func printer, void *arg)
|
2001-03-08 13:11:16 +08:00
|
|
|
{
|
|
|
|
struct option_list *list;
|
|
|
|
int i;
|
|
|
|
|
2001-03-13 06:56:12 +08:00
|
|
|
printer(arg, "pppd options in effect:\n");
|
2001-03-08 13:11:16 +08:00
|
|
|
print_option_list(general_options, printer, arg);
|
|
|
|
print_option_list(auth_options, printer, arg);
|
|
|
|
for (list = extra_options; list != NULL; list = list->next)
|
|
|
|
print_option_list(list->options, printer, arg);
|
|
|
|
print_option_list(the_channel->options, printer, arg);
|
|
|
|
for (i = 0; protocols[i] != NULL; ++i)
|
|
|
|
print_option_list(protocols[i]->options, printer, arg);
|
|
|
|
}
|
|
|
|
|
1998-11-07 14:59:32 +08:00
|
|
|
/*
|
|
|
|
* usage - print out a message telling how to use the program.
|
|
|
|
*/
|
1999-03-19 09:27:43 +08:00
|
|
|
static void
|
2020-12-29 13:08:24 +08:00
|
|
|
usage(void)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
|
|
|
if (phase == PHASE_INITIALIZE)
|
2001-03-08 13:11:16 +08:00
|
|
|
fprintf(stderr, usage_string, VERSION, progname);
|
1998-11-07 14:59:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* showhelp - print out usage message and exit.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
showhelp(char **argv)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
|
|
|
if (phase == PHASE_INITIALIZE) {
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* showversion - print out the version number and exit.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
showversion(char **argv)
|
1998-11-07 14:59:32 +08:00
|
|
|
{
|
|
|
|
if (phase == PHASE_INITIALIZE) {
|
2020-03-21 14:42:47 +08:00
|
|
|
fprintf(stdout, "pppd version %s\n", VERSION);
|
1998-11-07 14:59:32 +08:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1996-05-27 08:04:47 +08:00
|
|
|
/*
|
|
|
|
* option_error - print a message about an error in an option.
|
|
|
|
* The message is logged, and also sent to
|
|
|
|
* stderr if phase == PHASE_INITIALIZE.
|
|
|
|
*/
|
|
|
|
void
|
2020-12-29 13:08:24 +08:00
|
|
|
option_error(char *fmt, ...)
|
1996-05-27 08:04:47 +08:00
|
|
|
{
|
|
|
|
va_list args;
|
2000-12-28 07:25:55 +08:00
|
|
|
char buf[1024];
|
1996-05-27 08:04:47 +08:00
|
|
|
|
|
|
|
va_start(args, fmt);
|
1999-03-12 14:07:24 +08:00
|
|
|
vslprintf(buf, sizeof(buf), fmt, args);
|
1996-05-27 08:04:47 +08:00
|
|
|
va_end(args);
|
|
|
|
if (phase == PHASE_INITIALIZE)
|
|
|
|
fprintf(stderr, "%s: %s\n", progname, buf);
|
|
|
|
syslog(LOG_ERR, "%s", buf);
|
|
|
|
}
|
|
|
|
|
1999-03-19 09:27:43 +08:00
|
|
|
#if 0
|
1994-05-18 14:34:15 +08:00
|
|
|
/*
|
|
|
|
* readable - check if a file is readable by the real user.
|
|
|
|
*/
|
1999-02-26 19:03:34 +08:00
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
readable(int fd)
|
1994-05-18 14:34:15 +08:00
|
|
|
{
|
1999-03-06 19:28:11 +08:00
|
|
|
uid_t uid;
|
1999-03-12 14:07:24 +08:00
|
|
|
int i;
|
1994-05-18 14:34:15 +08:00
|
|
|
struct stat sbuf;
|
|
|
|
|
1999-03-06 19:28:11 +08:00
|
|
|
uid = getuid();
|
1994-05-18 14:34:15 +08:00
|
|
|
if (uid == 0)
|
|
|
|
return 1;
|
|
|
|
if (fstat(fd, &sbuf) != 0)
|
|
|
|
return 0;
|
|
|
|
if (sbuf.st_uid == uid)
|
|
|
|
return sbuf.st_mode & S_IRUSR;
|
|
|
|
if (sbuf.st_gid == getgid())
|
|
|
|
return sbuf.st_mode & S_IRGRP;
|
|
|
|
for (i = 0; i < ngroups; ++i)
|
|
|
|
if (sbuf.st_gid == groups[i])
|
|
|
|
return sbuf.st_mode & S_IRGRP;
|
|
|
|
return sbuf.st_mode & S_IROTH;
|
|
|
|
}
|
1999-03-19 09:27:43 +08:00
|
|
|
#endif
|
1994-05-18 14:34:15 +08:00
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
|
|
|
* Read a word from a file.
|
1995-06-12 20:02:25 +08:00
|
|
|
* Words are delimited by white-space or by quotes (" or ').
|
1993-11-11 11:56:47 +08:00
|
|
|
* Quotes, white-space and \ may be escaped with \.
|
|
|
|
* \<newline> is ignored.
|
|
|
|
*/
|
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
getword(FILE *f, char *word, int *newlinep, char *filename)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
|
|
|
int c, len, escape;
|
1995-06-12 19:22:55 +08:00
|
|
|
int quoted, comment;
|
|
|
|
int value, digit, got, n;
|
|
|
|
|
|
|
|
#define isoctal(c) ((c) >= '0' && (c) < '8')
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
*newlinep = 0;
|
|
|
|
len = 0;
|
|
|
|
escape = 0;
|
1995-06-12 19:22:55 +08:00
|
|
|
comment = 0;
|
2010-08-23 22:03:07 +08:00
|
|
|
quoted = 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
/*
|
1995-06-12 19:22:55 +08:00
|
|
|
* First skip white-space and comments.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
1995-06-12 19:22:55 +08:00
|
|
|
for (;;) {
|
|
|
|
c = getc(f);
|
|
|
|
if (c == EOF)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A newline means the end of a comment; backslash-newline
|
|
|
|
* is ignored. Note that we cannot have escape && comment.
|
|
|
|
*/
|
|
|
|
if (c == '\n') {
|
|
|
|
if (!escape) {
|
|
|
|
*newlinep = 1;
|
|
|
|
comment = 0;
|
|
|
|
} else
|
|
|
|
escape = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ignore characters other than newline in a comment.
|
|
|
|
*/
|
|
|
|
if (comment)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this character is escaped, we have a word start.
|
|
|
|
*/
|
|
|
|
if (escape)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is the escape character, look at the next character.
|
|
|
|
*/
|
1993-11-11 11:56:47 +08:00
|
|
|
if (c == '\\') {
|
1995-06-12 19:22:55 +08:00
|
|
|
escape = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is the start of a comment, ignore the rest of the line.
|
|
|
|
*/
|
|
|
|
if (c == '#') {
|
|
|
|
comment = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A non-whitespace character is the start of a word.
|
|
|
|
*/
|
|
|
|
if (!isspace(c))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process characters until the end of the word.
|
|
|
|
*/
|
|
|
|
while (c != EOF) {
|
|
|
|
if (escape) {
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
1995-06-12 19:22:55 +08:00
|
|
|
* This character is escaped: backslash-newline is ignored,
|
|
|
|
* various other characters indicate particular values
|
|
|
|
* as for C backslash-escapes.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
1995-06-12 19:22:55 +08:00
|
|
|
escape = 0;
|
|
|
|
if (c == '\n') {
|
|
|
|
c = getc(f);
|
1993-11-11 11:56:47 +08:00
|
|
|
continue;
|
1995-06-12 19:22:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
got = 0;
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
value = '\a';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
value = '\b';
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
value = '\f';
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
value = '\n';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
value = '\r';
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
value = ' ';
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
value = '\t';
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (isoctal(c)) {
|
|
|
|
/*
|
|
|
|
* \ddd octal sequence
|
|
|
|
*/
|
|
|
|
value = 0;
|
|
|
|
for (n = 0; n < 3 && isoctal(c); ++n) {
|
|
|
|
value = (value << 3) + (c & 07);
|
|
|
|
c = getc(f);
|
|
|
|
}
|
|
|
|
got = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == 'x') {
|
|
|
|
/*
|
|
|
|
* \x<hex_string> sequence
|
|
|
|
*/
|
|
|
|
value = 0;
|
|
|
|
c = getc(f);
|
|
|
|
for (n = 0; n < 2 && isxdigit(c); ++n) {
|
|
|
|
digit = toupper(c) - '0';
|
|
|
|
if (digit > 10)
|
|
|
|
digit += '0' + 10 - 'A';
|
|
|
|
value = (value << 4) + digit;
|
|
|
|
c = getc (f);
|
|
|
|
}
|
|
|
|
got = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise the character stands for itself.
|
|
|
|
*/
|
|
|
|
value = c;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store the resulting character for the escape sequence.
|
|
|
|
*/
|
2014-08-01 14:05:42 +08:00
|
|
|
if (len < MAXWORDLEN) {
|
1995-06-12 19:22:55 +08:00
|
|
|
word[len] = value;
|
2014-08-01 14:05:42 +08:00
|
|
|
++len;
|
|
|
|
}
|
1995-06-12 19:22:55 +08:00
|
|
|
|
|
|
|
if (!got)
|
|
|
|
c = getc(f);
|
|
|
|
continue;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
1995-06-12 19:22:55 +08:00
|
|
|
|
|
|
|
/*
|
2010-08-23 22:03:07 +08:00
|
|
|
* Backslash starts a new escape sequence.
|
1995-06-12 19:22:55 +08:00
|
|
|
*/
|
2010-08-23 22:03:07 +08:00
|
|
|
if (c == '\\') {
|
|
|
|
escape = 1;
|
|
|
|
c = getc(f);
|
|
|
|
continue;
|
1995-06-12 19:22:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-08-23 22:03:07 +08:00
|
|
|
* Not escaped: check for the start or end of a quoted
|
|
|
|
* section and see if we've reached the end of the word.
|
1995-06-12 19:22:55 +08:00
|
|
|
*/
|
2010-08-23 22:03:07 +08:00
|
|
|
if (quoted) {
|
|
|
|
if (c == quoted) {
|
|
|
|
quoted = 0;
|
|
|
|
c = getc(f);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (c == '"' || c == '\'') {
|
|
|
|
quoted = c;
|
1995-06-12 19:22:55 +08:00
|
|
|
c = getc(f);
|
|
|
|
continue;
|
2010-08-23 22:03:07 +08:00
|
|
|
} else if (isspace(c) || c == '#') {
|
|
|
|
ungetc (c, f);
|
|
|
|
break;
|
1995-06-12 19:22:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An ordinary character: store it in the word and get another.
|
|
|
|
*/
|
2014-08-01 14:05:42 +08:00
|
|
|
if (len < MAXWORDLEN) {
|
1995-06-12 19:22:55 +08:00
|
|
|
word[len] = c;
|
2014-08-01 14:05:42 +08:00
|
|
|
++len;
|
|
|
|
}
|
1995-06-12 19:22:55 +08:00
|
|
|
|
|
|
|
c = getc(f);
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
2019-12-30 06:32:18 +08:00
|
|
|
word[MAXWORDLEN-1] = 0; /* make sure word is null-terminated */
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
/*
|
1995-06-12 19:22:55 +08:00
|
|
|
* End of the word: check for errors.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
|
|
|
if (c == EOF) {
|
|
|
|
if (ferror(f)) {
|
1995-06-12 19:22:55 +08:00
|
|
|
if (errno == 0)
|
|
|
|
errno = EIO;
|
1996-05-27 08:04:47 +08:00
|
|
|
option_error("Error reading %s: %m", filename);
|
1993-11-11 11:56:47 +08:00
|
|
|
die(1);
|
|
|
|
}
|
|
|
|
/*
|
1995-06-12 19:22:55 +08:00
|
|
|
* If len is zero, then we didn't find a word before the
|
|
|
|
* end of the file.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
1995-06-12 19:22:55 +08:00
|
|
|
if (len == 0)
|
|
|
|
return 0;
|
2010-08-23 22:03:07 +08:00
|
|
|
if (quoted)
|
|
|
|
option_error("warning: quoted word runs to end of file (%.20s...)",
|
|
|
|
filename, word);
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
|
|
|
|
1995-06-12 19:22:55 +08:00
|
|
|
/*
|
|
|
|
* Warn if the word was too long, and append a terminating null.
|
|
|
|
*/
|
1993-11-11 11:56:47 +08:00
|
|
|
if (len >= MAXWORDLEN) {
|
1996-05-27 08:04:47 +08:00
|
|
|
option_error("warning: word in file %s too long (%.20s...)",
|
|
|
|
filename, word);
|
1995-06-12 19:22:55 +08:00
|
|
|
len = MAXWORDLEN - 1;
|
|
|
|
}
|
|
|
|
word[len] = 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
return 1;
|
1995-06-12 19:22:55 +08:00
|
|
|
|
|
|
|
#undef isoctal
|
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1995-06-12 20:02:25 +08:00
|
|
|
* number_option - parse an unsigned numeric parameter for an option.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
1999-03-19 09:27:43 +08:00
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
number_option(char *str, u_int32_t *valp, int base)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
|
|
|
char *ptr;
|
|
|
|
|
1995-06-12 20:02:25 +08:00
|
|
|
*valp = strtoul(str, &ptr, base);
|
1993-11-11 11:56:47 +08:00
|
|
|
if (ptr == str) {
|
1996-05-27 08:04:47 +08:00
|
|
|
option_error("invalid numeric parameter '%s' for %s option",
|
|
|
|
str, current_option);
|
1993-11-11 11:56:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* int_option - like number_option, but valp is int *,
|
|
|
|
* the base is assumed to be 0, and *valp is not changed
|
|
|
|
* if there is an error.
|
|
|
|
*/
|
1998-11-07 14:59:32 +08:00
|
|
|
int
|
2020-12-29 13:08:24 +08:00
|
|
|
int_option(char *str, int *valp)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
1995-06-12 20:02:25 +08:00
|
|
|
u_int32_t v;
|
1993-11-11 11:56:47 +08:00
|
|
|
|
|
|
|
if (!number_option(str, &v, 0))
|
|
|
|
return 0;
|
|
|
|
*valp = (int) v;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
1996-05-27 08:04:47 +08:00
|
|
|
* The following procedures parse options.
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* readfile - take commands from a file.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
readfile(char **argv)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
1996-08-28 14:41:35 +08:00
|
|
|
return options_from_file(*argv, 1, 1, privileged_option);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* callfile - take commands from /etc/ppp/peers/<name>.
|
|
|
|
* Name may not contain /../, start with / or ../, or end in /..
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
callfile(char **argv)
|
1996-08-28 14:41:35 +08:00
|
|
|
{
|
|
|
|
char *fname, *arg, *p;
|
|
|
|
int l, ok;
|
|
|
|
|
|
|
|
arg = *argv;
|
|
|
|
ok = 1;
|
|
|
|
if (arg[0] == '/' || arg[0] == 0)
|
|
|
|
ok = 0;
|
|
|
|
else {
|
|
|
|
for (p = arg; *p != 0; ) {
|
|
|
|
if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
|
|
|
|
ok = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (*p != '/' && *p != 0)
|
|
|
|
++p;
|
|
|
|
if (*p == '/')
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ok) {
|
|
|
|
option_error("call option value may not contain .. or start with /");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
|
|
|
|
if ((fname = (char *) malloc(l)) == NULL)
|
|
|
|
novm("call file name");
|
1999-03-12 14:07:24 +08:00
|
|
|
slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
|
2020-12-31 12:50:46 +08:00
|
|
|
script_setenv("CALL_FILE", arg, 0);
|
1996-08-28 14:41:35 +08:00
|
|
|
|
|
|
|
ok = options_from_file(fname, 1, 1, 1);
|
|
|
|
|
|
|
|
free(fname);
|
|
|
|
return ok;
|
1993-11-11 11:56:47 +08:00
|
|
|
}
|
|
|
|
|
1997-04-30 13:55:54 +08:00
|
|
|
#ifdef PPP_FILTER
|
|
|
|
/*
|
|
|
|
* setpassfilter - Set the pass filter for packets
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
setpassfilter(char **argv)
|
1997-04-30 13:55:54 +08:00
|
|
|
{
|
2004-10-28 08:15:08 +08:00
|
|
|
pcap_t *pc;
|
2005-07-09 12:58:36 +08:00
|
|
|
int ret = 1;
|
2004-10-28 08:15:08 +08:00
|
|
|
|
2005-07-13 20:31:36 +08:00
|
|
|
pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
|
2004-10-28 08:15:08 +08:00
|
|
|
if (pcap_compile(pc, &pass_filter, *argv, 1, netmask) == -1) {
|
|
|
|
option_error("error in pass-filter expression: %s\n",
|
|
|
|
pcap_geterr(pc));
|
2005-07-09 12:58:36 +08:00
|
|
|
ret = 0;
|
2004-10-28 08:15:08 +08:00
|
|
|
}
|
|
|
|
pcap_close(pc);
|
|
|
|
|
|
|
|
return ret;
|
1997-04-30 13:55:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setactivefilter - Set the active filter for packets
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
setactivefilter(char **argv)
|
1997-04-30 13:55:54 +08:00
|
|
|
{
|
2004-10-28 08:15:08 +08:00
|
|
|
pcap_t *pc;
|
2005-07-09 12:58:36 +08:00
|
|
|
int ret = 1;
|
2004-10-28 08:15:08 +08:00
|
|
|
|
2005-07-13 20:31:36 +08:00
|
|
|
pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
|
2004-10-28 08:15:08 +08:00
|
|
|
if (pcap_compile(pc, &active_filter, *argv, 1, netmask) == -1) {
|
|
|
|
option_error("error in active-filter expression: %s\n",
|
|
|
|
pcap_geterr(pc));
|
2005-07-09 12:58:36 +08:00
|
|
|
ret = 0;
|
2004-10-28 08:15:08 +08:00
|
|
|
}
|
|
|
|
pcap_close(pc);
|
|
|
|
|
|
|
|
return ret;
|
1997-04-30 13:55:54 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1993-11-11 11:56:47 +08:00
|
|
|
/*
|
1998-11-07 14:59:32 +08:00
|
|
|
* setdomain - Set domain name to append to hostname
|
1993-11-11 11:56:47 +08:00
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
setdomain(char **argv)
|
1993-11-11 11:56:47 +08:00
|
|
|
{
|
1998-11-07 14:59:32 +08:00
|
|
|
gethostname(hostname, MAXNAMELEN);
|
|
|
|
if (**argv != 0) {
|
|
|
|
if (**argv != '.')
|
|
|
|
strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
|
2001-03-08 13:11:16 +08:00
|
|
|
domain = hostname + strlen(hostname);
|
1998-11-07 14:59:32 +08:00
|
|
|
strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
|
|
|
|
}
|
|
|
|
hostname[MAXNAMELEN-1] = 0;
|
1993-11-11 11:56:47 +08:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
1999-07-21 08:24:32 +08:00
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
setlogfile(char **argv)
|
1999-07-21 08:24:32 +08:00
|
|
|
{
|
|
|
|
int fd, err;
|
2006-06-18 19:26:00 +08:00
|
|
|
uid_t euid;
|
1999-07-21 08:24:32 +08:00
|
|
|
|
2006-06-18 19:26:00 +08:00
|
|
|
euid = geteuid();
|
2006-06-04 15:04:57 +08:00
|
|
|
if (!privileged_option && seteuid(getuid()) == -1) {
|
|
|
|
option_error("unable to drop permissions to open %s: %m", *argv);
|
|
|
|
return 0;
|
|
|
|
}
|
1999-11-15 11:55:37 +08:00
|
|
|
fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
|
|
|
|
if (fd < 0 && errno == EEXIST)
|
|
|
|
fd = open(*argv, O_WRONLY | O_APPEND);
|
1999-07-21 08:24:32 +08:00
|
|
|
err = errno;
|
2006-06-18 19:26:00 +08:00
|
|
|
if (!privileged_option && seteuid(euid) == -1)
|
2006-06-04 15:04:57 +08:00
|
|
|
fatal("unable to regain privileges: %m");
|
1999-07-21 08:24:32 +08:00
|
|
|
if (fd < 0) {
|
|
|
|
errno = err;
|
|
|
|
option_error("Can't open log file %s: %m", *argv);
|
|
|
|
return 0;
|
|
|
|
}
|
2001-03-08 13:11:16 +08:00
|
|
|
strlcpy(logfile_name, *argv, sizeof(logfile_name));
|
|
|
|
if (logfile_fd >= 0)
|
|
|
|
close(logfile_fd);
|
|
|
|
logfile_fd = fd;
|
1999-07-21 08:24:32 +08:00
|
|
|
log_to_fd = fd;
|
2001-03-08 13:11:16 +08:00
|
|
|
log_default = 0;
|
1999-07-21 08:24:32 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2003-03-03 13:11:46 +08:00
|
|
|
|
2002-07-13 14:24:36 +08:00
|
|
|
#ifdef MAXOCTETS
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
setmodir(char **argv)
|
2002-07-13 14:24:36 +08:00
|
|
|
{
|
|
|
|
if(*argv == NULL)
|
|
|
|
return 0;
|
|
|
|
if(!strcmp(*argv,"in")) {
|
|
|
|
maxoctets_dir = PPP_OCTETS_DIRECTION_IN;
|
|
|
|
} else if (!strcmp(*argv,"out")) {
|
|
|
|
maxoctets_dir = PPP_OCTETS_DIRECTION_OUT;
|
|
|
|
} else if (!strcmp(*argv,"max")) {
|
2002-07-18 23:25:04 +08:00
|
|
|
maxoctets_dir = PPP_OCTETS_DIRECTION_MAXOVERAL;
|
2002-07-13 14:24:36 +08:00
|
|
|
} else {
|
|
|
|
maxoctets_dir = PPP_OCTETS_DIRECTION_SUM;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
1999-09-11 20:09:00 +08:00
|
|
|
|
|
|
|
#ifdef PLUGIN
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
loadplugin(char **argv)
|
1999-09-11 20:09:00 +08:00
|
|
|
{
|
|
|
|
char *arg = *argv;
|
|
|
|
void *handle;
|
|
|
|
const char *err;
|
2020-12-29 13:08:24 +08:00
|
|
|
void (*init)(void);
|
2001-03-08 13:11:16 +08:00
|
|
|
char *path = arg;
|
|
|
|
const char *vers;
|
|
|
|
|
|
|
|
if (strchr(arg, '/') == 0) {
|
|
|
|
const char *base = _PATH_PLUGIN;
|
|
|
|
int l = strlen(base) + strlen(arg) + 2;
|
|
|
|
path = malloc(l);
|
|
|
|
if (path == 0)
|
|
|
|
novm("plugin file path");
|
|
|
|
strlcpy(path, base, l);
|
|
|
|
strlcat(path, "/", l);
|
|
|
|
strlcat(path, arg, l);
|
|
|
|
}
|
|
|
|
handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
|
1999-09-11 20:09:00 +08:00
|
|
|
if (handle == 0) {
|
|
|
|
err = dlerror();
|
|
|
|
if (err != 0)
|
|
|
|
option_error("%s", err);
|
|
|
|
option_error("Couldn't load plugin %s", arg);
|
2001-03-08 13:11:16 +08:00
|
|
|
goto err;
|
1999-09-11 20:09:00 +08:00
|
|
|
}
|
2000-04-15 09:27:13 +08:00
|
|
|
init = (void (*)(void))dlsym(handle, "plugin_init");
|
1999-09-11 20:09:00 +08:00
|
|
|
if (init == 0) {
|
|
|
|
option_error("%s has no initialization entry point", arg);
|
2001-03-08 13:11:16 +08:00
|
|
|
goto errclose;
|
|
|
|
}
|
|
|
|
vers = (const char *) dlsym(handle, "pppd_version");
|
|
|
|
if (vers == 0) {
|
|
|
|
warn("Warning: plugin %s has no version information", arg);
|
|
|
|
} else if (strcmp(vers, VERSION) != 0) {
|
|
|
|
option_error("Plugin %s is for pppd version %s, this is %s",
|
2002-01-12 02:11:51 +08:00
|
|
|
arg, vers, VERSION);
|
2001-03-08 13:11:16 +08:00
|
|
|
goto errclose;
|
1999-09-11 20:09:00 +08:00
|
|
|
}
|
|
|
|
info("Plugin %s loaded.", arg);
|
|
|
|
(*init)();
|
|
|
|
return 1;
|
2001-03-08 13:11:16 +08:00
|
|
|
|
|
|
|
errclose:
|
|
|
|
dlclose(handle);
|
|
|
|
err:
|
|
|
|
if (path != arg)
|
|
|
|
free(path);
|
|
|
|
return 0;
|
1999-09-11 20:09:00 +08:00
|
|
|
}
|
|
|
|
#endif /* PLUGIN */
|
2010-08-23 21:59:56 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set an environment variable specified by the user.
|
|
|
|
*/
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
user_setenv(char **argv)
|
2010-08-23 21:59:56 +08:00
|
|
|
{
|
|
|
|
char *arg = argv[0];
|
|
|
|
char *eqp;
|
|
|
|
struct userenv *uep, **insp;
|
|
|
|
|
|
|
|
if ((eqp = strchr(arg, '=')) == NULL) {
|
|
|
|
option_error("missing = in name=value: %s", arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (eqp == arg) {
|
|
|
|
option_error("missing variable name: %s", arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
|
|
|
|
int nlen = strlen(uep->ue_name);
|
|
|
|
if (nlen == (eqp - arg) &&
|
|
|
|
strncmp(arg, uep->ue_name, nlen) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Ignore attempts by unprivileged users to override privileged sources */
|
|
|
|
if (uep != NULL && !privileged_option && uep->ue_priv)
|
|
|
|
return 1;
|
|
|
|
/* The name never changes, so allocate it with the structure */
|
|
|
|
if (uep == NULL) {
|
|
|
|
uep = malloc(sizeof (*uep) + (eqp-arg));
|
|
|
|
strncpy(uep->ue_name, arg, eqp-arg);
|
|
|
|
uep->ue_name[eqp-arg] = '\0';
|
|
|
|
uep->ue_next = NULL;
|
|
|
|
insp = &userenv_list;
|
|
|
|
while (*insp != NULL)
|
|
|
|
insp = &(*insp)->ue_next;
|
|
|
|
*insp = uep;
|
|
|
|
} else {
|
|
|
|
struct userenv *uep2;
|
|
|
|
for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
|
|
|
|
if (uep2 != uep && !uep2->ue_isset)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (uep2 == NULL && !uep->ue_isset)
|
|
|
|
find_option("unset")->flags |= OPT_NOPRINT;
|
|
|
|
free(uep->ue_value);
|
|
|
|
}
|
|
|
|
uep->ue_isset = 1;
|
|
|
|
uep->ue_priv = privileged_option;
|
|
|
|
uep->ue_source = option_source;
|
|
|
|
uep->ue_value = strdup(eqp + 1);
|
|
|
|
curopt->flags &= ~OPT_NOPRINT;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-12-29 13:08:24 +08:00
|
|
|
user_setprint(option_t *opt, printer_func printer, void *arg)
|
2010-08-23 21:59:56 +08:00
|
|
|
{
|
|
|
|
struct userenv *uep, *uepnext;
|
|
|
|
|
|
|
|
uepnext = userenv_list;
|
|
|
|
while (uepnext != NULL && !uepnext->ue_isset)
|
|
|
|
uepnext = uepnext->ue_next;
|
|
|
|
while ((uep = uepnext) != NULL) {
|
|
|
|
uepnext = uep->ue_next;
|
|
|
|
while (uepnext != NULL && !uepnext->ue_isset)
|
|
|
|
uepnext = uepnext->ue_next;
|
|
|
|
(*printer)(arg, "%s=%s", uep->ue_name, uep->ue_value);
|
|
|
|
if (uepnext != NULL)
|
|
|
|
(*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
|
|
|
|
else
|
|
|
|
opt->source = uep->ue_source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2020-12-29 13:08:24 +08:00
|
|
|
user_unsetenv(char **argv)
|
2010-08-23 21:59:56 +08:00
|
|
|
{
|
|
|
|
struct userenv *uep, **insp;
|
|
|
|
char *arg = argv[0];
|
|
|
|
|
|
|
|
if (strchr(arg, '=') != NULL) {
|
|
|
|
option_error("unexpected = in name: %s", arg);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-23 14:40:27 +08:00
|
|
|
if (*arg == '\0') {
|
2010-08-23 21:59:56 +08:00
|
|
|
option_error("missing variable name for unset");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (uep = userenv_list; uep != NULL; uep = uep->ue_next) {
|
|
|
|
if (strcmp(arg, uep->ue_name) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Ignore attempts by unprivileged users to override privileged sources */
|
|
|
|
if (uep != NULL && !privileged_option && uep->ue_priv)
|
|
|
|
return 1;
|
|
|
|
/* The name never changes, so allocate it with the structure */
|
|
|
|
if (uep == NULL) {
|
|
|
|
uep = malloc(sizeof (*uep) + strlen(arg));
|
|
|
|
strcpy(uep->ue_name, arg);
|
|
|
|
uep->ue_next = NULL;
|
|
|
|
insp = &userenv_list;
|
|
|
|
while (*insp != NULL)
|
|
|
|
insp = &(*insp)->ue_next;
|
|
|
|
*insp = uep;
|
|
|
|
} else {
|
|
|
|
struct userenv *uep2;
|
|
|
|
for (uep2 = userenv_list; uep2 != NULL; uep2 = uep2->ue_next) {
|
|
|
|
if (uep2 != uep && uep2->ue_isset)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (uep2 == NULL && uep->ue_isset)
|
|
|
|
find_option("set")->flags |= OPT_NOPRINT;
|
|
|
|
free(uep->ue_value);
|
|
|
|
}
|
|
|
|
uep->ue_isset = 0;
|
|
|
|
uep->ue_priv = privileged_option;
|
|
|
|
uep->ue_source = option_source;
|
|
|
|
uep->ue_value = NULL;
|
|
|
|
curopt->flags &= ~OPT_NOPRINT;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-12-29 13:08:24 +08:00
|
|
|
user_unsetprint(option_t *opt, printer_func printer, void *arg)
|
2010-08-23 21:59:56 +08:00
|
|
|
{
|
|
|
|
struct userenv *uep, *uepnext;
|
|
|
|
|
|
|
|
uepnext = userenv_list;
|
|
|
|
while (uepnext != NULL && uepnext->ue_isset)
|
|
|
|
uepnext = uepnext->ue_next;
|
|
|
|
while ((uep = uepnext) != NULL) {
|
|
|
|
uepnext = uep->ue_next;
|
|
|
|
while (uepnext != NULL && uepnext->ue_isset)
|
|
|
|
uepnext = uepnext->ue_next;
|
|
|
|
(*printer)(arg, "%s", uep->ue_name);
|
|
|
|
if (uepnext != NULL)
|
|
|
|
(*printer)(arg, "\t\t# (from %s)\n%s ", uep->ue_source, opt->name);
|
|
|
|
else
|
|
|
|
opt->source = uep->ue_source;
|
|
|
|
}
|
|
|
|
}
|