From a4efaa63e68e25e712af030a138a272dfe0d2180 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 21 Jul 1999 00:24:32 +0000 Subject: [PATCH] allow options in secrets files only disable holdoff if link terminated by idle timer open all network protos on callback add init and logfile options document various options --- pppd/auth.c | 51 +++++++++++++++----- pppd/cbcp.c | 5 +- pppd/main.c | 58 ++++++++++++----------- pppd/options.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++--- pppd/pppd.8 | 38 ++++++++++++++- pppd/pppd.h | 37 ++++++++++----- 6 files changed, 253 insertions(+), 59 deletions(-) diff --git a/pppd/auth.c b/pppd/auth.c index c51a67d..7548b46 100644 --- a/pppd/auth.c +++ b/pppd/auth.c @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: auth.c,v 1.53 1999/05/13 00:33:05 paulus Exp $"; +static char rcsid[] = "$Id: auth.c,v 1.54 1999/07/21 00:24:30 paulus Exp $"; #endif #include @@ -78,12 +78,6 @@ static char rcsid[] = "$Id: auth.c,v 1.53 1999/05/13 00:33:05 paulus Exp $"; #endif #include "pathnames.h" -/* Used for storing a sequence of words. Usually malloced. */ -struct wordlist { - struct wordlist *next; - char *word; -}; - /* Bits in scan_authfile return value */ #define NONWILD_SERVER 1 #define NONWILD_CLIENT 2 @@ -102,6 +96,9 @@ static int logged_in; /* List of addresses which the peer may use. */ static struct permitted_ip *addresses[NUM_PPP]; +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; + /* Number of network protocols which we have opened. */ static int num_np_open; @@ -432,6 +429,20 @@ network_phase(unit) } #endif + /* + * Process extra options from the secrets file + */ + if (extra_options) { + options_from_list(extra_options, 1); + free_wordlist(extra_options); + extra_options = 0; + } + start_networks(); +} + +void +start_networks() +{ phase = PHASE_NETWORK; #if 0 if (!demand) @@ -563,7 +574,6 @@ np_up(unit, proto) /* * At this point we consider that the link has come up successfully. */ - need_holdoff = 0; status = EXIT_OK; if (idle_time_limit > 0) @@ -628,6 +638,7 @@ check_idle(arg) /* link is idle: shut it down. */ notice("Terminating connection due to lack of activity."); lcp_close(0, "Link inactive"); + need_holdoff = 0; status = EXIT_IDLE_TIMEOUT; } else { TIMEOUT(check_idle, NULL, idle_time_limit - itime); @@ -1266,14 +1277,16 @@ get_secret(unit, client, server, secret, secret_len, save_addrs) /* * set_allowed_addrs() - set the list of allowed addresses. + * Also looks for `--' indicating options to apply for this peer + * and leaves the following words in extra_options. */ static void set_allowed_addrs(unit, addrs) int unit; struct wordlist *addrs; { - int n = 0; - struct wordlist *ap; + int n; + struct wordlist *ap, **pap; struct permitted_ip *ip; char *ptr_word, *ptr_mask; struct hostent *hp; @@ -1285,9 +1298,23 @@ set_allowed_addrs(unit, addrs) if (addresses[unit] != NULL) free(addresses[unit]); addresses[unit] = NULL; + if (extra_options != NULL) + free_wordlist(extra_options); + extra_options = NULL; - for (ap = addrs; ap != NULL; ap = ap->next) - ++n; + /* + * Count the number of IP addresses given, and chop off + * any extra options for this peer. + */ + for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next, ++n) { + if (strcmp(ap->word, "--") == 0) { + /* rest are options */ + *pap = 0; + extra_options = ap->next; + free(ap); + break; + } + } if (n == 0) return; ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); diff --git a/pppd/cbcp.c b/pppd/cbcp.c index 34ba6f7..b19283f 100644 --- a/pppd/cbcp.c +++ b/pppd/cbcp.c @@ -19,7 +19,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: cbcp.c,v 1.7 1999/05/12 06:19:46 paulus Exp $"; +static char rcsid[] = "$Id: cbcp.c,v 1.8 1999/07/21 00:24:30 paulus Exp $"; #endif #include @@ -31,7 +31,6 @@ static char rcsid[] = "$Id: cbcp.c,v 1.7 1999/05/12 06:19:46 paulus Exp $"; #include "cbcp.h" #include "fsm.h" #include "lcp.h" -#include "ipcp.h" /* * Options. @@ -384,7 +383,7 @@ cbcp_resp(us) PUTCHAR(len , bufp); PUTCHAR(0, bufp); cbcp_send(us, CBCP_RESP, buf, len); - (*ipcp_protent.open)(us->us_unit); + start_networks(); return; } } diff --git a/pppd/main.c b/pppd/main.c index 7eee192..a33a5e2 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -18,7 +18,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: main.c,v 1.79 1999/05/13 00:35:23 paulus Exp $"; +static char rcsid[] = "$Id: main.c,v 1.80 1999/07/21 00:24:31 paulus Exp $"; #endif #include @@ -85,6 +85,7 @@ int need_holdoff; /* need holdoff period before restarting */ int detached; /* have detached from terminal */ struct stat devstat; /* result of stat() on devnam */ int prepass = 0; /* doing prepass to find device name */ +int devnam_fixed; /* set while in options.ttyxx file */ volatile int status; /* exit status for pppd */ static int fd_ppp = -1; /* fd for talking PPP */ @@ -287,24 +288,13 @@ main(argc, argv) * The per-tty options file should not change * ptycommand, notty or devnam. */ + devnam_fixed = 1; if (!using_pty) { - int save_defdev = default_device; - - default_device = 1; if (!options_for_tty()) exit(EXIT_OPTION_ERROR); - if (notty || ptycommand != NULL) { - option_error("%s option may not be used in per-tty options file", - notty? "notty": "pty"); - exit(EXIT_OPTION_ERROR); - } - if (!default_device) { - option_error("per-tty options file may not specify device name"); - exit(EXIT_OPTION_ERROR); - } - default_device = save_defdev; } + devnam_fixed = 0; if (!parse_args(argc-1, argv+1)) exit(EXIT_OPTION_ERROR); @@ -551,6 +541,8 @@ main(argc, argv) info("Starting link"); } + phase = PHASE_SERIALCONN; + /* * Get a pty master/slave pair if the pty, notty, or record * options were specified. @@ -622,7 +614,7 @@ main(argc, argv) /* * Set line speed, flow control, etc. - * If we have a non-null connection script, + * If we have a non-null connection or initializer script, * on most systems we set CLOCAL for now so that we can talk * to the modem before carrier comes up. But this has the * side effect that we might miss it if CD drops before we @@ -630,7 +622,8 @@ main(argc, argv) * successfully to the modem with CLOCAL clear and CD down, * we could clear CLOCAL at this point. */ - set_up_tty(ttyfd, (connector != NULL && connector[0] != 0)); + set_up_tty(ttyfd, ((connector != NULL && connector[0] != 0) + || initializer != NULL)); real_ttyfd = ttyfd; } @@ -669,9 +662,7 @@ main(argc, argv) } /* run connection script */ - if (connector && connector[0]) { - MAINDEBUG(("Connecting with <%s>", connector)); - + if ((connector && connector[0]) || initializer) { if (real_ttyfd != -1) { if (!default_device && modem) { setdtr(real_ttyfd, 0); /* in case modem is off hook */ @@ -680,15 +671,29 @@ main(argc, argv) } } - if (device_script(connector, ttyfd, ttyfd, 0) < 0) { - error("Connect script failed"); - status = EXIT_CONNECT_FAILED; - goto fail; + if (initializer && initializer[0]) { + if (device_script(initializer, ttyfd, ttyfd, 0) < 0) { + error("Initializer script failed"); + status = EXIT_INIT_FAILED; + goto fail; + } + if (kill_link) + goto disconnect; + + info("Serial port initialized."); } - if (kill_link) - goto disconnect; - info("Serial connection established."); + if (connector && connector[0]) { + if (device_script(connector, ttyfd, ttyfd, 0) < 0) { + error("Connect script failed"); + status = EXIT_CONNECT_FAILED; + goto fail; + } + if (kill_link) + goto disconnect; + + info("Serial connection established."); + } /* set line speed, flow control, etc.; clear CLOCAL if modem option */ @@ -886,6 +891,7 @@ main(argc, argv) } /* Wait for scripts to finish */ + /* XXX should have a timeout here */ while (n_children > 0) { if (debug) { struct subprocess *chp; diff --git a/pppd/options.c b/pppd/options.c index 495c29a..5d14416 100644 --- a/pppd/options.c +++ b/pppd/options.c @@ -18,13 +18,14 @@ */ #ifndef lint -static char rcsid[] = "$Id: options.c,v 1.59 1999/05/14 01:09:03 paulus Exp $"; +static char rcsid[] = "$Id: options.c,v 1.60 1999/07/21 00:24:31 paulus Exp $"; #endif #include #include #include #include +#include #include #include #include @@ -73,6 +74,7 @@ u_int32_t netmask = 0; /* IP netmask to set on interface */ bool lockflag = 0; /* Create lock file to lock the serial dev */ bool nodetach = 0; /* Don't detach from controlling tty */ bool updetach = 0; /* Detach once link is up */ +char *initializer = NULL; /* Script to initialize physical link */ char *connector = NULL; /* Script to establish physical link */ char *disconnector = NULL; /* Script to disestablish physical link */ char *welcomer = NULL; /* Script to run after phys link estab. */ @@ -96,6 +98,7 @@ extern option_t auth_options[]; extern struct stat devstat; extern int prepass; /* Doing pre-pass to find device name */ +struct option_info initializer_info; struct option_info connector_info; struct option_info disconnector_info; struct option_info welcomer_info; @@ -111,6 +114,7 @@ pcap_t pc; /* Fake struct pcap so we can compile expr */ 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 */ +bool log_to_file; /* log_to_fd is a file opened by us */ /* * Prototypes @@ -127,6 +131,7 @@ static int callfile __P((char **)); static int showversion __P((char **)); static int showhelp __P((char **)); static void usage __P((void)); +static int setlogfile __P((char **)); #ifdef PPP_FILTER static int setpassfilter __P((char **)); @@ -163,6 +168,9 @@ option_t general_options[] = { "Lock serial device with UUCP-style lock file", 1 }, { "-all", o_special_noarg, noopt, "Don't request/allow any LCP or IPCP options (useless)" }, + { "init", o_string, &initializer, + "A program to initialize the device", + OPT_A2INFO | OPT_PRIVFIX, &initializer_info }, { "connect", o_string, &connector, "A program to set up a connection", OPT_A2INFO | OPT_PRIVFIX, &connector_info }, @@ -174,9 +182,9 @@ option_t general_options[] = { OPT_A2INFO | OPT_PRIVFIX, &welcomer_info }, { "pty", o_string, &ptycommand, "Script to run on pseudo-tty master side", - OPT_A2INFO | OPT_PRIVFIX | OPT_PREPASS, &ptycommand_info }, + OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info }, { "notty", o_bool, ¬ty, - "Input/output is not a tty", OPT_PREPASS | 1 }, + "Input/output is not a tty", OPT_DEVNAM | 1 }, { "record", o_string, &record_file, "Record characters sent/received to file" }, { "maxconnect", o_int, &maxconnect, @@ -212,7 +220,7 @@ option_t general_options[] = { { "nopersist", o_bool, &persist, "Turn off persist option" }, { "demand", o_bool, &demand, - "Dial on demand", 1, &persist }, + "Dial on demand", OPT_INITONLY | 1, &persist }, { "--version", o_special_noarg, showversion, "Show version number" }, { "--help", o_special_noarg, showhelp, @@ -223,6 +231,11 @@ option_t general_options[] = { "Use synchronous HDLC serial encoding", 1 }, { "logfd", o_int, &log_to_fd, "Send log messages to this file descriptor" }, + { "logfile", o_special, setlogfile, + "Append log messages to this file" }, + { "nolog", o_int, &log_to_fd, + "Don't send log messages to any file", + OPT_NOARG | OPT_VAL(-1) }, { "nologfd", o_int, &log_to_fd, "Don't send log messages to any file descriptor", OPT_NOARG | OPT_VAL(-1) }, @@ -409,6 +422,11 @@ options_from_file(filename, must_exist, check_prot, priv) argv[i] = args[i]; } current_option = cmd; + if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) { + option_error("the %s option may not be used in the %s file", + cmd, filename); + goto err; + } if (!process_option(opt, argv)) goto err; continue; @@ -492,6 +510,64 @@ options_for_tty() return ret; } +/* + * options_from_list - process a string of options in a wordlist. + */ +int +options_from_list(w, priv) + struct wordlist *w; + int priv; +{ + char *argv[MAXARGS]; + option_t *opt; + int i, ret = 0; + + privileged_option = priv; + option_source = "secrets file"; + + while (w != NULL) { + /* + * First see if it's a command. + */ + opt = find_option(w->word); + if (opt != NULL) { + int n = n_arguments(opt); + struct wordlist *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; + } + current_option = w0->word; + if (!process_option(opt, argv)) + goto err; + continue; + } + + /* + * Maybe a tty name, speed or IP address? + */ + if ((i = setdevname(w->word)) == 0 + && (i = setspeed(w->word)) == 0 + && (i = setipaddr(w->word)) == 0) { + option_error("In secrets file: unrecognized option '%s'", + w->word); + goto err; + } + if (i < 0) /* error */ + goto err; + } + ret = 1; + +err: + return ret; +} + /* * find_option - scan the option lists for the various protocols * looking for an entry with the given name. @@ -531,9 +607,12 @@ process_option(opt, argv) char *sv; int (*parser) __P((char **)); - if (prepass && (opt->flags & OPT_PREPASS) == 0) + if ((opt->flags & OPT_PREPASS) == 0 && prepass) return 1; - + if ((opt->flags & OPT_INITONLY) && phase != PHASE_INITIALIZE) { + option_error("it's too late to use the %s option", opt->name); + return 0; + } if ((opt->flags & OPT_PRIV) && !privileged_option) { option_error("using the %s option requires root privilege", opt->name); return 0; @@ -1229,6 +1308,14 @@ setdevname(cp) return -1; } + if (phase != PHASE_INITIALIZE) { + option_error("device name cannot be changed after initialization"); + return -1; + } else if (devnam_fixed) { + option_error("per-tty options file may not specify device name"); + return -1; + } + if (devnam_info.priv && !privileged_option) { option_error("device name cannot be overridden"); return -1; @@ -1370,3 +1457,27 @@ setxonxoff(argv) crtscts = -2; return (1); } + +static int +setlogfile(argv) + char **argv; +{ + int fd, err; + + if (!privileged_option) + seteuid(getuid()); + fd = open(*argv, O_WRONLY | O_APPEND); + err = errno; + if (!privileged_option) + seteuid(0); + if (fd < 0) { + errno = err; + option_error("Can't open log file %s: %m", *argv); + return 0; + } + if (log_to_file && log_to_fd >= 0) + close(log_to_fd); + log_to_fd = fd; + log_to_file = 1; + return 1; +} diff --git a/pppd/pppd.8 b/pppd/pppd.8 index 4c83af8..105c0a1 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -1,5 +1,5 @@ .\" manual page [] for pppd 2.3 -.\" $Id: pppd.8,v 1.40 1999/05/13 00:34:04 paulus Exp $ +.\" $Id: pppd.8,v 1.41 1999/07/21 00:24:32 paulus Exp $ .\" SH section heading .\" SS subsection heading .\" LP paragraph @@ -132,6 +132,13 @@ with hex values 0x20 - 0x3f or 0x5e. Read options from file \fIname\fR (the format is described below). The file must be readable by the user who has invoked pppd. .TP +.B init \fIscript +Run the executable or shell command specified by \fIscript\fR to +initialize the serial line. This script would typically use the +chat(8) program to configure the modem to enable auto answer. A value +for this option from a privileged source cannot be overridden by a +non-privileged user. +.TP .B lock Specifies that pppd should create a UUCP-style lock file for the serial device to ensure exclusive access to the device. @@ -424,6 +431,18 @@ Don't use the modem control lines. With this option, pppd will ignore the state of the CD (Carrier Detect) signal from the modem and will not change the state of the DTR (Data Terminal Ready) signal. .TP +.B logfd \fIn +Send log messages to file descriptor \fIn\fR. Pppd will send log +messages to at most one file or file descriptor (as well as sending +the log messages to syslog), so this option and the \fBlogfile\fR +option are mutually exclusive. The default is for pppd to send log +messages to stdout (file descriptor 1), unless the serial port is +already open on stdout. +.TP +.B logfile \fIfilename +Append log messages to the file \fIfilename\fR (as well as sending the +log messages to syslog). The file is opened with the privileges of +the user who invoked pppd, in append mode. .B login Use the system password database for authenticating the peer using PAP, and record the user in the system wtmp file. Note that the peer @@ -538,6 +557,9 @@ Disable the IPXCP and IPX protocols. This option should only be required if the peer is buggy and gets confused by requests from pppd for IPXCP negotiation. .TP +.B nolog +Do not send log messages to a file or file descriptor. This option +cancels the \fBlogfd\fR and \fBlogfile\fR options. .B nomagic Disable magic number negotiation. With this option, pppd cannot detect a looped-back line. This option should only be needed if the @@ -696,12 +718,23 @@ The device used by pppd with this option must have sync support. Currently supports Microgate SyncLink adapters under Linux and FreeBSD 2.2.8 and later. .TP +.B updetach +With this option, pppd will detach from its controlling terminal once +it has successfully established the ppp connection (to the point where +the first network control protocol, usually the IP control protocol, +has come up). +.TP .B usehostname Enforce the use of the hostname (with domain name appended, if given) as the name of the local system for authentication purposes (overrides the \fIname\fR option). This option is not normally needed since the \fIname\fR option is privileged. .TP +.B usepeerdns +Ask the peer for up to 2 DNS server addresses. The addresses supplied +by the peer (if any) are passed to the /etc/ppp/ip-up script in the +environment variables DNS1 and DNS2. +.TP .B user \fIname Sets the name used for authenticating the local system to the peer to \fIname\fR. @@ -1115,6 +1148,9 @@ The link was terminated by the modem hanging up. .TP .B 17 The PPP negotiation failed because serial loopback was detected. +.TP +.B 18 +The init script failed (returned a non-zero exit status). .SH SCRIPTS Pppd invokes scripts at various stages in its processing which can be used to perform site-specific ancillary processing. These scripts are diff --git a/pppd/pppd.h b/pppd/pppd.h index a95f461..c7ddd3b 100644 --- a/pppd/pppd.h +++ b/pppd/pppd.h @@ -16,7 +16,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: pppd.h,v 1.41 1999/05/14 01:09:03 paulus Exp $ + * $Id: pppd.h,v 1.42 1999/07/21 00:24:32 paulus Exp $ */ /* @@ -97,7 +97,10 @@ typedef struct { #define OPT_A2COPY 0x200000 /* addr2 -> second location to rcv value */ #define OPT_ENABLE 0x400000 /* use *addr2 as enable for option */ #define OPT_PRIVFIX 0x800000 /* can't be overridden if noauth */ -#define OPT_PREPASS 0x1000000/* do this opt in pre-pass to find device */ +#define OPT_PREPASS 0x1000000 /* do this opt in pre-pass to find device */ +#define OPT_INITONLY 0x2000000 /* option can only be set in init phase */ +#define OPT_DEVEQUIV 0x4000000 /* equiv to device name */ +#define OPT_DEVNAM (OPT_PREPASS | OPT_INITONLY | OPT_DEVEQUIV) #define OPT_VAL(x) ((x) & OPT_VALUE) @@ -123,6 +126,12 @@ struct pppd_stats { unsigned int bytes_out; }; +/* Used for storing a sequence of words. Usually malloced. */ +struct wordlist { + struct wordlist *next; + char *word; +}; + /* * Global variables. */ @@ -150,6 +159,7 @@ extern int using_pty; /* using pty as device (notty or pty opt.) */ extern int log_to_fd; /* logging to this fd as well as syslog */ extern char *no_ppp_msg; /* message to print if ppp not in kernel */ extern volatile int status; /* exit status for pppd */ +extern int devnam_fixed; /* can no longer change devnam */ /* * Variables set by command-line options. @@ -166,6 +176,7 @@ extern u_int32_t netmask; /* IP netmask to set on interface */ extern bool lockflag; /* Create lock file to lock the serial dev */ extern bool nodetach; /* Don't detach from controlling tty */ extern bool updetach; /* Detach from controlling tty when link up */ +extern char *initializer; /* Script to initialize physical link */ extern char *connector; /* Script to establish physical link */ extern char *disconnector; /* Script to disestablish physical link */ extern char *welcomer; /* Script to welcome client after connection */ @@ -207,13 +218,14 @@ extern char *option_source; /* string saying where the option came from */ */ #define PHASE_DEAD 0 #define PHASE_INITIALIZE 1 -#define PHASE_DORMANT 2 -#define PHASE_ESTABLISH 3 -#define PHASE_AUTHENTICATE 4 -#define PHASE_CALLBACK 5 -#define PHASE_NETWORK 6 -#define PHASE_TERMINATE 7 -#define PHASE_HOLDOFF 8 +#define PHASE_SERIALCONN 2 +#define PHASE_DORMANT 3 +#define PHASE_ESTABLISH 4 +#define PHASE_AUTHENTICATE 5 +#define PHASE_CALLBACK 6 +#define PHASE_NETWORK 7 +#define PHASE_TERMINATE 8 +#define PHASE_HOLDOFF 9 /* * The following struct gives the addresses of procedures to call @@ -298,6 +310,7 @@ void link_required __P((int)); /* we are starting to use the link */ void link_terminated __P((int)); /* we are finished with the link */ void link_down __P((int)); /* the LCP layer has left the Opened state */ void link_established __P((int)); /* the link is up; authenticate now */ +void start_networks __P((void)); /* start all the network control protos */ void np_up __P((int, int)); /* a network protocol has come up */ void np_down __P((int, int)); /* a network protocol has gone down */ void np_finished __P((int, int)); /* a network protocol no longer needs link */ @@ -410,8 +423,8 @@ int options_from_file __P((char *filename, int must_exist, int check_prot, /* Parse options from an options file */ int options_from_user __P((void)); /* Parse options from user's .ppprc */ int options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */ -void scan_args __P((int argc, char **argv)); - /* Look for tty name in command-line args */ +int options_from_list __P((struct wordlist *, int privileged)); + /* Parse options from a wordlist */ int getword __P((FILE *f, char *word, int *newlinep, char *filename)); /* Read a word from a file */ void option_error __P((char *fmt, ...)); @@ -431,6 +444,7 @@ struct option_info { }; extern struct option_info devnam_info; +extern struct option_info initializer_info; extern struct option_info connector_info; extern struct option_info disconnector_info; extern struct option_info welcomer_info; @@ -516,6 +530,7 @@ extern struct option_info ptycommand_info; #define EXIT_PEER_DEAD 15 #define EXIT_HANGUP 16 #define EXIT_LOOPBACK 17 +#define EXIT_INIT_FAILED 18 /* * Debug macros. Slightly useful for finding bugs in pppd, not particularly -- 2.39.2