summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pppd
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1997-08-19 17:52:48 +0000
committerpeter <peter@FreeBSD.org>1997-08-19 17:52:48 +0000
commit070f42a366d1f592be37f248439635c1d36eaaa3 (patch)
tree485faad86f4448a6b6ceaf08b9bca8d9250596b3 /usr.sbin/pppd
parentf52b01f46739c1ff6b61ccfe02a7fbd874f14bed (diff)
downloadFreeBSD-src-070f42a366d1f592be37f248439635c1d36eaaa3.zip
FreeBSD-src-070f42a366d1f592be37f248439635c1d36eaaa3.tar.gz
*gulp* First pass at merging in ppp-2.3.0's pppd. (this has
dial-on-demand, packet filtering, idle timeouts, etc). The IPX support is pretty much there but more work needs to be done in sys-bsd.c for the interface ioctls (Linux has a very different way of configuring IPX interfaces). Along the way some things have temporarily been lost due to very messy conflicts. I will recover them shortly when I can think clearer. The main one is the local:remote address override in pap-secrets and chap-secrets. Some other home-grown features (dns1,dns2) have been implemented differently. Microsoft's chap client auth hacks have been implemented. There are bound to be more rough edges... The changes for connect-max-retries doesn't fit well with the dial-on-demand code.
Diffstat (limited to 'usr.sbin/pppd')
-rw-r--r--usr.sbin/pppd/Makefile9
-rw-r--r--usr.sbin/pppd/RELNOTES169
-rw-r--r--usr.sbin/pppd/auth.c732
-rw-r--r--usr.sbin/pppd/cbcp.c430
-rw-r--r--usr.sbin/pppd/cbcp.h26
-rw-r--r--usr.sbin/pppd/ccp.c510
-rw-r--r--usr.sbin/pppd/ccp.h17
-rw-r--r--usr.sbin/pppd/chap.c134
-rw-r--r--usr.sbin/pppd/chap.h30
-rw-r--r--usr.sbin/pppd/chap_ms.c327
-rw-r--r--usr.sbin/pppd/chap_ms.h32
-rw-r--r--usr.sbin/pppd/demand.c348
-rw-r--r--usr.sbin/pppd/fsm.c88
-rw-r--r--usr.sbin/pppd/fsm.h60
-rw-r--r--usr.sbin/pppd/ipcp.c538
-rw-r--r--usr.sbin/pppd/ipcp.h22
-rw-r--r--usr.sbin/pppd/ipxcp.c1414
-rw-r--r--usr.sbin/pppd/ipxcp.h71
-rw-r--r--usr.sbin/pppd/lcp.c457
-rw-r--r--usr.sbin/pppd/lcp.h16
-rw-r--r--usr.sbin/pppd/magic.c5
-rw-r--r--usr.sbin/pppd/main.c1045
-rw-r--r--usr.sbin/pppd/options.c1253
-rw-r--r--usr.sbin/pppd/patchlevel.h6
-rw-r--r--usr.sbin/pppd/pathnames.h9
-rw-r--r--usr.sbin/pppd/pppd.81437
-rw-r--r--usr.sbin/pppd/pppd.h268
-rw-r--r--usr.sbin/pppd/sys-bsd.c717
-rw-r--r--usr.sbin/pppd/upap.c98
-rw-r--r--usr.sbin/pppd/upap.h10
30 files changed, 8250 insertions, 2028 deletions
diff --git a/usr.sbin/pppd/Makefile b/usr.sbin/pppd/Makefile
index 3a3574f..f758d58 100644
--- a/usr.sbin/pppd/Makefile
+++ b/usr.sbin/pppd/Makefile
@@ -3,14 +3,15 @@
CFLAGS+= -DHAVE_PATHS_H
PROG= pppd
-SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c ccp.c \
- auth.c options.c sys-bsd.c
+SRCS= main.c magic.c fsm.c lcp.c ipcp.c ipxcp.c upap.c chap.c ccp.c \
+ demand.c auth.c options.c sys-bsd.c
MAN8= pppd.8
-# The next line is for NetBSD-current systems.
-MAN= pppd.cat8
BINMODE=4555
BINOWN= root
+#CFLAGS+=-DIPX_CHANGE
+#SRCS+= ipxcp.c
+
LDADD= -lcrypt -lutil -lmd
DPADD= ${LIBCRYPT} ${LIBUTIL} ${LIBMD}
diff --git a/usr.sbin/pppd/RELNOTES b/usr.sbin/pppd/RELNOTES
index 8567a7a..2b4b1ab 100644
--- a/usr.sbin/pppd/RELNOTES
+++ b/usr.sbin/pppd/RELNOTES
@@ -1,3 +1,172 @@
+This is the README file for ppp-2.3, a package which implements the
+Point-to-Point Protocol (PPP) to provide Internet connections over
+serial lines.
+
+
+Introduction.
+*************
+
+The Point-to-Point Protocol (PPP) provides a standard way to establish
+a network connection over a serial link. At present, this package
+supports IP and the protocols layered above IP, such as TCP and UDP.
+The Linux port of this package also has support for IPX.
+
+This software consists of two parts:
+
+- Kernel code, which establishes a network interface and passes
+packets between the serial port, the kernel networking code and the
+PPP daemon (pppd). This code is implemented using STREAMS modules on
+SunOS 4.x, Solaris 2.x, System V Release 4, and OSF/1, and as a
+line discipline under Ultrix, NextStep, NetBSD, FreeBSD, and Linux.
+
+- The PPP daemon (pppd), which negotiates with the peer to establish
+the link and sets up the ppp network interface. Pppd includes support
+for authentication, so you can control which other systems may make a
+PPP connection and what IP addresses they may use.
+
+
+Installation.
+*************
+
+The file SETUP contains general information about setting up your
+system for using PPP. There is also a README file for each supported
+system, which contains more specific details for installing PPP on
+that system. The supported systems, and the corresponding README
+files, are:
+
+ Digital Unix (OSF/1) README.osf
+ Linux README.linux
+ NetBSD, FreeBSD README.bsd
+ NeXTStep README.next
+ Solaris 2 README.sol2
+ SunOS 4.x README.sunos4
+ System V Release 4 README.svr4
+ Ultrix 4.x README.ultrix
+
+(Unfortunately, AIX 4 is no longer supported, since I don't have a
+maintainer for the AIX 4 port. If you want to volunteer, contact me.)
+
+In each case you start by running the ./configure script. This works
+out which operating system you are using and creates symbolic links to
+the appropriate makefiles. You then run `make' to compile the
+user-level code, and (as root) `make install' to install the
+user-level programs pppd, chat and pppstats.
+
+The procedures for installing the kernel code vary from system to
+system. On some systems, the kernel code can be loaded into a running
+kernel using a `modload' facility. On others, the kernel image has to
+be recompiled and the system rebooted. See the README.* files for
+details.
+
+
+What's new in ppp-2.3.
+**********************
+
+* Demand-dialling. Pppd now has a mode where it will establish the
+network interface immediately when it starts, but not actually bring
+the link up until it sees some data to be sent. Look for the demand
+option description in the pppd man page. Demand-dialling is not
+supported under Ultrix or NeXTStep.
+
+* Idle timeout. Pppd will optionally terminate the link if no data
+packets are sent or received within a certain time interval.
+
+* Pppd now runs the /etc/ppp/auth-up script, if it exists, when the
+peer successfully authenticates itself, and /etc/ppp/auth-down when
+the connection is subsequently terminated. This can be useful for
+accounting purposes.
+
+* A new packet compression scheme, Deflate, has been implemented.
+This uses the same compression method as `gzip'. This method is free
+of patent or copyright restrictions, and it achieves better
+compression than BSD-Compress. It does consume more CPU cycles for
+compression than BSD-Compress, but this shouldn't be a problem for
+links running at 100kbit/s or less.
+
+* There is no code in this distribution which is covered by Brad
+Clements' restrictive copyright notice. The STREAMS modules for SunOS
+and OSF/1 have been rewritten, based on the Solaris 2 modules, which
+were written from scratch without any Clements code.
+
+* Pppstats has been reworked to clean up the output format somewhat.
+It also has a new -d option which displays data rate in kbyte/s for
+those columns which would normally display bytes.
+
+* Pppd options beginning with - or + have been renamed, e.g. -ip
+became noip, +chap became require-chap, etc. The old options are
+still accepted for compatibility but may be removed in future.
+
+* Pppd now has some options (such as the new `noauth' option) which
+can only be specified if it is being run by root, or in an
+"privileged" options file: /etc/ppp/options or an options file in the
+/etc/ppp/peers directory. There is a new "call" option to read
+options from a file in /etc/ppp/peers, making it possible for non-root
+users to make unauthenticated connections, but only to certain trusted
+peers. My intention is to make the `auth' option the default in a
+future release.
+
+* Several minor new features have been added to pppd, including the
+maxconnect and welcome options. Pppd will now terminate the
+connection when there are no network control protocols running. The
+allowed IP address(es) field in the secrets files can now specify
+subnets (with a notation like 123.45.67.89/24) and addresses which are
+not acceptable (put a ! on the front).
+
+* Numerous bugs have been fixed (no doubt some have been introduced :-)
+Thanks to those who reported bugs in ppp-2.2.
+
+
+Patents.
+********
+
+The BSD-Compress algorithm used for packet compression is the same as
+that used in the Unix "compress" command. It is apparently covered by
+U.S. patents 4,814,746 (owned by IBM) and 4,558,302 (owned by Unisys),
+and corresponding patents in various other countries (but not
+Australia). If this is of concern, you can build the package without
+including BSD-Compress. To do this, edit net/ppp-comp.h to change the
+definition of DO_BSD_COMPRESS to 0. The bsd-comp.c files are then no
+longer needed, so the references to bsd-comp.o may optionally be
+removed from the Makefiles.
+
+
+Contacts.
+*********
+
+The comp.protocols.ppp newsgroup is a useful place to get help if you
+have trouble getting your ppp connections to work. Please do not send
+me questions of the form "please help me get connected to my ISP" -
+I'm sorry, but I simply do not have the time to answer all the
+questions like this that I get.
+
+If you find bugs in this package, please report them to the maintainer
+for the port for the operating system you are using:
+
+Digital Unix (OSF/1) Farrell Woods <ftw@zk3.dec.com>
+Linux Al Longyear <longyear@pobox.com>
+NetBSD Matthew Green <mrg@eterna.com.au
+FreeBSD Peter Wemm <peter@haywire.DIALix.COM>
+NeXTStep Steve Perkins <perkins@cps.msu.edu>
+Solaris 2 Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+SunOS 4.x Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+System V Release 4 Matthias Apitz <Matthias.Apitz@SOFTCON.de>
+Ultrix 4.x Paul Mackerras (for want of anybody better :-)
+
+
+Copyrights:
+***********
+
+All of the code can be freely used and redistributed.
+
+
+Distribution:
+*************
+
+The primary site for releases of this software is:
+
+ ftp://cs.anu.edu.au/pub/software/ppp/
+
+-------------------------
This is the README file for ppp-2.2, a package which implements the
Point-to-Point Protocol (PPP) to provide Internet connections over
serial lines.
diff --git a/usr.sbin/pppd/auth.c b/usr.sbin/pppd/auth.c
index 5e696a2..6a63893 100644
--- a/usr.sbin/pppd/auth.c
+++ b/usr.sbin/pppd/auth.c
@@ -33,7 +33,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: auth.c,v 1.15 1997/04/16 02:07:06 danny Exp $";
+static char rcsid[] = "$Id$";
#endif
#include <stdio.h>
@@ -45,6 +45,7 @@ static char rcsid[] = "$Id: auth.c,v 1.15 1997/04/16 02:07:06 danny Exp $";
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -52,9 +53,16 @@ static char rcsid[] = "$Id: auth.c,v 1.15 1997/04/16 02:07:06 danny Exp $";
#include <sys/time.h>
#include <utmp.h>
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#endif
+
#ifdef HAS_SHADOW
#include <shadow.h>
+#ifndef SVR4
#include <shadow/pwauth.h>
+#endif
#ifndef PW_PPP
#define PW_PPP PW_LOGIN
#endif
@@ -63,16 +71,14 @@ static char rcsid[] = "$Id: auth.c,v 1.15 1997/04/16 02:07:06 danny Exp $";
#include "pppd.h"
#include "fsm.h"
#include "lcp.h"
+#include "ipcp.h"
#include "upap.h"
#include "chap.h"
-#include "ipcp.h"
-#include "ccp.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
#include "pathnames.h"
-#if defined(sun) && defined(sparc)
-#include <alloca.h>
-#endif /*sparc*/
-
/* Used for storing a sequence of words. Usually malloced. */
struct wordlist {
struct wordlist *next;
@@ -88,32 +94,58 @@ struct wordlist {
#define FALSE 0
#define TRUE 1
+/* The name by which the peer authenticated itself to us. */
+char peer_authname[MAXNAMELEN];
+
/* Records which authentication operations haven't completed yet. */
static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called login() */
static int logged_in;
-static int non_wildclient =0; /* not wild nor blank */
+
+/* Set if we have run the /etc/ppp/auth-up script. */
+static int did_authup;
+
+/* List of addresses which the peer may use. */
static struct wordlist *addresses[NUM_PPP];
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+
/* Bits in auth_pending[] */
-#define UPAP_WITHPEER 1
-#define UPAP_PEER 2
+#define PAP_WITHPEER 1
+#define PAP_PEER 2
#define CHAP_WITHPEER 4
#define CHAP_PEER 8
-/* Prototypes */
-void check_access __P((FILE *, char *));
+extern char *crypt __P((const char *, const char *));
+
+/* Prototypes for procedures local to this file. */
static void network_phase __P((int));
+static void check_idle __P((void *));
+static void connect_time_expired __P((void *));
static int ppplogin __P((char *, char *, char **, int *));
static void ppplogout __P((void));
static int null_login __P((int));
-static int get_upap_passwd __P((void));
-static int have_upap_secret __P((void));
-static int have_chap_secret __P((char *, char *));
-static int scan_authfile __P((FILE *, char *, char *, char *,
- struct wordlist **, char *));
+static int get_pap_passwd __P((char *));
+static int have_pap_secret __P((void));
+static int have_chap_secret __P((char *, char *, u_int32_t));
+static int ip_addr_check __P((u_int32_t, struct wordlist *));
+static int scan_authfile __P((FILE *, char *, char *, u_int32_t, char *,
+ struct wordlist **, char *));
static void free_wordlist __P((struct wordlist *));
-static void auth_set_ip_addr __P((int));
+static void auth_script __P((char *));
+static void set_allowed_addrs __P((int, struct wordlist *));
+#ifdef CBCP_SUPPORT
+static void callback_phase __P((int));
+#endif
/*
* An Open on LCP has requested a change from Dead to Establish phase.
@@ -154,9 +186,25 @@ void
link_down(unit)
int unit;
{
- ipcp_close(0);
- ccp_close(0);
- phase = PHASE_TERMINATE;
+ int i;
+ struct protent *protp;
+
+ if (did_authup) {
+ auth_script(_PATH_AUTHDOWN);
+ did_authup = 0;
+ }
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (!protp->enabled_flag)
+ continue;
+ if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+ (*protp->lowerdown)(unit);
+ if (protp->protocol < 0xC000 && protp->close != NULL)
+ (*protp->close)(unit, "LCP down");
+ }
+ num_np_open = 0;
+ num_np_up = 0;
+ if (phase != PHASE_DEAD)
+ phase = PHASE_TERMINATE;
}
/*
@@ -171,6 +219,16 @@ link_established(unit)
lcp_options *wo = &lcp_wantoptions[unit];
lcp_options *go = &lcp_gotoptions[unit];
lcp_options *ho = &lcp_hisoptions[unit];
+ int i;
+ struct protent *protp;
+
+ /*
+ * Tell higher-level protocols that LCP is up.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol != PPP_LCP && protp->enabled_flag
+ && protp->lowerup != NULL)
+ (*protp->lowerup)(unit);
if (auth_required && !(go->neg_chap || go->neg_upap)) {
/*
@@ -180,8 +238,7 @@ link_established(unit)
*/
if (!wo->neg_upap || !null_login(unit)) {
syslog(LOG_WARNING, "peer refused to authenticate");
- lcp_close(unit);
- phase = PHASE_TERMINATE;
+ lcp_close(unit, "peer refused to authenticate");
return;
}
}
@@ -193,14 +250,19 @@ link_established(unit)
auth |= CHAP_PEER;
} else if (go->neg_upap) {
upap_authpeer(unit);
- auth |= UPAP_PEER;
+ auth |= PAP_PEER;
}
if (ho->neg_chap) {
- ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
+ ChapAuthWithPeer(unit, user, ho->chap_mdtype);
auth |= CHAP_WITHPEER;
} else if (ho->neg_upap) {
+ if (passwd[0] == 0) {
+ passwd_from_file = 1;
+ if (!get_pap_passwd(passwd))
+ syslog(LOG_ERR, "No secret found for PAP login");
+ }
upap_authwithpeer(unit, user, passwd);
- auth |= UPAP_WITHPEER;
+ auth |= PAP_WITHPEER;
}
auth_pending[unit] = auth;
@@ -215,9 +277,41 @@ static void
network_phase(unit)
int unit;
{
+ int i;
+ struct protent *protp;
+ lcp_options *go = &lcp_gotoptions[unit];
+
+ /*
+ * If the peer had to authenticate, run the auth-up script now.
+ */
+ if ((go->neg_chap || go->neg_upap) && !did_authup) {
+ auth_script(_PATH_AUTHUP);
+ did_authup = 1;
+ }
+
+#ifdef CBCP_SUPPORT
+ /*
+ * If we negotiated callback, do it now.
+ */
+ if (go->neg_cbcp) {
+ phase = PHASE_CALLBACK;
+ (*cbcp_protent.open)(unit);
+ return;
+ }
+#endif
+
phase = PHASE_NETWORK;
- ipcp_open(unit);
- ccp_open(unit);
+#if 0
+ if (!demand)
+ set_filters(&pass_filter, &active_filter);
+#endif
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol < 0xC000 && protp->enabled_flag
+ && protp->open != NULL) {
+ (*protp->open)(unit);
+ if (protp->protocol != PPP_CCP)
+ ++num_np_open;
+ }
}
/*
@@ -230,16 +324,17 @@ auth_peer_fail(unit, protocol)
/*
* Authentication failure: take the link down
*/
- lcp_close(unit);
- phase = PHASE_TERMINATE;
+ lcp_close(unit, "Authentication failed");
}
/*
* The peer has been successfully authenticated using `protocol'.
*/
void
-auth_peer_success(unit, protocol)
+auth_peer_success(unit, protocol, name, namelen)
int unit, protocol;
+ char *name;
+ int namelen;
{
int bit;
@@ -248,7 +343,7 @@ auth_peer_success(unit, protocol)
bit = CHAP_PEER;
break;
case PPP_PAP:
- bit = UPAP_PEER;
+ bit = PAP_PEER;
break;
default:
syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
@@ -257,20 +352,19 @@ auth_peer_success(unit, protocol)
}
/*
- * If we have overridden addresses based on auth info
- * then set that information now before continuing
+ * Save the authenticated name of the peer for later.
*/
- auth_set_ip_addr(unit);
+ if (namelen > sizeof(peer_authname) - 1)
+ namelen = sizeof(peer_authname) - 1;
+ BCOPY(name, peer_authname, namelen);
+ peer_authname[namelen] = 0;
/*
* If there is no more authentication still to be done,
- * proceed to the network phase.
+ * proceed to the network (or callback) phase.
*/
- if ((auth_pending[unit] &= ~bit) == 0) {
- phase = PHASE_NETWORK;
- ipcp_open(unit);
- ccp_open(unit);
- }
+ if ((auth_pending[unit] &= ~bit) == 0)
+ network_phase(unit);
}
/*
@@ -280,6 +374,8 @@ void
auth_withpeer_fail(unit, protocol)
int unit, protocol;
{
+ if (passwd_from_file)
+ BZERO(passwd, MAXSECRETLEN);
/*
* We've failed to authenticate ourselves to our peer.
* He'll probably take the link down, and there's not much
@@ -301,7 +397,9 @@ auth_withpeer_success(unit, protocol)
bit = CHAP_WITHPEER;
break;
case PPP_PAP:
- bit = UPAP_WITHPEER;
+ if (passwd_from_file)
+ BZERO(passwd, MAXSECRETLEN);
+ bit = PAP_WITHPEER;
break;
default:
syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
@@ -310,14 +408,8 @@ auth_withpeer_success(unit, protocol)
}
/*
- * If we have overridden addresses based on auth info
- * then set that information now before continuing
- */
- auth_set_ip_addr(unit);
-
- /*
* If there is no more authentication still being done,
- * proceed to the network phase.
+ * proceed to the network (or callback) phase.
*/
if ((auth_pending[unit] &= ~bit) == 0)
network_phase(unit);
@@ -325,13 +417,95 @@ auth_withpeer_success(unit, protocol)
/*
- * check_auth_options - called to check authentication options.
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(unit, proto)
+ int unit, proto;
+{
+ if (num_np_up == 0 && idle_time_limit > 0) {
+ TIMEOUT(check_idle, NULL, idle_time_limit);
+
+ /*
+ * Set a timeout to close the connection once the maximum
+ * connect time has expired.
+ */
+ if (maxconnect > 0)
+ TIMEOUT(connect_time_expired, 0, maxconnect);
+ }
+ ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(unit, proto)
+ int unit, proto;
+{
+ if (--num_np_up == 0 && idle_time_limit > 0) {
+ UNTIMEOUT(check_idle, NULL);
+ }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(unit, proto)
+ int unit, proto;
+{
+ if (--num_np_open <= 0) {
+ /* no further use for the link: shut up shop. */
+ lcp_close(0, "No network protocols running");
+ }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(arg)
+ void *arg;
+{
+ struct ppp_idle idle;
+ time_t itime;
+
+ if (!get_idle_time(0, &idle))
+ return;
+ itime = MIN(idle.xmit_idle, idle.recv_idle);
+ if (itime >= idle_time_limit) {
+ /* link is idle: shut it down. */
+ syslog(LOG_INFO, "Terminating connection due to lack of activity.");
+ need_holdoff = 0;
+ lcp_close(0, "Link inactive");
+ } else {
+ TIMEOUT(check_idle, NULL, idle_time_limit - itime);
+ }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(arg)
+ void *arg;
+{
+ syslog(LOG_INFO, "Connect time expired");
+ lcp_close(0, "Connect time expired"); /* Close connection */
+}
+
+/*
+ * auth_check_options - called to check authentication options.
*/
void
-check_auth_options()
+auth_check_options()
{
lcp_options *wo = &lcp_wantoptions[0];
- lcp_options *ao = &lcp_allowoptions[0];
+ int can_auth;
+ ipcp_options *ipwo = &ipcp_wantoptions[0];
+ u_int32_t remote;
/* Default our_name to hostname, and user to our_name */
if (our_name[0] == 0 || usehostname)
@@ -347,23 +521,69 @@ check_auth_options()
/*
* Check whether we have appropriate secrets to use
- * to authenticate ourselves and/or the peer.
+ * to authenticate the peer.
*/
- if (ao->neg_upap && passwd[0] == 0 && !get_upap_passwd())
- ao->neg_upap = 0;
- if (wo->neg_upap && !uselogin && !have_upap_secret())
- wo->neg_upap = 0;
- if (ao->neg_chap && !have_chap_secret(our_name, remote_name))
- ao->neg_chap = 0;
- if (wo->neg_chap && !have_chap_secret(remote_name, our_name))
- wo->neg_chap = 0;
+ can_auth = wo->neg_upap && (uselogin || have_pap_secret());
+ if (!can_auth && wo->neg_chap) {
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ can_auth = have_chap_secret(remote_name, our_name, remote);
+ }
- if (auth_required && !wo->neg_chap && !wo->neg_upap) {
- fprintf(stderr, "\
-pppd: peer authentication required but no authentication files accessible\n");
+ if (auth_required && !can_auth) {
+ option_error("peer authentication required but no suitable secret(s) found\n");
+ if (remote_name[0] == 0)
+ option_error("for authenticating any peer to us (%s)\n", our_name);
+ else
+ option_error("for authenticating peer %s to us (%s)\n",
+ remote_name, our_name);
exit(1);
}
+ /*
+ * Check whether the user tried to override certain values
+ * set by root.
+ */
+ if (!auth_required && auth_req_info.priv > 0) {
+ if (!default_device && devnam_info.priv == 0) {
+ option_error("can't override device name when noauth option used");
+ exit(1);
+ }
+ if ((connector != NULL && connector_info.priv == 0)
+ || (disconnector != NULL && disconnector_info.priv == 0)
+ || (welcomer != NULL && welcomer_info.priv == 0)) {
+ option_error("can't override connect, disconnect or welcome");
+ option_error("option values when noauth option used");
+ exit(1);
+ }
+ }
+}
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void
+auth_reset(unit)
+ int unit;
+{
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[0];
+ ipcp_options *ipwo = &ipcp_wantoptions[0];
+ u_int32_t remote;
+
+ ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
+ ao->neg_chap = !refuse_chap
+ && have_chap_secret(user, remote_name, (u_int32_t)0);
+
+ if (go->neg_upap && !uselogin && !have_pap_secret())
+ go->neg_upap = 0;
+ if (go->neg_chap) {
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ if (!have_chap_secret(remote_name, our_name, remote))
+ go->neg_chap = 0;
+ }
+
}
@@ -391,6 +611,8 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
char *filename;
FILE *f;
struct wordlist *addrs;
+ u_int32_t remote;
+ ipcp_options *ipwo = &ipcp_wantoptions[unit];
char passwd[256], user[256];
char secret[MAXWORDLEN];
static int attempts = 0;
@@ -405,9 +627,10 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
len = MIN(userlen, sizeof(user) - 1);
BCOPY(auser, user, len);
user[len] = '\0';
+ *msg = (char *) 0;
/*
- * Open the file of upap secrets and scan for a suitable secret
+ * Open the file of pap secrets and scan for a suitable secret
* for authenticating this user.
*/
filename = _PATH_UPAPFILE;
@@ -415,17 +638,17 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
ret = UPAP_AUTHACK;
f = fopen(filename, "r");
if (f == NULL) {
- if (!uselogin) {
- syslog(LOG_ERR, "Can't open upap password file %s: %m", filename);
- ret = UPAP_AUTHNAK;
- }
+ syslog(LOG_ERR, "Can't open PAP password file %s: %m", filename);
+ ret = UPAP_AUTHNAK;
} else {
check_access(f, filename);
- if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ if (scan_authfile(f, user, our_name, remote,
+ secret, &addrs, filename) < 0
|| (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0)
&& strcmp(crypt(passwd, secret), secret) != 0)) {
- syslog(LOG_WARNING, "upap authentication failure for %s", user);
+ syslog(LOG_WARNING, "PAP authentication failure for %s", user);
ret = UPAP_AUTHNAK;
}
fclose(f);
@@ -434,12 +657,13 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
if (uselogin && ret == UPAP_AUTHACK) {
ret = ppplogin(user, passwd, msg, msglen);
if (ret == UPAP_AUTHNAK) {
- syslog(LOG_WARNING, "upap login failure for %s", user);
+ syslog(LOG_WARNING, "PAP login failure for %s", user);
}
}
if (ret == UPAP_AUTHNAK) {
- *msg = "Login incorrect";
+ if (*msg == (char *) 0)
+ *msg = "Login incorrect";
*msglen = strlen(*msg);
/*
* Frustrate passwd stealer programs.
@@ -458,17 +682,18 @@ check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
} else {
attempts = 0; /* Reset count */
- *msg = "Login ok";
+ if (*msg == (char *) 0)
+ *msg = "Login ok";
*msglen = strlen(*msg);
- if (addresses[unit] != NULL)
- free_wordlist(addresses[unit]);
- addresses[unit] = addrs;
+ set_allowed_addrs(unit, addrs);
}
+ BZERO(passwd, sizeof(passwd));
+ BZERO(secret, sizeof(secret));
+
return ret;
}
-
/*
* Check if an "entry" is in the file "fname" - used by ppplogin.
* Taken from libexec/ftpd/ftpd.c
@@ -501,6 +726,18 @@ checkfile(fname, name)
return (found);
}
+/*
+ * This function is needed for PAM. However, it should not be called.
+ * If it is, return the error code.
+ */
+
+#ifdef USE_PAM
+static int pam_conv(int num_msg, const struct pam_message **msg,
+ struct pam_response **resp, void *appdata_ptr)
+{
+ return PAM_CONV_ERR;
+}
+#endif
/*
* ppplogin - Check the user name and password against the system
@@ -513,6 +750,7 @@ checkfile(fname, name)
*
* UPAP_AUTHACK should only be returned *after* wtmp and utmp are updated.
*/
+
static int
ppplogin(user, passwd, msg, msglen)
char *user;
@@ -520,21 +758,65 @@ ppplogin(user, passwd, msg, msglen)
char **msg;
int *msglen;
{
- struct utmp utmp;
+ char *tty;
+
+#ifdef USE_PAM
+ struct pam_conv pam_conversation;
+ pam_handle_t *pamh;
+ int pam_error;
+ char *pass;
+ char *dev;
+/*
+ * Fill the pam_conversion structure
+ */
+ memset (&pam_conversation, '\0', sizeof (struct pam_conv));
+ pam_conversation.conv = &pam_conv;
+
+ pam_error = pam_start ("ppp", user, &pam_conversation, &pamh);
+ if (pam_error != PAM_SUCCESS) {
+ *msg = (char *) pam_strerror (pam_error);
+ return UPAP_AUTHNAK;
+ }
+/*
+ * Define the fields for the credintial validation
+ */
+ (void) pam_set_item (pamh, PAM_AUTHTOK, passwd);
+ (void) pam_set_item (pamh, PAM_TTY, devnam);
+/*
+ * Validate the user
+ */
+ pam_error = pam_authenticate (pamh, PAM_SILENT);
+ if (pam_error == PAM_SUCCESS)
+ pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
+
+ *msg = (char *) pam_strerror (pam_error);
+/*
+ * Clean up the mess
+ */
+ (void) pam_end (pamh, pam_error);
+
+ if (pam_error != PAM_SUCCESS)
+ return UPAP_AUTHNAK;
+/*
+ * Use the non-PAM methods directly
+ */
+#else /* #ifdef USE_PAM */
+
struct passwd *pw;
+ struct utmp utmp;
struct timeval tp;
char *epasswd;
- char *tty;
#ifdef HAS_SHADOW
struct spwd *spwd;
struct spwd *getspnam();
+ extern int isexpired (struct passwd *, struct spwd *); /* in libshadow.a */
#endif
- if ((pw = getpwnam(user)) == NULL) {
+ pw = getpwnam(user);
+ if (pw == NULL) {
return (UPAP_AUTHNAK);
}
-
/*
* Check that the user is not listed in /etc/ppp/ppp.deny
* and that the user's shell is listed in /etc/ppp/ppp.shells
@@ -554,15 +836,20 @@ ppplogin(user, passwd, msg, msglen)
}
#ifdef HAS_SHADOW
- if ((spwd = getspnam(user)) == NULL) {
- pw->pw_passwd = "";
- } else {
+ spwd = getspnam(user);
+ endspent();
+ if (spwd) {
+ /* check the age of the password entry */
+ if (isexpired(pw, spwd)) {
+ syslog(LOG_WARNING,"Expired password for %s",user);
+ return (UPAP_AUTHNAK);
+ }
pw->pw_passwd = spwd->sp_pwdp;
}
#endif
/*
- * If there is a password, check it.
+ * If no passwd, don't let them login.
*/
if (pw->pw_passwd[0] != '\0') {
@@ -587,6 +874,7 @@ ppplogin(user, passwd, msg, msglen)
}
}
} /* if password */
+#endif /* #ifdef USE_PAM */
syslog(LOG_INFO, "user %s logged in", user);
@@ -596,6 +884,7 @@ ppplogin(user, passwd, msg, msglen)
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
+ logwtmp(tty, user, remote_name); /* Add wtmp login entry */
logged_in = TRUE;
memset((void *)&utmp, 0, sizeof(utmp));
@@ -642,7 +931,7 @@ null_login(unit)
char secret[MAXWORDLEN];
/*
- * Open the file of upap secrets and scan for a suitable secret.
+ * Open the file of pap secrets and scan for a suitable secret.
* We don't accept a wildcard client.
*/
filename = _PATH_UPAPFILE;
@@ -652,14 +941,14 @@ null_login(unit)
return 0;
check_access(f, filename);
- i = scan_authfile(f, "", our_name, secret, &addrs, filename);
+ i = scan_authfile(f, "", our_name, (u_int32_t)0, secret, &addrs, filename);
ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0;
+ BZERO(secret, sizeof(secret));
- if (ret) {
- if (addresses[unit] != NULL)
- free_wordlist(addresses[unit]);
- addresses[unit] = addrs;
- }
+ if (ret)
+ set_allowed_addrs(unit, addrs);
+ else
+ free_wordlist(addrs);
fclose(f);
return ret;
@@ -667,12 +956,13 @@ null_login(unit)
/*
- * get_upap_passwd - get a password for authenticating ourselves with
+ * get_pap_passwd - get a password for authenticating ourselves with
* our peer using PAP. Returns 1 on success, 0 if no suitable password
* could be found.
*/
static int
-get_upap_passwd()
+get_pap_passwd(passwd)
+ char *passwd;
{
char *filename;
FILE *f;
@@ -685,31 +975,39 @@ get_upap_passwd()
if (f == NULL)
return 0;
check_access(f, filename);
- if (scan_authfile(f, user, remote_name, secret, NULL, filename) < 0)
+ if (scan_authfile(f, user,
+ remote_name[0]? remote_name: NULL,
+ (u_int32_t)0, secret, NULL, filename) < 0)
return 0;
- strncpy(passwd, secret, MAXSECRETLEN);
- passwd[MAXSECRETLEN-1] = 0;
+ if (passwd != NULL) {
+ strncpy(passwd, secret, MAXSECRETLEN);
+ passwd[MAXSECRETLEN-1] = 0;
+ }
+ BZERO(secret, sizeof(secret));
return 1;
}
/*
- * have_upap_secret - check whether we have a PAP file with any
+ * have_pap_secret - check whether we have a PAP file with any
* secrets that we could possibly use for authenticating the peer.
*/
static int
-have_upap_secret()
+have_pap_secret()
{
FILE *f;
int ret;
char *filename;
+ ipcp_options *ipwo = &ipcp_wantoptions[0];
+ u_int32_t remote;
filename = _PATH_UPAPFILE;
f = fopen(filename, "r");
if (f == NULL)
return 0;
- ret = scan_authfile(f, NULL, our_name, NULL, NULL, filename);
+ remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+ ret = scan_authfile(f, NULL, our_name, remote, NULL, NULL, filename);
fclose(f);
if (ret < 0)
return 0;
@@ -725,9 +1023,10 @@ have_upap_secret()
* know the identity yet.
*/
static int
-have_chap_secret(client, server)
+have_chap_secret(client, server, remote)
char *client;
char *server;
+ u_int32_t remote;
{
FILE *f;
int ret;
@@ -743,7 +1042,7 @@ have_chap_secret(client, server)
else if (server[0] == 0)
server = NULL;
- ret = scan_authfile(f, client, server, NULL, NULL, filename);
+ ret = scan_authfile(f, client, server, remote, NULL, NULL, filename);
fclose(f);
if (ret < 0)
return 0;
@@ -783,16 +1082,14 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
}
check_access(f, filename);
- ret = scan_authfile(f, client, server, secbuf, &addrs, filename);
+ ret = scan_authfile(f, client, server, (u_int32_t)0,
+ secbuf, &addrs, filename);
fclose(f);
if (ret < 0)
return 0;
- if (save_addrs) {
- if (addresses[unit] != NULL)
- free_wordlist(addresses[unit]);
- addresses[unit] = addrs;
- }
+ if (save_addrs)
+ set_allowed_addrs(unit, addrs);
len = strlen(secbuf);
if (len > MAXSECRETLEN) {
@@ -800,32 +1097,47 @@ get_secret(unit, client, server, secret, secret_len, save_addrs)
len = MAXSECRETLEN;
}
BCOPY(secbuf, secret, len);
+ BZERO(secbuf, sizeof(secbuf));
*secret_len = len;
return 1;
}
-
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ */
static void
-auth_set_ip_addr(unit)
+set_allowed_addrs(unit, addrs)
int unit;
-{
struct wordlist *addrs;
+{
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
- if (non_wildclient && (addrs = addresses[unit]) != NULL) {
- for (; addrs != NULL; addrs = addrs->next) {
- /*
- * Look for address overrides, and set them if we have any
- */
- if (strchr(addrs->word, ':') != NULL) {
- if (setipaddr(addrs->word))
- break;
- }
+ /*
+ * If there's only one authorized address we might as well
+ * ask our peer for that one right away
+ */
+ if (addrs != NULL && addrs->next == NULL) {
+ char *p = addrs->word;
+ struct ipcp_options *wo = &ipcp_wantoptions[unit];
+ u_int32_t a;
+ struct hostent *hp;
+
+ if (wo->hisaddr == 0 && *p != '!' && *p != '-'
+ && strchr(p, '/') == NULL) {
+ hp = gethostbyname(p);
+ if (hp != NULL && hp->h_addrtype == AF_INET)
+ a = *(u_int32_t *)hp->h_addr;
+ else
+ a = inet_addr(p);
+ if (a != (u_int32_t) -1)
+ wo->hisaddr = a;
}
}
}
-
/*
* auth_ip_addr - check whether the peer is authorized to use
* a given IP address. Returns 1 if authorized, 0 otherwise.
@@ -835,40 +1147,93 @@ auth_ip_addr(unit, addr)
int unit;
u_int32_t addr;
{
- int x, y;
- u_int32_t a;
- struct hostent *hp;
+ return ip_addr_check(addr, addresses[unit]);
+}
+
+static int
+ip_addr_check(addr, addrs)
+ u_int32_t addr;
struct wordlist *addrs;
+{
+ u_int32_t a, mask, ah;
+ int accept;
+ char *ptr_word, *ptr_mask;
+ struct hostent *hp;
+ struct netent *np;
/* don't allow loopback or multicast address */
if (bad_ip_adrs(addr))
return 0;
- x = y = 0;
- for (addrs = addresses[unit]; addrs != NULL; addrs = addrs->next, y++) {
- /* "-" means no addresses authorized */
- if (strcmp(addrs->word, "-") == 0)
+ if (addrs == NULL)
+ return !auth_required; /* no addresses authorized */
+
+ for (; addrs != NULL; addrs = addrs->next) {
+ /* "-" means no addresses authorized, "*" means any address allowed */
+ ptr_word = addrs->word;
+ if (strcmp(ptr_word, "-") == 0)
break;
- /*
- * A colon in the string means that we wish to force a specific
- * local:remote address, but we ignore these for now
- */
- if (strchr(addrs->word, ':') != NULL)
- x++;
- else {
- if ((a = inet_addr(addrs->word)) == -1) {
- if ((hp = gethostbyname(addrs->word)) == NULL) {
- syslog(LOG_WARNING, "unknown host %s in auth. address list",
- addrs->word);
- continue;
- } else
- a = *(u_int32_t *)hp->h_addr;
+ if (strcmp(ptr_word, "*") == 0)
+ return 1;
+
+ accept = 1;
+ if (*ptr_word == '!') {
+ accept = 0;
+ ++ptr_word;
+ }
+
+ mask = ~ (u_int32_t) 0;
+ ptr_mask = strchr (ptr_word, '/');
+ if (ptr_mask != NULL) {
+ int bit_count;
+
+ bit_count = (int) strtol (ptr_mask+1, (char **) 0, 10);
+ if (bit_count <= 0 || bit_count > 32) {
+ syslog (LOG_WARNING,
+ "invalid address length %s in auth. address list",
+ ptr_mask);
+ continue;
+ }
+ *ptr_mask = '\0';
+ mask <<= 32 - bit_count;
+ }
+
+ hp = gethostbyname(ptr_word);
+ if (hp != NULL && hp->h_addrtype == AF_INET) {
+ a = *(u_int32_t *)hp->h_addr;
+ } else {
+ np = getnetbyname (ptr_word);
+ if (np != NULL && np->n_addrtype == AF_INET) {
+ a = htonl (*(u_int32_t *)np->n_net);
+ if (ptr_mask == NULL) {
+ /* calculate appropriate mask for net */
+ ah = ntohl(a);
+ if (IN_CLASSA(ah))
+ mask = IN_CLASSA_NET;
+ else if (IN_CLASSB(ah))
+ mask = IN_CLASSB_NET;
+ else if (IN_CLASSC(ah))
+ mask = IN_CLASSC_NET;
+ }
+ } else {
+ a = inet_addr (ptr_word);
}
- if (addr == a)
- return 1;
}
+
+ if (ptr_mask != NULL)
+ *ptr_mask = '/';
+
+ if (a == (u_int32_t)-1L)
+ syslog (LOG_WARNING,
+ "unknown host %s in auth. address list",
+ addrs->word);
+ else
+ /* Here a and addr are in network byte order,
+ and mask is in host order. */
+ if (((addr ^ a) & htonl(mask)) == 0)
+ return accept;
}
- return x == y; /* not in list => can't have it */
+ return 0; /* not in list => can't have it */
}
/*
@@ -913,10 +1278,11 @@ check_access(f, filename)
* info) are placed in a wordlist and returned in *addrs.
*/
static int
-scan_authfile(f, client, server, secret, addrs, filename)
+scan_authfile(f, client, server, ipaddr, secret, addrs, filename)
FILE *f;
char *client;
char *server;
+ u_int32_t ipaddr;
char *secret;
struct wordlist **addrs;
char *filename;
@@ -924,9 +1290,10 @@ scan_authfile(f, client, server, secret, addrs, filename)
int newline, xxx;
int got_flag, best_flag;
FILE *sf;
- struct wordlist *ap, *addr_list, *addr_last;
+ struct wordlist *ap, *addr_list, *alist, *alast;
char word[MAXWORDLEN];
char atfile[MAXWORDLEN];
+ char lsecret[MAXWORDLEN];
if (addrs != NULL)
*addrs = NULL;
@@ -1002,16 +1369,12 @@ scan_authfile(f, client, server, secret, addrs, filename)
fclose(sf);
}
if (secret != NULL)
- strcpy(secret, word);
-
- best_flag = got_flag;
+ strcpy(lsecret, word);
/*
* Now read address authorization info and make a wordlist.
*/
- if (addr_list)
- free_wordlist(addr_list);
- addr_list = addr_last = NULL;
+ alist = alast = NULL;
for (;;) {
if (!getword(f, word, &newline, filename) || newline)
break;
@@ -1021,12 +1384,31 @@ scan_authfile(f, client, server, secret, addrs, filename)
novm("authorized addresses");
ap->next = NULL;
strcpy(ap->word, word);
- if (addr_list == NULL)
- addr_list = ap;
+ if (alist == NULL)
+ alist = ap;
else
- addr_last->next = ap;
- addr_last = ap;
+ alast->next = ap;
+ alast = ap;
+ }
+
+ /*
+ * Check if the given IP address is allowed by the wordlist.
+ */
+ if (ipaddr != 0 && !ip_addr_check(ipaddr, alist)) {
+ free_wordlist(alist);
+ continue;
}
+
+ /*
+ * This is the best so far; remember it.
+ */
+ best_flag = got_flag;
+ if (addr_list)
+ free_wordlist(addr_list);
+ addr_list = alist;
+ if (secret != NULL)
+ strcpy(secret, lsecret);
+
if (!newline)
break;
}
@@ -1036,7 +1418,6 @@ scan_authfile(f, client, server, secret, addrs, filename)
else if (addr_list != NULL)
free_wordlist(addr_list);
- non_wildclient = (best_flag & NONWILD_CLIENT) && client && *client != '\0';
return best_flag;
}
@@ -1055,3 +1436,36 @@ free_wordlist(wp)
wp = next;
}
}
+
+/*
+ * auth_script - execute a script with arguments
+ * interface-name peer-name real-user tty speed
+ */
+static void
+auth_script(script)
+ char *script;
+{
+ char strspeed[32];
+ struct passwd *pw;
+ char struid[32];
+ char *user_name;
+ char *argv[8];
+
+ if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL)
+ user_name = pw->pw_name;
+ else {
+ sprintf(struid, "%d", getuid());
+ user_name = struid;
+ }
+ sprintf(strspeed, "%d", baud_rate);
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = peer_authname;
+ argv[3] = user_name;
+ argv[4] = devnam;
+ argv[5] = strspeed;
+ argv[6] = NULL;
+
+ run_program(script, argv, 0);
+}
diff --git a/usr.sbin/pppd/cbcp.c b/usr.sbin/pppd/cbcp.c
new file mode 100644
index 0000000..db939ba
--- /dev/null
+++ b/usr.sbin/pppd/cbcp.c
@@ -0,0 +1,430 @@
+/*
+ * cbcp - Call Back Configuration Protocol.
+ *
+ * Copyright (c) 1995 Pedro Roque Marques
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Pedro Roque Marques. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "cbcp.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+
+/*
+ * Protocol entry points.
+ */
+static void cbcp_init __P((int unit));
+static void cbcp_open __P((int unit));
+static void cbcp_lowerup __P((int unit));
+static void cbcp_input __P((int unit, u_char *pkt, int len));
+static void cbcp_protrej __P((int unit));
+static int cbcp_printpkt __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+
+struct protent cbcp_protent = {
+ PPP_CBCP,
+ cbcp_init,
+ cbcp_input,
+ cbcp_protrej,
+ cbcp_lowerup,
+ NULL,
+ cbcp_open,
+ NULL,
+ cbcp_printpkt,
+ NULL,
+ 0,
+ "CBCP",
+ NULL,
+ NULL,
+ NULL
+};
+
+cbcp_state cbcp[NUM_PPP];
+
+/* internal prototypes */
+
+static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_resp __P((cbcp_state *us));
+static void cbcp_up __P((cbcp_state *us));
+static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
+
+/* init state */
+static void
+cbcp_init(iface)
+ int iface;
+{
+ cbcp_state *us;
+
+ us = &cbcp[iface];
+ memset(us, 0, sizeof(cbcp_state));
+ us->us_unit = iface;
+ us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+static void
+cbcp_lowerup(iface)
+ int iface;
+{
+ cbcp_state *us = &cbcp[iface];
+
+ syslog(LOG_DEBUG, "cbcp_lowerup");
+ syslog(LOG_DEBUG, "want: %d", us->us_type);
+
+ if (us->us_type == CB_CONF_USER)
+ syslog(LOG_DEBUG, "phone no: %s", us->us_number);
+}
+
+static void
+cbcp_open(unit)
+ int unit;
+{
+ syslog(LOG_DEBUG, "cbcp_open");
+}
+
+/* process an incomming packet */
+static void
+cbcp_input(unit, inpacket, pktlen)
+ int unit;
+ u_char *inpacket;
+ int pktlen;
+{
+ u_char *inp;
+ u_char code, id;
+ u_short len;
+
+ cbcp_state *us = &cbcp[unit];
+
+ inp = inpacket;
+
+ if (pktlen < CBCP_MINLEN) {
+ syslog(LOG_ERR, "CBCP packet is too small");
+ return;
+ }
+
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+
+#if 0
+ if (len > pktlen) {
+ syslog(LOG_ERR, "CBCP packet: invalid length");
+ return;
+ }
+#endif
+
+ len -= CBCP_MINLEN;
+
+ switch(code) {
+ case CBCP_REQ:
+ us->us_id = id;
+ cbcp_recvreq(us, inp, len);
+ break;
+
+ case CBCP_RESP:
+ syslog(LOG_DEBUG, "CBCP_RESP received");
+ break;
+
+ case CBCP_ACK:
+ if (id != us->us_id)
+ syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
+ us->us_id, id);
+
+ cbcp_recvack(us, inp, len);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {
+ "Request", "Response", "Ack"
+};
+
+char *cbcp_optionnames[] = {
+ "NoCallback",
+ "UserDefined",
+ "AdminDefined",
+ "List"
+};
+
+/* pretty print a packet */
+static int
+cbcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, opt, id, len, olen, delay;
+ u_char *pstart;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+ printer(arg, " %s", cbcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+
+ switch (code) {
+ case CBCP_REQ:
+ case CBCP_RESP:
+ case CBCP_ACK:
+ while(len >= 2) {
+ GETCHAR(opt, p);
+ GETCHAR(olen, p);
+
+ if (olen < 2 || olen > len) {
+ break;
+ }
+
+ printer(arg, " <");
+ len -= olen;
+
+ if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+ printer(arg, " %s", cbcp_optionnames[opt-1]);
+ else
+ printer(arg, " option=0x%x", opt);
+
+ if (olen > 2) {
+ GETCHAR(delay, p);
+ printer(arg, " delay = %d", delay);
+ }
+
+ if (olen > 3) {
+ int addrt;
+ char str[256];
+
+ GETCHAR(addrt, p);
+ memcpy(str, p, olen - 4);
+ str[olen - 4] = 0;
+ printer(arg, " number = %s", str);
+ }
+ printer(arg, ">");
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", code);
+ }
+
+ return p - pstart;
+}
+
+/* received CBCP request */
+static void
+cbcp_recvreq(us, pckt, pcktlen)
+ cbcp_state *us;
+ char *pckt;
+ int pcktlen;
+{
+ u_char type, opt_len, delay, addr_type;
+ char address[256];
+ int len = pcktlen;
+
+ address[0] = 0;
+
+ while (len) {
+ syslog(LOG_DEBUG, "length: %d", len);
+
+ GETCHAR(type, pckt);
+ GETCHAR(opt_len, pckt);
+
+ if (opt_len > 2)
+ GETCHAR(delay, pckt);
+
+ us->us_allowed |= (1 << type);
+
+ switch(type) {
+ case CB_CONF_NO:
+ syslog(LOG_DEBUG, "no callback allowed");
+ break;
+
+ case CB_CONF_USER:
+ syslog(LOG_DEBUG, "user callback allowed");
+ if (opt_len > 4) {
+ GETCHAR(addr_type, pckt);
+ memcpy(address, pckt, opt_len - 4);
+ address[opt_len - 4] = 0;
+ if (address[0])
+ syslog(LOG_DEBUG, "address: %s", address);
+ }
+ break;
+
+ case CB_CONF_ADMIN:
+ syslog(LOG_DEBUG, "user admin defined allowed");
+ break;
+
+ case CB_CONF_LIST:
+ break;
+ }
+ len -= opt_len;
+ }
+
+ cbcp_resp(us);
+}
+
+static void
+cbcp_resp(us)
+ cbcp_state *us;
+{
+ u_char cb_type;
+ u_char buf[256];
+ u_char *bufp = buf;
+ int len = 0;
+
+ cb_type = us->us_allowed & us->us_type;
+ syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+ if (!cb_type)
+ lcp_down(us->us_unit);
+#endif
+
+ if (cb_type & ( 1 << CB_CONF_USER ) ) {
+ syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
+ PUTCHAR(CB_CONF_USER, bufp);
+ len = 3 + 1 + strlen(us->us_number) + 1;
+ PUTCHAR(len , bufp);
+ PUTCHAR(5, bufp); /* delay */
+ PUTCHAR(1, bufp);
+ BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+ cbcp_send(us, CBCP_RESP, buf, len);
+ return;
+ }
+
+ if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
+ syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
+ PUTCHAR(CB_CONF_ADMIN, bufp);
+ len = 3 + 1;
+ PUTCHAR(len , bufp);
+ PUTCHAR(5, bufp); /* delay */
+ PUTCHAR(0, bufp);
+ cbcp_send(us, CBCP_RESP, buf, len);
+ return;
+ }
+
+ if (cb_type & ( 1 << CB_CONF_NO ) ) {
+ syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
+ PUTCHAR(CB_CONF_NO, bufp);
+ len = 3;
+ PUTCHAR(len , bufp);
+ PUTCHAR(0, bufp);
+ cbcp_send(us, CBCP_RESP, buf, len);
+ (*ipcp_protent.open)(us->us_unit);
+ return;
+ }
+}
+
+static void
+cbcp_send(us, code, buf, len)
+ cbcp_state *us;
+ u_char code;
+ u_char *buf;
+ int len;
+{
+ u_char *outp;
+ int outlen;
+
+ outp = outpacket_buf;
+
+ outlen = 4 + len;
+
+ MAKEHEADER(outp, PPP_CBCP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(us->us_id, outp);
+ PUTSHORT(outlen, outp);
+
+ if (len)
+ BCOPY(buf, outp, len);
+
+ output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+static void
+cbcp_recvack(us, pckt, len)
+ cbcp_state *us;
+ char *pckt;
+ int len;
+{
+ u_char type, delay, addr_type;
+ int opt_len;
+ char address[256];
+
+ if (len) {
+ GETCHAR(type, pckt);
+ GETCHAR(opt_len, pckt);
+
+ if (opt_len > 2)
+ GETCHAR(delay, pckt);
+
+ if (opt_len > 4) {
+ GETCHAR(addr_type, pckt);
+ memcpy(address, pckt, opt_len - 4);
+ address[opt_len - 4] = 0;
+ if (address[0])
+ syslog(LOG_DEBUG, "peer will call: %s", address);
+ }
+ }
+
+ cbcp_up(us);
+}
+
+extern int persist;
+
+/* ok peer will do callback */
+static void
+cbcp_up(us)
+ cbcp_state *us;
+{
+ persist = 0;
+ lcp_close(0, "Call me back, please");
+}
diff --git a/usr.sbin/pppd/cbcp.h b/usr.sbin/pppd/cbcp.h
new file mode 100644
index 0000000..c2ab3f6
--- /dev/null
+++ b/usr.sbin/pppd/cbcp.h
@@ -0,0 +1,26 @@
+#ifndef CBCP_H
+#define CBCP_H
+
+typedef struct cbcp_state {
+ int us_unit; /* Interface unit number */
+ u_char us_id; /* Current id */
+ u_char us_allowed;
+ int us_type;
+ char *us_number; /* Telefone Number */
+} cbcp_state;
+
+extern cbcp_state cbcp[];
+
+extern struct protent cbcp_protent;
+
+#define CBCP_MINLEN 4
+
+#define CBCP_REQ 1
+#define CBCP_RESP 2
+#define CBCP_ACK 3
+
+#define CB_CONF_NO 1
+#define CB_CONF_USER 2
+#define CB_CONF_ADMIN 3
+#define CB_CONF_LIST 4
+#endif
diff --git a/usr.sbin/pppd/ccp.c b/usr.sbin/pppd/ccp.c
index 3035039..000d916 100644
--- a/usr.sbin/pppd/ccp.c
+++ b/usr.sbin/pppd/ccp.c
@@ -29,14 +29,50 @@
static char rcsid[] = "$Id$";
#endif
+#include <string.h>
#include <syslog.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/ppp_defs.h>
#include <net/ppp_comp.h>
#include "pppd.h"
#include "fsm.h"
#include "ccp.h"
+/*
+ * Protocol entry points from main code.
+ */
+static void ccp_init __P((int unit));
+static void ccp_open __P((int unit));
+static void ccp_close __P((int unit, char *));
+static void ccp_lowerup __P((int unit));
+static void ccp_lowerdown __P((int));
+static void ccp_input __P((int unit, u_char *pkt, int len));
+static void ccp_protrej __P((int unit));
+static int ccp_printpkt __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+static void ccp_datainput __P((int unit, u_char *pkt, int len));
+
+struct protent ccp_protent = {
+ PPP_CCP,
+ ccp_init,
+ ccp_input,
+ ccp_protrej,
+ ccp_lowerup,
+ ccp_lowerdown,
+ ccp_open,
+ ccp_close,
+ ccp_printpkt,
+ ccp_datainput,
+ 1,
+ "CCP",
+ NULL,
+ NULL,
+ NULL
+};
+
fsm ccp_fsm[NUM_PPP];
ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */
ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */
@@ -56,7 +92,8 @@ static int ccp_reqci __P((fsm *, u_char *, int *, int));
static void ccp_up __P((fsm *));
static void ccp_down __P((fsm *));
static int ccp_extcode __P((fsm *, int, int, u_char *, int));
-static void ccp_rack_timeout __P(());
+static void ccp_rack_timeout __P((void *));
+static char *method_name __P((ccp_options *, ccp_options *));
static fsm_callbacks ccp_callbacks = {
ccp_resetci,
@@ -79,10 +116,11 @@ static fsm_callbacks ccp_callbacks = {
/*
* Do we want / did we get any compression?
*/
-#define ANY_COMPRESS(opt) ((opt).bsd_compress)
+#define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \
+ || (opt).predictor_1 || (opt).predictor_2)
/*
- * Local state (mainly for handling reset-reqs and reset-acks
+ * Local state (mainly for handling reset-reqs and reset-acks).
*/
static int ccp_localstate[NUM_PPP];
#define RACK_PENDING 1 /* waiting for reset-ack */
@@ -90,10 +128,12 @@ static int ccp_localstate[NUM_PPP];
#define RACKTIMEOUT 1 /* second */
+static int all_rejected[NUM_PPP]; /* we rejected all peer's options */
+
/*
* ccp_init - initialize CCP.
*/
-void
+static void
ccp_init(unit)
int unit;
{
@@ -109,17 +149,23 @@ ccp_init(unit)
memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options));
- ccp_wantoptions[0].bsd_compress = 1;
- ccp_wantoptions[0].bsd_bits = 12; /* default value */
+ ccp_wantoptions[0].deflate = 1;
+ ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_allowoptions[0].deflate = 1;
+ ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+ ccp_wantoptions[0].bsd_compress = 1;
+ ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
ccp_allowoptions[0].bsd_compress = 1;
ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+
+ ccp_allowoptions[0].predictor_1 = 1;
}
/*
* ccp_open - CCP is allowed to come up.
*/
-void
+static void
ccp_open(unit)
int unit;
{
@@ -127,26 +173,34 @@ ccp_open(unit)
if (f->state != OPENED)
ccp_flags_set(unit, 1, 0);
- if (!ANY_COMPRESS(ccp_wantoptions[unit]))
+
+ /*
+ * Find out which compressors the kernel supports before
+ * deciding whether to open in silent mode.
+ */
+ ccp_resetci(f);
+ if (!ANY_COMPRESS(ccp_gotoptions[unit]))
f->flags |= OPT_SILENT;
+
fsm_open(f);
}
/*
* ccp_close - Terminate CCP.
*/
-void
-ccp_close(unit)
+static void
+ccp_close(unit, reason)
int unit;
+ char *reason;
{
ccp_flags_set(unit, 0, 0);
- fsm_close(&ccp_fsm[unit]);
+ fsm_close(&ccp_fsm[unit], reason);
}
/*
* ccp_lowerup - we may now transmit CCP packets.
*/
-void
+static void
ccp_lowerup(unit)
int unit;
{
@@ -156,7 +210,7 @@ ccp_lowerup(unit)
/*
* ccp_lowerdown - we may not transmit CCP packets.
*/
-void
+static void
ccp_lowerdown(unit)
int unit;
{
@@ -166,7 +220,7 @@ ccp_lowerdown(unit)
/*
* ccp_input - process a received CCP packet.
*/
-void
+static void
ccp_input(unit, p, len)
int unit;
u_char *p;
@@ -189,7 +243,7 @@ ccp_input(unit, p, len)
*/
if (oldstate == REQSENT && p[0] == TERMACK
&& !ANY_COMPRESS(ccp_gotoptions[unit]))
- ccp_close(unit);
+ ccp_close(unit, "No compression negotiated");
}
/*
@@ -214,7 +268,7 @@ ccp_extcode(f, code, id, p, len)
case CCP_RESETACK:
if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
- UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
+ UNTIMEOUT(ccp_rack_timeout, f);
}
break;
@@ -228,7 +282,7 @@ ccp_extcode(f, code, id, p, len)
/*
* ccp_protrej - peer doesn't talk CCP.
*/
-void
+static void
ccp_protrej(unit)
int unit;
{
@@ -247,13 +301,39 @@ ccp_resetci(f)
u_char opt_buf[16];
*go = ccp_wantoptions[f->unit];
+ all_rejected[f->unit] = 0;
+
+ /*
+ * Check whether the kernel knows about the various
+ * compression methods we might request.
+ */
if (go->bsd_compress) {
opt_buf[0] = CI_BSD_COMPRESS;
opt_buf[1] = CILEN_BSD_COMPRESS;
- opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
- if (!ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0))
+ opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
+ if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
go->bsd_compress = 0;
}
+ if (go->deflate) {
+ opt_buf[0] = CI_DEFLATE;
+ opt_buf[1] = CILEN_DEFLATE;
+ opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
+ opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+ if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+ go->deflate = 0;
+ }
+ if (go->predictor_1) {
+ opt_buf[0] = CI_PREDICTOR_1;
+ opt_buf[1] = CILEN_PREDICTOR_1;
+ if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
+ go->predictor_1 = 0;
+ }
+ if (go->predictor_2) {
+ opt_buf[0] = CI_PREDICTOR_2;
+ opt_buf[1] = CILEN_PREDICTOR_2;
+ if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
+ go->predictor_2 = 0;
+ }
}
/*
@@ -265,7 +345,10 @@ ccp_cilen(f)
{
ccp_options *go = &ccp_gotoptions[f->unit];
- return (go->bsd_compress? CILEN_BSD_COMPRESS: 0);
+ return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
+ + (go->deflate? CILEN_DEFLATE: 0)
+ + (go->predictor_1? CILEN_PREDICTOR_1: 0)
+ + (go->predictor_2? CILEN_PREDICTOR_2: 0);
}
/*
@@ -277,18 +360,78 @@ ccp_addci(f, p, lenp)
u_char *p;
int *lenp;
{
+ int res;
ccp_options *go = &ccp_gotoptions[f->unit];
u_char *p0 = p;
+ /*
+ * Add the compression types that we can receive, in decreasing
+ * preference order. Get the kernel to allocate the first one
+ * in case it gets Acked.
+ */
+ if (go->deflate) {
+ p[0] = CI_DEFLATE;
+ p[1] = CILEN_DEFLATE;
+ p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+ if (res > 0) {
+ p += CILEN_DEFLATE;
+ break;
+ }
+ if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
+ go->deflate = 0;
+ break;
+ }
+ --go->deflate_size;
+ p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+ }
+ }
if (go->bsd_compress) {
p[0] = CI_BSD_COMPRESS;
p[1] = CILEN_BSD_COMPRESS;
p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
- if (ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0))
- p += CILEN_BSD_COMPRESS;
- else
- go->bsd_compress = 0;
+ if (p != p0) {
+ p += CILEN_BSD_COMPRESS; /* not the first option */
+ } else {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
+ if (res > 0) {
+ p += CILEN_BSD_COMPRESS;
+ break;
+ }
+ if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+ go->bsd_compress = 0;
+ break;
+ }
+ --go->bsd_bits;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+ }
+ }
+ }
+ /* XXX Should Predictor 2 be preferable to Predictor 1? */
+ if (go->predictor_1) {
+ p[0] = CI_PREDICTOR_1;
+ p[1] = CILEN_PREDICTOR_1;
+ if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
+ go->predictor_1 = 0;
+ } else {
+ p += CILEN_PREDICTOR_1;
+ }
}
+ if (go->predictor_2) {
+ p[0] = CI_PREDICTOR_2;
+ p[1] = CILEN_PREDICTOR_2;
+ if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
+ go->predictor_2 = 0;
+ } else {
+ p += CILEN_PREDICTOR_2;
+ }
+ }
+
+ go->method = (p > p0)? p0[0]: -1;
+
*lenp = p - p0;
}
@@ -303,7 +446,20 @@ ccp_ackci(f, p, len)
int len;
{
ccp_options *go = &ccp_gotoptions[f->unit];
+ u_char *p0 = p;
+ if (go->deflate) {
+ if (len < CILEN_DEFLATE
+ || p[0] != CI_DEFLATE || p[1] != CILEN_DEFLATE
+ || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ /* XXX Cope with first/fast ack */
+ if (len == 0)
+ return 1;
+ }
if (go->bsd_compress) {
if (len < CILEN_BSD_COMPRESS
|| p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
@@ -311,7 +467,31 @@ ccp_ackci(f, p, len)
return 0;
p += CILEN_BSD_COMPRESS;
len -= CILEN_BSD_COMPRESS;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
+ }
+ if (go->predictor_1) {
+ if (len < CILEN_PREDICTOR_1
+ || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
+ return 0;
+ p += CILEN_PREDICTOR_1;
+ len -= CILEN_PREDICTOR_1;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
}
+ if (go->predictor_2) {
+ if (len < CILEN_PREDICTOR_2
+ || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
+ return 0;
+ p += CILEN_PREDICTOR_2;
+ len -= CILEN_PREDICTOR_2;
+ /* XXX Cope with first/fast ack */
+ if (p == p0 && len == 0)
+ return 1;
+ }
+
if (len != 0)
return 0;
return 1;
@@ -334,7 +514,24 @@ ccp_nakci(f, p, len)
memset(&no, 0, sizeof(no));
try = *go;
- if (go->bsd_compress && !no.bsd_compress && len >= CILEN_BSD_COMPRESS
+ if (go->deflate && len >= CILEN_DEFLATE
+ && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
+ no.deflate = 1;
+ /*
+ * Peer wants us to use a different code size or something.
+ * Stop asking for Deflate if we don't understand his suggestion.
+ */
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+ || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ try.deflate = 0;
+ else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
+ try.deflate_size = DEFLATE_SIZE(p[2]);
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
+
+ if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
no.bsd_compress = 1;
/*
@@ -350,7 +547,9 @@ ccp_nakci(f, p, len)
}
/*
- * Have a look at any remaining options...???
+ * Predictor-1 and 2 have no options, so they can't be Naked.
+ *
+ * XXX What should we do with any remaining options?
*/
if (len != 0)
@@ -375,6 +574,22 @@ ccp_rejci(f, p, len)
try = *go;
+ /*
+ * Cope with empty configure-rejects by ceasing to send
+ * configure-requests.
+ */
+ if (len == 0 && all_rejected[f->unit])
+ return -1;
+
+ if (go->deflate && len >= CILEN_DEFLATE
+ && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
+ if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+ || p[3] != DEFLATE_CHK_SEQUENCE)
+ return 0; /* Rej is bad */
+ try.deflate = 0;
+ p += CILEN_DEFLATE;
+ len -= CILEN_DEFLATE;
+ }
if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
@@ -383,6 +598,18 @@ ccp_rejci(f, p, len)
p += CILEN_BSD_COMPRESS;
len -= CILEN_BSD_COMPRESS;
}
+ if (go->predictor_1 && len >= CILEN_PREDICTOR_1
+ && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
+ try.predictor_1 = 0;
+ p += CILEN_PREDICTOR_1;
+ len -= CILEN_PREDICTOR_1;
+ }
+ if (go->predictor_2 && len >= CILEN_PREDICTOR_2
+ && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
+ try.predictor_2 = 0;
+ p += CILEN_PREDICTOR_2;
+ len -= CILEN_PREDICTOR_2;
+ }
if (len != 0)
return 0;
@@ -405,7 +632,7 @@ ccp_reqci(f, p, lenp, dont_nak)
int *lenp;
int dont_nak;
{
- int ret, newret;
+ int ret, newret, res;
u_char *p0, *retp;
int len, clen, type, nb;
ccp_options *ho = &ccp_hisoptions[f->unit];
@@ -416,6 +643,7 @@ ccp_reqci(f, p, lenp, dont_nak)
len = *lenp;
memset(ho, 0, sizeof(ccp_options));
+ ho->method = (len > 0)? p[0]: -1;
while (len > 0) {
newret = CONFACK;
@@ -429,6 +657,49 @@ ccp_reqci(f, p, lenp, dont_nak)
clen = p[1];
switch (type) {
+ case CI_DEFLATE:
+ if (!ao->deflate || clen != CILEN_DEFLATE) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->deflate = 1;
+ ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+ || p[3] != DEFLATE_CHK_SEQUENCE
+ || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) {
+ newret = CONFNAK;
+ if (!dont_nak) {
+ p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
+ p[3] = DEFLATE_CHK_SEQUENCE;
+ /* fall through to test this #bits below */
+ } else
+ break;
+ }
+
+ /*
+ * Check whether we can do Deflate with the window
+ * size they want. If the window is too big, reduce
+ * it until the kernel can cope and nak with that.
+ * We only check this for the first option.
+ */
+ if (p == p0) {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
+ if (res > 0)
+ break; /* it's OK now */
+ if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) {
+ newret = CONFREJ;
+ p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
+ break;
+ }
+ newret = CONFNAK;
+ --nb;
+ p[2] = DEFLATE_MAKE_OPT(nb);
+ }
+ }
+ break;
+
case CI_BSD_COMPRESS:
if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
newret = CONFREJ;
@@ -438,22 +709,63 @@ ccp_reqci(f, p, lenp, dont_nak)
ho->bsd_compress = 1;
ho->bsd_bits = nb = BSD_NBITS(p[2]);
if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
- || nb > ao->bsd_bits) {
+ || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
newret = CONFNAK;
- nb = ao->bsd_bits;
- } else if (nb < BSD_MIN_BITS) {
- newret = CONFREJ;
- } else if (!ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1)) {
- if (nb > BSD_MIN_BITS) {
- --nb;
- newret = CONFNAK;
+ if (!dont_nak) {
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
+ /* fall through to test this #bits below */
} else
- newret = CONFREJ;
+ break;
+ }
+
+ /*
+ * Check whether we can do BSD-Compress with the code
+ * size they want. If the code size is too big, reduce
+ * it until the kernel can cope and nak with that.
+ * We only check this for the first option.
+ */
+ if (p == p0) {
+ for (;;) {
+ res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
+ if (res > 0)
+ break;
+ if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
+ newret = CONFREJ;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
+ ho->bsd_bits);
+ break;
+ }
+ newret = CONFNAK;
+ --nb;
+ p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+ }
+ }
+ break;
+
+ case CI_PREDICTOR_1:
+ if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
+ newret = CONFREJ;
+ break;
+ }
+
+ ho->predictor_1 = 1;
+ if (p == p0
+ && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
+ newret = CONFREJ;
}
- if (newret == CONFNAK && !dont_nak) {
- p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+ break;
+
+ case CI_PREDICTOR_2:
+ if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
+ newret = CONFREJ;
+ break;
}
+ ho->predictor_2 = 1;
+ if (p == p0
+ && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
+ newret = CONFREJ;
+ }
break;
default:
@@ -463,7 +775,7 @@ ccp_reqci(f, p, lenp, dont_nak)
if (newret == CONFNAK && dont_nak)
newret = CONFREJ;
- if (!(newret == CONFACK || newret == CONFNAK && ret == CONFREJ)) {
+ if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
/* we're returning this option */
if (newret == CONFREJ && ret == CONFNAK)
retp = p0;
@@ -477,13 +789,53 @@ ccp_reqci(f, p, lenp, dont_nak)
len -= clen;
}
- if (ret != CONFACK)
- *lenp = retp - p0;
+ if (ret != CONFACK) {
+ if (ret == CONFREJ && *lenp == retp - p0)
+ all_rejected[f->unit] = 1;
+ else
+ *lenp = retp - p0;
+ }
return ret;
}
/*
- * CCP has come up - inform the kernel driver.
+ * Make a string name for a compression method (or 2).
+ */
+static char *
+method_name(opt, opt2)
+ ccp_options *opt, *opt2;
+{
+ static char result[64];
+
+ if (!ANY_COMPRESS(*opt))
+ return "(none)";
+ switch (opt->method) {
+ case CI_DEFLATE:
+ if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+ sprintf(result, "Deflate (%d/%d)", opt->deflate_size,
+ opt2->deflate_size);
+ else
+ sprintf(result, "Deflate (%d)", opt->deflate_size);
+ break;
+ case CI_BSD_COMPRESS:
+ if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
+ sprintf(result, "BSD-Compress (%d/%d)", opt->bsd_bits,
+ opt2->bsd_bits);
+ else
+ sprintf(result, "BSD-Compress (%d)", opt->bsd_bits);
+ break;
+ case CI_PREDICTOR_1:
+ return "Predictor 1";
+ case CI_PREDICTOR_2:
+ return "Predictor 2";
+ default:
+ sprintf(result, "Method %d", opt->method);
+ }
+ return result;
+}
+
+/*
+ * CCP has come up - inform the kernel driver and log a message.
*/
static void
ccp_up(f)
@@ -491,16 +843,25 @@ ccp_up(f)
{
ccp_options *go = &ccp_gotoptions[f->unit];
ccp_options *ho = &ccp_hisoptions[f->unit];
+ char method1[64];
ccp_flags_set(f->unit, 1, 1);
- if (go->bsd_compress || ho->bsd_compress)
- syslog(LOG_NOTICE, "%s enabled",
- go->bsd_compress? ho->bsd_compress? "Compression":
- "Receive compression": "Transmit compression");
- if (!ANY_COMPRESS(ccp_gotoptions[f->unit])) {
- syslog(LOG_NOTICE, "No matching compression scheme, CCP disabled");
- ccp_close(f->unit);
- }
+ if (ANY_COMPRESS(*go)) {
+ if (ANY_COMPRESS(*ho)) {
+ if (go->method == ho->method) {
+ syslog(LOG_NOTICE, "%s compression enabled",
+ method_name(go, ho));
+ } else {
+ strcpy(method1, method_name(go, NULL));
+ syslog(LOG_NOTICE, "%s / %s compression enabled",
+ method1, method_name(ho, NULL));
+ }
+ } else
+ syslog(LOG_NOTICE, "%s receive compression enabled",
+ method_name(go, NULL));
+ } else if (ANY_COMPRESS(*ho))
+ syslog(LOG_NOTICE, "%s transmit compression enabled",
+ method_name(ho, NULL));
}
/*
@@ -511,7 +872,7 @@ ccp_down(f)
fsm *f;
{
if (ccp_localstate[f->unit] & RACK_PENDING)
- UNTIMEOUT(ccp_rack_timeout, (caddr_t) f);
+ UNTIMEOUT(ccp_rack_timeout, f);
ccp_localstate[f->unit] = 0;
ccp_flags_set(f->unit, 1, 0);
}
@@ -519,14 +880,14 @@ ccp_down(f)
/*
* Print the contents of a CCP packet.
*/
-char *ccp_codenames[] = {
+static char *ccp_codenames[] = {
"ConfReq", "ConfAck", "ConfNak", "ConfRej",
"TermReq", "TermAck", "CodeRej",
NULL, NULL, NULL, NULL, NULL, NULL,
"ResetReq", "ResetAck",
};
-int
+static int
ccp_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
@@ -570,6 +931,16 @@ ccp_printpkt(p, plen, printer, arg)
len -= optlen;
optend = p + optlen;
switch (code) {
+ case CI_DEFLATE:
+ if (optlen >= CILEN_DEFLATE) {
+ printer(arg, "deflate %d", DEFLATE_SIZE(p[2]));
+ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
+ printer(arg, " method %d", DEFLATE_METHOD(p[2]));
+ if (p[3] != DEFLATE_CHK_SEQUENCE)
+ printer(arg, " check %d", p[3]);
+ p += CILEN_DEFLATE;
+ }
+ break;
case CI_BSD_COMPRESS:
if (optlen >= CILEN_BSD_COMPRESS) {
printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
@@ -577,12 +948,33 @@ ccp_printpkt(p, plen, printer, arg)
p += CILEN_BSD_COMPRESS;
}
break;
+ case CI_PREDICTOR_1:
+ if (optlen >= CILEN_PREDICTOR_1) {
+ printer(arg, "predictor 1");
+ p += CILEN_PREDICTOR_1;
+ }
+ break;
+ case CI_PREDICTOR_2:
+ if (optlen >= CILEN_PREDICTOR_2) {
+ printer(arg, "predictor 2");
+ p += CILEN_PREDICTOR_2;
+ }
+ break;
}
while (p < optend)
printer(arg, " %.2x", *p++);
printer(arg, ">");
}
break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ print_string(p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
}
/* dump out the rest of the packet in hex */
@@ -604,7 +996,7 @@ ccp_printpkt(p, plen, printer, arg)
* decompression; if it was, we take CCP down, thus disabling
* compression :-(, otherwise we issue the reset-request.
*/
-void
+static void
ccp_datainput(unit, pkt, len)
int unit;
u_char *pkt;
@@ -619,7 +1011,7 @@ ccp_datainput(unit, pkt, len)
* Disable compression by taking CCP down.
*/
syslog(LOG_ERR, "Lost compression sync: disabling compression");
- ccp_close(unit);
+ ccp_close(unit, "Lost compression sync");
} else {
/*
* Send a reset-request to reset the peer's compressor.
@@ -628,7 +1020,7 @@ ccp_datainput(unit, pkt, len)
*/
if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
- TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
+ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
ccp_localstate[f->unit] |= RACK_PENDING;
} else
ccp_localstate[f->unit] |= RREQ_REPEAT;
@@ -641,13 +1033,13 @@ ccp_datainput(unit, pkt, len)
*/
static void
ccp_rack_timeout(arg)
- caddr_t arg;
+ void *arg;
{
- fsm *f = (fsm *) arg;
+ fsm *f = arg;
if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
- TIMEOUT(ccp_rack_timeout, (caddr_t) f, RACKTIMEOUT);
+ TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
ccp_localstate[f->unit] &= ~RREQ_REPEAT;
} else
ccp_localstate[f->unit] &= ~RACK_PENDING;
diff --git a/usr.sbin/pppd/ccp.h b/usr.sbin/pppd/ccp.h
index 20ff421..32f7b05 100644
--- a/usr.sbin/pppd/ccp.h
+++ b/usr.sbin/pppd/ccp.h
@@ -29,7 +29,12 @@
typedef struct ccp_options {
u_int bsd_compress: 1; /* do BSD Compress? */
+ u_int deflate: 1; /* do Deflate? */
+ u_int predictor_1: 1; /* do Predictor-1? */
+ u_int predictor_2: 1; /* do Predictor-2? */
u_short bsd_bits; /* # bits/code for BSD Compress */
+ u_short deflate_size; /* lg(window size) for Deflate */
+ short method; /* code for chosen compression method */
} ccp_options;
extern fsm ccp_fsm[];
@@ -38,14 +43,4 @@ extern ccp_options ccp_gotoptions[];
extern ccp_options ccp_allowoptions[];
extern ccp_options ccp_hisoptions[];
-void ccp_init __P((int unit));
-void ccp_open __P((int unit));
-void ccp_close __P((int unit));
-void ccp_lowerup __P((int unit));
-void ccp_lowerdown __P((int));
-void ccp_input __P((int unit, u_char *pkt, int len));
-void ccp_protrej __P((int unit));
-int ccp_printpkt __P((u_char *pkt, int len,
- void (*printer) __P((void *, char *, ...)),
- void *arg));
-void ccp_datainput __P((int unit, u_char *pkt, int len));
+extern struct protent ccp_protent;
diff --git a/usr.sbin/pppd/chap.c b/usr.sbin/pppd/chap.c
index 9003554..584b18b 100644
--- a/usr.sbin/pppd/chap.c
+++ b/usr.sbin/pppd/chap.c
@@ -1,5 +1,20 @@
/*
- * chap.c - Crytographic Handshake Authentication Protocol.
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Copyright (c) 1991 Gregory M. Christy.
* All rights reserved.
@@ -35,12 +50,46 @@ static char rcsid[] = "$Id$";
#include "pppd.h"
#include "chap.h"
+#include "md5.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
+
+/*
+ * Protocol entry points.
+ */
+static void ChapInit __P((int));
+static void ChapLowerUp __P((int));
+static void ChapLowerDown __P((int));
+static void ChapInput __P((int, u_char *, int));
+static void ChapProtocolReject __P((int));
+static int ChapPrintPkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent chap_protent = {
+ PPP_CHAP,
+ ChapInit,
+ ChapInput,
+ ChapProtocolReject,
+ ChapLowerUp,
+ ChapLowerDown,
+ NULL,
+ NULL,
+ ChapPrintPkt,
+ NULL,
+ 1,
+ "CHAP",
+ NULL,
+ NULL,
+ NULL
+};
chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
-static void ChapChallengeTimeout __P((caddr_t));
-static void ChapResponseTimeout __P((caddr_t));
+static void ChapChallengeTimeout __P((void *));
+static void ChapResponseTimeout __P((void *));
static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
+static void ChapRechallenge __P((void *));
static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
@@ -55,7 +104,7 @@ extern void srand48 __P((long));
/*
* ChapInit - Initialize a CHAP unit.
*/
-void
+static void
ChapInit(unit)
int unit;
{
@@ -134,7 +183,7 @@ ChapAuthPeer(unit, our_name, digest)
*/
static void
ChapChallengeTimeout(arg)
- caddr_t arg;
+ void *arg;
{
chap_state *cstate = (chap_state *) arg;
@@ -161,7 +210,7 @@ ChapChallengeTimeout(arg)
*/
static void
ChapResponseTimeout(arg)
- caddr_t arg;
+ void *arg;
{
chap_state *cstate = (chap_state *) arg;
@@ -178,7 +227,7 @@ ChapResponseTimeout(arg)
*/
static void
ChapRechallenge(arg)
- caddr_t arg;
+ void *arg;
{
chap_state *cstate = (chap_state *) arg;
@@ -197,7 +246,7 @@ ChapRechallenge(arg)
*
* Start up if we have pending requests.
*/
-void
+static void
ChapLowerUp(unit)
int unit;
{
@@ -223,7 +272,7 @@ ChapLowerUp(unit)
*
* Cancel all timeouts.
*/
-void
+static void
ChapLowerDown(unit)
int unit;
{
@@ -232,12 +281,12 @@ ChapLowerDown(unit)
/* Timeout(s) pending? Cancel if so. */
if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
cstate->serverstate == CHAPSS_RECHALLENGE)
- UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
else if (cstate->serverstate == CHAPSS_OPEN
&& cstate->chal_interval != 0)
- UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
+ UNTIMEOUT(ChapRechallenge, cstate);
if (cstate->clientstate == CHAPCS_RESPONSE)
- UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapResponseTimeout, cstate);
cstate->clientstate = CHAPCS_INITIAL;
cstate->serverstate = CHAPSS_INITIAL;
@@ -247,7 +296,7 @@ ChapLowerDown(unit)
/*
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
-void
+static void
ChapProtocolReject(unit)
int unit;
{
@@ -266,7 +315,7 @@ ChapProtocolReject(unit)
/*
* ChapInput - Input CHAP packet.
*/
-void
+static void
ChapInput(unit, inpacket, packet_len)
int unit;
u_char *inpacket;
@@ -342,7 +391,7 @@ ChapReceiveChallenge(cstate, inp, id, len)
char secret[MAXSECRETLEN];
char rhostname[256];
MD5_CTX mdContext;
- unsigned char digest[16];
+ u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
if (cstate->clientstate == CHAPCS_CLOSED ||
@@ -371,9 +420,17 @@ ChapReceiveChallenge(cstate, inp, id, len)
BCOPY(inp, rhostname, len);
rhostname[len] = '\000';
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'",
rhostname));
+ /* Microsoft doesn't send their name back in the PPP packet */
+ if (remote_name[0] != 0 && (explicit_remote || rhostname[0] == 0)) {
+ strncpy(rhostname, remote_name, sizeof(rhostname));
+ rhostname[sizeof(rhostname) - 1] = 0;
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name",
+ rhostname));
+ }
+
/* get secret for authenticating ourselves with the specified host */
if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
secret, &secret_len, 0)) {
@@ -384,7 +441,7 @@ ChapReceiveChallenge(cstate, inp, id, len)
/* cancel response send timeout if necessary */
if (cstate->clientstate == CHAPCS_RESPONSE)
- UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapResponseTimeout, cstate);
cstate->resp_id = id;
cstate->resp_transmits = 0;
@@ -392,21 +449,28 @@ ChapReceiveChallenge(cstate, inp, id, len)
/* generate MD based on negotiated type */
switch (cstate->resp_type) {
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ case CHAP_DIGEST_MD5:
MD5Init(&mdContext);
MD5Update(&mdContext, &cstate->resp_id, 1);
MD5Update(&mdContext, secret, secret_len);
MD5Update(&mdContext, rchallenge, rchallenge_len);
- MD5Final(digest, &mdContext);
- BCOPY(digest, cstate->response, MD5_SIGNATURE_SIZE);
+ MD5Final(hash, &mdContext);
+ BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
cstate->resp_length = MD5_SIGNATURE_SIZE;
break;
+#ifdef CHAPMS
+ case CHAP_MICROSOFT:
+ ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+ break;
+#endif
+
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
return;
}
+ BZERO(secret, sizeof(secret));
ChapSendResponse(cstate);
}
@@ -425,11 +489,9 @@ ChapReceiveResponse(cstate, inp, id, len)
int secret_len, old_state;
int code;
char rhostname[256];
- u_char buf[256];
MD5_CTX mdContext;
- unsigned char digest[16];
- u_char msg[256];
char secret[MAXSECRETLEN];
+ u_char hash[MD5_SIGNATURE_SIZE];
CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
@@ -471,7 +533,7 @@ ChapReceiveResponse(cstate, inp, id, len)
return;
}
- UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapChallengeTimeout, cstate);
if (len >= sizeof(rhostname))
len = sizeof(rhostname) - 1;
@@ -502,10 +564,10 @@ ChapReceiveResponse(cstate, inp, id, len)
MD5Update(&mdContext, &cstate->chal_id, 1);
MD5Update(&mdContext, secret, secret_len);
MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
- MD5Final(digest, &mdContext);
+ MD5Final(hash, &mdContext);
/* compare local and remote MDs and send the appropriate status */
- if (memcmp (digest, remmd, MD5_SIGNATURE_SIZE) == 0)
+ if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
code = CHAP_SUCCESS; /* they are the same! */
break;
@@ -514,16 +576,17 @@ ChapReceiveResponse(cstate, inp, id, len)
}
}
+ BZERO(secret, sizeof(secret));
ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
old_state = cstate->serverstate;
cstate->serverstate = CHAPSS_OPEN;
if (old_state == CHAPSS_INITIAL_CHAL) {
- auth_peer_success(cstate->unit, PPP_CHAP);
+ auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
}
if (cstate->chal_interval != 0)
- TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
+ TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
} else {
syslog(LOG_ERR, "CHAP peer authentication failed");
@@ -556,7 +619,7 @@ ChapReceiveSuccess(cstate, inp, id, len)
return;
}
- UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapResponseTimeout, cstate);
/*
* Print message.
@@ -580,9 +643,6 @@ ChapReceiveFailure(cstate, inp, id, len)
u_char id;
int len;
{
- u_char msglen;
- u_char *msg;
-
CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
if (cstate->clientstate != CHAPCS_RESPONSE) {
@@ -592,7 +652,7 @@ ChapReceiveFailure(cstate, inp, id, len)
return;
}
- UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+ UNTIMEOUT(ChapResponseTimeout, cstate);
/*
* Print message.
@@ -637,7 +697,7 @@ ChapSendChallenge(cstate)
CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
- TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
+ TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
++cstate->chal_transmits;
}
@@ -737,18 +797,18 @@ ChapSendResponse(cstate)
output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
cstate->clientstate = CHAPCS_RESPONSE;
- TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
+ TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
++cstate->resp_transmits;
}
/*
* ChapPrintPkt - print the contents of a CHAP packet.
*/
-char *ChapCodenames[] = {
+static char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
-int
+static int
ChapPrintPkt(p, plen, printer, arg)
u_char *p;
int plen;
diff --git a/usr.sbin/pppd/chap.h b/usr.sbin/pppd/chap.h
index 700c421..6e2cc45 100644
--- a/usr.sbin/pppd/chap.h
+++ b/usr.sbin/pppd/chap.h
@@ -1,5 +1,20 @@
/*
- * chap.h - Cryptographic Handshake Authentication Protocol definitions.
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Copyright (c) 1991 Gregory M. Christy
* All rights reserved.
@@ -29,6 +44,8 @@
#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT 0x80 /* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */
#define CHAP_CHALLENGE 1
#define CHAP_RESPONSE 2
@@ -40,7 +57,7 @@
*/
#define MIN_CHALLENGE_LENGTH 32
#define MAX_CHALLENGE_LENGTH 64
-#define MAX_RESPONSE_LENGTH 16 /* sufficient for MD5 */
+#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */
/*
* Each interface is described by a chap structure.
@@ -98,15 +115,10 @@ typedef struct chap_state {
extern chap_state chap[];
-void ChapInit __P((int));
void ChapAuthWithPeer __P((int, char *, int));
void ChapAuthPeer __P((int, char *, int));
-void ChapLowerUp __P((int));
-void ChapLowerDown __P((int));
-void ChapInput __P((int, u_char *, int));
-void ChapProtocolReject __P((int));
-int ChapPrintPkt __P((u_char *, int,
- void (*) __P((void *, char *, ...)), void *));
+
+extern struct protent chap_protent;
#define __CHAP_INCLUDE__
#endif /* __CHAP_INCLUDE__ */
diff --git a/usr.sbin/pppd/chap_ms.c b/usr.sbin/pppd/chap_ms.c
new file mode 100644
index 0000000..a19c87d
--- /dev/null
+++ b/usr.sbin/pppd/chap_ms.c
@@ -0,0 +1,327 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ * Implemented LANManager type password response to MS-CHAP challenges.
+ * Now pppd provides both NT style and LANMan style blocks, and the
+ * prefered is set by option "ms-lanman". Default is to use NT.
+ * The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#ifdef CHAPMS
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+#ifndef USE_CRYPT
+#include <des.h>
+#endif
+
+typedef struct {
+ u_char LANManResp[24];
+ u_char NTResp[24];
+ u_char UseNT; /* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+ in case this struct gets padded. */
+
+
+static void DesEncrypt __P((u_char *, u_char *, u_char *));
+static void MakeKey __P((u_char *, u_char *));
+
+#ifdef USE_CRYPT
+static void Expand __P((u_char *, u_char *));
+static void Collapse __P((u_char *, u_char *));
+#endif
+
+static void
+ChallengeResponse(challenge, pwHash, response)
+ u_char *challenge; /* IN 8 octets */
+ u_char *pwHash; /* IN 16 octets */
+ u_char *response; /* OUT 24 octets */
+{
+ char ZPasswordHash[21];
+
+ BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+ BCOPY(pwHash, ZPasswordHash, 16);
+
+#if 0
+ log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
+#endif
+
+ DesEncrypt(challenge, ZPasswordHash + 0, response + 0);
+ DesEncrypt(challenge, ZPasswordHash + 7, response + 8);
+ DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+ log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void
+DesEncrypt(clear, key, cipher)
+ u_char *clear; /* IN 8 octets */
+ u_char *key; /* IN 7 octets */
+ u_char *cipher; /* OUT 8 octets */
+{
+ u_char des_key[8];
+ u_char crypt_key[66];
+ u_char des_input[66];
+
+ MakeKey(key, des_key);
+
+ Expand(des_key, crypt_key);
+ setkey(crypt_key);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
+ clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+ Expand(clear, des_input);
+ encrypt(des_input, 0);
+ Collapse(des_input, cipher);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
+ cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void
+DesEncrypt(clear, key, cipher)
+ u_char *clear; /* IN 8 octets */
+ u_char *key; /* IN 7 octets */
+ u_char *cipher; /* OUT 8 octets */
+{
+ des_cblock des_key;
+ des_key_schedule key_schedule;
+
+ MakeKey(key, des_key);
+
+ des_set_key(&des_key, key_schedule);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
+ clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+ des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
+ cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char Get7Bits(input, startBit)
+ u_char *input;
+ int startBit;
+{
+ register unsigned int word;
+
+ word = (unsigned)input[startBit / 8] << 8;
+ word |= (unsigned)input[startBit / 8 + 1];
+
+ word >>= 15 - (startBit % 8 + 7);
+
+ return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void Expand(in, out)
+ u_char *in;
+ u_char *out;
+{
+ int j, c;
+ int i;
+
+ for(i = 0; i < 64; in++){
+ c = *in;
+ for(j = 7; j >= 0; j--)
+ *out++ = (c >> j) & 01;
+ i += 8;
+ }
+}
+
+/* The inverse of Expand
+ */
+static void Collapse(in, out)
+ u_char *in;
+ u_char *out;
+{
+ int j;
+ int i;
+ unsigned int c;
+
+ for (i = 0; i < 64; i += 8, out++) {
+ c = 0;
+ for (j = 7; j >= 0; j--, in++)
+ c |= *in << j;
+ *out = c & 0xff;
+ }
+}
+#endif
+
+static void MakeKey(key, des_key)
+ u_char *key; /* IN 56 bit DES key missing parity bits */
+ u_char *des_key; /* OUT 64 bit DES key with parity bits added */
+{
+ des_key[0] = Get7Bits(key, 0);
+ des_key[1] = Get7Bits(key, 7);
+ des_key[2] = Get7Bits(key, 14);
+ des_key[3] = Get7Bits(key, 21);
+ des_key[4] = Get7Bits(key, 28);
+ des_key[5] = Get7Bits(key, 35);
+ des_key[6] = Get7Bits(key, 42);
+ des_key[7] = Get7Bits(key, 49);
+
+#ifndef USE_CRYPT
+ des_set_odd_parity((des_cblock *)des_key);
+#endif
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
+ key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
+ CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
+ des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
+#endif
+}
+
+static void
+ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+ MS_ChapResponse *response;
+{
+ int i;
+ MDstruct md4Context;
+ u_char unicodePassword[MAX_NT_PASSWORD * 2];
+ static int low_byte_first = -1;
+
+ /* Initialize the Unicode version of the secret (== password). */
+ /* This implicitly supports 8-bit ISO8859/1 characters. */
+ BZERO(unicodePassword, sizeof(unicodePassword));
+ for (i = 0; i < secret_len; i++)
+ unicodePassword[i * 2] = (u_char)secret[i];
+
+ MDbegin(&md4Context);
+ MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */
+
+ if (low_byte_first == -1)
+ low_byte_first = (htons((unsigned short int)1) != 1);
+ if (low_byte_first == 0)
+ MDreverse(&md4Context); /* sfb 961105 */
+
+ MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */
+
+ ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+ MS_ChapResponse *response;
+{
+ int i;
+ u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+ u_char PasswordHash[16];
+
+ /* LANMan password is case insensitive */
+ BZERO(UcasePassword, sizeof(UcasePassword));
+ for (i = 0; i < secret_len; i++)
+ UcasePassword[i] = (u_char)toupper(secret[i]);
+ DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+ DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+ ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+void
+ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
+ chap_state *cstate;
+ char *rchallenge;
+ int rchallenge_len;
+ char *secret;
+ int secret_len;
+{
+ MS_ChapResponse response;
+#ifdef MSLANMAN
+ extern int ms_lanman;
+#endif
+
+#if 0
+ CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+ BZERO(&response, sizeof(response));
+
+ /* Calculate both always */
+ ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+ ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+ /* prefered method is set by option */
+ response.UseNT = !ms_lanman;
+#else
+ response.UseNT = 1;
+#endif
+
+ BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+ cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+#endif /* CHAPMS */
diff --git a/usr.sbin/pppd/chap_ms.h b/usr.sbin/pppd/chap_ms.h
new file mode 100644
index 0000000..f22607d
--- /dev/null
+++ b/usr.sbin/pppd/chap_ms.h
@@ -0,0 +1,32 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist. The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+#ifndef __CHAPMS_INCLUDE__
+
+#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS __P((chap_state *, char *, int, char *, int));
+
+#define __CHAPMS_INCLUDE__
+#endif /* __CHAPMS_INCLUDE__ */
diff --git a/usr.sbin/pppd/demand.c b/usr.sbin/pppd/demand.c
new file mode 100644
index 0000000..f44510f
--- /dev/null
+++ b/usr.sbin/pppd/demand.c
@@ -0,0 +1,348 @@
+/*
+ * demand.c - Support routines for demand-dialling.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#include <pcap.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "lcp.h"
+
+char *frame;
+int framelen;
+int framemax;
+int escape_flag;
+int flush_flag;
+int fcs;
+
+struct packet {
+ int length;
+ struct packet *next;
+ unsigned char data[1];
+};
+
+struct packet *pend_q;
+struct packet *pend_qtail;
+
+static int active_packet __P((unsigned char *, int));
+
+/*
+ * demand_conf - configure the interface for doing dial-on-demand.
+ */
+void
+demand_conf()
+{
+ int i;
+ struct protent *protp;
+
+/* framemax = lcp_allowoptions[0].mru;
+ if (framemax < PPP_MRU) */
+ framemax = PPP_MRU;
+ framemax += PPP_HDRLEN + PPP_FCSLEN;
+ frame = malloc(framemax);
+ if (frame == NULL)
+ novm("demand frame");
+ framelen = 0;
+ pend_q = NULL;
+ escape_flag = 0;
+ flush_flag = 0;
+ fcs = PPP_INITFCS;
+
+ ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+ ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+
+#ifdef PPP_FILTER
+ set_filters(&pass_filter, &active_filter);
+#endif
+
+ /*
+ * Call the demand_conf procedure for each protocol that's got one.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ if (!((*protp->demand_conf)(0)))
+ die(1);
+}
+
+
+/*
+ * demand_block - set each network protocol to block further packets.
+ */
+void
+demand_block()
+{
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
+ get_loop_output();
+}
+
+/*
+ * demand_discard - set each network protocol to discard packets
+ * with an error.
+ */
+void
+demand_discard()
+{
+ struct packet *pkt, *nextpkt;
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
+ get_loop_output();
+
+ /* discard all saved packets */
+ for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
+ nextpkt = pkt->next;
+ free(pkt);
+ }
+ pend_q = NULL;
+ framelen = 0;
+ flush_flag = 0;
+ escape_flag = 0;
+ fcs = PPP_INITFCS;
+}
+
+/*
+ * demand_unblock - set each enabled network protocol to pass packets.
+ */
+void
+demand_unblock()
+{
+ int i;
+ struct protent *protp;
+
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->enabled_flag && protp->demand_conf != NULL)
+ sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
+}
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*
+ * loop_chars - process characters received from the loopback.
+ * Calls loop_frame when a complete frame has been accumulated.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+loop_chars(p, n)
+ unsigned char *p;
+ int n;
+{
+ int c, rv;
+
+ rv = 0;
+ for (; n > 0; --n) {
+ c = *p++;
+ if (c == PPP_FLAG) {
+ if (!escape_flag && !flush_flag
+ && framelen > 2 && fcs == PPP_GOODFCS) {
+ framelen -= 2;
+ if (loop_frame(frame, framelen))
+ rv = 1;
+ }
+ framelen = 0;
+ flush_flag = 0;
+ escape_flag = 0;
+ fcs = PPP_INITFCS;
+ continue;
+ }
+ if (flush_flag)
+ continue;
+ if (escape_flag) {
+ c ^= PPP_TRANS;
+ escape_flag = 0;
+ } else if (c == PPP_ESCAPE) {
+ escape_flag = 1;
+ continue;
+ }
+ if (framelen >= framemax) {
+ flush_flag = 1;
+ continue;
+ }
+ frame[framelen++] = c;
+ fcs = PPP_FCS(fcs, c);
+ }
+ return rv;
+}
+
+/*
+ * loop_frame - given a frame obtained from the loopback,
+ * decide whether to bring up the link or not, and, if we want
+ * to transmit this frame later, put it on the pending queue.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ * We assume that the kernel driver has already applied the
+ * pass_filter, so we won't get packets it rejected.
+ * We apply the active_filter to see if we want this packet to
+ * bring up the link.
+ */
+int
+loop_frame(frame, len)
+ unsigned char *frame;
+ int len;
+{
+ struct packet *pkt;
+
+ /* log_packet(frame, len, "from loop: ", LOG_DEBUG); */
+ if (len < PPP_HDRLEN)
+ return 0;
+ if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
+ return 0; /* shouldn't get any of these anyway */
+ if (!active_packet(frame, len))
+ return 0;
+
+ pkt = (struct packet *) malloc(sizeof(struct packet) + len);
+ if (pkt != NULL) {
+ pkt->length = len;
+ pkt->next = NULL;
+ memcpy(pkt->data, frame, len);
+ if (pend_q == NULL)
+ pend_q = pkt;
+ else
+ pend_qtail->next = pkt;
+ pend_qtail = pkt;
+ }
+ return 1;
+}
+
+/*
+ * demand_rexmit - Resend all those frames which we got via the
+ * loopback, now that the real serial link is up.
+ */
+void
+demand_rexmit(proto)
+ int proto;
+{
+ struct packet *pkt, *prev, *nextpkt;
+
+ prev = NULL;
+ pkt = pend_q;
+ pend_q = NULL;
+ for (; pkt != NULL; pkt = nextpkt) {
+ nextpkt = pkt->next;
+ if (PPP_PROTOCOL(pkt->data) == proto) {
+ output(0, pkt->data, pkt->length);
+ free(pkt);
+ } else {
+ if (prev == NULL)
+ pend_q = pkt;
+ else
+ prev->next = pkt;
+ prev = pkt;
+ }
+ }
+ pend_qtail = prev;
+ if (prev != NULL)
+ prev->next = NULL;
+}
+
+/*
+ * Scan a packet to decide whether it is an "active" packet,
+ * that is, whether it is worth bringing up the link for.
+ */
+static int
+active_packet(p, len)
+ unsigned char *p;
+ int len;
+{
+ int proto, i;
+ struct protent *protp;
+
+ if (len < PPP_HDRLEN)
+ return 0;
+ proto = PPP_PROTOCOL(p);
+#ifdef PPP_FILTER
+ if (active_filter.bf_len != 0
+ && bpf_filter(active_filter.bf_insns, frame, len, len) == 0)
+ return 0;
+#endif
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+ if (!protp->enabled_flag)
+ return 0;
+ if (protp->active_pkt == NULL)
+ return 1;
+ return (*protp->active_pkt)(p, len);
+ }
+ }
+ return 0; /* not a supported protocol !!?? */
+}
diff --git a/usr.sbin/pppd/fsm.c b/usr.sbin/pppd/fsm.c
index ea3815c..624799f 100644
--- a/usr.sbin/pppd/fsm.c
+++ b/usr.sbin/pppd/fsm.c
@@ -35,13 +35,11 @@ static char rcsid[] = "$Id$";
#include "pppd.h"
#include "fsm.h"
-extern char *proto_name();
-
-static void fsm_timeout __P((caddr_t));
+static void fsm_timeout __P((void *));
static void fsm_rconfreq __P((fsm *, int, u_char *, int));
static void fsm_rconfack __P((fsm *, int, u_char *, int));
static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
-static void fsm_rtermreq __P((fsm *, int));
+static void fsm_rtermreq __P((fsm *, int, u_char *, int));
static void fsm_rtermack __P((fsm *));
static void fsm_rcoderej __P((fsm *, u_char *, int));
static void fsm_sconfreq __P((fsm *, int));
@@ -67,6 +65,7 @@ fsm_init(f)
f->maxconfreqtransmits = DEFMAXCONFREQS;
f->maxtermtransmits = DEFMAXTERMREQS;
f->maxnakloops = DEFMAXNAKLOOPS;
+ f->term_reason_len = 0;
}
@@ -121,7 +120,7 @@ fsm_lowerdown(f)
case CLOSING:
f->state = INITIAL;
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case STOPPING:
@@ -129,7 +128,7 @@ fsm_lowerdown(f)
case ACKRCVD:
case ACKSENT:
f->state = STARTING;
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
break;
case OPENED:
@@ -190,9 +189,12 @@ fsm_open(f)
* the CLOSED state.
*/
void
-fsm_close(f)
+fsm_close(f, reason)
fsm *f;
+ char *reason;
{
+ f->term_reason = reason;
+ f->term_reason_len = (reason == NULL? 0: strlen(reason));
switch( f->state ){
case STARTING:
f->state = INITIAL;
@@ -209,14 +211,15 @@ fsm_close(f)
case ACKSENT:
case OPENED:
if( f->state != OPENED )
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
else if( f->callbacks->down )
(*f->callbacks->down)(f); /* Inform upper layers we're down */
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = CLOSING;
@@ -230,7 +233,7 @@ fsm_close(f)
*/
static void
fsm_timeout(arg)
- caddr_t arg;
+ void *arg;
{
fsm *f = (fsm *) arg;
@@ -246,8 +249,9 @@ fsm_timeout(arg)
(*f->callbacks->finished)(f);
} else {
/* Send Terminate-Request */
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
}
break;
@@ -288,7 +292,7 @@ fsm_input(f, inpacket, l)
u_char *inpacket;
int l;
{
- u_char *inp, *outp;
+ u_char *inp;
u_char code, id;
int len;
@@ -341,7 +345,7 @@ fsm_input(f, inpacket, l)
break;
case TERMREQ:
- fsm_rtermreq(f, id);
+ fsm_rtermreq(f, id, inp, len);
break;
case TERMACK:
@@ -371,7 +375,6 @@ fsm_rconfreq(f, id, inp, len)
u_char *inp;
int len;
{
- u_char *outp;
int code, reject_if_disagree;
FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
@@ -415,7 +418,7 @@ fsm_rconfreq(f, id, inp, len)
if (code == CONFACK) {
if (f->state == ACKRCVD) {
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
@@ -451,6 +454,7 @@ fsm_rconfack(f, id, inp, len)
if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
(len == 0)) ){
/* Ack is bad - ignore it */
+ log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR);
FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
PROTO_NAME(f), len));
return;
@@ -470,13 +474,13 @@ fsm_rconfack(f, id, inp, len)
case ACKRCVD:
/* Huh? an extra valid Ack? oh well... */
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
case ACKSENT:
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
f->state = OPENED;
f->retransmits = f->maxconfreqtransmits;
if (f->callbacks->up)
@@ -504,7 +508,8 @@ fsm_rconfnakrej(f, code, id, inp, len)
u_char *inp;
int len;
{
- int (*proc)();
+ int (*proc) __P((fsm *, u_char *, int));
+ int ret;
FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
PROTO_NAME(f), id));
@@ -512,8 +517,9 @@ fsm_rconfnakrej(f, code, id, inp, len)
if (id != f->reqid || f->seen_ack) /* Expected id? */
return; /* Nope, toss... */
proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
- if (!proc || !proc(f, inp, len)) {
+ if (!proc || !(ret = proc(f, inp, len))) {
/* Nak/reject is bad - ignore it */
+ log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR);
FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
return;
@@ -529,13 +535,16 @@ fsm_rconfnakrej(f, code, id, inp, len)
case REQSENT:
case ACKSENT:
/* They didn't agree to what we wanted - try another request */
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- fsm_sconfreq(f, 0); /* Send Configure-Request */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
+ if (ret < 0)
+ f->state = STOPPED; /* kludge for stopping CCP */
+ else
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
case ACKRCVD:
/* Got a Nak/reject when we had already had an Ack?? oh well... */
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
@@ -555,10 +564,14 @@ fsm_rconfnakrej(f, code, id, inp, len)
* fsm_rtermreq - Receive Terminate-Req.
*/
static void
-fsm_rtermreq(f, id)
+fsm_rtermreq(f, id, p, len)
fsm *f;
int id;
+ u_char *p;
+ int len;
{
+ char str[80];
+
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
PROTO_NAME(f), id));
@@ -569,12 +582,16 @@ fsm_rtermreq(f, id)
break;
case OPENED:
- syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f));
+ if (len > 0) {
+ fmtmsg(str, sizeof(str), "%0.*v", len, p);
+ syslog(LOG_INFO, "%s terminated by peer (%s)", PROTO_NAME(f), str);
+ } else
+ syslog(LOG_INFO, "%s terminated by peer", PROTO_NAME(f));
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
f->retransmits = 0;
f->state = STOPPING;
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
break;
}
@@ -593,13 +610,13 @@ fsm_rtermack(f)
switch (f->state) {
case CLOSING:
- UNTIMEOUT(fsm_timeout, (caddr_t) f);
+ UNTIMEOUT(fsm_timeout, f);
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
- UNTIMEOUT(fsm_timeout, (caddr_t) f);
+ UNTIMEOUT(fsm_timeout, f);
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
@@ -656,7 +673,7 @@ fsm_protreject(f)
{
switch( f->state ){
case CLOSING:
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case CLOSED:
f->state = CLOSED;
@@ -668,7 +685,7 @@ fsm_protreject(f)
case REQSENT:
case ACKRCVD:
case ACKSENT:
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
/* fall through */
case STOPPED:
f->state = STOPPED;
@@ -682,8 +699,9 @@ fsm_protreject(f)
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+ (u_char *) f->term_reason, f->term_reason_len);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
--f->retransmits;
f->state = STOPPING;
@@ -705,7 +723,7 @@ fsm_sconfreq(f, retransmit)
int retransmit;
{
u_char *outp;
- int outlen, cilen;
+ int cilen;
if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
/* Not currently negotiating - reset options */
@@ -740,7 +758,7 @@ fsm_sconfreq(f, retransmit)
/* start the retransmit timer */
--f->retransmits;
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ TIMEOUT(fsm_timeout, f, f->timeouttime);
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
PROTO_NAME(f), f->reqid));
diff --git a/usr.sbin/pppd/fsm.h b/usr.sbin/pppd/fsm.h
index dc6be6d..f289429 100644
--- a/usr.sbin/pppd/fsm.h
+++ b/usr.sbin/pppd/fsm.h
@@ -38,27 +38,8 @@
/*
- * Each FSM is described by a fsm_callbacks and a fsm structure.
+ * Each FSM is described by an fsm structure and fsm callbacks.
*/
-typedef struct fsm_callbacks {
- void (*resetci)(); /* Reset our Configuration Information */
- int (*cilen)(); /* Length of our Configuration Information */
- void (*addci)(); /* Add our Configuration Information */
- int (*ackci)(); /* ACK our Configuration Information */
- int (*nakci)(); /* NAK our Configuration Information */
- int (*rejci)(); /* Reject our Configuration Information */
- int (*reqci)(); /* Request peer's Configuration Information */
- void (*up)(); /* Called when fsm reaches OPENED state */
- void (*down)(); /* Called when fsm leaves OPENED state */
- void (*starting)(); /* Called when we want the lower layer */
- void (*finished)(); /* Called when we don't want the lower layer */
- void (*protreject)(); /* Called when Protocol-Reject received */
- void (*retransmit)(); /* Retransmission is necessary */
- int (*extcode)(); /* Called when unknown code received */
- char *proto_name; /* String name for protocol (for messages) */
-} fsm_callbacks;
-
-
typedef struct fsm {
int unit; /* Interface unit number */
int protocol; /* Data Link Layer Protocol field value */
@@ -73,10 +54,45 @@ typedef struct fsm {
int maxtermtransmits; /* Maximum Terminate-Request transmissions */
int nakloops; /* Number of nak loops since last ack */
int maxnakloops; /* Maximum number of nak loops tolerated */
- fsm_callbacks *callbacks; /* Callback routines */
+ struct fsm_callbacks *callbacks; /* Callback routines */
+ char *term_reason; /* Reason for closing protocol */
+ int term_reason_len; /* Length of term_reason */
} fsm;
+typedef struct fsm_callbacks {
+ void (*resetci) /* Reset our Configuration Information */
+ __P((fsm *));
+ int (*cilen) /* Length of our Configuration Information */
+ __P((fsm *));
+ void (*addci) /* Add our Configuration Information */
+ __P((fsm *, u_char *, int *));
+ int (*ackci) /* ACK our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*nakci) /* NAK our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*rejci) /* Reject our Configuration Information */
+ __P((fsm *, u_char *, int));
+ int (*reqci) /* Request peer's Configuration Information */
+ __P((fsm *, u_char *, int *, int));
+ void (*up) /* Called when fsm reaches OPENED state */
+ __P((fsm *));
+ void (*down) /* Called when fsm leaves OPENED state */
+ __P((fsm *));
+ void (*starting) /* Called when we want the lower layer */
+ __P((fsm *));
+ void (*finished) /* Called when we don't want the lower layer */
+ __P((fsm *));
+ void (*protreject) /* Called when Protocol-Reject received */
+ __P((int));
+ void (*retransmit) /* Retransmission is necessary */
+ __P((fsm *));
+ int (*extcode) /* Called when unknown code received */
+ __P((fsm *, int, int, u_char *, int));
+ char *proto_name; /* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
/*
* Link states.
*/
@@ -116,7 +132,7 @@ void fsm_init __P((fsm *));
void fsm_lowerup __P((fsm *));
void fsm_lowerdown __P((fsm *));
void fsm_open __P((fsm *));
-void fsm_close __P((fsm *));
+void fsm_close __P((fsm *, char *));
void fsm_input __P((fsm *, u_char *, int));
void fsm_protreject __P((fsm *));
void fsm_sdata __P((fsm *, int, int, u_char *, int));
diff --git a/usr.sbin/pppd/ipcp.c b/usr.sbin/pppd/ipcp.c
index f567992..94dfd8d 100644
--- a/usr.sbin/pppd/ipcp.c
+++ b/usr.sbin/pppd/ipcp.c
@@ -28,6 +28,8 @@ static char rcsid[] = "$Id$";
#include <stdio.h>
#include <string.h>
#include <syslog.h>
+#include <netdb.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -44,7 +46,9 @@ ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
/* local vars */
-static int cis_received[NUM_PPP]; /* # Conf-Reqs received */
+static int cis_received[NUM_PPP]; /* # Conf-Reqs received */
+static int default_route_set[NUM_PPP]; /* Have set up a default route */
+static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */
/*
* Callbacks for fsm code. (CI = Configuration Information)
@@ -59,6 +63,7 @@ static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
static void ipcp_up __P((fsm *)); /* We're UP */
static void ipcp_down __P((fsm *)); /* We're DOWN */
static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */
+static void ipcp_finished __P((fsm *)); /* Don't need lower layer */
fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
@@ -73,7 +78,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
ipcp_up, /* Called when fsm reaches OPENED state */
ipcp_down, /* Called when fsm leaves OPENED state */
NULL, /* Called when we want the lower layer up */
- NULL, /* Called when we want the lower layer down */
+ ipcp_finished, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
NULL, /* Retransmission is necessary */
NULL, /* Called to handle protocol-specific codes */
@@ -81,6 +86,42 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
};
/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init __P((int));
+static void ipcp_open __P((int));
+static void ipcp_close __P((int, char *));
+static void ipcp_lowerup __P((int));
+static void ipcp_lowerdown __P((int));
+static void ipcp_input __P((int, u_char *, int));
+static void ipcp_protrej __P((int));
+static int ipcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+static void ip_check_options __P((void));
+static int ip_demand_conf __P((int));
+static int ip_active_pkt __P((u_char *, int));
+
+struct protent ipcp_protent = {
+ PPP_IPCP,
+ ipcp_init,
+ ipcp_input,
+ ipcp_protrej,
+ ipcp_lowerup,
+ ipcp_lowerdown,
+ ipcp_open,
+ ipcp_close,
+ ipcp_printpkt,
+ NULL,
+ 1,
+ "IPCP",
+ ip_check_options,
+ ip_demand_conf,
+ ip_active_pkt
+};
+
+static void ipcp_clear_addrs __P((int));
+
+/*
* Lengths of configuration options.
*/
#define CILEN_VOID 2
@@ -117,7 +158,7 @@ u_int32_t ipaddr;
/*
* ipcp_init - Initialize IPCP.
*/
-void
+static void
ipcp_init(unit)
int unit;
{
@@ -130,13 +171,11 @@ ipcp_init(unit)
f->callbacks = &ipcp_callbacks;
fsm_init(&ipcp_fsm[unit]);
- wo->neg_addr = 1;
- wo->old_addrs = 0;
- wo->ouraddr = 0;
- wo->hisaddr = 0;
+ memset(wo, 0, sizeof(*wo));
+ memset(ao, 0, sizeof(*ao));
+ wo->neg_addr = 1;
wo->neg_vj = 1;
- wo->old_vj = 0;
wo->vj_protocol = IPCP_VJ_COMP;
wo->maxslotindex = MAX_STATES - 1; /* really max index */
wo->cflag = 1;
@@ -150,7 +189,10 @@ ipcp_init(unit)
ao->maxslotindex = MAX_STATES - 1;
ao->cflag = 1;
- /* allow default route and proxyarp */
+ /*
+ * XXX These control whether the user may use the proxyarp
+ * and defaultroute options.
+ */
ao->proxy_arp = 1;
ao->default_route = 1;
}
@@ -159,7 +201,7 @@ ipcp_init(unit)
/*
* ipcp_open - IPCP is allowed to come up.
*/
-void
+static void
ipcp_open(unit)
int unit;
{
@@ -170,18 +212,19 @@ ipcp_open(unit)
/*
* ipcp_close - Take IPCP down.
*/
-void
-ipcp_close(unit)
+static void
+ipcp_close(unit, reason)
int unit;
+ char *reason;
{
- fsm_close(&ipcp_fsm[unit]);
+ fsm_close(&ipcp_fsm[unit], reason);
}
/*
* ipcp_lowerup - The lower layer is up.
*/
-void
+static void
ipcp_lowerup(unit)
int unit;
{
@@ -192,7 +235,7 @@ ipcp_lowerup(unit)
/*
* ipcp_lowerdown - The lower layer is down.
*/
-void
+static void
ipcp_lowerdown(unit)
int unit;
{
@@ -203,7 +246,7 @@ ipcp_lowerdown(unit)
/*
* ipcp_input - Input IPCP packet.
*/
-void
+static void
ipcp_input(unit, p, len)
int unit;
u_char *p;
@@ -218,7 +261,7 @@ ipcp_input(unit, p, len)
*
* Pretend the lower layer went down, so we shut up.
*/
-void
+static void
ipcp_protrej(unit)
int unit;
{
@@ -253,10 +296,36 @@ ipcp_cilen(f)
fsm *f;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+ /*
+ * First see if we want to change our options to the old
+ * forms because we have received old forms from the peer.
+ */
+ if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+ /* use the old style of address negotiation */
+ go->neg_addr = 1;
+ go->old_addrs = 1;
+ }
+ if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+ /* try an older style of VJ negotiation */
+ if (cis_received[f->unit] == 0) {
+ /* keep trying the new style until we see some CI from the peer */
+ go->neg_vj = 1;
+ } else {
+ /* use the old style only if the peer did */
+ if (ho->neg_vj && ho->old_vj) {
+ go->neg_vj = 1;
+ go->old_vj = 1;
+ go->vj_protocol = ho->vj_protocol;
+ }
+ }
+ }
+
return (LENCIADDR(go->neg_addr, go->old_addrs) +
LENCIVJ(go->neg_vj, go->old_vj));
}
@@ -271,9 +340,7 @@ ipcp_addci(f, ucp, lenp)
u_char *ucp;
int *lenp;
{
- ipcp_options *wo = &ipcp_wantoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
- ipcp_options *ho = &ipcp_hisoptions[f->unit];
int len = *lenp;
#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
@@ -310,30 +377,6 @@ ipcp_addci(f, ucp, lenp)
neg = 0; \
}
- /*
- * First see if we want to change our options to the old
- * forms because we have received old forms from the peer.
- */
- if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
- /* use the old style of address negotiation */
- go->neg_addr = 1;
- go->old_addrs = 1;
- }
- if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
- /* try an older style of VJ negotiation */
- if (cis_received[f->unit] == 0) {
- /* keep trying the new style until we see some CI from the peer */
- go->neg_vj = 1;
- } else {
- /* use the old style only if the peer did */
- if (ho->neg_vj && ho->old_vj) {
- go->neg_vj = 1;
- go->old_vj = 1;
- go->vj_protocol = ho->vj_protocol;
- }
- }
- }
-
ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
go->old_addrs, go->ouraddr, go->hisaddr);
@@ -561,7 +604,7 @@ ipcp_nakci(f, p, len)
no.neg_vj = 1;
break;
case CI_ADDRS:
- if (go->neg_addr && go->old_addrs || no.old_addrs
+ if ((go->neg_addr && go->old_addrs) || no.old_addrs
|| cilen != CILEN_ADDRS)
goto bad;
try.neg_addr = 1;
@@ -728,6 +771,9 @@ ipcp_reqci(f, inp, len, reject_if_disagree)
u_char *ucp = inp; /* Pointer to current output char */
int l = *len; /* Length left */
u_char maxslotindex, cflag;
+ int d;
+
+ cis_received[f->unit] = 1;
/*
* Reset all his options.
@@ -756,28 +802,6 @@ ipcp_reqci(f, inp, len, reject_if_disagree)
next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_DNS1:
- case CI_DNS2:
- if ( (citype == CI_DNS1 && !dns1) ||
- (citype == CI_DNS2 && !dns2)) {
- orc = CONFREJ; /* Reject DNS */
- break;
- }
- IPCPDEBUG((LOG_INFO, "ipcp: received DNS[12] "));
- GETLONG(tl, p); /* Parse his idea */
- ciaddr1 = htonl(tl);
- IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
- if ( (citype == CI_DNS1 && ciaddr1 != dns1) ||
- (citype == CI_DNS2 && ciaddr1 != dns2)) {
- orc = CONFNAK;
- if (!reject_if_disagree) {
- DECPTR(sizeof (long), p);
- tl = ntohl(citype == CI_DNS1 ? dns1 : dns2);
- PUTLONG(tl, p);
- }
- }
- break;
-
case CI_ADDRS:
IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
if (!ao->neg_addr ||
@@ -876,6 +900,48 @@ ipcp_reqci(f, inp, len, reject_if_disagree)
ho->neg_addr = 1;
ho->hisaddr = ciaddr1;
break;
+
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ /* Microsoft primary or secondary DNS request */
+ d = citype == CI_MS_DNS2;
+ IPCPDEBUG((LOG_INFO, "ipcp: received DNS%d Request ", d+1));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->dnsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->dnsaddr[d]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->dnsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ /* Microsoft primary or secondary WINS request */
+ d = citype == CI_MS_WINS2;
+ IPCPDEBUG((LOG_INFO, "ipcp: received WINS%d Request ", d+1));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->winsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->winsaddr[d]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->winsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
case CI_COMPRESSTYPE:
IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
@@ -987,6 +1053,76 @@ endswitch:
/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ip_check_options()
+{
+ struct hostent *hp;
+ u_int32_t local;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * Default our local IP address based on our hostname.
+ * If local IP address already given, don't bother.
+ */
+ if (wo->ouraddr == 0 && !disable_defaultip) {
+ /*
+ * Look up our hostname (possibly with domain name appended)
+ * and take the first IP address as our local IP address.
+ * If there isn't an IP address for our hostname, too bad.
+ */
+ wo->accept_local = 1; /* don't insist on this default value */
+ if ((hp = gethostbyname(hostname)) != NULL) {
+ local = *(u_int32_t *)hp->h_addr;
+ if (local != 0 && !bad_ip_adrs(local))
+ wo->ouraddr = local;
+ }
+ }
+
+ if (demand && wo->hisaddr == 0) {
+ option_error("remote IP address required for demand-dialling\n");
+ exit(1);
+ }
+ if (demand && wo->accept_remote) {
+ option_error("ipcp-accept-remote is incompatible with demand\n");
+ exit(1);
+ }
+}
+
+
+/*
+ * ip_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+static int
+ip_demand_conf(u)
+ int u;
+{
+ ipcp_options *wo = &ipcp_wantoptions[u];
+
+ if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+ return 0;
+ if (!sifup(u))
+ return 0;
+ if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+ return 0;
+ if (wo->default_route)
+ if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
+ default_route_set[u] = 1;
+ if (wo->proxy_arp)
+ if (sifproxyarp(u, wo->hisaddr))
+ proxy_arp_set[u] = 1;
+
+ syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(wo->ouraddr));
+ syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr));
+
+ return 1;
+}
+
+
+/*
* ipcp_up - IPCP has come UP.
*
* Configure the IP network interface appropriately and bring it up.
@@ -998,25 +1134,25 @@ ipcp_up(f)
u_int32_t mask;
ipcp_options *ho = &ipcp_hisoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+ np_up(f->unit, PPP_IP);
IPCPDEBUG((LOG_INFO, "ipcp: up"));
- go->default_route = 0;
- go->proxy_arp = 0;
/*
* We must have a non-zero IP address for both ends of the link.
*/
if (!ho->neg_addr)
- ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+ ho->hisaddr = wo->hisaddr;
if (ho->hisaddr == 0) {
syslog(LOG_ERR, "Could not determine remote IP address");
- ipcp_close(f->unit);
+ ipcp_close(f->unit, "Could not determine remote IP address");
return;
}
if (go->ouraddr == 0) {
syslog(LOG_ERR, "Could not determine local IP address");
- ipcp_close(f->unit);
+ ipcp_close(f->unit, "Could not determine local IP address");
return;
}
@@ -1026,42 +1162,93 @@ ipcp_up(f)
if (!auth_ip_addr(f->unit, ho->hisaddr)) {
syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
ip_ntoa(ho->hisaddr));
- ipcp_close(f->unit);
+ ipcp_close(f->unit, "Unauthorized remote IP address");
return;
}
- syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
- syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
/*
- * Set IP addresses and (if specified) netmask.
+ * If we are doing dial-on-demand, the interface is already
+ * configured, so we put out any saved-up packets, then set the
+ * interface to pass IP packets.
*/
- mask = GetMask(go->ouraddr);
- if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
- IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
- ipcp_close(f->unit);
- return;
- }
+ if (demand) {
+ if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+ if (go->ouraddr != wo->ouraddr)
+ syslog(LOG_WARNING, "Local IP address changed to %s",
+ ip_ntoa(go->ouraddr));
+ if (ho->hisaddr != wo->hisaddr)
+ syslog(LOG_WARNING, "Remote IP address changed to %s",
+ ip_ntoa(ho->hisaddr));
+ ipcp_clear_addrs(f->unit);
+
+ /* Set the interface to the new addresses */
+ mask = GetMask(go->ouraddr);
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
- /* set tcp compression */
- sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+ default_route_set[f->unit] = 1;
- /* bring the interface up for IP */
- if (!sifup(f->unit)) {
- IPCPDEBUG((LOG_WARNING, "sifup failed"));
- ipcp_close(f->unit);
- return;
- }
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ proxy_arp_set[f->unit] = 1;
- /* assign a default route through the interface if required */
- if (ipcp_wantoptions[f->unit].default_route)
- if (sifdefaultroute(f->unit, ho->hisaddr))
- go->default_route = 1;
+ }
+ demand_rexmit(PPP_IP);
+ sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+ } else {
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ IPCPDEBUG((LOG_WARNING, "sifup failed"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
- /* Make a proxy ARP entry if requested. */
- if (ipcp_wantoptions[f->unit].proxy_arp)
- if (sifproxyarp(f->unit, ho->hisaddr))
- go->proxy_arp = 1;
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
+ sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+ default_route_set[f->unit] = 1;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ proxy_arp_set[f->unit] = 1;
+
+ syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
+ syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+ }
/*
* Execute the ip-up script, like this:
@@ -1082,18 +1269,20 @@ static void
ipcp_down(f)
fsm *f;
{
- u_int32_t ouraddr, hisaddr;
-
IPCPDEBUG((LOG_INFO, "ipcp: down"));
+ np_down(f->unit, PPP_IP);
+ sifvjcomp(f->unit, 0, 0, 0);
- ouraddr = ipcp_gotoptions[f->unit].ouraddr;
- hisaddr = ipcp_hisoptions[f->unit].hisaddr;
- if (ipcp_gotoptions[f->unit].proxy_arp)
- cifproxyarp(f->unit, hisaddr);
- if (ipcp_gotoptions[f->unit].default_route)
- cifdefaultroute(f->unit, hisaddr);
- sifdown(f->unit);
- cifaddr(f->unit, ouraddr, hisaddr);
+ /*
+ * If we are doing dial-on-demand, set the interface
+ * to queue up outgoing packets (for now).
+ */
+ if (demand) {
+ sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
+ } else {
+ sifdown(f->unit);
+ ipcp_clear_addrs(f->unit);
+ }
/* Execute the ip-down script */
ipcp_script(f, _PATH_IPDOWN);
@@ -1101,6 +1290,41 @@ ipcp_down(f)
/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes,
+ * proxy arp entries, etc.
+ */
+static void
+ipcp_clear_addrs(unit)
+ int unit;
+{
+ u_int32_t ouraddr, hisaddr;
+
+ ouraddr = ipcp_gotoptions[unit].ouraddr;
+ hisaddr = ipcp_hisoptions[unit].hisaddr;
+ if (proxy_arp_set[unit]) {
+ cifproxyarp(unit, hisaddr);
+ proxy_arp_set[unit] = 0;
+ }
+ if (default_route_set[unit]) {
+ cifdefaultroute(unit, ouraddr, hisaddr);
+ default_route_set[unit] = 0;
+ }
+ cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(f)
+ fsm *f;
+{
+ np_finished(f->unit, PPP_IP);
+}
+
+
+/*
* ipcp_script - Execute a script with arguments
* interface-name tty-name speed local-IP remote-IP.
*/
@@ -1130,16 +1354,16 @@ ipcp_script(f, script)
/*
* ipcp_printpkt - print the contents of an IPCP packet.
*/
-char *ipcp_codenames[] = {
+static char *ipcp_codenames[] = {
"ConfReq", "ConfAck", "ConfNak", "ConfRej",
"TermReq", "TermAck", "CodeRej"
};
-int
+static int
ipcp_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
- void (*printer)();
+ void (*printer) __P((void *, char *, ...));
void *arg;
{
int code, id, len, olen;
@@ -1212,33 +1436,17 @@ ipcp_printpkt(p, plen, printer, arg)
printer(arg, "addr %s", ip_ntoa(htonl(cilong)));
}
break;
- case CI_DNS1:
- if (olen == CILEN_ADDR) {
- p += 2;
- GETLONG(cilong, p);
- printer(arg, "dns1 %s", ip_ntoa(htonl(cilong)));
- }
- break;
- case CI_DNS2:
- if (olen == CILEN_ADDR) {
- p += 2;
- GETLONG(cilong, p);
- printer(arg, "dns2 %s", ip_ntoa(htonl(cilong)));
- }
- break;
- case CI_NBNS1:
- if (olen == CILEN_ADDR) {
- p += 2;
- GETLONG(cilong, p);
- printer(arg, "nbns1 %s", ip_ntoa(htonl(cilong)));
- }
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "dns-addr %s", ip_ntoa(htonl(cilong)));
break;
- case CI_NBNS2:
- if (olen == CILEN_ADDR) {
- p += 2;
- GETLONG(cilong, p);
- printer(arg, "nbns2 %s", ip_ntoa(htonl(cilong)));
- }
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "wins-addr %s", ip_ntoa(htonl(cilong)));
break;
}
while (p < optend) {
@@ -1248,6 +1456,16 @@ ipcp_printpkt(p, plen, printer, arg)
printer(arg, ">");
}
break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string(p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
}
/* print the rest of the bytes in the packet */
@@ -1258,3 +1476,51 @@ ipcp_printpkt(p, plen, printer, arg)
return p - pstart;
}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN 20 /* bytes */
+#define IP_OFFMASK 0x1fff
+#define IPPROTO_TCP 6
+#define TCP_HDRLEN 20
+#define TH_FIN 0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x) (((x)[0] << 8) + (x)[1])
+#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x) (((unsigned char *)(x))[9])
+#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x) (((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(pkt, len)
+ u_char *pkt;
+ int len;
+{
+ u_char *tcp;
+ int hlen;
+
+ len -= PPP_HDRLEN;
+ pkt += PPP_HDRLEN;
+ if (len < IP_HDRLEN)
+ return 0;
+ if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+ return 0;
+ if (get_ipproto(pkt) != IPPROTO_TCP)
+ return 1;
+ hlen = get_iphl(pkt) * 4;
+ if (len < hlen + TCP_HDRLEN)
+ return 0;
+ tcp = pkt + hlen;
+ if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+ return 0;
+ return 1;
+}
diff --git a/usr.sbin/pppd/ipcp.h b/usr.sbin/pppd/ipcp.h
index dafc115..90a625a 100644
--- a/usr.sbin/pppd/ipcp.h
+++ b/usr.sbin/pppd/ipcp.h
@@ -25,10 +25,11 @@
#define CI_ADDRS 1 /* IP Addresses */
#define CI_COMPRESSTYPE 2 /* Compression Type */
#define CI_ADDR 3
-#define CI_DNS1 129 /* Primary DNS */
-#define CI_NBNS1 130 /* Primary NBNS */
-#define CI_DNS2 131 /* Secondary DNS */
-#define CI_NBNS2 132 /* Secondary NBNS */
+
+#define CI_MS_WINS1 128 /* Primary WINS value */
+#define CI_MS_DNS1 129 /* Primary DNS value */
+#define CI_MS_WINS2 130 /* Secondary WINS value */
+#define CI_MS_DNS2 131 /* Secondary DNS value */
#define MAX_STATES 16 /* from slcompress.h */
@@ -54,6 +55,8 @@ typedef struct ipcp_options {
u_short vj_protocol; /* protocol value to use in VJ option */
u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */
u_int32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+ u_int32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */
+ u_int32_t winsaddr[2]; /* Primary and secondary MS WINS entries */
} ipcp_options;
extern fsm ipcp_fsm[];
@@ -62,11 +65,6 @@ extern ipcp_options ipcp_gotoptions[];
extern ipcp_options ipcp_allowoptions[];
extern ipcp_options ipcp_hisoptions[];
-void ipcp_init __P((int));
-void ipcp_open __P((int));
-void ipcp_close __P((int));
-void ipcp_lowerup __P((int));
-void ipcp_lowerdown __P((int));
-void ipcp_input __P((int, u_char *, int));
-void ipcp_protrej __P((int));
-int ipcp_printpkt __P((u_char *, int, void (*)(), void *));
+char *ip_ntoa __P((u_int32_t));
+
+extern struct protent ipcp_protent;
diff --git a/usr.sbin/pppd/ipxcp.c b/usr.sbin/pppd/ipxcp.c
new file mode 100644
index 0000000..9390643
--- /dev/null
+++ b/usr.sbin/pppd/ipxcp.c
@@ -0,0 +1,1414 @@
+/*
+ * ipxcp.c - PPP IPX Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef IPX_CHANGE
+#ifndef lint
+static char rcsid[] = "$Id$";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipxcp.h"
+#include "pathnames.h"
+
+/* global vars */
+ipxcp_options ipxcp_wantoptions[NUM_PPP]; /* Options that we want to request */
+ipxcp_options ipxcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */
+ipxcp_options ipxcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
+ipxcp_options ipxcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
+
+#define wo (&ipxcp_wantoptions[0])
+#define ao (&ipxcp_allowoptions[0])
+#define go (&ipxcp_gotoptions[0])
+#define ho (&ipxcp_hisoptions[0])
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipxcp_resetci __P((fsm *)); /* Reset our CI */
+static int ipxcp_cilen __P((fsm *)); /* Return length of our CI */
+static void ipxcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int ipxcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipxcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipxcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipxcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipxcp_up __P((fsm *)); /* We're UP */
+static void ipxcp_down __P((fsm *)); /* We're DOWN */
+static void ipxcp_script __P((fsm *, char *)); /* Run an up/down script */
+
+fsm ipxcp_fsm[NUM_PPP]; /* IPXCP fsm structure */
+
+static fsm_callbacks ipxcp_callbacks = { /* IPXCP callback routines */
+ ipxcp_resetci, /* Reset our Configuration Information */
+ ipxcp_cilen, /* Length of our Configuration Information */
+ ipxcp_addci, /* Add our Configuration Information */
+ ipxcp_ackci, /* ACK our Configuration Information */
+ ipxcp_nakci, /* NAK our Configuration Information */
+ ipxcp_rejci, /* Reject our Configuration Information */
+ ipxcp_reqci, /* Request peer's Configuration Information */
+ ipxcp_up, /* Called when fsm reaches OPENED state */
+ ipxcp_down, /* Called when fsm leaves OPENED state */
+ NULL, /* Called when we want the lower layer up */
+ NULL, /* Called when we want the lower layer down */
+ NULL, /* Called when Protocol-Reject received */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPXCP" /* String name of protocol */
+};
+
+/*
+ * Protocol entry points.
+ */
+
+static void ipxcp_init __P((int));
+static void ipxcp_open __P((int));
+static void ipxcp_close __P((int, char *));
+static void ipxcp_lowerup __P((int));
+static void ipxcp_lowerdown __P((int));
+static void ipxcp_input __P((int, u_char *, int));
+static void ipxcp_protrej __P((int));
+static int ipxcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent ipxcp_protent = {
+ PPP_IPXCP,
+ ipxcp_init,
+ ipxcp_input,
+ ipxcp_protrej,
+ ipxcp_lowerup,
+ ipxcp_lowerdown,
+ ipxcp_open,
+ ipxcp_close,
+ ipxcp_printpkt,
+ NULL,
+ 0,
+ "IPXCP",
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Lengths of configuration options.
+ */
+
+#define CILEN_VOID 2
+#define CILEN_COMPLETE 2 /* length of complete option */
+#define CILEN_NETN 6 /* network number length option */
+#define CILEN_NODEN 8 /* node number length option */
+#define CILEN_PROTOCOL 4 /* Minimum length of routing protocol */
+#define CILEN_NAME 3 /* Minimum length of router name */
+#define CILEN_COMPRESS 4 /* Minimum length of compression protocol */
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+/* Used in printing the node number */
+#define NODE(base) base[0], base[1], base[2], base[3], base[4], base[5]
+
+/* Used to generate the proper bit mask */
+#define BIT(num) (1 << (num))
+
+/*
+ * Convert from internal to external notation
+ */
+
+static short int
+to_external(internal)
+short int internal;
+{
+ short int external;
+
+ if (internal & IPX_NONE)
+ external = IPX_NONE;
+ else
+ external = RIP_SAP;
+
+ return external;
+}
+
+/*
+ * Make a string representation of a network IP address.
+ */
+
+char *
+ipx_ntoa(ipxaddr)
+u_int32_t ipxaddr;
+{
+ static char b[64];
+ sprintf(b, "%lx", ipxaddr);
+ return b;
+}
+
+
+/*
+ * ipxcp_init - Initialize IPXCP.
+ */
+static void
+ipxcp_init(unit)
+ int unit;
+{
+ fsm *f = &ipxcp_fsm[unit];
+
+ f->unit = unit;
+ f->protocol = PPP_IPXCP;
+ f->callbacks = &ipxcp_callbacks;
+ fsm_init(&ipxcp_fsm[unit]);
+
+ memset (wo->name, 0, sizeof (wo->name));
+ memset (wo->our_node, 0, sizeof (wo->our_node));
+ memset (wo->his_node, 0, sizeof (wo->his_node));
+
+ wo->neg_nn = 1;
+ wo->neg_complete = 1;
+ wo->network = 0;
+
+ ao->neg_node = 1;
+ ao->neg_nn = 1;
+ ao->neg_name = 1;
+ ao->neg_complete = 1;
+ ao->neg_router = 1;
+
+ ao->accept_local = 0;
+ ao->accept_remote = 0;
+ ao->accept_network = 0;
+
+ wo->tried_rip = 0;
+ wo->tried_nlsp = 0;
+}
+
+/*
+ * Copy the node number
+ */
+
+static void
+copy_node (src, dst)
+u_char *src, *dst;
+{
+ memcpy (dst, src, sizeof (ipxcp_wantoptions[0].our_node));
+}
+
+/*
+ * Compare node numbers
+ */
+
+static int
+compare_node (src, dst)
+u_char *src, *dst;
+{
+ return memcmp (dst, src, sizeof (ipxcp_wantoptions[0].our_node)) == 0;
+}
+
+/*
+ * Is the node number zero?
+ */
+
+static int
+zero_node (node)
+u_char *node;
+{
+ int indx;
+ for (indx = 0; indx < sizeof (ipxcp_wantoptions[0].our_node); ++indx)
+ if (node [indx] != 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Increment the node number
+ */
+
+static void
+inc_node (node)
+u_char *node;
+{
+ u_char *outp;
+ u_int32_t magic_num;
+
+ outp = node;
+ magic_num = magic();
+ *outp++ = '\0';
+ *outp++ = '\0';
+ PUTLONG (magic_num, outp);
+}
+
+/*
+ * ipxcp_open - IPXCP is allowed to come up.
+ */
+static void
+ipxcp_open(unit)
+ int unit;
+{
+ fsm_open(&ipxcp_fsm[unit]);
+}
+
+/*
+ * ipxcp_close - Take IPXCP down.
+ */
+static void
+ipxcp_close(unit, reason)
+ int unit;
+ char *reason;
+{
+ fsm_close(&ipxcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipxcp_lowerup - The lower layer is up.
+ */
+static void
+ipxcp_lowerup(unit)
+ int unit;
+{
+ fsm_lowerup(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_lowerdown - The lower layer is down.
+ */
+static void
+ipxcp_lowerdown(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_input - Input IPXCP packet.
+ */
+static void
+ipxcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ fsm_input(&ipxcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipxcp_protrej - A Protocol-Reject was received for IPXCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipxcp_protrej(unit)
+ int unit;
+{
+ fsm_lowerdown(&ipxcp_fsm[unit]);
+}
+
+
+/*
+ * ipxcp_resetci - Reset our CI.
+ */
+static void
+ipxcp_resetci(f)
+ fsm *f;
+{
+ u_int32_t network;
+ int unit = f->unit;
+
+ wo->req_node = wo->neg_node && ao->neg_node;
+ wo->req_nn = wo->neg_nn && ao->neg_nn;
+
+ if (wo->our_network == 0) {
+ wo->neg_node = 1;
+ ao->accept_network = 1;
+ }
+/*
+ * If our node number is zero then change it.
+ */
+ if (zero_node (wo->our_node)) {
+ inc_node (wo->our_node);
+ ao->accept_local = 1;
+ wo->neg_node = 1;
+ }
+/*
+ * If his node number is zero then change it.
+ */
+ if (zero_node (wo->his_node)) {
+ inc_node (wo->his_node);
+ ao->accept_remote = 1;
+ }
+/*
+ * If no routing agent was specified then we do RIP/SAP according to the
+ * RFC documents. If you have specified something then OK. Otherwise, we
+ * do RIP/SAP.
+ */
+ if (ao->router == 0) {
+ ao->router |= BIT(RIP_SAP);
+ wo->router |= BIT(RIP_SAP);
+ }
+
+ /* Always specify a routing protocol unless it was REJected. */
+ wo->neg_router = 1;
+/*
+ * Start with these default values
+ */
+ *go = *wo;
+}
+
+/*
+ * ipxcp_cilen - Return length of our CI.
+ */
+
+static int
+ipxcp_cilen(f)
+ fsm *f;
+{
+ int unit = f->unit;
+ int len;
+
+ len = go->neg_nn ? CILEN_NETN : 0;
+ len += go->neg_node ? CILEN_NODEN : 0;
+ len += go->neg_name ? CILEN_NAME + strlen (go->name) - 1 : 0;
+
+ /* RFC says that defaults should not be included. */
+ if (go->neg_router && to_external(go->router) != RIP_SAP)
+ len += CILEN_PROTOCOL;
+
+ return (len);
+}
+
+
+/*
+ * ipxcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipxcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
+{
+ int len = *lenp;
+ int unit = f->unit;
+/*
+ * Add the options to the record.
+ */
+ if (go->neg_nn) {
+ PUTCHAR (IPX_NETWORK_NUMBER, ucp);
+ PUTCHAR (CILEN_NETN, ucp);
+ PUTLONG (go->our_network, ucp);
+ }
+
+ if (go->neg_node) {
+ int indx;
+ PUTCHAR (IPX_NODE_NUMBER, ucp);
+ PUTCHAR (CILEN_NODEN, ucp);
+ for (indx = 0; indx < sizeof (go->our_node); ++indx)
+ PUTCHAR (go->our_node[indx], ucp);
+ }
+
+ if (go->neg_name) {
+ int cilen = strlen (go->name);
+ int indx;
+ PUTCHAR (IPX_ROUTER_NAME, ucp);
+ PUTCHAR (CILEN_NAME + cilen - 1, ucp);
+ for (indx = 0; indx < cilen; ++indx)
+ PUTCHAR (go->name [indx], ucp);
+ }
+
+ if (go->neg_router) {
+ short external = to_external (go->router);
+ if (external != RIP_SAP) {
+ PUTCHAR (IPX_ROUTER_PROTOCOL, ucp);
+ PUTCHAR (CILEN_PROTOCOL, ucp);
+ PUTSHORT (external, ucp);
+ }
+ }
+}
+
+/*
+ * ipxcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ * 0 - Ack was bad.
+ * 1 - Ack was good.
+ */
+static int
+ipxcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ int unit = f->unit;
+ u_short cilen, citype, cishort;
+ u_char cichar;
+ u_int32_t cilong;
+
+#define ACKCIVOID(opt, neg) \
+ if (neg) { \
+ if ((len -= CILEN_VOID) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || \
+ citype != opt) \
+ break; \
+ }
+
+#define ACKCICOMPLETE(opt,neg) ACKCIVOID(opt, neg)
+
+#define ACKCICHARS(opt, neg, val, cnt) \
+ if (neg) { \
+ int indx, count = cnt; \
+ len -= (count + 2); \
+ if (len < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != (count + 2) || \
+ citype != opt) \
+ break; \
+ for (indx = 0; indx < count; ++indx) {\
+ GETCHAR(cichar, p); \
+ if (cichar != ((u_char *) &val)[indx]) \
+ break; \
+ }\
+ if (indx != count) \
+ break; \
+ }
+
+#define ACKCINODE(opt,neg,val) ACKCICHARS(opt,neg,val,sizeof(val))
+#define ACKCINAME(opt,neg,val) ACKCICHARS(opt,neg,val,strlen(val))
+
+#define ACKCINETWORK(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_NETN) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_NETN || \
+ citype != opt) \
+ break; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ break; \
+ }
+
+#define ACKCIPROTO(opt, neg, val) \
+ if (neg) { \
+ if (len < 2) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_PROTOCOL || citype != opt) \
+ break; \
+ len -= cilen; \
+ if (len < 0) \
+ break; \
+ GETSHORT(cishort, p); \
+ if (cishort != to_external (val) || cishort == RIP_SAP) \
+ break; \
+ }
+/*
+ * Process the ACK frame in the order in which the frame was assembled
+ */
+ do {
+ ACKCINETWORK (IPX_NETWORK_NUMBER, go->neg_nn, go->our_network);
+ ACKCINODE (IPX_NODE_NUMBER, go->neg_node, go->our_node);
+ ACKCINAME (IPX_ROUTER_NAME, go->neg_name, go->name);
+ ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+ ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+ ACKCIPROTO (IPX_ROUTER_PROTOCOL, go->neg_router, go->router);
+/*
+ * This is the end of the record.
+ */
+ if (len == 0)
+ return (1);
+ } while (0);
+/*
+ * The frame is invalid
+ */
+ IPXCPDEBUG((LOG_INFO, "ipxcp_ackci: received bad Ack!"));
+ return (0);
+}
+
+/*
+ * ipxcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPXCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
+ */
+
+static int
+ipxcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ int unit = f->unit;
+ u_char citype, cilen, *next;
+ u_short s;
+ u_int32_t l;
+ ipxcp_options no; /* options we've seen Naks for */
+ ipxcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
+ while (len > CILEN_VOID) {
+ GETCHAR (citype, p);
+ GETCHAR (cilen, p);
+ len -= cilen;
+ if (len < 0)
+ goto bad;
+ next = &p [cilen - CILEN_VOID];
+
+ switch (citype) {
+ case IPX_NETWORK_NUMBER:
+ if (!go->neg_nn || no.neg_nn || (cilen != CILEN_NETN))
+ goto bad;
+ no.neg_nn = 1;
+
+ GETLONG(l, p);
+ IPXCPDEBUG((LOG_INFO, "local IP address %d", l));
+ if (l && ao->accept_network)
+ try.our_network = l;
+ break;
+
+ case IPX_NODE_NUMBER:
+ if (!go->neg_node || no.neg_node || (cilen != CILEN_NODEN))
+ goto bad;
+ no.neg_node = 1;
+
+ IPXCPDEBUG((LOG_INFO,
+ "local node number %02X%02X%02X%02X%02X%02X",
+ NODE(p)));
+
+ if (!zero_node (p) && ao->accept_local &&
+ ! compare_node (p, ho->his_node))
+ copy_node (p, try.our_node);
+ break;
+
+ /* This has never been sent. Ignore the NAK frame */
+ case IPX_COMPRESSION_PROTOCOL:
+ goto bad;
+
+ case IPX_ROUTER_PROTOCOL:
+ if (!go->neg_router || (cilen < CILEN_PROTOCOL))
+ goto bad;
+
+ GETSHORT (s, p);
+ if (s > 15) /* This is just bad, but ignore for now. */
+ break;
+
+ s = BIT(s);
+ if (no.router & s) /* duplicate NAKs are always bad */
+ goto bad;
+
+ if (no.router == 0) /* Reset on first NAK only */
+ try.router = 0;
+
+ no.router |= s;
+ try.router |= s;
+ try.neg_router = 1;
+
+ IPXCPDEBUG((LOG_INFO, "Router protocol number %d", s));
+ break;
+
+ /* These, according to the RFC, must never be NAKed. */
+ case IPX_ROUTER_NAME:
+ case IPX_COMPLETE:
+ goto bad;
+
+ /* These are for options which we have not seen. */
+ default:
+ break;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * Do not permit the peer to force a router protocol which we do not
+ * support. However, default to the condition that will accept "NONE".
+ */
+ try.router &= (ao->router | BIT(IPX_NONE));
+ if (try.router == 0 && ao->router != 0)
+ try.router = BIT(IPX_NONE);
+
+ if (try.router != 0)
+ try.neg_router = 1;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
+bad:
+ IPXCPDEBUG((LOG_INFO, "ipxcp_nakci: received bad Nak!"));
+ return 0;
+}
+
+/*
+ * ipxcp_rejci - Reject some of our CIs.
+ */
+static int
+ipxcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
+{
+ int unit = f->unit;
+ u_short cilen, citype, cishort;
+ u_char cichar;
+ u_int32_t cilong;
+ ipxcp_options try; /* options to request next time */
+
+#define REJCINETWORK(opt, neg, val) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_NETN) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_NETN || \
+ citype != opt) \
+ break; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ break; \
+ IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected long opt %d", opt)); \
+ neg = 0; \
+ }
+
+#define REJCICHARS(opt, neg, val, cnt) \
+ if (neg && p[0] == opt) { \
+ int indx, count = cnt; \
+ len -= (count + 2); \
+ if (len < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != (count + 2) || \
+ citype != opt) \
+ break; \
+ for (indx = 0; indx < count; ++indx) {\
+ GETCHAR(cichar, p); \
+ if (cichar != ((u_char *) &val)[indx]) \
+ break; \
+ }\
+ if (indx != count) \
+ break; \
+ IPXCPDEBUG((LOG_INFO,"ipxcp_rejci rejected opt %d", opt)); \
+ neg = 0; \
+ }
+
+#define REJCINODE(opt,neg,val) REJCICHARS(opt,neg,val,sizeof(val))
+#define REJCINAME(opt,neg,val) REJCICHARS(opt,neg,val,strlen(val))
+
+#define REJCIVOID(opt, neg) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_VOID) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_VOID || citype != opt) \
+ break; \
+ IPXCPDEBUG((LOG_INFO, "ipxcp_rejci rejected void opt %d", opt)); \
+ neg = 0; \
+ }
+
+/* a reject for RIP/SAP is invalid since we don't send it and you can't
+ reject something which is not sent. (You can NAK, but you can't REJ.) */
+#define REJCIPROTO(opt, neg, val, bit) \
+ if (neg && p[0] == opt) { \
+ if ((len -= CILEN_PROTOCOL) < 0) \
+ break; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_PROTOCOL) \
+ break; \
+ GETSHORT(cishort, p); \
+ if (cishort != to_external (val) || cishort == RIP_SAP) \
+ break; \
+ IPXCPDEBUG((LOG_INFO, "ipxcp_rejci short opt %d", opt)); \
+ neg = 0; \
+ }
+/*
+ * Any Rejected CIs must be in exactly the same order that we sent.
+ * Check packet length and CI length at each step.
+ * If we find any deviations, then this packet is bad.
+ */
+ try = *go;
+
+ do {
+ REJCINETWORK (IPX_NETWORK_NUMBER, try.neg_nn, try.our_network);
+ REJCINODE (IPX_NODE_NUMBER, try.neg_node, try.our_node);
+ REJCINAME (IPX_ROUTER_NAME, try.neg_name, try.name);
+ REJCIPROTO (IPX_ROUTER_PROTOCOL, try.neg_router, try.router, 0);
+/*
+ * This is the end of the record.
+ */
+ if (len == 0) {
+ if (f->state != OPENED)
+ *go = try;
+ return (1);
+ }
+ } while (0);
+/*
+ * The frame is invalid at this point.
+ */
+ IPXCPDEBUG((LOG_INFO, "ipxcp_rejci: received bad Reject!"));
+ return 0;
+}
+
+/*
+ * ipxcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipxcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
+{
+ int unit = f->unit;
+ u_char *cip, *next; /* Pointer to current and next CIs */
+ u_short cilen, citype; /* Parsed len, type */
+ u_short cishort, ts; /* Parsed short value */
+ u_int32_t tl, cinetwork, outnet;/* Parsed address values */
+ int rc = CONFACK; /* Final packet return code */
+ int orc; /* Individual option return code */
+ u_char *p; /* Pointer to next char to parse */
+ u_char *ucp = inp; /* Pointer to current output char */
+ int l = *len; /* Length left */
+ u_char maxslotindex, cflag;
+
+ /*
+ * Reset all his options.
+ */
+ BZERO(ho, sizeof(*ho));
+
+ /*
+ * Process all his options.
+ */
+ next = inp;
+ while (l) {
+ orc = CONFACK; /* Assume success */
+ cip = p = next; /* Remember begining of CI */
+ if (l < 2 || /* Not enough data for CI header or */
+ p[1] < 2 || /* CI length too small or */
+ p[1] > l) { /* CI length too big? */
+ IPXCPDEBUG((LOG_INFO, "ipxcp_reqci: bad CI length!"));
+ orc = CONFREJ; /* Reject bad CI */
+ cilen = l; /* Reject till end of packet */
+ l = 0; /* Don't loop again */
+ goto endswitch;
+ }
+ GETCHAR(citype, p); /* Parse CI type */
+ GETCHAR(cilen, p); /* Parse CI length */
+ l -= cilen; /* Adjust remaining length */
+ next += cilen; /* Step to next CI */
+
+ switch (citype) { /* Check CI type */
+/*
+ * The network number must match. Choose the larger of the two.
+ */
+ case IPX_NETWORK_NUMBER:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Network Number request"));
+
+ /* if we wont negotiate the network number or the length is wrong
+ then reject the option */
+ if ( !ao->neg_nn || cilen != CILEN_NETN ) {
+ orc = CONFREJ;
+ break;
+ }
+ GETLONG(cinetwork, p);
+ IPXCPDEBUG((LOG_INFO,"Remote proposed IPX network number is %8Lx",tl));
+
+ /* If the network numbers match then acknowledge them. */
+ if (cinetwork != 0) {
+ ho->his_network = cinetwork;
+ ho->neg_nn = 1;
+ if (wo->our_network == cinetwork)
+ break;
+/*
+ * If the network number is not given or we don't accept their change or
+ * the network number is too small then NAK it.
+ */
+ if (! ao->accept_network || cinetwork < wo->our_network) {
+ DECPTR (sizeof (u_int32_t), p);
+ PUTLONG (wo->our_network, p);
+ orc = CONFNAK;
+ }
+ break;
+ }
+/*
+ * The peer sent '0' for the network. Give it ours if we have one.
+ */
+ if (go->our_network != 0) {
+ DECPTR (sizeof (u_int32_t), p);
+ PUTLONG (wo->our_network, p);
+ orc = CONFNAK;
+/*
+ * We don't have one. Reject the value.
+ */
+ } else
+ orc = CONFREJ;
+
+ break;
+/*
+ * The node number is required
+ */
+ case IPX_NODE_NUMBER:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Node Number request"));
+
+ /* if we wont negotiate the node number or the length is wrong
+ then reject the option */
+ if ( cilen != CILEN_NODEN ) {
+ orc = CONFREJ;
+ break;
+ }
+
+ copy_node (p, ho->his_node);
+ ho->neg_node = 1;
+/*
+ * If the remote does not have a number and we do then NAK it with the value
+ * which we have for it. (We never have a default value of zero.)
+ */
+ if (zero_node (ho->his_node)) {
+ orc = CONFNAK;
+ copy_node (wo->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If you have given me the expected network node number then I'll accept
+ * it now.
+ */
+ if (compare_node (wo->his_node, ho->his_node)) {
+ orc = CONFACK;
+ ho->neg_node = 1;
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If his node number is the same as ours then ask him to try the next
+ * value.
+ */
+ if (compare_node (ho->his_node, go->our_node)) {
+ inc_node (ho->his_node);
+ orc = CONFNAK;
+ copy_node (ho->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+ }
+/*
+ * If we don't accept a new value then NAK it.
+ */
+ if (! ao->accept_remote) {
+ copy_node (wo->his_node, p);
+ INCPTR (sizeof (wo->his_node), p);
+ orc = CONFNAK;
+ break;
+ }
+ orc = CONFACK;
+ ho->neg_node = 1;
+ INCPTR (sizeof (wo->his_node), p);
+ break;
+/*
+ * Compression is not desired at this time. It is always rejected.
+ */
+ case IPX_COMPRESSION_PROTOCOL:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Compression Protocol request "));
+ orc = CONFREJ;
+ break;
+/*
+ * The routing protocol is a bitmask of various types. Any combination
+ * of the values RIP_SAP and NLSP are permissible. 'IPX_NONE' for no
+ * routing protocol must be specified only once.
+ */
+ case IPX_ROUTER_PROTOCOL:
+ if ( !ao->neg_router || cilen < CILEN_PROTOCOL ) {
+ orc = CONFREJ;
+ break;
+ }
+
+ GETSHORT (cishort, p);
+ IPXCPDEBUG((LOG_INFO,
+ "Remote router protocol number 0x%04x",
+ cishort));
+
+ if (wo->neg_router == 0) {
+ wo->neg_router = 1;
+ wo->router = BIT(IPX_NONE);
+ }
+
+ if ((cishort == IPX_NONE && ho->router != 0) ||
+ (ho->router & BIT(IPX_NONE))) {
+ orc = CONFREJ;
+ break;
+ }
+
+ cishort = BIT(cishort);
+ if (ho->router & cishort) {
+ orc = CONFREJ;
+ break;
+ }
+
+ ho->router |= cishort;
+ ho->neg_router = 1;
+
+ /* Finally do not allow a router protocol which we do not
+ support. */
+
+ if ((cishort & (ao->router | BIT(IPX_NONE))) == 0) {
+ int protocol;
+
+ if (cishort == BIT(NLSP) &&
+ (ao->router & BIT(RIP_SAP)) &&
+ !wo->tried_rip) {
+ protocol = RIP_SAP;
+ wo->tried_rip = 1;
+ } else
+ protocol = IPX_NONE;
+
+ DECPTR (sizeof (u_int16_t), p);
+ PUTSHORT (protocol, p);
+ orc = CONFNAK;
+ }
+ break;
+/*
+ * The router name is advisorary. Just accept it if it is not too large.
+ */
+ case IPX_ROUTER_NAME:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Router Name request"));
+ if (cilen >= CILEN_NAME) {
+ int name_size = cilen - CILEN_NAME;
+ if (name_size > sizeof (ho->name))
+ name_size = sizeof (ho->name) - 1;
+ memset (ho->name, 0, sizeof (ho->name));
+ memcpy (ho->name, p, name_size);
+ ho->name [name_size] = '\0';
+ ho->neg_name = 1;
+ orc = CONFACK;
+ break;
+ }
+ orc = CONFREJ;
+ break;
+/*
+ * This is advisorary.
+ */
+ case IPX_COMPLETE:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
+ if (cilen != CILEN_COMPLETE)
+ orc = CONFREJ;
+ else {
+ ho->neg_complete = 1;
+ orc = CONFACK;
+ }
+ break;
+/*
+ * All other entries are not known at this time.
+ */
+ default:
+ IPXCPDEBUG((LOG_INFO, "ipxcp: received Complete request"));
+ orc = CONFREJ;
+ break;
+ }
+
+endswitch:
+ IPXCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
+
+ if (orc == CONFACK && /* Good CI */
+ rc != CONFACK) /* but prior CI wasnt? */
+ continue; /* Don't send this one */
+
+ if (orc == CONFNAK) { /* Nak this CI? */
+ if (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ if (rc == CONFREJ) /* Rejecting prior CI? */
+ continue; /* Don't send this one */
+ if (rc == CONFACK) { /* Ack'd all prior CIs? */
+ rc = CONFNAK; /* Not anymore... */
+ ucp = inp; /* Backup */
+ }
+ }
+
+ if (orc == CONFREJ && /* Reject this CI */
+ rc != CONFREJ) { /* but no prior ones? */
+ rc = CONFREJ;
+ ucp = inp; /* Backup */
+ }
+
+ /* Need to move CI? */
+ if (ucp != cip)
+ BCOPY(cip, ucp, cilen); /* Move it */
+
+ /* Update output pointer */
+ INCPTR(cilen, ucp);
+ }
+
+ /*
+ * If we aren't rejecting this packet, and we want to negotiate
+ * their address, and they didn't send their address, then we
+ * send a NAK with a IPX_NODE_NUMBER option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
+ */
+
+ if (rc != CONFREJ && !ho->neg_node &&
+ wo->req_nn && !reject_if_disagree) {
+ u_char *ps;
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ wo->req_nn = 0; /* don't ask again */
+ ucp = inp; /* reset pointer */
+ }
+
+ if (zero_node (wo->his_node))
+ inc_node (wo->his_node);
+
+ PUTCHAR (IPX_NODE_NUMBER, ucp);
+ PUTCHAR (CILEN_NODEN, ucp);
+ copy_node (wo->his_node, ucp);
+ INCPTR (sizeof (wo->his_node), ucp);
+ }
+
+ *len = ucp - inp; /* Compute output length */
+ IPXCPDEBUG((LOG_INFO, "ipxcp: returning Configure-%s", CODENAME(rc)));
+ return (rc); /* Return final code */
+}
+
+/*
+ * ipxcp_up - IPXCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+
+static void
+ipxcp_up(f)
+ fsm *f;
+{
+ int unit = f->unit;
+
+ IPXCPDEBUG((LOG_INFO, "ipxcp: up"));
+
+ /* The default router protocol is RIP/SAP. */
+ if (ho->router == 0)
+ ho->router = BIT(RIP_SAP);
+
+ if (go->router == 0)
+ go->router = BIT(RIP_SAP);
+
+ /* Fetch the network number */
+ if (!ho->neg_nn)
+ ho->his_network = wo->his_network;
+
+ if (!ho->neg_node)
+ copy_node (wo->his_node, ho->his_node);
+
+ if (!wo->neg_node && !go->neg_node)
+ copy_node (wo->our_node, go->our_node);
+
+ if (zero_node (go->our_node)) {
+ static char errmsg[] = "Could not determine local IPX node address";
+ IPXCPDEBUG((LOG_ERR, errmsg));
+ ipxcp_close(f->unit, errmsg);
+ return;
+ }
+
+ go->network = go->our_network;
+ if (ho->his_network != 0 && ho->his_network > go->network)
+ go->network = ho->his_network;
+
+ if (go->network == 0) {
+ static char errmsg[] = "Can not determine network number";
+ IPXCPDEBUG((LOG_ERR, errmsg));
+ ipxcp_close (unit, errmsg);
+ return;
+ }
+
+ /* bring the interface up */
+ if (!sifup(unit)) {
+ IPXCPDEBUG((LOG_WARNING, "sifup failed"));
+ ipxcp_close(unit, "Interface configuration failed");
+ return;
+ }
+
+ /* set the network number for IPX */
+ if (!sipxfaddr(unit, go->network, go->our_node)) {
+ IPXCPDEBUG((LOG_WARNING, "sipxfaddr failed"));
+ ipxcp_close(unit, "Interface configuration failed");
+ return;
+ }
+
+ /*
+ * Execute the ipx-up script, like this:
+ * /etc/ppp/ipx-up interface tty speed local-IPX remote-IPX
+ */
+
+ ipxcp_script (f, _PATH_IPXUP);
+}
+
+/*
+ * ipxcp_down - IPXCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+
+static void
+ipxcp_down(f)
+ fsm *f;
+{
+ u_int32_t ournn, network;
+
+ IPXCPDEBUG((LOG_INFO, "ipxcp: down"));
+
+ cipxfaddr (f->unit);
+ sifdown(f->unit);
+ ipxcp_script (f, _PATH_IPXDOWN);
+}
+
+
+/*
+ * ipxcp_script - Execute a script with arguments
+ * interface-name tty-name speed local-IPX remote-IPX networks.
+ */
+static void
+ipxcp_script(f, script)
+ fsm *f;
+ char *script;
+{
+ int unit = f->unit;
+ char strspeed[32], strlocal[32], strremote[32];
+ char strnetwork[32], strpid[32];
+ char *argv[14], strproto_lcl[32], strproto_rmt[32];
+
+ sprintf (strpid, "%d", getpid());
+ sprintf (strspeed, "%d", baud_rate);
+
+ strproto_lcl[0] = '\0';
+ if (go->neg_router && ((go->router & BIT(IPX_NONE)) == 0)) {
+ if (go->router & BIT(RIP_SAP))
+ strcpy (strproto_lcl, "RIP ");
+ if (go->router & BIT(NLSP))
+ strcat (strproto_lcl, "NLSP ");
+ }
+
+ if (strproto_lcl[0] == '\0')
+ strcpy (strproto_lcl, "NONE ");
+
+ strproto_lcl[strlen (strproto_lcl)-1] = '\0';
+
+ strproto_rmt[0] = '\0';
+ if (ho->neg_router && ((ho->router & BIT(IPX_NONE)) == 0)) {
+ if (ho->router & BIT(RIP_SAP))
+ strcpy (strproto_rmt, "RIP ");
+ if (ho->router & BIT(NLSP))
+ strcat (strproto_rmt, "NLSP ");
+ }
+
+ if (strproto_rmt[0] == '\0')
+ strcpy (strproto_rmt, "NONE ");
+
+ strproto_rmt[strlen (strproto_rmt)-1] = '\0';
+
+ strcpy (strnetwork, ipx_ntoa (go->network));
+
+ sprintf (strlocal,
+ "%02X%02X%02X%02X%02X%02X",
+ NODE(go->our_node));
+
+ sprintf (strremote,
+ "%02X%02X%02X%02X%02X%02X",
+ NODE(ho->his_node));
+
+ argv[0] = script;
+ argv[1] = ifname;
+ argv[2] = devnam;
+ argv[3] = strspeed;
+ argv[4] = strnetwork;
+ argv[5] = strlocal;
+ argv[6] = strremote;
+ argv[7] = strproto_lcl;
+ argv[8] = strproto_rmt;
+ argv[9] = go->name;
+ argv[10] = ho->name;
+ argv[11] = ipparam;
+ argv[12] = strpid;
+ argv[13] = NULL;
+ run_program(script, argv, 0);
+}
+
+/*
+ * ipxcp_printpkt - print the contents of an IPXCP packet.
+ */
+static char *ipxcp_codenames[] = {
+ "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+ "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipxcp_printpkt(p, plen, printer, arg)
+ u_char *p;
+ int plen;
+ void (*printer) __P((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_int32_t cilong;
+
+ if (plen < HEADERLEN)
+ return 0;
+ pstart = p;
+ GETCHAR(code, p);
+ GETCHAR(id, p);
+ GETSHORT(len, p);
+ if (len < HEADERLEN || len > plen)
+ return 0;
+
+ if (code >= 1 && code <= sizeof(ipxcp_codenames) / sizeof(char *))
+ printer(arg, " %s", ipxcp_codenames[code-1]);
+ else
+ printer(arg, " code=0x%x", code);
+ printer(arg, " id=0x%x", id);
+ len -= HEADERLEN;
+ switch (code) {
+ case CONFREQ:
+ case CONFACK:
+ case CONFNAK:
+ case CONFREJ:
+ /* print option list */
+ while (len >= 2) {
+ GETCHAR(code, p);
+ GETCHAR(olen, p);
+ p -= 2;
+ if (olen < CILEN_VOID || olen > len) {
+ break;
+ }
+ printer(arg, " <");
+ len -= olen;
+ optend = p + olen;
+ switch (code) {
+ case IPX_NETWORK_NUMBER:
+ if (olen == CILEN_NETN) {
+ p += 2;
+ GETLONG(cilong, p);
+ printer (arg, "network %s", ipx_ntoa (cilong));
+ }
+ break;
+ case IPX_NODE_NUMBER:
+ if (olen == CILEN_NODEN) {
+ p += 2;
+ printer (arg, "node ");
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, "%.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ }
+ break;
+ case IPX_COMPRESSION_PROTOCOL:
+ if (olen == CILEN_COMPRESS) {
+ p += 2;
+ GETSHORT (cishort, p);
+ printer (arg, "compression %d", (int) cishort);
+ }
+ break;
+ case IPX_ROUTER_PROTOCOL:
+ if (olen == CILEN_PROTOCOL) {
+ p += 2;
+ GETSHORT (cishort, p);
+ printer (arg, "router proto %d", (int) cishort);
+ }
+ break;
+ case IPX_ROUTER_NAME:
+ if (olen >= CILEN_NAME) {
+ p += 2;
+ printer (arg, "router name \"");
+ while (p < optend) {
+ GETCHAR(code, p);
+ if (code >= 0x20 && code <= 0x7E)
+ printer (arg, "%c", (int) (unsigned int) (unsigned char) code);
+ else
+ printer (arg, " \\%.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ printer (arg, "\"");
+ }
+ break;
+ case IPX_COMPLETE:
+ if (olen == CILEN_COMPLETE) {
+ p += 2;
+ printer (arg, "complete");
+ }
+ break;
+ default:
+ break;
+ }
+
+ while (p < optend) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code);
+ }
+ printer(arg, ">");
+ }
+ break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string(p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+ }
+
+ /* print the rest of the bytes in the packet */
+ for (; len > 0; --len) {
+ GETCHAR(code, p);
+ printer(arg, " %.2x", (int) (unsigned int) (unsigned char) code);
+ }
+
+ return p - pstart;
+}
+#endif /* ifdef IPX_CHANGE */
diff --git a/usr.sbin/pppd/ipxcp.h b/usr.sbin/pppd/ipxcp.h
new file mode 100644
index 0000000..139a726
--- /dev/null
+++ b/usr.sbin/pppd/ipxcp.h
@@ -0,0 +1,71 @@
+/*
+ * ipxcp.h - IPX Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+/*
+ * Options.
+ */
+#define IPX_NETWORK_NUMBER 1 /* IPX Network Number */
+#define IPX_NODE_NUMBER 2
+#define IPX_COMPRESSION_PROTOCOL 3
+#define IPX_ROUTER_PROTOCOL 4
+#define IPX_ROUTER_NAME 5
+#define IPX_COMPLETE 6
+
+/* Values for the router protocol */
+#define IPX_NONE 0
+#define RIP_SAP 2
+#define NLSP 4
+
+typedef struct ipxcp_options {
+ int neg_node : 1; /* Negotiate IPX node number? */
+ int req_node : 1; /* Ask peer to send IPX node number? */
+
+ int neg_nn : 1; /* Negotiate IPX network number? */
+ int req_nn : 1; /* Ask peer to send IPX network number */
+
+ int neg_name : 1; /* Negotiate IPX router name */
+ int neg_complete : 1; /* Negotiate completion */
+ int neg_router : 1; /* Negotiate IPX router number */
+
+ int accept_local : 1; /* accept peer's value for ournode */
+ int accept_remote : 1; /* accept peer's value for hisnode */
+ int accept_network : 1; /* accept network number */
+
+ int tried_nlsp : 1; /* I have suggested NLSP already */
+ int tried_rip : 1; /* I have suggested RIP/SAP already */
+
+ u_int32_t his_network; /* base network number */
+ u_int32_t our_network; /* our value for network number */
+ u_int32_t network; /* the final network number */
+
+ u_char his_node[6]; /* peer's node number */
+ u_char our_node[6]; /* our node number */
+ u_char name [48]; /* name of the router */
+ int router; /* routing protocol */
+} ipxcp_options;
+
+extern fsm ipxcp_fsm[];
+extern ipxcp_options ipxcp_wantoptions[];
+extern ipxcp_options ipxcp_gotoptions[];
+extern ipxcp_options ipxcp_allowoptions[];
+extern ipxcp_options ipxcp_hisoptions[];
+
+extern struct protent ipxcp_protent;
diff --git a/usr.sbin/pppd/lcp.c b/usr.sbin/pppd/lcp.c
index 25256ad..325806b 100644
--- a/usr.sbin/pppd/lcp.c
+++ b/usr.sbin/pppd/lcp.c
@@ -38,15 +38,8 @@ static char rcsid[] = "$Id$";
#include "pppd.h"
#include "fsm.h"
#include "lcp.h"
-#include "magic.h"
#include "chap.h"
-#include "upap.h"
-#include "ipcp.h"
-
-#ifdef _linux_ /* Needs ppp ioctls */
-#include <net/if.h>
-#include <linux/if_ppp.h>
-#endif
+#include "magic.h"
/* global vars */
fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/
@@ -62,11 +55,6 @@ static u_int32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */
static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */
-#ifdef _linux_
-u_int32_t idle_timer_running = 0;
-extern int idle_time_limit;
-#endif
-
/*
* Callbacks for fsm code. (CI = Configuration Information)
*/
@@ -90,10 +78,11 @@ static void lcp_rprotrej __P((fsm *, u_char *, int));
static void lcp_echo_lowerup __P((int));
static void lcp_echo_lowerdown __P((int));
-static void LcpEchoTimeout __P((caddr_t));
+static void LcpEchoTimeout __P((void *));
static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
static void LcpSendEchoRequest __P((fsm *));
static void LcpLinkFailure __P((fsm *));
+static void LcpEchoCheck __P((fsm *));
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_resetci, /* Reset our Configuration Information */
@@ -113,16 +102,47 @@ static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
"LCP" /* String name of protocol */
};
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+
+static void lcp_init __P((int));
+static void lcp_input __P((int, u_char *, int));
+static void lcp_protrej __P((int));
+static int lcp_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent lcp_protent = {
+ PPP_LCP,
+ lcp_init,
+ lcp_input,
+ lcp_protrej,
+ lcp_lowerup,
+ lcp_lowerdown,
+ lcp_open,
+ lcp_close,
+ lcp_printpkt,
+ NULL,
+ 1,
+ "LCP",
+ NULL,
+ NULL,
+ NULL
+};
+
int lcp_loopbackfail = DEFLOOPBACKFAIL;
/*
* Length of each type of configuration option (in octets)
*/
#define CILEN_VOID 2
+#define CILEN_CHAR 3
#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */
#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */
#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */
#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */
+#define CILEN_CBCP 3
#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
(x) == CONFNAK ? "NAK" : "REJ")
@@ -131,7 +151,7 @@ int lcp_loopbackfail = DEFLOOPBACKFAIL;
/*
* lcp_init - Initialize LCP.
*/
-void
+static void
lcp_init(unit)
int unit;
{
@@ -160,6 +180,7 @@ lcp_init(unit)
wo->neg_pcompression = 1;
wo->neg_accompression = 1;
wo->neg_lqr = 0; /* no LQR implementation yet */
+ wo->neg_cbcp = 0;
ao->neg_mru = 1;
ao->mru = MAXMRU;
@@ -172,6 +193,11 @@ lcp_init(unit)
ao->neg_pcompression = 1;
ao->neg_accompression = 1;
ao->neg_lqr = 0; /* no LQR implementation yet */
+#ifdef CBCP_SUPPORT
+ ao->neg_cbcp = 1;
+#else
+ ao->neg_cbcp = 0;
+#endif
memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
xmit_accm[unit][3] = 0x60000000;
@@ -201,77 +227,28 @@ lcp_open(unit)
* lcp_close - Take LCP down.
*/
void
-lcp_close(unit)
+lcp_close(unit, reason)
int unit;
+ char *reason;
{
fsm *f = &lcp_fsm[unit];
+ if (phase != PHASE_DEAD)
+ phase = PHASE_TERMINATE;
if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
/*
* This action is not strictly according to the FSM in RFC1548,
* but it does mean that the program terminates if you do a
- * lcp_close(0) in passive/silent mode when a connection hasn't
+ * lcp_close() in passive/silent mode when a connection hasn't
* been established.
*/
f->state = CLOSED;
lcp_finished(f);
} else
- fsm_close(&lcp_fsm[unit]);
-}
-
-#ifdef _linux_
-static void IdleTimeCheck __P((caddr_t));
-
-/*
- * Timer expired for the LCP echo requests from this process.
- */
-
-static void
-RestartIdleTimer (f)
- fsm *f;
-{
- u_long delta;
- struct ppp_idle ddinfo;
-/*
- * Read the time since the last packet was received.
- */
- if (ioctl (fd, PPPIOCGIDLE, &ddinfo) < 0) {
- syslog (LOG_ERR, "ioctl(PPPIOCGIDLE): %m");
- die (1);
- }
-/*
- * Compute the time since the last packet was received. If the timer
- * has expired then disconnect the line.
- */
- delta = idle_time_limit - (u_long) ddinfo.recv_idle;
- if (((int) delta <= 0L) && (f->state == OPENED)) {
- syslog (LOG_NOTICE, "No IP frames received within idle time limit");
- lcp_close(f->unit); /* Reset connection */
- phase = PHASE_TERMINATE; /* Mark it down */
- } else {
- if ((int) delta <= 0L)
- delta = (u_long) idle_time_limit;
- assert (idle_timer_running==0);
- TIMEOUT (IdleTimeCheck, (caddr_t) f, delta);
- idle_timer_running = 1;
- }
+ fsm_close(&lcp_fsm[unit], reason);
}
-/*
- * IdleTimeCheck - Timer expired on the IDLE detection for IP frames
- */
-
-static void
-IdleTimeCheck (arg)
- caddr_t arg;
-{
- if (idle_timer_running != 0) {
- idle_timer_running = 0;
- RestartIdleTimer ((fsm *) arg);
- }
-}
-#endif
/*
* lcp_lowerup - The lower layer is up.
@@ -280,10 +257,17 @@ void
lcp_lowerup(unit)
int unit;
{
- sifdown(unit);
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ /*
+ * Don't use A/C or protocol compression on transmission,
+ * but accept A/C and protocol compressed packets
+ * if we are going to ask for A/C and protocol compression.
+ */
ppp_set_xaccm(unit, xmit_accm[unit]);
ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
- ppp_recv_config(unit, PPP_MRU, 0x00000000, 0, 0);
+ ppp_recv_config(unit, PPP_MRU, 0x00000000,
+ wo->neg_pcompression, wo->neg_accompression);
peer_mru[unit] = PPP_MRU;
lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
@@ -305,29 +289,15 @@ lcp_lowerdown(unit)
/*
* lcp_input - Input LCP packet.
*/
-void
+static void
lcp_input(unit, p, len)
int unit;
u_char *p;
int len;
{
- int oldstate;
fsm *f = &lcp_fsm[unit];
- lcp_options *go = &lcp_gotoptions[f->unit];
- oldstate = f->state;
fsm_input(f, p, len);
- if (oldstate == REQSENT && f->state == ACKSENT) {
- /*
- * The peer will probably send us an ack soon and then
- * immediately start sending packets with the negotiated
- * options. So as to be ready when that happens, we set
- * our receive side to accept packets as negotiated now.
- */
- ppp_recv_config(f->unit, PPP_MRU,
- go->neg_asyncmap? go->asyncmap: 0x00000000,
- go->neg_pcompression, go->neg_accompression);
- }
}
@@ -382,6 +352,8 @@ lcp_rprotrej(f, inp, len)
u_char *inp;
int len;
{
+ int i;
+ struct protent *protp;
u_short prot;
LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
@@ -408,7 +380,17 @@ lcp_rprotrej(f, inp, len)
return;
}
- DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+ /*
+ * Upcall the proper Protocol-Reject routine.
+ */
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->protocol == prot && protp->enabled_flag) {
+ (*protp->protrej)(f->unit);
+ return;
+ }
+
+ syslog(LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x",
+ prot);
}
@@ -416,7 +398,7 @@ lcp_rprotrej(f, inp, len)
* lcp_protrej - A Protocol-Reject was received.
*/
/*ARGSUSED*/
-void
+static void
lcp_protrej(unit)
int unit;
{
@@ -454,13 +436,14 @@ lcp_sprotrej(unit, p, len)
* lcp_resetci - Reset our CI.
*/
static void
- lcp_resetci(f)
-fsm *f;
+lcp_resetci(f)
+ fsm *f;
{
lcp_wantoptions[f->unit].magicnumber = magic();
lcp_wantoptions[f->unit].numloops = 0;
lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
peer_mru[f->unit] = PPP_MRU;
+ auth_reset(f->unit);
}
@@ -473,20 +456,22 @@ lcp_cilen(f)
{
lcp_options *go = &lcp_gotoptions[f->unit];
-#define LENCIVOID(neg) (neg ? CILEN_VOID : 0)
-#define LENCICHAP(neg) (neg ? CILEN_CHAP : 0)
-#define LENCISHORT(neg) (neg ? CILEN_SHORT : 0)
-#define LENCILONG(neg) (neg ? CILEN_LONG : 0)
-#define LENCILQR(neg) (neg ? CILEN_LQR: 0)
+#define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg) ((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg) ((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0)
/*
* NB: we only ask for one of CHAP and UPAP, even if we will
* accept either.
*/
- return (LENCISHORT(go->neg_mru) +
- LENCILONG(go->neg_asyncmap) +
+ return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) +
+ LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
LENCICHAP(go->neg_chap) +
LENCISHORT(!go->neg_chap && go->neg_upap) +
LENCILQR(go->neg_lqr) +
+ LENCICBCP(go->neg_cbcp) +
LENCILONG(go->neg_magicnumber) +
LENCIVOID(go->neg_pcompression) +
LENCIVOID(go->neg_accompression));
@@ -536,12 +521,20 @@ lcp_addci(f, ucp, lenp)
PUTSHORT(PPP_LQR, ucp); \
PUTLONG(val, ucp); \
}
+#define ADDCICHAR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_CHAR, ucp); \
+ PUTCHAR(val, ucp); \
+ }
- ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
- ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+ go->asyncmap);
ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
@@ -600,6 +593,19 @@ lcp_ackci(f, p, len)
if (cishort != val) \
goto bad; \
}
+#define ACKCICHAR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_CHAR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_CHAR || \
+ citype != opt) \
+ goto bad; \
+ GETCHAR(cichar, p); \
+ if (cichar != val) \
+ goto bad; \
+ }
#define ACKCICHAP(opt, neg, val, digest) \
if (neg) { \
if ((len -= CILEN_CHAP) < 0) \
@@ -646,11 +652,13 @@ lcp_ackci(f, p, len)
goto bad; \
}
- ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
- ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+ go->asyncmap);
ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
@@ -722,6 +730,17 @@ lcp_nakci(f, p, len)
no.neg = 1; \
code \
}
+#define NAKCICHAR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAR && \
+ p[1] == CILEN_CHAR && \
+ p[0] == opt) { \
+ len -= CILEN_CHAR; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
+ code \
+ }
#define NAKCISHORT(opt, neg, code) \
if (go->neg && \
len >= CILEN_SHORT && \
@@ -764,17 +783,21 @@ lcp_nakci(f, p, len)
* If they send us a bigger MRU than what we asked, accept it, up to
* the limit of the default MRU we'd get if we didn't negotiate.
*/
- NAKCISHORT(CI_MRU, neg_mru,
- if (cishort <= wo->mru || cishort < DEFMRU)
- try.mru = cishort;
- );
+ if (go->neg_mru && go->mru != DEFMRU) {
+ NAKCISHORT(CI_MRU, neg_mru,
+ if (cishort <= wo->mru || cishort < DEFMRU)
+ try.mru = cishort;
+ );
+ }
/*
* Add any characters they want to our (receive-side) asyncmap.
*/
- NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
- try.asyncmap = go->asyncmap | cilong;
- );
+ if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ }
/*
* If they've nak'd our authentication-protocol, check whether
@@ -783,19 +806,22 @@ lcp_nakci(f, p, len)
*/
if ((go->neg_chap || go->neg_upap)
&& len >= CILEN_SHORT
- && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT) {
+ && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
cilen = p[1];
+ len -= cilen;
+ no.neg_chap = go->neg_chap;
+ no.neg_upap = go->neg_upap;
INCPTR(2, p);
GETSHORT(cishort, p);
if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
/*
- * If they are asking for PAP, then they don't want to do CHAP.
+ * If we were asking for CHAP, they obviously don't want to do it.
* If we weren't asking for CHAP, then we were asking for PAP,
* in which case this Nak is bad.
*/
if (!go->neg_chap)
goto bad;
- go->neg_chap = 0;
+ try.neg_chap = 0;
} else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
GETCHAR(cichar, p);
@@ -806,12 +832,12 @@ lcp_nakci(f, p, len)
* asking for CHAP.
*/
if (cichar != go->chap_mdtype)
- go->neg_chap = 0;
+ try.neg_chap = 0;
} else {
/*
* Stop asking for PAP if we were asking for it.
*/
- go->neg_upap = 0;
+ try.neg_upap = 0;
}
} else {
@@ -820,25 +846,14 @@ lcp_nakci(f, p, len)
* Stop asking for what we were asking for.
*/
if (go->neg_chap)
- go->neg_chap = 0;
+ try.neg_chap = 0;
else
- go->neg_upap = 0;
+ try.neg_upap = 0;
p += cilen - CILEN_SHORT;
}
}
/*
- * Peer shouldn't send Nak for protocol compression or
- * address/control compression requests; they should send
- * a Reject instead. If they send a Nak, treat it as a Reject.
- */
- if (!go->neg_chap ){
- NAKCISHORT(CI_AUTHTYPE, neg_upap,
- try.neg_upap = 0;
- );
- }
-
- /*
* If they can't cope with our link quality protocol, we'll have
* to stop asking for LQR. We haven't got any other protocol.
* If they Nak the reporting period, take their value XXX ?
@@ -851,6 +866,13 @@ lcp_nakci(f, p, len)
);
/*
+ * Only implementing CBCP...not the rest of the callback options
+ */
+ NAKCICHAR(CI_CALLBACK, neg_cbcp,
+ try.neg_cbcp = 0;
+ );
+
+ /*
* Check for a looped-back line.
*/
NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
@@ -858,6 +880,11 @@ lcp_nakci(f, p, len)
looped_back = 1;
);
+ /*
+ * Peer shouldn't send Nak for protocol compression or
+ * address/control compression requests; they should send
+ * a Reject instead. If they send a Nak, treat it as a Reject.
+ */
NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
try.neg_pcompression = 0;
);
@@ -884,17 +911,22 @@ lcp_nakci(f, p, len)
while (len > CILEN_VOID) {
GETCHAR(citype, p);
GETCHAR(cilen, p);
- if ((len -= cilen) < 0)
+ if (cilen < CILEN_VOID || (len -= cilen) < 0)
goto bad;
next = p + cilen - 2;
switch (citype) {
case CI_MRU:
- if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT)
+ if ((go->neg_mru && go->mru != DEFMRU)
+ || no.neg_mru || cilen != CILEN_SHORT)
goto bad;
+ GETSHORT(cishort, p);
+ if (cishort < DEFMRU)
+ try.mru = cishort;
break;
case CI_ASYNCMAP:
- if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG)
+ if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
+ || no.neg_asyncmap || cilen != CILEN_LONG)
goto bad;
break;
case CI_AUTHTYPE:
@@ -935,7 +967,7 @@ lcp_nakci(f, p, len)
if (looped_back) {
if (++try.numloops >= lcp_loopbackfail) {
syslog(LOG_NOTICE, "Serial line is looped back.");
- lcp_close(f->unit);
+ lcp_close(f->unit, "Loopback detected");
}
} else
try.numloops = 0;
@@ -969,8 +1001,6 @@ lcp_rejci(f, p, len)
u_char cichar;
u_short cishort;
u_int32_t cilong;
- u_char *start = p;
- int plen = len;
lcp_options try; /* options to request next time */
try = *go;
@@ -1049,6 +1079,20 @@ lcp_rejci(f, p, len)
try.neg = 0; \
LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
}
+#define REJCICBCP(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_CBCP && \
+ p[1] == CILEN_CBCP && \
+ p[0] == opt) { \
+ len -= CILEN_CBCP; \
+ INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ /* Check rejected value. */ \
+ if (cichar != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected Callback opt %d", opt)); \
+ }
REJCISHORT(CI_MRU, neg_mru, go->mru);
REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
@@ -1057,6 +1101,7 @@ lcp_rejci(f, p, len)
REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
}
REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
@@ -1075,8 +1120,6 @@ lcp_rejci(f, p, len)
bad:
LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"));
- LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d",
- plen, len, p - start));
return 0;
}
@@ -1099,7 +1142,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *ao = &lcp_allowoptions[f->unit];
u_char *cip, *next; /* Pointer to current and next CIs */
- u_char cilen, citype, cichar;/* Parsed len, type, char value */
+ int cilen, citype, cichar; /* Parsed len, type, char value */
u_short cishort; /* Parsed short value */
u_int32_t cilong; /* Parse long value */
int rc = CONFACK; /* Final packet return code */
@@ -1130,6 +1173,7 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
orc = CONFREJ; /* Reject bad CI */
cilen = l; /* Reject till end of packet */
l = 0; /* Don't loop again */
+ citype = 0;
goto endswitch;
}
GETCHAR(citype, p); /* Parse CI type */
@@ -1248,7 +1292,11 @@ lcp_reqci(f, inp, lenp, reject_if_disagree)
break;
}
GETCHAR(cichar, p); /* get digest type*/
- if (cichar != ao->chap_mdtype) {
+ if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+ && cichar != CHAP_MICROSOFT
+#endif
+ ) {
orc = CONFNAK;
PUTCHAR(CI_AUTHTYPE, nakp);
PUTCHAR(CILEN_CHAP, nakp);
@@ -1412,8 +1460,6 @@ endswitch:
/*
* lcp_up - LCP has come UP.
- *
- * Start UPAP, IPCP, etc.
*/
static void
lcp_up(f)
@@ -1450,10 +1496,6 @@ lcp_up(f)
if (ho->neg_mru)
peer_mru[f->unit] = ho->mru;
- ChapLowerUp(f->unit); /* Enable CHAP */
- upap_lowerup(f->unit); /* Enable UPAP */
- ipcp_lowerup(f->unit); /* Enable IPCP */
- ccp_lowerup(f->unit); /* Enable CCP */
lcp_echo_lowerup(f->unit); /* Enable echo messages */
link_established(f->unit);
@@ -1469,18 +1511,17 @@ static void
lcp_down(f)
fsm *f;
{
+ lcp_options *go = &lcp_gotoptions[f->unit];
+
lcp_echo_lowerdown(f->unit);
- ccp_lowerdown(f->unit);
- ipcp_lowerdown(f->unit);
- ChapLowerDown(f->unit);
- upap_lowerdown(f->unit);
- sifdown(f->unit);
+ link_down(f->unit);
+
ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
- ppp_recv_config(f->unit, PPP_MRU, 0x00000000, 0, 0);
+ ppp_recv_config(f->unit, PPP_MRU,
+ (go->neg_asyncmap? go->asyncmap: 0x00000000),
+ go->neg_pcompression, go->neg_accompression);
peer_mru[f->unit] = PPP_MRU;
-
- link_down(f->unit);
}
@@ -1509,13 +1550,13 @@ lcp_finished(f)
/*
* lcp_printpkt - print the contents of an LCP packet.
*/
-char *lcp_codenames[] = {
+static char *lcp_codenames[] = {
"ConfReq", "ConfAck", "ConfNak", "ConfRej",
"TermReq", "TermAck", "CodeRej", "ProtRej",
"EchoReq", "EchoRep", "DiscReq"
};
-int
+static int
lcp_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
@@ -1580,7 +1621,7 @@ lcp_printpkt(p, plen, printer, arg)
GETSHORT(cishort, p);
switch (cishort) {
case PPP_PAP:
- printer(arg, "upap");
+ printer(arg, "pap");
break;
case PPP_CHAP:
printer(arg, "chap");
@@ -1604,6 +1645,20 @@ lcp_printpkt(p, plen, printer, arg)
}
}
break;
+ case CI_CALLBACK:
+ if (olen >= CILEN_CHAR) {
+ p += 2;
+ printer(arg, "callback ");
+ GETSHORT(cishort, p);
+ switch (cishort) {
+ case CBCP_OPT:
+ printer(arg, "CBCP");
+ break;
+ default:
+ printer(arg, "0x%x", cishort);
+ }
+ }
+ break;
case CI_MAGICNUMBER:
if (olen == CILEN_LONG) {
p += 2;
@@ -1631,6 +1686,27 @@ lcp_printpkt(p, plen, printer, arg)
printer(arg, ">");
}
break;
+
+ case TERMACK:
+ case TERMREQ:
+ if (len > 0 && *p >= ' ' && *p < 0x7f) {
+ printer(arg, " ");
+ print_string(p, len, printer, arg);
+ p += len;
+ len = 0;
+ }
+ break;
+
+ case ECHOREQ:
+ case ECHOREP:
+ case DISCREQ:
+ if (len >= 4) {
+ GETLONG(cilong, p);
+ printer(arg, " magic=0x%x", cilong);
+ p += 4;
+ len -= 4;
+ }
+ break;
}
/* print the rest of the bytes in the packet */
@@ -1651,8 +1727,9 @@ void LcpLinkFailure (f)
fsm *f;
{
if (f->state == OPENED) {
- syslog (LOG_NOTICE, "Excessive lack of response to LCP echo frames.");
- lcp_close(f->unit); /* Reset connection */
+ syslog(LOG_INFO, "No response to %d echo-requests", lcp_echos_pending);
+ syslog(LOG_NOTICE, "Serial link appears to be disconnected.");
+ lcp_close(f->unit, "Peer not responding");
}
}
@@ -1664,36 +1741,13 @@ static void
LcpEchoCheck (f)
fsm *f;
{
- long int delta;
-#ifdef __linux__
- struct ppp_idle ddinfo;
-/*
- * Read the time since the last packet was received.
- */
- if (ioctl (fd, PPPIOCGIDLE, &ddinfo) < 0) {
- syslog (LOG_ERR, "ioctl(PPPIOCGIDLE): %m");
- die (1);
- }
-/*
- * Compute the time since the last packet was received. If the timer
- * has expired then send the echo request and reset the timer to maximum.
- */
- delta = (long int) lcp_echo_interval - (long int) ddinfo.recv_idle;
- if (delta < 0L) {
- LcpSendEchoRequest (f);
- delta = (int) lcp_echo_interval;
- }
-
-#else /* Other implementations do not have ability to find delta */
LcpSendEchoRequest (f);
- delta = (int) lcp_echo_interval;
-#endif
-/*
- * Start the timer for the next interval.
- */
+ /*
+ * Start the timer for the next interval.
+ */
assert (lcp_echo_timer_running==0);
- TIMEOUT (LcpEchoTimeout, (caddr_t) f, (u_int32_t) delta);
+ TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
lcp_echo_timer_running = 1;
}
@@ -1703,7 +1757,7 @@ LcpEchoCheck (f)
static void
LcpEchoTimeout (arg)
- caddr_t arg;
+ void *arg;
{
if (lcp_echo_timer_running != 0) {
lcp_echo_timer_running = 0;
@@ -1749,27 +1803,24 @@ LcpSendEchoRequest (f)
u_int32_t lcp_magic;
u_char pkt[4], *pktp;
-/*
- * Detect the failure of the peer at this point.
- */
+ /*
+ * Detect the failure of the peer at this point.
+ */
if (lcp_echo_fails != 0) {
if (lcp_echos_pending++ >= lcp_echo_fails) {
LcpLinkFailure(f);
lcp_echos_pending = 0;
}
}
-/*
- * Make and send the echo request frame.
- */
+
+ /*
+ * Make and send the echo request frame.
+ */
if (f->state == OPENED) {
- lcp_magic = lcp_gotoptions[f->unit].neg_magicnumber
- ? lcp_gotoptions[f->unit].magicnumber
- : 0L;
+ lcp_magic = lcp_gotoptions[f->unit].magicnumber;
pktp = pkt;
PUTLONG(lcp_magic, pktp);
-
- fsm_sdata(f, ECHOREQ,
- lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+ fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
}
}
@@ -1791,11 +1842,6 @@ lcp_echo_lowerup (unit)
/* If a timeout interval is specified then start the timer */
if (lcp_echo_interval != 0)
LcpEchoCheck (f);
-#ifdef _linux_
- /* If a idle time limit is given then start it */
- if (idle_time_limit != 0)
- RestartIdleTimer (f);
-#endif
}
/*
@@ -1809,14 +1855,7 @@ lcp_echo_lowerdown (unit)
fsm *f = &lcp_fsm[unit];
if (lcp_echo_timer_running != 0) {
- UNTIMEOUT (LcpEchoTimeout, (caddr_t) f);
+ UNTIMEOUT (LcpEchoTimeout, f);
lcp_echo_timer_running = 0;
}
-#ifdef _linux_
- /* If a idle time limit is running then stop it */
- if (idle_timer_running != 0) {
- UNTIMEOUT (IdleTimeCheck, (caddr_t) f);
- idle_timer_running = 0;
- }
-#endif
}
diff --git a/usr.sbin/pppd/lcp.h b/usr.sbin/pppd/lcp.h
index c98ba5e..42260f3 100644
--- a/usr.sbin/pppd/lcp.h
+++ b/usr.sbin/pppd/lcp.h
@@ -29,6 +29,7 @@
#define CI_MAGICNUMBER 5 /* Magic Number */
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
+#define CI_CALLBACK 13 /* callback */
/*
* LCP-specific packet types.
@@ -37,6 +38,7 @@
#define ECHOREQ 9 /* Echo Request */
#define ECHOREP 10 /* Echo Reply */
#define DISCREQ 11 /* Discard Request */
+#define CBCP_OPT 6 /* Use callback control protocol */
/*
* The state of options is described by an lcp_options structure.
@@ -53,6 +55,7 @@ typedef struct lcp_options {
int neg_pcompression : 1; /* HDLC Protocol Field Compression? */
int neg_accompression : 1; /* HDLC Address/Control Field Compression? */
int neg_lqr : 1; /* Negotiate use of Link Quality Reports */
+ int neg_cbcp : 1; /* Negotiate use of CBCP */
u_short mru; /* Value of MRU */
u_char chap_mdtype; /* which MD type (hashing algorithm) */
u_int32_t asyncmap; /* Value of async map */
@@ -72,17 +75,14 @@ extern u_int32_t xmit_accm[][8];
#define MINMRU 128 /* No MRUs below this */
#define MAXMRU 16384 /* Normally limit MRU to this */
-void lcp_init __P((int));
void lcp_open __P((int));
-void lcp_close __P((int));
+void lcp_close __P((int, char *));
void lcp_lowerup __P((int));
void lcp_lowerdown __P((int));
-void lcp_input __P((int, u_char *, int));
-void lcp_protrej __P((int));
-void lcp_sprotrej __P((int, u_char *, int));
-int lcp_printpkt __P((u_char *, int,
- void (*) __P((void *, char *, ...)), void *));
+void lcp_sprotrej __P((int, u_char *, int)); /* send protocol reject */
+
+extern struct protent lcp_protent;
/* Default number of times we receive our magic number from the peer
before deciding the link is looped-back. */
-#define DEFLOOPBACKFAIL 5
+#define DEFLOOPBACKFAIL 10
diff --git a/usr.sbin/pppd/magic.c b/usr.sbin/pppd/magic.c
index a35ec40..be3b503 100644
--- a/usr.sbin/pppd/magic.c
+++ b/usr.sbin/pppd/magic.c
@@ -22,19 +22,16 @@ static char rcsid[] = "$Id$";
#endif
#include <stdio.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include "pppd.h"
#include "magic.h"
-static u_int32_t next; /* Next value to return */
-
-extern int gethostid __P((void));
extern long mrand48 __P((void));
extern void srand48 __P((long));
-
/*
* magic_init - Initialize the magic number generator.
*
diff --git a/usr.sbin/pppd/main.c b/usr.sbin/pppd/main.c
index 5fb98dd..d525258 100644
--- a/usr.sbin/pppd/main.c
+++ b/usr.sbin/pppd/main.c
@@ -18,12 +18,14 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: main.c,v 1.11 1997/04/15 07:00:33 danny Exp $";
+static char rcsid[] = "$Id$";
#endif
#include <stdio.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
@@ -52,12 +54,19 @@ static char rcsid[] = "$Id: main.c,v 1.11 1997/04/15 07:00:33 danny Exp $";
#include "pathnames.h"
#include "patchlevel.h"
-/*
- * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
- * /etc/ppp/options exists.
- */
-#ifndef REQ_SYSOPTIONS
-#define REQ_SYSOPTIONS 1
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#if defined(SUNOS4)
+extern char *strerror();
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
+#ifdef AT_CHANGE
+#include "atcp.h"
#endif
/* interface vars */
@@ -69,138 +78,171 @@ char hostname[MAXNAMELEN]; /* Our hostname */
static char pidfilename[MAXPATHLEN]; /* name of pid file */
static char iffilename[MAXPATHLEN]; /* name of if file */
static char default_devnam[MAXPATHLEN]; /* name of default device */
-static pid_t pid; /* Our pid */
-static pid_t pgrpid; /* Process Group ID */
+static pid_t pid; /* Our pid */
static uid_t uid; /* Our real user-id */
time_t etime,stime; /* End and Start time */
int minutes; /* connection duration */
+static int conn_running; /* we have a [dis]connector running */
-int fd = -1; /* Device file descriptor */
+int ttyfd = -1; /* Serial port file descriptor */
+mode_t tty_mode = -1; /* Original access permissions to tty */
+int baud_rate; /* Actual bits/second for serial device */
+int hungup; /* terminal has been hung up */
+int privileged; /* we're running as real uid root */
+int need_holdoff; /* need holdoff period before restarting */
int phase; /* where the link is at */
int kill_link;
int open_ccp_flag;
-
-static int initfdflags = -1; /* Initial file descriptor flags */
+int redirect_stderr; /* Connector's stderr should go to file */
u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
-static u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
-int hungup; /* terminal has been hung up */
static int n_children; /* # child processes still running */
-int baud_rate;
+static int locked; /* lock() has succeeded */
char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
-/* prototypes */
+/* Prototypes for procedures local to this file. */
+
+static void cleanup __P((void));
+static void close_tty __P((void));
+static void get_input __P((void));
+static void calltimeout __P((void));
+static struct timeval *timeleft __P((struct timeval *));
+static void kill_my_pg __P((int));
static void hup __P((int));
static void term __P((int));
static void chld __P((int));
static void toggle_debug __P((int));
static void open_ccp __P((int));
static void bad_signal __P((int));
-
-static void get_input __P((void));
-void establish_ppp __P((void));
-void calltimeout __P((void));
-struct timeval *timeleft __P((struct timeval *));
-void reap_kids __P((void));
-void cleanup __P((int, caddr_t));
-void close_fd __P((void));
-void die __P((int));
-void novm __P((char *));
-
-void log_packet __P((u_char *, int, char *));
-void format_packet __P((u_char *, int,
- void (*) (void *, char *, ...), void *));
-void pr_log __P((void *, char *, ...));
+static void holdoff_end __P((void *));
+static int device_script __P((char *, int, int));
+static void reap_kids __P((void));
+static void pr_log __P((void *, char *, ...));
extern char *ttyname __P((int));
extern char *getlogin __P((void));
+int main __P((int, char *[]));
#ifdef ultrix
#undef O_NONBLOCK
#define O_NONBLOCK O_NDELAY
#endif
+#ifdef ULTRIX
+#define setlogmask(x)
+#endif
+
/*
* PPP Data Link Layer "protocol" table.
* One entry per supported protocol.
+ * The last entry must be NULL.
*/
-static struct protent {
- u_short protocol;
- void (*init)();
- void (*input)();
- void (*protrej)();
- int (*printpkt)();
- void (*datainput)();
- char *name;
-} prottbl[] = {
- { PPP_LCP, lcp_init, lcp_input, lcp_protrej,
- lcp_printpkt, NULL, "LCP" },
- { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej,
- ipcp_printpkt, NULL, "IPCP" },
- { PPP_PAP, upap_init, upap_input, upap_protrej,
- upap_printpkt, NULL, "PAP" },
- { PPP_CHAP, ChapInit, ChapInput, ChapProtocolReject,
- ChapPrintPkt, NULL, "CHAP" },
- { PPP_CCP, ccp_init, ccp_input, ccp_protrej,
- ccp_printpkt, ccp_datainput, "CCP" },
+struct protent *protocols[] = {
+ &lcp_protent,
+ &pap_protent,
+ &chap_protent,
+#ifdef CBCP_SUPPORT
+ &cbcp_protent,
+#endif
+ &ipcp_protent,
+ &ccp_protent,
+#ifdef IPX_CHANGE
+ &ipxcp_protent,
+#endif
+#ifdef AT_CHANGE
+ &atcp_protent,
+#endif
+ NULL
};
-#define N_PROTO (sizeof(prottbl) / sizeof(prottbl[0]))
-
+int
main(argc, argv)
int argc;
char *argv[];
{
- int i, n, nonblock;
+ int i, n, nonblock, fdflags;
struct sigaction sa;
- struct cmd *cmdp;
FILE *pidfile;
FILE *iffile;
char *p;
struct passwd *pw;
struct timeval timo;
sigset_t mask;
- int connect_attempts = 0;
+ struct protent *protp;
+ struct stat statbuf;
+ phase = PHASE_INITIALIZE;
p = ttyname(0);
if (p)
strcpy(devnam, p);
strcpy(default_devnam, devnam);
+ /* Initialize syslog facilities */
+#ifdef ULTRIX
+ openlog("pppd", LOG_PID);
+#else
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
+#endif
+
if (gethostname(hostname, MAXNAMELEN) < 0 ) {
- perror("couldn't get hostname");
+ option_error("Couldn't get hostname: %m");
die(1);
}
hostname[MAXNAMELEN-1] = 0;
uid = getuid();
-
- if (!ppp_available()) {
- fprintf(stderr, no_ppp_msg);
- exit(1);
- }
+ privileged = uid == 0;
/*
* Initialize to the standard option set, then parse, in order,
- * the system options file, the user's options file, and the command
- * line arguments.
+ * the system options file, the user's options file,
+ * the tty's options file, and the command line arguments.
*/
- for (i = 0; i < N_PROTO; i++)
- (*prottbl[i].init)(0);
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ (*protp->init)(0);
progname = *argv;
- if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS, 0) ||
- !options_from_user() ||
- !parse_args(argc-1, argv+1) ||
- !options_for_tty())
+ if (!options_from_file(_PATH_SYSOPTIONS, !privileged, 0, 1)
+ || !options_from_user())
+ exit(1);
+ scan_args(argc-1, argv+1); /* look for tty name on command line */
+ if (!options_for_tty()
+ || !parse_args(argc-1, argv+1))
+ exit(1);
+
+ /*
+ * Check that we are running as root.
+ */
+ if (geteuid() != 0) {
+ option_error("must be root to run %s, since it is not setuid-root",
+ argv[0]);
die(1);
- check_auth_options();
- setipdefault();
+ }
+
+ if (!ppp_available()) {
+ option_error(no_ppp_msg);
+ exit(1);
+ }
+
+ /*
+ * Check that the options given are valid and consistent.
+ */
+ sys_check_options();
+ auth_check_options();
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (protp->check_options != NULL)
+ (*protp->check_options)();
+ if (demand && connector == 0) {
+ option_error("connect script required for demand-dialling\n");
+ exit(1);
+ }
/*
* If the user has specified the default device name explicitly,
@@ -208,12 +250,15 @@ main(argc, argv)
*/
if (!default_device && strcmp(devnam, default_devnam) == 0)
default_device = 1;
+ redirect_stderr = !nodetach || default_device;
/*
* Initialize system-dependent stuff and magic number package.
*/
sys_init();
magic_init();
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
/*
* Detach ourselves from the terminal, if required,
@@ -233,8 +278,8 @@ main(argc, argv)
else
p = "(unknown)";
}
- syslog(LOG_NOTICE, "pppd %s.%d started by %s, uid %d",
- VERSION, PATCHLEVEL, p, uid);
+ syslog(LOG_NOTICE, "pppd %s.%d%s started by %s, uid %d",
+ VERSION, PATCHLEVEL, IMPLEMENTATION, p, uid);
/*
* Compute mask of all interesting signals and install signal handlers
@@ -305,121 +350,192 @@ main(argc, argv)
#endif
/*
- * Lock the device if we've been asked to.
+ * Apparently we can get a SIGPIPE when we call syslog, if
+ * syslogd has died and been restarted. Ignoring it seems
+ * be sufficient.
*/
- if (lockflag && !default_device)
- if (lock(devnam) < 0)
- die(1);
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * If we're doing dial-on-demand, set up the interface now.
+ */
+ if (demand) {
+ /*
+ * Open the loopback channel and set it up to be the ppp interface.
+ */
+ open_ppp_loopback();
- do {
+ syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+ (void) sprintf(ifname, "ppp%d", ifunit);
+
+ /* write pid to file */
+ (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
+ pidfilename[0] = 0;
+ }
/*
- * Open the serial device and set it up to be the ppp interface.
- * If we're dialling out, or we don't want to use the modem lines,
- * we open it in non-blocking mode, but then we need to clear
- * the non-blocking I/O bit.
+ * Configure the interface and mark it up, etc.
*/
- nonblock = (connector || !modem)? O_NONBLOCK: 0;
- if ((fd = open(devnam, nonblock | O_RDWR, 0)) < 0) {
- syslog(LOG_ERR, "Failed to open %s: %m", devnam);
- die(1);
+ demand_conf();
+ }
+
+ for (;;) {
+
+ need_holdoff = 1;
+
+ if (demand) {
+ /*
+ * Don't do anything until we see some activity.
+ */
+ phase = PHASE_DORMANT;
+ kill_link = 0;
+ demand_unblock();
+ for (;;) {
+ wait_loop_output(timeleft(&timo));
+ calltimeout();
+ if (kill_link) {
+ if (!persist)
+ die(0);
+ kill_link = 0;
+ }
+ if (get_loop_output())
+ break;
+ reap_kids();
+ }
+
+ /*
+ * Now we want to bring up the link.
+ */
+ demand_block();
+ syslog(LOG_INFO, "Starting link");
}
- if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
- syslog(LOG_ERR, "Couldn't get device fd flags: %m");
- die(1);
+
+ /*
+ * Lock the device if we've been asked to.
+ */
+ if (lockflag && !default_device) {
+ if (lock(devnam) < 0)
+ goto fail;
+ locked = 1;
}
- if (nonblock) {
- initfdflags &= ~O_NONBLOCK;
- fcntl(fd, F_SETFL, initfdflags);
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ * First we open it in non-blocking mode so we can set the
+ * various termios flags appropriately. If we aren't dialling
+ * out and we want to use the modem lines, we reopen it later
+ * in order to wait for the carrier detect signal from the modem.
+ */
+ while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) {
+ if (errno != EINTR)
+ syslog(LOG_ERR, "Failed to open %s: %m", devnam);
+ if (!persist || errno != EINTR)
+ goto fail;
}
+ if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1
+ || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+ syslog(LOG_WARNING,
+ "Couldn't reset non-blocking mode on device: %m");
+
hungup = 0;
kill_link = 0;
- if (!default_device && !nodetach)
- setsid();
+ /*
+ * Do the equivalent of `mesg n' to stop broadcast messages.
+ */
+ if (fstat(ttyfd, &statbuf) < 0
+ || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) {
+ syslog(LOG_WARNING,
+ "Couldn't restrict write permissions to %s: %m", devnam);
+ } else
+ tty_mode = statbuf.st_mode;
/* run connection script */
if (connector && connector[0]) {
MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector));
/* set line speed, flow control, etc.; set CLOCAL for now */
- set_up_tty(fd, 1);
+ set_up_tty(ttyfd, 1);
/* drop dtr to hang up in case modem is off hook */
if (!default_device && modem) {
- setdtr(fd, FALSE);
+ setdtr(ttyfd, FALSE);
sleep(1);
- setdtr(fd, TRUE);
+ setdtr(ttyfd, TRUE);
}
- if (device_script(connector, fd, fd) < 0) {
+ if (device_script(connector, ttyfd, ttyfd) < 0) {
syslog(LOG_ERR, "Connect script failed");
- setdtr(fd, FALSE);
- if (++connect_attempts >= max_con_attempts)
- die(1);
- else {
- close(fd);
- sleep(5);
- continue;
- }
+ setdtr(ttyfd, FALSE);
+ goto fail;
}
syslog(LOG_INFO, "Serial connection established.");
sleep(1); /* give it time to set up its terminal */
}
- connect_attempts = 0; /* we made it through ok */
-
/* set line speed, flow control, etc.; clear CLOCAL if modem option */
- set_up_tty(fd, 0);
+ set_up_tty(ttyfd, 0);
+
+ /* reopen tty if necessary to wait for carrier */
+ if (connector == NULL && modem) {
+ while ((i = open(devnam, O_RDWR)) < 0) {
+ if (errno != EINTR)
+ syslog(LOG_ERR, "Failed to reopen %s: %m", devnam);
+ if (!persist || errno != EINTR)
+ goto fail;
+ }
+ close(i);
+ }
- /* attach to the controlling tty for signals */
- if (!default_device && !nodetach && ioctl(fd, TIOCSCTTY) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSCTTY) : %m");
- die(1);
+ /* run welcome script, if any */
+ if (welcomer && welcomer[0]) {
+ if (device_script(welcomer, ttyfd, ttyfd) < 0)
+ syslog(LOG_WARNING, "Welcome script failed");
}
/* set up the serial device as a ppp interface */
- establish_ppp();
-
- syslog(LOG_INFO, "Using interface ppp%d", ifunit);
- (void) sprintf(ifname, "ppp%d", ifunit);
-
- /* write pid to file */
- (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
- if ((pidfile = fopen(pidfilename, "w")) != NULL) {
- fprintf(pidfile, "%d\n", pid);
- (void) fclose(pidfile);
- } else {
- syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename);
- pidfilename[0] = 0;
- }
+ establish_ppp(ttyfd);
+
+ if (!demand) {
+
+ syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+ (void) sprintf(ifname, "ppp%d", ifunit);
+
+ /* write pid to file */
+ (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "Failed to create pid file %s: %m",
+ pidfilename);
+ pidfilename[0] = 0;
+ }
- /* write interface unit number to file */
- for (n = strlen(devnam); n > 0 ; n--)
- if (devnam[n] == '/') {
- n++;
- break;
- }
- (void) sprintf(iffilename, "%s%s.if", _PATH_VARRUN, &devnam[n]);
- if ((iffile = fopen(iffilename, "w")) != NULL) {
- fprintf(iffile, "ppp%d\n", ifunit);
- (void) fclose(iffile);
- } else {
- syslog(LOG_ERR, "Failed to create if file %s: %m", iffilename);
- iffilename[0] = 0;
+ /* write interface unit number to file */
+ for (n = strlen(devnam); n > 0 ; n--)
+ if (devnam[n] == '/') {
+ n++;
+ break;
+ }
+ (void) sprintf(iffilename, "%s%s.if", _PATH_VARRUN, &devnam[n]);
+ if ((iffile = fopen(iffilename, "w")) != NULL) {
+ fprintf(iffile, "ppp%d\n", ifunit);
+ (void) fclose(iffile);
+ } else {
+ syslog(LOG_ERR, "Failed to create if file %s: %m", iffilename);
+ iffilename[0] = 0;
+ }
}
/*
- * Set device for non-blocking reads.
- */
- if (fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
- syslog(LOG_ERR, "Couldn't set device to non-blocking mode: %m");
- die(1);
- }
-
- /*
- * Block all signals, start opening the connection, and wait for
+ * Start opening the connection and wait for
* incoming events (reply, timeout, etc.).
*/
syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
@@ -430,13 +546,13 @@ main(argc, argv)
calltimeout();
get_input();
if (kill_link) {
- lcp_close(0);
+ lcp_close(0, "User request");
kill_link = 0;
}
if (open_ccp_flag) {
if (phase == PHASE_NETWORK) {
ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
- ccp_open(0);
+ (*ccp_protent.open)(0);
}
open_ccp_flag = 0;
}
@@ -444,37 +560,83 @@ main(argc, argv)
}
/*
+ * If we may want to bring the link up again, transfer
+ * the ppp unit back to the loopback. Set the
+ * real serial device back to its normal mode of operation.
+ */
+ clean_check();
+ if (demand)
+ restore_loop();
+ disestablish_ppp(ttyfd);
+
+ /*
* Run disconnector script, if requested.
- * First we need to reset non-blocking mode.
* XXX we may not be able to do this if the line has hung up!
*/
- if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) >= 0)
- initfdflags = -1;
- disestablish_ppp();
- if (disconnector) {
- set_up_tty(fd, 1);
- if (device_script(disconnector, fd, fd) < 0) {
+ if (disconnector && !hungup) {
+ set_up_tty(ttyfd, 1);
+ if (device_script(disconnector, ttyfd, ttyfd) < 0) {
syslog(LOG_WARNING, "disconnect script failed");
} else {
syslog(LOG_INFO, "Serial link disconnected.");
}
}
- close_fd();
- if (unlink(pidfilename) < 0 && errno != ENOENT)
- syslog(LOG_WARNING, "unable to delete pid file: %m");
- pidfilename[0] = 0;
+ fail:
+ if (ttyfd >= 0)
+ close_tty();
+ if (locked) {
+ unlock();
+ locked = 0;
+ }
+
+ if (!demand) {
+ if (pidfilename[0] != 0
+ && unlink(pidfilename) < 0 && errno != ENOENT)
+ syslog(LOG_WARNING, "unable to delete pid file: %m");
+ pidfilename[0] = 0;
- if (iffile)
- if (unlink(iffilename) < 0 && errno != ENOENT)
- syslog(LOG_WARNING, "unable to delete if file: %m");
- iffilename[0] = 0;
+ if (iffile)
+ if (unlink(iffilename) < 0 && errno != ENOENT)
+ syslog(LOG_WARNING, "unable to delete if file: %m");
+ iffilename[0] = 0;
+ }
+
+ if (!persist)
+ break;
- } while (persist);
+ if (demand)
+ demand_discard();
+ if (holdoff > 0 && need_holdoff) {
+ phase = PHASE_HOLDOFF;
+ TIMEOUT(holdoff_end, NULL, holdoff);
+ do {
+ wait_time(timeleft(&timo));
+ calltimeout();
+ if (kill_link) {
+ if (!persist)
+ die(0);
+ kill_link = 0;
+ phase = PHASE_DORMANT; /* allow signal to end holdoff */
+ }
+ reap_kids();
+ } while (phase == PHASE_HOLDOFF);
+ }
+ }
die(0);
+ return 0;
}
+/*
+ * holdoff_end - called via a timeout when the holdoff period ends.
+ */
+static void
+holdoff_end(arg)
+ void *arg;
+{
+ phase = PHASE_DORMANT;
+}
/*
* get_input - called when incoming data is available.
@@ -485,6 +647,7 @@ get_input()
int len, i;
u_char *p;
u_short protocol;
+ struct protent *protp;
p = inpacket_buf; /* point to beginning of packet buffer */
@@ -498,12 +661,12 @@ get_input()
syslog(LOG_NOTICE, "Modem hangup, connected for %d minutes", (minutes >1) ? minutes : 1);
hungup = 1;
lcp_lowerdown(0); /* serial link is no longer available */
- phase = PHASE_DEAD;
+ link_terminated(0);
return;
}
if (debug /*&& (debugflags & DBG_INPACKET)*/)
- log_packet(p, len, "rcvd ");
+ log_packet(p, len, "rcvd ", LOG_DEBUG);
if (len < PPP_HDRLEN) {
MAINDEBUG((LOG_INFO, "io(): Received short packet."));
@@ -519,68 +682,44 @@ get_input()
*/
if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
MAINDEBUG((LOG_INFO,
- "io(): Received non-LCP packet when LCP not open."));
+ "get_input: Received non-LCP packet when LCP not open."));
+ return;
+ }
+
+ /*
+ * Until we get past the authentication phase, toss all packets
+ * except LCP, LQR and authentication packets.
+ */
+ if (phase <= PHASE_AUTHENTICATE
+ && !(protocol == PPP_LCP || protocol == PPP_LQR
+ || protocol == PPP_PAP || protocol == PPP_CHAP)) {
+ MAINDEBUG((LOG_INFO, "get_input: discarding proto 0x%x in phase %d",
+ protocol, phase));
return;
}
/*
* Upcall the proper protocol input routine.
*/
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++) {
- if (prottbl[i].protocol == protocol) {
- (*prottbl[i].input)(0, p, len);
+ for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ if (protp->protocol == protocol && protp->enabled_flag) {
+ (*protp->input)(0, p, len);
return;
}
- if (protocol == (prottbl[i].protocol & ~0x8000)
- && prottbl[i].datainput != NULL) {
- (*prottbl[i].datainput)(0, p, len);
+ if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
+ && protp->datainput != NULL) {
+ (*protp->datainput)(0, p, len);
return;
}
}
if (debug)
- syslog(LOG_WARNING, "Unknown protocol (0x%x) received", protocol);
+ syslog(LOG_WARNING, "Unsupported protocol (0x%x) received", protocol);
lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
}
/*
- * demuxprotrej - Demultiplex a Protocol-Reject.
- */
-void
-demuxprotrej(unit, protocol)
- int unit;
- u_short protocol;
-{
- int i;
-
- /*
- * Upcall the proper Protocol-Reject routine.
- */
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
- if (prottbl[i].protocol == protocol) {
- (*prottbl[i].protrej)(unit);
- return;
- }
-
- syslog(LOG_WARNING,
- "demuxprotrej: Unrecognized Protocol-Reject for protocol 0x%x",
- protocol);
-}
-
-
-/*
- * bad_signal - We've caught a fatal signal. Clean up state and exit.
- */
-static void
-bad_signal(sig)
- int sig;
-{
- syslog(LOG_ERR, "Fatal signal %d", sig);
- die(1);
-}
-
-/*
* quit - Clean up state and exit (with an error indication).
*/
void
@@ -596,7 +735,7 @@ void
die(status)
int status;
{
- cleanup(0, NULL);
+ cleanup();
syslog(LOG_INFO, "Exit.");
exit(status);
}
@@ -605,49 +744,54 @@ die(status)
* cleanup - restore anything which needs to be restored before we exit
*/
/* ARGSUSED */
-void
-cleanup(status, arg)
- int status;
- caddr_t arg;
+static void
+cleanup()
{
- if (fd >= 0)
- close_fd();
+ sys_cleanup();
+
+ if (ttyfd >= 0)
+ close_tty();
if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT)
syslog(LOG_WARNING, "unable to delete pid file: %m");
pidfilename[0] = 0;
- if (lockflag && !default_device)
+ if (locked)
unlock();
}
/*
- * close_fd - restore the terminal device and close it.
+ * close_tty - restore the terminal device and close it.
*/
-void
-close_fd()
+static void
+close_tty()
{
- disestablish_ppp();
+ disestablish_ppp(ttyfd);
/* drop dtr to hang up */
- if (modem)
- setdtr(fd, FALSE);
+ if (modem) {
+ setdtr(ttyfd, FALSE);
+ /*
+ * This sleep is in case the serial port has CLOCAL set by default,
+ * and consequently will reassert DTR when we close the device.
+ */
+ sleep(1);
+ }
- if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
- syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
- initfdflags = -1;
+ restore_tty(ttyfd);
- restore_tty();
+ if (tty_mode != (mode_t) -1)
+ chmod(devnam, tty_mode);
- close(fd);
- fd = -1;
+ close(ttyfd);
+ ttyfd = -1;
}
struct callout {
struct timeval c_time; /* time at which to call routine */
- caddr_t c_arg; /* argument to routine */
- void (*c_func)(); /* routine */
+ void *c_arg; /* argument to routine */
+ void (*c_func) __P((void *)); /* routine */
struct callout *c_next;
};
@@ -662,8 +806,8 @@ static struct timeval timenow; /* Current time */
*/
void
timeout(func, arg, time)
- void (*func)();
- caddr_t arg;
+ void (*func) __P((void *));
+ void *arg;
int time;
{
struct callout *newp, *p, **pp;
@@ -702,12 +846,10 @@ timeout(func, arg, time)
*/
void
untimeout(func, arg)
- void (*func)();
- caddr_t arg;
+ void (*func) __P((void *));
+ void *arg;
{
- struct itimerval itv;
struct callout **copp, *freep;
- int reschedule = 0;
MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg));
@@ -726,7 +868,7 @@ untimeout(func, arg)
/*
* calltimeout - Call any timeout routines which are now due.
*/
-void
+static void
calltimeout()
{
struct callout *p;
@@ -754,7 +896,7 @@ calltimeout()
/*
* timeleft - return the length of time until the next timeout is due.
*/
-struct timeval *
+static struct timeval *
timeleft(tvp)
struct timeval *tvp;
{
@@ -773,7 +915,24 @@ timeleft(tvp)
return tvp;
}
-
+
+
+/*
+ * kill_my_pg - send a signal to our process group, and ignore it ourselves.
+ */
+static void
+kill_my_pg(sig)
+ int sig;
+{
+ struct sigaction act, oldact;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ kill(0, sig);
+ sigaction(sig, &act, &oldact);
+ sigaction(sig, &oldact, NULL);
+}
+
/*
* hup - Catch SIGHUP signal.
@@ -788,6 +947,9 @@ hup(sig)
{
syslog(LOG_INFO, "Hangup (SIGHUP)");
kill_link = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
}
@@ -804,6 +966,9 @@ term(sig)
syslog(LOG_INFO, "Terminating on signal %d.", sig);
persist = 0; /* don't try to restart */
kill_link = 1;
+ if (conn_running)
+ /* Send the signal to the [dis]connector process(es) also */
+ kill_my_pg(sig);
}
@@ -830,7 +995,11 @@ toggle_debug(sig)
int sig;
{
debug = !debug;
- note_debug_level();
+ if (debug) {
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ } else {
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ }
}
@@ -849,10 +1018,24 @@ open_ccp(sig)
/*
+ * bad_signal - We've caught a fatal signal. Clean up state and exit.
+ */
+static void
+bad_signal(sig)
+ int sig;
+{
+ syslog(LOG_ERR, "Fatal signal %d", sig);
+ if (conn_running)
+ kill_my_pg(SIGTERM);
+ die(1);
+}
+
+
+/*
* device_script - run a program to connect or disconnect the
* serial device.
*/
-int
+static int
device_script(program, in, out)
char *program;
int in, out;
@@ -861,19 +1044,44 @@ device_script(program, in, out)
int status;
int errfd;
+ conn_running = 1;
pid = fork();
if (pid < 0) {
+ conn_running = 0;
syslog(LOG_ERR, "Failed to create child process: %m");
die(1);
}
if (pid == 0) {
- dup2(in, 0);
- dup2(out, 1);
- errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
- if (errfd >= 0)
- dup2(errfd, 2);
+ sys_close();
+ closelog();
+ if (in == out) {
+ if (in != 0) {
+ dup2(in, 0);
+ close(in);
+ }
+ dup2(0, 1);
+ } else {
+ if (out == 0)
+ out = dup(out);
+ if (in != 0) {
+ dup2(in, 0);
+ close(in);
+ }
+ if (out != 1) {
+ dup2(out, 1);
+ close(out);
+ }
+ }
+ if (redirect_stderr) {
+ close(2);
+ errfd = open(_PATH_CONNERRS, O_WRONLY | O_APPEND | O_CREAT, 0644);
+ if (errfd >= 0 && errfd != 2) {
+ dup2(errfd, 2);
+ close(errfd);
+ }
+ }
setuid(getuid());
setgid(getgid());
execl("/bin/sh", "sh", "-c", program, (char *)0);
@@ -888,6 +1096,7 @@ device_script(program, in, out)
syslog(LOG_ERR, "error waiting for (dis)connection process: %m");
die(1);
}
+ conn_running = 0;
return (status == 0 ? 0 : -1);
}
@@ -924,11 +1133,12 @@ run_program(prog, args, must_exist)
setgid(getegid());
/* Ensure that nothing of our device environment is inherited. */
+ sys_close();
+ closelog();
close (0);
close (1);
close (2);
- close (fd); /* tty interface to the ppp device */
- /* XXX should call sysdep cleanup procedure here */
+ close (ttyfd); /* tty interface to the ppp device */
/* Don't pass handles to the PPP device, even by accident. */
new_fd = open (_PATH_DEVNULL, O_RDWR);
@@ -966,7 +1176,7 @@ run_program(prog, args, must_exist)
* reap_kids - get status from any dead child processes,
* and log a message for abnormal terminations.
*/
-void
+static void
reap_kids()
{
int pid, status;
@@ -996,16 +1206,17 @@ char line[256]; /* line to be logged accumulated here */
char *linep;
void
-log_packet(p, len, prefix)
+log_packet(p, len, prefix, level)
u_char *p;
int len;
char *prefix;
+ int level;
{
strcpy(line, prefix);
linep = line + strlen(line);
format_packet(p, len, pr_log, NULL);
if (linep != line)
- syslog(LOG_DEBUG, "%s", line);
+ syslog(level, "%s", line);
}
/*
@@ -1022,17 +1233,18 @@ format_packet(p, len, printer, arg)
int i, n;
u_short proto;
u_char x;
+ struct protent *protp;
if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
p += 2;
GETSHORT(proto, p);
len -= PPP_HDRLEN;
- for (i = 0; i < N_PROTO; ++i)
- if (proto == prottbl[i].protocol)
+ for (i = 0; (protp = protocols[i]) != NULL; ++i)
+ if (proto == protp->protocol)
break;
- if (i < N_PROTO) {
- printer(arg, "[%s", prottbl[i].name);
- n = (*prottbl[i].printpkt)(p, len, printer, arg);
+ if (protp != NULL) {
+ printer(arg, "[%s", protp->name);
+ n = (*protp->printpkt)(p, len, printer, arg);
printer(arg, "]");
p += n;
len -= n;
@@ -1047,43 +1259,23 @@ format_packet(p, len, printer, arg)
}
}
-#ifdef __STDC__
-#include <stdarg.h>
-
-void
-pr_log(void *arg, char *fmt, ...)
+static void
+pr_log __V((void *arg, char *fmt, ...))
{
int n;
va_list pvar;
char buf[256];
+#if __STDC__
va_start(pvar, fmt);
- vsprintf(buf, fmt, pvar);
- va_end(pvar);
-
- n = strlen(buf);
- if (linep + n + 1 > line + sizeof(line)) {
- syslog(LOG_DEBUG, "%s", line);
- linep = line;
- }
- strcpy(linep, buf);
- linep += n;
-}
-
-#else /* __STDC__ */
-#include <varargs.h>
-
-void
-pr_log(arg, fmt, va_alist)
-void *arg;
-char *fmt;
-va_dcl
-{
- int n;
- va_list pvar;
- char buf[256];
-
+#else
+ void *arg;
+ char *fmt;
va_start(pvar);
+ arg = va_arg(pvar, void *);
+ fmt = va_arg(pvar, char *);
+#endif
+
vsprintf(buf, fmt, pvar);
va_end(pvar);
@@ -1095,7 +1287,6 @@ va_dcl
strcpy(linep, buf);
linep += n;
}
-#endif
/*
* print_string - print a readable representation of a string using
@@ -1113,10 +1304,25 @@ print_string(p, len, printer, arg)
printer(arg, "\"");
for (; len > 0; --len) {
c = *p++;
- if (' ' <= c && c <= '~')
+ if (' ' <= c && c <= '~') {
+ if (c == '\\' || c == '"')
+ printer(arg, "\\");
printer(arg, "%c", c);
- else
- printer(arg, "\\%.3o", c);
+ } else {
+ switch (c) {
+ case '\n':
+ printer(arg, "\\n");
+ break;
+ case '\r':
+ printer(arg, "\\r");
+ break;
+ case '\t':
+ printer(arg, "\\t");
+ break;
+ default:
+ printer(arg, "\\%.3o", c);
+ }
+ }
}
printer(arg, "\"");
}
@@ -1131,3 +1337,252 @@ novm(msg)
syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg);
die(1);
}
+
+/*
+ * fmtmsg - format a message into a buffer. Like sprintf except we
+ * also specify the length of the output buffer, and we handle
+ * %r (recursive format), %m (error message) and %I (IP address) formats.
+ * Doesn't do floating-point formats.
+ * Returns the number of chars put into buf.
+ */
+int
+fmtmsg __V((char *buf, int buflen, char *fmt, ...))
+{
+ va_list args;
+ int n;
+
+#if __STDC__
+ va_start(args, fmt);
+#else
+ char *buf;
+ int buflen;
+ char *fmt;
+ va_start(args);
+ buf = va_arg(args, char *);
+ buflen = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ n = vfmtmsg(buf, buflen, fmt, args);
+ va_end(args);
+ return n;
+}
+
+/*
+ * vfmtmsg - like fmtmsg, takes a va_list instead of a list of args.
+ */
+#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
+
+int
+vfmtmsg(buf, buflen, fmt, args)
+ char *buf;
+ int buflen;
+ char *fmt;
+ va_list args;
+{
+ int c, i, n;
+ int width, prec, fillch;
+ int base, len, neg, quoted;
+ unsigned long val = 0;
+ char *str, *f, *buf0;
+ unsigned char *p;
+ char num[32];
+ time_t t;
+ static char hexchars[] = "0123456789abcdef";
+
+ buf0 = buf;
+ --buflen;
+ while (buflen > 0) {
+ for (f = fmt; *f != '%' && *f != 0; ++f)
+ ;
+ if (f > fmt) {
+ len = f - fmt;
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, fmt, len);
+ buf += len;
+ buflen -= len;
+ fmt = f;
+ }
+ if (*fmt == 0)
+ break;
+ c = *++fmt;
+ width = prec = 0;
+ fillch = ' ';
+ if (c == '0') {
+ fillch = '0';
+ c = *++fmt;
+ }
+ if (c == '*') {
+ width = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ width = width * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ if (c == '.') {
+ c = *++fmt;
+ if (c == '*') {
+ prec = va_arg(args, int);
+ c = *++fmt;
+ } else {
+ while (isdigit(c)) {
+ prec = prec * 10 + c - '0';
+ c = *++fmt;
+ }
+ }
+ }
+ str = 0;
+ base = 0;
+ neg = 0;
+ ++fmt;
+ switch (c) {
+ case 'd':
+ i = va_arg(args, int);
+ if (i < 0) {
+ neg = 1;
+ val = -i;
+ } else
+ val = i;
+ base = 10;
+ break;
+ case 'o':
+ val = va_arg(args, unsigned int);
+ base = 8;
+ break;
+ case 'x':
+ val = va_arg(args, unsigned int);
+ base = 16;
+ break;
+ case 'p':
+ val = (unsigned long) va_arg(args, void *);
+ base = 16;
+ neg = 2;
+ break;
+ case 's':
+ str = va_arg(args, char *);
+ break;
+ case 'c':
+ num[0] = va_arg(args, int);
+ num[1] = 0;
+ str = num;
+ break;
+ case 'm':
+ str = strerror(errno);
+ break;
+ case 'I':
+ str = ip_ntoa(va_arg(args, u_int32_t));
+ break;
+ case 'r':
+ f = va_arg(args, char *);
+#ifndef __powerpc__
+ n = vfmtmsg(buf, buflen + 1, f, va_arg(args, va_list));
+#else
+ /* On the powerpc, a va_list is an array of 1 structure */
+ n = vfmtmsg(buf, buflen + 1, f, va_arg(args, void *));
+#endif
+ buf += n;
+ buflen -= n;
+ continue;
+ case 't':
+ time(&t);
+ str = ctime(&t);
+ str += 4; /* chop off the day name */
+ str[15] = 0; /* chop off year and newline */
+ break;
+ case 'v': /* "visible" string */
+ case 'q': /* quoted string */
+ quoted = c == 'q';
+ p = va_arg(args, unsigned char *);
+ if (fillch == '0' && prec > 0) {
+ n = prec;
+ } else {
+ n = strlen((char *)p);
+ if (prec > 0 && prec < n)
+ n = prec;
+ }
+ while (n > 0 && buflen > 0) {
+ c = *p++;
+ --n;
+ if (!quoted && c >= 0x80) {
+ OUTCHAR('M');
+ OUTCHAR('-');
+ c -= 0x80;
+ }
+ if (quoted && (c == '"' || c == '\\'))
+ OUTCHAR('\\');
+ if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
+ if (quoted) {
+ OUTCHAR('\\');
+ switch (c) {
+ case '\t': OUTCHAR('t'); break;
+ case '\n': OUTCHAR('n'); break;
+ case '\b': OUTCHAR('b'); break;
+ case '\f': OUTCHAR('f'); break;
+ default:
+ OUTCHAR('x');
+ OUTCHAR(hexchars[c >> 4]);
+ OUTCHAR(hexchars[c & 0xf]);
+ }
+ } else {
+ if (c == '\t')
+ OUTCHAR(c);
+ else {
+ OUTCHAR('^');
+ OUTCHAR(c ^ 0x40);
+ }
+ }
+ } else
+ OUTCHAR(c);
+ }
+ continue;
+ default:
+ *buf++ = '%';
+ if (c != '%')
+ --fmt; /* so %z outputs %z etc. */
+ --buflen;
+ continue;
+ }
+ if (base != 0) {
+ str = num + sizeof(num);
+ *--str = 0;
+ while (str > num + neg) {
+ *--str = hexchars[val % base];
+ val = val / base;
+ if (--prec <= 0 && val == 0)
+ break;
+ }
+ switch (neg) {
+ case 1:
+ *--str = '-';
+ break;
+ case 2:
+ *--str = 'x';
+ *--str = '0';
+ break;
+ }
+ len = num + sizeof(num) - 1 - str;
+ } else {
+ len = strlen(str);
+ if (prec > 0 && len > prec)
+ len = prec;
+ }
+ if (width > 0) {
+ if (width > buflen)
+ width = buflen;
+ if ((n = width - len) > 0) {
+ buflen -= n;
+ for (; n > 0; --n)
+ *buf++ = fillch;
+ }
+ }
+ if (len > buflen)
+ len = buflen;
+ memcpy(buf, str, len);
+ buf += len;
+ buflen -= len;
+ }
+ *buf = 0;
+ return buf - buf0;
+}
diff --git a/usr.sbin/pppd/options.c b/usr.sbin/pppd/options.c
index 46fda52..65e4c85 100644
--- a/usr.sbin/pppd/options.c
+++ b/usr.sbin/pppd/options.c
@@ -21,6 +21,7 @@
static char rcsid[] = "$Id$";
#endif
+#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
@@ -34,6 +35,11 @@ static char rcsid[] = "$Id$";
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef PPP_FILTER
+#include <pcap.h>
+#include <pcap-int.h> /* XXX: To get struct pcap */
+#endif
#include "pppd.h"
#include "pathnames.h"
@@ -44,6 +50,13 @@ static char rcsid[] = "$Id$";
#include "upap.h"
#include "chap.h"
#include "ccp.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
#include <net/ppp_comp.h>
@@ -61,6 +74,9 @@ char *strdup __P((char *));
/*
* Option variables and default values.
*/
+#ifdef PPP_FILTER
+int dflag = 0; /* Tell libpcap we want debugging */
+#endif
int debug = 0; /* Debug flag */
int kdebugflag = 0; /* Tell kernel to print debug messages */
int default_device = 1; /* Using /dev/tty or equivalent */
@@ -69,13 +85,12 @@ int crtscts = 0; /* Use hardware flow control */
int modem = 1; /* Use modem control lines */
int inspeed = 0; /* Input/Output speed requested */
u_int32_t netmask = 0; /* IP netmask to set on interface */
-u_int32_t dns1 = 0; /* Primary DNS server */
-u_int32_t dns2 = 0; /* Secondary DNS server */
int lockflag = 0; /* Create lock file to lock the serial dev */
int nodetach = 0; /* Don't detach from controlling tty */
char *connector = NULL; /* Script to establish physical link */
-int max_con_attempts = 1; /* Maximum number of connect attempts */
char *disconnector = NULL; /* Script to disestablish physical link */
+char *welcomer = NULL; /* Script to run after phys link estab. */
+int maxconnect = 0; /* Maximum connect time */
char user[MAXNAMELEN]; /* Username for PAP */
char passwd[MAXSECRETLEN]; /* Password for PAP */
int auth_required = 0; /* Peer is required to authenticate */
@@ -87,70 +102,96 @@ int lcp_echo_interval = 0; /* Interval between LCP echo-requests */
int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */
char our_name[MAXNAMELEN]; /* Our name for authentication purposes */
char remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+int explicit_remote = 0; /* User specified explicit remote name */
int usehostname = 0; /* Use hostname for our_name */
int disable_defaultip = 0; /* Don't use hostname for default IP adrs */
+int demand = 0; /* do dial-on-demand */
char *ipparam = NULL; /* Extra parameter for ip up/down scripts */
int cryptpap; /* Passwords in pap-secrets are encrypted */
+int idle_time_limit = 0; /* Disconnect if idle for this many seconds */
+int holdoff = 30; /* # seconds to pause before reconnecting */
+int refuse_pap = 0; /* Set to say we won't do PAP */
+int refuse_chap = 0; /* Set to say we won't do CHAP */
+
+#ifdef MSLANMAN
+int ms_lanman = 0; /* Nonzero if use LanMan password instead of NT */
+ /* Has meaning only with MS-CHAP challenges */
+#endif
-#ifdef _linux_
-int idle_time_limit = 0;
-static int setidle __P((char **));
+struct option_info auth_req_info;
+struct option_info connector_info;
+struct option_info disconnector_info;
+struct option_info welcomer_info;
+struct option_info devnam_info;
+#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 */
+pcap_t pc; /* Fake struct pcap so we can compile expr */
#endif
/*
* Prototypes
*/
-static int setdebug __P((void));
+static int setdevname __P((char *, int));
+static int setipaddr __P((char *));
+static int setspeed __P((char *));
+static int setdebug __P((char **));
static int setkdebug __P((char **));
-static int setpassive __P((void));
-static int setsilent __P((void));
-static int noopt __P((void));
-static int setnovj __P((void));
-static int setnovjccomp __P((void));
+static int setpassive __P((char **));
+static int setsilent __P((char **));
+static int noopt __P((char **));
+static int setnovj __P((char **));
+static int setnovjccomp __P((char **));
static int setvjslots __P((char **));
-static int reqpap __P((void));
-static int nopap __P((void));
+static int reqpap __P((char **));
+static int nopap __P((char **));
+#ifdef OLD_OPTIONS
static int setupapfile __P((char **));
-static int nochap __P((void));
-static int reqchap __P((void));
-static int setspeed __P((char *));
-static int noaccomp __P((void));
-static int noasyncmap __P((void));
-static int noipaddr __P((void));
-static int nomagicnumber __P((void));
+#endif
+static int nochap __P((char **));
+static int reqchap __P((char **));
+static int noaccomp __P((char **));
+static int noasyncmap __P((char **));
+static int noip __P((char **));
+static int nomagicnumber __P((char **));
static int setasyncmap __P((char **));
static int setescape __P((char **));
static int setmru __P((char **));
static int setmtu __P((char **));
-static int nomru __P((void));
-static int nopcomp __P((void));
+#ifdef CBCP_SUPPORT
+static int setcbcp __P((char *));
+#endif
+static int nomru __P((char **));
+static int nopcomp __P((char **));
static int setconnector __P((char **));
static int setdisconnector __P((char **));
-static int setmaxcon __P((char **));
+static int setwelcomer __P((char **));
+static int setmaxconnect __P((char **));
static int setdomain __P((char **));
static int setnetmask __P((char **));
-static int setdns1 __P((char **));
-static int setdns2 __P((char **));
-static int setcrtscts __P((void));
-static int setnocrtscts __P((void));
-static int setxonxoff __P((void));
-static int setnodetach __P((void));
-static int setmodem __P((void));
-static int setlocal __P((void));
-static int setlock __P((void));
+static int setcrtscts __P((char **));
+static int setnocrtscts __P((char **));
+static int setxonxoff __P((char **));
+static int setnodetach __P((char **));
+static int setmodem __P((char **));
+static int setlocal __P((char **));
+static int setlock __P((char **));
static int setname __P((char **));
static int setuser __P((char **));
static int setremote __P((char **));
-static int setauth __P((void));
+static int setauth __P((char **));
+static int setnoauth __P((char **));
static int readfile __P((char **));
-static int setdefaultroute __P((void));
-static int setnodefaultroute __P((void));
-static int setproxyarp __P((void));
-static int setnoproxyarp __P((void));
-static int setpersist __P((void));
-static int setdologin __P((void));
-static int setusehostname __P((void));
-static int setnoipdflt __P((void));
+static int callfile __P((char **));
+static int setdefaultroute __P((char **));
+static int setnodefaultroute __P((char **));
+static int setproxyarp __P((char **));
+static int setnoproxyarp __P((char **));
+static int setpersist __P((char **));
+static int setnopersist __P((char **));
+static int setdologin __P((char **));
+static int setusehostname __P((char **));
+static int setnoipdflt __P((char **));
static int setlcptimeout __P((char **));
static int setlcpterm __P((char **));
static int setlcpconf __P((char **));
@@ -165,53 +206,107 @@ static int setpapreqtime __P((char **));
static int setchaptimeout __P((char **));
static int setchapchal __P((char **));
static int setchapintv __P((char **));
-static int setipcpaccl __P((void));
-static int setipcpaccr __P((void));
+static int setipcpaccl __P((char **));
+static int setipcpaccr __P((char **));
static int setlcpechointv __P((char **));
static int setlcpechofails __P((char **));
+static int noccp __P((char **));
static int setbsdcomp __P((char **));
-static int setnobsdcomp __P((void));
+static int setnobsdcomp __P((char **));
+static int setdeflate __P((char **));
+static int setnodeflate __P((char **));
+static int setdemand __P((char **));
+static int setpred1comp __P((char **));
+static int setnopred1comp __P((char **));
static int setipparam __P((char **));
-static int setpapcrypt __P((void));
+static int setpapcrypt __P((char **));
+static int setidle __P((char **));
+static int setholdoff __P((char **));
+static int setdnsaddr __P((char **));
+static int resetipxproto __P((char **));
+static int setwinsaddr __P((char **));
+static int showversion __P((char **));
+static int showhelp __P((char **));
+
+#ifdef PPP_FILTER
+static int setpdebug __P((char **));
+static int setpassfilter __P((char **));
+static int setactivefilter __P((char **));
+#endif
+
+#ifdef IPX_CHANGE
+static int setipxproto __P((char **));
+static int setipxanet __P((char **));
+static int setipxalcl __P((char **));
+static int setipxarmt __P((char **));
+static int setipxnetwork __P((char **));
+static int setipxnode __P((char **));
+static int setipxrouter __P((char **));
+static int setipxname __P((char **));
+static int setipxcptimeout __P((char **));
+static int setipxcpterm __P((char **));
+static int setipxcpconf __P((char **));
+static int setipxcpfails __P((char **));
+#endif /* IPX_CHANGE */
+
+#ifdef MSLANMAN
+static int setmslanman __P((void));
+#endif
static int number_option __P((char *, u_int32_t *, int));
+static int int_option __P((char *, int *));
static int readable __P((int fd));
-void usage();
-
/*
* Valid arguments.
*/
static struct cmd {
char *cmd_name;
int num_args;
- int (*cmd_func)();
+ int (*cmd_func) __P((char **));
} cmds[] = {
- {"-all", 0, noopt}, /* Don't request/allow any options */
+ {"-all", 0, noopt}, /* Don't request/allow any options (useless) */
+ {"noaccomp", 0, noaccomp}, /* Disable Address/Control compression */
{"-ac", 0, noaccomp}, /* Disable Address/Control compress */
+ {"default-asyncmap", 0, noasyncmap}, /* Disable asyncmap negoatiation */
{"-am", 0, noasyncmap}, /* Disable asyncmap negotiation */
{"-as", 1, setasyncmap}, /* set the desired async map */
{"-d", 0, setdebug}, /* Increase debugging level */
+ {"nodetach", 0, setnodetach}, /* Don't detach from controlling tty */
{"-detach", 0, setnodetach}, /* don't fork */
- {"-ip", 0, noipaddr}, /* Disable IP address negotiation */
+ {"noip", 0, noip}, /* Disable IP and IPCP */
+ {"-ip", 0, noip}, /* Disable IP and IPCP */
+ {"nomagic", 0, nomagicnumber}, /* Disable magic number negotiation */
{"-mn", 0, nomagicnumber}, /* Disable magic number negotiation */
+ {"default-mru", 0, nomru}, /* Disable MRU negotiation */
{"-mru", 0, nomru}, /* Disable mru negotiation */
{"-p", 0, setpassive}, /* Set passive mode */
+ {"nopcomp", 0, nopcomp}, /* Disable protocol field compression */
{"-pc", 0, nopcomp}, /* Disable protocol field compress */
+#if OLD_OPTIONS
{"+ua", 1, setupapfile}, /* Get PAP user and password from file */
+#endif
+ {"require-pap", 0, reqpap}, /* Require PAP authentication from peer */
{"+pap", 0, reqpap}, /* Require PAP auth from peer */
+ {"refuse-pap", 0, nopap}, /* Don't agree to auth to peer with PAP */
{"-pap", 0, nopap}, /* Don't allow UPAP authentication with peer */
+ {"require-chap", 0, reqchap}, /* Require CHAP authentication from peer */
{"+chap", 0, reqchap}, /* Require CHAP authentication from peer */
+ {"refuse-chap", 0, nochap}, /* Don't agree to auth to peer with CHAP */
{"-chap", 0, nochap}, /* Don't allow CHAP authentication with peer */
+ {"novj", 0, setnovj}, /* Disable VJ compression */
{"-vj", 0, setnovj}, /* disable VJ compression */
+ {"novjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
{"-vjccomp", 0, setnovjccomp}, /* disable VJ connection-ID compression */
{"vj-max-slots", 1, setvjslots}, /* Set maximum VJ header slots */
{"asyncmap", 1, setasyncmap}, /* set the desired async map */
{"escape", 1, setescape}, /* set chars to escape on transmission */
{"connect", 1, setconnector}, /* A program to set up a connection */
- {"connect-max-attempts", 1, setmaxcon}, /* maximum # connection attempts */
{"disconnect", 1, setdisconnector}, /* program to disconnect serial dev. */
+ {"welcome", 1, setwelcomer},/* Script to welcome client */
+ {"maxconnect", 1, setmaxconnect}, /* specify a maximum connect time */
{"crtscts", 0, setcrtscts}, /* set h/w flow control */
+ {"nocrtscts", 0, setnocrtscts}, /* clear h/w flow control */
{"-crtscts", 0, setnocrtscts}, /* clear h/w flow control */
{"xonxoff", 0, setxonxoff}, /* set s/w flow control */
{"debug", 0, setdebug}, /* Increase debugging level */
@@ -219,25 +314,32 @@ static struct cmd {
{"domain", 1, setdomain}, /* Add given domain name to hostname*/
{"mru", 1, setmru}, /* Set MRU value for negotiation */
{"mtu", 1, setmtu}, /* Set our MTU */
+#ifdef CBCP_SUPPORT
+ {"callback", 1, setcbcp}, /* Ask for callback */
+#endif
{"netmask", 1, setnetmask}, /* set netmask */
- {"dns1", 1, setdns1}, /* set Primary Domain Name Server */
- {"dns2", 1, setdns2}, /* set Secondary Domain Name Server */
{"passive", 0, setpassive}, /* Set passive mode */
{"silent", 0, setsilent}, /* Set silent mode */
{"modem", 0, setmodem}, /* Use modem control lines */
{"local", 0, setlocal}, /* Don't use modem control lines */
{"lock", 0, setlock}, /* Lock serial device (with lock file) */
{"name", 1, setname}, /* Set local name for authentication */
- {"user", 1, setuser}, /* Set username for PAP auth with peer */
+ {"user", 1, setuser}, /* Set name for auth with peer */
{"usehostname", 0, setusehostname}, /* Must use hostname for auth. */
{"remotename", 1, setremote}, /* Set remote name for authentication */
{"auth", 0, setauth}, /* Require authentication from peer */
+ {"noauth", 0, setnoauth}, /* Don't require peer to authenticate */
{"file", 1, readfile}, /* Take options from a file */
+ {"call", 1, callfile}, /* Take options from a privileged file */
{"defaultroute", 0, setdefaultroute}, /* Add default route */
+ {"nodefaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
{"-defaultroute", 0, setnodefaultroute}, /* disable defaultroute option */
{"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
+ {"noproxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
{"-proxyarp", 0, setnoproxyarp}, /* disable proxyarp option */
{"persist", 0, setpersist}, /* Keep on reopening connection after close */
+ {"nopersist", 0, setnopersist}, /* Turn off persist option */
+ {"demand", 0, setdemand}, /* Dial on demand */
{"login", 0, setdologin}, /* Use system password database for UPAP */
{"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */
{"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */
@@ -258,13 +360,58 @@ static struct cmd {
{"chap-interval", 1, setchapintv}, /* Set interval for rechallenge */
{"ipcp-accept-local", 0, setipcpaccl}, /* Accept peer's address for us */
{"ipcp-accept-remote", 0, setipcpaccr}, /* Accept peer's address for it */
+ {"noccp", 0, noccp}, /* Disable CCP negotiation */
+ {"-ccp", 0, noccp}, /* Disable CCP negotiation */
{"bsdcomp", 1, setbsdcomp}, /* request BSD-Compress */
+ {"nobsdcomp", 0, setnobsdcomp}, /* don't allow BSD-Compress */
{"-bsdcomp", 0, setnobsdcomp}, /* don't allow BSD-Compress */
+ {"deflate", 1, setdeflate}, /* request Deflate compression */
+ {"nodeflate", 0, setnodeflate}, /* don't allow Deflate compression */
+ {"-deflate", 0, setnodeflate}, /* don't allow Deflate compression */
+ {"predictor1", 0, setpred1comp}, /* request Predictor-1 */
+ {"nopredictor1", 0, setnopred1comp},/* don't allow Predictor-1 */
+ {"-predictor1", 0, setnopred1comp}, /* don't allow Predictor-1 */
{"ipparam", 1, setipparam}, /* set ip script parameter */
{"papcrypt", 0, setpapcrypt}, /* PAP passwords encrypted */
-#ifdef _linux_
- {"idle-disconnect", 1, setidle}, /* seconds for disconnect of idle IP */
+ {"idle", 1, setidle}, /* idle time limit (seconds) */
+ {"holdoff", 1, setholdoff}, /* set holdoff time (seconds) */
+ {"ms-dns", 1, setdnsaddr}, /* DNS address for the peer's use */
+ {"ms-wins", 1, setwinsaddr}, /* Nameserver for SMB over TCP/IP for peer */
+ {"noipx", 0, resetipxproto}, /* Disable IPXCP (and IPX) */
+ {"-ipx", 0, resetipxproto}, /* Disable IPXCP (and IPX) */
+ {"--version", 0, showversion}, /* Show version number */
+ {"--help", 0, showhelp}, /* Show brief listing of options */
+ {"-h", 0, showhelp}, /* ditto */
+
+#ifdef PPP_FILTER
+ {"pdebug", 1, setpdebug}, /* libpcap debugging */
+ {"pass-filter", 1, setpassfilter}, /* set filter for packets to pass */
+ {"active-filter", 1, setactivefilter}, /* set filter for active pkts */
+#endif
+
+#ifdef IPX_CHANGE
+ {"ipx-network", 1, setipxnetwork}, /* IPX network number */
+ {"ipxcp-accept-network", 0, setipxanet}, /* Accept peer netowrk */
+ {"ipx-node", 1, setipxnode}, /* IPX node number */
+ {"ipxcp-accept-local", 0, setipxalcl}, /* Accept our address */
+ {"ipxcp-accept-remote", 0, setipxarmt}, /* Accept peer's address */
+ {"ipx-routing", 1, setipxrouter}, /* IPX routing proto number */
+ {"ipx-router-name", 1, setipxname}, /* IPX router name */
+ {"ipxcp-restart", 1, setipxcptimeout}, /* Set timeout for IPXCP */
+ {"ipxcp-max-terminate", 1, setipxcpterm}, /* max #xmits for term-reqs */
+ {"ipxcp-max-configure", 1, setipxcpconf}, /* max #xmits for conf-reqs */
+ {"ipxcp-max-failure", 1, setipxcpfails}, /* max #conf-naks for IPXCP */
+#if 0
+ {"ipx-compression", 1, setipxcompression}, /* IPX compression number */
#endif
+ {"ipx", 0, setipxproto}, /* Enable IPXCP (and IPX) */
+ {"+ipx", 0, setipxproto}, /* Enable IPXCP (and IPX) */
+#endif /* IPX_CHANGE */
+
+#ifdef MSLANMAN
+ {"ms-lanman", 0, setmslanman}, /* Use LanMan psswd when using MS-CHAP */
+#endif
+
{NULL, 0, NULL}
};
@@ -275,7 +422,7 @@ static struct cmd {
static char *usage_string = "\
pppd version %s patch level %d%s\n\
-Usage: %s [ arguments ], where arguments are:\n\
+Usage: %s [ options ], where options are:\n\
<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\
@@ -288,24 +435,27 @@ Usage: %s [ arguments ], where arguments are:\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\
- netmask <n> Set interface netmask to <n>\n\
See pppd(8) for more options.\n\
";
+static char *current_option; /* the name of the option being parsed */
+static int privileged_option; /* set iff the current option came from root */
+static char *option_source; /* string saying where the option came from */
/*
- * parse_args - parse a string of arguments, from the command
- * line or from a file.
+ * parse_args - parse a string of arguments from the command line.
*/
int
parse_args(argc, argv)
int argc;
char **argv;
{
- char *arg, *val;
+ char *arg;
struct cmd *cmdp;
int ret;
+ privileged_option = privileged;
+ option_source = "command line";
while (argc > 0) {
arg = *argv++;
--argc;
@@ -319,9 +469,10 @@ parse_args(argc, argv)
if (cmdp->cmd_name != NULL) {
if (argc < cmdp->num_args) {
- fprintf(stderr, "Too few parameters for command %s\n", arg);
+ option_error("too few parameters for option %s", arg);
return 0;
}
+ current_option = arg;
if (!(*cmdp->cmd_func)(argv))
return 0;
argc -= cmdp->num_args;
@@ -331,10 +482,10 @@ parse_args(argc, argv)
/*
* Maybe a tty name, speed or IP address?
*/
- if ((ret = setdevname(arg)) == 0
+ if ((ret = setdevname(arg, 0)) == 0
&& (ret = setspeed(arg)) == 0
&& (ret = setipaddr(arg)) == 0) {
- fprintf(stderr, "%s: unrecognized command\n", arg);
+ option_error("unrecognized option '%s'", arg);
usage();
return 0;
}
@@ -346,13 +497,75 @@ parse_args(argc, argv)
}
/*
+ * scan_args - scan the command line arguments to get the tty name,
+ * if specified.
+ */
+void
+scan_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg;
+ struct cmd *cmdp;
+
+ while (argc > 0) {
+ arg = *argv++;
+ --argc;
+
+ /* Skip options and their arguments */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(arg, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ argc -= cmdp->num_args;
+ argv += cmdp->num_args;
+ continue;
+ }
+
+ /* Check if it's a tty name and copy it if so */
+ (void) setdevname(arg, 1);
+ }
+}
+
+/*
* usage - print out a message telling how to use the program.
*/
void
usage()
{
- fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
- progname);
+ if (phase == PHASE_INITIALIZE)
+ fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
+ progname);
+}
+
+/*
+ * showhelp - print out usage message and exit.
+ */
+static int
+showhelp(argv)
+ char **argv;
+{
+ if (phase == PHASE_INITIALIZE) {
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+/*
+ * showversion - print out the version number and exit.
+ */
+static int
+showversion(argv)
+ char **argv;
+{
+ if (phase == PHASE_INITIALIZE) {
+ fprintf(stderr, "pppd version %s patch level %d%s\n",
+ VERSION, PATCHLEVEL, IMPLEMENTATION);
+ exit(0);
+ }
+ return 0;
}
/*
@@ -360,14 +573,16 @@ usage()
* and interpret them.
*/
int
-options_from_file(filename, must_exist, check_prot)
+options_from_file(filename, must_exist, check_prot, priv)
char *filename;
int must_exist;
int check_prot;
+ int priv;
{
FILE *f;
int i, newline, ret;
struct cmd *cmdp;
+ int oldpriv;
char *argv[MAXARGS];
char args[MAXARGS][MAXWORDLEN];
char cmd[MAXWORDLEN];
@@ -375,15 +590,18 @@ options_from_file(filename, must_exist, check_prot)
if ((f = fopen(filename, "r")) == NULL) {
if (!must_exist && errno == ENOENT)
return 1;
- perror(filename);
+ option_error("Can't open options file %s: %m", filename);
return 0;
}
if (check_prot && !readable(fileno(f))) {
- fprintf(stderr, "%s: access denied\n", filename);
+ option_error("Can't open options file %s: access denied", filename);
fclose(f);
return 0;
}
+ oldpriv = privileged_option;
+ privileged_option = priv;
+ ret = 0;
while (getword(f, cmd, &newline, filename)) {
/*
* First see if it's a command.
@@ -395,36 +613,38 @@ options_from_file(filename, must_exist, check_prot)
if (cmdp->cmd_name != NULL) {
for (i = 0; i < cmdp->num_args; ++i) {
if (!getword(f, args[i], &newline, filename)) {
- fprintf(stderr,
- "In file %s: too few parameters for command %s\n",
- filename, cmd);
- fclose(f);
- return 0;
+ option_error(
+ "In file %s: too few parameters for option '%s'",
+ filename, cmd);
+ goto err;
}
argv[i] = args[i];
}
- if (!(*cmdp->cmd_func)(argv)) {
- fclose(f);
- return 0;
- }
+ current_option = cmd;
+ if (!(*cmdp->cmd_func)(argv))
+ goto err;
} else {
/*
* Maybe a tty name, speed or IP address?
*/
- if ((ret = setdevname(cmd)) == 0
- && (ret = setspeed(cmd)) == 0
- && (ret = setipaddr(cmd)) == 0) {
- fprintf(stderr, "In file %s: unrecognized command %s\n",
- filename, cmd);
- fclose(f);
- return 0;
+ if ((i = setdevname(cmd, 0)) == 0
+ && (i = setspeed(cmd)) == 0
+ && (i = setipaddr(cmd)) == 0) {
+ option_error("In file %s: unrecognized option '%s'",
+ filename, cmd);
+ goto err;
}
- if (ret < 0) /* error */
- return 0;
+ if (i < 0) /* error */
+ goto err;
}
}
- return 1;
+ ret = 1;
+
+err:
+ fclose(f);
+ privileged_option = oldpriv;
+ return ret;
}
/*
@@ -448,7 +668,7 @@ options_from_user()
strcpy(path, user);
strcat(path, "/");
strcat(path, file);
- ret = options_from_file(path, 0, 1);
+ ret = options_from_file(path, 0, 1, privileged);
free(path);
return ret;
}
@@ -460,27 +680,53 @@ options_from_user()
int
options_for_tty()
{
- char *dev, *path;
+ char *dev, *path, *p;
int ret;
- dev = strrchr(devnam, '/');
- if (dev == NULL)
- dev = devnam;
- else
- ++dev;
+ dev = devnam;
+ if (strncmp(dev, "/dev/", 5) == 0)
+ dev += 5;
if (strcmp(dev, "tty") == 0)
return 1; /* don't look for /etc/ppp/options.tty */
path = malloc(strlen(_PATH_TTYOPT) + strlen(dev) + 1);
if (path == NULL)
novm("tty init file name");
strcpy(path, _PATH_TTYOPT);
- strcat(path, dev);
- ret = options_from_file(path, 0, 0);
+ /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
+ for (p = path + strlen(path); *dev != 0; ++dev)
+ *p++ = (*dev == '/'? '.': *dev);
+ *p = 0;
+ ret = options_from_file(path, 0, 0, 1);
free(path);
return ret;
}
/*
+ * 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
+option_error __V((char *fmt, ...))
+{
+ va_list args;
+ char buf[256];
+
+#if __STDC__
+ va_start(args, fmt);
+#else
+ char *fmt;
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfmtmsg(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if (phase == PHASE_INITIALIZE)
+ fprintf(stderr, "%s: %s\n", progname, buf);
+ syslog(LOG_ERR, "%s", buf);
+}
+
+/*
* readable - check if a file is readable by the real user.
*/
static int
@@ -514,7 +760,6 @@ readable(fd)
* Quotes, white-space and \ may be escaped with \.
* \<newline> is ignored.
*/
-
int
getword(f, word, newlinep, filename)
FILE *f;
@@ -728,7 +973,7 @@ getword(f, word, newlinep, filename)
if (ferror(f)) {
if (errno == 0)
errno = EIO;
- perror(filename);
+ option_error("Error reading %s: %m", filename);
die(1);
}
/*
@@ -743,8 +988,8 @@ getword(f, word, newlinep, filename)
* Warn if the word was too long, and append a terminating null.
*/
if (len >= MAXWORDLEN) {
- fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
- progname, filename, word);
+ option_error("warning: word in file %s too long (%.20s...)",
+ filename, word);
len = MAXWORDLEN - 1;
}
word[len] = 0;
@@ -768,7 +1013,8 @@ number_option(str, valp, base)
*valp = strtoul(str, &ptr, base);
if (ptr == str) {
- fprintf(stderr, "%s: invalid number: %s\n", progname, str);
+ option_error("invalid numeric parameter '%s' for %s option",
+ str, current_option);
return 0;
}
return 1;
@@ -795,7 +1041,7 @@ int_option(str, valp)
/*
- * The following procedures execute commands.
+ * The following procedures parse options.
*/
/*
@@ -805,14 +1051,60 @@ static int
readfile(argv)
char **argv;
{
- return options_from_file(*argv, 1, 1);
+ 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
+callfile(argv)
+ char **argv;
+{
+ 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");
+ strcpy(fname, _PATH_PEERFILES);
+ strcat(fname, arg);
+
+ ok = options_from_file(fname, 1, 1, 1);
+
+ free(fname);
+ return ok;
+}
+
+
+/*
* setdebug - Set debug (command line argument).
*/
static int
-setdebug()
+setdebug(argv)
+ char **argv;
{
debug++;
return (1);
@@ -828,16 +1120,67 @@ setkdebug(argv)
return int_option(*argv, &kdebugflag);
}
+#ifdef PPP_FILTER
+/*
+ * setpdebug - Set libpcap debugging level.
+ */
+static int
+setpdebug(argv)
+ char **argv;
+{
+ return int_option(*argv, &dflag);
+}
+
+/*
+ * setpassfilter - Set the pass filter for packets
+ */
+static int
+setpassfilter(argv)
+ char **argv;
+{
+ pc.linktype = DLT_PPP;
+ pc.snapshot = PPP_HDRLEN;
+
+ if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
+ return 1;
+ option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
+ return 0;
+}
+
+/*
+ * setactivefilter - Set the active filter for packets
+ */
+static int
+setactivefilter(argv)
+ char **argv;
+{
+ pc.linktype = DLT_PPP;
+ pc.snapshot = PPP_HDRLEN;
+
+ if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
+ return 1;
+ option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
+ return 0;
+}
+#endif
+
/*
* noopt - Disable all options.
*/
static int
-noopt()
+noopt(argv)
+ char **argv;
{
BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
+
+#ifdef IPX_CHANGE
+ BZERO((char *) &ipxcp_wantoptions[0], sizeof (struct ipxcp_options));
+ BZERO((char *) &ipxcp_allowoptions[0], sizeof (struct ipxcp_options));
+#endif /* IPX_CHANGE */
+
return (1);
}
@@ -845,7 +1188,8 @@ noopt()
* noaccomp - Disable Address/Control field compression negotiation.
*/
static int
-noaccomp()
+noaccomp(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_accompression = 0;
lcp_allowoptions[0].neg_accompression = 0;
@@ -857,7 +1201,8 @@ noaccomp()
* noasyncmap - Disable async map negotiation.
*/
static int
-noasyncmap()
+noasyncmap(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_asyncmap = 0;
lcp_allowoptions[0].neg_asyncmap = 0;
@@ -866,13 +1211,13 @@ noasyncmap()
/*
- * noipaddr - Disable IP address negotiation.
+ * noip - Disable IP and IPCP.
*/
static int
-noipaddr()
+noip(argv)
+ char **argv;
{
- ipcp_wantoptions[0].neg_addr = 0;
- ipcp_allowoptions[0].neg_addr = 0;
+ ipcp_protent.enabled_flag = 0;
return (1);
}
@@ -881,7 +1226,8 @@ noipaddr()
* nomagicnumber - Disable magic number negotiation.
*/
static int
-nomagicnumber()
+nomagicnumber(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_magicnumber = 0;
lcp_allowoptions[0].neg_magicnumber = 0;
@@ -893,7 +1239,8 @@ nomagicnumber()
* nomru - Disable mru negotiation.
*/
static int
-nomru()
+nomru(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_mru = 0;
lcp_allowoptions[0].neg_mru = 0;
@@ -930,20 +1277,36 @@ setmtu(argv)
if (!number_option(*argv, &mtu, 0))
return 0;
if (mtu < MINMRU || mtu > MAXMRU) {
- fprintf(stderr, "mtu option value of %ld is too %s\n", mtu,
- (mtu < MINMRU? "small": "large"));
+ option_error("mtu option value of %u is too %s", mtu,
+ (mtu < MINMRU? "small": "large"));
return 0;
}
lcp_allowoptions[0].mru = mtu;
return (1);
}
+#ifdef CBCP_SUPPORT
+static int
+setcbcp(argv)
+ char **argv;
+{
+ lcp_wantoptions[0].neg_cbcp = 1;
+ cbcp_protent.enabled_flag = 1;
+ cbcp[0].us_number = strdup(*argv);
+ if (cbcp[0].us_number == 0)
+ novm("callback number");
+ cbcp[0].us_type |= (1 << CB_CONF_USER);
+ cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
+ return (1);
+}
+#endif
/*
* nopcomp - Disable Protocol field compression negotiation.
*/
static int
-nopcomp()
+nopcomp(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_pcompression = 0;
lcp_allowoptions[0].neg_pcompression = 0;
@@ -956,7 +1319,8 @@ nopcomp()
* LCP configure-requests).
*/
static int
-setpassive()
+setpassive(argv)
+ char **argv;
{
lcp_wantoptions[0].passive = 1;
return (1);
@@ -968,7 +1332,8 @@ setpassive()
* until we get one from the peer).
*/
static int
-setsilent()
+setsilent(argv)
+ char **argv;
{
lcp_wantoptions[0].silent = 1;
return 1;
@@ -979,9 +1344,10 @@ setsilent()
* nopap - Disable PAP authentication with peer.
*/
static int
-nopap()
+nopap(argv)
+ char **argv;
{
- lcp_allowoptions[0].neg_upap = 0;
+ refuse_pap = 1;
return (1);
}
@@ -990,14 +1356,15 @@ nopap()
* reqpap - Require PAP authentication from peer.
*/
static int
-reqpap()
+reqpap(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_upap = 1;
- auth_required = 1;
+ setauth(NULL);
return 1;
}
-
+#if OLD_OPTIONS
/*
* setupapfile - specifies UPAP info for authenticating with peer.
*/
@@ -1012,11 +1379,11 @@ setupapfile(argv)
/* open user info file */
if ((ufile = fopen(*argv, "r")) == NULL) {
- fprintf(stderr, "unable to open user login data file %s\n", *argv);
+ option_error("unable to open user login data file %s", *argv);
return 0;
}
if (!readable(fileno(ufile))) {
- fprintf(stderr, "%s: access denied\n", *argv);
+ option_error("%s: access denied", *argv);
return 0;
}
check_access(ufile, *argv);
@@ -1024,7 +1391,7 @@ setupapfile(argv)
/* get username */
if (fgets(user, MAXNAMELEN - 1, ufile) == NULL
|| fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){
- fprintf(stderr, "Unable to read user login data file %s.\n", *argv);
+ option_error("unable to read user login data file %s", *argv);
return 0;
}
fclose(ufile);
@@ -1039,15 +1406,16 @@ setupapfile(argv)
return (1);
}
-
+#endif
/*
* nochap - Disable CHAP authentication with peer.
*/
static int
-nochap()
+nochap(argv)
+ char **argv;
{
- lcp_allowoptions[0].neg_chap = 0;
+ refuse_chap = 1;
return (1);
}
@@ -1056,10 +1424,11 @@ nochap()
* reqchap - Require CHAP authentication from peer.
*/
static int
-reqchap()
+reqchap(argv)
+ char **argv;
{
lcp_wantoptions[0].neg_chap = 1;
- auth_required = 1;
+ setauth(NULL);
return (1);
}
@@ -1068,7 +1437,8 @@ reqchap()
* setnovj - disable vj compression
*/
static int
-setnovj()
+setnovj(argv)
+ char **argv;
{
ipcp_wantoptions[0].neg_vj = 0;
ipcp_allowoptions[0].neg_vj = 0;
@@ -1080,7 +1450,8 @@ setnovj()
* setnovjccomp - disable VJ connection-ID compression
*/
static int
-setnovjccomp()
+setnovjccomp(argv)
+ char **argv;
{
ipcp_wantoptions[0].cflag = 0;
ipcp_allowoptions[0].cflag = 0;
@@ -1100,7 +1471,7 @@ setvjslots(argv)
if (!int_option(*argv, &value))
return 0;
if (value < 2 || value > 16) {
- fprintf(stderr, "pppd: vj-max-slots value must be between 2 and 16\n");
+ option_error("vj-max-slots value must be between 2 and 16");
return 0;
}
ipcp_wantoptions [0].maxslotindex =
@@ -1118,8 +1489,10 @@ setconnector(argv)
{
connector = strdup(*argv);
if (connector == NULL)
- novm("connector string");
-
+ novm("connect script");
+ connector_info.priv = privileged_option;
+ connector_info.source = option_source;
+
return (1);
}
@@ -1132,11 +1505,51 @@ setdisconnector(argv)
{
disconnector = strdup(*argv);
if (disconnector == NULL)
- novm("disconnector string");
+ novm("disconnect script");
+ disconnector_info.priv = privileged_option;
+ disconnector_info.source = option_source;
return (1);
}
+/*
+ * setwelcomer - Set a program to welcome a client after connection
+ */
+static int
+setwelcomer(argv)
+ char **argv;
+{
+ welcomer = strdup(*argv);
+ if (welcomer == NULL)
+ novm("welcome script");
+ welcomer_info.priv = privileged_option;
+ welcomer_info.source = option_source;
+
+ return (1);
+}
+
+/*
+ * setmaxconnect - Set the maximum connect time
+ */
+static int
+setmaxconnect(argv)
+ char **argv;
+{
+ int value;
+
+ if (!int_option(*argv, &value))
+ return 0;
+ if (value < 0) {
+ option_error("maxconnect time must be positive");
+ return 0;
+ }
+ if (maxconnect > 0 && (value == 0 || value > maxconnect)) {
+ option_error("maxconnect time cannot be increased");
+ return 0;
+ }
+ maxconnect = value;
+ return 1;
+}
/*
* setdomain - Set domain name to append to hostname
@@ -1145,6 +1558,10 @@ static int
setdomain(argv)
char **argv;
{
+ if (!privileged_option) {
+ option_error("using the domain option requires root privilege");
+ return 0;
+ }
gethostname(hostname, MAXNAMELEN);
if (**argv != 0) {
if (**argv != '.')
@@ -1188,12 +1605,13 @@ setescape(argv)
while (*p) {
n = strtol(p, &endp, 16);
if (p == endp) {
- fprintf(stderr, "%s: invalid hex number: %s\n", progname, p);
+ option_error("escape parameter contains invalid hex number '%s'",
+ p);
return 0;
}
p = endp;
- if (n < 0 || 0x20 <= n && n <= 0x3F || n == 0x5E || n > 0xFF) {
- fprintf(stderr, "%s: can't escape character 0x%x\n", progname, n);
+ if (n < 0 || (0x20 <= n && n <= 0x3F) || n == 0x5E || n > 0xFF) {
+ option_error("can't escape character 0x%x", n);
ret = 0;
} else
xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
@@ -1225,14 +1643,17 @@ setspeed(arg)
/*
* setdevname - Set the device name.
*/
-int
-setdevname(cp)
+static int
+setdevname(cp, quiet)
char *cp;
+ int quiet;
{
struct stat statbuf;
- char *tty, *ttyname();
char dev[MAXPATHLEN];
-
+
+ if (*cp == 0)
+ return 0;
+
if (strncmp("/dev/", cp, 5) != 0) {
strcpy(dev, "/dev/");
strncat(dev, cp, MAXPATHLEN - 5);
@@ -1244,15 +1665,17 @@ setdevname(cp)
* Check if there is a device by this name.
*/
if (stat(cp, &statbuf) < 0) {
- if (errno == ENOENT)
+ if (errno == ENOENT || quiet)
return 0;
- syslog(LOG_ERR, cp);
+ option_error("Couldn't stat %s: %m", cp);
return -1;
}
-
+
(void) strncpy(devnam, cp, MAXPATHLEN);
devnam[MAXPATHLEN-1] = 0;
default_device = FALSE;
+ devnam_info.priv = privileged_option;
+ devnam_info.source = option_source;
return 1;
}
@@ -1261,7 +1684,7 @@ setdevname(cp)
/*
* setipaddr - Set the IP address
*/
-int
+static int
setipaddr(arg)
char *arg;
{
@@ -1283,18 +1706,14 @@ setipaddr(arg)
*colon = '\0';
if ((local = inet_addr(arg)) == -1) {
if ((hp = gethostbyname(arg)) == NULL) {
- fprintf(stderr, "unknown host: %s\n", arg);
+ option_error("unknown host: %s", arg);
return -1;
} else {
local = *(u_int32_t *)hp->h_addr;
- if (our_name[0] == 0) {
- strncpy(our_name, arg, MAXNAMELEN);
- our_name[MAXNAMELEN-1] = 0;
- }
}
}
if (bad_ip_adrs(local)) {
- fprintf(stderr, "bad local IP address %s\n", ip_ntoa(local));
+ option_error("bad local IP address %s", ip_ntoa(local));
return -1;
}
if (local != 0)
@@ -1308,7 +1727,7 @@ setipaddr(arg)
if (*++colon != '\0') {
if ((remote = inet_addr(colon)) == -1) {
if ((hp = gethostbyname(colon)) == NULL) {
- fprintf(stderr, "unknown host: %s\n", colon);
+ option_error("unknown host: %s", colon);
return -1;
} else {
remote = *(u_int32_t *)hp->h_addr;
@@ -1319,7 +1738,7 @@ setipaddr(arg)
}
}
if (bad_ip_adrs(remote)) {
- fprintf(stderr, "bad remote IP address %s\n", ip_ntoa(remote));
+ option_error("bad remote IP address %s", ip_ntoa(remote));
return -1;
}
if (remote != 0)
@@ -1334,7 +1753,8 @@ setipaddr(arg)
* setnoipdflt - disable setipdefault()
*/
static int
-setnoipdflt()
+setnoipdflt(argv)
+ char **argv;
{
disable_defaultip = 1;
return 1;
@@ -1345,7 +1765,8 @@ setnoipdflt()
* setipcpaccl - accept peer's idea of our address
*/
static int
-setipcpaccl()
+setipcpaccl(argv)
+ char **argv;
{
ipcp_wantoptions[0].accept_local = 1;
return 1;
@@ -1356,7 +1777,8 @@ setipcpaccl()
* setipcpaccr - accept peer's idea of its address
*/
static int
-setipcpaccr()
+setipcpaccr(argv)
+ char **argv;
{
ipcp_wantoptions[0].accept_remote = 1;
return 1;
@@ -1364,36 +1786,6 @@ setipcpaccr()
/*
- * setipdefault - default our local IP address based on our hostname.
- */
-void
-setipdefault()
-{
- struct hostent *hp;
- u_int32_t local;
- ipcp_options *wo = &ipcp_wantoptions[0];
-
- /*
- * If local IP address already given, don't bother.
- */
- if (wo->ouraddr != 0 || disable_defaultip)
- return;
-
- /*
- * Look up our hostname (possibly with domain name appended)
- * and take the first IP address as our local IP address.
- * If there isn't an IP address for our hostname, too bad.
- */
- wo->accept_local = 1; /* don't insist on this default value */
- if ((hp = gethostbyname(hostname)) == NULL)
- return;
- local = *(u_int32_t *)hp->h_addr;
- if (local != 0 && !bad_ip_adrs(local))
- wo->ouraddr = local;
-}
-
-
-/*
* setnetmask - set the netmask to be used on the interface.
*/
static int
@@ -1411,98 +1803,77 @@ setnetmask(argv)
return (1);
}
-
-/*
- * setdns1 - set the primary dns.
- */
static int
-setdns1(argv)
+setcrtscts(argv)
char **argv;
{
- struct in_addr mask;
-
- if ((inet_aton(*argv, &mask) < 0)) {
- fprintf(stderr, "Invalid dns1 %s\n", *argv);
- return (0);
- }
-
- dns1 = mask.s_addr;
- return (1);
-}
-
-
-/*
- * setdns2 - set the secondary dns.
- */
-static int
-setdns2(argv)
- char **argv;
-{
- struct in_addr mask;
-
- if ((inet_aton(*argv, &mask) < 0)) {
- fprintf(stderr, "Invalid dns2 %s\n", *argv);
- return (0);
- }
-
- dns2 = mask.s_addr;
- return (1);
-}
-
-static int
-setcrtscts()
-{
crtscts = 1;
return (1);
}
static int
-setnocrtscts()
+setnocrtscts(argv)
+ char **argv;
{
crtscts = -1;
return (1);
}
static int
-setxonxoff()
+setxonxoff(argv)
+ char **argv;
{
lcp_wantoptions[0].asyncmap |= 0x000A0000; /* escape ^S and ^Q */
lcp_wantoptions[0].neg_asyncmap = 1;
- crtscts = 2;
+ crtscts = -2;
return (1);
}
static int
-setnodetach()
+setnodetach(argv)
+ char **argv;
{
nodetach = 1;
return (1);
}
static int
-setmodem()
+setdemand(argv)
+ char **argv;
+{
+ demand = 1;
+ persist = 1;
+ return 1;
+}
+
+static int
+setmodem(argv)
+ char **argv;
{
modem = 1;
return 1;
}
static int
-setlocal()
+setlocal(argv)
+ char **argv;
{
modem = 0;
return 1;
}
static int
-setlock()
+setlock(argv)
+ char **argv;
{
lockflag = 1;
return 1;
}
static int
-setusehostname()
+setusehostname(argv)
+ char **argv;
{
usehostname = 1;
return 1;
@@ -1512,10 +1883,12 @@ static int
setname(argv)
char **argv;
{
- if (our_name[0] == 0) {
- strncpy(our_name, argv[0], MAXNAMELEN);
- our_name[MAXNAMELEN-1] = 0;
+ if (!privileged_option) {
+ option_error("using the name option requires root privilege");
+ return 0;
}
+ strncpy(our_name, argv[0], MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
return 1;
}
@@ -1538,17 +1911,36 @@ setremote(argv)
}
static int
-setauth()
+setauth(argv)
+ char **argv;
{
auth_required = 1;
+ if (privileged_option > auth_req_info.priv) {
+ auth_req_info.priv = privileged_option;
+ auth_req_info.source = option_source;
+ }
return 1;
}
static int
-setdefaultroute()
+setnoauth(argv)
+ char **argv;
+{
+ if (auth_required && privileged_option < auth_req_info.priv) {
+ option_error("cannot override auth option set by %s",
+ auth_req_info.source);
+ return 0;
+ }
+ auth_required = 0;
+ return 1;
+}
+
+static int
+setdefaultroute(argv)
+ char **argv;
{
if (!ipcp_allowoptions[0].default_route) {
- fprintf(stderr, "%s: defaultroute option is disabled\n", progname);
+ option_error("defaultroute option is disabled");
return 0;
}
ipcp_wantoptions[0].default_route = 1;
@@ -1556,7 +1948,8 @@ setdefaultroute()
}
static int
-setnodefaultroute()
+setnodefaultroute(argv)
+ char **argv;
{
ipcp_allowoptions[0].default_route = 0;
ipcp_wantoptions[0].default_route = 0;
@@ -1564,10 +1957,11 @@ setnodefaultroute()
}
static int
-setproxyarp()
+setproxyarp(argv)
+ char **argv;
{
if (!ipcp_allowoptions[0].proxy_arp) {
- fprintf(stderr, "%s: proxyarp option is disabled\n", progname);
+ option_error("proxyarp option is disabled");
return 0;
}
ipcp_wantoptions[0].proxy_arp = 1;
@@ -1575,7 +1969,8 @@ setproxyarp()
}
static int
-setnoproxyarp()
+setnoproxyarp(argv)
+ char **argv;
{
ipcp_wantoptions[0].proxy_arp = 0;
ipcp_allowoptions[0].proxy_arp = 0;
@@ -1583,14 +1978,24 @@ setnoproxyarp()
}
static int
-setpersist()
+setpersist(argv)
+ char **argv;
{
persist = 1;
return 1;
}
static int
-setdologin()
+setnopersist(argv)
+ char **argv;
+{
+ persist = 0;
+ return 1;
+}
+
+static int
+setdologin(argv)
+ char **argv;
{
uselogin = 1;
return 1;
@@ -1716,6 +2121,14 @@ setchapintv(argv)
}
static int
+noccp(argv)
+ char **argv;
+{
+ ccp_protent.enabled_flag = 0;
+ return 1;
+}
+
+static int
setbsdcomp(argv)
char **argv;
{
@@ -1729,14 +2142,13 @@ setbsdcomp(argv)
abits = strtol(str, &endp, 0);
}
if (*endp != 0 || endp == str) {
- fprintf(stderr, "%s: invalid argument format for bsdcomp option\n",
- progname);
+ option_error("invalid parameter '%s' for bsdcomp option", *argv);
return 0;
}
- if (rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)
- || abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS)) {
- fprintf(stderr, "%s: bsdcomp option values must be 0 or %d .. %d\n",
- progname, BSD_MIN_BITS, BSD_MAX_BITS);
+ if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
+ || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
+ option_error("bsdcomp option values must be 0 or %d .. %d",
+ BSD_MIN_BITS, BSD_MAX_BITS);
return 0;
}
if (rbits > 0) {
@@ -1753,7 +2165,8 @@ setbsdcomp(argv)
}
static int
-setnobsdcomp()
+setnobsdcomp(argv)
+ char **argv;
{
ccp_wantoptions[0].bsd_compress = 0;
ccp_allowoptions[0].bsd_compress = 0;
@@ -1761,6 +2174,70 @@ setnobsdcomp()
}
static int
+setdeflate(argv)
+ char **argv;
+{
+ int rbits, abits;
+ char *str, *endp;
+
+ str = *argv;
+ abits = rbits = strtol(str, &endp, 0);
+ if (endp != str && *endp == ',') {
+ str = endp + 1;
+ abits = strtol(str, &endp, 0);
+ }
+ if (*endp != 0 || endp == str) {
+ option_error("invalid parameter '%s' for deflate option", *argv);
+ return 0;
+ }
+ if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE))
+ || (abits != 0 && (abits < DEFLATE_MIN_SIZE
+ || abits > DEFLATE_MAX_SIZE))) {
+ option_error("deflate option values must be 0 or %d .. %d",
+ DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
+ return 0;
+ }
+ if (rbits > 0) {
+ ccp_wantoptions[0].deflate = 1;
+ ccp_wantoptions[0].deflate_size = rbits;
+ } else
+ ccp_wantoptions[0].deflate = 0;
+ if (abits > 0) {
+ ccp_allowoptions[0].deflate = 1;
+ ccp_allowoptions[0].deflate_size = abits;
+ } else
+ ccp_allowoptions[0].deflate = 0;
+ return 1;
+}
+
+static int
+setnodeflate(argv)
+ char **argv;
+{
+ ccp_wantoptions[0].deflate = 0;
+ ccp_allowoptions[0].deflate = 0;
+ return 1;
+}
+
+static int
+setpred1comp(argv)
+ char **argv;
+{
+ ccp_wantoptions[0].predictor_1 = 1;
+ ccp_allowoptions[0].predictor_1 = 1;
+ return 1;
+}
+
+static int
+setnopred1comp(argv)
+ char **argv;
+{
+ ccp_wantoptions[0].predictor_1 = 0;
+ ccp_allowoptions[0].predictor_1 = 0;
+ return 1;
+}
+
+static int
setipparam(argv)
char **argv;
{
@@ -1772,22 +2249,274 @@ setipparam(argv)
}
static int
-setpapcrypt()
+setpapcrypt(argv)
+ char **argv;
{
cryptpap = 1;
return 1;
}
-static int setmaxcon (argv)
+static int
+setidle(argv)
char **argv;
{
- return int_option(*argv, &max_con_attempts);
+ return int_option(*argv, &idle_time_limit);
}
-#ifdef _linux_
-static int setidle (argv)
+static int
+setholdoff(argv)
char **argv;
{
- return int_option(*argv, &idle_time_limit);
+ return int_option(*argv, &holdoff);
+}
+
+/*
+ * setdnsaddr - set the dns address(es)
+ */
+static int
+setdnsaddr(argv)
+ char **argv;
+{
+ u_int32_t dns;
+ struct hostent *hp;
+
+ dns = inet_addr(*argv);
+ if (dns == -1) {
+ if ((hp = gethostbyname(*argv)) == NULL) {
+ option_error("invalid address parameter '%s' for ms-dns option",
+ *argv);
+ return 0;
+ }
+ dns = *(u_int32_t *)hp->h_addr;
+ }
+
+ if (ipcp_allowoptions[0].dnsaddr[0] == 0) {
+ ipcp_allowoptions[0].dnsaddr[0] = dns;
+ } else {
+ ipcp_allowoptions[0].dnsaddr[1] = dns;
+ }
+
+ return (1);
+}
+
+/*
+ * setwinsaddr - set the wins address(es)
+ * This is primrarly used with the Samba package under UNIX or for pointing
+ * the caller to the existing WINS server on a Windows NT platform.
+ */
+static int
+setwinsaddr(argv)
+ char **argv;
+{
+ u_int32_t wins;
+ struct hostent *hp;
+
+ wins = inet_addr(*argv);
+ if (wins == -1) {
+ if ((hp = gethostbyname(*argv)) == NULL) {
+ option_error("invalid address parameter '%s' for ms-wins option",
+ *argv);
+ return 0;
+ }
+ wins = *(u_int32_t *)hp->h_addr;
+ }
+
+ if (ipcp_allowoptions[0].winsaddr[0] == 0) {
+ ipcp_allowoptions[0].winsaddr[0] = wins;
+ } else {
+ ipcp_allowoptions[0].winsaddr[1] = wins;
+ }
+
+ return (1);
+}
+
+#ifdef IPX_CHANGE
+static int
+setipxrouter (argv)
+ char **argv;
+{
+ ipxcp_wantoptions[0].neg_router = 1;
+ ipxcp_allowoptions[0].neg_router = 1;
+ return int_option(*argv, &ipxcp_wantoptions[0].router);
+}
+
+static int
+setipxname (argv)
+ char **argv;
+{
+ char *dest = ipxcp_wantoptions[0].name;
+ char *src = *argv;
+ int count;
+ char ch;
+
+ ipxcp_wantoptions[0].neg_name = 1;
+ ipxcp_allowoptions[0].neg_name = 1;
+ memset (dest, '\0', sizeof (ipxcp_wantoptions[0].name));
+
+ count = 0;
+ while (*src) {
+ ch = *src++;
+ if (! isalnum (ch) && ch != '_') {
+ option_error("IPX router name must be alphanumeric or _");
+ return 0;
+ }
+
+ if (count >= sizeof (ipxcp_wantoptions[0].name)) {
+ option_error("IPX router name is limited to %d characters",
+ sizeof (ipxcp_wantoptions[0].name) - 1);
+ return 0;
+ }
+
+ dest[count++] = toupper (ch);
+ }
+
+ return 1;
+}
+
+static int
+setipxcptimeout (argv)
+ char **argv;
+{
+ return int_option(*argv, &ipxcp_fsm[0].timeouttime);
+}
+
+static int
+setipxcpterm (argv)
+ char **argv;
+{
+ return int_option(*argv, &ipxcp_fsm[0].maxtermtransmits);
+}
+
+static int
+setipxcpconf (argv)
+ char **argv;
+{
+ return int_option(*argv, &ipxcp_fsm[0].maxconfreqtransmits);
+}
+
+static int
+setipxcpfails (argv)
+ char **argv;
+{
+ return int_option(*argv, &ipxcp_fsm[0].maxnakloops);
+}
+
+static int
+setipxnetwork(argv)
+ char **argv;
+{
+ u_int32_t v;
+
+ if (!number_option(*argv, &v, 16))
+ return 0;
+
+ ipxcp_wantoptions[0].our_network = (int) v;
+ ipxcp_wantoptions[0].neg_nn = 1;
+ return 1;
+}
+
+static int
+setipxanet(argv)
+ char **argv;
+{
+ ipxcp_wantoptions[0].accept_network = 1;
+ ipxcp_allowoptions[0].accept_network = 1;
+}
+
+static int
+setipxalcl(argv)
+ char **argv;
+{
+ ipxcp_wantoptions[0].accept_local = 1;
+ ipxcp_allowoptions[0].accept_local = 1;
+}
+
+static int
+setipxarmt(argv)
+ char **argv;
+{
+ ipxcp_wantoptions[0].accept_remote = 1;
+ ipxcp_allowoptions[0].accept_remote = 1;
+}
+
+static u_char *
+setipxnodevalue(src,dst)
+u_char *src, *dst;
+{
+ int indx;
+ int item;
+
+ for (;;) {
+ if (!isxdigit (*src))
+ break;
+
+ for (indx = 0; indx < 5; ++indx) {
+ dst[indx] <<= 4;
+ dst[indx] |= (dst[indx + 1] >> 4) & 0x0F;
+ }
+
+ item = toupper (*src) - '0';
+ if (item > 9)
+ item -= 7;
+
+ dst[5] = (dst[5] << 4) | item;
+ ++src;
+ }
+ return src;
+}
+
+static int
+setipxnode(argv)
+ char **argv;
+{
+ char *end;
+
+ memset (&ipxcp_wantoptions[0].our_node[0], 0, 6);
+ memset (&ipxcp_wantoptions[0].his_node[0], 0, 6);
+
+ end = setipxnodevalue (*argv, &ipxcp_wantoptions[0].our_node[0]);
+ if (*end == ':')
+ end = setipxnodevalue (++end, &ipxcp_wantoptions[0].his_node[0]);
+
+ if (*end == '\0') {
+ ipxcp_wantoptions[0].neg_node = 1;
+ return 1;
+ }
+
+ option_error("invalid parameter '%s' for ipx-node option", *argv);
+ return 0;
+}
+
+static int
+setipxproto(argv)
+ char **argv;
+{
+ ipxcp_protent.enabled_flag = 1;
+ return 1;
+}
+
+static int
+resetipxproto(argv)
+ char **argv;
+{
+ ipxcp_protent.enabled_flag = 0;
+ return 1;
+}
+#else
+
+static int
+resetipxproto(argv)
+ char **argv;
+{
+ return 1;
+}
+#endif /* IPX_CHANGE */
+
+#ifdef MSLANMAN
+static int
+setmslanman()
+{
+ ms_lanman = 1;
+ return (1);
}
#endif
diff --git a/usr.sbin/pppd/patchlevel.h b/usr.sbin/pppd/patchlevel.h
index 9ff41ac..37321a6 100644
--- a/usr.sbin/pppd/patchlevel.h
+++ b/usr.sbin/pppd/patchlevel.h
@@ -1,6 +1,6 @@
/* $Id$ */
#define PATCHLEVEL 0
-#define VERSION "2.2"
-#define IMPLEMENTATION "beta3"
-#define DATE "11 July 95"
+#define VERSION "2.3"
+#define IMPLEMENTATION ""
+#define DATE "22 May 97"
diff --git a/usr.sbin/pppd/pathnames.h b/usr.sbin/pppd/pathnames.h
index c06aad8..896fed6 100644
--- a/usr.sbin/pppd/pathnames.h
+++ b/usr.sbin/pppd/pathnames.h
@@ -1,7 +1,7 @@
/*
* define path names
*
- * $Id: pathnames.h,v 1.6 1997/04/15 07:00:34 danny Exp $
+ * $Id$
*/
#ifdef HAVE_PATHS_H
@@ -17,9 +17,16 @@
#define _PATH_SYSOPTIONS "/etc/ppp/options"
#define _PATH_IPUP "/etc/ppp/ip-up"
#define _PATH_IPDOWN "/etc/ppp/ip-down"
+#define _PATH_AUTHUP "/etc/ppp/auth-up"
+#define _PATH_AUTHDOWN "/etc/ppp/auth-down"
#define _PATH_TTYOPT "/etc/ppp/options."
#define _PATH_CONNERRS "/etc/ppp/connect-errors"
#define _PATH_USEROPT ".ppprc"
+#define _PATH_PEERFILES "/etc/ppp/peers/"
#define _PATH_PPPDENY "/etc/ppp/ppp.deny"
#define _PATH_PPPSHELLS "/etc/ppp/ppp.shells"
+#ifdef IPX_CHANGE
+#define _PATH_IPXUP "/etc/ppp/ipx-up"
+#define _PATH_IPXDOWN "/etc/ppp/ipx-down"
+#endif /* IPX_CHANGE */
diff --git a/usr.sbin/pppd/pppd.8 b/usr.sbin/pppd/pppd.8
index 06af499..27ee92d 100644
--- a/usr.sbin/pppd/pppd.8
+++ b/usr.sbin/pppd/pppd.8
@@ -1,5 +1,5 @@
-.\" manual page [] for pppd 2.0
-.\" $Id: pppd.8,v 1.12 1997/04/16 02:07:10 danny Exp $
+.\" manual page [] for pppd 2.3
+.\" $Id$
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
@@ -11,11 +11,11 @@ pppd \- Point to Point Protocol daemon
.SH SYNOPSIS
.B pppd
[
-.I options
-] [
.I tty_name
] [
.I speed
+] [
+.I options
]
.SH DESCRIPTION
.LP
@@ -27,133 +27,126 @@ a family of Network Control Protocols (NCP) for establishing
and configuring different network-layer protocols.
.LP
The encapsulation scheme is provided by driver code in the kernel.
-.B pppd
-provides the basic LCP, authentication support, and an
-NCP for establishing and configuring the Internet Protocol (IP)
-(called the IP Control Protocol, IPCP).
+Pppd provides the basic LCP, authentication support, and an NCP for
+establishing and configuring the Internet Protocol (IP) (called the IP
+Control Protocol, IPCP).
.SH FREQUENTLY USED OPTIONS
.TP
.I <tty_name>
-Communicate over the named device. The string "/dev/"
-is prepended if necessary. If no device name is given,
-or if the name of the controlling terminal is given,
-.I pppd
-will use the controlling terminal, and will not fork to put itself in
-the background.
+Communicate over the named device. The string "/dev/" is prepended if
+necessary. If no device name is given, or if the name of the terminal
+connected to the standard input is given, pppd
+will use that terminal, and will not fork to put itself in the
+background. This option is privileged if the \fInoauth\fR option is
+used.
.TP
.I <speed>
-Set the baud rate to <speed>. On systems such as 4.4BSD and NetBSD,
-any speed can be specified. Other systems (e.g. SunOS) allow only a
-limited set of speeds.
+Set the baud rate to <speed> (a decimal number). On systems such as
+4.4BSD and NetBSD, any speed can be specified. Other systems
+(e.g. SunOS) allow only a limited set of speeds.
+.TP
+.B active-filter \fIfilter-expression
+Specifies a packet filter to be applied to data packets to determine
+which packets are to be regarded as link activity, and therefore reset
+the idle timer, or cause the link to be brought up in demand-dialling
+mode. This option is useful in conjunction with the
+\fBidle\fR option if there are packets being sent or received
+regularly over the link (for example, routing information packets)
+which would otherwise prevent the link from ever appearing to be idle.
+The \fIfilter-expression\fR syntax is as described for tcpdump(1),
+except that qualifiers which are inappropriate for a PPP link, such as
+\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
+expression should be enclosed in single-quotes to prevent whitespace
+in the expression from being interpreted by the shell. This option
+is currently only available under NetBSD, and then only
+if both the kernel and pppd were compiled with PPP_FILTER defined.
.TP
.B asyncmap \fI<map>
-Set the async character map to <map>.
-This map describes which control characters cannot be successfully
-received over the serial line.
-.I pppd
-will ask the peer to send these characters as a 2-byte escape sequence.
-The argument is a 32 bit hex number
-with each bit representing a character to escape.
-Bit 0 (00000001) represents the character 0x00;
-bit 31 (80000000) represents the character 0x1f or ^_.
-If multiple \fBasyncmap\fR options are
-given, the values are ORed together.
-If no \fBasyncmap\fR option is given, no async character map will be
-negotiated for the receive direction; the peer should then escape
-\fIall\fR control characters.
+Set the async character map to <map>. This map describes which
+control characters cannot be successfully received over the serial
+line. Pppd will ask the peer to send these characters as a 2-byte
+escape sequence. The argument is a 32 bit hex number with each bit
+representing a character to escape. Bit 0 (00000001) represents the
+character 0x00; bit 31 (80000000) represents the character 0x1f or ^_.
+If multiple \fIasyncmap\fR options are given, the values are ORed
+together. If no \fIasyncmap\fR option is given, no async character
+map will be negotiated for the receive direction; the peer should then
+escape \fIall\fR control characters. To escape transmitted
+characters, use the \fIescape\fR option.
.TP
.B auth
Require the peer to authenticate itself before allowing network
packets to be sent or received.
.TP
-.B connect \fI<p>
-Use the executable or shell command specified by \fI<p>\fR to set up the
-serial line. This script would typically use the "chat" program to
-dial the modem and start the remote ppp session.
+.B call \fIname
+Read options from the file /etc/ppp/peers/\fIname\fR. This file may
+contain privileged options, such as \fInoauth\fR, even if pppd
+is not being run by root. The \fIname\fR string may not begin with /
+or include .. as a pathname component. The format of the options file
+is described below.
.TP
-.B connect-max-attempts \fI<n>
-Attempt dial-out connection to remote system no more than specified number
-of times (default = 1). If the connection is not made, pppd will exit.
-Requires that \fBpersist\fR has been specified.
+.B connect \fIscript
+Use the executable or shell command specified by \fIscript\fR to set
+up the serial line. This script would typically use the chat(8)
+program to dial the modem and start the remote ppp session. This
+option is privileged if the \fInoauth\fR option is used.
.TP
.B crtscts
-Use hardware flow control (i.e. RTS/CTS) to control the flow of data on
-the serial port.
-.TP
-.B -crtscts
-Disable hardware flow control (i.e. RTS/CTS) on the serial port. If
-neither the \fBcrtscts\fR nor the \fB\-crtscts\fR option is given,
-the hardware flow control setting for the serial port is left
-unchanged.
-.TP
-.B xonxoff
-Use software flow control (i.e. XON/XOFF) to control the flow of data on
-the serial port. This option is only implemented on Linux systems
-at present.
+Use hardware flow control (i.e. RTS/CTS) to control the flow of data
+on the serial port. If neither the \fIcrtscts\fR nor the
+\fInocrtscts\fR option is given, the hardware flow control setting
+for the serial port is left unchanged.
.TP
.B defaultroute
Add a default route to the system routing tables, using the peer as
the gateway, when IPCP negotiation is successfully completed.
-This entry is removed when the PPP connection is broken.
+This entry is removed when the PPP connection is broken. This option
+is privileged if the \fInodefaultroute\fR option has been specified.
.TP
-.B disconnect \fI<p>
-Run the executable or shell command specified by \fI<p>\fR after
-\fIpppd\fR has terminated the link. This script could, for example,
-issue commands to the modem to cause it to hang up if hardware modem
-control signals were not available.
+.B disconnect \fIscript
+Run the executable or shell command specified by \fIscript\fR after
+pppd has terminated the link. This script could, for example, issue
+commands to the modem to cause it to hang up if hardware modem control
+signals were not available. The disconnect script is not run if the
+modem has already hung up. This option is privileged if the
+\fInoauth\fR option is used.
.TP
.B escape \fIxx,yy,...
Specifies that certain characters should be escaped on transmission
(regardless of whether the peer requests them to be escaped with its
async control character map). The characters to be escaped are
specified as a list of hex numbers separated by commas. Note that
-almost any character can be specified for the \fBescape\fR option,
-unlike the \fBasyncmap\fR option which only allows control characters
+almost any character can be specified for the \fIescape\fR option,
+unlike the \fIasyncmap\fR option which only allows control characters
to be specified. The characters which may not be escaped are those
with hex values 0x20 - 0x3f or 0x5e.
.TP
-.B file \fI<f>
-Read options from file <f> (the format is described below).
+.B file \fIname
+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 lock
-Specifies that \fIpppd\fR should use a UUCP-style lock on the serial
-device to ensure exclusive access to the device.
-.TP
-.B mru \fI<n>
-Set the MRU [Maximum Receive Unit] value to <n> for negotiation.
-.I pppd
-will ask the peer to send packets of no more than <n> bytes.
-The minimum MRU value is 128.
-The default MRU value is 1500. A value of 296 is recommended for slow
-links (40 bytes for TCP/IP header + 256 bytes of data).
-.TP
-.B netmask \fI<n>
-Set the interface netmask to <n>, a 32 bit netmask in "decimal dot" notation
-(e.g. 255.255.255.0).
-.TP
-.B dns1 \fI<n>
-If peer asks for primary DNS server, tell them this address,
-a 32 bit ip number in "decimal dot" notation (e.g. 1.2.3.4).
-.TP
-.B dns2 \fI<n>
-If peer asks for secondary DNS server, tell them this address,
-a 32 bit ip number in "decimal dot" notation (e.g. 1.2.3.5).
+Specifies that pppd should create a UUCP-style lock file for the
+serial device to ensure exclusive access to the device.
+.TP
+.B mru \fIn
+Set the MRU [Maximum Receive Unit] value to \fIn\fR. Pppd
+will ask the peer to send packets of no more than \fIn\fR bytes. The
+minimum MRU value is 128. The default MRU value is 1500. A value of
+296 is recommended for slow links (40 bytes for TCP/IP header + 256
+bytes of data).
+.TP
+.B mtu \fIn
+Set the MTU [Maximum Transmit Unit] value to \fIn\fR. Unless the
+peer requests a smaller value via MRU negotiation, pppd will
+request that the kernel networking code send data packets of no more
+than \fIn\fR bytes through the PPP network interface.
.TP
.B passive
-Enables the "passive" option in the LCP. With this option,
-.I pppd
-will attempt to initiate a connection; if no reply is received from
-the peer,
-.I pppd
-will then just wait passively for a valid LCP packet from the peer
-(instead of exiting, as it does without this option).
-.TP
-.B silent
-With this option,
-.I pppd
-will not transmit LCP packets to initiate a connection until a valid
-LCP packet is received from the peer (as for the `passive' option with
-old versions of \fIpppd\fR).
+Enables the "passive" option in the LCP. With this option, pppd will
+attempt to initiate a connection; if no reply is received from the
+peer, pppd will then just wait passively for a valid LCP packet from
+the peer, instead of exiting, as it would without this option.
.SH OPTIONS
.TP
.I <local_IP_address>\fB:\fI<remote_IP_address>
@@ -161,90 +154,14 @@ Set the local and/or remote interface IP addresses. Either one may be
omitted. The IP addresses can be specified with a host name or in
decimal dot notation (e.g. 150.234.56.78). The default local
address is the (first) IP address of the system (unless the
-.B noipdefault
+\fInoipdefault\fR
option is given). The remote address will be obtained from the peer
if not specified in any option. Thus, in simple cases, this option is
-not required.
-If a local and/or remote IP address is specified with this option,
-.I pppd
+not required. If a local and/or remote IP address is specified with
+this option, pppd
will not accept a different value from the peer in the IPCP
-negotiation, unless the
-.B ipcp-accept-local
-and/or
-.B ipcp-accept-remote
-options are given, respectively.
-.TP
-.B -all
-Don't request or allow negotiation of any options for LCP and IPCP (use
-default values).
-.TP
-.B -ac
-Disable Address/Control compression negotiation (use default, i.e.
-address/control field disabled).
-.TP
-.B -am
-Disable asyncmap negotiation (use the default asyncmap, i.e. escape
-all control characters).
-.TP
-.B -as \fI<n>
-Same as
-.B asyncmap \fI<n>
-.TP
-.B -d
-Increase debugging level (same as the \fBdebug\fR option).
-.TP
-.B -detach
-Don't fork to become a background process (otherwise
-.I pppd
-will do so if a serial device is specified and that serial device
-is not the controlling terminal).
-.TP
-.B -ip
-Disable IP address negotiation (with this option, the remote IP
-address must be specified with an option on the command line or in an
-options file).
-.TP
-.B -mn
-Disable magic number negotiation. With this option,
-.I pppd
-cannot detect a looped-back line.
-.TP
-.B -mru
-Disable MRU [Maximum Receive Unit] negotiation (use default, i.e. 1500).
-.TP
-.B -p
-Same as the
-.B passive
-option.
-.TP
-.B -pc
-Disable protocol field compression negotiation (use default, i.e.
-protocol field compression disabled).
-.TP
-.B +ua \fI<p>
-Agree to authenticate using PAP [Password Authentication Protocol] if
-requested by the peer, and
-use the data in file <p> for the user and password to send to the
-peer. The file contains the remote user name, followed by a newline,
-followed by the remote password, followed by a newline. This option
-is obsolescent.
-.TP
-.B +pap
-Require the peer to authenticate itself using PAP.
-.TP
-.B -pap
-Don't agree to authenticate using PAP.
-.TP
-.B +chap
-Require the peer to authenticate itself using CHAP [Challenge
-Handshake Authentication Protocol] authentication.
-.TP
-.B -chap
-Don't agree to authenticate using CHAP.
-.TP
-.B -vj
-Disable negotiation of Van Jacobson style IP header compression (use
-default, i.e. no compression).
+negotiation, unless the \fIipcp-accept-local\fR and/or
+\fIipcp-accept-remote\fR options are given, respectively.
.TP
.B bsdcomp \fInr,nt
Request that the peer compress packets that it sends, using the
@@ -255,109 +172,326 @@ given for \fInr\fR. Values in the range 9 to 15 may be used for
\fInr\fR and \fInt\fR; larger values give better compression but
consume more kernel memory for compression dictionaries.
Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
-compression in the corresponding direction.
+compression in the corresponding direction. Use \fInobsdcomp\fR or
+\fIbsdcomp 0\fR to disable BSD-Compress compression entirely.
+.TP
+.B chap-interval \fIn
+If this option is given, pppd will rechallenge the peer every \fIn\fR
+seconds.
.TP
-.B \-bsdcomp
-Disables compression; \fBpppd\fR will not request or agree to compress
-packets using the BSD-Compress scheme.
+.B chap-max-challenge \fIn
+Set the maximum number of CHAP challenge transmissions to \fIn\fR
+(default 10).
+.TP
+.B chap-restart \fIn
+Set the CHAP restart interval (retransmission timeout for challenges)
+to \fIn\fR seconds (default 3).
.TP
.B debug
-Increase debugging level (same as \fB\-d\fR).
-If this
-option is given, \fIpppd\fR will log the contents of all control
-packets sent or received in a readable form. The packets are logged
-through syslog with facility \fIdaemon\fR and level \fIdebug\fR. This
-information can be directed to a file by setting up /etc/syslog.conf
-appropriately (see syslog.conf(5)).
-.TP
-.B \-defaultroute
-Disable the \fBdefaultroute\fR option. The system administrator who
-wishes to prevent users from creating default routes with \fIpppd\fR
-can do so by placing this option in the /etc/ppp/options file.
+Enables connection debugging facilities.
+If this option is given, pppd will log the contents of all
+control packets sent or received in a readable form. The packets are
+logged through syslog with facility \fIdaemon\fR and level
+\fIdebug\fR. This information can be directed to a file by setting up
+/etc/syslog.conf appropriately (see syslog.conf(5)).
+.TP
+.B default-asyncmap
+Disable asyncmap negotiation, forcing all control characters to be
+escaped for both the transmit and the receive direction.
+.TP
+.B default-mru
+Disable MRU [Maximum Receive Unit] negotiation. With this option,
+pppd will use the default MRU value of 1500 bytes for both the
+transmit and receive direction.
+.TP
+.B deflate \fInr,nt
+Request that the peer compress packets that it sends, using the
+Deflate scheme, with a maximum window size of \fI2**nr\fR bytes, and
+agree to compress packets sent to the peer with a maximum window size
+of \fI2**nt\fR bytes. If \fInt\fR is not specified, it defaults to
+the value given for \fInr\fR. Values in the range 8 to 15 may be used
+for \fInr\fR and \fInt\fR; larger values give better compression but
+consume more kernel memory for compression dictionaries.
+Alternatively, a value of 0 for \fInr\fR or \fInt\fR disables
+compression in the corresponding direction. Use \fInodeflate\fR or
+\fIdeflate 0\fR to disable Deflate compression entirely. (Note: pppd
+requests Deflate compression in preference to BSD-Compress if the peer
+can do either.)
+.TP
+.B demand
+Initiate the link only on demand, i.e. when data traffic is present.
+With this option, the remote IP address must be specified by the user
+on the command line or in an options file. Pppd will initially
+configure the interface and enable it for IP traffic without
+connecting to the peer. When traffic is available, pppd will
+connect to the peer and perform negotiation, authentication, etc.
+When this is completed, pppd will commence passing data packets
+(i.e., IP packets) across the link.
+
+The \fIdemand\fR option implies the \fIpersist\fR option. If this
+behaviour is not desired, use the \fInopersist\fR option after the
+\fIdemand\fR option. The \fIidle\fR and \fIholdoff\fR
+options are also useful in conjuction with the \fIdemand\fR option.
+.TP
+.B domain \fId
+Append the domain name \fId\fR to the local host name for authentication
+purposes. For example, if gethostname() returns the name porsche, but
+the fully qualified domain name is porsche.Quotron.COM, you could
+specify \fIdomain Quotron.COM\fR. Pppd would then use the name
+\fIporsche.Quotron.COM\fR for looking up secrets in the secrets file,
+and as the default name to send to the peer when authenticating itself
+to the peer. This option is privileged.
+.TP
+.B holdoff \fIn
+Specifies how many seconds to wait before re-initiating the link after
+it terminates. This option only has any effect if the \fIpersist\fR
+or \fIdemand\fR option is used. The holdoff period is not applied if
+the link was terminated because it was idle.
+.TP
+.B idle \fIn
+Specifies that pppd should disconnect if the link is idle for \fIn\fR
+seconds. The link is idle when no data packets (i.e. IP packets) are
+being sent or received. Note: it is not advisable to use this option
+with the \fIpersist\fR option without the \fIdemand\fR option.
+If the \fBactive-filter\fR
+option is given, data packets which are rejected by the specified
+activity filter also count as the link being idle.
+.TP
+.B ipcp-accept-local
+With this option, pppd will accept the peer's idea of our local IP
+address, even if the local IP address was specified in an option.
+.TP
+.B ipcp-accept-remote
+With this option, pppd will accept the peer's idea of its (remote) IP
+address, even if the remote IP address was specified in an option.
.TP
-.B domain \fI<d>
-Append the domain name <d> to the local host name for authentication
-purposes. For example, if gethostname() returns the name porsche, but the
-fully qualified domain name is porsche.Quotron.COM, you would use the
-domain option to set the domain name to Quotron.COM.
+.B ipcp-max-configure \fIn
+Set the maximum number of IPCP configure-request transmissions to
+\fIn\fR (default 10).
+.TP
+.B ipcp-max-failure \fIn
+Set the maximum number of IPCP configure-NAKs returned before starting
+to send configure-Rejects instead to \fIn\fR (default 10).
+.TP
+.B ipcp-max-terminate \fIn
+Set the maximum number of IPCP terminate-request transmissions to
+\fIn\fR (default 3).
+.TP
+.B ipcp-restart \fIn
+Set the IPCP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
.TP
.B ipparam \fIstring
Provides an extra parameter to the ip-up and ip-down scripts. If this
option is given, the \fIstring\fR supplied is given as the 6th
parameter to those scripts.
.TP
-.B modem
-Use the modem control lines. This option is the default. With this
-option,
-.B pppd
-will wait for the CD (Carrier Detect) signal from the modem to be asserted
-when opening the serial device
-(unless a connect script is specified), and it will drop the DTR (Data
-Terminal Ready) signal briefly when the connection is terminated and before
-executing the connect script.
-On Ultrix, this option implies hardware
-flow control, as for the \fBcrtscts\fR option.
+.B ipx
+Enable the IPXCP and IPX protocols. This option is presently only
+supported under Linux, and only if your kernel has been configured to
+include IPX support.
+.TP
+.B ipx-network \fIn
+Set the IPX network number in the IPXCP configure request frame to
+\fIn\fR, a hexadecimal number (without a leading 0x). There is no
+valid default. If this option is not specified, the network number is
+obtained from the peer. If the peer does not have the network number,
+the IPX protocol will not be started.
+.TP
+.B ipx-node \fIn\fB:\fIm
+Set the IPX node numbers. The two node numbers are separated from each
+other with a colon character. The first number \fIn\fR is the local
+node number. The second number \fIm\fR is the peer's node number. Each
+node number is a hexadecimal number, at most 10 digits long. The node
+numbers on the ipx-network must be unique. There is no valid
+default. If this option is not specified then the node numbers are
+obtained from the peer.
+.TP
+.B ipx-router-name \fI<string>
+Set the name of the router. This is a string and is sent to the peer
+as information data.
+.TP
+.B ipx-routing \fIn
+Set the routing protocol to be received by this option. More than one
+instance of \fIipx-routing\fR may be specified. The '\fInone\fR'
+option (0) may be specified as the only instance of ipx-routing. The
+values may be \fI0\fR for \fINONE\fR, \fI2\fR for \fIRIP/SAP\fR, and
+\fI4\fR for \fINLSP\fR.
+.TP
+.B ipxcp-accept-local
+Accept the peer's NAK for the node number specified in the ipx-node
+option. If a node number was specified, and non-zero, the default is
+to insist that the value be used. If you include this option then you
+will permit the peer to override the entry of the node number.
+.TP
+.B ipxcp-accept-network
+Accept the peer's NAK for the network number specified in the
+ipx-network option. If a network number was specified, and non-zero, the
+default is to insist that the value be used. If you include this
+option then you will permit the peer to override the entry of the node
+number.
+.TP
+.B ipxcp-accept-remote
+Use the peer's network number specified in the configure request
+frame. If a node number was specified for the peer and this option was
+not specified, the peer will be forced to use the value which you have
+specified.
+.TP
+.B ipxcp-max-configure \fIn
+Set the maximum number of IPXCP configure request frames which the
+system will send to \fIn\fR. The default is 10.
+.TP
+.B ipxcp-max-failure \fIn
+Set the maximum number of IPXCP NAK frames which the local system will
+send before it rejects the options. The default value is 3.
+.TP
+.B ipxcp-max-terminate \fIn
+Set the maximum nuber of IPXCP terminate request frames before the
+local system considers that the peer is not listening to them. The
+default value is 3.
.TP
.B kdebug \fIn
Enable debugging code in the kernel-level PPP driver. The argument
\fIn\fR is a number which is the sum of the following values: 1 to
enable general debug messages, 2 to request that the contents of
received packets be printed, and 4 to request that the contents of
-transmitted packets be printed.
+transmitted packets be printed. On most systems, messages printed by
+the kernel are logged by syslog(1) to a file as directed in the
+/etc/syslog.conf configuration file.
.TP
-.B local
-Don't use the modem control lines. With this option,
-.B 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.
+.B lcp-echo-failure \fIn
+If this option is given, pppd will presume the peer to be dead
+if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
+echo-reply. If this happens, pppd will terminate the
+connection. Use of this option requires a non-zero value for the
+\fIlcp-echo-interval\fR parameter. This option can be used to enable
+pppd to terminate after the physical connection has been broken
+(e.g., the modem has hung up) in situations where no hardware modem
+control lines are available.
.TP
-.B mtu \fI<n>
-Set the MTU [Maximum Transmit Unit] value to \fI<n>\fR. Unless the
-peer requests a smaller value via MRU negotiation, \fIpppd\fR will
-request that the kernel networking code send data packets of no more
-than \fIn\fR bytes through the PPP network interface.
+.B lcp-echo-interval \fIn
+If this option is given, pppd will send an LCP echo-request frame to
+the peer every \fIn\fR seconds. Normally the peer should respond to
+the echo-request by sending an echo-reply. This option can be used
+with the \fIlcp-echo-failure\fR option to detect that the peer is no
+longer connected.
.TP
-.B name \fI<n>
-Set the name of the local system for authentication purposes to <n>.
+.B lcp-max-configure \fIn
+Set the maximum number of LCP configure-request transmissions to
+\fIn\fR (default 10).
.TP
-.B user \fI<u>
-Set the user name to use for authenticating this machine with the peer
-using PAP to <u>.
+.B lcp-max-failure \fIn
+Set the maximum number of LCP configure-NAKs returned before starting
+to send configure-Rejects instead to \fIn\fR (default 10).
.TP
-.B usehostname
-Enforce the use of the hostname as the name of the local system for
-authentication purposes (overrides the
-.B name
-option).
+.B lcp-max-terminate \fIn
+Set the maximum number of LCP terminate-request transmissions to
+\fIn\fR (default 3).
.TP
-.B remotename \fI<n>
-Set the assumed name of the remote system for authentication purposes
-to <n>.
+.B lcp-restart \fIn
+Set the LCP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
.TP
-.B papcrypt
-Indicates that all secrets in the /etc/ppp/pap-secrets file which
-are used for checking the identity of the peer are encrypted, and thus
-pppd should not accept a password which (before encryption) is
-identical to the secret from the /etc/ppp/pap-secrets file.
+.B local
+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 proxyarp
-Add an entry to this system's ARP [Address Resolution Protocol] table
-with the IP address of the peer and the Ethernet address of this
-system.
+.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
+must have an entry in the /etc/ppp/pap-secrets file as well as the
+system password database to be allowed access.
.TP
-.B \-proxyarp
-Disable the \fBproxyarp\fR option. The system administrator who
-wishes to prevent users from creating proxy ARP entries with
-\fIpppd\fR can do so by placing this option in the /etc/ppp/options
-file.
+.B maxconnect \fIn
+Terminate the connection when it has been available for network
+traffic for \fIn\fR seconds (i.e. \fIn\fR seconds after the first
+network control protocol comes up).
.TP
-.B persist
-Do not exit after a connection is terminated; instead try to reopen
-the connection.
+.B modem
+Use the modem control lines. This option is the default. With this
+option, pppd will wait for the CD (Carrier Detect) signal from the
+modem to be asserted when opening the serial device (unless a connect
+script is specified), and it will drop the DTR (Data Terminal Ready)
+signal briefly when the connection is terminated and before executing
+the connect script. On Ultrix, this option implies hardware flow
+control, as for the \fIcrtscts\fR option.
+.TP
+.B ms-dns \fI<addr>
+If pppd is acting as a server for Microsoft Windows clients, this
+option allows pppd to supply one or two DNS (Domain Name Server)
+addresses to the clients. The first instance of this option specifies
+the primary DNS address; the second instance (if given) specifies the
+secondary DNS address. (This option was present in some older
+versions of pppd under the name \fBdns-addr\fR.)
+.TP
+.B ms-wins \fI<addr>
+If pppd is acting as a server for Microsoft Windows or "Samba"
+clients, this option allows pppd to supply one or two WINS (Windows
+Internet Name Services) server addresses to the clients. The first
+instance of this option specifies the primary WINS address; the second
+instance (if given) specifies the secondary WINS address.
+.TP
+.B name \fIname
+Set the name of the local system for authentication purposes to
+\fIname\fR. This is a privileged option. With this option, pppd will
+use lines in the secrets files which have \fIname\fR as the second
+field when looking for a secret to use in authenticating the peer. In
+addition, unless overridden with the \fIuser\fR option, \fIname\fR
+will be used as the name to send to the peer when authenticating the
+local system to the peer. (Note that pppd does not append the domain
+name to \fIname\fR.)
+.TP
+.B netmask \fIn
+Set the interface netmask to \fIn\fR, a 32 bit netmask in "decimal dot"
+notation (e.g. 255.255.255.0). If this option is given, the value
+specified is ORed with the default netmask. The default netmask is
+chosen based on the negotiated remote IP address; it is the
+appropriate network mask for the class of the remote IP address, ORed
+with the netmasks for any non point-to-point network interfaces in the
+system which are on the same network.
+.TP
+.B noaccomp
+Disable Address/Control compression in both directions (send and
+receive).
+.TP
+.B noauth
+Do not require the peer to authenticate itself. This option is
+privileged if the \fIauth\fR option is specified in /etc/ppp/options.
+.TP
+.B nobsdcomp
+Disables BSD-Compress compression; \fBpppd\fR will not request or
+agree to compress packets using the BSD-Compress scheme.
+.TP
+.B noccp
+Disable CCP (Compression Control Protocol) negotiation. This option
+should only be required if the peer is buggy and gets confused by
+requests from pppd for CCP negotiation.
+.TP
+.B nocrtscts
+Disable hardware flow control (i.e. RTS/CTS) on the serial port. If
+neither the \fIcrtscts\fR nor the \fInocrtscts\fR option is given,
+the hardware flow control setting for the serial port is left
+unchanged.
.TP
-.B login
-Use the system password database for authenticating the peer using
-PAP.
+.B nodefaultroute
+Disable the \fIdefaultroute\fR option. The system administrator who
+wishes to prevent users from creating default routes with pppd
+can do so by placing this option in the /etc/ppp/options file.
+.TP
+.B nodeflate
+Disables Deflate compression; pppd will not request or agree to
+compress packets using the Deflate scheme.
+.TP
+.B nodetach
+Don't detach from the controlling terminal. Without this option, if a
+serial device other than the terminal on the standard input is
+specified, pppd will fork to become a background process.
+.TP
+.B noip
+Disable IPCP negotiation and IP communication. This option should
+only be required if the peer is buggy and gets confused by requests
+from pppd for IPCP negotiation.
.TP
.B noipdefault
Disables the default behaviour when no local IP address is specified,
@@ -366,330 +500,482 @@ hostname. With this option, the peer will have to supply the local IP
address during IPCP negotiation (unless it specified explicitly on the
command line or in an options file).
.TP
-.B lcp-echo-interval \fI<n>
-If this option is given, \fIpppd\fR will send an LCP echo-request
-frame to the peer every \fIn\fR seconds. Under Linux, the
-echo-request is sent when no packets have been received from the peer
-for \fIn\fR seconds. Normally the peer should respond to the
-echo-request by sending an echo-reply. This option can be used with
-the \fIlcp-echo-failure\fR option to detect that the peer is no longer
-connected.
-.TP
-.B lcp-echo-failure \fI<n>
-If this option is given, \fIpppd\fR will presume the peer to be dead
-if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
-echo-reply. If this happens, \fIpppd\fR will terminate the
-connection. Use of this option requires a non-zero value for the
-\fIlcp-echo-interval\fR parameter. This option can be used to enable
-\fIpppd\fR to terminate after the physical connection has been broken
-(e.g., the modem has hung up) in situations where no hardware modem
-control lines are available.
-.TP
-.B lcp-restart \fI<n>
-Set the LCP restart interval (retransmission timeout) to <n> seconds
-(default 3).
+.B noipx
+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 lcp-max-terminate \fI<n>
-Set the maximum number of LCP terminate-request transmissions to <n>
-(default 3).
+.B nomagic
+Disable magic number negotiation. With this option, pppd cannot
+detect a looped-back line. This option should only be needed if the
+peer is buggy.
.TP
-.B lcp-max-configure \fI<n>
-Set the maximum number of LCP configure-request transmissions to <n>
-(default 10).
+.B nopcomp
+Disable protocol field compression negotiation in both the receive and
+the transmit direction.
.TP
-.B lcp-max-failure \fI<n>
-Set the maximum number of LCP configure-NAKs returned before starting
-to send configure-Rejects instead to <n> (default 10).
+.B nopersist
+Exit once a connection has been made and terminated. This is the
+default unless the \fIpersist\fR or \fIdemand\fR option has been
+specified.
.TP
-.B ipcp-restart \fI<n>
-Set the IPCP restart interval (retransmission timeout) to <n> seconds
-(default 3).
+.B nopredictor1
+Do not accept or agree to Predictor-1 comprssion.
.TP
-.B ipcp-max-terminate \fI<n>
-Set the maximum number of IPCP terminate-request transmissions to <n>
-(default 3).
+.B noproxyarp
+Disable the \fIproxyarp\fR option. The system administrator who
+wishes to prevent users from creating proxy ARP entries with pppd can
+do so by placing this option in the /etc/ppp/options file.
.TP
-.B ipcp-max-configure \fI<n>
-Set the maximum number of IPCP configure-request transmissions to <n>
-(default 10).
+.B novj
+Disable Van Jacobson style TCP/IP header compression in both the
+transmit and the receive direction.
.TP
-.B ipcp-max-failure \fI<n>
-Set the maximum number of IPCP configure-NAKs returned before starting
-to send configure-Rejects instead to <n> (default 10).
+.B novjccomp
+Disable the connection-ID compression option in Van Jacobson style
+TCP/IP header compression. With this option, pppd will not omit the
+connection-ID byte from Van Jacobson compressed TCP/IP headers, nor
+ask the peer to do so.
.TP
-.B pap-restart \fI<n>
-Set the PAP restart interval (retransmission timeout) to <n> seconds
-(default 3).
+.B papcrypt
+Indicates that all secrets in the /etc/ppp/pap-secrets file which are
+used for checking the identity of the peer are encrypted, and thus
+pppd should not accept a password which, before encryption, is
+identical to the secret from the /etc/ppp/pap-secrets file.
.TP
-.B pap-max-authreq \fI<n>
+.B pap-max-authreq \fIn
Set the maximum number of PAP authenticate-request transmissions to
-<n> (default 10).
+\fIn\fR (default 10).
+.TP
+.B pap-restart \fIn
+Set the PAP restart interval (retransmission timeout) to \fIn\fR
+seconds (default 3).
+.TP
+.B pap-timeout \fIn
+Set the maximum time that pppd will wait for the peer to authenticate
+itself with PAP to \fIn\fR seconds (0 means no limit).
+.TP
+.B pass-filter \fIfilter-expression
+Specifies a packet filter to applied to data packets being sent or
+received to determine which packets should be allowed to pass.
+Packets which are rejected by the filter are silently discarded. This
+option can be used to prevent specific network daemons (such as
+routed) using up link bandwidth, or to provide a basic firewall
+capability.
+The \fIfilter-expression\fR syntax is as described for tcpdump(1),
+except that qualifiers which are inappropriate for a PPP link, such as
+\fBether\fR and \fBarp\fR, are not permitted. Generally the filter
+expression should be enclosed in single-quotes to prevent whitespace
+in the expression from being interpreted by the shell. Note that it
+is possible to apply different constraints to incoming and outgoing
+packets using the \fBinbound\fR and \fBoutbound\fR qualifiers. This
+option is currently only available under NetBSD, and then only if both
+the kernel and pppd were compiled with PPP_FILTER defined.
.TP
-.B pap-timeout \fI<n>
-Set the maximum time that
-.I pppd
-will wait for the peer to authenticate itself with PAP to
-<n> seconds (0 means no limit).
+.B persist
+Do not exit after a connection is terminated; instead try to reopen
+the connection.
.TP
-.B chap-restart \fI<n>
-Set the CHAP restart interval (retransmission timeout for challenges)
-to <n> seconds (default 3).
+.B predictor1
+Request that the peer compress frames that it sends using Predictor-1
+compression, and agree to compress transmitted frames with Predictor-1
+if requested. This option has no effect unless the kernel driver
+supports Predictor-1 compression.
.TP
-.B chap-max-challenge \fI<n>
-Set the maximum number of CHAP challenge transmissions to <n> (default
-10).
+.B proxyarp
+Add an entry to this system's ARP [Address Resolution Protocol] table
+with the IP address of the peer and the Ethernet address of this
+system. This will have the effect of making the peer appear to other
+systems to be on the local ethernet.
.TP
-.B chap-interval \fI<n>
-If this option is given,
-.I pppd
-will rechallenge the peer every <n> seconds.
+.B remotename \fIname
+Set the assumed name of the remote system for authentication purposes
+to \fIname\fR.
.TP
-.B ipcp-accept-local
-With this option,
-.I pppd
-will accept the peer's idea of our local IP address, even if the
-local IP address was specified in an option.
+.B refuse-chap
+With this option, pppd will not agree to authenticate itself to the
+peer using CHAP.
.TP
-.B ipcp-accept-remote
-With this option,
-.I pppd
-will accept the peer's idea of its (remote) IP address, even if the
-remote IP address was specified in an option.
+.B refuse-pap
+With this option, pppd will not agree to authenticate itself to the
+peer using PAP.
+.TP
+.B require-chap
+Require the peer to authenticate itself using CHAP [Challenge
+Handshake Authentication Protocol] authentication.
+.TP
+.B require-pap
+Require the peer to authenticate itself using PAP [Password
+Authentication Protocol] authentication.
+.TP
+.B silent
+With this option, pppd will not transmit LCP packets to initiate a
+connection until a valid LCP packet is received from the peer (as for
+the `passive' option with ancient versions of pppd).
+.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).
+.TP
+.B user \fIname
+Sets the name used for authenticating the local system to the peer to
+\fIname\fR.
+.TP
+.B vj-max-slots \fIn
+Sets the number of connection slots to be used by the Van Jacobson
+TCP/IP header compression and decompression code to \fIn\fR, which
+must be between 2 and 16 (inclusive).
+.TP
+.B welcome \fIscript
+Run the executable or shell command specified by \fIscript\fR before
+initiating PPP negotiation, after the connect script (if any) has
+completed. This option is privileged if the \fInoauth\fR option is
+used.
+.TP
+.B xonxoff
+Use software flow control (i.e. XON/XOFF) to control the flow of data on
+the serial port.
.SH OPTIONS FILES
-Options can be taken from files as well as the command line.
-.I pppd
-reads options from the files /etc/ppp/options and ~/.ppprc before
-looking at the command line. An options file is parsed into a series
-of words, delimited by whitespace. Whitespace can be included in a
-word by enclosing the word in quotes ("). A backslash (\\) quotes the
-following character. A hash (#) starts a comment, which continues
-until the end of the line.
-.SH AUTHENTICATION
+Options can be taken from files as well as the command line. Pppd
+reads options from the files /etc/ppp/options, ~/.ppprc and
+/etc/ppp/options.\fIttyname\fR (in that order) before processing the
+options on the command line. (In fact, the command-line options are
+scanned to find the terminal name before the options.\fIttyname\fR
+file is read.) In forming the name of the options.\fIttyname\fR file,
+the initial /dev/ is removed from the terminal name, and any remaining
+/ characters are replaced with dots.
+.PP
+An options file is parsed into a series of words, delimited by
+whitespace. Whitespace can be included in a word by enclosing the
+word in quotes ("). A backslash (\\) quotes the following character.
+A hash (#) starts a comment, which continues until the end of the
+line. There is no restriction on using the \fIfile\fR or \fIcall\fR
+options within an options file.
+.SH SECURITY
.I pppd
provides system administrators with sufficient access control that PPP
access to a server machine can be provided to legitimate users without
fear of compromising the security of the server or the network it's
on. In part this is provided by the /etc/ppp/options file, where the
-administrator can place options to require authentication whenever
-.I pppd
-is run, and in part by the PAP and CHAP secrets files, where the
+administrator can place options to restrict the ways in which pppd can
+be used, and in part by the PAP and CHAP secrets files, where the
administrator can restrict the set of IP addresses which individual
users may use.
+.PP
+The normal way that pppd should be set up is to have the \fIauth\fR
+option in the /etc/ppp/options file. (This may become the default in
+later releases.) If users wish to use pppd to dial out to a peer
+which will refuse to authenticate itself (such as an internet service
+provider), the system administrator should create an options file
+under /etc/ppp/peers containing the \fInoauth\fR option, the name of
+the serial port to use, and the \fIconnect\fR option (if required),
+plus any other appropriate options. In this way, pppd can be set up
+to allow non-privileged users to make unauthenticated connections only
+to trusted peers.
+.PP
+As indicated above, some security-sensitive options are privileged,
+which means that they may not be used by an ordinary non-privileged
+user running a setuid-root pppd, either on the command line, in the
+user's ~/.ppprc file, or in an options file read using the \fIfile\fR
+option. Privileged options may be used in /etc/ppp/options file or in
+an options file read using the \fIcall\fR option. If pppd is being
+run by the root user, privileged options can be used without
+restriction.
+.SH AUTHENTICATION
+Authentication is the process whereby one peer convinces the other of
+its identity. This involves the first peer sending its name to the
+other, together with some kind of secret information which could only
+come from the genuine authorized user of that name. In such an
+exchange, we will call the first peer the "client" and the other the
+"server". The client has a name by which it identifies itself to the
+server, and the server also has a name by which it identifies itself
+to the client. Generally the genuine client shares some secret (or
+password) with the server, and authenticates itself by proving that it
+knows that secret. Very often, the names used for authentication
+correspond to the internet hostnames of the peers, but this is not
+essential.
.LP
-The default behaviour of
-.I pppd
-is to agree to authenticate if requested, and to not
-require authentication from the peer. However,
-.I pppd
-will not agree to
-authenticate itself with a particular protocol if it has no secrets
-which could be used to do so.
+At present, pppd supports two authentication protocols: the Password
+Authentication Protocol (PAP) and the Challenge Handshake
+Authentication Protocol (CHAP). PAP involves the client sending its
+name and a cleartext password to the server to authenticate itself.
+In contrast, the server initiates the CHAP authentication exchange by
+sending a challenge to the client (the challenge packet includes the
+server's name). The client must respond with a response which
+includes its name plus a hash value derived from the shared secret and
+the challenge, in order to prove that it knows the secret.
+.LP
+The PPP protocol, being symmetrical, allows both peers to require the
+other to authenticate itself. In that case, two separate and
+independent authentication exchanges will occur. The two exchanges
+could use different authentication protocols, and in principle,
+different names could be used in the two exchanges.
+.LP
+The default behaviour of pppd is to agree to authenticate if
+requested, and to not require authentication from the peer. However,
+pppd will not agree to authenticate itself with a particular protocol
+if it has no secrets which could be used to do so.
.LP
-Authentication is based on secrets, which are selected from secrets
+Pppd stores secrets for use in authentication in secrets
files (/etc/ppp/pap-secrets for PAP, /etc/ppp/chap-secrets for CHAP).
-Both secrets files have the same format, and both can store secrets
-for several combinations of server (authenticating peer) and client
-(peer being authenticated). Note that
-.I pppd
-can be both a server
-and client, and that different protocols can be used in the two
-directions if desired.
-.LP
-A secrets file is parsed into words as for a options file. A secret
-is specified by a line containing at least 3 words, in the order
-client name, server name, secret. Any following words on the same line are
-taken to be a list of acceptable IP addresses for that client, or an
-override for "local:remote" addresses (the same format used on the
-command line or in the options file) when on a line that contains a
-specific client name (not a wildcard nor empty).
-If there are only 3 words on the line, it is assumed that any IP address
-is OK; to disallow all IP addresses, use "-". If the secret starts
-with an `@', what follows is assumed to be the name of a file from
-which to read the secret. A "*" as the client or server name matches
-any name. When selecting a secret, \fIpppd\fR takes the best match, i.e.
-the match with the fewest wildcards.
+Both secrets files have the same format. The secrets files can
+contain secrets for pppd to use in authenticating itself to other
+systems, as well as secrets for pppd to use when authenticating other
+systems to itself.
+.LP
+Each line in a secrets file contains one secret. A given secret is
+specific to a particular combination of client and server - it can
+only be used by that client to authenticate itself to that server.
+Thus each line in a secrets file has at least 3 fields: the name of
+the client, the name of the server, and the secret. These fields may
+be followed by a list of the IP addresses that the specified client
+may use when connecting to the specified server.
+.LP
+A secrets file is parsed into words as for a options file, so the
+client name, server name and secrets fields must each be one word,
+with any embedded spaces or other special characters quoted or
+escaped. Any following words on the same line are taken to be a list
+of acceptable IP addresses for that client. If there are only 3 words
+on the line, or if the first word is "-", then all IP addresses are
+disallowed. To allow any address, use "*".
+A word starting with "!" indicates that the
+specified address is \fInot\fR acceptable. An address may be followed
+by "/" and a number \fIn\fR, to indicate a whole subnet, i.e. all
+addresses which have the same value in the most significant \fIn\fR
+bits. Note that case is significant in the client and server names
+and in the secret.
+.LP
+If the secret starts with an `@', what follows is assumed to be the
+name of a file from which to read the secret. A "*" as the client or
+server name matches any name. When selecting a secret, pppd takes the
+best match, i.e. the match with the fewest wildcards.
.LP
Thus a secrets file contains both secrets for use in authenticating
other hosts, plus secrets which we use for authenticating ourselves to
-others. Which secret to use is chosen based on the names of the host
-(the `local name') and its peer (the `remote name'). The local name
-is set as follows:
-.TP 3
-if the \fBusehostname\fR option is given,
-then the local name is the hostname of this machine
-(with the domain appended, if given)
-.TP 3
-else if the \fBname\fR option is given,
-then use the argument of the first \fBname\fR option seen
-.TP 3
-else if the local IP address is specified with a hostname,
-then use that name
-.TP 3
-else use the hostname of this machine (with the domain appended, if given)
-.LP
-When authenticating ourselves using PAP, there is also a `username'
-which is the local name by default, but can be set with the \fBuser\fR
-option or the \fB+ua\fR option.
-.LP
-The remote name is set as follows:
-.TP 3
-if the \fBremotename\fR option is given,
-then use the argument of the last \fBremotename\fR option seen
-.TP 3
-else if the remote IP address is specified with a hostname,
-then use that host name
-.TP 3
-else the remote name is the null string "".
-.LP
-Secrets are selected from the PAP secrets file as follows:
-.TP 2
-*
-For authenticating the peer, look for a secret with client ==
-username specified in the PAP authenticate-request, and server ==
-local name.
-.TP 2
-*
-For authenticating ourselves to the peer, look for a secret with
-client == our username, server == remote name.
-.LP
-When authenticating the peer with PAP, a secret of "" matches any
-password supplied by the peer. If the password doesn't match the
-secret, the password is encrypted using crypt() and checked against
-the secret again; thus secrets for authenticating the peer can be
-stored in encrypted form. If the \fBpapcrypt\fR option is given, the
-first (unencrypted) comparison is omitted, for better security.
-.LP
-If the \fBlogin\fR option was specified, the
-username and password are also checked against the system password
-database. Thus, the system administrator can set up the pap-secrets
-file to allow PPP access only to certain users, and to restrict the
-set of IP addresses that each user can use. Typically, when using the
-\fBlogin\fR option, the secret in /etc/ppp/pap-secrets would be "", to
-avoid the need to have the same secret in two places.
+others. When pppd is authenticating the peer (checking the peer's
+identity), it chooses a secret with the peer's name in the first
+field and the name of the local system in the second field. The
+name of the local system defaults to the hostname, with the domain
+name appended if the \fIdomain\fR option is used. This default can be
+overridden with the \fIname\fR option, except when the
+\fIusehostname\fR option is used.
+.LP
+When pppd is choosing a secret to use in authenticating itself to the
+peer, it first determines what name it is going to use to identify
+itself to the peer. This name can be specified by the user with the
+\fIuser\fR option. If this option is not used, the name defaults to
+the name of the local system, determined as described in the previous
+paragraph. Then pppd looks for a secret with this name in the first
+field and the peer's name in the second field. Pppd will know the
+name of the peer if CHAP authentication is being used, because the
+peer will have sent it in the challenge packet. However, if PAP is being
+used, pppd will have to determine the peer's name from the options
+specified by the user. The user can specify the peer's name directly
+with the \fIremotename\fR option. Otherwise, if the remote IP address
+was specified by a name (rather than in numeric form), that name will
+be used as the peer's name. Failing that, pppd will use the null
+string as the peer's name.
+.LP
+When authenticating the peer with PAP, the supplied password is first
+compared with the secret from the secrets file. If the password
+doesn't match the secret, the password is encrypted using crypt() and
+checked against the secret again. Thus secrets for authenticating the
+peer can be stored in encrypted form if desired. If the
+\fIpapcrypt\fR option is given, the first (unencrypted) comparison is
+omitted, for better security.
+.LP
+Furthermore, if the \fIlogin\fR option was specified, the username and
+password are also checked against the system password database. Thus,
+the system administrator can set up the pap-secrets file to allow PPP
+access only to certain users, and to restrict the set of IP addresses
+that each user can use. Typically, when using the \fIlogin\fR option,
+the secret in /etc/ppp/pap-secrets would be "", which will match any
+password supplied by the peer. This avoids the need to have the same
+secret in two places.
.LP
Additional checks are performed when the \fBlogin\fR option is used.
If the file /etc/ppp/ppp.deny exists, and the user is listed in it,
the authentication fails. If the file /etc/ppp/ppp.shells exists and
the user's normal login shell is not listed, the authentication fails.
.LP
-Secrets are selected from the CHAP secrets file as follows:
-.TP 2
-*
-For authenticating the peer, look for a secret with client == name
-specified in the CHAP-Response message, and server == local name.
-.TP 2
-*
-For authenticating ourselves to the peer, look for a secret with
-client == local name, and server == name specified in the
-CHAP-Challenge message.
-.LP
Authentication must be satisfactorily completed before IPCP (or any
-other Network Control Protocol) can be started. If authentication
-fails, \fIpppd\fR will terminated the link (by closing LCP). If IPCP
-negotiates an unacceptable IP address for the remote host, IPCP will
-be closed. IP packets can only be sent or received when IPCP is open.
+other Network Control Protocol) can be started. If the peer is
+required to authenticate itself, and fails to do so, pppd will
+terminated the link (by closing LCP). If IPCP negotiates an
+unacceptable IP address for the remote host, IPCP will be closed. IP
+packets can only be sent or received when IPCP is open.
.LP
In some cases it is desirable to allow some hosts which can't
authenticate themselves to connect and use one of a restricted set of
IP addresses, even when the local host generally requires
authentication. If the peer refuses to authenticate itself when
-requested, \fIpppd\fR takes that as equivalent to authenticating with
-PAP using the empty string for the username and password. Thus, by
-adding a line to the pap-secrets file which specifies the empty string
-for the client and password, it is possible to allow restricted access
-to hosts which refuse to authenticate themselves.
+requested, pppd takes that as equivalent to authenticating with PAP
+using the empty string for the username and password. Thus, by adding
+a line to the pap-secrets file which specifies the empty string for
+the client and password, it is possible to allow restricted access to
+hosts which refuse to authenticate themselves.
.SH ROUTING
.LP
-When IPCP negotiation is completed successfully,
-.I pppd
-will inform the kernel of the local and remote IP addresses for the
-ppp interface. This is sufficient to create a
-host route to the remote end of the link, which will enable the peers
-to exchange IP packets. Communication with other machines generally
-requires further modification to routing tables and/or ARP (Address
-Resolution Protocol) tables. In some cases this will be done
-automatically through the actions of the \fIrouted\fR or \fIgated\fR
-daemons, but in most cases some further intervention is required.
-.LP
-Sometimes it is desirable
-to add a default route through the remote host, as in the case of a
-machine whose only connection to the Internet is through the ppp
-interface. The \fBdefaultroute\fR option causes \fIpppd\fR to create such a
-default route when IPCP comes up, and delete it when the link is
-terminated.
+When IPCP negotiation is completed successfully, pppd will inform the
+kernel of the local and remote IP addresses for the ppp interface.
+This is sufficient to create a host route to the remote end of the
+link, which will enable the peers to exchange IP packets.
+Communication with other machines generally requires further
+modification to routing tables and/or ARP (Address Resolution
+Protocol) tables. In most cases the \fIdefaultroute\fR and/or
+\fIproxyarp\fR options are sufficient for this, but in some cases
+further intervention is required. The /etc/ppp/ip-up script can be
+used for this.
+.LP
+Sometimes it is desirable to add a default route through the remote
+host, as in the case of a machine whose only connection to the
+Internet is through the ppp interface. The \fIdefaultroute\fR option
+causes pppd to create such a default route when IPCP comes up, and
+delete it when the link is terminated.
.LP
In some cases it is desirable to use proxy ARP, for example on a
server machine connected to a LAN, in order to allow other hosts to
-communicate with the remote host. The \fBproxyarp\fR option causes \fIpppd\fR
-to look for a network interface on the same subnet as the remote host
-(an interface supporting broadcast and ARP, which is up and not a
-point-to-point or loopback interface). If found, \fIpppd\fR creates a
+communicate with the remote host. The \fIproxyarp\fR option causes
+pppd to look for a network interface on the same subnet as the remote
+host (an interface supporting broadcast and ARP, which is up and not a
+point-to-point or loopback interface). If found, pppd creates a
permanent, published ARP entry with the IP address of the remote host
and the hardware address of the network interface found.
+.LP
+When the \fIdemand\fR option is used, the interface IP addresses have
+already been set at the point when IPCP comes up. If pppd has not
+been able to negotiate the same addresses that it used to configure
+the interface (for example when the peer is an ISP that uses dynamic
+IP address assignment), pppd has to change the interface IP addresses
+to the negotiated addresses. This may disrupt existing connections,
+and the use of demand dialling with peers that do dynamic IP address
+assignment is not recommended.
.SH EXAMPLES
.LP
-In the simplest case, you can connect the serial ports of two machines
-and issue a command like
+The following examples assume that the /etc/ppp/options file contains
+the \fIauth\fR option (as in the default /etc/ppp/options file in the
+ppp distribution).
+.LP
+Probably the most common use of pppd is to dial out to an ISP. This
+can be done with a command such as
.IP
-pppd /dev/ttya 9600 passive
+pppd call isp
.LP
-to each machine, assuming there is no \fIgetty\fR running on the
-serial ports. If one machine has a \fIgetty\fR running, you can use
-\fIkermit\fR or \fItip\fR on the other machine to log in to the first
-machine and issue a command like
+where the /etc/ppp/peers/isp file is set up by the system
+administrator to contain something like this:
.IP
-pppd passive
+ttyS0 19200 crtscts
+.br
+connect '/usr/sbin/chat -v -f /etc/ppp/chat-isp'
+.br
+noauth
.LP
-Then exit from the communications program (making sure the connection
-isn't dropped), and issue a command like
+In this example, we are using chat to dial the ISP's modem and go
+through any logon sequence required. The /etc/ppp/chat-isp file
+contains the script used by chat; it could for example contain
+something like this:
.IP
-pppd /dev/ttya 9600
+ABORT "NO CARRIER"
+.br
+ABORT "NO DIALTONE"
+.br
+ABORT "ERROR"
+.br
+ABORT "NO ANSWER"
+.br
+ABORT "BUSY"
+.br
+ABORT "Username/Password Incorrect"
+.br
+"" "at"
+.br
+OK "at&d0&c1"
+.br
+OK "atdt2468135"
+.br
+"name:" "^Umyuserid"
+.br
+"word:" "\\qmypassword"
+.br
+"ispts" "\\q^Uppp"
+.br
+"~-^Uppp-~"
.LP
-The process of logging in to the other machine and starting \fIpppd\fR
-can be automated by using the \fBconnect\fR option to run \fIchat\fR,
-for example:
+See the chat(8) man page for details of chat scripts.
+.LP
+Pppd can also be used to provide a dial-in ppp service for users. If
+the users already have login accounts, the simplest way to set up the
+ppp service is to let the users log in to their accounts and run pppd
+(installed setuid-root) with a command such as
+.IP
+pppd proxyarp
+.LP
+To allow a user to use the PPP facilities, you need to allocate an IP
+address for that user's machine and create an entry in
+/etc/ppp/pap-secrets or /etc/ppp/chap-secrets (depending on which
+authentication method the PPP implementation on the user's machine
+supports), so that the user's
+machine can authenticate itself. For example, if Joe has a machine
+called "joespc" which is to be allowed to dial in to the machine
+called "server" and use the IP address joespc.my.net, you would add an
+entry like this to /etc/ppp/pap-secrets or /etc/ppp/chap-secrets:
.IP
-pppd /dev/ttya 38400 connect 'chat "" "" "login:" "username"
-"Password:" "password" "% " "exec pppd passive"'
+joespc server "joe's secret" joespc.my.net
.LP
-(Note however that running chat like this will leave the password
-visible in the parameter list of pppd and chat.)
+Alternatively, you can create a username called (for example) "ppp",
+whose login shell is pppd and whose home directory is /etc/ppp.
+Options to be used when pppd is run this way can be put in
+/etc/ppp/.ppprc.
.LP
If your serial connection is any more complicated than a piece of
wire, you may need to arrange for some control characters to be
escaped. In particular, it is often useful to escape XON (^Q) and
-XOFF (^S), using \fBasyncmap a0000\fR. If the path includes a telnet,
-you probably should escape ^] as well (\fBasyncmap 200a0000\fR).
-If the path includes an rlogin, you will need to use the \fBescape
-ff\fR option on the end which is running the rlogin client, since many
-rlogin implementations are not
-transparent; they will remove the sequence [0xff, 0xff, 0x73, 0x73,
-followed by any 8 bytes] from the stream.
+XOFF (^S), using \fIasyncmap a0000\fR. If the path includes a telnet,
+you probably should escape ^] as well (\fIasyncmap 200a0000\fR). If
+the path includes an rlogin, you will need to use the \fIescape ff\fR
+option on the end which is running the rlogin client, since many
+rlogin implementations are not transparent; they will remove the
+sequence [0xff, 0xff, 0x73, 0x73, followed by any 8 bytes] from the
+stream.
.SH DIAGNOSTICS
.LP
Messages are sent to the syslog daemon using facility LOG_DAEMON.
-(This can be overriden by recompiling \fIpppd\fR with the macro
+(This can be overriden by recompiling pppd with the macro
LOG_PPP defined as the desired facility.) In order to see the error
and debug messages, you will need to edit your /etc/syslog.conf file
to direct the messages to the desired output device or file.
.LP
-The \fBdebug\fR option causes the contents of all control packets sent
+The \fIdebug\fR option causes the contents of all control packets sent
or received to be logged, that is, all LCP, PAP, CHAP or IPCP packets.
-This can be useful if the PPP negotiation does not succeed.
-If debugging is enabled at compile time, the \fBdebug\fR option also
+This can be useful if the PPP negotiation does not succeed or if
+authentication fails.
+If debugging is enabled at compile time, the \fIdebug\fR option also
causes other debugging messages to be logged.
.LP
-Debugging can also be enabled or disabled by sending a
-SIGUSR1 to the
-.I pppd
-process. This signal acts as a toggle.
+Debugging can also be enabled or disabled by sending a SIGUSR1 signal
+to the pppd process. This signal acts as a toggle.
.SH FILES
.TP
.B /var/run/ppp\fIn\fB.pid \fR(BSD or Linux), \fB/etc/ppp/ppp\fIn\fB.pid \fR(others)
-Process-ID for \fIpppd\fR process on ppp interface unit \fIn\fR.
+Process-ID for pppd process on ppp interface unit \fIn\fR.
+.TP
+.B /etc/ppp/auth-up
+A program or script which is executed after the remote system
+successfully authenticates itself. It is executed with the parameters
+.IP
+\fIinterface-name peer-name user-name tty-device speed\fR
+.IP
+and with its standard input, output and error redirected to
+/dev/null. This program or script is executed with the real and
+effective user-IDs set to root, and with an empty environment. (Note
+that this script is not executed if the peer doesn't authenticate
+itself, for example when the \fInoauth\fR option is used.)
.TP
-.B /var/run/tty\fIXn\fB.if \fR(BSD or Linux), \fB/etc/ppp/tty\fIXn\fB.if \fR(others)
-Interface for \fIpppd\fR process on serial device /dev/tty\fIXn\fR.
+.B /etc/ppp/auth-down
+A program or script which is executed when the link goes down, if
+/etc/ppp/auth-up was previously executed. It is executed in the same
+manner with the same parameters as /etc/ppp/auth-up.
.TP
.B /etc/ppp/ip-up
A program or script which is executed when the link is available for
@@ -697,44 +983,97 @@ sending and receiving IP packets (that is, IPCP has come up). It is
executed with the parameters
.IP
\fIinterface-name tty-device speed local-IP-address
-remote-IP-address\fR
+remote-IP-address ipparam\fR
.IP
and with its standard input,
-output and error streams redirected to \fB/dev/null\fR.
+output and error streams redirected to /dev/null.
+.IP
+This program or script is executed with the real and effective
+user-IDs set to root. This is so that it can be used to manipulate
+routes, run privileged daemons (e.g. \fIsendmail\fR), etc. Be
+careful that the contents of the /etc/ppp/ip-up and /etc/ppp/ip-down
+scripts do not compromise your system's security.
.IP
-This program or script is executed with the same real and effective
-user-ID as \fIpppd\fR, that is, at least the effective user-ID and
-possibly the real user-ID will be \fBroot\fR. This is so that it can
-be used to manipulate routes, run privileged daemons (e.g.
-\fBsendmail\fR), etc. Be careful that the contents of the
-/etc/ppp/ip-up and /etc/ppp/ip-down scripts do not compromise your
-system's security.
+This program or script is executed with an empty environment, so you
+must either specify a PATH or use full pathnames.
.TP
.B /etc/ppp/ip-down
A program or script which is executed when the link is no longer
available for sending and receiving IP packets. This script can be
used for undoing the effects of the /etc/ppp/ip-up script. It is
-invoked with the same parameters as the ip-up script, and the same
-security considerations apply, since it is executed with the same
-effective and real user-IDs as \fIpppd\fR.
+invoked in the same manner and with the same parameters as the ip-up
+script, and the same security considerations apply.
+.TP
+.B /etc/ppp/ipx-up
+A program or script which is executed when the link is available for
+sending and receiving IPX packets (that is, IPXCP has come up). It is
+executed with the parameters
+.IP
+\fIinterface-name tty-device speed network-number local-IPX-node-address
+remote-IPX-node-address local-IPX-routing-protocol remote-IPX-routing-protocol
+local-IPX-router-name remote-IPX-router-name ipparam pppd-pid\fR
+.IP
+and with its standard input,
+output and error streams redirected to /dev/null.
+.br
+.IP
+The local-IPX-routing-protocol and remote-IPX-routing-protocol field
+may be one of the following:
+.IP
+NONE to indicate that there is no routing protocol
+.br
+RIP to indicate that RIP/SAP should be used
+.br
+NLSP to indicate that Novell NLSP should be used
+.br
+RIP NLSP to indicate that both RIP/SAP and NLSP should be used
+.br
+.IP
+This program or script is executed with the real and effective
+user-IDs set to root, and with an empty environment. This is so
+that it can be used to manipulate routes, run privileged daemons (e.g.
+\fIripd\fR), etc. Be careful that the contents of the /etc/ppp/ipx-up
+and /etc/ppp/ipx-down scripts do not compromise your system's
+security.
+.TP
+.B /etc/ppp/ipx-down
+A program or script which is executed when the link is no longer
+available for sending and receiving IPX packets. This script can be
+used for undoing the effects of the /etc/ppp/ipx-up script. It is
+invoked in the same manner and with the same parameters as the ipx-up
+script, and the same security considerations apply.
.TP
.B /etc/ppp/pap-secrets
-Usernames, passwords and IP addresses for PAP authentication.
+Usernames, passwords and IP addresses for PAP authentication. This
+file should be owned by root and not readable or writable by any other
+user. Pppd will log a warning if this is not the case.
.TP
.B /etc/ppp/chap-secrets
-Names, secrets and IP addresses for CHAP authentication.
+Names, secrets and IP addresses for CHAP authentication. As for
+/etc/ppp/pap-secrets, this file should be owned by root and not
+readable or writable by any other user. Pppd will log a warning if
+this is not the case.
.TP
.B /etc/ppp/options
-System default options for
-.I pppd,
-read before user default options or command-line options.
+System default options for pppd, read before user default options or
+command-line options.
.TP
.B ~/.ppprc
-User default options, read before command-line options.
+User default options, read before /etc/ppp/options.\fIttyname\fR.
.TP
.B /etc/ppp/options.\fIttyname
System default options for the serial port being used, read after
-command-line options.
+~/.ppprc. In forming the \fIttyname\fR part of this
+filename, an initial /dev/ is stripped from the port name (if
+present), and any slashes in the remaining part are converted to
+dots.
+.TP
+.B /etc/ppp/peers
+A directory containing options files which may contain privileged
+options, even if pppd was invoked by a user other than root. The
+system administrator can create options files in this directory to
+permit non-privileged users to dial out without requiring the peer to
+authenticate, but only to certain trusted peers.
.TP
.B /etc/ppp/ppp.deny
Lists users who may not use the system password PAP authentication.
@@ -748,62 +1087,62 @@ logins.
.TP
.B RFC1144
Jacobson, V.
-.I Compressing TCP/IP headers for low-speed serial links.
-1990 February.
+\fICompressing TCP/IP headers for low-speed serial links.\fR
+February 1990.
.TP
.B RFC1321
Rivest, R.
.I The MD5 Message-Digest Algorithm.
-1992 April.
+April 1992.
.TP
.B RFC1332
McGregor, G.
.I PPP Internet Protocol Control Protocol (IPCP).
-1992 May.
+May 1992.
.TP
.B RFC1334
Lloyd, B.; Simpson, W.A.
.I PPP authentication protocols.
-1992 October.
+October 1992.
.TP
-.B RFC1548
+.B RFC1661
Simpson, W.A.
.I The Point\-to\-Point Protocol (PPP).
-1993 December.
+July 1994.
.TP
-.B RFC1549
+.B RFC1662
Simpson, W.A.
-.I PPP in HDLC Framing.
-1993 December
+.I PPP in HDLC-like Framing.
+July 1994.
.SH NOTES
-The following signals have the specified effect when sent to the
-.I pppd
-process.
+The following signals have the specified effect when sent to pppd.
.TP
.B SIGINT, SIGTERM
-These signals cause \fBpppd\fR to terminate the link (by closing LCP),
+These signals cause pppd to terminate the link (by closing LCP),
restore the serial device settings, and exit.
.TP
.B SIGHUP
-This signal causes \fBpppd\fR to terminate the link, restore the
-serial device settings, and close the serial device. If the
-\fBpersist\fR option has been specified, \fBpppd\fR will try to reopen
-the serial device and start another connection. Otherwise \fBpppd\fR
-will exit.
+This signal causes pppd to terminate the link, restore the serial
+device settings, and close the serial device. If the \fIpersist\fR or
+\fIdemand\fR option has been specified, pppd will try to reopen the
+serial device and start another connection (after the holdoff period).
+Otherwise pppd will exit. If this signal is received during the
+holdoff period, it causes pppd to end the holdoff period immediately.
+.TP
+.B SIGUSR1
+This signal toggles the state of the \fIdebug\fR option.
.TP
.B SIGUSR2
-This signal causes
-.B pppd
-to renegotiate compression. This can be useful to re-enable
-compression after it has been disabled as a result of a fatal
-decompression error. With the BSD Compress scheme, fatal
-decompression errors generally indicate a bug in one or other
-implementation.
+This signal causes pppd to renegotiate compression. This can be
+useful to re-enable compression after it has been disabled as a result
+of a fatal decompression error. (Fatal decompression errors generally
+indicate a bug in one or other implementation.)
.SH AUTHORS
+Paul Mackerras (Paul.Mackerras@cs.anu.edu.au), based on earlier work by
Drew Perkins,
Brad Clements,
Karl Fox,
Greg Christy,
-Brad Parker,
-Paul Mackerras (paulus@cs.anu.edu.au).
+and
+Brad Parker.
diff --git a/usr.sbin/pppd/pppd.h b/usr.sbin/pppd/pppd.h
index d9c1f63..236b400 100644
--- a/usr.sbin/pppd/pppd.h
+++ b/usr.sbin/pppd/pppd.h
@@ -26,16 +26,26 @@
#ifndef __PPPD_H__
#define __PPPD_H__
+#include <stdio.h> /* for FILE */
#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
#include <sys/types.h> /* for u_int32_t, if defined */
+#include <sys/time.h> /* for struct timeval */
#include <net/ppp_defs.h>
-#define NUM_PPP 1 /* One PPP interface supported (per process) */
+#if __STDC__
+#include <stdarg.h>
+#define __V(x) x
+#else
+#include <varargs.h>
+#define __V(x) (va_alist) va_dcl
+#define const
+#endif
/*
* Limits.
*/
+#define NUM_PPP 1 /* One PPP interface supported (per process) */
#define MAXWORDLEN 1024 /* max length of word in file (incl null) */
#define MAXARGS 1 /* max # args to a command */
#define MAXNAMELEN 256 /* max length of hostname or name for auth */
@@ -48,12 +58,16 @@
extern int hungup; /* Physical layer has disconnected */
extern int ifunit; /* Interface unit number */
extern char ifname[]; /* Interface name */
-extern int fd; /* Serial device file descriptor */
+extern int ttyfd; /* Serial device file descriptor */
extern char hostname[]; /* Our hostname */
extern u_char outpacket_buf[]; /* Buffer for outgoing packets */
extern int phase; /* Current state of link - see values below */
extern int baud_rate; /* Current link speed in bits/sec */
extern char *progname; /* Name of this program */
+extern int redirect_stderr;/* Connector's stderr should go to file */
+extern char peer_authname[];/* Authenticated name of peer */
+extern int privileged; /* We were run by real-uid root */
+extern int need_holdoff; /* Need holdoff period after link terminates */
/*
* Variables set by command-line options.
@@ -67,14 +81,13 @@ extern int crtscts; /* Use hardware flow control */
extern int modem; /* Use modem control lines */
extern int inspeed; /* Input/Output speed requested */
extern u_int32_t netmask; /* IP netmask to set on interface */
-extern u_int32_t dns1; /* Primary DNS server */
-extern u_int32_t dns2; /* Secondary DNS server */
extern int lockflag; /* Create lock file to lock the serial dev */
extern int nodetach; /* Don't detach from controlling tty */
extern char *connector; /* Script to establish physical link */
extern char *disconnector; /* Script to disestablish physical link */
-extern int max_con_attempts;/* Maximum number of time to try dialing */
-extern char user[]; /* Username for PAP */
+extern char *welcomer; /* Script to welcome client after connection */
+extern int maxconnect; /* Maximum connect time (seconds) */
+extern char user[]; /* Our name for authenticating ourselves */
extern char passwd[]; /* Password for PAP */
extern int auth_required; /* Peer is required to authenticate */
extern int proxyarp; /* Set up proxy ARP entry for peer */
@@ -84,38 +97,239 @@ extern int lcp_echo_interval; /* Interval between LCP echo-requests */
extern int lcp_echo_fails; /* Tolerance to unanswered echo-requests */
extern char our_name[]; /* Our name for authentication purposes */
extern char remote_name[]; /* Peer's name for authentication */
+extern int explicit_remote;/* remote_name specified with remotename opt */
extern int usehostname; /* Use hostname for our_name */
extern int disable_defaultip; /* Don't use hostname for default IP adrs */
+extern int demand; /* Do dial-on-demand */
extern char *ipparam; /* Extra parameter for ip up/down scripts */
extern int cryptpap; /* Others' PAP passwords are encrypted */
+extern int idle_time_limit;/* Shut down link if idle for this long */
+extern int holdoff; /* Dead time before restarting */
+extern int refuse_pap; /* Don't wanna auth. ourselves with PAP */
+extern int refuse_chap; /* Don't wanna auth. ourselves with CHAP */
+#ifdef PPP_FILTER
+extern struct bpf_program pass_filter; /* Filter for pkts to pass */
+extern struct bpf_program active_filter; /* Filter for link-active pkts */
+#endif
+
+
+#ifdef MSLANMAN
+extern int ms_lanman; /* Nonzero if use LanMan password instead of NT */
+ /* Has meaning only with MS-CHAP challenges */
+#endif
/*
* Values for phase.
*/
#define PHASE_DEAD 0
-#define PHASE_ESTABLISH 1
-#define PHASE_AUTHENTICATE 2
-#define PHASE_NETWORK 3
-#define PHASE_TERMINATE 4
+#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
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+ u_short protocol; /* PPP protocol number */
+ /* Initialization procedure */
+ void (*init) __P((int unit));
+ /* Process a received packet */
+ void (*input) __P((int unit, u_char *pkt, int len));
+ /* Process a received protocol-reject */
+ void (*protrej) __P((int unit));
+ /* Lower layer has come up */
+ void (*lowerup) __P((int unit));
+ /* Lower layer has gone down */
+ void (*lowerdown) __P((int unit));
+ /* Open the protocol */
+ void (*open) __P((int unit));
+ /* Close the protocol */
+ void (*close) __P((int unit, char *reason));
+ /* Print a packet in readable form */
+ int (*printpkt) __P((u_char *pkt, int len,
+ void (*printer) __P((void *, char *, ...)),
+ void *arg));
+ /* Process a received data packet */
+ void (*datainput) __P((int unit, u_char *pkt, int len));
+ int enabled_flag; /* 0 iff protocol is disabled */
+ char *name; /* Text name of protocol */
+ /* Check requested options, assign defaults */
+ void (*check_options) __P((void));
+ /* Configure interface for demand-dial */
+ int (*demand_conf) __P((int unit));
+ /* Say whether to bring up link for this pkt */
+ int (*active_pkt) __P((u_char *pkt, int len));
+};
+
+/* Table of pointers to supported protocols */
+extern struct protent *protocols[];
/*
* Prototypes.
*/
-void quit __P((void)); /* Cleanup and exit */
-void timeout __P((void (*)(), caddr_t, int));
- /* Look-alike of kernel's timeout() */
-void untimeout __P((void (*)(), caddr_t));
- /* Look-alike of kernel's untimeout() */
-void output __P((int, u_char *, int));
- /* Output a PPP packet */
+
+/* Procedures exported from main.c. */
+void die __P((int)); /* Cleanup and exit */
+void quit __P((void)); /* like die(1) */
+void novm __P((char *)); /* Say we ran out of memory, and die */
+void timeout __P((void (*func)(void *), void *arg, int t));
+ /* Call func(arg) after t seconds */
+void untimeout __P((void (*func)(void *), void *arg));
+ /* Cancel call to func(arg) */
+int run_program __P((char *prog, char **args, int must_exist));
+ /* Run program prog with args in child */
void demuxprotrej __P((int, int));
/* Demultiplex a Protocol-Reject */
+void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
+ void *)); /* Format a packet in human-readable form */
+void log_packet __P((u_char *, int, char *, int));
+ /* Format a packet and log it with syslog */
+void print_string __P((char *, int, void (*) (void *, char *, ...),
+ void *)); /* Format a string for output */
+int fmtmsg __P((char *, int, char *, ...)); /* sprintf++ */
+int vfmtmsg __P((char *, int, char *, va_list)); /* vsprintf++ */
+
+/* Procedures exported from auth.c */
+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 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 */
+void auth_peer_fail __P((int, int));
+ /* peer failed to authenticate itself */
+void auth_peer_success __P((int, int, char *, int));
+ /* peer successfully authenticated itself */
+void auth_withpeer_fail __P((int, int));
+ /* we failed to authenticate ourselves */
+void auth_withpeer_success __P((int, int));
+ /* we successfully authenticated ourselves */
+void auth_check_options __P((void));
+ /* check authentication options supplied */
+void auth_reset __P((int)); /* check what secrets we have */
int check_passwd __P((int, char *, int, char *, int, char **, int *));
/* Check peer-supplied username/password */
int get_secret __P((int, char *, char *, char *, int *, int));
/* get "secret" for chap */
-u_int32_t GetMask __P((u_int32_t)); /* get netmask for address */
-void die __P((int));
+int auth_ip_addr __P((int, u_int32_t));
+ /* check if IP address is authorized */
+int bad_ip_adrs __P((u_int32_t));
+ /* check if IP address is unreasonable */
+void check_access __P((FILE *, char *));
+ /* check permissions on secrets file */
+
+/* Procedures exported from demand.c */
+void demand_conf __P((void)); /* config interface(s) for demand-dial */
+void demand_block __P((void)); /* set all NPs to queue up packets */
+void demand_unblock __P((void)); /* set all NPs to pass packets */
+void demand_discard __P((void)); /* set all NPs to discard packets */
+void demand_rexmit __P((int)); /* retransmit saved frames for an NP */
+int loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+int loop_frame __P((unsigned char *, int)); /* process frame from loopback */
+
+/* Procedures exported from sys-*.c */
+void sys_init __P((void)); /* Do system-dependent initialization */
+void sys_cleanup __P((void)); /* Restore system state before exiting */
+void sys_check_options __P((void)); /* Check options specified */
+void sys_close __P((void)); /* Clean up in a child before execing */
+int ppp_available __P((void)); /* Test whether ppp kernel support exists */
+void open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
+void establish_ppp __P((int)); /* Turn serial port into a ppp interface */
+void restore_loop __P((void)); /* Transfer ppp unit back to loopback */
+void disestablish_ppp __P((int)); /* Restore port to normal operation */
+void clean_check __P((void)); /* Check if line was 8-bit clean */
+void set_up_tty __P((int, int)); /* Set up port's speed, parameters, etc. */
+void restore_tty __P((int)); /* Restore port's original parameters */
+void setdtr __P((int, int)); /* Raise or lower port's DTR line */
+void output __P((int, u_char *, int)); /* Output a PPP packet */
+void wait_input __P((struct timeval *));
+ /* Wait for input, with timeout */
+void wait_loop_output __P((struct timeval *));
+ /* Wait for pkt from loopback, with timeout */
+void wait_time __P((struct timeval *)); /* Wait for given length of time */
+int read_packet __P((u_char *)); /* Read PPP packet */
+int get_loop_output __P((void)); /* Read pkts from loopback */
+void ppp_send_config __P((int, int, u_int32_t, int, int));
+ /* Configure i/f transmit parameters */
+void ppp_set_xaccm __P((int, ext_accm));
+ /* Set extended transmit ACCM */
+void ppp_recv_config __P((int, int, u_int32_t, int, int));
+ /* Configure i/f receive parameters */
+int ccp_test __P((int, u_char *, int, int));
+ /* Test support for compression scheme */
+void ccp_flags_set __P((int, int, int));
+ /* Set kernel CCP state */
+int ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
+int get_idle_time __P((int, struct ppp_idle *));
+ /* Find out how long link has been idle */
+int sifvjcomp __P((int, int, int, int));
+ /* Configure VJ TCP header compression */
+int sifup __P((int)); /* Configure i/f up (for IP) */
+int sifnpmode __P((int u, int proto, enum NPmode mode));
+ /* Set mode for handling packets for proto */
+int sifdown __P((int)); /* Configure i/f down (for IP) */
+int sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
+ /* Configure IP addresses for i/f */
+int cifaddr __P((int, u_int32_t, u_int32_t));
+ /* Reset i/f IP addresses */
+int sifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Create default route through i/f */
+int cifdefaultroute __P((int, u_int32_t, u_int32_t));
+ /* Delete default route through i/f */
+int sifproxyarp __P((int, u_int32_t));
+ /* Add proxy ARP entry for peer */
+int cifproxyarp __P((int, u_int32_t));
+ /* Delete proxy ARP entry for peer */
+u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
+int lock __P((char *)); /* Create lock file for device */
+void unlock __P((void)); /* Delete previously-created lock file */
+int daemon __P((int, int)); /* Detach us from terminal session */
+void logwtmp __P((const char *, const char *, const char *));
+ /* Write entry to wtmp file */
+#ifdef PPP_FILTER
+int set_filters __P((struct bpf_program *pass, struct bpf_program *active));
+ /* Set filter programs in kernel */
+#endif
+
+/* Procedures exported from options.c */
+int parse_args __P((int argc, char **argv));
+ /* Parse options from arguments given */
+void usage __P((void)); /* Print a usage message */
+int options_from_file __P((char *filename, int must_exist, int check_prot,
+ int privileged));
+ /* 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 getword __P((FILE *f, char *word, int *newlinep, char *filename));
+ /* Read a word from a file */
+void option_error __P((char *fmt, ...));
+ /* Print an error message about an option */
+
+/*
+ * This structure is used to store information about certain
+ * options, such as where the option value came from (/etc/ppp/options,
+ * command line, etc.) and whether it came from a privileged source.
+ */
+
+struct option_info {
+ int priv; /* was value set by sysadmin? */
+ char *source; /* where option came from */
+};
+
+extern struct option_info auth_req_info;
+extern struct option_info connector_info;
+extern struct option_info disconnector_info;
+extern struct option_info welcomer_info;
+extern struct option_info devnam_info;
/*
* Inline versions of get/put char/short/long.
@@ -195,9 +409,9 @@ void die __P((int));
#endif
#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
-#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
|| defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
- || defined(DEBUGCHAP)
+ || defined(DEBUGCHAP) || defined(DEBUG)
#define LOG_PPP LOG_LOCAL2
#else
#define LOG_PPP LOG_DAEMON
@@ -210,6 +424,12 @@ void die __P((int));
#define MAINDEBUG(x)
#endif
+#ifdef DEBUGSYS
+#define SYSDEBUG(x) if (debug) syslog x
+#else
+#define SYSDEBUG(x)
+#endif
+
#ifdef DEBUGFSM
#define FSMDEBUG(x) if (debug) syslog x
#else
@@ -240,6 +460,12 @@ void die __P((int));
#define CHAPDEBUG(x)
#endif
+#ifdef DEBUGIPXCP
+#define IPXCPDEBUG(x) if (debug) syslog x
+#else
+#define IPXCPDEBUG(x)
+#endif
+
#ifndef SIGTYPE
#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
#define SIGTYPE void
diff --git a/usr.sbin/pppd/sys-bsd.c b/usr.sbin/pppd/sys-bsd.c
index b23bf69..a749a79 100644
--- a/usr.sbin/pppd/sys-bsd.c
+++ b/usr.sbin/pppd/sys-bsd.c
@@ -3,6 +3,7 @@
* PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
*
* Copyright (c) 1989 Carnegie Mellon University.
+ * Copyright (c) 1995 The Australian National University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
@@ -10,9 +11,10 @@
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
- * by Carnegie Mellon University. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * by Carnegie Mellon University and The Australian National University.
+ * The names of the Universities may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
@@ -34,11 +36,19 @@ static char rcsid[] = "$Id$";
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
+#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
+#include <sys/param.h>
+#ifdef NetBSD1_2
+#include <util.h>
+#endif
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
#include <net/if.h>
#include <net/if_var.h>
@@ -48,22 +58,46 @@ static char rcsid[] = "$Id$";
#include <net/if_dl.h>
#include <netinet/in.h>
+#ifdef IPX_CHANGE
+#include <netipx/ipx.h>
+#endif
+
#if RTM_VERSION >= 3
#include <netinet/if_ether.h>
#endif
#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
-static int initdisc = -1; /* Initial TTY discipline */
+static int initdisc = -1; /* Initial TTY discipline for ppp_fd */
+static int initfdflags = -1; /* Initial file descriptor flags for ppp_fd */
+static int ppp_fd = -1; /* fd which is set to PPP discipline */
static int rtm_seq;
-static int restore_term; /* 1 => we've munged the terminal */
+static int restore_term; /* 1 => we've munged the terminal */
static struct termios inittermios; /* Initial TTY termios */
static struct winsize wsinfo; /* Initial window size info */
static char *lock_file; /* name of lock file created */
-int sockfd; /* socket for doing interface ioctls */
+static int loop_slave = -1;
+static int loop_master;
+static char loop_name[20];
+
+static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+
+static int sockfd; /* socket for doing interface ioctls */
+
+static int if_is_up; /* the interface is currently up */
+static u_int32_t ifaddrs[2]; /* local and remote addresses we set */
+static u_int32_t default_route_gateway; /* gateway addr for default route */
+static u_int32_t proxy_arp_addr; /* remote addr for proxy arp */
+
+/* Prototypes for procedures local to this file. */
+static int dodefaultroute __P((u_int32_t, int));
+static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *));
+
/*
* sys_init - System-dependent initialization.
@@ -71,11 +105,6 @@ int sockfd; /* socket for doing interface ioctls */
void
sys_init()
{
- openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
- setlogmask(LOG_UPTO(LOG_INFO));
- if (debug)
- setlogmask(LOG_UPTO(LOG_DEBUG));
-
/* Get an internet socket for doing socket ioctl's on. */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "Couldn't create IP socket: %m");
@@ -84,17 +113,50 @@ sys_init()
}
/*
- * note_debug_level - note a change in the debug level.
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This should call die() because it's called from die().
*/
void
-note_debug_level()
+sys_cleanup()
{
- if (debug) {
- syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
- setlogmask(LOG_UPTO(LOG_DEBUG));
- } else {
- setlogmask(LOG_UPTO(LOG_WARNING));
+ struct ifreq ifr;
+
+ if (if_is_up) {
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
+ && ((ifr.ifr_flags & IFF_UP) != 0)) {
+ ifr.ifr_flags &= ~IFF_UP;
+ ioctl(sockfd, SIOCSIFFLAGS, &ifr);
+ }
}
+ if (ifaddrs[0] != 0)
+ cifaddr(0, ifaddrs[0], ifaddrs[1]);
+ if (default_route_gateway)
+ cifdefaultroute(0, 0, default_route_gateway);
+ if (proxy_arp_addr)
+ cifproxyarp(0, proxy_arp_addr);
+}
+
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+ close(sockfd);
+ if (loop_slave >= 0) {
+ close(loop_slave);
+ close(loop_master);
+ }
+}
+
+/*
+ * sys_check_options - check the options that the user specified
+ */
+void
+sys_check_options()
+{
}
/*
@@ -126,11 +188,25 @@ file in the ppp-2.2 distribution.\n";
* establish_ppp - Turn the serial port into a ppp interface.
*/
void
-establish_ppp()
+establish_ppp(fd)
+ int fd;
{
int pppdisc = PPPDISC;
int x;
+ if (demand) {
+ /*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+ if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) {
+ syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
+ die(1);
+ }
+ }
+
+ /*
+ * Save the old line discipline of fd, and set it to PPP.
+ */
if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
die(1);
@@ -140,14 +216,33 @@ establish_ppp()
die(1);
}
- /*
- * Find out which interface we were given.
- */
- if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
- syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
- die(1);
+ if (!demand) {
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+ } else {
+ /*
+ * Check that we got the same unit again.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+ if (x != ifunit) {
+ syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
+ ifunit, x);
+ die(1);
+ }
+ x = TTYDISC;
+ ioctl(loop_slave, TIOCSETD, &x);
}
+ ppp_fd = fd;
+
/*
* Enable debug in the driver if requested.
*/
@@ -160,6 +255,50 @@ establish_ppp()
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
}
}
+
+ /*
+ * Set device for non-blocking reads.
+ */
+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1
+ || fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+ syslog(LOG_WARNING, "Couldn't set device to non-blocking mode: %m");
+ }
+}
+
+/*
+ * restore_loop - reattach the ppp unit to the loopback.
+ */
+void
+restore_loop()
+{
+ int x;
+
+ /*
+ * Transfer the ppp interface back to the loopback.
+ */
+ if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0) {
+ syslog(LOG_ERR, "ioctl(transfer ppp unit): %m");
+ die(1);
+ }
+ x = PPPDISC;
+ if (ioctl(loop_slave, TIOCSETD, &x) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Check that we got the same unit again.
+ */
+ if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+ if (x != ifunit) {
+ syslog(LOG_ERR, "transfer_ppp failed: wanted unit %d, got %d",
+ ifunit, x);
+ die(1);
+ }
+ ppp_fd = loop_slave;
}
@@ -168,42 +307,55 @@ establish_ppp()
* This shouldn't call die() because it's called from die().
*/
void
-disestablish_ppp()
+disestablish_ppp(fd)
+ int fd;
+{
+ /* Reset non-blocking mode on fd. */
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_WARNING, "Couldn't restore device fd flags: %m");
+ initfdflags = -1;
+
+ /* Restore old line discipline. */
+ if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ initdisc = -1;
+
+ if (fd == ppp_fd)
+ ppp_fd = -1;
+}
+
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
{
int x;
char *s;
- if (initdisc >= 0) {
- /*
- * Check whether the link seems not to be 8-bit clean.
- */
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
- s = NULL;
- switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
- case SC_RCV_B7_0:
- s = "bit 7 set to 1";
- break;
- case SC_RCV_B7_1:
- s = "bit 7 set to 0";
- break;
- case SC_RCV_EVNP:
- s = "odd parity";
- break;
- case SC_RCV_ODDP:
- s = "even parity";
- break;
- }
- if (s != NULL) {
- syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
- syslog(LOG_WARNING, "All received characters had %s", s);
- }
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+ s = NULL;
+ switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+ case SC_RCV_B7_0:
+ s = "bit 7 set to 1";
+ break;
+ case SC_RCV_B7_1:
+ s = "bit 7 set to 0";
+ break;
+ case SC_RCV_EVNP:
+ s = "odd parity";
+ break;
+ case SC_RCV_ODDP:
+ s = "even parity";
+ break;
+ }
+ if (s != NULL) {
+ syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
+ syslog(LOG_WARNING, "All received characters had %s", s);
}
- if (ioctl(fd, TIOCSETD, &initdisc) < 0)
- syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
}
}
-
/*
* set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
* at the requested speed, etc. If `local' is true, set CLOCAL
@@ -211,6 +363,7 @@ disestablish_ppp()
*
* For *BSD, we assume that speed_t values numerically equal bits/second.
*/
+void
set_up_tty(fd, local)
int fd, local;
{
@@ -227,7 +380,7 @@ set_up_tty(fd, local)
}
tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
- if (crtscts > 0)
+ if (crtscts > 0 && !local)
tios.c_cflag |= CRTSCTS;
else if (crtscts < 0)
tios.c_cflag &= ~CRTSCTS;
@@ -241,8 +394,8 @@ set_up_tty(fd, local)
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
- if (crtscts == 2) {
- tios.c_iflag |= IXOFF;
+ if (crtscts == -2) {
+ tios.c_iflag |= IXON | IXOFF;
tios.c_cc[VSTOP] = 0x13; /* DC3 = XOFF = ^S */
tios.c_cc[VSTART] = 0x11; /* DC1 = XON = ^Q */
}
@@ -276,7 +429,8 @@ set_up_tty(fd, local)
* restore_tty - restore the terminal to the saved settings.
*/
void
-restore_tty()
+restore_tty(fd)
+ int fd;
{
if (restore_term) {
if (!default_device) {
@@ -300,6 +454,7 @@ restore_tty()
* setdtr - control the DTR line on the serial port.
* This is called from die(), so it shouldn't call die().
*/
+void
setdtr(fd, on)
int fd, on;
{
@@ -310,6 +465,68 @@ int fd, on;
/*
+ * open_ppp_loopback - open the device we use for getting
+ * packets in demand mode, and connect it to a ppp interface.
+ * Here we use a pty.
+ */
+void
+open_ppp_loopback()
+{
+ int flags;
+ struct termios tios;
+ int pppdisc = PPPDISC;
+
+ if (openpty(&loop_master, &loop_slave, loop_name, NULL, NULL) < 0) {
+ syslog(LOG_ERR, "No free pty for loopback");
+ die(1);
+ }
+ SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+
+ if (tcgetattr(loop_slave, &tios) == 0) {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD;
+ tios.c_iflag = IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(loop_slave, TCSAFLUSH, &tios) < 0)
+ syslog(LOG_WARNING, "couldn't set attributes on loopback: %m");
+ }
+
+ if ((flags = fcntl(loop_master, F_GETFL)) != -1)
+ if (fcntl(loop_master, F_SETFL, flags | O_NONBLOCK) == -1)
+ syslog(LOG_WARNING, "couldn't set loopback to nonblock: %m");
+
+ ppp_fd = loop_slave;
+ if (ioctl(ppp_fd, TIOCSETD, &pppdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+
+ /*
+ * Enable debug in the driver if requested.
+ */
+ if (kdebugflag) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &flags) < 0) {
+ syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
+ } else {
+ flags |= (kdebugflag & 0xFF) * SC_DEBUG;
+ if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &flags) < 0)
+ syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
+ }
+ }
+
+}
+
+
+/*
* output - Output PPP packet.
*/
void
@@ -318,23 +535,22 @@ output(unit, p, len)
u_char *p;
int len;
{
- if (unit != 0)
- MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
if (debug)
- log_packet(p, len, "sent ");
+ log_packet(p, len, "sent ", LOG_DEBUG);
- if (write(fd, p, len) < 0) {
- syslog(LOG_ERR, "write: %m");
- die(1);
+ if (write(ttyfd, p, len) < 0) {
+ if (errno != EIO)
+ syslog(LOG_ERR, "write: %m");
}
}
/*
- * wait_input - wait until there is data available on fd,
+ * wait_input - wait until there is data available on ttyfd,
* for the length of time specified by *timo (indefinite
* if timo is NULL).
*/
+void
wait_input(timo)
struct timeval *timo;
{
@@ -342,8 +558,48 @@ wait_input(timo)
int n;
FD_ZERO(&ready);
- FD_SET(fd, &ready);
- n = select(fd+1, &ready, NULL, &ready, timo);
+ FD_SET(ttyfd, &ready);
+ n = select(ttyfd+1, &ready, NULL, &ready, timo);
+ if (n < 0 && errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * wait_loop_output - wait until there is data available on the
+ * loopback, for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_loop_output(timo)
+ struct timeval *timo;
+{
+ fd_set ready;
+ int n;
+
+ FD_ZERO(&ready);
+ FD_SET(loop_master, &ready);
+ n = select(loop_master + 1, &ready, NULL, &ready, timo);
+ if (n < 0 && errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+void
+wait_time(timo)
+ struct timeval *timo;
+{
+ int n;
+
+ n = select(0, NULL, NULL, NULL, timo);
if (n < 0 && errno != EINTR) {
syslog(LOG_ERR, "select: %m");
die(1);
@@ -360,10 +616,10 @@ read_packet(buf)
{
int len;
- if ((len = read(fd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
+ if ((len = read(ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
if (errno == EWOULDBLOCK || errno == EINTR)
return -1;
- syslog(LOG_ERR, "read(fd): %m");
+ syslog(LOG_ERR, "read: %m");
die(1);
}
return len;
@@ -371,6 +627,34 @@ read_packet(buf)
/*
+ * get_loop_output - read characters from the loopback, form them
+ * into frames, and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output()
+{
+ int rv = 0;
+ int n;
+
+ while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) {
+ if (loop_chars(inbuf, n))
+ rv = 1;
+ }
+
+ if (n == 0) {
+ syslog(LOG_ERR, "eof on loopback");
+ die(1);
+ } else if (errno != EWOULDBLOCK){
+ syslog(LOG_ERR, "read from loopback: %m");
+ die(1);
+ }
+
+ return rv;
+}
+
+
+/*
* ppp_send_config - configure the transmit characteristics of
* the ppp interface.
*/
@@ -390,18 +674,18 @@ ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
quit();
}
- if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
quit();
}
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
quit();
}
x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
quit();
}
@@ -416,7 +700,7 @@ ppp_set_xaccm(unit, accm)
int unit;
ext_accm accm;
{
- if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
+ if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
}
@@ -433,20 +717,20 @@ ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
{
int x;
- if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
quit();
}
- if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
quit();
}
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
quit();
}
x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
quit();
}
@@ -454,8 +738,11 @@ ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
/*
* ccp_test - ask kernel whether a given compression method
- * is acceptable for use.
+ * is acceptable for use. Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
*/
+int
ccp_test(unit, opt_ptr, opt_len, for_transmit)
int unit, opt_len, for_transmit;
u_char *opt_ptr;
@@ -465,7 +752,9 @@ ccp_test(unit, opt_ptr, opt_len, for_transmit)
data.ptr = opt_ptr;
data.length = opt_len;
data.transmit = for_transmit;
- return ioctl(fd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0;
+ if (ioctl(ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
+ return 1;
+ return (errno == ENOBUFS)? 0: -1;
}
/*
@@ -477,13 +766,13 @@ ccp_flags_set(unit, isopen, isup)
{
int x;
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
return;
}
x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+ if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
}
@@ -498,7 +787,7 @@ ccp_fatal_error(unit)
{
int x;
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m");
return 0;
}
@@ -506,6 +795,44 @@ ccp_fatal_error(unit)
}
/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+ int u;
+ struct ppp_idle *ip;
+{
+ return ioctl(ppp_fd, PPPIOCGIDLE, ip) >= 0;
+}
+
+
+#ifdef PPP_FILTER
+/*
+ * set_filters - transfer the pass and active filters to the kernel.
+ */
+int
+set_filters(pass, active)
+ struct bpf_program *pass, *active;
+{
+ int ret = 1;
+
+ if (pass->bf_len > 0) {
+ if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) {
+ syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
+ ret = 0;
+ }
+ }
+ if (active->bf_len > 0) {
+ if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) {
+ syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+#endif
+
+/*
* sifvjcomp - config tcp header compression
*/
int
@@ -514,17 +841,17 @@ sifvjcomp(u, vjcomp, cidcomp, maxcid)
{
u_int x;
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
return 0;
}
x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
- if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
+ if (vjcomp && ioctl(ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
@@ -534,17 +861,11 @@ sifvjcomp(u, vjcomp, cidcomp, maxcid)
/*
* sifup - Config the interface up and enable IP packets to pass.
*/
-#ifndef SC_ENABLE_IP
-#define SC_ENABLE_IP 0x100 /* compat for old versions of kernel code */
-#endif
-
int
sifup(u)
int u;
{
struct ifreq ifr;
- u_int x;
- struct npioctl npi;
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
@@ -556,23 +877,26 @@ sifup(u)
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
return 0;
}
- npi.protocol = PPP_IP;
- npi.mode = NPMODE_PASS;
- if (ioctl(fd, PPPIOCSNPMODE, &npi) < 0) {
- if (errno != ENOTTY) {
- syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
- return 0;
- }
- /* for backwards compatibility */
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
- return 0;
- }
- x |= SC_ENABLE_IP;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
- return 0;
- }
+ if_is_up = 1;
+ return 1;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ struct npioctl npi;
+
+ npi.protocol = proto;
+ npi.mode = mode;
+ if (ioctl(ppp_fd, PPPIOCSNPMODE, &npi) < 0) {
+ syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %m", proto, mode);
+ return 0;
}
return 1;
}
@@ -585,31 +909,14 @@ sifdown(u)
int u;
{
struct ifreq ifr;
- u_int x;
int rv;
struct npioctl npi;
rv = 1;
npi.protocol = PPP_IP;
npi.mode = NPMODE_ERROR;
- if (ioctl(fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0) {
- if (errno != ENOTTY) {
- syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE): %m");
- rv = 0;
- } else {
- /* backwards compatibility */
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
- rv = 0;
- } else {
- x &= ~SC_ENABLE_IP;
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
- rv = 0;
- }
- }
- }
- }
+ ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi);
+ /* ignore errors, because ppp_fd might have been closed by now. */
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
@@ -620,7 +927,8 @@ sifdown(u)
if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
rv = 0;
- }
+ } else
+ if_is_up = 0;
}
return rv;
}
@@ -656,11 +964,15 @@ sifaddr(u, o, h, m)
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
if (errno != EEXIST) {
- syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ syslog(LOG_ERR, "Couldn't set interface address: %m");
return 0;
}
- syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ syslog(LOG_WARNING,
+ "Couldn't set interface address: Address %s already exists",
+ ip_ntoa(o));
}
+ ifaddrs[0] = o;
+ ifaddrs[1] = h;
return 1;
}
@@ -675,6 +987,7 @@ cifaddr(u, o, h)
{
struct ifaliasreq ifra;
+ ifaddrs[0] = 0;
strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
@@ -682,7 +995,8 @@ cifaddr(u, o, h)
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
- syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
+ if (errno != EADDRNOTAVAIL)
+ syslog(LOG_WARNING, "Couldn't delete interface address: %m");
return 0;
}
return 1;
@@ -692,9 +1006,9 @@ cifaddr(u, o, h)
* sifdefaultroute - assign a default route through the address given.
*/
int
-sifdefaultroute(u, g)
+sifdefaultroute(u, l, g)
int u;
- u_int32_t g;
+ u_int32_t l, g;
{
return dodefaultroute(g, 's');
}
@@ -703,9 +1017,9 @@ sifdefaultroute(u, g)
* cifdefaultroute - delete a default route through the address given.
*/
int
-cifdefaultroute(u, g)
+cifdefaultroute(u, l, g)
int u;
- u_int32_t g;
+ u_int32_t l, g;
{
return dodefaultroute(g, 'c');
}
@@ -713,7 +1027,7 @@ cifdefaultroute(u, g)
/*
* dodefaultroute - talk to a routing socket to add/delete a default route.
*/
-int
+static int
dodefaultroute(g, cmd)
u_int32_t g;
int cmd;
@@ -727,7 +1041,8 @@ dodefaultroute(g, cmd)
} rtmsg;
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
- syslog(LOG_ERR, "%cifdefaultroute: opening routing socket: %m", cmd);
+ syslog(LOG_ERR, "Couldn't %s default route: socket: %m",
+ cmd=='s'? "add": "delete");
return 0;
}
@@ -747,12 +1062,14 @@ dodefaultroute(g, cmd)
rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
- syslog(LOG_ERR, "%s default route: %m", cmd=='s'? "add": "delete");
+ syslog(LOG_ERR, "Couldn't %s default route: %m",
+ cmd=='s'? "add": "delete");
close(routes);
return 0;
}
close(routes);
+ default_route_gateway = (cmd == 's')? g: 0;
return 1;
}
@@ -776,7 +1093,6 @@ sifproxyarp(unit, hisaddr)
u_int32_t hisaddr;
{
int routes;
- int l;
/*
* Get the hardware address of an interface on the same subnet
@@ -789,7 +1105,7 @@ sifproxyarp(unit, hisaddr)
}
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
- syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
+ syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m");
return 0;
}
@@ -807,13 +1123,14 @@ sifproxyarp(unit, hisaddr)
arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+ arpmsg.hwa.sdl_len;
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
- syslog(LOG_ERR, "add proxy arp entry: %m");
+ syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
close(routes);
return 0;
}
close(routes);
arpmsg_valid = 1;
+ proxy_arp_addr = hisaddr;
return 1;
}
@@ -835,17 +1152,18 @@ cifproxyarp(unit, hisaddr)
arpmsg.hdr.rtm_seq = ++rtm_seq;
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
- syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
+ syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m");
return 0;
}
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
- syslog(LOG_ERR, "delete proxy arp entry: %m");
+ syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m");
close(routes);
return 0;
}
close(routes);
+ proxy_arp_addr = 0;
return 1;
}
@@ -883,10 +1201,11 @@ sifproxyarp(unit, hisaddr)
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
arpreq.arp_flags = ATF_PERM | ATF_PUBL;
if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
return 0;
}
+ proxy_arp_addr = hisaddr;
return 1;
}
@@ -904,13 +1223,114 @@ cifproxyarp(unit, hisaddr)
SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
- syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
return 0;
}
+ proxy_arp_addr = 0;
return 1;
}
#endif /* RTM_VERSION */
+#ifdef IPX_CHANGE
+/********************************************************************
+ *
+ * sipxfaddr - Config the interface IPX networknumber
+ */
+
+int
+sipxfaddr (int unit, unsigned long int network, unsigned char * node )
+ {
+ int result = 1;
+
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+ union ipx_net_u net;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ memcpy (sipx->sipx_addr.x_host.c_host, node, 6);
+ sipx->sipx_len = sizeof(sipx);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_port = 0;
+ memset(&net, 0, sizeof(net));
+ net.long_e = htonl (network);
+ sipx->sipx_addr.x_net = net.net_e;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ result = 0;
+ if (errno != EEXIST)
+ {
+ syslog (LOG_DEBUG,
+ "ioctl(SIOCAIFADDR, CRTITF): %m(%d)", errno);
+ }
+ else
+ {
+ syslog (LOG_WARNING,
+ "ioctl(SIOCAIFADDR, CRTITF): Address already exists");
+ }
+ }
+ close (skfd);
+ }
+ return result;
+ }
+
+/********************************************************************
+ *
+ * cipxfaddr - Clear the information for the IPX network. The IPX routes
+ * are removed and the device is no longer able to pass IPX
+ * frames.
+ */
+
+int cipxfaddr (int unit)
+ {
+ int result = 1;
+
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ sipx->sipx_len = sizeof(sipx);
+ sipx->sipx_family = AF_IPX;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ syslog (LOG_INFO,
+ "ioctl(SIOCAIFADDR, IPX_DLTITF): %m(%d)", errno);
+ result = 0;
+ }
+ close (skfd);
+ }
+ return result;
+ }
+#endif
/*
* get_ether_addr - get the hardware address of an interface on the
@@ -918,7 +1338,7 @@ cifproxyarp(unit, hisaddr)
*/
#define MAX_IFS 32
-int
+static int
get_ether_addr(ipaddr, hwaddr)
u_int32_t ipaddr;
struct sockaddr_dl *hwaddr;
@@ -1087,14 +1507,12 @@ lock(dev)
&& (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
/* Read the lock file to find out who has the device locked */
n = read(fd, hdb_lock_buffer, 11);
- if (n > 0) {
- hdb_lock_buffer[n] = 0;
- pid = atoi(hdb_lock_buffer);
- }
if (n <= 0) {
syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
close(fd);
} else {
+ hdb_lock_buffer[n] = 0;
+ pid = atoi(hdb_lock_buffer);
if (kill(pid, 0) == -1 && errno == ESRCH) {
/* pid no longer exists - remove the lock file */
if (unlink(lock_file) == 0) {
@@ -1127,6 +1545,7 @@ lock(dev)
/*
* unlock - remove our lockfile
*/
+void
unlock()
{
if (lock_file) {
diff --git a/usr.sbin/pppd/upap.c b/usr.sbin/pppd/upap.c
index bc04e70..469c5cb 100644
--- a/usr.sbin/pppd/upap.c
+++ b/usr.sbin/pppd/upap.c
@@ -34,12 +34,39 @@ static char rcsid[] = "$Id$";
#include "pppd.h"
#include "upap.h"
+/*
+ * Protocol entry points.
+ */
+static void upap_init __P((int));
+static void upap_lowerup __P((int));
+static void upap_lowerdown __P((int));
+static void upap_input __P((int, u_char *, int));
+static void upap_protrej __P((int));
+static int upap_printpkt __P((u_char *, int,
+ void (*) __P((void *, char *, ...)), void *));
+
+struct protent pap_protent = {
+ PPP_PAP,
+ upap_init,
+ upap_input,
+ upap_protrej,
+ upap_lowerup,
+ upap_lowerdown,
+ NULL,
+ NULL,
+ upap_printpkt,
+ NULL,
+ 1,
+ "PAP",
+ NULL,
+ NULL,
+ NULL
+};
upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
-
-static void upap_timeout __P((caddr_t));
-static void upap_reqtimeout __P((caddr_t));
+static void upap_timeout __P((void *));
+static void upap_reqtimeout __P((void *));
static void upap_rauthreq __P((upap_state *, u_char *, int, int));
static void upap_rauthack __P((upap_state *, u_char *, int, int));
static void upap_rauthnak __P((upap_state *, u_char *, int, int));
@@ -50,7 +77,7 @@ static void upap_sresp __P((upap_state *, int, int, char *, int));
/*
* upap_init - Initialize a UPAP unit.
*/
-void
+static void
upap_init(unit)
int unit;
{
@@ -120,7 +147,7 @@ upap_authpeer(unit)
u->us_serverstate = UPAPSS_LISTEN;
if (u->us_reqtimeout > 0)
- TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout);
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
}
@@ -129,7 +156,7 @@ upap_authpeer(unit)
*/
static void
upap_timeout(arg)
- caddr_t arg;
+ void *arg;
{
upap_state *u = (upap_state *) arg;
@@ -153,7 +180,7 @@ upap_timeout(arg)
*/
static void
upap_reqtimeout(arg)
- caddr_t arg;
+ void *arg;
{
upap_state *u = (upap_state *) arg;
@@ -170,7 +197,7 @@ upap_reqtimeout(arg)
*
* Start authenticating if pending.
*/
-void
+static void
upap_lowerup(unit)
int unit;
{
@@ -187,7 +214,7 @@ upap_lowerup(unit)
else if (u->us_serverstate == UPAPSS_PENDING) {
u->us_serverstate = UPAPSS_LISTEN;
if (u->us_reqtimeout > 0)
- TIMEOUT(upap_reqtimeout, (caddr_t) u, u->us_reqtimeout);
+ TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
}
}
@@ -197,16 +224,16 @@ upap_lowerup(unit)
*
* Cancel all timeouts.
*/
-void
+static void
upap_lowerdown(unit)
int unit;
{
upap_state *u = &upap[unit];
if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
- UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
+ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
- UNTIMEOUT(upap_reqtimeout, (caddr_t) u);
+ UNTIMEOUT(upap_reqtimeout, u);
u->us_clientstate = UPAPCS_INITIAL;
u->us_serverstate = UPAPSS_INITIAL;
@@ -218,7 +245,7 @@ upap_lowerdown(unit)
*
* This shouldn't happen. In any case, pretend lower layer went down.
*/
-void
+static void
upap_protrej(unit)
int unit;
{
@@ -239,7 +266,7 @@ upap_protrej(unit)
/*
* upap_input - Input UPAP packet.
*/
-void
+static void
upap_input(unit, inpacket, l)
int unit;
u_char *inpacket;
@@ -256,18 +283,18 @@ upap_input(unit, inpacket, l)
*/
inp = inpacket;
if (l < UPAP_HEADERLEN) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."));
+ UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header."));
return;
}
GETCHAR(code, inp);
GETCHAR(id, inp);
GETSHORT(len, inp);
if (len < UPAP_HEADERLEN) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."));
+ UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length."));
return;
}
if (len > l) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
@@ -310,7 +337,7 @@ upap_rauthreq(u, inp, id, len)
char *msg;
int msglen;
- UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
+ UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id));
if (u->us_serverstate < UPAPSS_LISTEN)
return;
@@ -332,20 +359,20 @@ upap_rauthreq(u, inp, id, len)
* Parse user/passwd.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);
if (len < 0) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
return;
}
ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
return;
}
rpasswd = (char *) inp;
@@ -355,19 +382,20 @@ upap_rauthreq(u, inp, id, len)
*/
retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
rpasswdlen, &msg, &msglen);
+ BZERO(rpasswd, rpasswdlen);
upap_sresp(u, retcode, id, msg, msglen);
if (retcode == UPAP_AUTHACK) {
u->us_serverstate = UPAPSS_OPEN;
- auth_peer_success(u->us_unit, PPP_PAP);
+ auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
} else {
u->us_serverstate = UPAPSS_BADAUTH;
auth_peer_fail(u->us_unit, PPP_PAP);
}
if (u->us_reqtimeout > 0)
- UNTIMEOUT(upap_reqtimeout, (caddr_t) u);
+ UNTIMEOUT(upap_reqtimeout, u);
}
@@ -384,7 +412,7 @@ upap_rauthack(u, inp, id, len)
u_char msglen;
char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
+ UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id));
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
@@ -392,13 +420,13 @@ upap_rauthack(u, inp, id, len)
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
- UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
return;
}
msg = (char *) inp;
@@ -423,7 +451,7 @@ upap_rauthnak(u, inp, id, len)
u_char msglen;
char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
+ UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id));
if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
@@ -431,13 +459,13 @@ upap_rauthnak(u, inp, id, len)
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
+ UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
return;
}
msg = (char *) inp;
@@ -477,9 +505,9 @@ upap_sauthreq(u)
output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
- UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
+ UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id));
- TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
+ TIMEOUT(upap_timeout, u, u->us_timeouttime);
++u->us_transmits;
u->us_clientstate = UPAPCS_AUTHREQ;
}
@@ -509,17 +537,17 @@ upap_sresp(u, code, id, msg, msglen)
BCOPY(msg, outp, msglen);
output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
- UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
+ UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id));
}
/*
* upap_printpkt - print the contents of a PAP packet.
*/
-char *upap_codenames[] = {
+static char *upap_codenames[] = {
"AuthReq", "AuthAck", "AuthNak"
};
-int
+static int
upap_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
@@ -575,7 +603,7 @@ upap_printpkt(p, plen, printer, arg)
msg = (char *) (p + 1);
p += mlen + 1;
len -= mlen + 1;
- printer(arg, "msg=");
+ printer(arg, " ");
print_string(msg, mlen, printer, arg);
break;
}
diff --git a/usr.sbin/pppd/upap.h b/usr.sbin/pppd/upap.h
index 3470e85..510efa3 100644
--- a/usr.sbin/pppd/upap.h
+++ b/usr.sbin/pppd/upap.h
@@ -79,15 +79,9 @@ typedef struct upap_state {
#define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */
#define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */
-
extern upap_state upap[];
-void upap_init __P((int));
void upap_authwithpeer __P((int, char *, char *));
void upap_authpeer __P((int));
-void upap_lowerup __P((int));
-void upap_lowerdown __P((int));
-void upap_input __P((int, u_char *, int));
-void upap_protrej __P((int));
-int upap_printpkt __P((u_char *, int,
- void (*) __P((void *, char *, ...)), void *));
+
+extern struct protent pap_protent;
OpenPOWER on IntegriCloud