aboutsummaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
committersvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86 /libexec
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
downloadsrc-releng/1.tar.gz
src-releng/1.zip
Release FreeBSD 1.1.5.1release/1.1.5.1_cvsreleng/1
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'libexec')
-rw-r--r--libexec/Makefile4
-rw-r--r--libexec/bootpd/bootpd.82
-rw-r--r--libexec/bootpd/bootptab.52
-rw-r--r--libexec/ftpd/Makefile9
-rw-r--r--libexec/ftpd/ftpd.c20
-rw-r--r--libexec/ftpd/skey-stuff.c23
-rw-r--r--libexec/getty/gettytab.h4
-rw-r--r--libexec/getty/main.c12
-rw-r--r--libexec/pppd/Makefile26
-rw-r--r--libexec/pppd/README284
-rw-r--r--libexec/pppd/args.h1
-rw-r--r--libexec/pppd/auth.c828
-rw-r--r--libexec/pppd/callout.h2
-rw-r--r--libexec/pppd/chap.c986
-rw-r--r--libexec/pppd/chap.h93
-rw-r--r--libexec/pppd/fsm.c1006
-rw-r--r--libexec/pppd/fsm.h76
-rw-r--r--libexec/pppd/ipcp.c1057
-rw-r--r--libexec/pppd/ipcp.h32
-rw-r--r--libexec/pppd/lcp.c1191
-rw-r--r--libexec/pppd/lcp.h37
-rw-r--r--libexec/pppd/magic.c4
-rw-r--r--libexec/pppd/magic.h2
-rw-r--r--libexec/pppd/main.c2701
-rw-r--r--libexec/pppd/md5.c134
-rw-r--r--libexec/pppd/options.c1195
-rw-r--r--libexec/pppd/patchlevel.h7
-rw-r--r--libexec/pppd/pathnames.h16
-rw-r--r--libexec/pppd/ppp.h41
-rw-r--r--libexec/pppd/pppd.82
-rw-r--r--libexec/pppd/pppd.h345
-rw-r--r--libexec/pppd/sys-bsd.c503
-rw-r--r--libexec/pppd/sys-str.c643
-rw-r--r--libexec/pppd/upap.c340
-rw-r--r--libexec/pppd/upap.h41
-rw-r--r--libexec/rexecd/Makefile6
-rw-r--r--libexec/rexecd/rexecd.c11
-rw-r--r--libexec/rlogind/Makefile15
-rw-r--r--libexec/rlogind/rlogind.c7
-rw-r--r--libexec/rpc.rusersd/rusers_proc.c2
-rw-r--r--libexec/rshd/Makefile16
-rw-r--r--libexec/telnetd/sys_term.c9
-rw-r--r--libexec/uucpd/Makefile1
-rw-r--r--libexec/uucpd/pathnames.h2
-rw-r--r--libexec/uucpd/uucpd.c214
-rw-r--r--libexec/xtend/Makefile11
-rw-r--r--libexec/xtend/packet.c317
-rw-r--r--libexec/xtend/paths.h11
-rw-r--r--libexec/xtend/status.c109
-rw-r--r--libexec/xtend/user.c162
-rw-r--r--libexec/xtend/xten.h58
-rw-r--r--libexec/xtend/xtend.8174
-rw-r--r--libexec/xtend/xtend.c319
-rw-r--r--libexec/xtend/xtend.h77
54 files changed, 8576 insertions, 4614 deletions
diff --git a/libexec/Makefile b/libexec/Makefile
index ac0119481fc2..cdbb7dcc6e9d 100644
--- a/libexec/Makefile
+++ b/libexec/Makefile
@@ -1,10 +1,10 @@
-# $Id: Makefile,v 1.7 1994/01/25 22:51:39 martin Exp $
+# $Id: Makefile,v 1.8 1994/06/01 15:37:58 paul Exp $
# From: @(#)Makefile 5.7 (Berkeley) 4/1/91
#
SUBDIR= atrun bugfiler bootpd comsat elvispreserve fingerd ftpd getNAME \
getty mail.local makekey pppd rexecd rlogind rpc.rstatd \
- rpc.rusersd rpc.rwalld rshd talkd telnetd tftpd uucpd
+ rpc.rusersd rpc.rwalld rshd talkd telnetd tftpd uucpd xtend
# kpasswdd not ported, it is old kerberosIV
diff --git a/libexec/bootpd/bootpd.8 b/libexec/bootpd/bootpd.8
index bf0c69a62beb..3fad3f28007d 100644
--- a/libexec/bootpd/bootpd.8
+++ b/libexec/bootpd/bootpd.8
@@ -1,6 +1,6 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.8,v 1.1.2.1 1994/05/01 16:06:34 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootpd.8,v 1.1 1994/01/25 22:53:33 martin Exp $
.\"
.TH BOOTPD 8 "November 11, 1991" "Carnegie Mellon University"
.UC 6
diff --git a/libexec/bootpd/bootptab.5 b/libexec/bootpd/bootptab.5
index 874ed48bad56..10bf21ba9502 100644
--- a/libexec/bootpd/bootptab.5
+++ b/libexec/bootpd/bootptab.5
@@ -1,6 +1,6 @@
.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
.\"
-.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootptab.5,v 1.1.2.1 1994/05/01 16:06:36 jkh Exp $
+.\" $Header: /home/cvs/386BSD/src/libexec/bootpd/bootptab.5,v 1.1 1994/01/25 22:53:43 martin Exp $
.\"
.TH BOOTPTAB 5 "October 31, 1991" "Carnegie Mellon University"
.UC 6
diff --git a/libexec/ftpd/Makefile b/libexec/ftpd/Makefile
index fe7ffd1a2c09..53cef2613b24 100644
--- a/libexec/ftpd/Makefile
+++ b/libexec/ftpd/Makefile
@@ -2,16 +2,19 @@
PROG= ftpd
-CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp -DSETPROCTITLE
-SRCS= ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c
+CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp \
+ -DSETPROCTITLE -DSKEY
+SRCS= ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c skey-stuff.c
MAN8= ftpd.8
CLEANFILES+=ftpcmd.c y.tab.h
.PATH: ${.CURDIR}/../../usr.bin/ftp
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
+
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
.endif
-
.include <bsd.prog.mk>
diff --git a/libexec/ftpd/ftpd.c b/libexec/ftpd/ftpd.c
index 2638e8dd8b71..701d2a29a839 100644
--- a/libexec/ftpd/ftpd.c
+++ b/libexec/ftpd/ftpd.c
@@ -144,6 +144,11 @@ char *LastArgv = NULL; /* end of argv */
char proctitle[BUFSIZ]; /* initial part of title */
#endif /* SETPROCTITLE */
+#ifdef SKEY
+int pwok = 0;
+char *skey_challenge();
+char *skey_crypt();
+#endif
main(argc, argv, envp)
int argc;
char *argv[];
@@ -151,6 +156,9 @@ main(argc, argv, envp)
{
int addrlen, on = 1, tos;
char *cp;
+#ifdef SKEY
+ char addr_string[20]; /* XXX */
+#endif
/*
* LOG_NDELAY sets up the logging connection immediately,
@@ -162,6 +170,10 @@ main(argc, argv, envp)
syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
exit(1);
}
+#ifdef SKEY
+ strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
+ pwok = authfile(addr_string);
+#endif
addrlen = sizeof (ctrl_addr);
if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
@@ -384,7 +396,11 @@ user(name)
return;
}
}
+#ifdef SKEY
+ reply(331, "%s", skey_challenge(name, pw, pwok));
+#else
reply(331, "Password required for %s.", name);
+#endif
askpasswd = 1;
/*
* Delay before reading passwd after first failed
@@ -448,7 +464,11 @@ pass(passwd)
salt = "xx";
else
salt = pw->pw_passwd;
+#ifdef SKEY
+ xpasswd = skey_crypt(passwd, salt, pw, pwok);
+#else
xpasswd = crypt(passwd, salt);
+#endif
/* The strcmp does not catch null passwords! */
if (pw == NULL || *pw->pw_passwd == '\0' ||
strcmp(xpasswd, pw->pw_passwd)) {
diff --git a/libexec/ftpd/skey-stuff.c b/libexec/ftpd/skey-stuff.c
new file mode 100644
index 000000000000..fdec650bcef0
--- /dev/null
+++ b/libexec/ftpd/skey-stuff.c
@@ -0,0 +1,23 @@
+/* Author: Wietse Venema, Eindhoven University of Technology. */
+
+#include <stdio.h>
+#include <pwd.h>
+
+#include <skey.h>
+
+/* skey_challenge - additional password prompt stuff */
+
+char *skey_challenge(name, pwd, pwok)
+char *name;
+struct passwd *pwd;
+int pwok;
+{
+ static char buf[128];
+ struct skey skey;
+
+ /* Display s/key challenge where appropriate. */
+
+ if (pwd == 0 || skeychallenge(&skey, pwd->pw_name, buf) != 0)
+ sprintf(buf, "Password required for %s.", name);
+ return (buf);
+}
diff --git a/libexec/getty/gettytab.h b/libexec/getty/gettytab.h
index 33f797a4ec5c..6f393ce3b2e6 100644
--- a/libexec/getty/gettytab.h
+++ b/libexec/getty/gettytab.h
@@ -113,9 +113,9 @@ struct gettyflags {
#define EP gettyflags[2].value
#define EPset gettyflags[2].set
#define OP gettyflags[3].value
-#define OPset gettyflags[2].set
+#define OPset gettyflags[3].set
#define AP gettyflags[4].value
-#define APset gettyflags[2].set
+#define APset gettyflags[4].set
#define EC gettyflags[5].value
#define CO gettyflags[6].value
#define CB gettyflags[7].value
diff --git a/libexec/getty/main.c b/libexec/getty/main.c
index 18b35b8c58be..7c11279bc61e 100644
--- a/libexec/getty/main.c
+++ b/libexec/getty/main.c
@@ -143,9 +143,8 @@ main(argc, argv)
int repcnt = 0;
signal(SIGINT, SIG_IGN);
-/*
signal(SIGQUIT, SIG_DFL);
-*/
+
openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
gethostname(hostname, sizeof(hostname));
if (hostname[0] == '\0')
@@ -168,10 +167,6 @@ main(argc, argv)
chown(ttyn, 0, 0);
chmod(ttyn, 0600);
revoke(ttyn);
- /*
- * Delay the open so DTR stays down long enough to be detected.
- */
- sleep(2);
while ((i = open(ttyn, O_RDWR)) == -1) {
if (repcnt % 10 == 0) {
syslog(LOG_ERR, "%s: %m", ttyn);
@@ -242,9 +237,9 @@ main(argc, argv)
if (getname()) {
register int i;
- oflush();
alarm(0);
signal(SIGALRM, SIG_DFL);
+ oflush();
if (name[0] == '-') {
puts("user names may not start with '-'.");
continue;
@@ -253,7 +248,6 @@ main(argc, argv)
continue;
set_tmode(2);
ioctl(0, TIOCSLTC, &ltc);
- signal(SIGINT, SIG_DFL);
for (i = 0; environ[i] != (char *)0; i++)
env[i] = environ[i];
makeenv(&env[i]);
@@ -262,9 +256,9 @@ main(argc, argv)
syslog(LOG_ERR, "%s: %m", LO);
exit(1);
}
+ signal(SIGINT, SIG_IGN);
alarm(0);
signal(SIGALRM, SIG_DFL);
- signal(SIGINT, SIG_IGN);
if (NX && *NX)
tname = NX;
}
diff --git a/libexec/pppd/Makefile b/libexec/pppd/Makefile
index eb2c0066c78c..196adb0b2d22 100644
--- a/libexec/pppd/Makefile
+++ b/libexec/pppd/Makefile
@@ -1,23 +1,25 @@
-#
-# $Id: Makefile,v 1.2 1993/10/14 11:18:55 rgrimes Exp $
-#
-PROG= pppd
-MAN8= pppd.8
-SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c logwtmp.c chap.c md5.c
-MD5SRCS = md5driver.c
+# $Id: Makefile,v 1.3 1994/03/30 09:31:19 jkh Exp $
DEBUG_FLAGS = -DDEBUGFSM -DDEBUGLCP -DDEBUGIPCP -DDEBUGUPAP -DDEBUGCHAP \
-DDEBUGMAIN
+CFLAGS+= ${DEBUG_FLAGS}
+
+PROG= pppd
+SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c \
+ auth.c options.c sys-bsd.c
+MAN8= pppd.8
+BINMODE=4555
+BINGRP= daemon
+BINOWN= root
-CFLAGS= -DKVMLIB -DPPP ${DEBUG_FLAGS}
+.if exists(/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
DPADD+= ${LIBUTIL}
LDADD+= -lutil
-BINOWN= root
-BINGRP= daemon
-BINMODE= 4555
-
md5driver: md5.h md5.o md5driver.o
$(CC) $(CFLAGS) -o md5driver md5driver.o md5.o
diff --git a/libexec/pppd/README b/libexec/pppd/README
new file mode 100644
index 000000000000..c393aa94a781
--- /dev/null
+++ b/libexec/pppd/README
@@ -0,0 +1,284 @@
+ pppd-2.0 alpha release notes
+ Paul Mackerras 18 Oct 1993
+
+This file details the new and changed features in pppd since version 1.3.
+Briefly:
+ - the protocol code has been updated to conform with
+ RFCs 1331, 1332 and 1334
+ - security has been improved
+ - functionality has been improved in various ways.
+
+
+NEW FEATURES
+
+* The option negotiation automaton has been updated to RFC1331. LCP
+now rejects the Quality Protocol option, since LQR is not implemented
+yet. IPCP now uses the IP-Address option, and falls back to the old
+IP-Addresses option if the IP-Address option is rejected. IPCP also
+uses the new form of the VJ-Compression option.
+
+RFC1331 also defines the "passive" option differently from earlier
+versions: "passive" now means that the automaton outputs configure-
+request packets initially, but does not close down if no answer is
+received. A valid configure-request received will restart the
+negotiation. The "silent" option has been added with the old meaning
+of "passive", i.e. the automaton will not output configure-requests
+until it receives a valid one from the peer.
+
+* Options can be taken from files as well as the command line. pppd
+reads options from the files /etc/ppp/options and $HOME/.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 ("). Backslash (\) quotes the
+following character. A hash (#) starts a comment, which continues
+until the end of the line.
+
+* On those systems, such as NetBSD, where the serial line speed is
+stored in the termios structure in bits per second (i.e. B9600 ==
+9600), it is possible to set any speed.
+
+
+AUTHENTICATION
+
+Previous versions of pppd have provided no control over which IP
+addresses the peer can use. Thus it is possible for the peer to
+impersonate another host on the local network, leading to various
+security holes. In addition, the authentication mechanisms were quite
+weak: if the peer refused to agree to authenticate, pppd would print a
+warning message but still allow the link to come up. The CHAP
+implementation also appeared to be quite broken (has anybody actually
+used it?).
+
+This new version of pppd addresses these problems. My aim has been to
+provide 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 which cannot
+be disabled by users. Thus the new pppd can made setuid-root and run
+by users.
+
+As a security feature, if pppd is compiled with -DREQ_SYSOPTIONS=1 on
+the command, pppd will refuse to run unless it can read the file
+/etc/ppp/options.
+
+The options related to authentication are:
+
+ auth Require authentication from the peer. If neither
+ +chap or +pap is also given, either CHAP or PAP
+ authentication will be accepted.
+ +chap Require CHAP authentication from the peer.
+ +pap Require PAP authentication from the peer.
+ -chap Don't agree to authenticate ourselves with the peer
+ using CHAP.
+ -pap Don't agree to authenticate ourselves using PAP.
+ +ua <f> Get username and password for authenticating ourselves
+ with the peer using PAP from file <f>.
+ name <n> Use <n> as the local name for authentication.
+ usehostname Use this machine's hostname as the local name for
+ authentication.
+ remotename <n> Use <n> as the name of the peer for authentication.
+ login If the peer authenticates using PAP, check the
+ supplied username and password against the system
+ password database, and make a wtmp entry.
+ user <n> Use <n> as the username for authenticating ourselves
+ using PAP.
+
+The defaults are 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.
+
+Authentication is based on secrets, which are selected from 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 each end can be both a server
+and client, and that different protocols can be used in the two
+directions if desired.
+
+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, server, secret. 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, 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, pppd takes the best match, i.e.
+the match with the fewest wildcards.
+
+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:
+
+ if the `usehostname' option is given,
+ then the local name is the hostname of this machine
+ (with the domain appended, if given)
+
+ else if the `name' option is given,
+ then use the argument of the first `name' option seen
+
+ else if the local IP address is specified with a
+ host name (e.g. `sirius:')
+ then use that host name
+
+ else use the hostname of this machine
+ (with the domain appended, if given)
+
+When authenticating ourselves using PAP, there is also a `username'
+which is the local name by default, but can be set with the `user'
+option or the `+ua' option.
+
+The remote name is set as follows:
+
+ if the `remotename' option is given,
+ then use the argument of the last `remotename' option seen
+
+ else if the remote IP address is specified with a
+ host name (e.g. `avago:')
+ then use that host name
+
+ else the remote name is the null string "".
+
+Secrets are selected from the PAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client ==
+username specified in the PAP authenticate-request, and server ==
+local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == our username, server == remote name.
+
+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 `login' 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.
+
+Secrets are selected from the CHAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client == name
+specified in the CHAP-Response message, and server == local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == local name, and server == name specified in the
+CHAP-Challenge message.
+
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If authentication
+fails, 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 cannot be sent or received until IPCP is
+successfully opened.
+
+(some examples needed here perhaps)
+
+
+ROUTING
+
+Setting the addresses on a ppp interface is sufficient to create a
+host route to the remote end of the link. 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 `defaultroute' option causes pppd to create such a
+default route when IPCP comes up, and delete it when the link is
+terminated.
+
+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 `proxyarp' option causes pppd
+to look for a network interface (an interface supporting broadcast and
+ARP, which is up and not a point-to-point or loopback interface) on
+the same subnet as the remote host. 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.
+
+
+OTHER NEW AND CHANGED OPTIONS
+
+ modem Use modem control lines (not fully implemented
+ yet)
+ local Don't use modem control lines
+ persist Keep reopening connection (not fully
+ implemented yet)
+
+ lcp-restart <n> Set timeout for LCP retransmissions to <n>
+ seconds (default 3 seconds)
+ lcp-max-terminate <n> Set maximum number of LCP terminate-request
+ transmissions (default 2)
+ lcp-max-configure <n> Set maximum number of LCP configure-request
+ transmissions (default 10)
+ lcp-max-failure <n> Set maximum number of LCP configure-Naks sent
+ before converting to configure-rejects
+ (default 10)
+
+ ipcp-restart <n> Set timeout for IPCP retransmissions to <n>
+ seconds (default 3 seconds)
+ ipcp-max-terminate <n> Set maximum number of IPCP
+ terminate-request transmissions (default 2)
+ ipcp-max-configure <n> Set maximum number of IPCP
+ configure-request transmissions (default 10)
+ ipcp-max-failure <n> Set maximum number of IPCP configure-Naks
+ sent before converting to configure-rejects
+ (default 10)
+
+ upap-restart <n> Set timeout for PAP retransmissions to
+ <n> seconds (default 3 seconds)
+ upap-max-authreq <n> Set maximum number of Authenticate-request
+ retransmissions (default 10)
+
+ chap-restart <n> Set timeout for CHAP retransmissions to
+ <n> seconds (default 3 seconds)
+ chap-max-challenge <n> Set maximum number of CHAP Challenge
+ retransmissions (default 10)
+ chap-interval <n> Set the interval between CHAP rechallenges
+ (default 0, meaning infinity)
+
+The -ua option no longer exists.
+
+
+SOFTWARE RESTRUCTURING
+
+Many of the source files for pppd have changed significantly from
+ppp-1.3, upon which it is based. In particular:
+
+- the macros for system-dependent operations in pppd.h have mostly
+been removed. Instead these operations are performed by procedures in
+sys-bsd.c (for BSD-4.4ish systems like NetBSD, 386BSD, etc.) or
+sys-str.c (for SunOS-based systems using STREAMS). (I got sick of
+having to recompile everything every time I wanted to change one of
+those horrible macros.)
+
+- most of the system-dependent code in main.c has also been removed to
+sys-bsd.c and sys-str.c.
+
+- the option processing code in main.c has been removed to options.c.
+
+- the authentication code in main.c has been removed to auth.c, which
+also contains substantial amounts of new code.
+
+- fsm.c has changed significantly, and lcp.c, ipcp.c, and upap.c have
+changed somewhat. chap.c has also changed significantly.
+
+
+STILL TO DO
+
+* sort out appropriate modem control and implement the persist option
+properly; add an `answer' option for auto-answering a modem.
+
+* add demand dialing.
+
+* implement link quality monitoring.
+
+* implement other network control protocols.
+
+* at the ppp network interface level: provide support for the receive
+asyncmap, plus control over VJ slot-id compression and the maximum
+number of slots.
diff --git a/libexec/pppd/args.h b/libexec/pppd/args.h
index 80f5526d2d07..a2bfdffd20b1 100644
--- a/libexec/pppd/args.h
+++ b/libexec/pppd/args.h
@@ -1,5 +1,6 @@
/*
* neat macro from ka9q to "do the right thing" with ansi prototypes
+ * $Id: args.h,v 1.2 1994/03/30 09:31:21 jkh Exp $
*/
#ifndef __ARGS
diff --git a/libexec/pppd/auth.c b/libexec/pppd/auth.c
new file mode 100644
index 000000000000..9f8d5766b9ed
--- /dev/null
+++ b/libexec/pppd/auth.c
@@ -0,0 +1,828 @@
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * 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) 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: auth.c,v 1.1 1994/03/30 09:38:10 jkh Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+#ifdef sparc
+#include <alloca.h>
+#ifndef __GNUC__
+/* why alloca.h doesn't define what alloca() returns is a mystery */
+/* char *alloca __ARGS((int)); */
+#endif /*__GNUC__*/
+#endif /*sparc*/
+
+/* Used for storing a sequence of words. Usually malloced. */
+struct wordlist {
+ struct wordlist *next;
+ char word[1];
+};
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER 1
+#define NONWILD_CLIENT 2
+
+#define ISWILD(word) (word[0] == '*' && word[1] == 0)
+
+#define FALSE 0
+#define TRUE 1
+
+extern char user[];
+extern char passwd[];
+extern char devname[];
+extern char our_name[];
+extern char remote_name[];
+extern char hostname[];
+extern int uselogin;
+extern int usehostname;
+extern int auth_required;
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[_NPPP];
+static int logged_in;
+static struct wordlist *addresses[_NPPP];
+
+/* Bits in auth_pending[] */
+#define UPAP_WITHPEER 1
+#define UPAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+/* Prototypes */
+void check_access __ARGS((FILE *, char *));
+
+static int login __ARGS((char *, char *, char **, int *));
+static void logout __ARGS((void));
+static int get_upap_passwd __ARGS((void));
+static int have_upap_secret __ARGS((void));
+static int have_chap_secret __ARGS((char *, char *));
+static int scan_authfile __ARGS((FILE *, char *, char *, char *,
+ struct wordlist **, char *));
+static void free_wordlist __ARGS((struct wordlist *));
+
+extern char *crypt __ARGS((char *, char *));
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(unit)
+ int unit;
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(unit)
+ int unit;
+{
+ if (logged_in)
+ logout();
+ if (lcp_wantoptions[unit].restart) {
+ lcp_lowerdown(unit);
+ lcp_lowerup(unit);
+ } else
+ EXIT(unit);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(unit)
+ int unit;
+{
+ int auth;
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *go = &lcp_gotoptions[unit];
+ lcp_options *ho = &lcp_hisoptions[unit];
+
+ if (auth_required && !(go->neg_chap || go->neg_upap)) {
+ /*
+ * We wanted the peer to authenticate himself, and he refused:
+ * tell him to go away.
+ */
+ syslog(LOG_WARNING, "peer refused to authenticate");
+ lcp_close(unit);
+ return;
+ }
+
+ auth = 0;
+ if (go->neg_chap) {
+ ChapAuthPeer(unit, our_name, go->chap_mdtype);
+ auth |= CHAP_PEER;
+ } else if (go->neg_upap) {
+ upap_authpeer(unit);
+ auth |= UPAP_PEER;
+ }
+ if (ho->neg_chap) {
+ ChapAuthWithPeer(unit, our_name, ho->chap_mdtype);
+ auth |= CHAP_WITHPEER;
+ } else if (ho->neg_upap) {
+ upap_authwithpeer(unit, user, passwd);
+ auth |= UPAP_WITHPEER;
+ }
+ auth_pending[unit] = auth;
+
+ if (!auth)
+ ipcp_open(unit);
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * Authentication failure: take the link down
+ */
+ lcp_close(unit);
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case CHAP:
+ bit = CHAP_PEER;
+ break;
+ case UPAP:
+ bit = UPAP_PEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ return;
+ }
+
+ /*
+ * If there is no more authentication still to be done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ ipcp_open(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(unit, protocol)
+ int unit, protocol;
+{
+ /*
+ * We've failed to authenticate ourselves to our peer.
+ * He'll probably take the link down, and there's not much
+ * we can do except wait for that.
+ */
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(unit, protocol)
+ int unit, protocol;
+{
+ int bit;
+
+ switch (protocol) {
+ case CHAP:
+ bit = CHAP_WITHPEER;
+ break;
+ case UPAP:
+ bit = UPAP_WITHPEER;
+ break;
+ default:
+ syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+ protocol);
+ }
+
+ /*
+ * If there is no more authentication still being done,
+ * proceed to the network phase.
+ */
+ if ((auth_pending[unit] &= ~bit) == 0)
+ ipcp_open(unit);
+}
+
+
+/*
+ * check_auth_options - called to check authentication options.
+ */
+void
+check_auth_options()
+{
+ lcp_options *wo = &lcp_wantoptions[0];
+ lcp_options *ao = &lcp_allowoptions[0];
+
+ /* Default our_name to hostname, and user to our_name */
+ if (our_name[0] == 0 || usehostname)
+ strcpy(our_name, hostname);
+ if (user[0] == 0)
+ strcpy(user, our_name);
+
+ /* If authentication is required, ask peer for CHAP or PAP. */
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ wo->neg_chap = 1;
+ wo->neg_upap = 1;
+ }
+
+ /*
+ * Check whether we have appropriate secrets to use
+ * to authenticate ourselves and/or 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;
+
+ if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+ fprintf(stderr, "\
+pppd: peer authentication required but no authentication files accessible\n");
+ exit(1);
+ }
+
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file. If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Authentication failed.
+ * UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
+ int unit;
+ char *auser;
+ int userlen;
+ char *apasswd;
+ int passwdlen;
+ char **msg;
+ int *msglen;
+{
+ int ret;
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char passwd[256], user[256];
+ char secret[MAXWORDLEN];
+ static int attempts = 0;
+
+ /*
+ * Make copies of apasswd and auser, then null-terminate them.
+ */
+ BCOPY(apasswd, passwd, passwdlen);
+ passwd[passwdlen] = '\0';
+ BCOPY(auser, user, userlen);
+ user[userlen] = '\0';
+
+ /*
+ * Open the file of upap secrets and scan for a suitable secret
+ * for authenticating this user.
+ */
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ 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;
+ }
+
+ } else {
+ check_access(f, filename);
+ if (scan_authfile(f, user, our_name, secret, &addrs, filename) < 0
+ || (secret[0] != 0 && strcmp(passwd, secret) != 0
+ && strcmp(crypt(passwd, secret), secret) != 0)) {
+ syslog(LOG_WARNING, "upap authentication failure for %s", user);
+ ret = UPAP_AUTHNAK;
+ }
+ fclose(f);
+ }
+
+ if (uselogin && ret == UPAP_AUTHACK) {
+ ret = login(user, passwd, msg, msglen);
+ if (ret == UPAP_AUTHNAK) {
+ syslog(LOG_WARNING, "upap login failure for %s", user);
+ }
+ }
+
+ if (ret == UPAP_AUTHNAK) {
+ *msg = "Login incorrect";
+ *msglen = strlen(*msg);
+ /*
+ * Frustrate passwd stealer programs.
+ * Allow 10 tries, but start backing off after 3 (stolen from login).
+ * On 10'th, drop the connection.
+ */
+ if (attempts++ >= 10) {
+ syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
+ attempts, devname, user);
+ quit();
+ }
+ if (attempts > 3)
+ sleep((u_int) (attempts - 3) * 5);
+ if (addrs != NULL)
+ free_wordlist(addrs);
+
+ } else {
+ attempts = 0; /* Reset count */
+ *msg = "Login ok";
+ *msglen = strlen(*msg);
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ return ret;
+}
+
+
+/*
+ * login - Check the user name and password against the system
+ * password database, and login the user if OK.
+ *
+ * returns:
+ * UPAP_AUTHNAK: Login failed.
+ * UPAP_AUTHACK: Login succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+static int
+login(user, passwd, msg, msglen)
+ char *user;
+ char *passwd;
+ char **msg;
+ int *msglen;
+{
+ struct passwd *pw;
+ char *epasswd;
+ char *tty;
+
+ if ((pw = getpwnam(user)) == NULL) {
+ return (UPAP_AUTHNAK);
+ }
+
+ /*
+ * XXX If no passwd, let them login without one.
+ */
+ if (pw->pw_passwd == '\0') {
+ return (UPAP_AUTHACK);
+ }
+
+ epasswd = crypt(passwd, pw->pw_passwd);
+ if (strcmp(epasswd, pw->pw_passwd)) {
+ return (UPAP_AUTHNAK);
+ }
+
+ syslog(LOG_INFO, "user %s logged in", user);
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ logwtmp(tty, user, ""); /* Add wtmp login entry */
+ logged_in = TRUE;
+
+ return (UPAP_AUTHACK);
+}
+
+/*
+ * logout - Logout the user.
+ */
+static void
+logout()
+{
+ char *tty;
+
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ logwtmp(tty, "", ""); /* Wipe out wtmp logout entry */
+ logged_in = FALSE;
+}
+
+
+/*
+ * get_upap_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()
+{
+ char *filename;
+ FILE *f;
+ struct wordlist *addrs;
+ char secret[MAXWORDLEN];
+
+ filename = _PATH_UPAPFILE;
+ addrs = NULL;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+ check_access(f, filename);
+ if (scan_authfile(f, user, remote_name, secret, NULL, filename) < 0)
+ return 0;
+ strncpy(passwd, secret, MAXSECRETLEN);
+ passwd[MAXSECRETLEN-1] = 0;
+ return 1;
+}
+
+
+/*
+ * have_upap_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()
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_UPAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ ret = scan_authfile(f, NULL, our_name, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'. Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(client, server)
+ char *client;
+ char *server;
+{
+ FILE *f;
+ int ret;
+ char *filename;
+
+ filename = _PATH_CHAPFILE;
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return 0;
+
+ if (client[0] == 0)
+ client = NULL;
+ else if (server[0] == 0)
+ server = NULL;
+
+ ret = scan_authfile(f, client, server, NULL, NULL, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(unit, client, server, secret, secret_len, save_addrs)
+ int unit;
+ char *client;
+ char *server;
+ char *secret;
+ int *secret_len;
+{
+ FILE *f;
+ int ret, len;
+ char *filename;
+ struct wordlist *addrs;
+ char secbuf[MAXWORDLEN];
+
+ filename = _PATH_CHAPFILE;
+ addrs = NULL;
+ secbuf[0] = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ syslog(LOG_ERR, "Can't open chap secret file %s: %m", filename);
+ return 0;
+ }
+ check_access(f, filename);
+
+ ret = scan_authfile(f, client, server, secbuf, &addrs, filename);
+ fclose(f);
+ if (ret < 0)
+ return 0;
+
+ if (save_addrs) {
+ if (addresses[unit] != NULL)
+ free_wordlist(addresses[unit]);
+ addresses[unit] = addrs;
+ }
+
+ len = strlen(secbuf);
+ if (len > MAXSECRETLEN) {
+ syslog(LOG_ERR, "Secret for %s on %s is too long", client, server);
+ len = MAXSECRETLEN;
+ }
+ BCOPY(secbuf, secret, len);
+ *secret_len = len;
+
+ return 1;
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address. Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(unit, addr)
+ int unit;
+ u_long addr;
+{
+ u_long a;
+ struct hostent *hp;
+ struct wordlist *addrs;
+
+ if ((addrs = addresses[unit]) == NULL)
+ return 1; /* no restriction */
+
+ for (; addrs != NULL; addrs = addrs->next) {
+ /* "-" means no addresses authorized */
+ if (strcmp(addrs->word, "-") == 0)
+ break;
+ 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_long *)hp->h_addr;
+ }
+ if (addr == a)
+ return 1;
+ }
+ return 0; /* not in list => can't have it */
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+void
+check_access(f, filename)
+ FILE *f;
+ char *filename;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(f), &sbuf) < 0) {
+ syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename);
+ } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+ syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename);
+ }
+}
+
+
+/*
+ * scan_authfile - Scan an authorization file for a secret suitable
+ * for authenticating `client' on `server'. The return value is -1
+ * if no secret is found, otherwise >= 0. The return value has
+ * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
+ * NONWILD_SERVER set if the secret didn't have "*" for the server.
+ * Any following words on the line (i.e. address authorization
+ * info) are placed in a wordlist and returned in *addrs.
+ */
+static int
+scan_authfile(f, client, server, secret, addrs, filename)
+ FILE *f;
+ char *client;
+ char *server;
+ char *secret;
+ struct wordlist **addrs;
+ char *filename;
+{
+ int newline, xxx;
+ int got_flag, best_flag;
+ FILE *sf;
+ struct wordlist *ap, *addr_list, *addr_last;
+ char word[MAXWORDLEN];
+ char atfile[MAXWORDLEN];
+
+ if (addrs != NULL)
+ *addrs = NULL;
+ addr_list = NULL;
+ if (!getword(f, word, &newline, filename))
+ return -1; /* file is empty??? */
+ newline = 1;
+ best_flag = -1;
+ for (;;) {
+ /*
+ * Skip until we find a word at the start of a line.
+ */
+ while (!newline && getword(f, word, &newline, filename))
+ ;
+ if (!newline)
+ break; /* got to end of file */
+
+ /*
+ * Got a client - check if it's a match or a wildcard.
+ */
+ got_flag = 0;
+ if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
+ newline = 0;
+ continue;
+ }
+ if (!ISWILD(word))
+ got_flag = NONWILD_CLIENT;
+
+ /*
+ * Now get a server and check if it matches.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+ if (server != NULL && strcmp(word, server) != 0 && !ISWILD(word))
+ continue;
+ if (!ISWILD(word))
+ got_flag |= NONWILD_SERVER;
+
+ /*
+ * Got some sort of a match - see if it's better than what
+ * we have already.
+ */
+ if (got_flag <= best_flag)
+ continue;
+
+ /*
+ * Get the secret.
+ */
+ if (!getword(f, word, &newline, filename))
+ break;
+ if (newline)
+ continue;
+
+ /*
+ * Special syntax: @filename means read secret from file.
+ */
+ if (word[0] == '@') {
+ strcpy(atfile, word+1);
+ if ((sf = fopen(atfile, "r")) == NULL) {
+ syslog(LOG_WARNING, "can't open indirect secret file %s",
+ atfile);
+ continue;
+ }
+ check_access(sf, atfile);
+ if (!getword(sf, word, &xxx, atfile)) {
+ syslog(LOG_WARNING, "no secret in indirect secret file %s",
+ atfile);
+ fclose(sf);
+ continue;
+ }
+ fclose(sf);
+ }
+ if (secret != NULL)
+ strcpy(secret, word);
+
+ best_flag = got_flag;
+
+ /*
+ * Now read address authorization info and make a wordlist.
+ */
+ if (addr_list)
+ free_wordlist(addr_list);
+ addr_list = NULL;
+ for (;;) {
+ if (!getword(f, word, &newline, filename) || newline)
+ break;
+ ap = (struct wordlist *) malloc(sizeof(struct wordlist)
+ + strlen(word));
+ if (ap == NULL)
+ novm("authorized addresses");
+ ap->next = NULL;
+ strcpy(ap->word, word);
+ if (addr_list == NULL)
+ addr_list = ap;
+ else
+ addr_last->next = ap;
+ addr_last = ap;
+ }
+ if (!newline)
+ break;
+ }
+
+ if (addrs != NULL)
+ *addrs = addr_list;
+ else if (addr_list != NULL)
+ free_wordlist(addr_list);
+
+ return best_flag;
+}
+
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(wp)
+ struct wordlist *wp;
+{
+ struct wordlist *next;
+
+ while (wp != NULL) {
+ next = wp->next;
+ free(wp);
+ wp = next;
+ }
+}
diff --git a/libexec/pppd/callout.h b/libexec/pppd/callout.h
index cb265f1ea083..65b8319fc893 100644
--- a/libexec/pppd/callout.h
+++ b/libexec/pppd/callout.h
@@ -3,6 +3,8 @@
/* to a pointer to a function of type void (generic pointer) as per */
/* ANSI C */
+/* $Id: callout.h,v 1.2 1994/03/30 09:31:22 jkh Exp $ */
+
#ifndef _ppp_callout_h
#define _ppp_callout_h
diff --git a/libexec/pppd/chap.c b/libexec/pppd/chap.c
index 6643db16c0dc..ebdc6537fb0c 100644
--- a/libexec/pppd/chap.c
+++ b/libexec/pppd/chap.c
@@ -18,6 +18,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: chap.c,v 1.3 1994/03/30 09:38:11 jkh Exp $";
+#endif
+
/*
* TODO:
*/
@@ -27,33 +31,23 @@
#include <sys/time.h>
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/socket.h>
-#include <net/if.h>
-#include <sys/stream.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
-#include "fsm.h"
-#include "lcp.h"
#include "chap.h"
-#include "upap.h"
-#include "ipcp.h"
#include "md5.h"
-chap_state chap[NPPP]; /* CHAP state; one for each unit */
+chap_state chap[_NPPP]; /* CHAP state; one for each unit */
-static void ChapTimeout __ARGS((caddr_t));
+static void ChapChallengeTimeout __ARGS((caddr_t));
+static void ChapResponseTimeout __ARGS((caddr_t));
static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveResponse __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, int, int));
static void ChapReceiveFailure __ARGS((chap_state *, u_char *, int, int));
-static void ChapSendStatus __ARGS((chap_state *, int, int,
- u_char *, int));
+static void ChapSendStatus __ARGS((chap_state *, int));
static void ChapSendChallenge __ARGS((chap_state *));
-static void ChapSendResponse __ARGS((chap_state *, int, u_char *, int));
-static void ChapGenChallenge __ARGS((int, u_char *));
+static void ChapSendResponse __ARGS((chap_state *));
+static void ChapGenChallenge __ARGS((chap_state *));
extern double drand48 __ARGS((void));
extern void srand48 __ARGS((long));
@@ -62,21 +56,18 @@ extern void srand48 __ARGS((long));
* ChapInit - Initialize a CHAP unit.
*/
void
- ChapInit(unit)
-int unit;
+ChapInit(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
-
- cstate->unit = unit;
- cstate->chal_str[0] = '\000';
- cstate->chal_len = 0;
- cstate->clientstate = CHAPCS_CLOSED;
- cstate->serverstate = CHAPSS_CLOSED;
- cstate->flags = 0;
- cstate->id = 0;
- cstate->timeouttime = CHAP_DEFTIMEOUT;
- cstate->retransmits = 0;
- srand48((long) time(NULL)); /* joggle random number generator */
+ chap_state *cstate = &chap[unit];
+
+ BZERO(cstate, sizeof(*cstate));
+ cstate->unit = unit;
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
+ cstate->timeouttime = CHAP_DEFTIMEOUT;
+ cstate->max_transmits = CHAP_DEFTRANSMITS;
+ srand48((long) time(NULL)); /* joggle random number generator */
}
@@ -85,35 +76,29 @@ int unit;
*
*/
void
- ChapAuthWithPeer(unit)
-int unit;
+ChapAuthWithPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
{
- chap_state *cstate = &chap[unit];
-
- cstate->flags &= ~CHAPF_AWPPENDING; /* Clear pending flag */
-
- /* Protect against programming errors that compromise security */
- if (cstate->serverstate != CHAPSS_CLOSED ||
- cstate->flags & CHAPF_APPENDING) {
- CHAPDEBUG((LOG_INFO,
- "ChapAuthWithPeer: we were called already!"))
- return;
- }
-
- if (cstate->clientstate == CHAPCS_CHALLENGE_SENT || /* should we be here? */
- cstate->clientstate == CHAPCS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(cstate->flags & CHAPF_LOWERUP)) {
- cstate->flags |= CHAPF_AWPPENDING; /* Nah, Wait */
- return;
- }
- ChapSendChallenge(cstate); /* crank it up dude! */
- TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime);
- /* set-up timeout */
- cstate->clientstate = CHAPCS_CHALLENGE_SENT; /* update state */
- cstate->retransmits = 0;
+ chap_state *cstate = &chap[unit];
+
+ cstate->resp_name = our_name;
+ cstate->resp_type = digest;
+
+ if (cstate->clientstate == CHAPCS_INITIAL ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->clientstate = CHAPCS_PENDING;
+ return;
+ }
+
+ /*
+ * We get here as a result of LCP coming up.
+ * So even if CHAP was open before, we will
+ * have to re-authenticate ourselves.
+ */
+ cstate->clientstate = CHAPCS_LISTEN;
}
@@ -121,44 +106,92 @@ int unit;
* ChapAuthPeer - Authenticate our peer (start server).
*/
void
- ChapAuthPeer(unit)
-int unit;
+ChapAuthPeer(unit, our_name, digest)
+ int unit;
+ char *our_name;
+ int digest;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags &= ~CHAPF_APPENDING; /* Clear pending flag */
-
- /* Already authenticat{ed,ing}? */
- if (cstate->serverstate == CHAPSS_LISTEN ||
- cstate->serverstate == CHAPSS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(cstate->flags & CHAPF_LOWERUP)) {
- cstate->flags |= CHAPF_APPENDING; /* Wait for desired event */
- return;
- }
- cstate->serverstate = CHAPSS_LISTEN;
+ cstate->chal_name = our_name;
+ cstate->chal_type = digest;
+
+ if (cstate->serverstate == CHAPSS_INITIAL ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ /* lower layer isn't up - wait until later */
+ cstate->serverstate = CHAPSS_PENDING;
+ return;
+ }
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate); /* crank it up dude! */
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
}
/*
- * ChapTimeout - Timeout expired.
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
*/
static void
- ChapTimeout(arg)
-caddr_t arg;
+ChapChallengeTimeout(arg)
+ caddr_t arg;
{
- chap_state *cstate = (chap_state *) arg;
+ chap_state *cstate = (chap_state *) arg;
- /* if we aren't sending challenges, don't worry. then again we */
- /* probably shouldn't be here either */
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT)
- return;
-
- ChapSendChallenge(cstate); /* Send challenge */
- TIMEOUT(ChapTimeout, (caddr_t) cstate, cstate->timeouttime);
- ++cstate->retransmits;
+ /* if we aren't sending challenges, don't worry. then again we */
+ /* probably shouldn't be here either */
+ if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+ cstate->serverstate != CHAPSS_RECHALLENGE)
+ return;
+
+ if (cstate->chal_transmits >= cstate->max_transmits) {
+ /* give up on peer */
+ syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, CHAP);
+ return;
+ }
+
+ ChapSendChallenge(cstate); /* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->clientstate != CHAPCS_RESPONSE)
+ return;
+
+ ChapSendResponse(cstate); /* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(arg)
+ caddr_t arg;
+{
+ chap_state *cstate = (chap_state *) arg;
+
+ /* if we aren't sending a response, don't worry. */
+ if (cstate->serverstate != CHAPSS_OPEN)
+ return;
+
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_RECHALLENGE;
+
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
}
@@ -168,16 +201,23 @@ caddr_t arg;
* Start up if we have pending requests.
*/
void
- ChapLowerUp(unit)
-int unit;
+ChapLowerUp(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags |= CHAPF_LOWERUP;
- if (cstate->flags & CHAPF_AWPPENDING) /* were we attempting authwithpeer? */
- ChapAuthWithPeer(unit); /* Try it now */
- if (cstate->flags & CHAPF_APPENDING) /* or authpeer? */
- ChapAuthPeer(unit);
+ if (cstate->clientstate == CHAPCS_INITIAL)
+ cstate->clientstate = CHAPCS_CLOSED;
+ else if (cstate->clientstate == CHAPCS_PENDING)
+ cstate->clientstate = CHAPCS_LISTEN;
+
+ if (cstate->serverstate == CHAPSS_INITIAL)
+ cstate->serverstate = CHAPSS_CLOSED;
+ else if (cstate->serverstate == CHAPSS_PENDING) {
+ ChapGenChallenge(cstate);
+ ChapSendChallenge(cstate);
+ cstate->serverstate = CHAPSS_INITIAL_CHAL;
+ }
}
@@ -187,20 +227,23 @@ int unit;
* Cancel all timeouts.
*/
void
- ChapLowerDown(unit)
-int unit;
+ChapLowerDown(unit)
+ int unit;
{
- chap_state *cstate = &chap[unit];
+ chap_state *cstate = &chap[unit];
- cstate->flags &= ~CHAPF_LOWERUP;
-
- if (cstate->clientstate == CHAPCS_CHALLENGE_SENT) /* Timeout pending? */
- UNTIMEOUT(ChapTimeout, (caddr_t) cstate); /* Cancel timeout */
-
- if (cstate->serverstate == CHAPSS_OPEN) /* have we successfully authed? */
- LOGOUT(unit);
- cstate->clientstate = CHAPCS_CLOSED;
- cstate->serverstate = CHAPSS_CLOSED;
+ /* Timeout(s) pending? Cancel if so. */
+ if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+ cstate->serverstate == CHAPSS_RECHALLENGE)
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+ else if (cstate->serverstate == CHAPSS_OPEN
+ && cstate->chal_interval != 0)
+ UNTIMEOUT(ChapRechallenge, (caddr_t) cstate);
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
+
+ cstate->clientstate = CHAPCS_INITIAL;
+ cstate->serverstate = CHAPSS_INITIAL;
}
@@ -208,13 +251,18 @@ int unit;
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
void
- ChapProtocolReject(unit)
-int unit;
+ChapProtocolReject(unit)
+ int unit;
{
- ChapLowerDown(unit); /* shutdown chap */
-
-
-/* Note: should we bail here if chap is required? */
+ chap_state *cstate = &chap[unit];
+
+ if (cstate->serverstate != CHAPSS_INITIAL &&
+ cstate->serverstate != CHAPSS_CLOSED)
+ auth_peer_fail(unit, CHAP);
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED)
+ auth_withpeer_fail(unit, CHAP);
+ ChapLowerDown(unit); /* shutdown chap */
}
@@ -222,311 +270,335 @@ int unit;
* ChapInput - Input CHAP packet.
*/
void
- ChapInput(unit, inpacket, packet_len)
-int unit;
-u_char *inpacket;
-int packet_len;
+ChapInput(unit, inpacket, packet_len)
+ int unit;
+ u_char *inpacket;
+ int packet_len;
{
- chap_state *cstate = &chap[unit];
- u_char *inp;
- u_char code, id;
- int len;
+ chap_state *cstate = &chap[unit];
+ u_char *inp;
+ u_char code, id;
+ int len;
- /*
- * Parse header (code, id and length).
- * If packet too short, drop it.
- */
- inp = inpacket;
- if (packet_len < CHAP_HEADERLEN) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."))
- return;
- }
- GETCHAR(code, inp);
- GETCHAR(id, inp);
- GETSHORT(len, inp);
- if (len < CHAP_HEADERLEN) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."))
- return;
- }
- if (len > packet_len) {
- CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."))
- return;
- }
- len -= CHAP_HEADERLEN;
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (packet_len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
+ return;
+ }
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < CHAP_HEADERLEN) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
+ return;
+ }
+ if (len > packet_len) {
+ CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
+ return;
+ }
+ len -= CHAP_HEADERLEN;
- /*
- * Action depends on code.
- */
- switch (code) {
- case CHAP_CHALLENGE:
- ChapReceiveChallenge(cstate, inp, id, len);
- break;
+ /*
+ * Action depends on code (as in fact it usually does :-).
+ */
+ switch (code) {
+ case CHAP_CHALLENGE:
+ ChapReceiveChallenge(cstate, inp, id, len);
+ break;
- case CHAP_RESPONSE:
- ChapReceiveResponse(cstate, inp, id, len);
- break;
+ case CHAP_RESPONSE:
+ ChapReceiveResponse(cstate, inp, id, len);
+ break;
- case CHAP_FAILURE:
- ChapReceiveFailure(cstate, inp, id, len);
- break;
-
- case CHAP_SUCCESS:
- ChapReceiveSuccess(cstate, inp, id, len);
- break;
-
- default: /* Need code reject? */
- syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
- break;
- }
-}
-
+ case CHAP_FAILURE:
+ ChapReceiveFailure(cstate, inp, id, len);
+ break;
-/*
- * ChapReceiveChallenge - Receive Challenge.
- */
-static void
- ChapReceiveChallenge(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-int id;
-int len;
-{
- u_char rchallenge_len;
- u_char *rchallenge;
- u_char secret[MAX_SECRET_LEN];
- int secret_len;
- u_char rhostname[256];
- u_char buf[256];
- MD5_CTX mdContext;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id))
- if (cstate->serverstate != CHAPSS_LISTEN) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received challenge but not in listen state"))
- return;
- }
-
- if (len < 2) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
- return;
- }
- GETCHAR(rchallenge_len, inp);
- len -= sizeof (u_char) + rchallenge_len ;
- if (len < 0) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."))
- return;
- }
- rchallenge = inp;
- INCPTR(rchallenge_len, inp);
-
- BCOPY(inp, rhostname, len);
- rhostname[len] = '\000';
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
- rhostname))
- GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
-
- BCOPY(rchallenge, buf, rchallenge_len); /* copy challenge into buffer */
- BCOPY(secret, buf + rchallenge_len, secret_len); /* append secret */
-
- /* generate MD based on negotiated type */
-
- switch (lcp_hisoptions[cstate->unit].chap_mdtype) {
-
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- MD5Init(&mdContext);
- MD5Update(&mdContext, buf, rchallenge_len + secret_len);
- MD5Final(&mdContext);
- ChapSendResponse(cstate, id, &mdContext.digest[0], MD5_SIGNATURE_SIZE);
- break;
-
- default:
- CHAPDEBUG((LOG_INFO, "unknown digest type %d",
- lcp_hisoptions[cstate->unit].chap_mdtype))
- }
+ case CHAP_SUCCESS:
+ ChapReceiveSuccess(cstate, inp, id, len);
+ break;
+ default: /* Need code reject? */
+ syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
+ break;
+ }
}
/*
- * ChapReceiveResponse - Receive and process response.
+ * ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void
- ChapReceiveResponse(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-int id;
-int len;
+ChapReceiveChallenge(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
{
- u_char *remmd, remmd_len;
- u_char secret[MAX_SECRET_LEN];
- int secret_len;
- u_char chal_len = cstate->chal_len;
- u_char code;
- u_char rhostname[256];
- u_char buf[256];
- MD5_CTX mdContext;
- u_char msg[256], msglen;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id))
-
-/* sanity check */
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received response but did not send a challenge"))
- return;
- }
-
- if (len < 2) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
- return;
- }
- GETCHAR(remmd_len, inp); /* get length of MD */
- len -= sizeof (u_char) + remmd_len ;
+ int rchallenge_len;
+ u_char *rchallenge;
+ int secret_len;
+ char secret[MAXSECRETLEN];
+ char rhostname[256];
+ MD5_CTX mdContext;
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
+ if (cstate->clientstate == CHAPCS_CLOSED ||
+ cstate->clientstate == CHAPCS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
+ cstate->clientstate));
+ return;
+ }
+
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
- if (len < 0) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."))
- return;
- }
+ GETCHAR(rchallenge_len, inp);
+ len -= sizeof (u_char) + rchallenge_len; /* now name field length */
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+ return;
+ }
+ rchallenge = inp;
+ INCPTR(rchallenge_len, inp);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field: %s",
+ rhostname));
+
+ /* get secret for authenticating ourselves with the specified host */
+ if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+ secret, &secret_len, 0)) {
+ secret_len = 0; /* assume null secret if can't find one */
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
+ rhostname);
+ }
- remmd = inp; /* get pointer to MD */
- INCPTR(remmd_len, inp);
+ /* cancel response send timeout if necessary */
+ if (cstate->clientstate == CHAPCS_RESPONSE)
+ UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
- BCOPY(inp, rhostname, len);
- rhostname[len] = '\000';
+ cstate->resp_id = id;
+ cstate->resp_transmits = 0;
- CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
- rhostname))
+ /* generate MD based on negotiated type */
+ switch (cstate->resp_type) {
- GETSECRET(rhostname, secret, &secret_len);/* get secret for specified host */
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->resp_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, rchallenge, rchallenge_len);
+ MD5Final(&mdContext);
+ BCOPY(mdContext.digest, cstate->response, MD5_SIGNATURE_SIZE);
+ cstate->resp_length = MD5_SIGNATURE_SIZE;
+ break;
- BCOPY(cstate->chal_str, buf, chal_len); /* copy challenge */
- /* into buffer */
- BCOPY(secret, buf + chal_len, secret_len); /* append secret */
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
+ return;
+ }
- /* generate MD based on negotiated type */
+ ChapSendResponse(cstate);
+}
- switch (lcp_gotoptions[cstate->unit].chap_mdtype) {
- case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
- MD5Init(&mdContext);
- MD5Update(&mdContext, buf, chal_len + secret_len);
- MD5Final(&mdContext);
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ int id;
+ int len;
+{
+ u_char *remmd, remmd_len;
+ int secret_len, old_state;
+ int code;
+ char rhostname[256];
+ u_char buf[256];
+ MD5_CTX mdContext;
+ u_char msg[256];
+ char secret[MAXSECRETLEN];
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
+
+ if (cstate->serverstate == CHAPSS_CLOSED ||
+ cstate->serverstate == CHAPSS_PENDING) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
+ cstate->serverstate));
+ return;
+ }
- /* compare local and remote MDs and send the appropriate status */
+ if (id != cstate->chal_id)
+ return; /* doesn't match ID of last challenge */
+
+ /*
+ * If we have received a duplicate or bogus Response,
+ * we have to send the same answer (Success/Failure)
+ * as we did for the first Response we saw.
+ */
+ if (cstate->serverstate == CHAPSS_OPEN) {
+ ChapSendStatus(cstate, CHAP_SUCCESS);
+ return;
+ }
+ if (cstate->serverstate == CHAPSS_BADAUTH) {
+ ChapSendStatus(cstate, CHAP_FAILURE);
+ return;
+ }
- if (bcmp (&mdContext.digest[0], remmd, MD5_SIGNATURE_SIZE))
- code = CHAP_FAILURE; /* they ain't the same */
- else
- code = CHAP_SUCCESS; /* they are the same! */
- break;
+ if (len < 2) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
+ GETCHAR(remmd_len, inp); /* get length of MD */
+ remmd = inp; /* get pointer to MD */
+ INCPTR(remmd_len, inp);
+
+ len -= sizeof (u_char) + remmd_len;
+ if (len < 0) {
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+ return;
+ }
- default:
- CHAPDEBUG((LOG_INFO, "unknown digest type %d",
- lcp_gotoptions[cstate->unit].chap_mdtype))
+ UNTIMEOUT(ChapChallengeTimeout, (caddr_t) cstate);
+
+ if (len >= sizeof(rhostname))
+ len = sizeof(rhostname) - 1;
+ BCOPY(inp, rhostname, len);
+ rhostname[len] = '\000';
+
+ CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
+ rhostname));
+
+ /*
+ * Get secret for authenticating them with us,
+ * do the hash ourselves, and compare the result.
+ */
+ code = CHAP_FAILURE;
+ if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+ secret, &secret_len, 1)) {
+ syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
+ rhostname);
+ } else {
+
+ /* generate MD based on negotiated type */
+ switch (cstate->chal_type) {
+
+ case CHAP_DIGEST_MD5: /* only MD5 is defined for now */
+ if (remmd_len != MD5_SIGNATURE_SIZE)
+ break; /* it's not even the right length */
+ MD5Init(&mdContext);
+ MD5Update(&mdContext, &cstate->chal_id, 1);
+ MD5Update(&mdContext, secret, secret_len);
+ MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+ MD5Final(&mdContext);
+
+ /* compare local and remote MDs and send the appropriate status */
+ if (bcmp (mdContext.digest, remmd, MD5_SIGNATURE_SIZE) == 0)
+ code = CHAP_SUCCESS; /* they are the same! */
+ break;
+
+ default:
+ CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
+ }
}
- if (code == CHAP_SUCCESS)
- sprintf((char *)msg, "Welcome to %s.", hostname);
- else
- sprintf((char *)msg, "I don't like you. Go 'way.");
- msglen = strlen(msg);
- ChapSendStatus(cstate, code, id, msg, msglen);
-
- /* only crank up IPCP when either we aren't doing PAP, or if we are, */
- /* that it is in open state */
+
+ ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
- cstate->serverstate = CHAPSS_OPEN;
- if (!lcp_hisoptions[cstate->unit].neg_upap ||
- (lcp_hisoptions[cstate->unit].neg_upap &&
- upap[cstate->unit].us_serverstate == UPAPSS_OPEN ))
- ipcp_activeopen(cstate->unit); /* Start IPCP */
+ old_state = cstate->serverstate;
+ cstate->serverstate = CHAPSS_OPEN;
+ if (old_state == CHAPSS_INITIAL_CHAL) {
+ auth_peer_success(cstate->unit, CHAP);
+ }
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
+
+ } else {
+ syslog(LOG_ERR, "CHAP peer authentication failed");
+ cstate->serverstate = CHAPSS_BADAUTH;
+ auth_peer_fail(cstate->unit, CHAP);
}
}
+
/*
* ChapReceiveSuccess - Receive Success
*/
-/* ARGSUSED */
static void
- ChapReceiveSuccess(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-u_char id;
-int len;
+ChapReceiveSuccess(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
{
- u_char msglen;
- u_char *msg;
-
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id))
-
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: received success, but did not send a challenge."))
- return;
- }
-
- /*
- * Parse message.
- */
- if (len < sizeof (u_char)) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
- return;
- }
- GETCHAR(msglen, inp);
- len -= sizeof (u_char);
- if (len < msglen) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: rcvd short packet."))
- return;
- }
- msg = inp;
- PRINTMSG(msg, msglen);
-
- cstate->clientstate = CHAPCS_OPEN;
- /* only crank up IPCP when either we aren't doing PAP, or if we are, */
- /* that it is in open state */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
+
+ if (cstate->clientstate == CHAPCS_OPEN)
+ /* presumably an answer to a duplicate response */
+ return;
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
- if (!lcp_gotoptions[cstate->unit].neg_chap ||
- (lcp_gotoptions[cstate->unit].neg_chap &&
- upap[cstate->unit].us_serverstate == UPAPCS_OPEN ))
- ipcp_activeopen(cstate->unit); /* Start IPCP */
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ cstate->clientstate = CHAPCS_OPEN;
+
+ auth_withpeer_success(cstate->unit, CHAP);
}
/*
* ChapReceiveFailure - Receive failure.
*/
-/* ARGSUSED */
static void
- ChapReceiveFailure(cstate, inp, id, len)
-chap_state *cstate;
-u_char *inp;
-u_char id;
-int len;
+ChapReceiveFailure(cstate, inp, id, len)
+ chap_state *cstate;
+ u_char *inp;
+ u_char id;
+ int len;
{
- u_char msglen;
- u_char *msg;
+ u_char msglen;
+ u_char *msg;
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id))
- if (cstate->clientstate != CHAPCS_CHALLENGE_SENT) /* XXX */
- return;
-
- /*
- * Parse message.
- */
- if (len < sizeof (u_char)) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
- return;
- }
- GETCHAR(msglen, inp);
- len -= sizeof (u_char);
- if (len < msglen) {
- CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: rcvd short packet."))
- return;
- }
- msg = inp;
- PRINTMSG(msg, msglen);
-
- cstate->flags &= ~CHAPF_UPVALID; /* Clear valid flag */
- cstate->clientstate = CHAPCS_CLOSED; /* Pretend for a moment */
- ChapAuthWithPeer(cstate->unit); /* Restart */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
+
+ if (cstate->clientstate != CHAPCS_RESPONSE) {
+ /* don't know what this is */
+ CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
+ cstate->clientstate));
+ return;
+ }
+
+ /*
+ * Print message.
+ */
+ if (len > 0)
+ PRINTMSG(inp, len);
+
+ syslog(LOG_ERR, "CHAP authentication failed");
+ auth_withpeer_fail(cstate->unit, CHAP);
}
@@ -534,43 +606,36 @@ int len;
* ChapSendChallenge - Send an Authenticate challenge.
*/
static void
- ChapSendChallenge(cstate)
-chap_state *cstate;
+ChapSendChallenge(cstate)
+ chap_state *cstate;
{
- u_char *outp;
- u_char chal_len;
- int outlen;
-
-/* pick a random challenge length between MIN_CHALLENGE_LENGTH and
- MAX_CHALLENGE_LENGTH */
- cstate->chal_len = (unsigned) ((drand48() *
- (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
- MIN_CHALLENGE_LENGTH);
- chal_len = cstate->chal_len;
-
- outlen = CHAP_HEADERLEN + 2 * sizeof (u_char) + chal_len + hostname_len;
- outp = outpacket_buf;
+ u_char *outp;
+ int chal_len, name_len;
+ int outlen;
- MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
-
- PUTCHAR(CHAP_CHALLENGE, outp);
- PUTCHAR(++cstate->id, outp);
- PUTSHORT(outlen, outp);
+ chal_len = cstate->chal_len;
+ name_len = strlen(cstate->chal_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+ outp = outpacket_buf;
- PUTCHAR(chal_len, outp); /* put length of challenge */
+ MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
- ChapGenChallenge(chal_len, cstate->chal_str); /* generate a challenge string */
+ PUTCHAR(CHAP_CHALLENGE, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
- BCOPY(cstate->chal_str, outp, chal_len); /* copy it the the output buffer */
- INCPTR(chal_len, outp);
+ PUTCHAR(chal_len, outp); /* put length of challenge */
+ BCOPY(cstate->challenge, outp, chal_len);
+ INCPTR(chal_len, outp);
- BCOPY(hostname, outp, hostname_len); /* append hostname */
- INCPTR(hostname_len, outp);
+ BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->id))
- cstate->clientstate |= CHAPCS_CHALLENGE_SENT;
+ CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
+
+ TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->chal_transmits;
}
@@ -578,88 +643,99 @@ chap_state *cstate;
* ChapSendStatus - Send a status response (ack or nak).
*/
static void
- ChapSendStatus(cstate, code, id, msg, msglen)
-chap_state *cstate;
-u_char code, id;
-u_char *msg;
-int msglen;
+ChapSendStatus(cstate, code)
+ chap_state *cstate;
+ int code;
{
- u_char *outp;
- int outlen;
-
- outlen = CHAP_HEADERLEN + msglen;
- outp = outpacket_buf;
+ u_char *outp;
+ int outlen, msglen;
+ char msg[256];
- MAKEHEADER(outp, CHAP); /* paste in a header */
+ if (code == CHAP_SUCCESS)
+ sprintf(msg, "Welcome to %s.", hostname);
+ else
+ sprintf(msg, "I don't like you. Go 'way.");
+ msglen = strlen(msg);
+
+ outlen = CHAP_HEADERLEN + msglen;
+ outp = outpacket_buf;
+
+ MAKEHEADER(outp, CHAP); /* paste in a header */
- PUTCHAR(code, outp);
- PUTCHAR(id, outp);
- PUTSHORT(outlen, outp);
- BCOPY(msg, outp, msglen);
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ PUTCHAR(code, outp);
+ PUTCHAR(cstate->chal_id, outp);
+ PUTSHORT(outlen, outp);
+ BCOPY(msg, outp, msglen);
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code, id))
+ CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
+ cstate->chal_id));
}
/*
* ChapGenChallenge is used to generate a pseudo-random challenge string of
- * a pseudo-random length between min_len and max_len and return the
- * challenge string, and the message digest of the secret appended to
- * the challenge string. the message digest type is specified by mdtype.
- *
- * It returns with the string in the caller-supplied buffer str (which
- * should be instantiated with a length of max_len + 1), and the
- * length of the generated string into chal_len.
- *
+ * a pseudo-random length between min_len and max_len. The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
*/
static void
- ChapGenChallenge(chal_len, str)
-u_char chal_len;
-u_char * str;
+ChapGenChallenge(cstate)
+ chap_state *cstate;
{
- u_char * ptr = str;
- unsigned int i;
-
- /* generate a random string */
-
- for (i = 0; i < chal_len; i++ )
- *ptr++ = (char) (drand48() * 0xff);
-
- *ptr = 0; /* null terminate it so we can printf it */
+ int chal_len;
+ u_char *ptr = cstate->challenge;
+ unsigned int i;
+
+ /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+ MAX_CHALLENGE_LENGTH */
+ chal_len = (unsigned) ((drand48() *
+ (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+ MIN_CHALLENGE_LENGTH);
+ cstate->chal_len = chal_len;
+ cstate->chal_id = ++cstate->id;
+ cstate->chal_transmits = 0;
+
+ /* generate a random string */
+ for (i = 0; i < chal_len; i++ )
+ *ptr++ = (char) (drand48() * 0xff);
}
+
/*
- * ChapSendResponse - send a response packet with the message
- * digest specified by md and md_len
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
*/
/* ARGSUSED */
static void
- ChapSendResponse(cstate, id, md, md_len)
-chap_state *cstate;
-u_char id;
-u_char *md;
-int md_len;
+ChapSendResponse(cstate)
+ chap_state *cstate;
{
u_char *outp;
- int outlen;
+ int outlen, md_len, name_len;
- outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + hostname_len;
+ md_len = cstate->resp_length;
+ name_len = strlen(cstate->resp_name);
+ outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
outp = outpacket_buf;
- MAKEHEADER(outp, CHAP);
- PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
- PUTCHAR(id, outp); /* copy id from challenge packet */
- PUTSHORT(outlen, outp); /* packet length */
+ MAKEHEADER(outp, CHAP);
- PUTCHAR(md_len, outp); /* length of MD */
+ PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */
+ PUTCHAR(cstate->resp_id, outp); /* copy id from challenge packet */
+ PUTSHORT(outlen, outp); /* packet length */
- BCOPY(md, outp, md_len); /* copy MD to buffer */
+ PUTCHAR(md_len, outp); /* length of MD */
+ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
INCPTR(md_len, outp);
- BCOPY(hostname, outp, hostname_len); /* append hostname */
- INCPTR(hostname_len, outp);
+ BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+ /* send the packet */
+ output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
- output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN); /* bomb's away! */
+ cstate->clientstate = CHAPCS_RESPONSE;
+ TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
+ ++cstate->resp_transmits;
}
#ifdef NO_DRAND48
diff --git a/libexec/pppd/chap.h b/libexec/pppd/chap.h
index 2d5c51e3485e..51d41d5b6acf 100644
--- a/libexec/pppd/chap.h
+++ b/libexec/pppd/chap.h
@@ -15,6 +15,8 @@
* 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: chap.h,v 1.2 1994/03/30 09:31:24 jkh Exp $
*/
#ifndef __CHAP_INCLUDE__
@@ -26,77 +28,80 @@
* CHAP codes.
*/
-#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
-
-#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
-
-#define CHAP_NOCALLBACK 0 /* don't call back after successful auth */
-#define CHAP_CALLBACK 1 /* do call back */
+#define CHAP_DIGEST_MD5 5 /* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */
-#define CHAP_CHALLENGE 1
-#define CHAP_RESPONSE 2
-#define CHAP_SUCCESS 3
-#define CHAP_FAILURE 4
+#define CHAP_CHALLENGE 1
+#define CHAP_RESPONSE 2
+#define CHAP_SUCCESS 3
+#define CHAP_FAILURE 4
/*
- * Challenge lengths
+ * Challenge lengths (for challenges we send) and other limits.
*/
+#define MIN_CHALLENGE_LENGTH 32
+#define MAX_CHALLENGE_LENGTH 64
+#define MAX_RESPONSE_LENGTH 16 /* sufficient for MD5 */
-#define MIN_CHALLENGE_LENGTH 64
-#define MAX_CHALLENGE_LENGTH 128
-
-#define MAX_SECRET_LEN 128
/*
- * Each interface is described by chap structure.
+ * Each interface is described by a chap structure.
*/
typedef struct chap_state {
- int unit; /* Interface unit number */
- u_char chal_str[MAX_CHALLENGE_LENGTH + 1]; /* challenge string */
- u_char chal_len; /* challenge length */
+ int unit; /* Interface unit number */
int clientstate; /* Client state */
int serverstate; /* Server state */
- int flags; /* Flags */
- unsigned char id; /* Current id */
- int timeouttime; /* Timeout time in milliseconds */
- int retransmits; /* Number of retransmissions */
+ u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+ u_char chal_len; /* challenge length */
+ u_char chal_id; /* ID of last challenge */
+ u_char chal_type; /* hash algorithm for challenges */
+ u_char id; /* Current id */
+ char *chal_name; /* Our name to use with challenge */
+ int chal_interval; /* Time until we challenge peer again */
+ int timeouttime; /* Timeout time in seconds */
+ int max_transmits; /* Maximum # of challenge transmissions */
+ int chal_transmits; /* Number of transmissions of challenge */
+ int resp_transmits; /* Number of transmissions of response */
+ u_char response[MAX_RESPONSE_LENGTH]; /* Response to send */
+ u_char resp_length; /* length of response */
+ u_char resp_id; /* ID for response messages */
+ u_char resp_type; /* hash algorithm for responses */
+ char *resp_name; /* Our name to send with response */
} chap_state;
/*
- * Client states.
+ * Client (peer) states.
*/
-#define CHAPCS_CLOSED 1 /* Connection down */
-#define CHAPCS_CHALLENGE_SENT 2 /* We've sent a challenge */
-#define CHAPCS_OPEN 3 /* We've received an Ack */
+#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */
+#define CHAPCS_LISTEN 3 /* Listening for a challenge */
+#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */
+#define CHAPCS_OPEN 5 /* We've received Success */
/*
- * Server states.
+ * Server (authenticator) states.
*/
-#define CHAPSS_CLOSED 1 /* Connection down */
-#define CHAPSS_LISTEN 2 /* Listening for a challenge */
-#define CHAPSS_OPEN 3 /* We've sent an Ack */
-
-/*
- * Flags.
- */
-#define CHAPF_LOWERUP 0x01 /* The lower level is UP */
-#define CHAPF_AWPPENDING 0x02 /* Auth with peer pending */
-#define CHAPF_APPENDING 0x04 /* Auth peer pending */
-#define CHAPF_UPVALID 0x08 /* values valid */
-#define CHAPF_UPPENDING 0x10 /* values pending */
-
+#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */
+#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */
+#define CHAPSS_PENDING 2 /* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */
+#define CHAPSS_OPEN 4 /* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */
+#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */
/*
* Timeouts.
*/
-#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTIMEOUT 3 /* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */
extern chap_state chap[];
void ChapInit __ARGS((int));
-void ChapAuthWithPeer __ARGS((int));
-void ChapAuthPeer __ARGS((int));
+void ChapAuthWithPeer __ARGS((int, char *, int));
+void ChapAuthPeer __ARGS((int, char *, int));
void ChapLowerUp __ARGS((int));
void ChapLowerDown __ARGS((int));
void ChapInput __ARGS((int, u_char *, int));
diff --git a/libexec/pppd/fsm.c b/libexec/pppd/fsm.c
index 19bfb97595c3..ba8b76082d69 100644
--- a/libexec/pppd/fsm.c
+++ b/libexec/pppd/fsm.c
@@ -17,10 +17,12 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: fsm.c,v 1.3 1994/03/30 09:38:12 jkh Exp $";
+#endif
+
/*
* TODO:
- * Mechanism to exit() and/or drop DTR.
- * Hold-down on open?
* Randomize fsm id on link/init.
* Deal with variable outgoing MTU.
*/
@@ -30,27 +32,24 @@
/*#include <malloc.h>*/
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/stream.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
#include "fsm.h"
extern char *proto_name();
static void fsm_timeout __ARGS((caddr_t));
-static void fsm_rconfack __ARGS((fsm *, u_char *, int, int));
-static void fsm_rconfnak __ARGS((fsm *, u_char *, int, int));
-static void fsm_rconfrej __ARGS((fsm *, u_char *, int, int));
+static void fsm_rconfreq __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfack __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __ARGS((fsm *, int, int, u_char *, int));
static void fsm_rtermreq __ARGS((fsm *, int));
static void fsm_rtermack __ARGS((fsm *));
static void fsm_rcoderej __ARGS((fsm *, u_char *, int));
-static void fsm_rprotrej __ARGS((fsm *, u_char *, int));
-static void fsm_sconfreq __ARGS((fsm *));
+static void fsm_sconfreq __ARGS((fsm *, int));
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[_NPPP];
/*
@@ -59,226 +58,225 @@ static void fsm_sconfreq __ARGS((fsm *));
* Initialize fsm state.
*/
void
- fsm_init(f)
-fsm *f;
+fsm_init(f)
+ fsm *f;
{
- f->state = CLOSED;
+ f->state = INITIAL;
f->flags = 0;
f->id = 0; /* XXX Start with random id? */
+ f->timeouttime = DEFTIMEOUT;
+ f->maxconfreqtransmits = DEFMAXCONFREQS;
+ f->maxtermtransmits = DEFMAXTERMREQS;
+ f->maxnakloops = DEFMAXNAKLOOPS;
}
/*
- * fsm_activeopen - Actively open connection.
- *
- * Set new state, reset desired options and send requests.
+ * fsm_lowerup - The lower layer is up.
*/
void
- fsm_activeopen(f)
-fsm *f;
+fsm_lowerup(f)
+ fsm *f;
{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == REQSENT || /* Already actively open(ing)? */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == OPEN)
- return;
- if (f->state == TERMSENT || /* Closing or */
- !(f->flags & LOWERUP)) { /* lower layer down? */
- f->flags |= AOPENDING; /* Wait for desired event */
- return;
- }
- if (f->callbacks->resetci)
- (*f->callbacks->resetci)(f); /* Reset options */
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = REQSENT;
- f->retransmits = 0; /* Reset retransmits count */
- f->nakloops = 0; /* Reset nakloops count */
-}
+ switch( f->state ){
+ case INITIAL:
+ f->state = CLOSED;
+ break;
+ case STARTING:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
+ }
+ break;
-/*
- * fsm_passiveopen - Passively open connection.
- *
- * Set new state and reset desired options.
- */
-void
- fsm_passiveopen(f)
-fsm *f;
-{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == LISTEN || /* Already passively open(ing)? */
- f->state == OPEN)
- return;
- if (f->state == REQSENT || /* Active-Opening or */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == TERMSENT || /* closing or */
- !(f->flags & LOWERUP)) { /* lower layer down? */
- f->flags |= POPENDING; /* Wait for desired event */
- return;
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
+ PROTO_NAME(f), f->state));
}
- if (f->callbacks->resetci)
- (*f->callbacks->resetci)(f); /* Reset options */
- f->state = LISTEN;
- f->retransmits = 0; /* Reset retransmits count */
- f->nakloops = 0; /* Reset nakloops count */
}
/*
- * fsm_close - Start closing connection.
+ * fsm_lowerdown - The lower layer is down.
*
- * Cancel timeouts and either initiate close or possibly go directly to
- * the CLOSED state.
+ * Cancel all timeouts and inform upper layers.
*/
void
- fsm_close(f)
-fsm *f;
+fsm_lowerdown(f)
+ fsm *f;
{
- f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
- if (f->state == CLOSED || /* Already CLOSED or Closing? */
- f->state == TERMSENT)
- return;
- if (f->state == REQSENT || /* Timeout pending for Open? */
- f->state == ACKRCVD ||
- f->state == ACKSENT)
+ switch( f->state ){
+ case CLOSED:
+ f->state = INITIAL;
+ break;
+
+ case STOPPED:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
+ break;
+
+ case CLOSING:
+ f->state = INITIAL;
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->state == OPEN && /* Open? */
- f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers we're down */
- if (f->state == ACKSENT || /* Could peer be OPEN? */
- f->state == OPEN) {
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- /* Send Terminate-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = TERMSENT;
- f->retransmits = 0; /* Reset retransmits count */
- }
- else {
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ break;
+
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ f->state = STARTING;
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ break;
+
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
+ f->state = STARTING;
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Down event in state %d!",
+ PROTO_NAME(f), f->state));
}
}
/*
- * fsm_timeout - Timeout expired.
+ * fsm_open - Link is allowed to come up.
*/
-static void
- fsm_timeout(arg)
-caddr_t arg;
+void
+fsm_open(f)
+ fsm *f;
{
- fsm *f = (fsm *) arg;
- switch (f->state) {
- case REQSENT:
- case ACKRCVD:
- case ACKSENT:
- if (f->flags & POPENDING) { /* Go passive? */
- f->state = CLOSED; /* Pretend for a moment... */
- fsm_passiveopen(f);
- return;
- }
- if (f->retransmits > f->maxconfreqtransmits) {
- if (f->nakloops > f->maxnakloops) {
- syslog(LOG_INFO, "%s: timeout sending Config-Requests",
- proto_name(f->protocol));
- } else
- syslog(LOG_INFO, "%s: timed out. Config-Requests not accepted",
- proto_name(f->protocol));
-
- /* timeout sending config-requests */
- fsm_close(f);
-
- return;
- }
- if (f->callbacks->retransmit) /* If there is a retransmit rtn? */
- (*f->callbacks->retransmit)(f);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- f->state = REQSENT;
- ++f->retransmits;
- f->nakloops = 0;
+ switch( f->state ){
+ case INITIAL:
+ f->state = STARTING;
+ if( f->callbacks->starting )
+ (*f->callbacks->starting)(f);
break;
- case TERMSENT:
- if (f->flags & POPENDING) { /* Go passive? */
- f->state = CLOSED; /* Pretend for a moment... */
- fsm_passiveopen(f);
- return;
+ case CLOSED:
+ if( f->flags & OPT_SILENT )
+ f->state = STOPPED;
+ else {
+ /* Send an initial configure-request */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
}
- if (++f->retransmits > f->maxtermtransmits) {
- /*
- * We've waited for an ack long enough. Peer probably heard us.
- */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
- return;
+ break;
+
+ case CLOSING:
+ f->state = STOPPING;
+ /* fall through */
+ case STOPPED:
+ case OPENED:
+ if( f->flags & OPT_RESTART ){
+ fsm_lowerdown(f);
+ fsm_lowerup(f);
}
- if (f->callbacks->retransmit) /* If there is a retransmit rtn? */
- (*f->callbacks->retransmit)(f);
- fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
- /* Send Terminate-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ break;
}
}
/*
- * fsm_lowerup - The lower layer is up.
+ * fsm_close - Start closing connection.
*
- * Start Active or Passive Open if pending.
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
*/
void
- fsm_lowerup(f)
-fsm *f;
+fsm_close(f)
+ fsm *f;
{
- f->flags |= LOWERUP;
- if (f->flags & AOPENDING) /* Attempting Active-Open? */
- fsm_activeopen(f); /* Try it now */
- else if (f->flags & POPENDING) /* Attempting Passive-Open? */
- fsm_passiveopen(f); /* Try it now */
-}
+ switch( f->state ){
+ case STARTING:
+ f->state = INITIAL;
+ break;
+ case STOPPED:
+ f->state = CLOSED;
+ break;
+ case STOPPING:
+ f->state = CLOSING;
+ break;
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ case OPENED:
+ if( f->state != OPENED )
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ else if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers we're down */
-/*
- * fsm_lowerdown - The lower layer is down.
- *
- * Cancel all timeouts and inform upper layers.
- */
-void
- fsm_lowerdown(f)
-fsm *f;
-{
- f->flags &= ~LOWERUP;
- if (f->state == REQSENT || /* Timeout pending? */
- f->state == ACKRCVD ||
- f->state == ACKSENT ||
- f->state == TERMSENT)
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->state == OPEN && /* OPEN? */
- f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ /* 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);
+ --f->retransmits;
+
+ f->state = CLOSING;
+ break;
+ }
}
/*
- * fsm_protreject - Peer doesn't speak this protocol.
- *
- * Pretend that the lower layer went down.
+ * fsm_timeout - Timeout expired.
*/
-void
- fsm_protreject(f)
-fsm *f;
+static void
+fsm_timeout(arg)
+ caddr_t arg;
{
- fsm_lowerdown(f);
+ fsm *f = (fsm *) arg;
+
+ switch (f->state) {
+ case CLOSING:
+ case STOPPING:
+ if( f->retransmits <= 0 ){
+ /*
+ * We've waited for an ack long enough. Peer probably heard us.
+ */
+ f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+ if( f->callbacks->finished )
+ (*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);
+ --f->retransmits;
+ }
+ break;
+
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ if (f->retransmits <= 0) {
+ syslog(LOG_WARNING, "%s: timeout sending Config-Requests",
+ PROTO_NAME(f));
+ f->state = STOPPED;
+ if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+
+ } else {
+ /* Retransmit the configure-request */
+ if (f->callbacks->retransmit)
+ (*f->callbacks->retransmit)(f);
+ fsm_sconfreq(f, 1); /* Re-send Configure-Request */
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
+ }
+ break;
+
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
}
@@ -286,302 +284,262 @@ fsm *f;
* fsm_input - Input packet.
*/
void
- fsm_input(f, inpacket, l)
-fsm *f;
-u_char *inpacket;
-int l;
+fsm_input(f, inpacket, l)
+ fsm *f;
+ u_char *inpacket;
+ int l;
{
- u_char *inp, *outp;
- u_char code, id;
- int len;
-
- /*
- * Parse header (code, id and length).
- * If packet too short, drop it.
- */
- inp = inpacket;
- if (l < HEADERLEN) {
- FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.", f->protocol))
- return;
- }
- GETCHAR(code, inp);
- GETCHAR(id, inp);
- GETSHORT(len, inp);
- if (len < HEADERLEN) {
- FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
- f->protocol))
- return;
- }
- if (len > l) {
- FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
- f->protocol))
- return;
- }
- len -= HEADERLEN; /* subtract header length */
-
- /*
- * Action depends on code.
- */
- switch (code) {
- case CONFREQ:
- FSMDEBUG((LOG_INFO, "fsm_rconfreq(%x): Rcvd id %d.",
- f->protocol, id))
-
- if (f->state == TERMSENT)
- return;
- if (f->state == CLOSED) {
- fsm_sdata(f, TERMACK, id, NULL, 0);
- return;
+ u_char *inp, *outp;
+ u_char code, id;
+ int len;
+
+ /*
+ * Parse header (code, id and length).
+ * If packet too short, drop it.
+ */
+ inp = inpacket;
+ if (l < HEADERLEN) {
+ FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.",
+ f->protocol));
+ return;
}
- if (f->state == OPEN && f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- if (f->state == OPEN || f->state == LISTEN) {
- /* XXX Possibly need hold-down on OPEN? */
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
+ GETCHAR(code, inp);
+ GETCHAR(id, inp);
+ GETSHORT(len, inp);
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
+ f->protocol));
+ return;
}
-
- if (f->callbacks->reqci) /* Check CI */
- code = (*f->callbacks->reqci)(f, inp, &len);
- else if (len)
- code = CONFREJ; /* Reject all CI */
-
- len += HEADERLEN; /* add header length back on */
-
- inp = inpacket; /* Reset to header */
- outp = outpacket_buf; /* get pointer to output buffer */
- MAKEHEADER(outp, f->protocol); /* paste in DLL header */
- BCOPY(inp, outp, len); /* copy input packet */
- PUTCHAR(code, outp); /* put in the code, id, and length*/
- PUTCHAR(id, outp);
- PUTSHORT(len, outp);
- output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it out */
-
- if (code == CONFACK) {
- if (f->state == ACKRCVD) {
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->up)
- (*f->callbacks->up)(f); /* Inform upper layers */
- f->state = OPEN;
- }
- else
- f->state = ACKSENT;
+ if (len > l) {
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
+ f->protocol));
+ return;
}
- else {
- if (f->state != ACKRCVD)
- f->state = REQSENT;
+ len -= HEADERLEN; /* subtract header length */
+
+ if( f->state == INITIAL || f->state == STARTING ){
+ FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
+ f->protocol, f->state));
+ return;
}
- return;
-
- case CONFACK:
- fsm_rconfack(f, inp, id, len);
- break;
-
- case CONFNAK:
- fsm_rconfnak(f, inp, id, len);
- break;
-
- case CONFREJ:
- fsm_rconfrej(f, inp, id, len);
- break;
+
+ /*
+ * Action depends on code.
+ */
+ switch (code) {
+ case CONFREQ:
+ fsm_rconfreq(f, id, inp, len);
+ break;
- case TERMREQ:
- fsm_rtermreq(f, id);
- break;
+ case CONFACK:
+ fsm_rconfack(f, id, inp, len);
+ break;
- case TERMACK:
- fsm_rtermack(f);
- break;
+ case CONFNAK:
+ case CONFREJ:
+ fsm_rconfnakrej(f, code, id, inp, len);
+ break;
- case CODEREJ:
- fsm_rcoderej(f, inp, len);
- break;
+ case TERMREQ:
+ fsm_rtermreq(f, id);
+ break;
- case PROTREJ:
- fsm_rprotrej(f, inp, len);
- break;
+ case TERMACK:
+ fsm_rtermack(f);
+ break;
- case ECHOREQ:
- FSMDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ case CODEREJ:
+ fsm_rcoderej(f, inp, len);
+ break;
- switch (f->state) {
- case CLOSED:
- case LISTEN:
- fsm_sdata(f, TERMACK, id, NULL, 0);
- break;
-
- case OPEN:
- inp = inpacket; /* Reset to header */
- outp = outpacket_buf; /* get pointer to output buffer */
- MAKEHEADER(outp, f->protocol); /* add DLL header */
- len += HEADERLEN; /* add header length */
- BCOPY(inp, outp, len); /* copy input packet to output buffer */
- PUTCHAR(ECHOREP, outp); /* set code to echo reply */
- PUTCHAR(id, outp); /* add in id */
- PUTSHORT(len, outp); /* and length */
- output(f->unit, outpacket_buf, len + DLLHEADERLEN); /* send it */
- return;
+ default:
+ if( !f->callbacks->extcode
+ || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+ fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+ break;
}
- break;
-
- case ECHOREP:
- case DISCREQ:
- /* XXX Deliver to ECHOREQ sender? */
- break;
-
- default:
- fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
- break;
- }
-
}
/*
- * fsm_rconfack - Receive Configure-Ack.
+ * fsm_rconfreq - Receive Configure-Request.
*/
static void
- fsm_rconfack(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfreq(f, id, inp, len)
+ fsm *f;
+ u_char id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfack(%x): Rcvd id %d.",
- f->protocol, id))
+ u_char *outp;
+ int code, reject_if_disagree;
- switch (f->state) {
- case LISTEN:
- case CLOSED:
+ FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
+ switch( f->state ){
+ case CLOSED:
+ /* Go away, we're closed */
fsm_sdata(f, TERMACK, id, NULL, 0);
+ return;
+ case CLOSING:
+ case STOPPING:
+ return;
+
+ case OPENED:
+ /* Go down and restart negotiation */
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
break;
- case ACKRCVD:
- case REQSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (f->callbacks->ackci &&
- (*f->callbacks->ackci)(f, inp, len)) /* Good ack? */
- f->state = ACKRCVD;
- else
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case STOPPED:
+ /* Negotiation started by our peer */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
+ }
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (f->callbacks->ackci &&
- (*f->callbacks->ackci)(f, inp, len)) { /* Good ack? */
+ /*
+ * Pass the requested configuration options
+ * to protocol-specific code for checking.
+ */
+ if (f->callbacks->reqci){ /* Check CI */
+ reject_if_disagree = (f->nakloops >= f->maxnakloops);
+ code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+ } else if (len)
+ code = CONFREJ; /* Reject all CI */
+
+ /* send the Ack, Nak or Rej to the peer */
+ fsm_sdata(f, code, id, inp, len);
+
+ if (code == CONFACK) {
+ if (f->state == ACKRCVD) {
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
if (f->callbacks->up)
(*f->callbacks->up)(f); /* Inform upper layers */
- f->state = OPEN;
- }
- else
- f->state = REQSENT; /* Wait for timeout to retransmit */
- break;
+ } else
+ f->state = ACKSENT;
+ f->nakloops = 0;
- case OPEN:
- if (f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
- break;
+ } else {
+ /* we sent CONFACK or CONFREJ */
+ if (f->state != ACKRCVD)
+ f->state = REQSENT;
+ if( code == CONFNAK )
+ ++f->nakloops;
}
}
/*
- * fsm_rconfnak - Receive Configure-Nak.
+ * fsm_rconfack - Receive Configure-Ack.
*/
static void
- fsm_rconfnak(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfack(f, id, inp, len)
+ fsm *f;
+ int id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfnak(%x): Rcvd id %d.",
- f->protocol, id))
+ FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid) /* Expected id? */
+ return; /* Nope, toss... */
+ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){
+ /* Ack is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
+ PROTO_NAME(f), len));
+ return;
+ }
switch (f->state) {
- case LISTEN:
- case CLOSED:
+ case CLOSED:
+ case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
- case REQSENT:
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (++f->nakloops > f->maxnakloops) {
- FSMDEBUG((LOG_INFO,
- "fsm_rconfnak(%x): Possible CONFNAK loop!",
- f->protocol))
- break; /* Break the loop */
- }
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->nakci)
- (*f->callbacks->nakci)(f, inp, len);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ case REQSENT:
+ f->state = ACKRCVD;
+ f->retransmits = f->maxconfreqtransmits;
break;
- case ACKRCVD:
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case ACKRCVD:
+ /* Huh? an extra Ack? oh well... */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
break;
- case OPEN:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ f->state = OPENED;
+ f->retransmits = f->maxconfreqtransmits;
+ if (f->callbacks->up)
+ (*f->callbacks->up)(f); /* Inform upper layers */
+ break;
+
+ case OPENED:
+ /* Go down and restart negotiation */
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
}
}
/*
- * fsm_rconfrej - Receive Configure-Rej.
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
*/
static void
- fsm_rconfrej(f, inp, id, len)
-fsm *f;
-u_char *inp;
-u_char id;
-int len;
+fsm_rconfnakrej(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
{
- FSMDEBUG((LOG_INFO, "fsm_rconfrej(%x): Rcvd id %d.",
- f->protocol, id))
+ int (*proc)();
+
+ FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
+
+ if (id != f->reqid) /* Expected id? */
+ return; /* Nope, toss... */
+ proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+ if( !proc || !proc(f, inp, len) ){
+ /* Nak/reject is bad - ignore it */
+ FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
+ PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+ return;
+ }
switch (f->state) {
- case LISTEN:
- case CLOSED:
+ case CLOSED:
+ case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
- case REQSENT:
- case ACKSENT:
- if (id != f->reqid) /* Expected id? */
- break; /* Nope, toss... */
- if (++f->nakloops > f->maxnakloops)
- break; /* Break the loop */
+ case REQSENT:
+ case ACKSENT:
+ /* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- if (f->callbacks->rejci)
- (*f->callbacks->rejci)(f, inp, len);
- fsm_sconfreq(f); /* Send Configure-Request */
- TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
- ++f->retransmits;
+ fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
- case ACKRCVD:
- f->state = REQSENT; /* Wait for timeout to retransmit */
+ case ACKRCVD:
+ /* Got a Nak/reject when we had already had an Ack?? oh well... */
+ fsm_sconfreq(f, 0);
+ f->state = REQSENT;
break;
- case OPEN:
- f->state = CLOSED; /* Only for a moment... */
- fsm_activeopen(f); /* Restart */
+ case OPENED:
+ /* Go down and restart negotiation */
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0); /* Send initial Configure-Request */
+ f->state = REQSENT;
break;
}
}
@@ -591,26 +549,27 @@ int len;
* fsm_rtermreq - Receive Terminate-Req.
*/
static void
- fsm_rtermreq(f, id)
-fsm *f;
-u_char id;
+fsm_rtermreq(f, id)
+ fsm *f;
+ int id;
{
- FSMDEBUG((LOG_INFO, "fsm_rtermreq(%x): Rcvd id %d.",
- f->protocol, id))
+ FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
+ PROTO_NAME(f), id));
fsm_sdata(f, TERMACK, id, NULL, 0);
switch (f->state) {
- case ACKRCVD:
- case ACKSENT:
+ case ACKRCVD:
+ case ACKSENT:
f->state = REQSENT; /* Start over but keep trying */
break;
- case OPEN:
+ case OPENED:
+ syslog(LOG_INFO, "%s terminated at peer's request", PROTO_NAME(f));
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ f->retransmits = 0;
+ f->state = STOPPING;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
break;
}
}
@@ -620,25 +579,31 @@ u_char id;
* fsm_rtermack - Receive Terminate-Ack.
*/
static void
- fsm_rtermack(f)
-fsm *f;
+fsm_rtermack(f)
+ fsm *f;
{
- FSMDEBUG((LOG_INFO, "fsm_rtermack(%x).", f->protocol))
+ FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
switch (f->state) {
- case OPEN:
- if (f->callbacks->down)
- (*f->callbacks->down)(f); /* Inform upper layers */
+ case CLOSING:
f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+ case STOPPING:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
break;
- case TERMSENT:
- UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
- f->state = CLOSED;
- if (f->callbacks->closed)
- (*f->callbacks->closed)(f); /* Exit/restart/etc. */
+ case ACKRCVD:
+ f->state = REQSENT;
+ break;
+
+ case OPENED:
+ if (f->callbacks->down)
+ (*f->callbacks->down)(f); /* Inform upper layers */
+ fsm_sconfreq(f, 0);
break;
}
}
@@ -648,59 +613,77 @@ fsm *f;
* fsm_rcoderej - Receive an Code-Reject.
*/
static void
- fsm_rcoderej(f, inp, len)
-fsm *f;
-u_char *inp;
-int len;
+fsm_rcoderej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
{
- u_char code;
+ u_char code, id;
- FSMDEBUG((LOG_INFO, "fsm_rcoderej(%x).", f->protocol))
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
- if (len < sizeof (u_char)) {
- FSMDEBUG((LOG_INFO,
- "fsm_rcoderej: Rcvd short Code-Reject packet!"))
+ if (len < HEADERLEN) {
+ FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
return;
}
GETCHAR(code, inp);
- FSMDEBUG((LOG_INFO,
- "fsm_rcoderej: Rcvd Code-Reject for code %d!",
- code))
+ GETCHAR(id, inp);
+ syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d",
+ PROTO_NAME(f), code, id);
+
+ if( f->state == ACKRCVD )
+ f->state = REQSENT;
}
/*
- * fsm_rprotrej - Receive an Protocol-Reject.
+ * fsm_protreject - Peer doesn't speak this protocol.
*
- * Figure out which protocol is rejected and inform it.
+ * Treat this as a catastrophic error (RXJ-).
*/
-static void
- fsm_rprotrej(f, inp, len)
-fsm *f;
-u_char *inp;
-int len;
+void
+fsm_protreject(f)
+ fsm *f;
{
- u_short prot;
+ switch( f->state ){
+ case CLOSING:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case CLOSED:
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
- FSMDEBUG((LOG_INFO, "fsm_rprotrej."))
+ case STOPPING:
+ case REQSENT:
+ case ACKRCVD:
+ case ACKSENT:
+ UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
+ /* fall through */
+ case STOPPED:
+ f->state = STOPPED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
- if (len < sizeof (u_short)) {
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd short Protocol-Reject packet!"))
- return;
- }
- if (f->protocol != LCP) { /* Only valid for LCP */
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd non-LCP Protocol-Reject!"))
- return;
- }
+ case OPENED:
+ if( f->callbacks->down )
+ (*f->callbacks->down)(f);
- GETSHORT(prot, inp);
+ /* 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);
+ --f->retransmits;
+
+ f->state = STOPPING;
+ break;
- FSMDEBUG((LOG_INFO,
- "fsm_rprotrej: Rcvd Protocol-Reject packet for %x!",
- prot))
- DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+ default:
+ FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
+ PROTO_NAME(f), f->state));
+ }
}
@@ -708,58 +691,79 @@ int len;
* fsm_sconfreq - Send a Configure-Request.
*/
static void
- fsm_sconfreq(f)
-fsm *f;
+fsm_sconfreq(f, retransmit)
+ fsm *f;
+ int retransmit;
{
u_char *outp;
- int outlen;
+ int outlen, cilen;
- outlen = HEADERLEN + (f->callbacks->cilen ? (*f->callbacks->cilen)(f) : 0);
- /* XXX Adjust outlen to MTU */
- outp = outpacket_buf;
- MAKEHEADER(outp, f->protocol);
+ if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+ /* Not currently negotiating - reset options */
+ if( f->callbacks->resetci )
+ (*f->callbacks->resetci)(f);
+ f->nakloops = 0;
+ }
- PUTCHAR(CONFREQ, outp);
- PUTCHAR(f->reqid = ++f->id, outp);
- PUTSHORT(outlen, outp);
- if (f->callbacks->cilen && f->callbacks->addci)
- (*f->callbacks->addci)(f, outp);
- output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
+ if( !retransmit ){
+ /* New request - reset retransmission counter, use new ID */
+ f->retransmits = f->maxconfreqtransmits;
+ f->reqid = ++f->id;
+ }
+
+ /*
+ * Make up the request packet
+ */
+ if( f->callbacks->cilen && f->callbacks->addci ){
+ cilen = (*f->callbacks->cilen)(f);
+ if( cilen > peer_mru[f->unit] - HEADERLEN )
+ cilen = peer_mru[f->unit] - HEADERLEN;
+ outp = outpacket_buf + DLLHEADERLEN + HEADERLEN;
+ if (f->callbacks->addci)
+ (*f->callbacks->addci)(f, outp, &cilen);
+ } else
+ cilen = 0;
+
+ /* send the request to our peer */
+ fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+ /* start the retransmit timer */
+ --f->retransmits;
+ TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
- proto_name(f->protocol), f->reqid))
+ PROTO_NAME(f), f->reqid));
}
/*
* fsm_sdata - Send some data.
*
- * Used for Terminate-Request, Terminate-Ack, Code-Reject, Protocol-Reject,
- * Echo-Request, and Discard-Request.
+ * Used for all packets sent to our peer by this module.
*/
void
- fsm_sdata(f, code, id, data, datalen)
-fsm *f;
-u_char code, id;
-u_char *data;
-int datalen;
+fsm_sdata(f, code, id, data, datalen)
+ fsm *f;
+ u_char code, id;
+ u_char *data;
+ int datalen;
{
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
- if (datalen > MTU - HEADERLEN)
- datalen = MTU - HEADERLEN;
- outlen = datalen + HEADERLEN;
outp = outpacket_buf;
+ if (datalen > peer_mru[f->unit] - HEADERLEN)
+ datalen = peer_mru[f->unit] - HEADERLEN;
+ if (datalen && data != outp + DLLHEADERLEN + HEADERLEN)
+ BCOPY(data, outp + DLLHEADERLEN + HEADERLEN, datalen);
+ outlen = datalen + HEADERLEN;
MAKEHEADER(outp, f->protocol);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
- if (datalen)
- BCOPY(data, outp, datalen);
output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
- FSMDEBUG((LOG_INFO, "fsm_sdata(%x): Sent code %d, id %d.",
- f->protocol, code, id))
+ FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
+ PROTO_NAME(f), code, id));
}
diff --git a/libexec/pppd/fsm.h b/libexec/pppd/fsm.h
index 82af3039ca55..abb242e21db5 100644
--- a/libexec/pppd/fsm.h
+++ b/libexec/pppd/fsm.h
@@ -15,6 +15,8 @@
* 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: fsm.h,v 1.2 1994/03/30 09:31:27 jkh Exp $
*/
/*
@@ -45,32 +47,35 @@
*/
typedef struct fsm_callbacks {
void (*resetci)(); /* Reset our Configuration Information */
- int (*cilen)(); /* Length of our Configuration Information */
+ int (*cilen)(); /* Length of our Configuration Information */
void (*addci)(); /* Add our Configuration Information */
- int (*ackci)(); /* ACK our Configuration Information */
- void (*nakci)(); /* NAK our Configuration Information */
- void (*rejci)(); /* Reject our Configuration Information */
- u_char (*reqci)(); /* Request peer's Configuration Information */
- void (*up)(); /* Called when fsm reaches OPEN state */
- void (*down)(); /* Called when fsm leaves OPEN state */
- void (*closed)(); /* Called when fsm reaches CLOSED state */
+ 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 */
- u_short protocol; /* Data Link Layer Protocol field value */
+ int protocol; /* Data Link Layer Protocol field value */
int state; /* State */
- int flags; /* Flags */
+ int flags; /* Contains option bits */
u_char id; /* Current id */
u_char reqid; /* Current request id */
int timeouttime; /* Timeout time in milliseconds */
int maxconfreqtransmits; /* Maximum Configure-Request transmissions */
- int retransmits; /* Number of retransmissions */
+ int retransmits; /* Number of retransmissions left */
int maxtermtransmits; /* Maximum Terminate-Request transmissions */
- int nakloops; /* Number of nak loops since last timeout */
+ int nakloops; /* Number of nak loops since last ack */
int maxnakloops; /* Maximum number of nak loops tolerated */
fsm_callbacks *callbacks; /* Callback routines */
} fsm;
@@ -79,40 +84,49 @@ typedef struct fsm {
/*
* Link states.
*/
-#define CLOSED 1 /* Connection closed */
-#define LISTEN 2 /* Listening for a Config Request */
-#define REQSENT 3 /* We've sent a Config Request */
-#define ACKSENT 4 /* We've sent a Config Ack */
-#define ACKRCVD 5 /* We've received a Config Ack */
-#define OPEN 6 /* Connection open */
-#define TERMSENT 7 /* We've sent a Terminate Request */
+#define INITIAL 0 /* Down, hasn't been opened */
+#define STARTING 1 /* Down, been opened */
+#define CLOSED 2 /* Up, hasn't been opened */
+#define STOPPED 3 /* Open, waiting for down event */
+#define CLOSING 4 /* Terminating the connection, not open */
+#define STOPPING 5 /* Terminating, but open */
+#define REQSENT 6 /* We've sent a Config Request */
+#define ACKRCVD 7 /* We've received a Config Ack */
+#define ACKSENT 8 /* We've sent a Config Ack */
+#define OPENED 9 /* Connection available */
/*
- * Flags.
+ * Flags - indicate options controlling FSM operation
*/
-#define LOWERUP 1 /* The lower level is UP */
-#define AOPENDING 2 /* Active Open pending timeout of request */
-#define POPENDING 4 /* Passive Open pending timeout of request */
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT 4 /* Wait for peer to speak first */
/*
* Timeouts.
*/
#define DEFTIMEOUT 3 /* Timeout time in seconds */
-#define DEFMAXTERMTRANSMITS 10 /* Maximum Terminate-Request transmissions */
-#define DEFMAXCONFIGREQS 10 /* Maximum Configure-Request transmissions */
-
-
+#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */
#define DEFMAXNAKLOOPS 10 /* Maximum number of nak loops */
+/*
+ * Prototypes
+ */
void fsm_init __ARGS((fsm *));
-void fsm_activeopen __ARGS((fsm *));
-void fsm_passiveopen __ARGS((fsm *));
-void fsm_close __ARGS((fsm *));
void fsm_lowerup __ARGS((fsm *));
void fsm_lowerdown __ARGS((fsm *));
-void fsm_protreject __ARGS((fsm *));
+void fsm_open __ARGS((fsm *));
+void fsm_close __ARGS((fsm *));
void fsm_input __ARGS((fsm *, u_char *, int));
+void fsm_protreject __ARGS((fsm *));
void fsm_sdata __ARGS((fsm *, int, int, u_char *, int));
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */
diff --git a/libexec/pppd/ipcp.c b/libexec/pppd/ipcp.c
index a805a3b61253..3638419ea6ac 100644
--- a/libexec/pppd/ipcp.c
+++ b/libexec/pppd/ipcp.c
@@ -17,12 +17,12 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: ipcp.c,v 1.3 1994/03/30 09:38:13 jkh Exp $";
+#endif
+
/*
* TODO:
- * Fix IP address negotiation (wantoptions or hisoptions).
- * Don't set zero IP addresses.
- * Send NAKs for unsent CIs.
- * VJ compression.
*/
#include <stdio.h>
@@ -33,64 +33,42 @@
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_ppp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <string.h>
-#ifndef BSD
-#ifndef sun
-#define BSD 44
-#endif
-#endif /*BSD*/
-
-#ifdef STREAMS
-#include <sys/stream.h>
-#include "ppp_str.h"
-#endif
-
#include "pppd.h"
-#include <net/if_ppp.h>
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "fsm.h"
#include "ipcp.h"
/* global vars */
-ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */
-ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */
-ipcp_options ipcp_allowoptions[NPPP]; /* Options that we allow peer to
- request */
-ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */
+ipcp_options ipcp_wantoptions[_NPPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[_NPPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[_NPPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[_NPPP]; /* Options that we ack'd */
/* local vars */
+static int cis_received[_NPPP]; /* # Conf-Reqs received */
/*
- * VJ compression protocol mode for negotiation. See ipcp.h for a
- * description of each mode.
+ * Callbacks for fsm code. (CI = Configuration Information)
*/
-static int vj_mode = IPCP_VJMODE_RFC1332;
-
-static int vj_opt_len = 6; /* holds length in octets for valid vj */
- /* compression frame depending on mode */
-
-static int vj_opt_val = IPCP_VJ_COMP;
- /* compression negotiation frames */
- /* depending on vj_mode */
-
-static void ipcp_resetci __ARGS((fsm *)); /* Reset our Configuration Information */
-static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
-static void ipcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
-static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
-static void ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
-static void ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Reject some CIs */
-static u_char ipcp_reqci __ARGS((fsm *, u_char *, int *)); /* Check the requested CIs */
+static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */
+static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */
static void ipcp_up __ARGS((fsm *)); /* We're UP */
-static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
+static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
-static fsm ipcp_fsm[NPPP]; /* IPCP fsm structure */
+fsm ipcp_fsm[_NPPP]; /* IPCP fsm structure */
static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
ipcp_resetci, /* Reset our Configuration Information */
@@ -100,19 +78,38 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
ipcp_nakci, /* NAK our Configuration Information */
ipcp_rejci, /* Reject our Configuration Information */
ipcp_reqci, /* Request peer's Configuration Information */
- ipcp_up, /* Called when fsm reaches OPEN state */
- ipcp_down, /* Called when fsm leaves OPEN state */
- NULL, /* Called when fsm reaches CLOSED state */
+ 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 */
NULL, /* Called when Protocol-Reject received */
- NULL /* Retransmission is necessary */
+ NULL, /* Retransmission is necessary */
+ NULL, /* Called to handle protocol-specific codes */
+ "IPCP" /* String name of protocol */
};
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID 2
+#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */
+#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR 6 /* new-style single address option */
+#define CILEN_ADDRS 10 /* old-style dual address option */
+
+
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * Make a string representation of a network IP address.
+ */
char *
ip_ntoa(ipaddr)
u_long ipaddr;
{
- static char b1[64], b2[64], w = 0;
- char *b = (w++&1) ? b1 : b2;
+ static char b[64];
ipaddr = ntohl(ipaddr);
@@ -124,12 +121,13 @@ u_long ipaddr;
return b;
}
+
/*
* ipcp_init - Initialize IPCP.
*/
void
- ipcp_init(unit)
-int unit;
+ipcp_init(unit)
+ int unit;
{
fsm *f = &ipcp_fsm[unit];
ipcp_options *wo = &ipcp_wantoptions[unit];
@@ -137,17 +135,17 @@ int unit;
f->unit = unit;
f->protocol = IPCP;
- f->timeouttime = DEFTIMEOUT;
- f->maxconfreqtransmits = DEFMAXCONFIGREQS;
- f->maxtermtransmits = DEFMAXTERMTRANSMITS;
- f->maxnakloops = DEFMAXNAKLOOPS;
f->callbacks = &ipcp_callbacks;
+ fsm_init(&ipcp_fsm[unit]);
- wo->neg_addrs = 1;
+ wo->neg_addr = 1;
+ wo->old_addrs = 0;
wo->ouraddr = 0;
wo->hisaddr = 0;
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;
@@ -155,77 +153,30 @@ int unit;
/* ppp_if.c to 16 and 1, this needs to be changed (among other */
/* things) gmc */
- ao->neg_addrs = 1; /* accept old style dual addr */
- ao->neg_addr = 1; /* accept new style single addr */
+ ao->neg_addr = 1;
ao->neg_vj = 1;
ao->maxslotindex = MAX_STATES - 1;
ao->cflag = 1;
- fsm_init(&ipcp_fsm[unit]);
}
-/*
- * ipcp_vj_setmode - set option length and option value for vj
- * compression negotiation frames depending on mode
- */
-
-void
- ipcp_vj_setmode(mode)
-int mode;
-{
- vj_mode = mode;
-
- switch (vj_mode) {
-
- case IPCP_VJMODE_OLD: /* with wrong code (0x0037) */
- vj_opt_len = 4;
- vj_opt_val = IPCP_VJ_COMP_OLD;
- break;
-
- case IPCP_VJMODE_RFC1172: /* as per rfc1172 */
- vj_opt_len = 4;
- vj_opt_val = IPCP_VJ_COMP;
- break;
- case IPCP_VJMODE_RFC1332: /* draft mode vj compression */
- vj_opt_len = 6; /* negotiation includes values for */
- /* maxslot and slot number compression */
- vj_opt_val = IPCP_VJ_COMP;
- break;
-
- default:
- IPCPDEBUG((LOG_WARNING, "Unknown vj compression mode %d. Please report \
-this error.", vj_mode))
- break;
- }
-
-}
/*
- * ipcp_activeopen - Actively open IPCP.
+ * ipcp_open - IPCP is allowed to come up.
*/
void
- ipcp_activeopen(unit)
-int unit;
-{
- fsm_activeopen(&ipcp_fsm[unit]);
-}
-
-
-/*
- * ipcp_passiveopen - Passively open IPCP.
- */
-void ipcp_passiveopen(unit)
+ipcp_open(unit)
int unit;
{
- fsm_passiveopen(&ipcp_fsm[unit]);
+ fsm_open(&ipcp_fsm[unit]);
}
/*
- * ipcp_close - Close IPCP.
+ * ipcp_close - Take IPCP down.
*/
void
- ipcp_close(unit)
-int unit;
+ipcp_close(unit)
+ int unit;
{
fsm_close(&ipcp_fsm[unit]);
}
@@ -235,8 +186,8 @@ int unit;
* ipcp_lowerup - The lower layer is up.
*/
void
- ipcp_lowerup(unit)
-int unit;
+ipcp_lowerup(unit)
+ int unit;
{
fsm_lowerup(&ipcp_fsm[unit]);
}
@@ -246,8 +197,8 @@ int unit;
* ipcp_lowerdown - The lower layer is down.
*/
void
- ipcp_lowerdown(unit)
-int unit;
+ipcp_lowerdown(unit)
+ int unit;
{
fsm_lowerdown(&ipcp_fsm[unit]);
}
@@ -257,10 +208,10 @@ int unit;
* ipcp_input - Input IPCP packet.
*/
void
- ipcp_input(unit, p, len)
-int unit;
-u_char *p;
-int len;
+ipcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
fsm_input(&ipcp_fsm[unit], p, len);
}
@@ -269,11 +220,11 @@ int len;
/*
* ipcp_protrej - A Protocol-Reject was received for IPCP.
*
- * Simply pretend that LCP went down.
+ * Pretend the lower layer went down, so we shut up.
*/
void
- ipcp_protrej(unit)
-int unit;
+ipcp_protrej(unit)
+ int unit;
{
fsm_lowerdown(&ipcp_fsm[unit]);
}
@@ -283,10 +234,18 @@ int unit;
* ipcp_resetci - Reset our CI.
*/
static void
- ipcp_resetci(f)
-fsm *f;
+ipcp_resetci(f)
+ fsm *f;
{
- ipcp_gotoptions[f->unit] = ipcp_wantoptions[f->unit];
+ ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+ wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+ if (wo->ouraddr == 0)
+ wo->accept_local = 1;
+ if (wo->hisaddr == 0)
+ wo->accept_remote = 1;
+ ipcp_gotoptions[f->unit] = *wo;
+ cis_received[f->unit] = 0;
}
@@ -294,21 +253,16 @@ fsm *f;
* ipcp_cilen - Return length of our CI.
*/
static int
- ipcp_cilen(f)
-fsm *f;
+ipcp_cilen(f)
+ fsm *f;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
+#define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
-#define LENCISHORT(neg) (neg ? vj_opt_len : 0)
-
-#define LENCIADDRS(neg) (neg ? 10 : 0)
-
-#define LENCIADDR(neg) (neg ? 6 : 0)
-
- return (LENCIADDRS(go->neg_addrs) +
- LENCIADDR(go->neg_addr) +
- LENCISHORT(go->neg_vj));
+ return (LENCIADDR(go->neg_addr, go->old_addrs) +
+ LENCIVJ(go->neg_vj, go->old_vj));
}
@@ -316,50 +270,81 @@ fsm *f;
* ipcp_addci - Add our desired CIs to a packet.
*/
static void
- ipcp_addci(f, ucp)
-fsm *f;
-u_char *ucp;
+ipcp_addci(f, ucp, lenp)
+ fsm *f;
+ 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 ADDCISHORT(opt, neg, val, maxslotindex, cflag) \
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
if (neg) { \
- PUTCHAR(opt, ucp); \
- PUTCHAR(vj_opt_len, ucp); \
- PUTSHORT(val, ucp); \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- PUTCHAR(maxslotindex, ucp); \
- PUTCHAR(cflag, ucp); \
- } \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if (len >= vjlen) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(vjlen, ucp); \
+ PUTSHORT(val, ucp); \
+ if (!old) { \
+ PUTCHAR(maxslotindex, ucp); \
+ PUTCHAR(cflag, ucp); \
+ } \
+ len -= vjlen; \
+ } else \
+ neg = 0; \
}
-#define ADDCIADDRS(opt, neg, val1, val2) \
+#define ADDCIADDR(opt, neg, old, val1, val2) \
if (neg) { \
- u_long l; \
- PUTCHAR(opt, ucp); \
- PUTCHAR(2 + 2 * sizeof (long), ucp); \
- l = ntohl(val1); \
- PUTLONG(l, ucp); \
- l = ntohl(val2); \
- PUTLONG(l, ucp); \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+ if (len >= addrlen) { \
+ u_long l; \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(addrlen, ucp); \
+ l = ntohl(val1); \
+ PUTLONG(l, ucp); \
+ if (old) { \
+ l = ntohl(val2); \
+ PUTLONG(l, ucp); \
+ } \
+ len -= addrlen; \
+ } else \
+ neg = 0; \
}
-#define ADDCIADDR(opt, neg, val) \
- if (neg) { \
- u_long l; \
- PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (long), ucp); \
- l = ntohl(val); \
- PUTLONG(l, ucp); \
+ /*
+ * 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;
+ }
+ }
}
- ADDCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
+ ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
- ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
+ ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
- ADDCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val,
- go->maxslotindex, go->cflag)
+ *lenp -= len;
}
@@ -371,93 +356,74 @@ u_char *ucp;
* 1 - Ack was good.
*/
static int
- ipcp_ackci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+ipcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_short cilen, citype, cishort;
u_long cilong;
u_char cimaxslotindex, cicflag;
+
/*
* 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.
*/
-#define ACKCISHORT(opt, neg, val, maxslotindex, cflag) \
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
if (neg) { \
- if ((len -= vj_opt_len) < 0) \
+ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+ if ((len -= vjlen) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != vj_opt_len || \
+ if (cilen != vjlen || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- GETCHAR(cimaxslotindex, p); \
- if (cimaxslotindex > maxslotindex) \
- goto bad; \
- GETCHAR(cicflag, p); \
- if (cicflag != cflag) \
- goto bad; \
- } \
- }
-
-#define ACKCIADDRS(opt, neg, val1, val2) \
- if (neg) { \
- u_long l; \
- if ((len -= 2 + 2 * sizeof (long)) < 0) \
- goto bad; \
- GETCHAR(citype, p); \
- GETCHAR(cilen, p); \
- if (cilen != 2 + 2 * sizeof (long) || \
- citype != opt) \
- goto bad; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- if (val1) { \
- if (val1 != cilong) \
+ if (!old) { \
+ GETCHAR(cimaxslotindex, p); \
+ if (cimaxslotindex != maxslotindex) \
goto bad; \
- } \
- else \
- val1 = cilong; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- if (val2) { \
- if (val2 != cilong) \
+ GETCHAR(cicflag, p); \
+ if (cicflag != cflag) \
goto bad; \
} \
- else \
- val2 = cilong; \
}
-#define ACKCIADDR(opt, neg, val) \
+#define ACKCIADDR(opt, neg, old, val1, val2) \
if (neg) { \
+ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
u_long l; \
- if ((len -= 2 + sizeof (long)) < 0) \
+ if ((len -= addrlen) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (long) || \
+ if (cilen != addrlen || \
citype != opt) \
goto bad; \
GETLONG(l, p); \
cilong = htonl(l); \
- if (val) { \
- if (val != cilong) \
+ if (val1 != cilong) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ if (val2 != cilong) \
goto bad; \
} \
- else \
- val = cilong; \
}
- ACKCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
- ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
- ACKCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
+ ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
+
+ ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
+
/*
* If there are any remaining CIs, then this packet is bad.
*/
@@ -467,153 +433,246 @@ int len;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
-
- if (vj_mode == IPCP_VJMODE_RFC1332 )
- IPCPDEBUG((LOG_INFO, "ipcp_ackci: citype %d, cilen %l",
- citype, cilen));
-
- if (citype == CI_COMPRESSTYPE) {
- IPCPDEBUG((LOG_INFO, "ipcp_ackci: compress_type %d", cishort));
- if (vj_mode == IPCP_VJMODE_RFC1332)
- IPCPDEBUG((LOG_INFO, ", maxslotindex %d, cflag %d",
- cishort, cimaxslotindex, cicflag));
- }
return (0);
}
/*
- * ipcp_nakci - NAK some of our CIs.
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
*
* Returns:
* 0 - Nak was bad.
* 1 - Nak was good.
*/
-static void
- ipcp_nakci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+ipcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
u_char cimaxslotindex, cicflag;
+ u_char citype, cilen, *next;
u_short cishort;
- u_long ciaddr1, ciaddr2;
+ u_long ciaddr1, ciaddr2, l;
+ ipcp_options no; /* options we've seen Naks for */
+ ipcp_options try; /* options to request next time */
+
+ BZERO(&no, sizeof(no));
+ try = *go;
/*
* Any Nak'd 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.
*/
-#define NAKCISHORT(opt, neg, code) \
- if (neg && \
- len >= vj_opt_len && \
- p[1] == vj_opt_len && \
+#define NAKCIADDR(opt, neg, old, code) \
+ if (go->neg && \
+ len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+ p[1] == cilen && \
p[0] == opt) { \
- len -= vj_opt_len; \
- INCPTR(2, p); \
- GETSHORT(cishort, p); \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
- GETCHAR(cimaxslotindex, p); \
- GETCHAR(cicflag, p); \
- } \
- code \
- }
-
-#define NAKCIADDRS(opt, neg, code) \
- if (neg && \
- len >= 2 + 2 * sizeof (long) && \
- p[1] == 2 + 2 * sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + 2 * sizeof (long); \
+ len -= cilen; \
INCPTR(2, p); \
GETLONG(l, p); \
ciaddr1 = htonl(l); \
- GETLONG(l, p); \
- ciaddr2 = htonl(l); \
+ if (old) { \
+ GETLONG(l, p); \
+ ciaddr2 = htonl(l); \
+ no.old_addrs = 1; \
+ } else \
+ ciaddr2 = 0; \
+ no.neg = 1; \
code \
}
-#define NAKCIADDR(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+#define NAKCIVJ(opt, neg, code) \
+ if (go->neg && \
+ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+ len >= cilen && \
p[0] == opt) { \
- u_long l; \
- len -= 2 + sizeof (long); \
+ len -= cilen; \
INCPTR(2, p); \
- GETLONG(l, p); \
- ciaddr1 = htonl(l); \
- code \
+ GETSHORT(cishort, p); \
+ if (cilen == CILEN_VJ) { \
+ GETCHAR(cimaxslotindex, p); \
+ GETCHAR(cicflag, p); \
+ } \
+ no.neg = 1; \
+ code \
}
- NAKCIADDRS(CI_ADDRS, go->neg_addrs,
- if (!go->ouraddr) { /* Didn't know our address? */
- syslog(LOG_INFO, "local IP address %s", ip_ntoa(ciaddr1));
- go->ouraddr = ciaddr1;
- }
- if (ciaddr2) { /* Does he know his? */
- go->hisaddr = ciaddr2;
- syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr2));
- }
- )
-
- NAKCIADDR(CI_ADDR, go->neg_addr,
- logf(LOG_INFO, "acquired IP address %s", ip_ntoa(ciaddr1));
- if (!go->ouraddr) { /* Didn't know our address? */
- go->ouraddr = ciaddr1;
- syslog(LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr1));
- }
- )
-
- NAKCISHORT(CI_COMPRESSTYPE, go->neg_vj,
- if (cishort != vj_opt_val)
- goto bad;
- go->maxslotindex = cimaxslotindex; /* this is what it */
- go->cflag = cicflag; /* wants */
-
- )
/*
- * If there are any remaining CIs, then this packet is bad.
+ * Accept the peer's idea of {our,his} address, if different
+ * from our idea, only if the accept_{local,remote} flag is set.
*/
- if (len == 0)
- return;
+ NAKCIADDR(CI_ADDR, neg_addr, go->old_addrs,
+ if (go->accept_local && ciaddr1) { /* Do we know our address? */
+ try.ouraddr = ciaddr1;
+ IPCPDEBUG((LOG_INFO, "local IP address %s",
+ ip_ntoa(ciaddr1)));
+ }
+ if (go->accept_remote && ciaddr2) { /* Does he know his? */
+ try.hisaddr = ciaddr2;
+ IPCPDEBUG((LOG_INFO, "remote IP address %s",
+ ip_ntoa(ciaddr2)));
+ }
+ );
+
+ /*
+ * Accept the peer's value of maxslotindex provided that it
+ * is less than what we asked for. Turn off slot-ID compression
+ * if the peer wants. Send old-style compress-type option if
+ * the peer wants.
+ */
+ NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+ if (cilen == CILEN_VJ) {
+ if (cishort == IPCP_VJ_COMP) {
+ try.old_vj = 0;
+ if (cimaxslotindex < go->maxslotindex)
+ try.maxslotindex = cimaxslotindex;
+ if (!cicflag)
+ try.cflag = 0;
+ } else {
+ try.neg_vj = 0;
+ }
+ } else {
+ if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+ try.old_vj = 1;
+ try.vj_protocol = cishort;
+ } else {
+ try.neg_vj = 0;
+ }
+ }
+ );
+
+ /*
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If they want to negotiate about IP addresses, we comply.
+ * If they want us to ask for compression, we refuse.
+ */
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_COMPRESSTYPE:
+ if (go->neg_vj || no.neg_vj ||
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+ goto bad;
+ no.neg_vj = 1;
+ break;
+ case CI_ADDRS:
+ if (go->neg_addr && go->old_addrs || no.old_addrs
+ || cilen != CILEN_ADDRS)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 1;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ GETLONG(l, p);
+ ciaddr2 = htonl(l);
+ if (ciaddr2 && go->accept_remote)
+ try.hisaddr = ciaddr2;
+ no.old_addrs = 1;
+ break;
+ case CI_ADDR:
+ if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+ goto bad;
+ try.neg_addr = 1;
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ no.neg_addr = 1;
+ break;
+ default:
+ goto bad;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+
+ return 1;
+
bad:
IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
+ return 0;
}
/*
* ipcp_rejci - Reject some of our CIs.
*/
-static void
- ipcp_rejci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+ipcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
ipcp_options *go = &ipcp_gotoptions[f->unit];
- u_char cimaxslotindex, ciflag;
+ u_char cimaxslotindex, ciflag, cilen;
u_short cishort;
u_long cilong;
+ ipcp_options try; /* options to request next time */
+ try = *go;
/*
* 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.
*/
-#define REJCISHORT(opt, neg, val, maxslot, cflag) \
- if (neg && \
- len >= vj_opt_len && \
- p[1] == vj_opt_len && \
+#define REJCIADDR(opt, neg, old, val1, val2) \
+ if (go->neg && \
+ len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+ p[1] == cilen && \
+ p[0] == opt) { \
+ u_long l; \
+ len -= cilen; \
+ INCPTR(2, p); \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val1) \
+ goto bad; \
+ if (old) { \
+ GETLONG(l, p); \
+ cilong = htonl(l); \
+ /* Check rejected value. */ \
+ if (cilong != val2) \
+ goto bad; \
+ } \
+ try.neg = 0; \
+ }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+ if (go->neg && \
+ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+ len >= p[1] && \
p[0] == opt) { \
- len -= vj_opt_len; \
+ len -= p[1]; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
if (cishort != val) \
goto bad; \
- if (vj_mode == IPCP_VJMODE_RFC1332) { \
+ if (!old) { \
GETCHAR(cimaxslotindex, p); \
if (cimaxslotindex != maxslot) \
goto bad; \
@@ -621,60 +680,30 @@ int len;
if (ciflag != cflag) \
goto bad; \
} \
- neg = 0; \
+ try.neg = 0; \
}
-#define REJCIADDRS(opt, neg, val1, val2) \
- if (neg && \
- len >= 2 + 2 * sizeof (long) && \
- p[1] == 2 + 2 * sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + 2 * sizeof (long); \
- INCPTR(2, p); \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val2) \
- goto bad; \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val1) \
- goto bad; \
- neg = 0; \
- }
+ REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+ go->old_addrs, go->ouraddr, go->hisaddr);
-#define REJCIADDR(opt, neg, val) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
- p[0] == opt) { \
- u_long l; \
- len -= 2 + sizeof (long); \
- INCPTR(2, p); \
- GETLONG(l, p); \
- cilong = htonl(l); \
- /* Check rejected value. */ \
- if (cilong != val) \
- goto bad; \
- neg = 0; \
- }
-
- REJCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
-
- REJCIADDR(CI_ADDR, go->neg_addr, go->ouraddr)
-
- REJCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
+ REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+ go->maxslotindex, go->cflag);
/*
* If there are any remaining CIs, then this packet is bad.
*/
- if (len == 0)
- return;
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
bad:
IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
+ return 0;
}
@@ -682,25 +711,27 @@ bad:
* ipcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
- * appropriately.
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
-static u_char
- ipcp_reqci(f, inp, len)
-fsm *f;
-u_char *inp; /* Requested CIs */
-int *len; /* Length of requested CIs */
+static int
+ipcp_reqci(f, inp, len, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *len; /* Length of requested CIs */
+ int reject_if_disagree;
{
ipcp_options *wo = &ipcp_wantoptions[f->unit];
ipcp_options *ho = &ipcp_hisoptions[f->unit];
ipcp_options *ao = &ipcp_allowoptions[f->unit];
ipcp_options *go = &ipcp_gotoptions[f->unit];
- u_char *cip; /* Pointer to Current CI */
+ u_char *cip, *next; /* Pointer to current and next CIs */
u_short cilen, citype; /* Parsed len, type */
u_short cishort; /* Parsed short value */
- u_long tl, ciaddr1, ciaddr2; /* Parsed address values */
+ u_long tl, ciaddr1, ciaddr2;/* Parsed address values */
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
- u_char *p = inp; /* Pointer to next char to parse */
+ 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;
@@ -708,17 +739,15 @@ int *len; /* Length of requested CIs */
/*
* Reset all his options.
*/
- ho->neg_addrs = 0;
- ho->neg_vj = 0;
- ho->maxslotindex = 0;
- ho->cflag = 0;
+ BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
+ next = inp;
while (l) {
orc = CONFACK; /* Assume success */
- cip = p; /* Remember begining of CI */
+ 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? */
@@ -731,15 +760,13 @@ int *len; /* Length of requested CIs */
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
- cilen -= 2; /* Adjust cilen to just data */
+ next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_ADDRS:
- logf(LOG_INFO, "ipcp: received ADDRS ");
- if (!ao->neg_addrs ||
- cilen != 2 * sizeof (long))
- { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
+ case CI_ADDRS:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
+ if (!ao->neg_addr ||
+ cilen != CILEN_ADDRS) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
@@ -752,13 +779,15 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse source address (his) */
ciaddr1 = htonl(tl);
- if (!ciaddr1 ||
- (wo->neg_addrs && wo->hisaddr && ciaddr1 != wo->hisaddr))
- {
+ IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = wo->neg_addrs ? ntohl(wo->hisaddr) : 0;
- PUTLONG(tl, p);
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
}
/*
@@ -767,37 +796,35 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse desination address (ours) */
ciaddr2 = htonl(tl);
- logf(LOG_INFO, "(%s:%s)", ip_ntoa(ciaddr1), ip_ntoa(ciaddr2));
- if (!ciaddr2 ||
- (wo->neg_addrs && wo->ouraddr && ciaddr2 != wo->ouraddr))
- {
- orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = ntohl(wo->ouraddr);
- PUTLONG(tl, p);
+ IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
+ if (ciaddr2 != wo->ouraddr) {
+ if (ciaddr2 == 0 || !wo->accept_local) {
+ orc = CONFNAK;
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->ouraddr);
+ PUTLONG(tl, p);
+ }
+ } else {
+ go->ouraddr = ciaddr2; /* accept peer's idea */
+ }
}
- if (orc == CONFNAK)
- break;
- /* XXX ho or go? */
- ho->neg_addrs = 1;
+ ho->neg_addr = 1;
+ ho->old_addrs = 1;
ho->hisaddr = ciaddr1;
ho->ouraddr = ciaddr2;
break;
- case CI_ADDR:
- logf(LOG_INFO, "ipcp: received ADDR ");
- go->got_addr = 1;
- go->neg_addrs = 0;
- go->neg_addr = 1;
+ case CI_ADDR:
+ IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
if (!ao->neg_addr ||
- cilen != sizeof (long)) { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
- orc = CONFREJ; /* Reject CI */
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
break;
}
-
+
/*
* If he has no address, or if we both have his address but
* disagree about it, then NAK it with our idea.
@@ -806,86 +833,83 @@ int *len; /* Length of requested CIs */
*/
GETLONG(tl, p); /* Parse source address (his) */
ciaddr1 = htonl(tl);
- logf(LOG_INFO, "(%s)", ip_ntoa(ciaddr1));
- if (!ciaddr1 ||
- (wo->neg_addr && wo->hisaddr && ciaddr1 != wo->hisaddr)) {
+ IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
+ if (ciaddr1 != wo->hisaddr
+ && (ciaddr1 == 0 || !wo->accept_remote)) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- tl = wo->neg_addr ? ntohl(wo->hisaddr) : 0;
- PUTLONG(tl, p);
+ if (!reject_if_disagree) {
+ DECPTR(sizeof (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
}
- if (orc == CONFNAK)
- break;
-
- /* XXX ho or go? */
ho->neg_addr = 1;
ho->hisaddr = ciaddr1;
break;
- case CI_COMPRESSTYPE:
- logf(LOG_INFO, "ipcp: received COMPRESSTYPE ");
+ case CI_COMPRESSTYPE:
+ IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
if (!ao->neg_vj ||
- cilen != (vj_opt_len - 2)) {
- INCPTR(cilen, p);
+ (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
orc = CONFREJ;
break;
}
GETSHORT(cishort, p);
- logf(LOG_INFO, "(%d)", cishort);
+ IPCPDEBUG((LOG_INFO, "(%d)", cishort));
- /*
- * Compresstype must be vj_opt_val.
- */
- if (cishort != vj_opt_val) {
- DECPTR(sizeof (short), p);
- orc = CONFNAK;
- PUTSHORT(vj_opt_val, p);
+ if (!(cishort == IPCP_VJ_COMP ||
+ (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+ orc = CONFREJ;
break;
}
- ho->neg_vj = 1;
- if (vj_mode == IPCP_VJMODE_RFC1332) {
- GETCHAR(maxslotindex, p);
- if (maxslotindex > wo->maxslotindex) {
- DECPTR(1, p);
- orc = CONFNAK;
- PUTCHAR(wo->maxslotindex, p);
- break;
- }
- ho->maxslotindex = maxslotindex;
- GETCHAR(cflag, p);
- if (cflag != wo->cflag) {
- DECPTR(1, p);
- orc = CONFNAK;
- PUTCHAR(wo->cflag, p);
- break;
- }
- ho->cflag = wo->cflag;
+ ho->neg_vj = 1;
+ ho->vj_protocol = cishort;
+ if (cilen == CILEN_VJ) {
+ GETCHAR(maxslotindex, p);
+ if (maxslotindex > ao->maxslotindex) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(ao->maxslotindex, p);
+ }
+ }
+ GETCHAR(cflag, p);
+ if (cflag && !ao->cflag) {
+ orc = CONFNAK;
+ if (!reject_if_disagree){
+ DECPTR(1, p);
+ PUTCHAR(wo->cflag, p);
+ }
+ }
+ ho->maxslotindex = maxslotindex;
+ ho->cflag = wo->cflag;
}
break;
- default:
- INCPTR(cilen, p);
+ default:
orc = CONFREJ;
break;
}
- cilen += 2; /* Adjust cilen whole CI */
endswitch:
- logf(LOG_INFO, " (%s)\n",
- orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "Reject"));
+ IPCPDEBUG((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 (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 (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ 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 */
+ }
}
}
@@ -897,72 +921,137 @@ endswitch:
/* Need to move CI? */
if (ucp != cip)
- /* Move it */
- memcpy(ucp, cip, (size_t)cilen);
+ BCOPY(cip, ucp, cilen); /* Move it */
/* Update output pointer */
INCPTR(cilen, ucp);
}
/*
- * XXX If we wanted to send additional NAKs (for unsent CIs), the
- * code would go here. This must be done with care since it might
- * require a longer packet than we received.
+ * 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 CI_ADDR option appended. We assume the
+ * input buffer is long enough that we can append the extra
+ * option safely.
*/
+ if (rc != CONFREJ && !ho->neg_addr &&
+ wo->req_addr && !reject_if_disagree) {
+ if (rc == CONFACK) {
+ rc = CONFNAK;
+ ucp = inp; /* reset pointer */
+ wo->req_addr = 0; /* don't ask again */
+ }
+ PUTCHAR(CI_ADDR, ucp);
+ PUTCHAR(CILEN_ADDR, ucp);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, ucp);
+ }
*len = ucp - inp; /* Compute output length */
-
- syslog(LOG_INFO, "ipcp: returning Configure-%s",
- rc == CONFACK ? "ACK" :
- rc == CONFNAK ? "NAK" : "Reject");
-
+ IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
return (rc); /* Return final code */
}
/*
* ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
*/
static void
- ipcp_up(f)
-fsm *f;
+ipcp_up(f)
+ fsm *f;
{
- u_long mask;
+ u_long mask;
+ ipcp_options *ho = &ipcp_hisoptions[f->unit];
+ ipcp_options *go = &ipcp_gotoptions[f->unit];
- syslog(LOG_INFO, "ipcp: up");
+ IPCPDEBUG((LOG_INFO, "ipcp: up"));
+ go->default_route = 0;
+ go->proxy_arp = 0;
- if (ipcp_hisoptions[f->unit].hisaddr == 0)
- ipcp_hisoptions[f->unit].hisaddr = ipcp_wantoptions[f->unit].hisaddr;
+ /*
+ * 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;
- syslog(LOG_INFO, "local IP address %s",
- ip_ntoa(ipcp_gotoptions[f->unit].ouraddr));
- syslog(LOG_INFO, "remote IP address %s",
- ip_ntoa(ipcp_hisoptions[f->unit].hisaddr));
+ if (ho->hisaddr == 0) {
+ syslog(LOG_ERR, "Could not determine remote IP address");
+ ipcp_close(f->unit);
+ return;
+ }
+ if (go->ouraddr == 0) {
+ syslog(LOG_ERR, "Could not determine local IP address");
+ ipcp_close(f->unit);
+ return;
+ }
- SIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
- ipcp_hisoptions[f->unit].hisaddr);
+ /*
+ * Check that the peer is allowed to use the IP address he wants.
+ */
+ 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);
+ return;
+ }
- /* set new netmask if specified */
- mask = GetMask(ipcp_gotoptions[f->unit].ouraddr);
- if (mask)
- SIFMASK(f->unit, mask);
+ syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr));
+ syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+
+ /*
+ * Set IP addresses and (if specified) netmask.
+ */
+ mask = GetMask(go->ouraddr);
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit);
+ return;
+ }
- /* set tcp compression */
- SIFVJCOMP(f->unit, ipcp_hisoptions[f->unit].neg_vj);
+ /* set tcp compression */
+ sifvjcomp(f->unit, ho->neg_vj, ho->cflag);
+
+ /* bring the interface up for IP */
+ if (!sifup(f->unit)) {
+ IPCPDEBUG((LOG_WARNING, "sifup failed"));
+ ipcp_close(f->unit);
+ return;
+ }
+
+ /* 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;
+
+ /* Make a proxy ARP entry if requested. */
+ if (ipcp_wantoptions[f->unit].proxy_arp)
+ if (sifproxyarp(f->unit, ho->hisaddr))
+ go->proxy_arp = 1;
}
/*
* ipcp_down - IPCP has gone DOWN.
*
- * Alert other protocols.
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
*/
static void
- ipcp_down(f)
-fsm *f;
+ipcp_down(f)
+ fsm *f;
{
- syslog(LOG_INFO, "ipcp: down");
-
- CIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
- ipcp_hisoptions[f->unit].hisaddr);
+ u_long ouraddr, hisaddr;
+
+ IPCPDEBUG((LOG_INFO, "ipcp: down"));
+
+ 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);
}
diff --git a/libexec/pppd/ipcp.h b/libexec/pppd/ipcp.h
index 3bbec12442ef..bae91e55c455 100644
--- a/libexec/pppd/ipcp.h
+++ b/libexec/pppd/ipcp.h
@@ -15,6 +15,8 @@
* 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: ipcp.h,v 1.2 1994/03/30 09:31:30 jkh Exp $
*/
/*
@@ -26,36 +28,38 @@
#define MAX_STATES 16 /* from slcompress.h */
-#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
-#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
-#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
- /* maxslot and slot number */
- /* compression from Aug. 1991 */
- /* ipcp draft RFC) */
+#define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */
+ /* maxslot and slot number compression) */
#define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/
#define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */
/* compression option*/
typedef struct ipcp_options {
- int neg_addrs : 1; /* Negotiate IP Addresses? */
int neg_addr : 1; /* Negotiate IP Address? */
- int got_addr : 1; /* Got IP Address? */
- u_long ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
+ int old_addrs : 1; /* Use old (IP-Addresses) option? */
+ int req_addr : 1; /* Ask peer to send IP address? */
+ int default_route : 1; /* Assign default route through interface? */
+ int proxy_arp : 1; /* Make proxy ARP entry for peer? */
int neg_vj : 1; /* Van Jacobson Compression? */
- u_char maxslotindex, cflag; /* fields for Aug. 1991 Draft VJ */
- /* compression negotiation */
+ int old_vj : 1; /* use old (short) form of VJ option? */
+ int accept_local : 1; /* accept peer's value for ouraddr */
+ int accept_remote : 1; /* accept peer's value for hisaddr */
+ u_short vj_protocol; /* protocol value to use in VJ option */
+ u_char maxslotindex, cflag; /* values for RFC1332 VJ compression neg. */
+ u_long ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */
} ipcp_options;
+extern fsm ipcp_fsm[];
extern ipcp_options ipcp_wantoptions[];
extern ipcp_options ipcp_gotoptions[];
extern ipcp_options ipcp_allowoptions[];
extern ipcp_options ipcp_hisoptions[];
void ipcp_init __ARGS((int));
-void ipcp_vj_setmode __ARGS((int));
-void ipcp_activeopen __ARGS((int));
-void ipcp_passiveopen __ARGS((int));
+void ipcp_open __ARGS((int));
void ipcp_close __ARGS((int));
void ipcp_lowerup __ARGS((int));
void ipcp_lowerdown __ARGS((int));
diff --git a/libexec/pppd/lcp.c b/libexec/pppd/lcp.c
index d95a8faf575f..e991ef66d3a0 100644
--- a/libexec/pppd/lcp.c
+++ b/libexec/pppd/lcp.c
@@ -17,13 +17,13 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: lcp.c,v 1.3 1994/03/30 09:38:14 jkh Exp $";
+#endif
+
/*
* TODO:
- * Keepalive.
- * Send NAKs for unsent CIs.
- * Keep separate MTU, MRU.
* Option tracing.
- * Extra data on authtype option.
* Test restart.
*/
@@ -35,19 +35,13 @@
#include <sys/time.h>
#include <net/if.h>
+#include <net/if_ppp.h>
#include <netinet/in.h>
#include <string.h>
-#ifdef STREAMS
-#include <sys/stream.h>
-#include "ppp_str.h"
-#endif
-
-#include <net/if_ppp.h>
#include "pppd.h"
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "fsm.h"
#include "lcp.h"
#include "magic.h"
@@ -56,26 +50,28 @@
#include "ipcp.h"
/* global vars */
-fsm lcp_fsm[NPPP]; /* LCP fsm structure (global)*/
-lcp_options lcp_wantoptions[NPPP]; /* Options that we want to request */
-lcp_options lcp_gotoptions[NPPP]; /* Options that peer ack'd */
-lcp_options lcp_allowoptions[NPPP]; /* Options that we allow peer to request */
-lcp_options lcp_hisoptions[NPPP]; /* Options that we ack'd */
-
-/* local vars */
-static void lcp_resetci __ARGS((fsm *));
- /* Reset our Configuration Information */
-static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
-static void lcp_addci __ARGS((fsm *, u_char *)); /* Add our CIs */
-static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Ack some CIs */
-static void lcp_nakci __ARGS((fsm *, u_char *, int)); /* Nak some CIs */
-static void lcp_rejci __ARGS((fsm *, u_char *, int));
- /* Reject some CIs */
-static u_char lcp_reqci __ARGS((fsm *, u_char *, int *));
- /* Check the requested CIs */
-static void lcp_up __ARGS((fsm *)); /* We're UP */
-static void lcp_down __ARGS((fsm *)); /* We're DOWN */
-static void lcp_closed __ARGS((fsm *)); /* We're CLOSED */
+fsm lcp_fsm[_NPPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[_NPPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[_NPPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[_NPPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[_NPPP]; /* Options that we ack'd */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void lcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __ARGS((fsm *)); /* We're UP */
+static void lcp_down __ARGS((fsm *)); /* We're DOWN */
+static void lcp_starting __ARGS((fsm *)); /* We need lower layer up */
+static void lcp_finished __ARGS((fsm *)); /* We need lower layer down */
+static int lcp_extcode __ARGS((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __ARGS((fsm *, u_char *, int));
static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_resetci, /* Reset our Configuration Information */
@@ -85,96 +81,104 @@ static fsm_callbacks lcp_callbacks = { /* LCP callback routines */
lcp_nakci, /* NAK our Configuration Information */
lcp_rejci, /* Reject our Configuration Information */
lcp_reqci, /* Request peer's Configuration Information */
- lcp_up, /* Called when fsm reaches OPEN state */
- lcp_down, /* Called when fsm leaves OPEN state */
- lcp_closed, /* Called when fsm reaches CLOSED state */
+ lcp_up, /* Called when fsm reaches OPENED state */
+ lcp_down, /* Called when fsm leaves OPENED state */
+ lcp_starting, /* Called when we want the lower layer up */
+ lcp_finished, /* Called when we want the lower layer down */
NULL, /* Called when Protocol-Reject received */
- NULL /* Retransmission is necessary */
+ NULL, /* Retransmission is necessary */
+ lcp_extcode, /* Called to handle LCP-specific codes */
+ "LCP" /* String name of protocol */
};
+int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID 2
+#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 DEFWARNLOOPS 10 /* XXX Move to lcp.h */
-static int lcp_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \
+ (x) == CONFNAK ? "NAK" : "REJ")
/*
* lcp_init - Initialize LCP.
*/
void
- lcp_init(unit)
-int unit;
+lcp_init(unit)
+ int unit;
{
- fsm *f = &lcp_fsm[unit];
- lcp_options *wo = &lcp_wantoptions[unit];
- lcp_options *ao = &lcp_allowoptions[unit];
-
- f->unit = unit;
- f->protocol = LCP;
- f->timeouttime = DEFTIMEOUT;
- f->maxconfreqtransmits = DEFMAXCONFIGREQS;
- f->maxtermtransmits = DEFMAXTERMTRANSMITS;
- f->maxnakloops = DEFMAXNAKLOOPS;
- f->callbacks = &lcp_callbacks;
-
- wo->passive = 0;
- wo->restart = 0; /* Set to 1 in kernels or multi-line
- implementations */
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+ lcp_options *ao = &lcp_allowoptions[unit];
- wo->neg_mru = 1;
- wo->mru = DEFMRU;
- wo->neg_asyncmap = 1;
- wo->asyncmap = 0;
- wo->neg_chap = 0; /* Set to 1 on server */
- wo->neg_upap = 0; /* Set to 1 on server */
- wo->neg_magicnumber = 1;
- wo->neg_pcompression = 1;
- wo->neg_accompression = 1;
-
- ao->neg_mru = 1;
- ao->neg_asyncmap = 1;
- ao->neg_chap = 0; /* Set to 1 on client */
- ao->chap_mdtype = CHAP_DIGEST_MD5;
- ao->chap_callback = CHAP_NOCALLBACK;
- ao->neg_upap = 0; /* Set to 1 on client */
-
- ao->neg_magicnumber = 1;
- ao->neg_pcompression = 1;
- ao->neg_accompression = 1;
-
- fsm_init(f);
-}
+ f->unit = unit;
+ f->protocol = LCP;
+ f->callbacks = &lcp_callbacks;
+ fsm_init(f);
+
+ wo->passive = 0;
+ wo->silent = 0;
+ wo->restart = 0; /* Set to 1 in kernels or multi-line
+ implementations */
+ wo->neg_mru = 1;
+ wo->mru = DEFMRU;
+ wo->neg_asyncmap = 1;
+ wo->asyncmap = 0;
+ wo->neg_chap = 0; /* Set to 1 on server */
+ wo->neg_upap = 0; /* Set to 1 on server */
+ wo->chap_mdtype = CHAP_DIGEST_MD5;
+ wo->neg_magicnumber = 1;
+ wo->neg_pcompression = 1;
+ wo->neg_accompression = 1;
+ wo->neg_lqr = 0; /* no LQR implementation yet */
+
+ ao->neg_mru = 1;
+ ao->mru = MAXMRU;
+ ao->neg_asyncmap = 1;
+ ao->asyncmap = 0;
+ ao->neg_chap = 1;
+ ao->chap_mdtype = CHAP_DIGEST_MD5;
+ ao->neg_upap = 1;
+ ao->neg_magicnumber = 1;
+ ao->neg_pcompression = 1;
+ ao->neg_accompression = 1;
+ ao->neg_lqr = 0; /* no LQR implementation yet */
-/*
- * lcp_activeopen - Actively open LCP.
- */
-void
- lcp_activeopen(unit)
-int unit;
-{
- fsm_activeopen(&lcp_fsm[unit]);
}
/*
- * lcp_passiveopen - Passively open LCP.
+ * lcp_open - LCP is allowed to come up.
*/
void
- lcp_passiveopen(unit)
-int unit;
+lcp_open(unit)
+ int unit;
{
- fsm_passiveopen(&lcp_fsm[unit]);
+ fsm *f = &lcp_fsm[unit];
+ lcp_options *wo = &lcp_wantoptions[unit];
+
+ f->flags = 0;
+ if (wo->passive)
+ f->flags |= OPT_PASSIVE;
+ if (wo->silent)
+ f->flags |= OPT_SILENT;
+ fsm_open(f);
}
/*
- * lcp_close - Close LCP.
+ * lcp_close - Take LCP down.
*/
void
- lcp_close(unit)
-int unit;
+lcp_close(unit)
+ int unit;
{
fsm_close(&lcp_fsm[unit]);
}
@@ -184,14 +188,13 @@ int unit;
* lcp_lowerup - The lower layer is up.
*/
void
- lcp_lowerup(unit)
-int unit;
+lcp_lowerup(unit)
+ int unit;
{
- SIFDOWN(unit);
- SIFMTU(unit, MTU);
- SIFASYNCMAP(unit, 0xffffffff);
- CIFPCOMPRESSION(unit);
- CIFACCOMPRESSION(unit);
+ sifdown(unit);
+ ppp_send_config(unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, MTU, 0, 0, 0);
+ peer_mru[unit] = MTU;
fsm_lowerup(&lcp_fsm[unit]);
}
@@ -201,8 +204,8 @@ int unit;
* lcp_lowerdown - The lower layer is down.
*/
void
- lcp_lowerdown(unit)
-int unit;
+lcp_lowerdown(unit)
+ int unit;
{
fsm_lowerdown(&lcp_fsm[unit]);
}
@@ -212,28 +215,103 @@ int unit;
* lcp_input - Input LCP packet.
*/
void
- lcp_input(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_input(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
fsm_input(&lcp_fsm[unit], p, len);
}
/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+ fsm *f;
+ int code, id;
+ u_char *inp;
+ int len;
+{
+ switch( code ){
+ case PROTREJ:
+ lcp_rprotrej(f, inp, len);
+ break;
+
+ case ECHOREQ:
+ if( f->state != OPENED )
+ break;
+ LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+ fsm_sdata(f, ECHOREP, id, inp, len);
+ break;
+
+ case ECHOREP:
+ case DISCREQ:
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+ fsm *f;
+ u_char *inp;
+ int len;
+{
+ u_short prot;
+
+ LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
+
+ if (len < sizeof (u_short)) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+ return;
+ }
+
+ GETSHORT(prot, inp);
+
+ LCPDEBUG((LOG_INFO,
+ "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!",
+ prot));
+
+ /*
+ * Protocol-Reject packets received in any state other than the LCP
+ * OPENED state SHOULD be silently discarded.
+ */
+ if( f->state != OPENED ){
+ LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d",
+ f->state));
+ return;
+ }
+
+ DEMUXPROTREJ(f->unit, prot); /* Inform protocol */
+}
+
+
+/*
* lcp_protrej - A Protocol-Reject was received.
*/
/*ARGSUSED*/
void
- lcp_protrej(unit)
-int unit;
+lcp_protrej(unit)
+ int unit;
{
/*
* Can't reject LCP!
*/
LCPDEBUG((LOG_WARNING,
- "lcp_protrej: Received Protocol-Reject for LCP!"))
+ "lcp_protrej: Received Protocol-Reject for LCP!"));
+ fsm_protreject(&lcp_fsm[unit]);
}
@@ -241,13 +319,14 @@ int unit;
* lcp_sprotrej - Send a Protocol-Reject for some protocol.
*/
void
- lcp_sprotrej(unit, p, len)
-int unit;
-u_char *p;
-int len;
+lcp_sprotrej(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
{
- /* this is marginal, as rejected-info should be full frame,
- * but at least we return the rejected-protocol
+ /*
+ * Send back the protocol and the information field of the
+ * rejected packet. We only get here if LCP is in the OPENED state.
*/
p += 2;
len -= 2;
@@ -267,6 +346,7 @@ 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] = MTU;
}
@@ -274,20 +354,25 @@ fsm *f;
* lcp_cilen - Return length of our CI.
*/
static int
- lcp_cilen(f)
-fsm *f;
+lcp_cilen(f)
+ fsm *f;
{
lcp_options *go = &lcp_gotoptions[f->unit];
-#define LENCIVOID(neg) (neg ? 2 : 0)
-#define LENCICHAP(neg) (neg ? 6 : 0)
-#define LENCISHORT(neg) (neg ? 4 : 0)
-#define LENCILONG(neg) (neg ? 6 : 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)
+ /*
+ * 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) +
LENCICHAP(go->neg_chap) +
- LENCISHORT(go->neg_upap) +
+ LENCISHORT(!go->neg_chap && go->neg_upap) +
+ LENCILQR(go->neg_lqr) +
LENCILONG(go->neg_magicnumber) +
LENCIVOID(go->neg_pcompression) +
LENCIVOID(go->neg_accompression));
@@ -298,60 +383,75 @@ fsm *f;
* lcp_addci - Add our desired CIs to a packet.
*/
static void
- lcp_addci(f, ucp)
-fsm *f;
-u_char *ucp;
+lcp_addci(f, ucp, lenp)
+ fsm *f;
+ u_char *ucp;
+ int *lenp;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char *start_ucp = ucp;
#define ADDCIVOID(opt, neg) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2, ucp); \
+ PUTCHAR(CILEN_VOID, ucp); \
}
#define ADDCISHORT(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (short), ucp); \
+ PUTCHAR(CILEN_SHORT, ucp); \
PUTSHORT(val, ucp); \
}
-#define ADDCICHAP(opt, neg, val, digest, callback) \
+#define ADDCICHAP(opt, neg, val, digest) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(6, ucp); \
+ PUTCHAR(CILEN_CHAP, ucp); \
PUTSHORT(val, ucp); \
PUTCHAR(digest, ucp); \
- PUTCHAR(callback, ucp); \
}
#define ADDCILONG(opt, neg, val) \
if (neg) { \
PUTCHAR(opt, ucp); \
- PUTCHAR(2 + sizeof (long), ucp); \
+ PUTCHAR(CILEN_LONG, ucp); \
+ PUTLONG(val, ucp); \
+ }
+#define ADDCILQR(opt, neg, val) \
+ if (neg) { \
+ PUTCHAR(opt, ucp); \
+ PUTCHAR(CILEN_LQR, ucp); \
+ PUTSHORT(LQR, ucp); \
PUTLONG(val, ucp); \
}
- ADDCISHORT(CI_MRU, go->neg_mru, go->mru)
- ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ADDCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ADDCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ADDCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+ if (ucp - start_ucp != *lenp) {
+ /* this should never happen, because peer_mtu should be 1500 */
+ syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
+ }
}
/*
* lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
*
* Returns:
* 0 - Ack was bad.
* 1 - Ack was good.
*/
static int
- lcp_ackci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+lcp_ackci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
u_char cilen, citype, cichar;
@@ -365,34 +465,34 @@ int len;
*/
#define ACKCIVOID(opt, neg) \
if (neg) { \
- if ((len -= 2) < 0) \
+ if ((len -= CILEN_VOID) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 || \
+ if (cilen != CILEN_VOID || \
citype != opt) \
goto bad; \
}
#define ACKCISHORT(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (short)) < 0) \
+ if ((len -= CILEN_SHORT) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (short) || \
+ if (cilen != CILEN_SHORT || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
if (cishort != val) \
goto bad; \
}
-#define ACKCICHAP(opt, neg, val, digest, callback) \
+#define ACKCICHAP(opt, neg, val, digest) \
if (neg) { \
- if ((len -= 4 + sizeof (short)) < 0) \
+ if ((len -= CILEN_CHAP) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 4 + sizeof (short) || \
+ if (cilen != CILEN_CHAP || \
citype != opt) \
goto bad; \
GETSHORT(cishort, p); \
@@ -401,31 +501,45 @@ int len;
GETCHAR(cichar, p); \
if (cichar != digest) \
goto bad; \
- GETCHAR(cichar, p); \
- if (cichar != callback) \
- goto bad; \
}
#define ACKCILONG(opt, neg, val) \
if (neg) { \
- if ((len -= 2 + sizeof (long)) < 0) \
+ if ((len -= CILEN_LONG) < 0) \
goto bad; \
GETCHAR(citype, p); \
GETCHAR(cilen, p); \
- if (cilen != 2 + sizeof (long) || \
+ if (cilen != CILEN_LONG || \
citype != opt) \
goto bad; \
GETLONG(cilong, p); \
if (cilong != val) \
goto bad; \
}
+#define ACKCILQR(opt, neg, val) \
+ if (neg) { \
+ if ((len -= CILEN_LQR) < 0) \
+ goto bad; \
+ GETCHAR(citype, p); \
+ GETCHAR(cilen, p); \
+ if (cilen != CILEN_LQR || \
+ citype != opt) \
+ goto bad; \
+ GETSHORT(cishort, p); \
+ if (cishort != LQR) \
+ goto bad; \
+ GETLONG(cilong, p); \
+ if (cilong != val) \
+ goto bad; \
+ }
- ACKCISHORT(CI_MRU, go->neg_mru, go->mru)
- ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->chap_callback)
- ACKCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ ACKCISHORT(CI_MRU, go->neg_mru, go->mru);
+ ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap);
+ ACKCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+ ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+ ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+ ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
@@ -434,67 +548,97 @@ int len;
goto bad;
return (1);
bad:
- LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"))
+ LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"));
return (0);
}
/*
- * lcp_nakci - NAK some of our CIs.
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Nak was bad.
+ * 1 - Nak was good.
*/
-static void
- lcp_nakci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_nakci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *wo = &lcp_wantoptions[f->unit];
+ u_char cilen, citype, cichar, *next;
u_short cishort;
u_long cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+
+ BZERO(&no, sizeof(no));
+ try = *go;
+
/*
* Any Nak'd 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.
*/
#define NAKCIVOID(opt, neg, code) \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ no.neg = 1; \
code \
}
-#define NAKCICHAP(opt, neg, digest, callback, code) \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define NAKCICHAP(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
- INCPTR(2, p); \
+ GETCHAR(cichar, p); \
+ no.neg = 1; \
code \
}
#define NAKCISHORT(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ no.neg = 1; \
code \
}
#define NAKCILONG(opt, neg, code) \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
+ no.neg = 1; \
+ code \
+ }
+#define NAKCILQR(opt, neg, code) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ no.neg = 1; \
code \
}
@@ -502,143 +646,270 @@ int len;
* We don't care if they want to send us smaller packets than
* we want. Therefore, accept any MRU less than what we asked for,
* but then ignore the new value when setting the MRU in the kernel.
- * If they send us a bigger MRU than what we asked, reject it and
- * let him decide to accept our value.
+ * 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;
+ );
+ /*
+ * Add any characters they want to our (receive-side) asyncmap.
+ */
+ NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+ try.asyncmap = go->asyncmap | cilong;
+ );
+ /*
+ * If they can't cope with our CHAP hash algorithm, we'll have
+ * to stop asking for CHAP. We haven't got any other algorithm.
+ */
+ NAKCICHAP(CI_AUTHTYPE, neg_chap,
+ try.neg_chap = 0;
+ );
+ /*
+ * Peer shouldn't send Nak for UPAP, 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 ?
+ */
+ NAKCILONG(CI_QUALITY, neg_lqr,
+ if (cishort != LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+ /*
+ * Check for a looped-back line.
*/
- NAKCISHORT(CI_MRU, go->neg_mru,
- if (cishort <= wo->mru)
- go->mru = cishort;
- else
- goto bad;
- )
- NAKCILONG(CI_ASYNCMAP, go->neg_asyncmap,
- go->asyncmap |= cilong;
- )
- NAKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype, go->chap_callback,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate chap!"))
- )
- NAKCISHORT(CI_AUTHTYPE, go->neg_upap,
- LCPDEBUG((LOG_WARNING, "Peer refuses to authenticate pap!"))
- )
- NAKCILONG(CI_MAGICNUMBER, go->neg_magicnumber,
- go->magicnumber = magic();
- if (++go->numloops % lcp_warnloops == 0)
- LCPDEBUG((LOG_INFO, "The line appears to be looped back."))
- )
- NAKCIVOID(CI_PCOMPRESSION, go->neg_pcompression,
- go->neg_pcompression = 0;
- )
- NAKCIVOID(CI_ACCOMPRESSION, go->neg_accompression,
- go->neg_accompression = 0;
- )
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ ++try.numloops;
+ looped_back = 1;
+ );
+
+ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+ try.neg_pcompression = 0;
+ );
+ NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+ try.neg_accompression = 0;
+ );
/*
- * If there are any remaining CIs, then this packet is bad.
+ * There may be remaining CIs, if the peer is requesting negotiation
+ * on an option that we didn't include in our request packet.
+ * If we see an option that we requested, or one we've already seen
+ * in this packet, then this packet is bad.
+ * If we wanted to respond by starting to negotiate on the requested
+ * option(s), we could, but we don't, because except for the
+ * authentication type and quality protocol, if we are not negotiating
+ * an option, it is because we were told not to.
+ * For the authentication type, the Nak from the peer means
+ * `let me authenticate myself with you' which is a bit pointless.
+ * For the quality protocol, the Nak means `ask me to send you quality
+ * reports', but if we didn't ask for them, we don't want them.
*/
- if (len == 0)
- return;
+ while (len > CILEN_VOID) {
+ GETCHAR(citype, p);
+ GETCHAR(cilen, p);
+ if( (len -= cilen) < 0 )
+ goto bad;
+ next = p + cilen - 2;
+
+ switch (citype) {
+ case CI_MRU:
+ if (go->neg_mru || no.neg_mru || cilen != CILEN_SHORT)
+ goto bad;
+ break;
+ case CI_ASYNCMAP:
+ if (go->neg_asyncmap || no.neg_asyncmap || cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_AUTHTYPE:
+ if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+ goto bad;
+ break;
+ case CI_MAGICNUMBER:
+ if (go->neg_magicnumber || no.neg_magicnumber ||
+ cilen != CILEN_LONG)
+ goto bad;
+ break;
+ case CI_PCOMPRESSION:
+ if (go->neg_pcompression || no.neg_pcompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_ACCOMPRESSION:
+ if (go->neg_accompression || no.neg_accompression
+ || cilen != CILEN_VOID)
+ goto bad;
+ break;
+ case CI_QUALITY:
+ if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+ goto bad;
+ break;
+ default:
+ goto bad;
+ }
+ p = next;
+ }
+
+ /* If there is still anything left, this packet is bad. */
+ if (len != 0)
+ goto bad;
+
+ /*
+ * OK, the Nak is good. Now we can update state.
+ */
+ if (f->state != OPENED) {
+ *go = try;
+ if (looped_back && try.numloops % lcp_warnloops == 0)
+ LCPDEBUG((LOG_INFO, "The line appears to be looped back."));
+ }
+
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"))
+ LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"));
+ return 0;
}
/*
- * lcp_rejci - Reject some of our CIs.
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ * 0 - Reject was bad.
+ * 1 - Reject was good.
*/
-static void
- lcp_rejci(f, p, len)
-fsm *f;
-u_char *p;
-int len;
+static int
+lcp_rejci(f, p, len)
+ fsm *f;
+ u_char *p;
+ int len;
{
lcp_options *go = &lcp_gotoptions[f->unit];
+ u_char cichar;
u_short cishort;
u_long cilong;
u_char *start = p;
- int myopt, myval, xval, plen = len;
+ int plen = len;
+ lcp_options try; /* options to request next time */
+
+ try = *go;
+
/*
* 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.
*/
#define REJCIVOID(opt, neg) \
- myopt = opt; \
- if (neg && \
- len >= 2 && \
- p[1] == 2 && \
+ if (go->neg && \
+ len >= CILEN_VOID && \
+ p[1] == CILEN_VOID && \
p[0] == opt) { \
- len -= 2; \
- INCPTR(2, p); \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected void opt %d",opt)) \
+ len -= CILEN_VOID; \
+ INCPTR(CILEN_VOID, p); \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \
}
#define REJCISHORT(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (short) && \
- p[1] == 2 + sizeof (short) && \
+ if (go->neg && \
+ len >= CILEN_SHORT && \
+ p[1] == CILEN_SHORT && \
p[0] == opt) { \
- len -= 2 + sizeof (short); \
+ len -= CILEN_SHORT; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
/* Check rejected value. */ \
- xval = cishort; \
if (cishort != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \
}
-#define REJCICHAP(opt, neg, val, digest, callback) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 4 + sizeof (short) && \
- p[1] == 4 + sizeof (short) && \
+#define REJCICHAP(opt, neg, val, digest) \
+ if (go->neg && \
+ len >= CILEN_CHAP && \
+ p[1] == CILEN_CHAP && \
p[0] == opt) { \
- len -= 4 + sizeof (short); \
+ len -= CILEN_CHAP; \
INCPTR(2, p); \
GETSHORT(cishort, p); \
+ GETCHAR(cichar, p); \
/* Check rejected value. */ \
- xval = cishort; \
- if (cishort != val) \
+ if (cishort != val || cichar != digest) \
goto bad; \
- neg = 0; \
- INCPTR(2, p); \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \
}
#define REJCILONG(opt, neg, val) \
- myopt = opt; myval = val; \
- if (neg && \
- len >= 2 + sizeof (long) && \
- p[1] == 2 + sizeof (long) && \
+ if (go->neg && \
+ len >= CILEN_LONG && \
+ p[1] == CILEN_LONG && \
p[0] == opt) { \
- len -= 2 + sizeof (long); \
+ len -= CILEN_LONG; \
INCPTR(2, p); \
GETLONG(cilong, p); \
- xval = cilong; \
/* Check rejected value. */ \
if (cilong != val) \
goto bad; \
- neg = 0; \
- LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)) \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \
+ }
+#define REJCILQR(opt, neg, val) \
+ if (go->neg && \
+ len >= CILEN_LQR && \
+ p[1] == CILEN_LQR && \
+ p[0] == opt) { \
+ len -= CILEN_LQR; \
+ INCPTR(2, p); \
+ GETSHORT(cishort, p); \
+ GETLONG(cilong, p); \
+ /* Check rejected value. */ \
+ if (cishort != LQR || cichar != val) \
+ goto bad; \
+ try.neg = 0; \
+ LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
}
- REJCISHORT(CI_MRU, go->neg_mru, go->mru)
- REJCILONG(CI_ASYNCMAP, go->neg_asyncmap, go->asyncmap)
- REJCICHAP(CI_AUTHTYPE, go->neg_chap, CHAP, go->chap_mdtype, go->callback)
- REJCISHORT(CI_AUTHTYPE, go->neg_upap, UPAP)
- REJCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber)
- REJCIVOID(CI_PCOMPRESSION, go->neg_pcompression)
- REJCIVOID(CI_ACCOMPRESSION, go->neg_accompression)
+ REJCISHORT(CI_MRU, neg_mru, go->mru);
+ REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+ REJCICHAP(CI_AUTHTYPE, neg_chap, CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, UPAP);
+ }
+ REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+ REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+ REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+ REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
/*
* If there are any remaining CIs, then this packet is bad.
*/
- if (len == 0)
- return;
+ if (len != 0)
+ goto bad;
+ /*
+ * Now we can update state.
+ */
+ if (f->state != OPENED)
+ *go = try;
+ return 1;
+
bad:
- LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"))
- LCPDEBUG((LOG_WARNING, "lcp_rejci: plen %d len %d off %d, exp opt %d, found %d, val %d fval %d ",
- plen, len, p - start, myopt, p[0] &0xff, myval, xval ))
+ 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;
}
@@ -646,48 +917,45 @@ bad:
* lcp_reqci - Check the peer's requested CIs and send appropriate response.
*
* Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
- * appropriately.
+ * appropriately. If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
*/
-static u_char
- lcp_reqci(f, inp, len)
-fsm *f;
-u_char *inp; /* Requested CIs */
-int *len; /* Length of requested CIs */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+ fsm *f;
+ u_char *inp; /* Requested CIs */
+ int *lenp; /* Length of requested CIs */
+ int reject_if_disagree;
{
lcp_options *go = &lcp_gotoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *ao = &lcp_allowoptions[f->unit];
- u_char *cip; /* Pointer to Current CI */
+ u_char *cip, *next; /* Pointer to current and next CIs */
u_char cilen, citype, cichar;/* Parsed len, type, char value */
u_short cishort; /* Parsed short value */
u_long cilong; /* Parse long value */
int rc = CONFACK; /* Final packet return code */
int orc; /* Individual option return code */
- u_char *p = inp; /* Pointer to next char to parse */
+ u_char *p; /* Pointer to next char to parse */
u_char *ucp = inp; /* Pointer to current output char */
- int l = *len; /* Length left */
+ int l = *lenp; /* Length left */
/*
* Reset all his options.
*/
- ho->neg_mru = 0;
- ho->neg_asyncmap = 0;
- ho->neg_chap = 0;
- ho->neg_upap = 0;
- ho->neg_magicnumber = 0;
- ho->neg_pcompression = 0;
- ho->neg_accompression = 0;
+ BZERO(ho, sizeof(*ho));
/*
* Process all his options.
*/
+ next = inp;
while (l) {
orc = CONFACK; /* Assume success */
- cip = p; /* Remember begining of CI */
+ 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? */
- LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"))
+ LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"));
orc = CONFREJ; /* Reject bad CI */
cilen = l; /* Reject till end of packet */
l = 0; /* Don't loop again */
@@ -696,19 +964,18 @@ int *len; /* Length of requested CIs */
GETCHAR(citype, p); /* Parse CI type */
GETCHAR(cilen, p); /* Parse CI length */
l -= cilen; /* Adjust remaining length */
- cilen -= 2; /* Adjust cilen to just data */
+ next += cilen; /* Step to next CI */
switch (citype) { /* Check CI type */
- case CI_MRU:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"))
+ case CI_MRU:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"));
if (!ao->neg_mru || /* Allow option? */
- cilen != sizeof (short)) { /* Check CI length */
- INCPTR(cilen, p); /* Skip rest of CI */
+ cilen != CILEN_SHORT) { /* Check CI length */
orc = CONFREJ; /* Reject CI */
break;
}
GETSHORT(cishort, p); /* Parse MRU */
- LCPDEBUG((LOG_INFO, "(%d)", cishort))
+ LCPDEBUG((LOG_INFO, "(%d)", cishort));
/*
* He must be able to receive at least our minimum.
@@ -717,131 +984,136 @@ int *len; /* Length of requested CIs */
*/
if (cishort < MINMRU) {
orc = CONFNAK; /* Nak CI */
- DECPTR(sizeof (short), p); /* Backup */
- PUTSHORT(MINMRU, p); /* Give him a hint */
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (short), p); /* Backup */
+ PUTSHORT(MINMRU, p); /* Give him a hint */
+ }
break;
}
- ho->neg_mru = 1; /* Remember he sent and MRU */
+ ho->neg_mru = 1; /* Remember he sent MRU */
ho->mru = cishort; /* And remember value */
break;
- case CI_ASYNCMAP:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"))
+ case CI_ASYNCMAP:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"));
if (!ao->neg_asyncmap ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
- /* XXX Accept anything he says */
-#if 0
/*
- * Asyncmap must be OR of two maps.
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
*/
- if ((lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != (lcp_wantoptions[f->unit].asyncmap | cilong)) ||
- (!lcp_wantoptions[f->unit].neg_asyncmap &&
- cilong != 0xffffffff)) {
+ if ((ao->asyncmap & ~cilong) != 0) {
orc = CONFNAK;
- DECPTR(sizeof (long), p);
- PUTLONG(lcp_wantoptions[f->unit].neg_asyncmap ?
- lcp_wantoptions[f->unit].asyncmap | cilong :
- 0xffffffff, p);
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (long), p);
+ PUTLONG(ao->asyncmap | cilong, p);
+ }
break;
}
-#endif
ho->neg_asyncmap = 1;
ho->asyncmap = cilong;
break;
- case CI_AUTHTYPE:
- if (cilen < sizeof (short) ||
- (!ao->neg_upap && !ao->neg_chap)) {
- LCPDEBUG((LOG_WARNING,
- "lcp_reqci: rcvd AUTHTYPE, rejecting ...!"))
- INCPTR(cilen, p);
- orc = CONFREJ;
- break;
+ case CI_AUTHTYPE:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE"));
+ if (cilen < CILEN_SHORT ||
+ !(ao->neg_upap || ao->neg_chap)) {
+ orc = CONFREJ;
+ break;
}
GETSHORT(cishort, p);
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE (%x)",
- cishort))
+ LCPDEBUG((LOG_INFO, "(%x)", cishort));
/*
* Authtype must be UPAP or CHAP.
+ *
+ * Note: if both ao->neg_upap and ao->neg_chap are set,
+ * and the peer sends a Configure-Request with two
+ * authenticate-protocol requests, one for CHAP and one
+ * for UPAP, then we will reject the second request.
+ * Whether we end up doing CHAP or UPAP depends then on
+ * the ordering of the CIs in the peer's Configure-Request.
*/
+
if (cishort == UPAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_upap) { /* we don't want to do PAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."))
- orc = CONFREJ;
+ if (!ao->neg_upap || /* we don't want to do PAP */
+ ho->neg_chap || /* or we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG((LOG_WARNING,
+ "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_upap = 1;
break;
- }
- ho->neg_upap = 1;
- break;
}
- else if (cishort == CHAP) {
- INCPTR(cilen - sizeof (u_short), p);
- if (!ao->neg_chap) { /* we don't want to do CHAP */
- LCPDEBUG((LOG_INFO,
- "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."))
- orc = CONFREJ;
+ if (cishort == CHAP) {
+ if (!ao->neg_chap || /* we don't want to do CHAP */
+ ho->neg_upap || /* or we've already accepted UPAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != ao->chap_mdtype) {
+ orc = CONFNAK;
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (u_char), p);
+ PUTCHAR(ao->chap_mdtype, p);
+ }
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
break;
- }
- GETCHAR(cichar, p); /* get digest type*/
- if (cichar != ao->chap_mdtype) {
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(ao->chap_mdtype, p);
- INCPTR(cilen - sizeof(u_char), p);
- break;
- }
- ho->chap_mdtype = cichar; /* save md type */
- GETCHAR(cichar, p); /* get callback type*/
- if (cichar != ao->chap_callback) { /* we don't callback yet */
- DECPTR(sizeof (u_char), p);
- orc = CONFNAK;
- PUTCHAR(CHAP_NOCALLBACK, p);
- INCPTR(cilen - sizeof(u_char), p);
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Reject it.
+ */
+ orc = CONFREJ;
+ break;
+
+ case CI_QUALITY:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY"));
+ if (!ao->neg_lqr ||
+ cilen != CILEN_LQR) {
+ orc = CONFREJ;
break;
- }
- ho->chap_callback = cichar; /* save callback */
- ho->neg_chap = 1;
- break;
}
- else {
- DECPTR(sizeof (short), p);
- orc = CONFNAK;
- if (ao->neg_chap) { /* We prefer CHAP */
- PUTSHORT(CHAP, p);
- }
- else
- if (ao->neg_upap) {
- PUTSHORT(CHAP, p);
- }
- else {
- syslog(LOG_ERR, "Coding botch in lcp_reqci authnak. This shouldn't happen.");
- exit(1);
- }
- INCPTR(cilen - sizeof (u_short), p);
- break;
+
+ GETSHORT(cishort, p);
+ GETLONG(cilong, p);
+ LCPDEBUG((LOG_INFO, "(%x %lx)", cishort, cilong));
+ if (cishort != LQR) {
+ orc = CONFREJ;
+ break;
}
+ /*
+ * Check the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ break;
- case CI_MAGICNUMBER:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"))
- if (!ao->neg_magicnumber ||
- cilen != sizeof (long)) {
- INCPTR(cilen, p);
+ case CI_MAGICNUMBER:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"));
+ if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+ cilen != CILEN_LONG) {
orc = CONFREJ;
break;
}
GETLONG(cilong, p);
- LCPDEBUG((LOG_INFO, "(%lx)", cilong))
+ LCPDEBUG((LOG_INFO, "(%lx)", cilong));
/*
* He must have a different magic number.
@@ -859,50 +1131,49 @@ int *len; /* Length of requested CIs */
break;
- case CI_PCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"))
+ case CI_PCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"));
if (!ao->neg_pcompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_pcompression = 1;
break;
- case CI_ACCOMPRESSION:
- LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"))
+ case CI_ACCOMPRESSION:
+ LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"));
if (!ao->neg_accompression ||
- cilen != 0) {
- INCPTR(cilen, p);
+ cilen != CILEN_VOID) {
orc = CONFREJ;
break;
}
ho->neg_accompression = 1;
break;
- default:
+ default:
LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d",
- citype))
- INCPTR(cilen, p);
+ citype));
orc = CONFREJ;
break;
}
- cilen += 2; /* Adjust cilen whole CI */
endswitch:
- LCPDEBUG((LOG_INFO, " (%s)",
- orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "REJ")))
+ LCPDEBUG((LOG_INFO, " (%s)", 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 (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 (reject_if_disagree) /* Getting fed up with sending NAKs? */
+ orc = CONFREJ; /* Get tough if so */
+ else {
+ 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 */
@@ -916,15 +1187,14 @@ endswitch:
}
/*
- * XXX If we wanted to send additional NAKs (for unsent CIs), the
+ * If we wanted to send additional NAKs (for unsent CIs), the
* code would go here. This must be done with care since it might
- * require a longer packet than we received.
+ * require a longer packet than we received. At present there
+ * are no cases where we want to ask the peer to negotiate an option.
*/
- *len = ucp - inp; /* Compute output length */
- LCPDEBUG((LOG_INFO, "lcp_reqci: returning %s.",
- rc == CONFACK ? "CONFACK" :
- rc == CONFNAK ? "CONFNAK" : "CONFREJ"))
+ *lenp = ucp - inp; /* Compute output length */
+ LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc)));
return (rc); /* Return final code */
}
@@ -935,43 +1205,35 @@ endswitch:
* Start UPAP, IPCP, etc.
*/
static void
- lcp_up(f)
-fsm *f;
+lcp_up(f)
+ fsm *f;
{
+ lcp_options *wo = &lcp_wantoptions[f->unit];
lcp_options *ho = &lcp_hisoptions[f->unit];
lcp_options *go = &lcp_gotoptions[f->unit];
- int auth = 0;
+ lcp_options *ao = &lcp_allowoptions[f->unit];
+
+ /*
+ * Set our MTU to the smaller of the MTU we wanted and
+ * the MRU our peer wanted. If we negotiated an MRU,
+ * set our MRU to the larger of value we wanted and
+ * the value we got in the negotiation.
+ */
+ ppp_send_config(f->unit, (ho->neg_mru? MIN(ao->mru, ho->mru): MTU),
+ (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+ ho->neg_pcompression, ho->neg_accompression);
+ ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): MTU),
+ (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+ go->neg_pcompression, go->neg_accompression);
if (ho->neg_mru)
- SIFMTU(f->unit, ho->mru);
- if (ho->neg_asyncmap)
- SIFASYNCMAP(f->unit, ho->asyncmap);
- if (ho->neg_pcompression)
- SIFPCOMPRESSION(f->unit);
- if (ho->neg_accompression)
- SIFACCOMPRESSION(f->unit);
- SIFUP(f->unit); /* Bring the interface up (set IFF_UP) */
+ peer_mru[f->unit] = ho->mru;
+
ChapLowerUp(f->unit); /* Enable CHAP */
upap_lowerup(f->unit); /* Enable UPAP */
ipcp_lowerup(f->unit); /* Enable IPCP */
- if (go->neg_chap) {
- ChapAuthPeer(f->unit);
- auth = 1;
- }
- if (ho->neg_chap) {
- ChapAuthWithPeer(f->unit);
- auth = 1;
- }
- if (go->neg_upap) {
- upap_authpeer(f->unit);
- auth = 1;
- }
- if (ho->neg_upap) {
- upap_authwithpeer(f->unit);
- auth = 1;
- }
- if (!auth)
- ipcp_activeopen(f->unit);
+
+ link_established(f->unit);
}
@@ -981,36 +1243,39 @@ fsm *f;
* Alert other protocols.
*/
static void
- lcp_down(f)
-fsm *f;
+lcp_down(f)
+ fsm *f;
{
- ipcp_lowerdown(f->unit);
- SIFDOWN(f->unit);
- SIFMTU(f->unit, MTU);
- SIFASYNCMAP(f->unit, 0xffffffff);
- CIFPCOMPRESSION(f->unit);
- CIFACCOMPRESSION(f->unit);
- ChapLowerDown(f->unit);
- upap_lowerdown(f->unit);
+ ipcp_lowerdown(f->unit);
+ ChapLowerDown(f->unit);
+ upap_lowerdown(f->unit);
+
+ sifdown(f->unit);
+ ppp_send_config(f->unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, MTU, 0, 0, 0);
+ peer_mru[f->unit] = MTU;
+ syslog(LOG_NOTICE, "Connection terminated.");
}
/*
- * lcp_closed - LCP has CLOSED.
- *
- * Alert other protocols.
+ * lcp_starting - LCP needs the lower layer up.
*/
static void
- lcp_closed(f)
-fsm *f;
+lcp_starting(f)
+ fsm *f;
{
- if (lcp_wantoptions[f->unit].restart) {
- if (lcp_wantoptions[f->unit].passive)
- lcp_passiveopen(f->unit); /* Start protocol in passive mode */
- else
- lcp_activeopen(f->unit); /* Start protocol in active mode */
- }
- else {
- EXIT(f->unit);
- }
+ link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+ fsm *f;
+{
+ link_terminated(f->unit);
}
+
diff --git a/libexec/pppd/lcp.h b/libexec/pppd/lcp.h
index d4db5344a925..3bcb59bcb73e 100644
--- a/libexec/pppd/lcp.h
+++ b/libexec/pppd/lcp.h
@@ -15,6 +15,8 @@
* 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: lcp.h,v 1.2 1994/03/30 09:31:32 jkh Exp $
*/
/*
@@ -23,9 +25,9 @@
#define CI_MRU 1 /* Maximum Receive Unit */
#define CI_ASYNCMAP 2 /* Async Control Character Map */
#define CI_AUTHTYPE 3 /* Authentication Type */
-#define CI_NOTDEFINED 4 /* not defined (used to be Encryption Type) */
+#define CI_QUALITY 4 /* Quality Protocol */
#define CI_MAGICNUMBER 5 /* Magic Number */
-#define CI_KEEPALIVE 6 /* Keep Alive Parameters */
+#define CI_KEEPALIVE 6 /* Keep Alive Parameters - OBSOLETE */
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
@@ -34,21 +36,23 @@
* The state of options is described by an lcp_options structure.
*/
typedef struct lcp_options {
- int passive : 1; /* Passives vs. active open */
+ int passive : 1; /* Don't die if we don't get a response */
+ int silent : 1; /* Wait for the other end to start first */
int restart : 1; /* Restart vs. exit after close */
int neg_mru : 1; /* Negotiate the MRU? */
- u_short mru; /* Value of MRU */
- int neg_asyncmap : 1; /* Async map? */
- u_long asyncmap;
- int neg_upap : 1; /* UPAP authentication? */
- int neg_chap : 1; /* CHAP authentication? */
- char chap_mdtype; /* which MD type */
- char chap_callback; /* callback ? */
- int neg_magicnumber : 1; /* Magic number? */
- u_long magicnumber;
- int numloops; /* Number loops during magic number negot. */
+ int neg_asyncmap : 1; /* Negotiate the async map? */
+ int neg_upap : 1; /* Ask for UPAP authentication? */
+ int neg_chap : 1; /* Ask for CHAP authentication? */
+ int neg_magicnumber : 1; /* Ask for magic number? */
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 */
+ u_short mru; /* Value of MRU */
+ char chap_mdtype; /* which MD type (hashing algorithm) */
+ u_long asyncmap; /* Value of async map */
+ u_long magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u_long lqr_period; /* Reporting period for link quality */
} lcp_options;
extern fsm lcp_fsm[];
@@ -59,13 +63,16 @@ extern lcp_options lcp_hisoptions[];
#define DEFMRU 1500 /* Try for this */
#define MINMRU 128 /* No MRUs below this */
+#define MAXMRU 16384 /* Normally limit MRU to this */
void lcp_init __ARGS((int));
-void lcp_activeopen __ARGS((int));
-void lcp_passiveopen __ARGS((int));
+void lcp_open __ARGS((int));
void lcp_close __ARGS((int));
void lcp_lowerup __ARGS((int));
void lcp_lowerdown __ARGS((int));
void lcp_input __ARGS((int, u_char *, int));
void lcp_protrej __ARGS((int));
void lcp_sprotrej __ARGS((int, u_char *, int));
+
+extern int lcp_warnloops; /* Warn about a loopback this often */
+#define DEFWARNLOOPS 10 /* Default value for above */
diff --git a/libexec/pppd/magic.c b/libexec/pppd/magic.c
index 87f2a7ac4cb3..44c7b29e87d2 100644
--- a/libexec/pppd/magic.c
+++ b/libexec/pppd/magic.c
@@ -17,6 +17,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: magic.c,v 1.2 1994/03/30 09:31:33 jkh Exp $";
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
diff --git a/libexec/pppd/magic.h b/libexec/pppd/magic.h
index a0479b2438f0..2a488d44c07d 100644
--- a/libexec/pppd/magic.h
+++ b/libexec/pppd/magic.h
@@ -15,6 +15,8 @@
* 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: magic.h,v 1.2 1994/03/30 09:31:34 jkh Exp $
*/
#include "args.h"
diff --git a/libexec/pppd/main.c b/libexec/pppd/main.c
index 557bc555e273..828d20bf818f 100644
--- a/libexec/pppd/main.c
+++ b/libexec/pppd/main.c
@@ -17,64 +17,45 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-/*
- * There are three scenarios:
- * 1. pppd used as daemon started from /etc/rc or perhaps /etc/ttys.
- * a. server
- * b. authentication necessary
- * c. want to use constant local ip addr
- * d. want to use constant remote ip addr, constant ip addr based on
- * authenticated user, or request ip addr
- * 2. pppd used on /dev/tty after remote login.
- * a. server
- * b. no authentication necessary or allowed
- * c. want to use constant local ip addr
- * d. want to use constant remote ip addr, constant ip addr based on
- * authenticated user, or request ip addr
- * 3. pppd used on line after tip'ing out.
- * a. client
- * b. remote end may request authentication
- * c. want to use constant local ip addr or request ip addr
- * d. want to use constant remote ip addr based on tip'd host, or
- * request remote ip addr
- */
-
-#ifdef __386BSD__
-#include <stdlib.h>
+#ifndef lint
+static char rcsid[] = "$Id: main.c,v 1.4 1994/03/30 09:31:35 jkh Exp $";
#endif
+#define SETSID
+
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
-#include <pwd.h>
#include <syslog.h>
#include <netdb.h>
#include <utmp.h>
-#ifdef sparc
-#include <alloca.h>
+/*
+ * If REQ_SYSOPTIONS is defined to 1, pppd will not run unless
+ * /etc/ppp/options exists.
+ */
+#ifndef REQ_SYSOPTIONS
+#define REQ_SYSOPTIONS 0
#endif
#ifdef STREAMS
-#include <sys/stream.h>
-#include <sys/stropts.h>
-#include <sys/termios.h>
-#else
+#undef SGTTY
+#endif
+
#ifdef SGTTY
#include <sgtty.h>
#else
+#ifndef sun
#include <sys/ioctl.h>
-#include <termios.h>
#endif
+#include <termios.h>
#endif
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <sys/time.h>
#include "callout.h"
@@ -82,19 +63,13 @@
#include <net/if.h>
#include <net/if_ppp.h>
-#ifdef STREAMS
-#include "ppp_str.h"
-#endif
-
-#define DEVNAME_SIZE 128 /* Buffer size for /dev filenames */
-
#include <string.h>
#ifndef BSD
#define BSD 43
#endif /*BSD*/
-#include <net/ppp.h>
+#include "ppp.h"
#include "magic.h"
#include "fsm.h"
#include "lcp.h"
@@ -116,55 +91,63 @@
#endif /*FALSE*/
#ifdef PIDPATH
-static char *pidpath = PIDPATH; /* filename in which pid will be */
- /* stored */
+static char *pidpath = PIDPATH; /* filename in which pid will be stored */
#else
static char *pidpath = _PATH_PIDFILE;
#endif /* PIDFILE */
-static char uinfopath[DEVNAME_SIZE];
-
/* interface vars */
-
char ifname[IFNAMSIZ]; /* Interface name */
-int ifunit; /* Interface unit number */
+int ifunit; /* Interface unit number */
char *progname; /* Name of this program */
-char hostname[MAX_HOSTNAME_LEN]; /* hostname */
-u_char hostname_len; /* hostname length */
-
-static pid_t pid; /* Our pid */
-static pid_t pgrpid; /* Process Group ID */
-static char pidfilename[DEVNAME_SIZE];
-
-static char devname[DEVNAME_SIZE] = "/dev/tty"; /* Device name */
-static int default_device = TRUE; /* use default device (stdin/out) */
-int fd; /* Device file descriptor */
-int s; /* Socket file descriptor */
-static int initdisc; /* Initial TTY discipline */
-#ifndef STREAMS
+char hostname[MAXNAMELEN]; /* Our hostname */
+char our_name[MAXNAMELEN];
+char remote_name[MAXNAMELEN];
+
+static pid_t pid; /* Our pid */
+static pid_t pgrpid; /* Process Group ID */
+static char pidfilename[MAXPATHLEN];
+
+char devname[MAXPATHLEN] = "/dev/tty"; /* Device name */
+int default_device = TRUE; /* use default device (stdin/out) */
+
+int fd; /* Device file descriptor */
+int s; /* Socket file descriptor */
+
#ifdef SGTTY
static struct sgttyb initsgttyb; /* Initial TTY sgttyb */
#else
-static struct termios inittermios; /* Initial TTY TIOCGETA */
-#endif
+static struct termios inittermios; /* Initial TTY termios */
#endif
-static int initfdflags; /* Initial file descriptor flags */
+static int initfdflags = -1; /* Initial file descriptor flags */
+
+static int restore_term; /* 1 => we've munged the terminal */
u_char outpacket_buf[MTU+DLLHEADERLEN]; /* buffer for outgoing packet */
static u_char inpacket_buf[MTU+DLLHEADERLEN]; /* buffer for incoming packet */
+int hungup; /* terminal has been hung up */
+
/* configured variables */
int debug = 0; /* Debug flag */
-static char user[80]; /* User name */
-static char passwd[80]; /* password */
-static char *connector = NULL; /* "connect" command */
-static int inspeed = 0; /* Input/Output speed */
-static u_long netmask = 0; /* netmask to use on ppp interface */
-static int crtscts = 0; /* use h/w flow control */
-static int nodetach = 0; /* don't fork */
+char user[MAXNAMELEN]; /* username for PAP */
+char passwd[MAXSECRETLEN]; /* password for PAP */
+char *connector = NULL; /* "connect" command */
+int inspeed = 0; /* Input/Output speed */
+u_long netmask = 0; /* netmask to use on ppp interface */
+int crtscts = 0; /* use h/w flow control */
+int nodetach = 0; /* don't fork */
+int modem = 0; /* use modem control lines */
+int auth_required = 0; /* require peer to authenticate */
+int defaultroute = 0; /* assign default route through interface */
+int proxyarp = 0; /* set entry in arp table */
+int persist = 0; /* re-initiate on termination */
+int answer = 0; /* wait for incoming call */
+int uselogin = 0; /* check PAP info against /etc/passwd */
+
/* prototypes */
static void hup __ARGS((int, int, struct sigcontext *, char *));
@@ -172,761 +155,657 @@ static void intr __ARGS((int, int, struct sigcontext *, char *));
static void term __ARGS((int, int, struct sigcontext *, char *));
static void alrm __ARGS((int, int, struct sigcontext *, char *));
static void io __ARGS((int, int, struct sigcontext *, char *));
-static void incdebug __ARGS((int, int, struct sigcontext *, char *));
-static void nodebug __ARGS((int, int, struct sigcontext *, char *));
-static void getuserpasswd __ARGS((void));
-
-static int setdebug __ARGS((int *, char ***));
-static int setpassive __ARGS((int *, char ***));
-static int noopt __ARGS((int *, char ***));
-static int setnovj __ARGS((int *, char ***));
-static int noupap __ARGS((int *, char ***));
-static int requpap __ARGS((int *, char ***));
-static int nochap __ARGS((int *, char ***));
-static int reqchap __ARGS((int *, char ***));
-static int setspeed __ARGS((int *, char ***));
-static int noaccomp __ARGS((int *, char ***));
-static int noasyncmap __ARGS((int *, char ***));
-static int noipaddr __ARGS((int *, char ***));
-static int nomagicnumber __ARGS((int *, char ***));
-static int setasyncmap __ARGS((int *, char ***));
-static int setvjmode __ARGS((int *, char ***));
-static int setmru __ARGS((int *, char ***));
-static int nomru __ARGS((int *, char ***));
-static int nopcomp __ARGS((int *, char ***));
-static int setconnector __ARGS((int *, char ***));
-static int setdomain __ARGS((int *, char ***));
-static int setnetmask __ARGS((int *, char ***));
-static int setcrtscts __ARGS((int *, char ***));
-static int setnodetach __ARGS((int *, char ***));
-static void cleanup __ARGS((int, caddr_t));
+static void incdebug __ARGS((int));
+static void nodebug __ARGS((int));
+void establish_ppp __ARGS((void));
+
+void cleanup __ARGS((int, caddr_t));
+void die __ARGS((int));
+void dumpbuffer __ARGS((unsigned char *, int, int));
#ifdef STREAMS
-static void str_restore __ARGS((void));
extern char *ttyname __ARGS((int));
-#define MAXMODULES 10 /* max number of module names that we can save */
-static struct modlist {
- char modname[FMNAMESZ+1];
-} str_modules[MAXMODULES];
-static int str_module_count = 0;
#endif
-
-/*
- * Valid arguments.
- */
-static struct cmd {
- char *cmd_name;
- int (*cmd_func)();
-} cmds[] = {
- "-all", noopt, /* Don't request/allow any options */
- "-ac", noaccomp, /* Disable Address/Control compress */
- "-am", noasyncmap, /* Disable asyncmap negotiation */
- "-as", setasyncmap, /* set the desired async map */
- "-d", setdebug, /* Increase debugging level */
- "-detach", setnodetach, /* don't fork */
- "-ip", noipaddr, /* Disable IP address negotiation */
- "-mn", nomagicnumber, /* Disable magic number negotiation */
- "-mru", nomru, /* Disable mru negotiation */
- "-p", setpassive, /* Set passive mode */
- "-pc", nopcomp, /* Disable protocol field compress */
- "+ua", requpap, /* Require UPAP authentication */
- "-ua", noupap, /* Don't allow UPAP authentication */
- "+chap", reqchap, /* Require CHAP authentication */
- "-chap", nochap, /* Don't allow CHAP authentication */
- "-vj", setnovj, /* disable VJ compression */
- "asyncmap", setasyncmap, /* set the desired async map */
- "connect", setconnector, /* A program to set up a connection */
- "crtscts", setcrtscts, /* set h/w flow control */
- "debug", setdebug, /* Increase debugging level */
- "domain", setdomain, /* Add given domain name to hostname*/
- "mru", setmru, /* Set MRU value for negotiation */
- "netmask", setnetmask, /* set netmask */
- "passive", setpassive, /* Set passive mode */
- "vjmode", setvjmode, /* set VJ compression mode */
- NULL
- };
-
+extern char *getlogin __ARGS((void));
/*
* PPP Data Link Layer "protocol" table.
* One entry per supported protocol.
*/
static struct protent {
- u_short protocol;
- void (*init)();
- void (*input)();
- void (*protrej)();
+ u_short protocol;
+ void (*init)();
+ void (*input)();
+ void (*protrej)();
} prottbl[] = {
- { LCP, lcp_init, lcp_input, lcp_protrej },
- { IPCP, ipcp_init, ipcp_input, ipcp_protrej },
- { UPAP, upap_init, upap_input, upap_protrej },
- { CHAP, ChapInit, ChapInput, ChapProtocolReject },
+ { LCP, lcp_init, lcp_input, lcp_protrej },
+ { IPCP, ipcp_init, ipcp_input, ipcp_protrej },
+ { UPAP, upap_init, upap_input, upap_protrej },
+ { CHAP, ChapInit, ChapInput, ChapProtocolReject },
};
-static char *usage = "pppd version %s patch level %d\n\
-Usage: %s [ arguments ], where arguments are:\n\
- -all Don't request/allow any options\n\
- -ac Disable Address/Control compression\n\
- -am Disable asyncmap negotiation\n\
- -as <n> Set the desired async map to hex <n>\n\
- -d Increase debugging level\n\
- -detach Don't fork to background\n\
- -ip Disable IP address negotiation\n\
- -mn Disable magic number negotiation\n\
- -mru Disable mru negotiation\n\
- -p Set passive mode\n\
- -pc Disable protocol field compression\n\
- +ua <p> Require UPAP authentication and use file <p> for\n\
- remote login data\n\
- -ua Don't allow UPAP authentication\n\
- +chap Require CHAP authentication\n\
- -chap Don't allow CHAP authentication\n\
- -vj disable VJ compression\n\
- connect <p> Invoke shell command <p> to set up the serial line\n\
- crtscts Use hardware RTS/CTS flow control\n\
- debug Increase debugging level\n\
- domain <d> Append domain name <d> to hostname for authentication\n\
- mru <n> Set MRU value to <n> for negotiation\n\
- netmask <n> Set interface netmask to <n>\n\
- passive Set passive mode\n\
- vjmode <m> VJ compression mode {old, rfc1172, rfc1132 (default)}\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\
- addresses. Either one may be omitted.\n";
-
-
main(argc, argv)
- int argc;
- char *argv[];
+ int argc;
+ char *argv[];
{
- int mask, i;
- struct sigvec sv;
- struct cmd *cmdp;
- FILE *pidfile;
-#ifndef STREAMS
- int pppdisc = PPPDISC;
-#endif
+ int mask, i;
+ struct sigvec sv;
+ struct cmd *cmdp;
+ FILE *pidfile;
+ char *p;
- /*
- * Initialize syslog system and magic number package.
- */
+ /*
+ * Initialize syslog system and magic number package.
+ */
#if BSD >= 43 || defined(sun)
- openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
- setlogmask(LOG_UPTO(LOG_INFO));
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
#else
- openlog("pppd", LOG_PID);
+ openlog("pppd", LOG_PID);
#define LOG_UPTO(x) (x)
#define setlogmask(x) (x)
#endif
#ifdef STREAMS
- if (ttyname(fileno(stdin)))
- strcpy(devname, ttyname(fileno(stdin)));
+ p = ttyname(fileno(stdin));
+ if (p)
+ strcpy(devname, p);
#endif
- magic_init();
-
- if (gethostname(hostname, MAX_HOSTNAME_LEN) < 0 ) {
- syslog(LOG_ERR, "couldn't get hostname: %m");
- exit(1);
- }
-
- /*
- * Initialize to the standard option set and then parse the command
- * line arguments.
- */
- for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
- (*prottbl[i].init)(0);
-
- progname = *argv;
- for (argc--, argv++; argc; ) {
- /*
- * First see if it's a command.
- */
- for (cmdp = cmds; cmdp->cmd_name; cmdp++)
- if (!strcmp(*argv, cmdp->cmd_name) &&
- (*cmdp->cmd_func)(&argc, &argv))
- break;
-
- /*
- * Maybe a tty name, speed or IP address?
- */
- if (cmdp->cmd_name == NULL &&
- !setdevname(&argc, &argv) &&
- !setspeed(&argc, &argv) &&
- !setipaddr(&argc, &argv)) {
- fprintf(stderr, usage, VERSION, PATCHLEVEL, progname);
- exit(1);
+ magic_init();
+
+ if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+ syslog(LOG_ERR, "couldn't get hostname: %m");
+ die(1);
}
- }
+ hostname[MAXNAMELEN-1] = 0;
- syslog(LOG_INFO, "Starting pppd %s patch level %d",
- VERSION, PATCHLEVEL);
+ pid = getpid();
- /*
- * Initialize state.
- */
+ if (!ppp_available()) {
+ fprintf(stderr, "Sorry - PPP is not available on this system\n");
+ exit(1);
+ }
+ /*
+ * Initialize to the standard option set, then parse, in order,
+ * the system options file, the user's options file, and the command
+ * line arguments.
+ */
+ for (i = 0; i < sizeof (prottbl) / sizeof (struct protent); i++)
+ (*prottbl[i].init)(0);
+
+ progname = *argv;
+
+ if (!options_from_file(_PATH_SYSOPTIONS, REQ_SYSOPTIONS) ||
+ !options_from_user() ||
+ !parse_args(argc-1, argv+1))
+ die(1);
+ check_auth_options();
+ setipdefault();
+
+ p = getlogin();
+ if (p == NULL)
+ p = "(unknown)";
+ syslog(LOG_NOTICE, "pppd %s.%d started by %s, uid %d",
+ VERSION, PATCHLEVEL, p, getuid());
-#define SETSID
#ifdef SETSID
- if (default_device) {
- /* No device name was specified... inherit the old controlling
- terminal */
-
- if ((pgrpid = getpgrp(0)) < 0) {
- syslog(LOG_ERR, "getpgrp(0): %m");
- exit(1);
+ /*
+ * Make sure we can set the serial device to be our controlling terminal.
+ */
+ if (default_device) {
+ /*
+ * No device name was specified:
+ * we are in the device's session already.
+ */
+ if ((pgrpid = getpgrp(0)) < 0) {
+ syslog(LOG_ERR, "getpgrp(0): %m");
+ die(1);
+ }
+
+ } else {
+ /*
+ * Not default device: make sure we're not a process group leader,
+ * then become session leader of a new session (so we can make
+ * our device its controlling terminal and thus get SIGHUPs).
+ */
+ if (!nodetach) {
+ /* fork so we're not a process group leader */
+ if (pid = fork()) {
+ exit(0); /* parent is finished */
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
+ }
+ pid = getpid(); /* otherwise pid is 0 in child */
+ } else {
+ /*
+ * try to put ourself into our parent's process group,
+ * so we're not a process group leader
+ */
+ if (setpgrp(pid, getppid()) < 0)
+ syslog(LOG_WARNING, "setpgrp: %m");
+ }
+
+ /* create new session */
+ if ((pgrpid = setsid()) < 0) {
+ syslog(LOG_ERR, "setsid(): %m");
+ die(1);
+ }
}
- if (pgrpid != pid)
- syslog(LOG_WARNING, "warning... not a process group leader");
- }
- else /*default_device*/
- {
- /* become session leader... */
-
- if (!nodetach) {
- /* fork so we're not a process group leader */
- if (pid = fork()) {
- exit(0);
- }
- }
-#ifdef xxx
- else
- /* bag controlling terminal */
- if (ioctl(0, TIOCNOTTY) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCNOTTY): %m");
- exit(1);
- }
#endif
- /* create new session */
- if ((pgrpid = setsid()) < 0) {
- syslog(LOG_ERR, "setsid(): %m");
- exit(1);
- }
- }
+ /* Get an internet socket for doing socket ioctl's on. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket : %m");
+ die(1);
+ }
+
+ /*
+ * Compute mask of all interesting signals and install signal handlers
+ * for each. Only one signal handler may be active at a time. Therefore,
+ * all other signals should be masked when any handler is executing.
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGHUP);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGALRM);
+ sigaddset(&mask, SIGIO);
+#ifdef STREAMS
+ sigaddset(&mask, SIGPOLL);
#endif
- /* open i/o device */
- if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
- syslog(LOG_ERR, "open(%s): %m", devname);
- exit(1);
- }
-
- /* drop dtr to hang up incase modem is off hook */
- if (!default_device) {
- setdtr(fd, FALSE);
- sleep(1);
- setdtr(fd, TRUE);
- }
-
- /* set device to be controlling tty */
- if (ioctl(fd, TIOCSCTTY) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
- exit(1);
- }
-
- /* run connection script */
- if (connector) {
- syslog(LOG_NOTICE, "Connecting with <%s>", connector);
- /* set line speed */
- set_up_tty(fd, 0);
- if (set_up_connection(connector, fd, fd) < 0) {
- syslog(LOG_ERR, "could not set up connection");
- setdtr(fd, FALSE);
- exit(1);
+#define SIGNAL(s, handler) { \
+ sv.sv_handler = handler; \
+ if (sigvec(s, &sv, NULL) < 0) { \
+ syslog(LOG_ERR, "sigvec(%d): %m", s); \
+ die(1); \
+ } \
}
- syslog(LOG_NOTICE, "Connected...");
- }
-
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "socket : %m");
- exit(1);
- }
-
- /* if we exit, then try and restore the stream */
-#ifdef sun
- on_exit(cleanup, NULL);
+
+ sv.sv_mask = mask;
+ sv.sv_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, intr); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGALRM, alrm); /* Timeout */
+ SIGNAL(SIGIO, io); /* Input available */
+#ifdef STREAMS
+ SIGNAL(SIGPOLL, io); /* Input available */
#endif
-
+
+ signal(SIGUSR1, incdebug); /* Increment debug flag */
+ signal(SIGUSR2, nodebug); /* Reset debug flag */
+
+ /*
+ * Block SIGIOs and SIGPOLLs for now
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGIO);
#ifdef STREAMS
- /* go through and save the name of all the modules, then pop em */
- while(1) {
- if(!ioctl(fd, I_LOOK, str_modules[str_module_count].modname))
- MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
- str_modules[str_module_count].modname))
- if(!ioctl(fd, I_POP, 0))
- str_module_count++;
- else
- break;
- }
-
- /* set line speed */
- set_up_tty(fd, 1);
-
- syslog(LOG_ERR, "about to push modules...");
-
- /* now push the async/fcs module */
- if(ioctl(fd, I_PUSH, "pppasync") < 0) {
- syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
- exit(1);
- }
- /* finally, push the ppp_if module that actually handles the */
- /* network interface */
- if(ioctl(fd, I_PUSH, "pppif") < 0) {
- syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
- exit(1);
- }
- if(ioctl(fd, I_SETSIG, S_INPUT) < 0) {
- syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
- exit(1);
- }
- /* read mode, message non-discard mode */
- if(ioctl(fd, I_SRDOPT, RMSGN) < 0) {
- syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
- exit(1);
- }
- /* Flush any waiting messages, or we'll never get SIGPOLL */
- if(ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
- syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
- exit(1);
- }
- /*
- * Find out which interface we were given.
- * (ppp_if handles this ioctl)
- */
- if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
- exit(1);
- }
-
- /* if debug, set debug flags in driver */
- {
- int flags = debug ? 0x3 : 0;
-syslog(LOG_INFO, "debug 0x%x, flags 0x%x", debug, flags);
- if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
- syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
- }
- }
-
- syslog(LOG_ERR, "done pushing modules, ifunit %d", ifunit);
-#else
- /* set line speed */
- set_up_tty(fd, 1);
-
- if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
- exit(1);
- }
- if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
- exit(1);
- }
-
- /*
- * Find out which interface we were given.
- */
- if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
- syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
- exit(1);
- }
+ sigaddset(&mask, SIGPOLL);
#endif
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ */
+ if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
+ syslog(LOG_ERR, "open(%s): %m", devname);
+ die(1);
+ }
+ hungup = 0;
- syslog(LOG_NOTICE, "Using interface ppp%d", ifunit);
- (void) sprintf(ifname, "ppp%d", ifunit);
- pid = getpid();
+ /* set device to be controlling tty */
+ if (!default_device && ioctl(fd, TIOCSCTTY) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
+ die(1);
+ }
- (void) sprintf(pidfilename, "%s/%s.pid", pidpath, ifname);
+ /* set line speed, flow control, etc. */
+ set_up_tty(fd);
- /* write pid to file */
+ /* run connection script */
+ if (connector) {
+ syslog(LOG_INFO, "Connecting with <%s>", connector);
- if ((pidfile = fopen(pidfilename, "w")) != NULL) {
- fprintf(pidfile, "%d\n", pid);
- (void) fclose(pidfile);
- }
+ /* drop dtr to hang up in case modem is off hook */
+ if (!default_device && modem) {
+ setdtr(fd, FALSE);
+ sleep(1);
+ setdtr(fd, TRUE);
+ }
- hostname_len = (u_char) strlen(hostname);
+ if (set_up_connection(connector, fd, fd) < 0) {
+ syslog(LOG_ERR, "could not set up connection");
+ setdtr(fd, FALSE);
+ die(1);
+ }
- MAINDEBUG((LOG_DEBUG, "hostname = %s", hostname))
-
-#ifdef SETSID
- if (default_device) {
- int id = tcgetpgrp(fd);
- if (id != pgrpid) {
- syslog(LOG_WARNING,
- "warning: pppd is not the leader of a forground process group");
+ syslog(LOG_INFO, "Connected...");
+ sleep(1); /* give it time to set up its terminal */
}
- }
- else
- if (tcsetpgrp(fd, pgrpid) < 0) {
- syslog(LOG_ERR, "tcsetpgrp(): %m");
- exit(1);
+
+ /* 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", pidpath, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "unable to create pid file: %m");
+ pidfilename[0] = 0;
+ }
+
+ /*
+ * Set process group of device to our process group so we can get
+ * SIGIOs and SIGHUPs.
+ */
+#ifdef SETSID
+ if (default_device) {
+ int id = tcgetpgrp(fd);
+ if (id != pgrpid) {
+ syslog(LOG_WARNING, "warning: not in tty's process group");
+ }
+ } else {
+ if (tcsetpgrp(fd, pgrpid) < 0) {
+ syslog(LOG_ERR, "tcsetpgrp(): %m");
+ die(1);
+ }
}
#else
- /* set process group on tty so we get SIGIO's */
- if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
- exit(1);
- }
+ /* set process group on tty so we get SIGIO's */
+ if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
+ die(1);
+ }
#endif
+
+ /*
+ * Record initial device flags, then set device to cause SIGIO
+ * signals to be generated.
+ */
+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
+ syslog(LOG_ERR, "fcntl(F_GETFL): %m");
+ die(1);
+ }
+ if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
+ syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
+ die(1);
+ }
- /*
- * Compute mask of all interesting signals and install signal handlers
- * for each. Only one signal handler may be active at a time. Therefore,
- * all other signals should be masked when any handler is executing.
- */
- mask = sigmask(SIGHUP) | sigmask(SIGINT) | sigmask(SIGALRM) |
- sigmask(SIGIO);
-#ifdef STREAMS
- mask |= sigmask(SIGPOLL);
-#endif
+ /*
+ * Block all signals, start opening the connection, and wait for
+ * incoming signals (reply, timeout, etc.).
+ */
+ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devname);
+ sigprocmask(SIG_BLOCK, &mask, NULL); /* Block signals now */
+ lcp_lowerup(0); /* XXX Well, sort of... */
+ lcp_open(0); /* Start protocol */
+ for (;;) {
+ sigpause(0); /* Wait for next signal */
+ }
+}
- sv.sv_handler = hup; /* Hangup */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGHUP, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGHUP)");
- exit(1);
- }
- sv.sv_handler = intr; /* Interrupt */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGINT, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGINT)");
- exit(1);
- }
- sv.sv_handler = term; /* Terminate */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGTERM, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGTERM)");
- exit(1);
- }
- sv.sv_handler = alrm; /* Timeout */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGALRM, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGALRM)");
- exit(1);
- }
- sv.sv_handler = io; /* Input available */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGIO, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGIO)");
- exit(1);
- }
-#ifdef STREAMS
- sv.sv_handler = io; /* Input available */
- sv.sv_mask = mask;
- sv.sv_flags = 0;
- if (sigvec(SIGPOLL, &sv, NULL)) {
- syslog(LOG_ERR, "sigvec(SIGPOLL)");
- exit(1);
- }
-#endif
+#if B9600 == 9600
+/*
+ * XXX assume speed_t values numerically equal bits per second
+ * (so we can ask for any speed).
+ */
+#define translate_speed(bps) (bps)
-#ifdef __STDC__
- /* Increment debug flag */
- (void) signal(SIGUSR1, (void (*)(int))incdebug);
- /* Reset debug flag */
- (void) signal(SIGUSR2, (void (*)(int))nodebug);
#else
- /* Increment debug flag */
- (void) signal(SIGUSR1, (void (*)())incdebug);
- /* Reset debug flag */
- (void) signal(SIGUSR2, (void (*)())nodebug);
+/*
+ * List of valid speeds.
+ */
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
#endif
-
- /*
- * Record initial device flags, then set device to cause SIGIO
- * signals to be generated.
- */
- if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
- syslog(LOG_ERR, "fcntl(F_GETFL): %m");
- exit(1);
- }
- if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
- syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
- exit(1);
- }
-
- /*
- * Block all signals, start opening the connection, and wait for
- * incoming signals (reply, timeout, etc.).
- */
- syslog(LOG_INFO, "Connect: %s <--> %s", ifname, devname);
- sigblock(mask); /* Block signals now */
- lcp_lowerup(0); /* XXX Well, sort of... */
- if (lcp_wantoptions[0].passive)
- lcp_passiveopen(0); /* Start protocol in passive mode */
- else
- lcp_activeopen(0); /* Start protocol in active mode */
- for (;;) {
- sigpause(0); /* Wait for next signal */
-
- /* Need to read user/passwd? */
- if (upap[0].us_flags & UPAPF_UPPENDING) {
- sigsetmask(0); /* Allow other signals to occur */
- getuserpasswd(); /* Get user and passwd */
- upap[0].us_flags &= ~UPAPF_UPPENDING;
- upap[0].us_flags |= UPAPF_UPVALID;
- sigsetmask(mask); /* Disallow signals */
- upap_authwithpeer(0);
- }
- }
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Translate from bits/second to a speed_t.
+ */
+int
+translate_speed(bps)
+ int bps;
+{
+ struct speed *speedp;
+
+ if (bps == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ syslog(LOG_WARNING, "speed %d not supported", bps);
+ return 0;
}
+#endif
-set_up_tty(fd, flow)
-int fd;
-int flow;
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc.
+ */
+set_up_tty(fd)
+ int fd;
{
-#ifdef STREAMS
- int new_cflag;
- struct termios tios;
-
- if(ioctl(fd, TCGETS, (caddr_t) &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TCGETS): %m");
- exit(1);
- }
-
- new_cflag = CS8 | CREAD | HUPCL;
- new_cflag |= inspeed ? inspeed : (tios.c_cflag & CBAUD);
- if (flow)
- new_cflag |= crtscts ? CRTSCTS : 0;
-
- tios.c_cflag = new_cflag;
- tios.c_iflag = IGNBRK | IGNPAR;
- tios.c_oflag = 0;
- tios.c_lflag = 0;
-
- if(ioctl(fd, TCSETS, (caddr_t) &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TCSETS): %m");
- exit(1);
- }
-#else
-#ifdef SGTTY
- struct sgttyb sgttyb;
-
- /*
- * Put the tty in raw mode and set the discipline to PPP.
- */
- if (ioctl(fd, TIOCGETP, &initsgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
- exit(1);
- }
-
- sgttyb = initsgttyb;
- sgttyb.sg_flags = RAW | ANYP;
- if (inspeed)
- sgttyb.sg_ispeed = inspeed;
-
- if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
- exit(1);
- }
-#else
+#ifndef SGTTY
+ int speed;
struct termios tios;
- if (ioctl(fd, TIOCGETA, &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCGETA): %m");
- exit(1);
+ if (tcgetattr(fd, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ die(1);
}
- inittermios = tios;
+ if (!restore_term)
+ inittermios = tios;
- tios.c_cflag = CREAD | CS8 | HUPCL;
- if (flow)
- tios.c_cflag |= crtscts ? CRTSCTS : 0;
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CRTSCTS);
+ tios.c_cflag |= CS8 | CREAD | HUPCL;
+ if (crtscts)
+ tios.c_cflag |= CRTSCTS;
+ if (!modem)
+ tios.c_cflag |= CLOCAL;
tios.c_iflag = IGNBRK | IGNPAR;
tios.c_oflag = 0;
tios.c_lflag = 0;
- tios.c_cc[VERASE] = tios.c_cc[VKILL] = 0;
tios.c_cc[VMIN] = 1;
tios.c_cc[VTIME] = 0;
- if (inspeed) {
- tios.c_ispeed = inspeed;
- tios.c_ospeed = inspeed;
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed(&tios, speed);
+ cfsetispeed(&tios, speed);
}
- if (ioctl(fd, TIOCSETA, &tios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETA): %m");
- exit(1);
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ die(1);
+ }
+#else /* SGTTY */
+ int speed;
+ struct sgttyb sgttyb;
+
+ /*
+ * Put the tty in raw mode.
+ */
+ if (ioctl(fd, TIOCGETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
+ die(1);
+ }
+
+ if (!restore_term)
+ initsgttyb = sgttyb;
+
+ sgttyb.sg_flags = RAW | ANYP;
+ speed = translate_speed(inspeed);
+ if (speed)
+ sgttyb.sg_ispeed = speed;
+
+ if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+ die(1);
}
#endif
-#endif
+ restore_term = TRUE;
}
+
/*
* quit - Clean up state and exit.
*/
void
- quit()
+quit()
{
- syslog(LOG_NOTICE, "Quitting");
+ die(0);
+}
- if (fd == 0)
- return;
+/*
+ * die - like quit, except we can specify an exit status.
+ */
+void
+die(status)
+ int status;
+{
+ cleanup(0, NULL);
+ syslog(LOG_INFO, "Exit.");
+ exit(status);
+}
- if (fcntl(fd, F_SETFL, initfdflags) == -1) {
- syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
- exit(1);
- }
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+void
+cleanup(status, arg)
+ int status;
+ caddr_t arg;
+{
+ if (fd != 0) {
+ /* drop dtr to hang up */
+ if (modem)
+ setdtr(fd, FALSE);
-#ifdef STREAMS
- str_restore();
-#else
-#ifdef SGTTY
- if (ioctl(fd, TIOCSETP, &initsgttyb) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETP)");
- exit(1);
- }
-#else
- if (ioctl(fd, TIOCSETA, &inittermios) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETA)");
- exit(1);
- }
+ if (fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_ERR, "fcntl(F_SETFL, fdflags): %m");
-#endif
- if (ioctl(fd, TIOCSETD, &initdisc) < 0) {
- syslog(LOG_ERR, "ioctl(TIOCSETD)");
- exit(1);
- }
-#endif
+ disestablish_ppp();
- /* drop dtr to hang up */
- setdtr(fd, FALSE);
+ if (restore_term) {
+#ifndef SGTTY
+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ syslog(LOG_ERR, "tcsetattr: %m");
+#else
+ if (ioctl(fd, TIOCSETP, &initsgttyb) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+#endif
+ }
- close(fd);
- fd = 0;
+ close(fd);
+ fd = 0;
+ }
- exit(0);
+ if (pidfilename[0] != 0 && unlink(pidfilename) < 0)
+ syslog(LOG_WARNING, "unable to unlink pid file: %m");
+ pidfilename[0] = 0;
}
static struct callout *callout = NULL; /* Callout list */
static struct timeval schedtime; /* Time last timeout was set */
-
/*
* timeout - Schedule a timeout.
*
* Note that this timeout takes the number of seconds, NOT hz (as in
* the kernel).
*/
-void timeout(func, arg, time)
- void (*func)();
- caddr_t arg;
- int time;
+void
+timeout(func, arg, time)
+ void (*func)();
+ caddr_t arg;
+ int time;
{
- struct itimerval itv;
- struct callout *newp, **oldpp;
+ struct itimerval itv;
+ struct callout *newp, **oldpp;
- MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
- (int) func, (int) arg, time))
+ MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
+ (int) func, (int) arg, time));
- /*
- * Allocate timeout.
- */
- if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
- syslog(LOG_ERR, "Out of memory in timeout()!");
- exit(1);
- }
- newp->c_arg = arg;
- newp->c_func = func;
+ /*
+ * Allocate timeout.
+ */
+ if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
+ syslog(LOG_ERR, "Out of memory in timeout()!");
+ die(1);
+ }
+ newp->c_arg = arg;
+ newp->c_func = func;
- /*
- * Find correct place to link it in and decrement its time by the
- * amount of time used by preceding timeouts.
- */
- for (oldpp = &callout;
- *oldpp && (*oldpp)->c_time <= time;
- oldpp = &(*oldpp)->c_next)
- time -= (*oldpp)->c_time;
- newp->c_time = time;
- newp->c_next = *oldpp;
- if (*oldpp)
- (*oldpp)->c_time -= time;
- *oldpp = newp;
+ /*
+ * Find correct place to link it in and decrement its time by the
+ * amount of time used by preceding timeouts.
+ */
+ for (oldpp = &callout;
+ *oldpp && (*oldpp)->c_time <= time;
+ oldpp = &(*oldpp)->c_next)
+ time -= (*oldpp)->c_time;
+ newp->c_time = time;
+ newp->c_next = *oldpp;
+ if (*oldpp)
+ (*oldpp)->c_time -= time;
+ *oldpp = newp;
- /*
- * If this is now the first callout then we have to set a new
- * itimer.
- */
- if (callout == newp) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout->c_time;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
- }
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+ /*
+ * If this is now the first callout then we have to set a new
+ * itimer.
+ */
+ if (callout == newp) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
/*
* untimeout - Unschedule a timeout.
*/
-void untimeout(func, arg)
- void (*func)();
- caddr_t arg;
+void
+untimeout(func, arg)
+ void (*func)();
+ caddr_t arg;
{
+ struct itimerval itv;
+ struct callout **copp, *freep;
+ int reschedule = 0;
- struct itimerval itv;
- struct callout **copp, *freep;
- int reschedule = 0;
+ MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg));
- MAINDEBUG((LOG_DEBUG, "Untimeout %x:%x.", (int) func, (int) arg))
-
- /*
- * If the first callout is unscheduled then we have to set a new
- * itimer.
- */
- if (callout &&
- callout->c_func == func &&
- callout->c_arg == arg)
- reschedule = 1;
+ /*
+ * If the first callout is unscheduled then we have to set a new
+ * itimer.
+ */
+ if (callout &&
+ callout->c_func == func &&
+ callout->c_arg == arg)
+ reschedule = 1;
- /*
- * Find first matching timeout. Add its time to the next timeouts
- * time.
- */
- for (copp = &callout; *copp; copp = &(*copp)->c_next)
- if ((*copp)->c_func == func &&
- (*copp)->c_arg == arg) {
- freep = *copp;
- *copp = freep->c_next;
- if (*copp)
- (*copp)->c_time += freep->c_time;
- (void) free((char *) freep);
- break;
- }
+ /*
+ * Find first matching timeout. Add its time to the next timeouts
+ * time.
+ */
+ for (copp = &callout; *copp; copp = &(*copp)->c_next)
+ if ((*copp)->c_func == func &&
+ (*copp)->c_arg == arg) {
+ freep = *copp;
+ *copp = freep->c_next;
+ if (*copp)
+ (*copp)->c_time += freep->c_time;
+ (void) free((char *) freep);
+ break;
+ }
- if (reschedule) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout ? callout->c_time : 0;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
- }
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+ if (reschedule) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout ? callout->c_time : 0;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
@@ -934,60 +813,29 @@ void untimeout(func, arg)
* adjtimeout - Decrement the first timeout by the amount of time since
* it was scheduled.
*/
-void adjtimeout()
+void
+adjtimeout()
{
- struct timeval tv;
- int timediff;
+ struct timeval tv;
+ int timediff;
- if (callout == NULL)
- return;
- /*
- * Make sure that the clock hasn't been warped dramatically.
- * Account for recently expired, but blocked timer by adding
- * small fudge factor.
- */
- if (gettimeofday(&tv, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
- }
- timediff = tv.tv_sec - schedtime.tv_sec;
- if (timediff < 0 ||
- timediff > callout->c_time + 1)
- return;
+ if (callout == NULL)
+ return;
+ /*
+ * Make sure that the clock hasn't been warped dramatically.
+ * Account for recently expired, but blocked timer by adding
+ * small fudge factor.
+ */
+ if (gettimeofday(&tv, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ timediff = tv.tv_sec - schedtime.tv_sec;
+ if (timediff < 0 ||
+ timediff > callout->c_time + 1)
+ return;
- callout->c_time -= timediff; /* OK, Adjust time */
-}
-
-
-/*
- * output - Output PPP packet.
- */
-void
- output(unit, p, len)
-int unit;
-u_char *p;
-int len;
-{
-#ifdef STREAMS
- struct strbuf str;
-
- str.len = len;
- str.buf = (caddr_t) p;
- if(putmsg(fd, NULL, &str, 0) < 0) {
- syslog(LOG_ERR, "putmsg");
- exit(1);
- }
-#else
- if (unit != 0) {
- MAINDEBUG((LOG_WARNING, "output: unit != 0!"))
- abort();
- }
-
- if (write(fd, p, len) < 0) {
- syslog(LOG_ERR, "write");
- exit(1);
- }
-#endif
+ callout->c_time -= timediff; /* OK, Adjust time */
}
@@ -998,14 +846,18 @@ int len;
*/
/*ARGSUSED*/
static void
- hup(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+hup(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Hangup (SIGHUP)");
- adjtimeout(); /* Adjust timeouts */
- lcp_lowerdown(0); /* Reset connection */
+ syslog(LOG_INFO, "Hangup (SIGHUP)");
+
+ hungup = 1; /* they hung up on us! */
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_lowerdown(0); /* Reset connection */
+ quit(); /* and die */
}
@@ -1016,14 +868,15 @@ char *addr;
*/
/*ARGSUSED*/
static void
- term(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+term(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Terminate signal received.");
- adjtimeout(); /* Adjust timeouts */
- lcp_close(0); /* Close connection */
+ syslog(LOG_INFO, "Terminating link.");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
}
@@ -1034,14 +887,15 @@ char *addr;
*/
/*ARGSUSED*/
static void
- intr(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+intr(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- syslog(LOG_NOTICE, "Interrupt received. Exiting.");
- adjtimeout(); /* Adjust timeouts */
- lcp_close(0); /* Close connection */
+ syslog(LOG_INFO, "Interrupt received: terminating link");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
}
@@ -1052,47 +906,47 @@ char *addr;
*/
/*ARGSUSED*/
static void
- alrm(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+alrm(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- struct itimerval itv;
- struct callout *freep;
-
- MAINDEBUG((LOG_DEBUG, "Alarm"))
-
- /*
- * Call and free first scheduled timeout and any that were scheduled
- * for the same time.
- */
- while (callout) {
- freep = callout; /* Remove entry before calling */
- callout = freep->c_next;
- (*freep->c_func)(freep->c_arg);
- (void) free((char *) freep);
- if (callout && callout->c_time)
- break;
- }
-
- /*
- * Set a new itimer if there are more timeouts scheduled.
- */
- if (callout) {
- itv.it_interval.tv_sec = itv.it_interval.tv_usec =
- itv.it_value.tv_usec = 0;
- itv.it_value.tv_sec = callout->c_time;
- MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
- itv.it_value.tv_sec))
- if (setitimer(ITIMER_REAL, &itv, NULL)) {
- syslog(LOG_ERR, "setitimer(ITIMER_REAL)");
- exit(1);
+ struct itimerval itv;
+ struct callout *freep;
+
+ MAINDEBUG((LOG_DEBUG, "Alarm"));
+
+ /*
+ * Call and free first scheduled timeout and any that were scheduled
+ * for the same time.
+ */
+ while (callout) {
+ freep = callout; /* Remove entry before calling */
+ callout = freep->c_next;
+ (*freep->c_func)(freep->c_arg);
+ (void) free((char *) freep);
+ if (callout && callout->c_time)
+ break;
}
- if (gettimeofday(&schedtime, NULL)) {
- syslog(LOG_ERR, "gettimeofday");
- exit(1);
+
+ /*
+ * Set a new itimer if there are more timeouts scheduled.
+ */
+ if (callout) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
}
- }
}
@@ -1103,161 +957,112 @@ char *addr;
*/
/*ARGSUSED*/
static void
- io(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+io(sig, code, scp, addr)
+ int sig, code;
+ struct sigcontext *scp;
+ char *addr;
{
- int len, i;
- u_char *p;
- u_short protocol;
- fd_set fdset;
- struct timeval notime;
- int ready;
-#ifdef STREAMS
- struct strbuf str;
-#endif
+ int len, i;
+ u_char *p;
+ u_short protocol;
+ fd_set fdset;
+ struct timeval notime;
+ int ready;
+
+ MAINDEBUG((LOG_DEBUG, "IO signal received"));
+ adjtimeout(); /* Adjust timeouts */
+
+ /* we do this to see if the SIGIO handler is being invoked for input */
+ /* ready, or for the socket buffer hitting the low-water mark. */
+
+ notime.tv_sec = 0;
+ notime.tv_usec = 0;
+ FD_ZERO(&fdset);
+ FD_SET(fd, &fdset);
+
+ if ((ready = select(32, &fdset, (fd_set *) NULL, (fd_set *) NULL,
+ &notime)) == -1) {
+ syslog(LOG_ERR, "Error in io() select: %m");
+ die(1);
+ }
+
+ if (ready == 0) {
+ MAINDEBUG((LOG_DEBUG, "IO non-input ready SIGIO occured."));
+ return;
+ }
+ /* Yup, this is for real */
+ for (;;) { /* Read all available packets */
+ p = inpacket_buf; /* point to beginning of packet buffer */
- MAINDEBUG((LOG_DEBUG, "IO signal received"))
- adjtimeout(); /* Adjust timeouts */
+ len = read_packet(inpacket_buf);
+ if (len < 0)
+ return;
- /* we do this to see if the SIGIO handler is being invoked for input */
- /* ready, or for the socket buffer hitting the low-water mark. */
+ if (len == 0) {
+ syslog(LOG_ERR, "End of file on fd!");
+ die(1);
+ }
- notime.tv_sec = 0;
- notime.tv_usec = 0;
+ if (len < DLLHEADERLEN) {
+ MAINDEBUG((LOG_INFO, "io(): Received short packet."));
+ return;
+ }
- FD_ZERO(&fdset);
- FD_SET(fd, &fdset);
-
- if ((ready = select(32, &fdset, (fd_set *) NULL, (fd_set *) NULL,
- &notime)) == -1) {
- syslog(LOG_ERR, "Error in io() select: %m");
- exit(1);
- }
-
- if (ready == 0) {
- MAINDEBUG((LOG_DEBUG, "IO non-input ready SIGIO occured."));
- return;
- }
+ p += 2; /* Skip address and control */
+ GETSHORT(protocol, p);
+ len -= DLLHEADERLEN;
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ */
+ if (protocol != LCP && lcp_fsm[0].state != OPENED) {
+ MAINDEBUG((LOG_INFO,
+ "io(): Received non-LCP packet when LCP not open."));
+ if (debug)
+ dumpbuffer(inpacket_buf, len + DLLHEADERLEN, LOG_INFO);
+ return;
+ }
- /* Yup, this is for real */
- for (;;) { /* Read all available packets */
- p = inpacket_buf; /* point to beggining of packet buffer */
+ /*
+ * 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);
+ break;
+ }
-#ifdef STREAMS
- str.maxlen = MTU+DLLHEADERLEN;
- str.buf = (caddr_t) p;
- i = 0;
- len = getmsg(fd, NULL, &str, &i);
- if(len < 0) {
- if(errno == EAGAIN || errno == EWOULDBLOCK) {
- return;
- }
- syslog(LOG_ERR, "getmsg(fd) %m");
- exit(1);
- }
- else if(len)
- MAINDEBUG((LOG_DEBUG, "getmsg returns with length 0x%x",len))
-
- if(str.len < 0) {
- MAINDEBUG((LOG_DEBUG, "getmsg short return length %d",
- str.len))
- return;
- }
-
- len = str.len;
-#else
- if ((len = read(fd, p, MTU + DLLHEADERLEN)) < 0) {
- if (errno == EWOULDBLOCK) {
- MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"))
- return;
- }
- else {
- syslog(LOG_ERR, "read(fd): %m");
- exit(1);
- }
- }
- else
-#endif
- if (len == 0) {
- syslog(LOG_ERR, "End of file on fd!");
- exit(1);
- }
-
- if (len < DLLHEADERLEN) {
- MAINDEBUG((LOG_INFO, "io(): Received short packet."))
- return;
- }
-
- p += 2; /* Skip address and control */
- GETSHORT(protocol, p);
- len -= DLLHEADERLEN;
-
- /*
- * Toss all non-LCP packets unless LCP is OPEN.
- */
- if (protocol != LCP && lcp_fsm[0].state != OPEN) {
- MAINDEBUG((LOG_INFO, "io(): Received non-LCP packet and LCP is not in open state."))
- dumpbuffer(inpacket_buf, len + DLLHEADERLEN, LOG_ERR);
- 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);
- break;
- }
-
- if (i == sizeof (prottbl) / sizeof (struct protent)) {
- syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
- protocol);
- p -= DLLHEADERLEN;
- len += DLLHEADERLEN;
- lcp_sprotrej(0, p, len);
+ if (i == sizeof (prottbl) / sizeof (struct protent)) {
+ syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
+ protocol);
+ lcp_sprotrej(0, p - DLLHEADERLEN, len + DLLHEADERLEN);
+ }
}
- }
}
/*
- * cleanup - clean_up before we exit
- */
-/* ARGSUSED */
-static void
- cleanup(status, arg)
-int status;
-caddr_t arg;
-{
- adjtimeout();
- lcp_lowerdown(0);
- if (unlink(pidfilename) < 0)
- syslog(LOG_WARNING, "unable to unlink pid file: %m");
-}
-
-
-/*
* demuxprotrej - Demultiplex a Protocol-Reject.
*/
void
- demuxprotrej(unit, protocol)
-int unit;
-u_short protocol;
+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 %d!", 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 %d!",
+ protocol);
}
@@ -1268,14 +1073,12 @@ u_short protocol;
*/
/*ARGSUSED*/
static void
- incdebug(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
+incdebug(sig)
+ int sig;
{
- syslog(LOG_NOTICE, "Debug turned ON, Level %d", debug);
- setlogmask(LOG_UPTO(LOG_DEBUG));
- debug++;
+ syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ debug++;
}
@@ -1286,913 +1089,82 @@ char *addr;
*/
/*ARGSUSED*/
static void
- nodebug(sig, code, scp, addr)
-int sig, code;
-struct sigcontext *scp;
-char *addr;
-{
- setlogmask(LOG_UPTO(LOG_WARNING));
- debug = 0;
-}
-
-
-/*
- * setdebug - Set debug (command line argument).
- */
-static int
- setdebug(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- debug++;
- setlogmask(LOG_UPTO(LOG_DEBUG));
- --*argcp, ++*argvp;
- return (1);
-}
-
-/*
- * noopt - Disable all options.
- */
-static int
- noopt(argcp, argvp)
-int *argcp;
-char ***argvp;
+nodebug(sig)
+ int sig;
{
- 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));
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setconnector - Set a program to connect to a serial line
- */
-static int
- setconnector(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
-
- --*argcp, ++*argvp;
-
- connector = strdup(**argvp);
- if (connector == NULL) {
- syslog(LOG_ERR, "cannot allocate space for connector string");
- exit(1);
- }
-
- --*argcp, ++*argvp;
- return (1);
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ debug = 0;
}
/*
* set_up_connection - run a program to initialize the serial connector
*/
-int set_up_connection(program, in, out)
- char *program;
- int in, out;
-{
- int pid;
- int flags;
- int status;
-
- flags = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
- pid = fork();
-
- if (pid < 0) {
- syslog(LOG_ERR, "fork");
- exit(1);
- }
-
- if (pid == 0) {
- (void) setreuid(getuid(), getuid());
- (void) setregid(getgid(), getgid());
- (void) sigsetmask(flags);
- (void) dup2(in, 0);
- (void) dup2(out, 1);
- (void) execl("/bin/sh", "sh", "-c", program, (char *)0);
- syslog(LOG_ERR, "could not exec /bin/sh");
- _exit(99);
- }
- else {
- while (waitpid(pid, &status, 0) != pid) {
- if (errno == EINTR)
- continue;
- syslog(LOG_ERR, "waiting for connection process");
- exit(1);
- }
- (void) sigsetmask(flags);
- }
- return (status == 0 ? 0 : -1);
-}
-
-/*
- * noaccomp - Disable Address/Control field compression negotiation.
- */
-static int
- noaccomp(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_accompression = 0;
- lcp_allowoptions[0].neg_accompression = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noasyncmap - Disable async map negotiation.
- */
-static int
- noasyncmap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_asyncmap = 0;
- lcp_allowoptions[0].neg_asyncmap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noipaddr - Disable IP address negotiation.
- */
-static int
- noipaddr(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- ipcp_wantoptions[0].neg_addrs = 0;
- ipcp_allowoptions[0].neg_addrs = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nomagicnumber - Disable magic number negotiation.
- */
-static int
- nomagicnumber(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_magicnumber = 0;
- lcp_allowoptions[0].neg_magicnumber = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nomru - Disable mru negotiation.
- */
-static int
- nomru(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_mru = 0;
- lcp_allowoptions[0].neg_mru = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setmru - Set MRU for negotiation.
- */
-static int
- setmru(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- --*argcp, ++*argvp;
- lcp_wantoptions[0].mru = atoi(**argvp);
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * nopcomp - Disable Protocol field compression negotiation.
- */
-static int
- nopcomp(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_pcompression = 0;
- lcp_allowoptions[0].neg_pcompression = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setpassive - Set passive mode.
- */
-static int
- setpassive(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].passive = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * noupap - Disable UPAP authentication.
- */
-static int
- noupap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_allowoptions[0].neg_upap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * requpap - Require UPAP authentication.
- */
-static int
- requpap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- FILE * ufile;
- struct stat sbuf;
-
- lcp_wantoptions[0].neg_upap = 1;
- lcp_allowoptions[0].neg_upap = 0;
- --*argcp, ++*argvp;
- strcpy(uinfopath, **argvp);
- --*argcp, ++*argvp;
-
- /* open user info file */
-
- if ((ufile = fopen(uinfopath, "r")) == NULL) {
- fprintf(stderr, "unable to open user login data file %s\n", uinfopath);
- exit(1);
- };
-
- if (fstat(fileno(ufile), &sbuf) < 0) {
- perror("cannot stat user login data file!");
- exit(1);
- }
- if ((sbuf.st_mode & 077) != 0)
- syslog(LOG_WARNING, "Warning - user info file has world and/or group access!\n");
-
- /* get username */
- fgets(user, sizeof (user) - 1, ufile);
- if (strlen(user) == 0) {
- fprintf(stderr, "Unable to get user name from user login data file.\n");
- exit(2);
- }
- /* get rid of newline */
- user[strlen(user) - 1] = '\000';
-
- fgets(passwd, sizeof(passwd) - 1, ufile);
-
- if (strlen(passwd) == 0) {
- fprintf(stderr, "Unable to get password from user login data file.\n");
- exit(2);
- }
-
- passwd[strlen(passwd) - 1] = '\000';
-
- return (1);
-}
-
-
-/*
- * nochap - Disable CHAP authentication.
- */
-static int
- nochap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_allowoptions[0].neg_chap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * reqchap - Require CHAP authentication.
- */
-static int
- reqchap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- lcp_wantoptions[0].neg_chap = 1;
- lcp_allowoptions[0].neg_chap = 0;
- --*argcp, ++*argvp;
- return (1);
-}
-
-
-/*
- * setvjmode - Set vj compression mode
- */
-
-static int
- setvjmode(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- extern int ipcp_vj_mode;
-
- --*argcp, ++*argvp;
-
- if (!strcmp(**argvp, "old")) { /* "old" mode */
- ipcp_vj_setmode(IPCP_VJMODE_OLD);
- }
-
- else if (!strcmp(**argvp, "rfc1172")) { /* "rfc1172" mode*/
- ipcp_vj_setmode(IPCP_VJMODE_RFC1172);
- }
-
- else if (!strcmp(**argvp, "rfc1332")) { /* "rfc1332" default mode */
- ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
- }
- else {
- syslog(LOG_WARNING,
- "Unknown vj compression mode %s. Defaulting to RFC1332", **argvp);
- ipcp_vj_setmode(IPCP_VJMODE_RFC1332);
- }
- --*argcp, ++*argvp;
-
- return (1);
-}
-/*
- * setnovj - diable vj compression
- */
-
-static int
- setnovj(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- extern int ipcp_vj_mode;
-
- --*argcp, ++*argvp;
- ipcp_wantoptions[0].neg_vj = 0;
- ipcp_allowoptions[0].neg_vj = 0;
-
- return (1);
-}
-
-/*
- * setdomain - Set domain name to append to hostname
- */
-static int
- setdomain(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
-
- --*argcp, ++*argvp;
-
- strcat(hostname, **argvp);
- hostname_len = strlen(hostname);
-
- --*argcp, ++*argvp;
-
- return (1);
-}
-
-/*
- * Valid speeds.
- */
-struct speed {
- int speed_int, speed_val;
-} speeds[] = {
-#ifdef B50
- { 50, B50 },
-#endif
-#ifdef B75
- { 75, B75 },
-#endif
-#ifdef B110
- { 110, B110 },
-#endif
-#ifdef B150
- { 150, B150 },
-#endif
-#ifdef B200
- { 200, B200 },
-#endif
-#ifdef B300
- { 300, B300 },
-#endif
-#ifdef B600
- { 600, B600 },
-#endif
-#ifdef B1200
- { 1200, B1200 },
-#endif
-#ifdef B1800
- { 1800, B1800 },
-#endif
-#ifdef B2000
- { 2000, B2000 },
-#endif
-#ifdef B2400
- { 2400, B2400 },
-#endif
-#ifdef B3600
- { 3600, B3600 },
-#endif
-#ifdef B4800
- { 4800, B4800 },
-#endif
-#ifdef B7200
- { 7200, B7200 },
-#endif
-#ifdef B9600
- { 9600, B9600 },
-#endif
-#ifdef EXTA
- { 19200, EXTA },
-#endif
-#ifdef EXTB
- { 38400, EXTB },
-#endif
-#ifdef B57600
- { 57600, B57600 },
-#endif
-#ifdef B115200
- { 115200, B115200 },
-#endif
- { 0, 0 }
-};
-
-static int
- setasyncmap(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- unsigned long asyncmap;
-
- asyncmap = 0xffffffff;
- ++*argvp;
- sscanf(**argvp,"%lx",&asyncmap);
- ++*argvp;
- lcp_wantoptions[0].asyncmap = asyncmap;
- *argcp -= 2;
- return(1);
-}
-
-/*
- * setspeed - Set the speed.
- */
-static int
- setspeed(argcp, argvp)
-int *argcp;
-char ***argvp;
+int
+set_up_connection(program, in, out)
+ char *program;
+ int in, out;
{
- int speed;
- struct speed *speedp;
-
- speed = atoi(**argvp);
- for (speedp = speeds; speedp->speed_int; speedp++)
- if (speed == speedp->speed_int) {
- inspeed = speedp->speed_val;
- --*argcp, ++*argvp;
- return (1);
- }
- return (0);
-}
+ int pid;
+ int status;
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &mask, &mask);
-/*
- * setdevname - Set the device name.
- */
-int setdevname(argcp, argvp)
- int *argcp;
- char ***argvp;
-{
- char dev[DEVNAME_SIZE];
- char *cp = **argvp;
- struct stat statbuf;
- char *tty, *ttyname();
-
- if (strncmp("/dev/", cp, sizeof ("/dev/") - 1)) {
- (void) sprintf(dev, "/dev/%s", cp);
- cp = dev;
- }
-
- /*
- * Check if there is a device by this name.
- */
- if (stat(cp, &statbuf) < 0) {
- if (errno == ENOENT)
- return (0);
- syslog(LOG_ERR, cp);
- exit(1);
- }
-
- (void) strcpy(devname, cp);
- default_device = FALSE;
- --*argcp, ++*argvp;
-
- /*
- * If we haven't already decided to require authentication,
- * or we are running ppp on the control terminal, then we can
- * allow authentication to be requested.
- */
- if ((tty = ttyname(fileno(stdin))) == NULL)
- tty = ""; /* running from init means no stdin. Null kills strcmp -KWK */
- if (lcp_wantoptions[0].neg_upap == 0 &&
- strcmp(devname, "/dev/tty") &&
- strcmp(devname, tty)) {
- lcp_wantoptions[0].neg_upap = 0;
- lcp_allowoptions[0].neg_upap = 1;
- }
- return (1);
-}
-
-
-/*
- * setipaddr - Set the IP address
- */
-int setipaddr(argcp, argvp)
- int *argcp;
- char ***argvp;
-{
- u_long local, remote;
- struct hostent *hp;
- char *colon, *index();
-
- /*
- * IP address pair separated by ":".
- */
- if ((colon = index(**argvp, ':')) == NULL)
- return (0);
+ pid = fork();
- /*
- * If colon first character, then no local addr.
- */
- if (colon == **argvp) {
- local = 0l;
- ++colon;
- }
- else {
- *colon++ = '\0';
- if ((local = inet_addr(**argvp)) == -1) {
- if ((hp = gethostbyname(**argvp)) == NULL) {
- syslog(LOG_WARNING, "unknown host: %s", **argvp);
- goto ret;
- }
- bcopy(hp->h_addr, (char *) &local, hp->h_length);
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
}
- }
- /*
- * If colon last character, then no remote addr.
- */
- if (*colon == '\0')
- remote = 0l;
- else {
- if ((remote = inet_addr(colon)) == -1) {
- if ((hp = gethostbyname(colon)) == NULL) {
- syslog(LOG_WARNING,"unknown host: %s", colon);
- goto ret;
- }
- bcopy(hp->h_addr, (char *) &remote, hp->h_length);
+ if (pid == 0) {
+ setreuid(getuid(), getuid());
+ setregid(getgid(), getgid());
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ dup2(in, 0);
+ dup2(out, 1);
+ execl("/bin/sh", "sh", "-c", program, (char *)0);
+ syslog(LOG_ERR, "could not exec /bin/sh: %m");
+ _exit(99);
+ /* NOTREACHED */
}
- }
-
- ipcp_wantoptions[0].neg_addrs = 1;
- ipcp_wantoptions[0].ouraddr = local;
- ipcp_wantoptions[0].hisaddr = remote;
-
- ret:
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setnetmask(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- u_long mask;
-
- --*argcp, ++*argvp;
- if ((mask = inet_addr(**argvp)) == -1) {
- fprintf(stderr, "Invalid netmask %s\n", **argvp);
- exit(1);
- }
-
- netmask = mask;
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setcrtscts(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- crtscts = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-static int
- setnodetach(argcp, argvp)
-int *argcp;
-char ***argvp;
-{
- nodetach = 1;
- --*argcp, ++*argvp;
- return (1);
-}
-
-/*
- * getuserpasswd - Get the user name and passwd.
- */
-static void
- getuserpasswd()
-{
-
- upap[0].us_user = user;
- upap[0].us_userlen = strlen(upap[0].us_user);
- upap[0].us_passwd = passwd;
- upap[0].us_passwdlen = strlen(upap[0].us_passwd);
-}
-
-
-/*
- * login - Check the user name and passwd and login the user.
- *
- * returns:
- * UPAP_AUTHNAK: Login failed.
- * UPAP_AUTHACK: Login succeeded.
- * In either case, msg points to an appropriate message.
- */
-u_char
- login(user, userlen, passwd, passwdlen, msg, msglen)
-char *user;
-int userlen;
-char *passwd;
-int passwdlen;
-char **msg;
-int *msglen;
-{
- struct passwd *pw;
- char *epasswd, *crypt();
- static int attempts = 0;
- char *tty, *rindex();
- char *tmp_passwd, *tmp_user;
-
- /* why alloca.h doesn't define what alloca() returns is a mystery */
- /* seems to be defined in stdlib.h for FreeBSD, rgrimes */
-
-#ifdef sparc
- char *__builtin_alloca __ARGS((int));
-#else
-#ifndef __386BSD__
- char *alloca __ARGS((int));
-#endif /* !__386BSD__ */
-#endif /*sparc*/
- tmp_passwd = alloca(passwdlen + 1); /* we best make copies before */
- /* null terminating the string */
- if (tmp_passwd == NULL) {
- syslog(LOG_ERR, "alloca failed");
- exit(1);
- }
- bcopy(passwd, tmp_passwd, passwdlen);
- tmp_passwd[passwdlen] = '\0';
-
- tmp_user = alloca(userlen + 1);
- if (tmp_user == NULL) {
- syslog(LOG_ERR, "alloca failed");
- exit(1);
- }
- bcopy(user, tmp_user, userlen);
- tmp_user[userlen] = '\0';
-
- if ((pw = getpwnam(tmp_user)) == NULL) {
- *msg = "Login incorrect";
- *msglen = strlen(*msg);
- syslog(LOG_WARNING, "upap login userid '%s' incorrect",tmp_user);
- return (UPAP_AUTHNAK);
- }
-
- /*
- * XXX If no passwd, let them login without one.
- */
- if (pw->pw_passwd == '\0') {
- *msg = "Login ok";
- *msglen = strlen(*msg);
- return (UPAP_AUTHACK);
- }
-
- epasswd = crypt(tmp_passwd, pw->pw_passwd);
- if (strcmp(epasswd, pw->pw_passwd)) {
- *msg = "Login incorrect";
- *msglen = strlen(*msg);
- syslog(LOG_WARNING, "upap login password '%s' incorrect", tmp_passwd);
- /*
- * Frustrate passwd stealer programs.
- * Allow 10 tries, but start backing off after 3 (stolen from login).
- * On 10'th, drop the connection.
- */
- if (attempts++ >= 10) {
- syslog(LOG_WARNING, "%d LOGIN FAILURES ON %s, %s",
- attempts, devname, tmp_user);
- lcp_close(0); /* Drop DTR? */
+ while (waitpid(pid, &status, 0) != pid) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "waiting for connection process: %m");
+ die(1);
}
- if (attempts > 3)
- sleep((u_int) (attempts - 3) * 5);
- return (UPAP_AUTHNAK);
- }
-
- attempts = 0; /* Reset count */
- *msg = "Login ok";
- *msglen = strlen(*msg);
- syslog(LOG_NOTICE, "user %s logged in", tmp_user);
- tty = rindex(devname, '/');
- if (tty == NULL)
- tty = devname;
- else
- tty++;
- logwtmp(tty, tmp_user, ""); /* Add wtmp login entry */
-
- return (UPAP_AUTHACK);
-}
-
+ sigprocmask(SIG_SETMASK, &mask, NULL);
-/*
- * logout - Logout the user.
- */
-void logout()
-{
- char *tty;
-
- tty = rindex(devname, '/');
- if (tty == NULL)
- tty = devname;
- else
- tty++;
- logwtmp(tty, "", ""); /* Add wtmp logout entry */
+ return (status == 0 ? 0 : -1);
}
/*
- * getuseropt - Get the options from /etc/hosts.ppp for this user.
- */
-int getuseropt(user)
- char *user;
-{
- char buf[1024], *s;
- FILE *fp;
- int rc = 0;
-
- if ((fp = fopen(PPPHOSTS, "r")) == NULL)
- return (0);;
-
- /*
- * Loop till we find an entry for this user.
- */
- for (;;) {
- if (fgets(buf, sizeof (buf), fp) == NULL) {
- if (feof(fp))
- break;
- else {
- syslog(LOG_ERR, "fgets");
- exit(1);
- }
- }
- if ((s = index(buf, ' ')) == NULL)
- continue;
- *s++ = '\0';
- if (!strcmp(user, buf)) {
- rc = 1;
- break;
- }
- }
- fclose(fp);
- return (rc);
-}
-/*
- * open "secret" file and return the secret matching the given name.
- * If no secret for a given name is found, use the one for "default".
- */
-
-void
- get_secret(name, secret, secret_len)
-u_char * name;
-u_char * secret;
-int * secret_len;
-{
- FILE * sfile;
- struct stat sbuf;
- u_char fname[256];
- int match_found, default_found;
-
- match_found = FALSE;
- default_found = FALSE;
-
- if ((sfile = fopen(_PATH_CHAPFILE, "r")) == NULL) {
- syslog(LOG_ERR, "unable to open secret file %s", _PATH_CHAPFILE);
- exit(1);
- };
-
- if (fstat(fileno(sfile), &sbuf) < 0) {
- syslog(LOG_ERR, "cannot stat secret file!: %m");
- exit(1);
- }
- if ((sbuf.st_mode & 077) != 0)
- syslog(LOG_WARNING, "Warning - secret file has world and/or group access!");
-
- while (!feof(sfile) && !match_found) {
- if (fscanf(sfile, "%s %s", fname, secret) == EOF)
- break;
- if (!strcasecmp((char *)fname, (char *)name)) {
- match_found = TRUE;
- }
- if (!strcasecmp("default", (char *)name)) {
- default_found = TRUE;
- }
- }
-
- if (!match_found && !default_found) {
- syslog(LOG_ERR, "No match or default entry found for %s in CHAP secret file! Aborting...", name);
- cleanup(0, NULL); /* shut us down */
- }
-#ifdef UNSECURE
-/* while this is useful for debugging, it is a security hole as well */
-
- syslog(LOG_DEBUG, "get_secret: found secret %s", secret);
-#endif /*UNSECURE*/
- fclose(sfile);
- *secret_len = strlen((char *)secret);
- if (*secret_len > MAX_SECRET_LEN) { /* don't let it overflow the buffer */
- syslog(LOG_ERR, "Length of secret for host %s is greater than the maximum %d characters! ", name, MAX_SECRET_LEN);
- cleanup(0, NULL); /* scream and die */
- }
- return;
-}
-/*
* Return user specified netmask. A value of zero means no netmask has
* been set.
*/
/* ARGSUSED */
u_long
- GetMask(addr)
-u_long addr;
+GetMask(addr)
+ u_long addr;
{
- return(netmask);
+ return(netmask);
}
-#ifdef STREAMS
-/*
- * this module will attempt to reconstruct the stream with the
- * previously popped modules
+/*
+ * dumpbuffer - print contents of a buffer in hex to standard output.
*/
-
-/*ARGSUSED*/
-static void
- str_restore()
-{
- /*EMPTY*/
- while(ioctl(fd, I_POP, 0) == 0); /* pop any we pushed */
-
- for(; str_module_count > 0; str_module_count--) {
- if(ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
- syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
- str_modules[str_module_count-1].modname);
- }
- else {
- MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
- str_modules[str_module_count-1].modname))
- }
- }
-}
-#endif
-
+void
dumpbuffer(buffer, size, level)
-unsigned char *buffer;
-int size;
-int level;
+ unsigned char *buffer;
+ int size;
+ int level;
{
register int i;
char line[256], *p;
@@ -2227,48 +1199,17 @@ int level;
}
}
-#ifdef sun
-setdtr(fd, on)
-int fd, on;
-{
- int linestate;
-
- ioctl(fd, TIOCMGET, &linestate);
-
- if (on)
- linestate |= TIOCM_DTR;
- else
- linestate &= ~TIOCM_DTR;
- ioctl(fd, TIOCMSET, &linestate);
-}
-#endif
-#ifdef __386BSD__
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
setdtr(fd, on)
int fd, on;
{
int modembits = TIOCM_DTR;
- if (on)
- ioctl(fd, TIOCMBIS, &modembits);
- else
- ioctl(fd, TIOCMBIC, &modembits);
-}
-#endif
-
-char *
-proto_name(proto)
-u_short proto;
-{
- switch (proto) {
- case LCP: return "lcp";
- case UPAP: return "pap";
- case CHAP: return "chap";
- case IPCP: return "ipcp";
-#define LQM 0xc025
- case LQM: return "lqm";
- }
- return "<unknown>";
+ ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
}
#include <varargs.h>
@@ -2296,3 +1237,11 @@ va_dcl
line[0] = 0;
}
}
+
+void
+novm(msg)
+ char *msg;
+{
+ syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg);
+ die(1);
+}
diff --git a/libexec/pppd/md5.c b/libexec/pppd/md5.c
index d9ef47b76f9f..480c860c0aa9 100644
--- a/libexec/pppd/md5.c
+++ b/libexec/pppd/md5.c
@@ -92,6 +92,12 @@ static unsigned char PADDING[64] = {
(a) += (b); \
}
+#ifdef __STDC__
+#define UL(x) x##U
+#else
+#define UL(x) x
+#endif
+
/* The routine MD5Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
@@ -202,88 +208,88 @@ UINT4 *in;
#define S12 12
#define S13 17
#define S14 22
- FF ( a, b, c, d, in[ 0], S11, 3614090360UL); /* 1 */
- FF ( d, a, b, c, in[ 1], S12, 3905402710UL); /* 2 */
- FF ( c, d, a, b, in[ 2], S13, 606105819UL); /* 3 */
- FF ( b, c, d, a, in[ 3], S14, 3250441966UL); /* 4 */
- FF ( a, b, c, d, in[ 4], S11, 4118548399UL); /* 5 */
- FF ( d, a, b, c, in[ 5], S12, 1200080426UL); /* 6 */
- FF ( c, d, a, b, in[ 6], S13, 2821735955UL); /* 7 */
- FF ( b, c, d, a, in[ 7], S14, 4249261313UL); /* 8 */
- FF ( a, b, c, d, in[ 8], S11, 1770035416UL); /* 9 */
- FF ( d, a, b, c, in[ 9], S12, 2336552879UL); /* 10 */
- FF ( c, d, a, b, in[10], S13, 4294925233UL); /* 11 */
- FF ( b, c, d, a, in[11], S14, 2304563134UL); /* 12 */
- FF ( a, b, c, d, in[12], S11, 1804603682UL); /* 13 */
- FF ( d, a, b, c, in[13], S12, 4254626195UL); /* 14 */
- FF ( c, d, a, b, in[14], S13, 2792965006UL); /* 15 */
- FF ( b, c, d, a, in[15], S14, 1236535329UL); /* 16 */
+ FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */
+ FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */
+ FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */
+ FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */
+ FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */
+ FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */
+ FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */
+ FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */
+ FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */
+ FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */
+ FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */
+ FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */
+ FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */
+ FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */
+ FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */
+ FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */
/* Round 2 */
#define S21 5
#define S22 9
#define S23 14
#define S24 20
- GG ( a, b, c, d, in[ 1], S21, 4129170786UL); /* 17 */
- GG ( d, a, b, c, in[ 6], S22, 3225465664UL); /* 18 */
- GG ( c, d, a, b, in[11], S23, 643717713UL); /* 19 */
- GG ( b, c, d, a, in[ 0], S24, 3921069994UL); /* 20 */
- GG ( a, b, c, d, in[ 5], S21, 3593408605UL); /* 21 */
- GG ( d, a, b, c, in[10], S22, 38016083UL); /* 22 */
- GG ( c, d, a, b, in[15], S23, 3634488961UL); /* 23 */
- GG ( b, c, d, a, in[ 4], S24, 3889429448UL); /* 24 */
- GG ( a, b, c, d, in[ 9], S21, 568446438UL); /* 25 */
- GG ( d, a, b, c, in[14], S22, 3275163606UL); /* 26 */
- GG ( c, d, a, b, in[ 3], S23, 4107603335UL); /* 27 */
- GG ( b, c, d, a, in[ 8], S24, 1163531501UL); /* 28 */
- GG ( a, b, c, d, in[13], S21, 2850285829UL); /* 29 */
- GG ( d, a, b, c, in[ 2], S22, 4243563512UL); /* 30 */
- GG ( c, d, a, b, in[ 7], S23, 1735328473UL); /* 31 */
- GG ( b, c, d, a, in[12], S24, 2368359562UL); /* 32 */
+ GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */
+ GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */
+ GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */
+ GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */
+ GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */
+ GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */
+ GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */
+ GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */
+ GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */
+ GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */
+ GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */
+ GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */
+ GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */
+ GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */
+ GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */
+ GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */
/* Round 3 */
#define S31 4
#define S32 11
#define S33 16
#define S34 23
- HH ( a, b, c, d, in[ 5], S31, 4294588738UL); /* 33 */
- HH ( d, a, b, c, in[ 8], S32, 2272392833UL); /* 34 */
- HH ( c, d, a, b, in[11], S33, 1839030562UL); /* 35 */
- HH ( b, c, d, a, in[14], S34, 4259657740UL); /* 36 */
- HH ( a, b, c, d, in[ 1], S31, 2763975236UL); /* 37 */
- HH ( d, a, b, c, in[ 4], S32, 1272893353UL); /* 38 */
- HH ( c, d, a, b, in[ 7], S33, 4139469664UL); /* 39 */
- HH ( b, c, d, a, in[10], S34, 3200236656UL); /* 40 */
- HH ( a, b, c, d, in[13], S31, 681279174UL); /* 41 */
- HH ( d, a, b, c, in[ 0], S32, 3936430074UL); /* 42 */
- HH ( c, d, a, b, in[ 3], S33, 3572445317UL); /* 43 */
- HH ( b, c, d, a, in[ 6], S34, 76029189UL); /* 44 */
- HH ( a, b, c, d, in[ 9], S31, 3654602809UL); /* 45 */
- HH ( d, a, b, c, in[12], S32, 3873151461UL); /* 46 */
- HH ( c, d, a, b, in[15], S33, 530742520UL); /* 47 */
- HH ( b, c, d, a, in[ 2], S34, 3299628645UL); /* 48 */
+ HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */
+ HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */
+ HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */
+ HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */
+ HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */
+ HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */
+ HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */
+ HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */
+ HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */
+ HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */
+ HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */
+ HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */
+ HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */
+ HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */
+ HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */
+ HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */
/* Round 4 */
#define S41 6
#define S42 10
#define S43 15
#define S44 21
- II ( a, b, c, d, in[ 0], S41, 4096336452UL); /* 49 */
- II ( d, a, b, c, in[ 7], S42, 1126891415UL); /* 50 */
- II ( c, d, a, b, in[14], S43, 2878612391UL); /* 51 */
- II ( b, c, d, a, in[ 5], S44, 4237533241UL); /* 52 */
- II ( a, b, c, d, in[12], S41, 1700485571UL); /* 53 */
- II ( d, a, b, c, in[ 3], S42, 2399980690UL); /* 54 */
- II ( c, d, a, b, in[10], S43, 4293915773UL); /* 55 */
- II ( b, c, d, a, in[ 1], S44, 2240044497UL); /* 56 */
- II ( a, b, c, d, in[ 8], S41, 1873313359UL); /* 57 */
- II ( d, a, b, c, in[15], S42, 4264355552UL); /* 58 */
- II ( c, d, a, b, in[ 6], S43, 2734768916UL); /* 59 */
- II ( b, c, d, a, in[13], S44, 1309151649UL); /* 60 */
- II ( a, b, c, d, in[ 4], S41, 4149444226UL); /* 61 */
- II ( d, a, b, c, in[11], S42, 3174756917UL); /* 62 */
- II ( c, d, a, b, in[ 2], S43, 718787259UL); /* 63 */
- II ( b, c, d, a, in[ 9], S44, 3951481745UL); /* 64 */
+ II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */
+ II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */
+ II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */
+ II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */
+ II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */
+ II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */
+ II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */
+ II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */
+ II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */
+ II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */
+ II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */
+ II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */
+ II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */
+ II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */
+ II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */
+ II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */
buf[0] += a;
buf[1] += b;
diff --git a/libexec/pppd/options.c b/libexec/pppd/options.c
new file mode 100644
index 000000000000..9f622b1ba4c0
--- /dev/null
+++ b/libexec/pppd/options.c
@@ -0,0 +1,1195 @@
+/*
+ * options.c - handles option processing for PPP.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: options.c,v 1.1 1994/03/30 09:38:16 jkh Exp $";
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <syslog.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+
+#define FALSE 0
+#define TRUE 1
+
+
+/*
+ * Prototypes
+ */
+static int setdebug __ARGS((void));
+static int setpassive __ARGS((void));
+static int setsilent __ARGS((void));
+static int noopt __ARGS((void));
+static int setnovj __ARGS((void));
+static int reqpap __ARGS((void));
+static int nopap __ARGS((void));
+static int setupapfile __ARGS((char **));
+static int nochap __ARGS((void));
+static int reqchap __ARGS((void));
+static int setspeed __ARGS((char *));
+static int noaccomp __ARGS((void));
+static int noasyncmap __ARGS((void));
+static int noipaddr __ARGS((void));
+static int nomagicnumber __ARGS((void));
+static int setasyncmap __ARGS((char **));
+static int setmru __ARGS((char **));
+static int nomru __ARGS((void));
+static int nopcomp __ARGS((void));
+static int setconnector __ARGS((char **));
+static int setdomain __ARGS((char **));
+static int setnetmask __ARGS((char **));
+static int setcrtscts __ARGS((void));
+static int setnodetach __ARGS((void));
+static int setmodem __ARGS((void));
+static int setlocal __ARGS((void));
+static int setname __ARGS((char **));
+static int setuser __ARGS((char **));
+static int setremote __ARGS((char **));
+static int setauth __ARGS((void));
+static int readfile __ARGS((char **));
+static int setdefaultroute __ARGS((void));
+static int setproxyarp __ARGS((void));
+static int setpersist __ARGS((void));
+static int setdologin __ARGS((void));
+static int setusehostname __ARGS((void));
+static int setnoipdflt __ARGS((void));
+static int setlcptimeout __ARGS((char **));
+static int setlcpterm __ARGS((char **));
+static int setlcpconf __ARGS((char **));
+static int setlcpfails __ARGS((char **));
+static int setipcptimeout __ARGS((char **));
+static int setipcpterm __ARGS((char **));
+static int setipcpconf __ARGS((char **));
+static int setipcpfails __ARGS((char **));
+static int setpaptimeout __ARGS((char **));
+static int setpapreqs __ARGS((char **));
+static int setchaptimeout __ARGS((char **));
+static int setchapchal __ARGS((char **));
+static int setchapintv __ARGS((char **));
+static int setipcpaccl __ARGS((void));
+static int setipcpaccr __ARGS((void));
+
+static int number_option __ARGS((char *, long *, int));
+
+
+/*
+ * Option variables
+ */
+extern char *progname;
+extern int debug;
+extern int modem;
+extern int crtscts;
+extern int nodetach;
+extern char *connector;
+extern int inspeed;
+extern char devname[];
+extern int default_device;
+extern u_long netmask;
+extern int detach;
+extern char user[];
+extern char passwd[];
+extern int auth_required;
+extern int proxyarp;
+extern int persist;
+extern int uselogin;
+extern char our_name[];
+extern char remote_name[];
+int usehostname;
+int disable_defaultip;
+
+/*
+ * Valid arguments.
+ */
+static struct cmd {
+ char *cmd_name;
+ int num_args;
+ int (*cmd_func)();
+} cmds[] = {
+ "-all", 0, noopt, /* Don't request/allow any options */
+ "-ac", 0, noaccomp, /* Disable Address/Control compress */
+ "-am", 0, noasyncmap, /* Disable asyncmap negotiation */
+ "-as", 1, setasyncmap, /* set the desired async map */
+ "-d", 0, setdebug, /* Increase debugging level */
+ "-detach", 0, setnodetach, /* don't fork */
+ "-ip", 0, noipaddr, /* Disable IP address negotiation */
+ "-mn", 0, nomagicnumber, /* Disable magic number negotiation */
+ "-mru", 0, nomru, /* Disable mru negotiation */
+ "-p", 0, setpassive, /* Set passive mode */
+ "-pc", 0, nopcomp, /* Disable protocol field compress */
+ "+ua", 1, setupapfile, /* Get PAP user and password from file */
+ "+pap", 0, reqpap, /* Require PAP auth from peer */
+ "-pap", 0, nopap, /* Don't allow UPAP authentication with peer */
+ "+chap", 0, reqchap, /* Require CHAP authentication from peer */
+ "-chap", 0, nochap, /* Don't allow CHAP authentication with peer */
+ "-vj", 0, setnovj, /* disable VJ compression */
+ "asyncmap", 1, setasyncmap, /* set the desired async map */
+ "connect", 1, setconnector, /* A program to set up a connection */
+ "crtscts", 0, setcrtscts, /* set h/w flow control */
+ "debug", 0, setdebug, /* Increase debugging level */
+ "domain", 1, setdomain, /* Add given domain name to hostname*/
+ "mru", 1, setmru, /* Set MRU value for negotiation */
+ "netmask", 1, setnetmask, /* set netmask */
+ "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 */
+ "name", 1, setname, /* Set local name for authentication */
+ "user", 1, setuser, /* Set username for PAP 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 */
+ "file", 1, readfile, /* Take options from a file */
+ "defaultroute", 0, setdefaultroute, /* Add default route */
+ "proxyarp", 0, setproxyarp, /* Add proxy ARP entry */
+ "persist", 0, setpersist, /* Keep on reopening connection after close */
+ "login", 0, setdologin, /* Use system password database for UPAP */
+ "noipdefault", 0, setnoipdflt, /* Don't use name for default IP adrs */
+ "lcp-restart", 1, setlcptimeout, /* Set timeout for LCP */
+ "lcp-max-terminate", 1, setlcpterm, /* Set max #xmits for term-reqs */
+ "lcp-max-configure", 1, setlcpconf, /* Set max #xmits for conf-reqs */
+ "lcp-max-failure", 1, setlcpfails, /* Set max #conf-naks for LCP */
+ "ipcp-restart", 1, setipcptimeout, /* Set timeout for IPCP */
+ "ipcp-max-terminate", 1, setipcpterm, /* Set max #xmits for term-reqs */
+ "ipcp-max-configure", 1, setipcpconf, /* Set max #xmits for conf-reqs */
+ "ipcp-max-failure", 1, setipcpfails, /* Set max #conf-naks for IPCP */
+ "pap-restart", 1, setpaptimeout, /* Set timeout for UPAP */
+ "pap-max-authreq", 1, setpapreqs, /* Set max #xmits for auth-reqs */
+ "chap-restart", 1, setchaptimeout, /* Set timeout for CHAP */
+ "chap-max-challenge", 1, setchapchal, /* Set max #xmits for challenge */
+ "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 */
+ NULL
+};
+
+
+static char *usage_string = "\
+pppd version %s patch level %d\n\
+Usage: %s [ arguments ], where arguments 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\
+ addresses. Either one may be omitted.\n\
+ asyncmap <n> Set the desired async map to hex <n>\n\
+ auth Require authentication from peer\n\
+ connect <p> Invoke shell command <p> to set up the serial line\n\
+ crtscts Use hardware RTS/CTS flow control\n\
+ defaultroute Add default route through interface\n\
+ file <f> Take options from file <f>\n\
+ modem Use modem control lines\n\
+ mru <n> Set MRU value to <n> for negotiation\n\
+ netmask <n> Set interface netmask to <n>\n\
+See pppd(8) for more options.\n\
+";
+
+/*
+Options omitted:
+ -all Don't request/allow any options\n\
+ -ac Disable Address/Control compression\n\
+ -am Disable asyncmap negotiation\n\
+ -as <n> Set the desired async map to hex <n>\n\
+ -d Increase debugging level\n\
+ -detach Don't fork to background\n\
+ -ip Disable IP address negotiation\n\
+ -mn Disable magic number negotiation\n\
+ -mru Disable mru negotiation\n\
+ -p Set passive mode\n\
+ -pc Disable protocol field compression\n\
+ +ua <f> Get username and password for authenticating\n\
+ with peer using PAP from file <f>\n\
+ +pap Require PAP authentication from peer\n\
+ -pap Don't agree to authenticating with peer using PAP\n\
+ +chap Require CHAP authentication from peer\n\
+ -chap Don't agree to authenticating with peer using CHAP\n\
+ -vj disable VJ compression\n\
+ -auth Don't agree to authenticate with peer\n\
+ debug Increase debugging level\n\
+ domain <d> Append domain name <d> to hostname for authentication\n\
+ passive Set passive mode\n\
+ local Don't use modem control lines\n\
+ proxyarp Add proxy ARP entry\n\
+*/
+
+
+/*
+ * parse_args - parse a string of arguments, from the command
+ * line or from a file.
+ */
+int
+parse_args(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *arg, *val;
+ struct cmd *cmdp;
+
+ while (argc > 0) {
+ arg = *argv++;
+ --argc;
+
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(arg, cmdp->cmd_name))
+ break;
+
+ if (cmdp->cmd_name != NULL) {
+ if (argc < cmdp->num_args) {
+ fprintf(stderr, "Too few parameters for command %s\n", arg);
+ return 0;
+ }
+ if (!(*cmdp->cmd_func)(argv))
+ return 0;
+ argc -= cmdp->num_args;
+ argv += cmdp->num_args;
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if (!setdevname(arg) && !setspeed(arg) && !setipaddr(arg)) {
+ fprintf(stderr, "%s: unrecognized command\n", arg);
+ usage();
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ * usage - print out a message telling how to use the program.
+ */
+usage()
+{
+ fprintf(stderr, usage_string, VERSION, PATCHLEVEL, progname);
+}
+
+/*
+ * options_from_file - Read a string of options from a file,
+ * and interpret them.
+ */
+int
+options_from_file(filename, must_exist)
+ char *filename;
+ int must_exist;
+{
+ FILE *f;
+ int i, newline;
+ struct cmd *cmdp;
+ char *argv[MAXARGS];
+ char args[MAXARGS][MAXWORDLEN];
+ char cmd[MAXWORDLEN];
+
+ if ((f = fopen(filename, "r")) == NULL) {
+ if (!must_exist && errno == ENOENT)
+ return 1;
+ perror(filename);
+ exit(1);
+ }
+ while (getword(f, cmd, &newline, filename)) {
+ /*
+ * First see if it's a command.
+ */
+ for (cmdp = cmds; cmdp->cmd_name; cmdp++)
+ if (!strcmp(cmd, cmdp->cmd_name))
+ break;
+
+ 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;
+ }
+ argv[i] = args[i];
+ }
+ if (!(*cmdp->cmd_func)(argv)) {
+ fclose(f);
+ return 0;
+ }
+
+ } else {
+ /*
+ * Maybe a tty name, speed or IP address?
+ */
+ if (!setdevname(cmd) && !setspeed(cmd) && !setipaddr(cmd)) {
+ fprintf(stderr, "In file %s: unrecognized command %s\n",
+ filename, cmd);
+ fclose(f);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/*
+ * options_from_user - See if the use has a ~/.ppprc file,
+ * and if so, interpret options from it.
+ */
+int
+options_from_user()
+{
+ char *user, *path, *file;
+ int ret;
+
+ if ((user = getenv("HOME")) == NULL)
+ return;
+ file = "/.ppprc";
+ path = malloc(strlen(user) + strlen(file) + 1);
+ if (path == NULL)
+ novm("init file name");
+ strcpy(path, user);
+ strcat(path, file);
+ ret = options_from_file(path, 0);
+ free(path);
+ return ret;
+}
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (").
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> is ignored.
+ */
+int
+getword(f, word, newlinep, filename)
+ FILE *f;
+ char *word;
+ int *newlinep;
+ char *filename;
+{
+ int c, len, escape;
+ int quoted;
+
+ *newlinep = 0;
+ len = 0;
+ escape = 0;
+ quoted = 0;
+
+ /*
+ * First skip white-space and comments
+ */
+ while ((c = getc(f)) != EOF) {
+ if (c == '\\') {
+ /*
+ * \<newline> is ignored; \ followed by anything else
+ * starts a word.
+ */
+ if ((c = getc(f)) == '\n')
+ continue;
+ word[len++] = '\\';
+ escape = 1;
+ break;
+ }
+ if (c == '\n')
+ *newlinep = 1; /* next word starts a line */
+ else if (c == '#') {
+ /* comment - ignore until EOF or \n */
+ while ((c = getc(f)) != EOF && c != '\n')
+ ;
+ if (c == EOF)
+ break;
+ *newlinep = 1;
+ } else if (!isspace(c))
+ break;
+ }
+
+ /*
+ * End of file or error - fail
+ */
+ if (c == EOF) {
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+ return 0;
+ }
+
+ for (;;) {
+ /*
+ * Is this character escaped by \ ?
+ */
+ if (escape) {
+ if (c == '\n')
+ --len; /* ignore \<newline> */
+ else if (c == '"' || isspace(c) || c == '\\')
+ word[len-1] = c; /* put special char in word */
+ else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ }
+ escape = 0;
+ } else if (c == '"') {
+ quoted = !quoted;
+ } else if (!quoted && (isspace(c) || c == '#')) {
+ ungetc(c, f);
+ break;
+ } else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ if (c == '\\')
+ escape = 1;
+ }
+ if ((c = getc(f)) == EOF)
+ break;
+ }
+
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+
+ if (len >= MAXWORDLEN) {
+ word[MAXWORDLEN-1] = 0;
+ fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
+ progname, filename, word);
+ } else
+ word[len] = 0;
+
+ return 1;
+}
+
+/*
+ * number_option - parse a numeric parameter for an option
+ */
+static int
+number_option(str, valp, base)
+ char *str;
+ long *valp;
+ int base;
+{
+ char *ptr;
+
+ *valp = strtol(str, &ptr, base);
+ if (ptr == str) {
+ fprintf(stderr, "%s: invalid number: %s\n", progname, str);
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * int_option - like number_option, but valp is int *,
+ * the base is assumed to be 0, and *valp is not changed
+ * if there is an error.
+ */
+static int
+int_option(str, valp)
+ char *str;
+ int *valp;
+{
+ long v;
+
+ if (!number_option(str, &v, 0))
+ return 0;
+ *valp = (int) v;
+ return 1;
+}
+
+
+/*
+ * The following procedures execute commands.
+ */
+
+/*
+ * readfile - take commands from a file.
+ */
+static int
+readfile(argv)
+ char **argv;
+{
+ return options_from_file(*argv, 1);
+}
+
+/*
+ * setdebug - Set debug (command line argument).
+ */
+static int
+setdebug()
+{
+ debug++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ return (1);
+}
+
+/*
+ * noopt - Disable all options.
+ */
+static int
+noopt()
+{
+ 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));
+ return (1);
+}
+
+/*
+ * noaccomp - Disable Address/Control field compression negotiation.
+ */
+static int
+noaccomp()
+{
+ lcp_wantoptions[0].neg_accompression = 0;
+ lcp_allowoptions[0].neg_accompression = 0;
+ return (1);
+}
+
+
+/*
+ * noasyncmap - Disable async map negotiation.
+ */
+static int
+noasyncmap()
+{
+ lcp_wantoptions[0].neg_asyncmap = 0;
+ lcp_allowoptions[0].neg_asyncmap = 0;
+ return (1);
+}
+
+
+/*
+ * noipaddr - Disable IP address negotiation.
+ */
+static int
+noipaddr()
+{
+ ipcp_wantoptions[0].neg_addr = 0;
+ ipcp_allowoptions[0].neg_addr = 0;
+ return (1);
+}
+
+
+/*
+ * nomagicnumber - Disable magic number negotiation.
+ */
+static int
+nomagicnumber()
+{
+ lcp_wantoptions[0].neg_magicnumber = 0;
+ lcp_allowoptions[0].neg_magicnumber = 0;
+ return (1);
+}
+
+
+/*
+ * nomru - Disable mru negotiation.
+ */
+static int
+nomru()
+{
+ lcp_wantoptions[0].neg_mru = 0;
+ lcp_allowoptions[0].neg_mru = 0;
+ return (1);
+}
+
+
+/*
+ * setmru - Set MRU for negotiation.
+ */
+static int
+setmru(argv)
+ char **argv;
+{
+ long mru;
+
+ if (!number_option(*argv, &mru, 0))
+ return 0;
+ lcp_wantoptions[0].mru = mru;
+ lcp_wantoptions[0].neg_mru = 1;
+ return (1);
+}
+
+
+/*
+ * nopcomp - Disable Protocol field compression negotiation.
+ */
+static int
+nopcomp()
+{
+ lcp_wantoptions[0].neg_pcompression = 0;
+ lcp_allowoptions[0].neg_pcompression = 0;
+ return (1);
+}
+
+
+/*
+ * setpassive - Set passive mode (don't give up if we time out sending
+ * LCP configure-requests).
+ */
+static int
+setpassive()
+{
+ lcp_wantoptions[0].passive = 1;
+ return (1);
+}
+
+
+/*
+ * setsilent - Set silent mode (don't start sending LCP configure-requests
+ * until we get one from the peer).
+ */
+static int
+setsilent()
+{
+ lcp_wantoptions[0].silent = 1;
+ return 1;
+}
+
+
+/*
+ * nopap - Disable PAP authentication with peer.
+ */
+static int
+nopap()
+{
+ lcp_allowoptions[0].neg_upap = 0;
+ return (1);
+}
+
+
+/*
+ * reqpap - Require PAP authentication from peer.
+ */
+static int
+reqpap()
+{
+ lcp_wantoptions[0].neg_upap = 1;
+ auth_required = 1;
+}
+
+
+/*
+ * setupapfile - specifies UPAP info for authenticating with peer.
+ */
+static int
+setupapfile(argv)
+ char **argv;
+{
+ FILE * ufile;
+ int l;
+
+ lcp_allowoptions[0].neg_upap = 1;
+
+ /* open user info file */
+ if ((ufile = fopen(*argv, "r")) == NULL) {
+ fprintf(stderr, "unable to open user login data file %s\n", *argv);
+ exit(1);
+ }
+ check_access(ufile, *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);
+ exit(2);
+ }
+ fclose(ufile);
+
+ /* get rid of newlines */
+ l = strlen(user);
+ if (l > 0 && user[l-1] == '\n')
+ user[l-1] = 0;
+ l = strlen(passwd);
+ if (l > 0 && passwd[l-1] == '\n')
+ passwd[l-1] = 0;
+
+ return (1);
+}
+
+
+/*
+ * nochap - Disable CHAP authentication with peer.
+ */
+static int
+nochap()
+{
+ lcp_allowoptions[0].neg_chap = 0;
+ return (1);
+}
+
+
+/*
+ * reqchap - Require CHAP authentication from peer.
+ */
+static int
+reqchap()
+{
+ lcp_wantoptions[0].neg_chap = 1;
+ auth_required = 1;
+ return (1);
+}
+
+
+/*
+ * setnovj - diable vj compression
+ */
+static int
+setnovj()
+{
+ ipcp_wantoptions[0].neg_vj = 0;
+ ipcp_allowoptions[0].neg_vj = 0;
+ return (1);
+}
+
+/*
+ * setconnector - Set a program to connect to a serial line
+ */
+static int
+setconnector(argv)
+ char **argv;
+{
+ connector = strdup(*argv);
+ if (connector == NULL)
+ novm("connector string");
+
+ return (1);
+}
+
+
+/*
+ * setdomain - Set domain name to append to hostname
+ */
+static int
+setdomain(argv)
+ char **argv;
+{
+ strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
+ hostname[MAXNAMELEN-1] = 0;
+ return (1);
+}
+
+static int
+setasyncmap(argv)
+ char **argv;
+{
+ long asyncmap;
+
+ if (!number_option(*argv, &asyncmap, 16))
+ return 0;
+ lcp_wantoptions[0].asyncmap |= asyncmap;
+ lcp_wantoptions[0].neg_asyncmap = 1;
+ return(1);
+}
+
+/*
+ * setspeed - Set the speed.
+ */
+static int
+setspeed(arg)
+ char *arg;
+{
+ char *ptr;
+ int spd;
+
+ spd = strtol(arg, &ptr, 0);
+ if (ptr == arg || *ptr != 0 || spd == 0)
+ return 0;
+ inspeed = spd;
+ return 1;
+}
+
+
+/*
+ * setdevname - Set the device name.
+ */
+int
+setdevname(cp)
+ char *cp;
+{
+ struct stat statbuf;
+ char *tty, *ttyname();
+ char dev[MAXPATHLEN];
+
+ if (strncmp("/dev/", cp, 5) != 0) {
+ strcpy(dev, "/dev/");
+ strncat(dev, cp, MAXPATHLEN - 5);
+ dev[MAXPATHLEN-1] = 0;
+ cp = dev;
+ }
+
+ /*
+ * Check if there is a device by this name.
+ */
+ if (stat(cp, &statbuf) < 0) {
+ if (errno == ENOENT)
+ return (0);
+ syslog(LOG_ERR, cp);
+ exit(1);
+ }
+
+ (void) strncpy(devname, cp, MAXPATHLEN);
+ devname[MAXPATHLEN-1] = 0;
+ default_device = FALSE;
+
+ return (1);
+}
+
+
+/*
+ * setipaddr - Set the IP address
+ */
+int
+setipaddr(arg)
+ char *arg;
+{
+ struct hostent *hp;
+ char *colon, *index();
+ u_long local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = index(arg, ':')) == NULL)
+ return (0);
+
+ /*
+ * If colon first character, then no local addr.
+ */
+ if (colon != arg) {
+ *colon = '\0';
+ if ((local = inet_addr(arg)) == -1) {
+ if ((hp = gethostbyname(arg)) == NULL) {
+ fprintf(stderr, "unknown host: %s", arg);
+ local = 0;
+ } else {
+ local = *(long *)hp->h_addr;
+ if (our_name[0] == 0) {
+ strncpy(our_name, arg, MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (local != 0)
+ wo->ouraddr = local;
+ *colon = ':';
+ }
+
+ /*
+ * If colon last character, then no remote addr.
+ */
+ if (*++colon != '\0') {
+ if ((remote = inet_addr(colon)) == -1) {
+ if ((hp = gethostbyname(colon)) == NULL) {
+ fprintf(stderr, "unknown host: %s", colon);
+ remote = 0;
+ } else {
+ remote = *(long *)hp->h_addr;
+ if (remote_name[0] == 0) {
+ strncpy(remote_name, colon, MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ }
+ }
+ }
+ if (remote != 0)
+ wo->hisaddr = remote;
+ }
+
+ return (1);
+}
+
+
+/*
+ * setnoipdflt - disable setipdefault()
+ */
+static int
+setnoipdflt()
+{
+ disable_defaultip = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccl - accept peer's idea of our address
+ */
+static int
+setipcpaccl()
+{
+ ipcp_wantoptions[0].accept_local = 1;
+ return 1;
+}
+
+
+/*
+ * setipcpaccr - accept peer's idea of its address
+ */
+static int
+setipcpaccr()
+{
+ ipcp_wantoptions[0].accept_remote = 1;
+ return 1;
+}
+
+
+/*
+ * setipdefault - default our local IP address based on our hostname.
+ */
+void
+setipdefault()
+{
+ struct hostent *hp;
+ u_long 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 = *(long *)hp->h_addr;
+ if (local != 0)
+ wo->ouraddr = local;
+}
+
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(argv)
+ char **argv;
+{
+ u_long mask;
+
+ if ((mask = inet_addr(*argv)) == -1) {
+ fprintf(stderr, "Invalid netmask %s\n", *argv);
+ exit(1);
+ }
+
+ netmask = mask;
+ return (1);
+}
+
+static int
+setcrtscts()
+{
+ crtscts = 1;
+ return (1);
+}
+
+static int
+setnodetach()
+{
+ nodetach = 1;
+ return (1);
+}
+
+static int
+setmodem()
+{
+ modem = 1;
+ return 1;
+}
+
+static int
+setlocal()
+{
+ modem = 0;
+ return 1;
+}
+
+static int
+setusehostname()
+{
+ usehostname = 1;
+ return 1;
+}
+
+static int
+setname(argv)
+ char **argv;
+{
+ if (our_name[0] == 0) {
+ strncpy(our_name, argv[0], MAXNAMELEN);
+ our_name[MAXNAMELEN-1] = 0;
+ }
+ return 1;
+}
+
+static int
+setuser(argv)
+ char **argv;
+{
+ strncpy(user, argv[0], MAXNAMELEN);
+ user[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setremote(argv)
+ char **argv;
+{
+ strncpy(remote_name, argv[0], MAXNAMELEN);
+ remote_name[MAXNAMELEN-1] = 0;
+ return 1;
+}
+
+static int
+setauth()
+{
+ auth_required = 1;
+ return 1;
+}
+
+static int
+setdefaultroute()
+{
+ ipcp_wantoptions[0].default_route = 1;
+ return 1;
+}
+
+static int
+setproxyarp()
+{
+ ipcp_wantoptions[0].proxy_arp = 1;
+ return 1;
+}
+
+static int
+setpersist()
+{
+ persist = 1;
+ return 1;
+}
+
+static int
+setdologin()
+{
+ uselogin = 1;
+ return 1;
+}
+
+/*
+ * Functions to set timeouts, max transmits, etc.
+ */
+static int
+setlcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].timeouttime, 0);
+}
+
+static int setlcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxtermtransmits, 0);
+}
+
+static int setlcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxconfreqtransmits, 0);
+}
+
+static int setlcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops, 0);
+}
+
+static int setipcptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].timeouttime, 0);
+}
+
+static int setipcpterm(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxtermtransmits, 0);
+}
+
+static int setipcpconf(argv)
+ char **argv;
+{
+ return int_option(*argv, &ipcp_fsm[0].maxconfreqtransmits, 0);
+}
+
+static int setipcpfails(argv)
+ char **argv;
+{
+ return int_option(*argv, &lcp_fsm[0].maxnakloops, 0);
+}
+
+static int setpaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_timeouttime, 0);
+}
+
+static int setpapreqs(argv)
+ char **argv;
+{
+ return int_option(*argv, &upap[0].us_maxtransmits, 0);
+}
+
+static int setchaptimeout(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].timeouttime, 0);
+}
+
+static int setchapchal(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].max_transmits, 0);
+}
+
+static int setchapintv(argv)
+ char **argv;
+{
+ return int_option(*argv, &chap[0].chal_interval, 0);
+}
diff --git a/libexec/pppd/patchlevel.h b/libexec/pppd/patchlevel.h
index 3c62d5286095..bcfe48398036 100644
--- a/libexec/pppd/patchlevel.h
+++ b/libexec/pppd/patchlevel.h
@@ -1,4 +1,5 @@
-#define PATCHLEVEL 0
+/* $Id: patchlevel.h,v 1.2 1994/03/30 09:31:38 jkh Exp $ */
+#define PATCHLEVEL 4
-#define VERSION "1.3"
-#define DATE "17 Jun 93"
+#define VERSION "2.0"
+#define DATE "9 Feb 94"
diff --git a/libexec/pppd/pathnames.h b/libexec/pppd/pathnames.h
index dac7cd94c54b..81ddeb1e73d4 100644
--- a/libexec/pppd/pathnames.h
+++ b/libexec/pppd/pathnames.h
@@ -1,11 +1,15 @@
-
/*
* define path names
+ *
+ * $Id: pathnames.h,v 1.2 1994/03/30 09:31:39 jkh Exp $
*/
-#define PPPHOSTS "/etc/ppp/hosts"
-
-#define _PATH_DEBUG "/usr/tmp/"
+#ifdef STREAMS
#define _PATH_PIDFILE "/etc/ppp"
-#define _PATH_UPAPFILE "/etc/ppp/upap"
-#define _PATH_CHAPFILE "/etc/ppp/chap"
+#else
+#define _PATH_PIDFILE "/var/run"
+#endif
+
+#define _PATH_UPAPFILE "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS "/etc/ppp/options"
diff --git a/libexec/pppd/ppp.h b/libexec/pppd/ppp.h
new file mode 100644
index 000000000000..f3615a756c7a
--- /dev/null
+++ b/libexec/pppd/ppp.h
@@ -0,0 +1,41 @@
+/*
+ * ppp.h - PPP global declarations.
+ *
+ * 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: ppp.h,v 1.1 1994/03/30 09:38:17 jkh Exp $
+ */
+
+#ifndef __PPP_H__
+#define __PPP_H__
+
+#define _NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Data Link Layer header = Address, Control, Protocol.
+ */
+#define ALLSTATIONS 0xff /* All-Stations Address */
+#define UI 0x03 /* Unnumbered Information */
+#define LCP 0xc021 /* Link Control Protocol */
+#define IPCP 0x8021 /* IP Control Protocol */
+#define UPAP 0xc023 /* User/Password Authentication Protocol */
+#define CHAP 0xc223 /* Crytpographic Handshake Protocol */
+#define LQR 0xc025 /* Link Quality Report protocol */
+#define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */
+#define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+#define MTU 1500 /* Default MTU */
+
+#endif /* __PPP_H__ */
diff --git a/libexec/pppd/pppd.8 b/libexec/pppd/pppd.8
index d64c26f40b11..1bc47df2f64e 100644
--- a/libexec/pppd/pppd.8
+++ b/libexec/pppd/pppd.8
@@ -1,5 +1,5 @@
.\" manual page [] for pppd 2.0
-.\" $Id: pppd.8,v 1.1.2.1 1994/05/01 16:06:43 jkh Exp $
+.\" $Id: pppd.8,v 1.3 1994/04/24 01:22:02 jkh Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
diff --git a/libexec/pppd/pppd.h b/libexec/pppd/pppd.h
index 2a114390e2c2..1cecd3555062 100644
--- a/libexec/pppd/pppd.h
+++ b/libexec/pppd/pppd.h
@@ -15,6 +15,8 @@
* 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: pppd.h,v 1.3 1994/03/30 09:38:17 jkh Exp $
*/
/*
@@ -24,30 +26,41 @@
#ifndef __PPPD_H__
#define __PPPD_H__
#include "args.h"
-#define NPPP 1 /* One PPP interface supported (per process) */
+
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+
+#define _NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Limits.
+ */
+#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 */
+#define MAXSECRETLEN 256 /* max length of password or secret */
extern int debug; /* Debug flag */
+extern int ifunit; /* Interface unit number */
extern char ifname[]; /* Interface name */
extern int fd; /* Device file descriptor */
extern int s; /* socket descriptor */
extern char hostname[]; /* hostname */
-extern u_char hostname_len; /* and its length */
extern u_char outpacket_buf[]; /* buffer for outgoing packets */
-#define MAX_HOSTNAME_LEN 128 /* should be 255 - MAX_CHALLENGE_LEN + 1 */
-
-void quit __ARGS((void)); /* Cleanup and exit */
+void quit __ARGS((void)); /* Cleanup and exit */
void timeout __ARGS((void (*)(), caddr_t, int));
- /* Look-alike of kernel's timeout() */
+ /* Look-alike of kernel's timeout() */
void untimeout __ARGS((void (*)(), caddr_t));
- /* Look-alike of kernel's untimeout() */
-void output __ARGS((int, u_char *, int)); /* Output a PPP packet */
-void demuxprotrej __ARGS((int, int)); /* Demultiplex a Protocol-Reject */
-u_char login __ARGS((char *, int, char *, int, char **, int *)); /* Login user */
-void logout __ARGS((void)); /* Logout user */
-void get_secret __ARGS((u_char *, u_char *, int *)); /* get "secret" for chap */
+ /* Look-alike of kernel's untimeout() */
+void output __ARGS((int, u_char *, int));
+ /* Output a PPP packet */
+void demuxprotrej __ARGS((int, int));
+ /* Demultiplex a Protocol-Reject */
+int check_passwd __ARGS((int, char *, int, char *, int, char **, int *));
+ /* Check peer-supplied username/password */
+int get_secret __ARGS((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
u_long GetMask __ARGS((u_long)); /* get netmask for address */
-extern int errno;
/*
@@ -93,293 +106,35 @@ extern int errno;
* System dependent definitions for user-level 4.3BSD UNIX implementation.
*/
-#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
+#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
-#define TIMEOUT(r, f, t) timeout((r), (f), (t))
-#define UNTIMEOUT(r, f) untimeout((r), (f))
+#define TIMEOUT(r, f, t) timeout((r), (f), (t))
+#define UNTIMEOUT(r, f) untimeout((r), (f))
-#define BCOPY(s, d, l) bcopy(s, d, l)
-#define EXIT(u) quit()
+#define BCOPY(s, d, l) memcpy(d, s, l)
+#define BZERO(s, n) memset(s, 0, n)
+#define EXIT(u) quit()
-#define GETUSERPASSWD(u)
-#define LOGIN(n, u, ul, p, pl, m, ml) login(u, ul, p, pl, m, ml);
-#define LOGOUT(n) logout()
-#define GETSECRET(n, s, sl) get_secret(n, s, sl)
#define PRINTMSG(m, l) { m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); }
/*
- * return a pointer to the beginning of the data part of a packet.
- */
-
-#define PACKET_DATA(p) (p + DLLHEADERLEN)
-
-/*
- * MAKEHEADER - Add Header fields to a packet. (Should we do
- * AC compression here?)
+ * MAKEHEADER - Add Header fields to a packet.
*/
#define MAKEHEADER(p, t) { \
PUTCHAR(ALLSTATIONS, p); \
PUTCHAR(UI, p); \
PUTSHORT(t, p); }
-/*
- * SIFASYNCMAP - Config the interface async map.
- */
-#ifdef STREAMS
-#define SIFASYNCMAP(u, a) { \
- u_long x = a; \
- if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m"); \
- } }
-#else
-#define SIFASYNCMAP(u, a) { \
- u_long x = a; \
- if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * SIFPCOMPRESSION - Config the interface for protocol compression.
- */
-#ifdef STREAMS
-#define SIFPCOMPRESSION(u) { \
- char c = 1; \
- if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); \
- }}
-#else
-#define SIFPCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x |= SC_COMP_PROT; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * CIFPCOMPRESSION - Config the interface for no protocol compression.
- */
-#ifdef STREAMS
-#define CIFPCOMPRESSION(u) { \
- char c = 0; \
- if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m"); \
- quit(); \
- }}
-#else
-#define CIFPCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x &= ~SC_COMP_PROT; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-/*
- * SIFACCOMPRESSION - Config the interface for address/control compression.
- */
-#ifdef STREAMS
-#define SIFACCOMPRESSION(u) { \
- char c = 1; \
- if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); \
- quit(); \
- }}
-#else
-#define SIFACCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x |= SC_COMP_AC; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * CIFACCOMPRESSION - Config the interface for no address/control compression.
- */
-#ifdef STREAMS
-#define CIFACCOMPRESSION(u) { \
- char c = 0; \
- if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m"); \
- quit(); \
- }}
-#else
-#define CIFACCOMPRESSION(u) { \
- u_int x; \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x &= ~SC_COMP_AC; \
- if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
+#ifdef DEBUGALL
+#define DEBUGMAIN 1
+#define DEBUGFSM 1
+#define DEBUGLCP 1
+#define DEBUGIPCP 1
+#define DEBUGUPAP 1
+#define DEBUGCHAP 1
#endif
-/*
- * SIFVJCOMP - config tcp header compression
- */
-#ifdef STREAMS
-#define SIFVJCOMP(u, a) { \
- char x = a; \
- if (debug) syslog(LOG_DEBUG, "SIFVJCOMP unit %d to value %d\n",u,x); \
- if(ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m"); \
- quit(); \
- } \
-}
-#else
-#define SIFVJCOMP(u, a) { \
- u_int x; \
- if (debug) \
- syslog(LOG_DEBUG, "PPPIOCSFLAGS unit %d set %s\n",u,a?"on":"off"); \
- if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m"); \
- quit(); \
- } \
- x = (x & ~SC_COMP_TCP) | ((a) ? SC_COMP_TCP : 0); \
- if(ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) { \
- syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m"); \
- quit(); \
- } }
-#endif
-
-/*
- * SIFUP - Config the interface up.
- */
-#define SIFUP(u) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); \
- quit(); \
- } \
- ifr.ifr_flags |= IFF_UP; \
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); \
- quit(); \
- } }
-
-/*
- * SIFDOWN - Config the interface down.
- */
-#define SIFDOWN(u) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m"); \
- quit(); \
- } \
- ifr.ifr_flags &= ~IFF_UP; \
- if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m"); \
- quit(); \
- } }
-
-/*
- * SIFMTU - Config the interface MTU.
- */
-#define SIFMTU(u, m) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- ifr.ifr_mtu = m; \
- if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m"); \
- quit(); \
- } }
-
-
-#ifdef __386BSD__ /* BSD >= 44 ? */
-#define SET_SA_FAMILY(addr, family) \
- bzero((char *) &(addr), sizeof(addr)); \
- addr.sa_family = (family); \
- addr.sa_len = sizeof(addr);
-#else
-#define SET_SA_FAMILY(addr, family) \
- bzero((char *) &(addr), sizeof(addr)); \
- addr.sa_family = (family);
-#endif
-
-/*
- * SIFADDR - Config the interface IP addresses.
- */
-#define SIFADDR(u, o, h) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- SET_SA_FAMILY(ifr.ifr_addr, AF_INET); \
- ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o; \
- if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); \
- } \
- ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h; \
- if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m"); \
- quit(); \
- } }
-
-/*
- * CIFADDR - Clear the interface IP addresses.
- */
-#if BSD > 43
-#define CIFADDR(u, o, h) { \
- struct ortentry rt; \
- SET_SA_FAMILY(rt.rt_dst, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; \
- SET_SA_FAMILY(rt.rt_gateway, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; \
- rt.rt_flags |= RTF_HOST; \
- syslog(LOG_INFO, "Deleting host route from %s to %s\n", \
- ip_ntoa(h), ip_ntoa(o)); \
- if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); \
- } }
-#else
-#define CIFADDR(u, o, h) { \
- struct rtentry rt; \
- SET_SA_FAMILY(rt.rt_dst, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h; \
- SET_SA_FAMILY(rt.rt_gateway, AF_INET); \
- ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o; \
- rt.rt_flags |= RTF_HOST; \
- syslog(LOG_INFO, "Deleting host route from %s to %s\n", \
- ip_ntoa(h), ip_ntoa(o)); \
- if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCDELRT): %m"); \
- } }
-#endif
-
-/*
- * SIFMASK - Config the interface net mask
- */
-#define SIFMASK(u, m) { \
- struct ifreq ifr; \
- strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); \
- SET_SA_FAMILY(ifr.ifr_addr, AF_INET); \
- ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m; \
- syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m)); \
- if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) { \
- syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m"); \
- } }
-
#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
|| defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
@@ -391,37 +146,37 @@ extern int errno;
#endif /* LOG_PPP */
#ifdef DEBUGMAIN
-#define MAINDEBUG(x) if (debug) syslog x;
+#define MAINDEBUG(x) if (debug) syslog x
#else
#define MAINDEBUG(x)
#endif
#ifdef DEBUGFSM
-#define FSMDEBUG(x) if (debug) syslog x;
+#define FSMDEBUG(x) if (debug) syslog x
#else
#define FSMDEBUG(x)
#endif
#ifdef DEBUGLCP
-#define LCPDEBUG(x) if (debug) syslog x;
+#define LCPDEBUG(x) if (debug) syslog x
#else
#define LCPDEBUG(x)
#endif
#ifdef DEBUGIPCP
-#define IPCPDEBUG(x) if (debug) syslog x;
+#define IPCPDEBUG(x) if (debug) syslog x
#else
#define IPCPDEBUG(x)
#endif
#ifdef DEBUGUPAP
-#define UPAPDEBUG(x) if (debug) syslog x;
+#define UPAPDEBUG(x) if (debug) syslog x
#else
#define UPAPDEBUG(x)
#endif
#ifdef DEBUGCHAP
-#define CHAPDEBUG(x) if (debug) syslog x;
+#define CHAPDEBUG(x) if (debug) syslog x
#else
#define CHAPDEBUG(x)
#endif
@@ -433,4 +188,12 @@ extern int errno;
#define SIGTYPE int
#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b) ((a) > (b)? (a): (b))
+#endif
+
#endif /* __PPP_H__ */
diff --git a/libexec/pppd/sys-bsd.c b/libexec/pppd/sys-bsd.c
new file mode 100644
index 000000000000..314af4447ebf
--- /dev/null
+++ b/libexec/pppd/sys-bsd.c
@@ -0,0 +1,503 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: sys-bsd.c,v 1.1 1994/03/30 09:38:18 jkh Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+
+static int initdisc; /* Initial TTY discipline */
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ int pppdisc = PPPDISC;
+
+ if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
+ die(1);
+ }
+ if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ die(1);
+ }
+
+ /*
+ * Find out which interface we were given.
+ */
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die(1);
+ }
+}
+
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ if (ioctl(fd, TIOCSETD, &initdisc) < 0)
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+
+ if (write(fd, p, len) < 0) {
+ syslog(LOG_ERR, "write: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
+ if (errno == EWOULDBLOCK) {
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+ return -1;
+ }
+ syslog(LOG_ERR, "read(fd): %m");
+ die(1);
+ }
+ return len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ u_int x;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(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) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface. At present this does nothing.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+#ifdef notyet
+ if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
+ quit();
+ }
+
+ if (ioctl(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) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+#endif /* notyet */
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp)
+{
+ u_int x;
+
+ if (ioctl(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) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family); \
+ addr.sa_len = sizeof(addr);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ struct ifaliasreq ifra;
+
+ 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;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ if (m != 0) {
+ SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+ } else
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+ if (errno != EEXIST) {
+ syslog(LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ return 0;
+ }
+ syslog(LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct ifaliasreq ifra;
+
+ 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;
+ SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+ ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+ BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+ if (ioctl(s, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDIFADDR): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct ortentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0)
+ syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (ifr->ifr_addr.sa_family == AF_INET) {
+ ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+ /*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on the right subnet.
+ */
+ if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ) {
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+ && ifr->ifr_addr.sa_family == AF_LINK) {
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *)&ifr->ifr_addr;
+ hwaddr->sa_len = sizeof(struct sockaddr);
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY(LLADDR(dla), hwaddr->sa_data, dla->sdl_alen);
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ return 0;
+}
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+
+int
+ppp_available()
+{
+ int s, ok;
+ struct ifreq ifr;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}
diff --git a/libexec/pppd/sys-str.c b/libexec/pppd/sys-str.c
new file mode 100644
index 000000000000..866a61a1738a
--- /dev/null
+++ b/libexec/pppd/sys-str.c
@@ -0,0 +1,643 @@
+/*
+ * sys-str.c - System-dependent procedures for setting up
+ * PPP interfaces on systems which use the STREAMS ppp interface.
+ *
+ * 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.
+ */
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include <net/ppp_str.h>
+
+#ifndef ifr_mtu
+#define ifr_mtu ifr_metric
+#endif
+
+#define MAXMODULES 10 /* max number of module names to save */
+static struct modlist {
+ char modname[FMNAMESZ+1];
+} str_modules[MAXMODULES];
+static int str_module_count = 0;
+
+extern int hungup; /* has the physical layer been disconnected? */
+
+/*
+ * ppp_available - check if this kernel supports PPP.
+ */
+int
+ppp_available()
+{
+ int fd, ret;
+
+ fd = open("/dev/tty", O_RDONLY, 0);
+ if (fd < 0)
+ return 1; /* can't find out - assume we have ppp */
+ ret = ioctl(fd, I_FIND, "pppasync") >= 0;
+ close(fd);
+ return ret;
+}
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ /* go through and save the name of all the modules, then pop em */
+ for (;;) {
+ if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
+ ioctl(fd, I_POP, 0) < 0)
+ break;
+ MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
+ str_modules[str_module_count].modname));
+ str_module_count++;
+ }
+
+ MAINDEBUG((LOG_INFO, "about to push modules..."));
+
+ /* now push the async/fcs module */
+ if (ioctl(fd, I_PUSH, "pppasync") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
+ die(1);
+ }
+ /* finally, push the ppp_if module that actually handles the */
+ /* network interface */
+ if (ioctl(fd, I_PUSH, "pppif") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
+ die(1);
+ }
+ if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
+ die(1);
+ }
+ /* read mode, message non-discard mode */
+ if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
+ die(1);
+ }
+ /* Flush any waiting messages, or we'll never get SIGPOLL */
+ if (ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
+ syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
+ die(1);
+ }
+ /*
+ * Find out which interface we were given.
+ * (ppp_if handles this ioctl)
+ */
+ if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
+ die(1);
+ }
+
+ /* if debug, set debug flags in driver */
+ {
+ int flags = debug ? 0x3 : 0;
+ if (ioctl(fd, SIOCSIFDEBUG, &flags) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
+ }
+ }
+
+ MAINDEBUG((LOG_INFO, "done pushing modules, ifunit %d", ifunit));
+}
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * It attempts to reconstruct the stream with the previously popped
+ * modules. This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ /*EMPTY*/
+
+ if (hungup) {
+ /* we can't push or pop modules after the stream has hung up */
+ str_module_count = 0;
+ return;
+ }
+
+ while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */
+ ;
+
+ for (; str_module_count > 0; str_module_count--) {
+ if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
+ syslog(LOG_ERR, "str_restore: couldn't push module %s: %m",
+ str_modules[str_module_count-1].modname);
+ } else {
+ MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
+ str_modules[str_module_count-1].modname));
+ }
+ }
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ struct strbuf str;
+
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+
+ str.len = len;
+ str.buf = (caddr_t) p;
+ if(putmsg(fd, NULL, &str, 0) < 0) {
+ syslog(LOG_ERR, "putmsg: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ struct strbuf str;
+ int len, i;
+
+ str.maxlen = MTU+DLLHEADERLEN;
+ str.buf = (caddr_t) buf;
+ i = 0;
+ len = getmsg(fd, NULL, &str, &i);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return -1;
+ }
+ syslog(LOG_ERR, "getmsg(fd) %m");
+ die(1);
+ }
+ if (len)
+ MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
+
+ if (str.len < 0) {
+ MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
+ return -1;
+ }
+
+ return str.len;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+ int unit, mtu;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
+ quit();
+ }
+
+ c = pcomp;
+ if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
+ quit();
+ }
+
+ c = accomp;
+ if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
+ quit();
+ }
+}
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface. At present this just sets the MRU.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+ int unit, mru;
+ u_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+
+ if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
+ }
+
+#ifdef notyet
+ if(ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
+ }
+
+ c = accomp;
+ if(ioctl(fd, SIOCSIFRCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFRCOMPAC): %m");
+ quit();
+ }
+#endif /* notyet */
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp)
+{
+ char x = vjcomp;
+
+ if(ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ int ret;
+ struct ifreq ifr;
+
+ ret = 1;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
+ if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
+ ret = 0;
+ }
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
+ if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
+ ret = 0;
+ }
+ if (m != 0) {
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
+ if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
+ rt.rt_flags = RTF_HOST;
+ if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+ if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr. Code borrowed from myetheraddr.c
+ * in the cslip-2.6 distribution, which is subject to the following
+ * copyright notice:
+ *
+ * Copyright (c) 1990, 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may 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
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <fcntl.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <arpa/inet.h>
+
+/* XXX SunOS 4.1 defines this and 3.5 doesn't... */
+#ifdef _nlist_h
+#define SUNOS4
+#endif
+
+#ifdef SUNOS4
+#include <netinet/in_var.h>
+#endif
+#include <netinet/if_ether.h>
+
+/* Cast a struct sockaddr to a structaddr_in */
+#define SATOSIN(sa) ((struct sockaddr_in *)(sa))
+
+/* Determine if "bits" is set in "flag" */
+#define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
+
+static struct nlist nl[] = {
+#define N_IFNET 0
+ { "_ifnet" },
+ 0
+};
+
+static void kread();
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ register kvm_t *kd;
+ register struct ifnet *ifp;
+ register struct arpcom *ac;
+ struct arpcom arpcom;
+ struct in_addr *inp;
+#ifdef SUNOS4
+ register struct ifaddr *ifa;
+ register struct in_ifaddr *in;
+ union {
+ struct ifaddr ifa;
+ struct in_ifaddr in;
+ } ifaddr;
+#endif
+ u_long addr, mask;
+
+ /* Open kernel memory for reading */
+ kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
+ if (kd == 0) {
+ syslog(LOG_ERR, "kvm_open: %m");
+ return 0;
+ }
+
+ /* Fetch namelist */
+ if (kvm_nlist(kd, nl) != 0) {
+ syslog(LOG_ERR, "kvm_nlist failed");
+ return 0;
+ }
+
+ ac = &arpcom;
+ ifp = &arpcom.ac_if;
+#ifdef SUNOS4
+ ifa = &ifaddr.ifa;
+ in = &ifaddr.in;
+#endif
+
+ if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
+ != sizeof(addr)) {
+ syslog(LOG_ERR, "error reading ifnet addr");
+ return 0;
+ }
+ for ( ; addr; addr = (u_long)ifp->if_next) {
+ if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
+ syslog(LOG_ERR, "error reading ifnet");
+ return 0;
+ }
+
+ /* Only look at configured, broadcast interfaces */
+ if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
+ continue;
+#ifdef SUNOS4
+ /* This probably can't happen... */
+ if (ifp->if_addrlist == 0)
+ continue;
+#endif
+
+ /* Get interface ip address */
+#ifdef SUNOS4
+ if (kvm_read(kd, (u_long)ifp->if_addrlist, (char *)&ifaddr,
+ sizeof(ifaddr)) != sizeof(ifaddr)) {
+ syslog(LOG_ERR, "error reading ifaddr");
+ return 0;
+ }
+ inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
+#else
+ inp = &SATOSIN(&ifp->if_addr)->sin_addr;
+#endif
+
+ /* Check if this interface on the right subnet */
+#ifdef SUNOS4
+ mask = in->ia_subnetmask;
+#else
+ mask = ifp->if_subnetmask;
+#endif
+ if ((ipaddr & mask) != (inp->s_addr & mask))
+ continue;
+
+ /* Copy out the local ethernet address */
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
+ sizeof(arpcom.ac_enaddr));
+ return 1; /* success! */
+ }
+
+ /* couldn't find one */
+ return 0;
+}
diff --git a/libexec/pppd/upap.c b/libexec/pppd/upap.c
index a58a01838836..7a9fa1f2db36 100644
--- a/libexec/pppd/upap.c
+++ b/libexec/pppd/upap.c
@@ -17,6 +17,10 @@
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#ifndef lint
+static char rcsid[] = "$Id: upap.c,v 1.3 1994/03/30 09:38:20 jkh Exp $";
+#endif
+
/*
* TODO:
*/
@@ -26,38 +30,28 @@
#include <sys/time.h>
#include <syslog.h>
-#ifdef STREAMS
-#include <sys/socket.h>
-#include <net/if.h>
-#include <sys/stream.h>
-#endif
-
-#include <net/ppp.h>
+#include "ppp.h"
#include "pppd.h"
-#include "fsm.h"
-#include "lcp.h"
#include "upap.h"
-#include "chap.h"
-#include "ipcp.h"
-upap_state upap[NPPP]; /* UPAP state; one for each unit */
+upap_state upap[_NPPP]; /* UPAP state; one for each unit */
static void upap_timeout __ARGS((caddr_t));
-static void upap_rauth __ARGS((upap_state *, u_char *, int, int));
+static void upap_rauthreq __ARGS((upap_state *, u_char *, int, int));
static void upap_rauthack __ARGS((upap_state *, u_char *, int, int));
static void upap_rauthnak __ARGS((upap_state *, u_char *, int, int));
-static void upap_sauth __ARGS((upap_state *));
-static void upap_sresp __ARGS((upap_state *, int, int, u_char *, int));
+static void upap_sauthreq __ARGS((upap_state *));
+static void upap_sresp __ARGS((upap_state *, int, int, char *, int));
/*
* upap_init - Initialize a UPAP unit.
*/
void
- upap_init(unit)
-int unit;
+upap_init(unit)
+ int unit;
{
upap_state *u = &upap[unit];
@@ -66,11 +60,11 @@ int unit;
u->us_userlen = 0;
u->us_passwd = NULL;
u->us_passwdlen = 0;
- u->us_clientstate = UPAPCS_CLOSED;
- u->us_serverstate = UPAPSS_CLOSED;
- u->us_flags = 0;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
u->us_id = 0;
u->us_timeouttime = UPAP_DEFTIMEOUT;
+ u->us_maxtransmits = 10;
}
@@ -80,45 +74,27 @@ int unit;
* Set new state and send authenticate's.
*/
void
- upap_authwithpeer(unit)
-int unit;
+upap_authwithpeer(unit, user, password)
+ int unit;
+ char *user, *password;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_AWPPENDING; /* Clear pending flag */
-
- /* Protect against programming errors that compromise security */
- if (u->us_serverstate != UPAPSS_CLOSED ||
- u->us_flags & UPAPF_APPENDING) {
- UPAPDEBUG((LOG_WARNING,
- "upap_authwithpeer: upap_authpeer already called!"))
+ /* Save the username and password we're given */
+ u->us_user = user;
+ u->us_userlen = strlen(user);
+ u->us_passwd = password;
+ u->us_passwdlen = strlen(password);
+ u->us_transmits = 0;
+
+ /* Lower layer up yet? */
+ if (u->us_clientstate == UPAPCS_INITIAL ||
+ u->us_clientstate == UPAPCS_PENDING) {
+ u->us_clientstate = UPAPCS_PENDING;
return;
}
- /* Already authenticat{ed,ing}? */
- if (u->us_clientstate == UPAPCS_AUTHSENT ||
- u->us_clientstate == UPAPCS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(u->us_flags & UPAPF_LOWERUP)) {
- u->us_flags |= UPAPF_AWPPENDING; /* Wait */
- return;
- }
-
- /* User/passwd values valid? */
- if (!(u->us_flags & UPAPF_UPVALID)) {
- GETUSERPASSWD(unit); /* Start getting user and passwd */
- if (!(u->us_flags & UPAPF_UPVALID)) {
- u->us_flags |= UPAPF_UPPENDING; /* Wait */
- return;
- }
- }
-
- upap_sauth(u); /* Start protocol */
-/* TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);*/
- u->us_clientstate = UPAPCS_AUTHSENT;
- u->us_retransmits = 0;
+ upap_sauthreq(u); /* Start protocol */
}
@@ -128,23 +104,18 @@ int unit;
* Set new state.
*/
void
- upap_authpeer(unit)
-int unit;
+upap_authpeer(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_APPENDING; /* Clear pending flag */
-
- /* Already authenticat{ed,ing}? */
- if (u->us_serverstate == UPAPSS_LISTEN ||
- u->us_serverstate == UPAPSS_OPEN)
- return;
-
- /* Lower layer up? */
- if (!(u->us_flags & UPAPF_LOWERUP)) {
- u->us_flags |= UPAPF_APPENDING; /* Wait for desired event */
+ /* Lower layer up yet? */
+ if (u->us_serverstate == UPAPSS_INITIAL ||
+ u->us_serverstate == UPAPSS_PENDING) {
+ u->us_serverstate = UPAPSS_PENDING;
return;
}
+
u->us_serverstate = UPAPSS_LISTEN;
}
@@ -153,19 +124,23 @@ int unit;
* upap_timeout - Timeout expired.
*/
static void
- upap_timeout(arg)
-caddr_t arg;
+upap_timeout(arg)
+ caddr_t arg;
{
- upap_state *u = (upap_state *) arg;
+ upap_state *u = (upap_state *) arg;
- if (u->us_clientstate != UPAPCS_AUTHSENT)
+ if (u->us_clientstate != UPAPCS_AUTHREQ)
return;
- /* XXX Print warning after many retransmits? */
+ if (u->us_transmits >= u->us_maxtransmits) {
+ /* give up in disgust */
+ syslog(LOG_ERR, "No response to PAP authenticate-requests");
+ u->us_clientstate = UPAPCS_BADAUTH;
+ auth_withpeer_fail(u->us_unit, UPAP);
+ return;
+ }
- upap_sauth(u); /* Send Configure-Request */
- TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
- ++u->us_retransmits;
+ upap_sauthreq(u); /* Send Authenticate-Request */
}
@@ -175,16 +150,21 @@ caddr_t arg;
* Start authenticating if pending.
*/
void
- upap_lowerup(unit)
-int unit;
+upap_lowerup(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags |= UPAPF_LOWERUP;
- if (u->us_flags & UPAPF_AWPPENDING) /* Attempting authwithpeer? */
- upap_authwithpeer(unit); /* Try it now */
- if (u->us_flags & UPAPF_APPENDING) /* Attempting authpeer? */
- upap_authpeer(unit); /* Try it now */
+ if (u->us_clientstate == UPAPCS_INITIAL)
+ u->us_clientstate = UPAPCS_CLOSED;
+ else if (u->us_clientstate == UPAPCS_PENDING) {
+ upap_sauthreq(u); /* send an auth-request */
+ }
+
+ if (u->us_serverstate == UPAPSS_INITIAL)
+ u->us_serverstate = UPAPSS_CLOSED;
+ else if (u->us_serverstate == UPAPSS_PENDING)
+ u->us_serverstate = UPAPSS_LISTEN;
}
@@ -194,20 +174,16 @@ int unit;
* Cancel all timeouts.
*/
void
- upap_lowerdown(unit)
-int unit;
+upap_lowerdown(unit)
+ int unit;
{
upap_state *u = &upap[unit];
- u->us_flags &= ~UPAPF_LOWERUP; /* XXX UPAP_UPVALID? */
-
- if (u->us_clientstate == UPAPCS_AUTHSENT) /* Timeout pending? */
+ if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
- if (u->us_serverstate == UPAPSS_OPEN) /* User logged in? */
- LOGOUT(unit);
- u->us_clientstate = UPAPCS_CLOSED;
- u->us_serverstate = UPAPSS_CLOSED;
+ u->us_clientstate = UPAPCS_INITIAL;
+ u->us_serverstate = UPAPSS_INITIAL;
}
@@ -217,9 +193,19 @@ int unit;
* This shouldn't happen. In any case, pretend lower layer went down.
*/
void
- upap_protrej(unit)
-int unit;
+upap_protrej(unit)
+ int unit;
{
+ upap_state *u = &upap[unit];
+
+ if (u->us_clientstate == UPAPCS_AUTHREQ) {
+ syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
+ auth_withpeer_fail(unit, UPAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(unit, UPAP);
+ }
upap_lowerdown(unit);
}
@@ -228,10 +214,10 @@ int unit;
* upap_input - Input UPAP packet.
*/
void
- upap_input(unit, inpacket, l)
-int unit;
-u_char *inpacket;
-int l;
+upap_input(unit, inpacket, l)
+ int unit;
+ u_char *inpacket;
+ int l;
{
upap_state *u = &upap[unit];
u_char *inp;
@@ -244,18 +230,18 @@ int l;
*/
inp = inpacket;
if (l < UPAP_HEADERLEN) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."))
+ UPAPDEBUG((LOG_INFO, "upap_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, "upap_input: rcvd illegal length."));
return;
}
if (len > l) {
- UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
@@ -264,19 +250,19 @@ int l;
* Action depends on code.
*/
switch (code) {
- case UPAP_AUTH:
- upap_rauth(u, inp, id, len);
+ case UPAP_AUTHREQ:
+ upap_rauthreq(u, inp, id, len);
break;
- case UPAP_AUTHACK:
+ case UPAP_AUTHACK:
upap_rauthack(u, inp, id, len);
break;
- case UPAP_AUTHNAK:
+ case UPAP_AUTHNAK:
upap_rauthnak(u, inp, id, len);
break;
- default: /* XXX Need code reject */
+ default: /* XXX Need code reject */
break;
}
}
@@ -286,58 +272,72 @@ int l;
* upap_rauth - Receive Authenticate.
*/
static void
- upap_rauth(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthreq(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char ruserlen, rpasswdlen;
- u_char *ruser, *rpasswd;
- u_char retcode;
- u_char *msg;
+ char *ruser, *rpasswd;
+ int retcode;
+ char *msg;
int msglen;
- UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id))
- if (u->us_serverstate != UPAPSS_LISTEN) /* XXX Reset connection? */
+ UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
+
+ if (u->us_serverstate < UPAPSS_LISTEN)
return;
/*
+ * If we receive a duplicate authenticate-request, we are
+ * supposed to return the same status as for the first request.
+ */
+ if (u->us_serverstate == UPAPSS_OPEN) {
+ upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
+ return;
+ }
+ if (u->us_serverstate == UPAPSS_BADAUTH) {
+ upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
+ return;
+ }
+
+ /*
* Parse user/passwd.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_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, "upap_rauth: rcvd short packet."));
return;
}
- ruser = inp;
+ ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
- UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
- rpasswd = inp;
+ rpasswd = (char *) inp;
- retcode = LOGIN(u->us_unit, (char *) ruser, (int) ruserlen, (char *) rpasswd,
- (int) rpasswdlen, (char **) &msg, &msglen);
+ /*
+ * Check the username and password given.
+ */
+ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+ rpasswdlen, &msg, &msglen);
upap_sresp(u, retcode, id, msg, msglen);
- /* only crank up IPCP when either we aren't doing CHAP, or if we are, */
- /* that it is in open state */
-
if (retcode == UPAP_AUTHACK) {
u->us_serverstate = UPAPSS_OPEN;
- if (!lcp_hisoptions[u->us_unit].neg_chap ||
- (lcp_hisoptions[u->us_unit].neg_chap &&
- chap[u->us_unit].serverstate == CHAPSS_OPEN))
- ipcp_activeopen(u->us_unit); /* Start IPCP */
+ auth_peer_success(u->us_unit, UPAP);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, UPAP);
}
}
@@ -346,44 +346,38 @@ int len;
* upap_rauthack - Receive Authenticate-Ack.
*/
static void
- upap_rauthack(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthack(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char msglen;
- u_char *msg;
+ char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id))
- if (u->us_clientstate != UPAPCS_AUTHSENT) /* XXX */
+ UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_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, "upap_rauthack: rcvd short packet."));
return;
}
- msg = inp;
+ msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_OPEN;
- /* only crank up IPCP when either we aren't doing CHAP, or if we are, */
- /* that it is in open state */
-
- if (!lcp_gotoptions[u->us_unit].neg_chap ||
- (lcp_gotoptions[u->us_unit].neg_chap &&
- chap[u->us_unit].clientstate == CHAPCS_OPEN))
- ipcp_activeopen(u->us_unit); /* Start IPCP */
+ auth_withpeer_success(u->us_unit, UPAP);
}
@@ -391,47 +385,48 @@ int len;
* upap_rauthnak - Receive Authenticate-Nakk.
*/
static void
- upap_rauthnak(u, inp, id, len)
-upap_state *u;
-u_char *inp;
-u_char id;
-int len;
+upap_rauthnak(u, inp, id, len)
+ upap_state *u;
+ u_char *inp;
+ int id;
+ int len;
{
u_char msglen;
- u_char *msg;
+ char *msg;
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id))
- if (u->us_clientstate != UPAPCS_AUTHSENT) /* XXX */
+ UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
+ if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
return;
/*
* Parse message.
*/
if (len < sizeof (u_char)) {
- UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."))
+ UPAPDEBUG((LOG_INFO, "upap_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, "upap_rauthnak: rcvd short packet."));
return;
}
- msg = inp;
+ msg = (char *) inp;
PRINTMSG(msg, msglen);
- u->us_flags &= ~UPAPF_UPVALID; /* Clear valid flag */
- u->us_clientstate = UPAPCS_CLOSED; /* Pretend for a moment */
- upap_authwithpeer(u->us_unit); /* Restart */
+ u->us_clientstate = UPAPCS_BADAUTH;
+
+ syslog(LOG_ERR, "PAP authentication failed");
+ auth_withpeer_fail(u->us_unit, UPAP);
}
/*
- * upap_sauth - Send an Authenticate.
+ * upap_sauthreq - Send an Authenticate-Request.
*/
static void
- upap_sauth(u)
-upap_state *u;
+upap_sauthreq(u)
+ upap_state *u;
{
u_char *outp;
int outlen;
@@ -442,7 +437,7 @@ upap_state *u;
MAKEHEADER(outp, UPAP);
- PUTCHAR(UPAP_AUTH, outp);
+ PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++u->us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(u->us_userlen, outp);
@@ -450,9 +445,14 @@ upap_state *u;
INCPTR(u->us_userlen, outp);
PUTCHAR(u->us_passwdlen, outp);
BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
- UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id))
+ UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
+
+ TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
+ ++u->us_transmits;
+ u->us_clientstate = UPAPCS_AUTHREQ;
}
@@ -460,11 +460,11 @@ upap_state *u;
* upap_sresp - Send a response (ack or nak).
*/
static void
- upap_sresp(u, code, id, msg, msglen)
-upap_state *u;
-u_char code, id;
-u_char *msg;
-int msglen;
+upap_sresp(u, code, id, msg, msglen)
+ upap_state *u;
+ u_char code, id;
+ char *msg;
+ int msglen;
{
u_char *outp;
int outlen;
@@ -480,5 +480,5 @@ int msglen;
BCOPY(msg, outp, msglen);
output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
- UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id))
+ UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
}
diff --git a/libexec/pppd/upap.h b/libexec/pppd/upap.h
index f25b9487ec5b..7f3b4e9613ca 100644
--- a/libexec/pppd/upap.h
+++ b/libexec/pppd/upap.h
@@ -15,6 +15,8 @@
* 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: upap.h,v 1.2 1994/03/30 09:31:44 jkh Exp $
*/
/*
@@ -26,9 +28,9 @@
/*
* UPAP codes.
*/
-#define UPAP_AUTH 1 /* Authenticate */
-#define UPAP_AUTHACK 2 /* Authenticate Ack */
-#define UPAP_AUTHNAK 3 /* Authenticate Nak */
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
/*
@@ -42,35 +44,32 @@ typedef struct upap_state {
int us_passwdlen; /* Password length */
int us_clientstate; /* Client state */
int us_serverstate; /* Server state */
- int us_flags; /* Flags */
u_char us_id; /* Current id */
int us_timeouttime; /* Timeout time in milliseconds */
- int us_retransmits; /* Number of retransmissions */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
} upap_state;
/*
* Client states.
*/
-#define UPAPCS_CLOSED 1 /* Connection down */
-#define UPAPCS_AUTHSENT 2 /* We've sent an Authenticate */
-#define UPAPCS_OPEN 3 /* We've received an Ack */
+#define UPAPCS_INITIAL 0 /* Connection down */
+#define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN 4 /* We've received an Ack */
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */
/*
* Server states.
*/
-#define UPAPSS_CLOSED 1 /* Connection down */
-#define UPAPSS_LISTEN 2 /* Listening for an Authenticate */
-#define UPAPSS_OPEN 3 /* We've sent an Ack */
-
-/*
- * Flags.
- */
-#define UPAPF_LOWERUP 1 /* The lower level is UP */
-#define UPAPF_AWPPENDING 2 /* Auth with peer pending */
-#define UPAPF_APPENDING 4 /* Auth peer pending */
-#define UPAPF_UPVALID 8 /* User/passwd values valid */
-#define UPAPF_UPPENDING 0x10 /* User/passwd values pending */
+#define UPAPSS_INITIAL 0 /* Connection down */
+#define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */
+#define UPAPSS_LISTEN 3 /* Listening for an Authenticate */
+#define UPAPSS_OPEN 4 /* We've sent an Ack */
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */
/*
@@ -82,7 +81,7 @@ typedef struct upap_state {
extern upap_state upap[];
void upap_init __ARGS((int));
-void upap_authwithpeer __ARGS((int));
+void upap_authwithpeer __ARGS((int, char *, char *));
void upap_authpeer __ARGS((int));
void upap_lowerup __ARGS((int));
void upap_lowerdown __ARGS((int));
diff --git a/libexec/rexecd/Makefile b/libexec/rexecd/Makefile
index 093e9a6444f7..5916212ae5de 100644
--- a/libexec/rexecd/Makefile
+++ b/libexec/rexecd/Makefile
@@ -2,6 +2,12 @@
PROG= rexecd
MAN8= rexecd.8
+CFLAGS+= -DSKEY
+
+.PATH: ${.CURDIR}/../../usr.bin/key
+
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
diff --git a/libexec/rexecd/rexecd.c b/libexec/rexecd/rexecd.c
index 914e051ed916..ff2704bafe75 100644
--- a/libexec/rexecd/rexecd.c
+++ b/libexec/rexecd/rexecd.c
@@ -98,7 +98,13 @@ doit(f, fromp)
struct sockaddr_in *fromp;
{
char cmdbuf[NCARGS+1], *cp, *namep;
+#ifdef SKEY
+ char *skey_crypt();
+ int permit_passwd = authfile(inet_ntoa(fromp->sin_addr));
+ char user[16], pass[100];
+#else /* SKEY */
char user[16], pass[16];
+#endif /* SKEY */
struct passwd *pwd;
int s;
u_short port;
@@ -154,7 +160,11 @@ doit(f, fromp)
}
endpwent();
if (*pwd->pw_passwd != '\0') {
+#ifdef SKEY
+ namep = skey_crypt(pass, pwd->pw_passwd, pwd, permit_passwd);
+#else /* SKEY */
namep = crypt(pass, pwd->pw_passwd);
+#endif /* SKEY */
if (strcmp(namep, pwd->pw_passwd)) {
error("Password incorrect.\n");
exit(1);
@@ -208,6 +218,7 @@ doit(f, fromp)
pwd->pw_shell = _PATH_BSHELL;
if (f > 2)
(void) close(f);
+ (void) setlogin(pwd->pw_name);
(void) setgid((gid_t)pwd->pw_gid);
initgroups(pwd->pw_name, pwd->pw_gid);
(void) setuid((uid_t)pwd->pw_uid);
diff --git a/libexec/rlogind/Makefile b/libexec/rlogind/Makefile
index 90254a106465..3ca4401cf755 100644
--- a/libexec/rlogind/Makefile
+++ b/libexec/rlogind/Makefile
@@ -1,4 +1,5 @@
-# @(#)Makefile 5.9 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.5 1994/03/04 20:32:55 wollman Exp $
+# From: @(#)Makefile 5.9 (Berkeley) 9/27/90
PROG= rlogind
SRCS= rlogind.c
@@ -7,10 +8,14 @@ DPADD= ${LIBUTIL}
LDADD= -lutil
.PATH: ${.CURDIR}/../../usr.bin/rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+CFLAGS+= -DKERBEROS
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
.endif
.include <bsd.prog.mk>
diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c
index f3b50b696be4..f81c8253f2a3 100644
--- a/libexec/rlogind/rlogind.c
+++ b/libexec/rlogind/rlogind.c
@@ -44,7 +44,7 @@ static char sccsid[] = "@(#)rlogind.c 5.53 (Berkeley) 4/20/91";
#ifdef KERBEROS
/* From:
* $Source: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v $
- * $Header: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.1.1.1 1993/06/12 14:54:58 rgrimes Exp $
+ * $Header: /home/cvs/386BSD/src/libexec/rlogind/rlogind.c,v 1.2 1994/05/22 19:22:02 karl Exp $
*/
#endif
@@ -317,6 +317,11 @@ doit(f, fromp)
if (f > 2) /* f should always be 0, but... */
(void) close(f);
setup_term(0);
+ if (strchr(lusername, '-')) {
+ syslog(LOG_ERR, "tried to pass user \"%s\" to login",
+ lusername);
+ fatal(STDERR_FILENO, "invalid user", 0);
+ }
if (authenticated) {
#ifdef KERBEROS
if (use_kerberos && (pwd->pw_uid == 0))
diff --git a/libexec/rpc.rusersd/rusers_proc.c b/libexec/rpc.rusersd/rusers_proc.c
index 31f4bfe50d9f..ab9d6a0c53f3 100644
--- a/libexec/rpc.rusersd/rusers_proc.c
+++ b/libexec/rpc.rusersd/rusers_proc.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: rusers_proc.c,v 1.1.2.1 1994/03/07 02:28:00 rgrimes Exp $";
+static char rcsid[] = "$Id: rusers_proc.c,v 1.2 1994/03/06 02:07:58 jkh Exp $";
#endif /* not lint */
#include <signal.h>
diff --git a/libexec/rshd/Makefile b/libexec/rshd/Makefile
index bf4b594e99e6..2c0ac884c0e6 100644
--- a/libexec/rshd/Makefile
+++ b/libexec/rshd/Makefile
@@ -1,4 +1,5 @@
-# @(#)Makefile 5.6 (Berkeley) 9/27/90
+# $Id: Makefile,v 1.5 1994/03/04 20:36:58 wollman Exp $
+# From: @(#)Makefile 5.6 (Berkeley) 9/27/90
PROG= rshd
SRCS= rshd.c
@@ -7,11 +8,14 @@ DPADD= ${LIBUTIL}
LDADD= -lutil
.PATH: ${.CURDIR}/../../usr.bin/rlogin
-.if exists(/usr/lib/libcrypt.a)
-#CFLAGS+=-DCRYPT -DKERBEROS
-DPADD+= ${LIBCRYPT} #${LIBKRB}
-LDADD+= -lcrypt #-lkrb
+.if exists(${DESTDIR}/usr/lib/libcrypt.a)
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
+.endif
+.if exists(${DESTDIR}/usr/lib/libkrb.a)
+DPADD+= ${LIBKRB} ${LIBDES}
+LDADD+= -lkrb -ldes
+CFLAGS+= -DKERBEROS -DCRYPT
.endif
-
.include <bsd.prog.mk>
diff --git a/libexec/telnetd/sys_term.c b/libexec/telnetd/sys_term.c
index cde67833dfb4..675916174162 100644
--- a/libexec/telnetd/sys_term.c
+++ b/libexec/telnetd/sys_term.c
@@ -1273,7 +1273,7 @@ start_login(host, autologin, name)
{
register char *cp;
register char **argv;
- char **addarg();
+ char **addarg(), *user;
/*
* -h : pass on name of host.
@@ -1315,7 +1315,12 @@ start_login(host, autologin, name)
argv = addarg(argv, name);
} else
#endif
- if (getenv("USER")) {
+ if (user = getenv("USER")) {
+ if (strchr(user, '-')) {
+ syslog(LOG_ERR, "tried to pass user \"%s\" to login",
+ user);
+ fatal(net, "invalid user");
+ }
argv = addarg(argv, getenv("USER"));
#if defined(CRAY) && defined(NO_LOGIN_P)
{
diff --git a/libexec/uucpd/Makefile b/libexec/uucpd/Makefile
index 474992ec92e1..7904bfd53c3a 100644
--- a/libexec/uucpd/Makefile
+++ b/libexec/uucpd/Makefile
@@ -3,6 +3,7 @@
PROG= uucpd
NOMAN= noman
+LDADD+= -lutil
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
diff --git a/libexec/uucpd/pathnames.h b/libexec/uucpd/pathnames.h
index 380c7ef204dd..133f2f5a7347 100644
--- a/libexec/uucpd/pathnames.h
+++ b/libexec/uucpd/pathnames.h
@@ -35,4 +35,4 @@
#include <paths.h>
-#define _PATH_UUCICO "/usr/lib/uucp/uucico"
+#define _PATH_UUCICO "/usr/libexec/uucp/uucico"
diff --git a/libexec/uucpd/uucpd.c b/libexec/uucpd/uucpd.c
index 76a994c6b729..c862ccea137d 100644
--- a/libexec/uucpd/uucpd.c
+++ b/libexec/uucpd/uucpd.c
@@ -65,11 +65,18 @@ static char sccsid[] = "@(#)uucpd.c 5.10 (Berkeley) 2/26/91";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <utmp.h>
+#include <syslog.h>
+#include <varargs.h>
#include "pathnames.h"
-struct sockaddr_in hisctladdr;
+#define SCPYN(a, b) strncpy(a, b, sizeof (a))
+
+struct utmp utmp;
+
+struct sockaddr hisctladdr;
int hisaddrlen = sizeof hisctladdr;
-struct sockaddr_in myctladdr;
+struct sockaddr myctladdr;
int mypid;
char Username[64];
@@ -83,176 +90,128 @@ main(argc, argv)
int argc;
char **argv;
{
-#ifndef BSDINETD
- register int s, tcp_socket;
- struct servent *sp;
-#endif !BSDINETD
extern int errno;
int dologout();
environ = nenv;
-#ifdef BSDINETD
close(1); close(2);
dup(0); dup(0);
hisaddrlen = sizeof (hisctladdr);
+ openlog("uucpd", LOG_PID, LOG_DAEMON);
if (getpeername(0, &hisctladdr, &hisaddrlen) < 0) {
- fprintf(stderr, "%s: ", argv[0]);
- perror("getpeername");
+ syslog(LOG_ERR, "getpeername: %m");
_exit(1);
}
- if (fork() == 0)
- doit(&hisctladdr);
+ doit(&hisctladdr);
dologout();
- exit(1);
-#else !BSDINETD
- sp = getservbyname("uucp", "tcp");
- if (sp == NULL){
- perror("uucpd: getservbyname");
- exit(1);
- }
- if (fork())
- exit(0);
- if ((s=open(_PATH_TTY, 2)) >= 0){
- ioctl(s, TIOCNOTTY, (char *)0);
- close(s);
- }
+ _exit(0);
+}
- bzero((char *)&myctladdr, sizeof (myctladdr));
- myctladdr.sin_family = AF_INET;
- myctladdr.sin_port = sp->s_port;
-#ifdef BSD4_2
- tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (tcp_socket < 0) {
- perror("uucpd: socket");
- exit(1);
- }
- if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) {
- perror("uucpd: bind");
- exit(1);
- }
- listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */
- signal(SIGCHLD, dologout);
+login_incorrect()
+{
+ char passwd[64];
- for(;;) {
- s = accept(tcp_socket, &hisctladdr, &hisaddrlen);
- if (s < 0){
- if (errno == EINTR)
- continue;
- perror("uucpd: accept");
- exit(1);
- }
- if (fork() == 0) {
- close(0); close(1); close(2);
- dup(s); dup(s); dup(s);
- close(tcp_socket); close(s);
- doit(&hisctladdr);
- exit(1);
- }
- close(s);
+ printf("Password: "); fflush(stdout);
+ if (readline(passwd, sizeof passwd, 1) < 0) {
+ syslog(LOG_WARNING, "passwd read");
+ _exit(1);
}
-#endif BSD4_2
-
-#endif !BSDINETD
+ fprintf(stderr, "Login incorrect.\n");
+ exit(1);
}
doit(sinp)
-struct sockaddr_in *sinp;
+struct sockaddr *sinp;
{
- char user[64], passwd[64];
+ char user[64], passwd[64], ubuf[64];
char *xpasswd, *crypt();
struct passwd *pw, *getpwnam();
+ int s;
alarm(60);
printf("login: "); fflush(stdout);
- if (readline(user, sizeof user) < 0) {
- fprintf(stderr, "user read\n");
- return;
+ if (readline(user, sizeof user, 0) < 0) {
+ syslog(LOG_WARNING, "login read");
+ _exit(1);
}
/* truncate username to 8 characters */
user[8] = '\0';
pw = getpwnam(user);
- if (pw == NULL) {
- fprintf(stderr, "user unknown\n");
- return;
- }
- if (strcmp(pw->pw_shell, _PATH_UUCICO)) {
- fprintf(stderr, "Login incorrect.");
- return;
- }
+ if (pw == NULL)
+ login_incorrect();
+ if (strcmp(pw->pw_shell, _PATH_UUCICO))
+ login_incorrect();
if (pw->pw_passwd && *pw->pw_passwd != '\0') {
printf("Password: "); fflush(stdout);
- if (readline(passwd, sizeof passwd) < 0) {
- fprintf(stderr, "passwd read\n");
- return;
+ if (readline(passwd, sizeof passwd, 1) < 0) {
+ syslog(LOG_WARNING, "passwd read");
+ _exit(1);
}
xpasswd = crypt(passwd, pw->pw_passwd);
if (strcmp(xpasswd, pw->pw_passwd)) {
- fprintf(stderr, "Login incorrect.");
- return;
+ fprintf(stderr, "Login incorrect.\n");
+ exit(1);
}
}
alarm(0);
- sprintf(Username, "USER=%s", user);
- dologin(pw, sinp);
- setgid(pw->pw_gid);
-#ifdef BSD4_2
- initgroups(pw->pw_name, pw->pw_gid);
-#endif BSD4_2
- chdir(pw->pw_dir);
- setuid(pw->pw_uid);
-#ifdef BSD4_2
- execl(UUCICO, "uucico", (char *)0);
-#endif BSD4_2
- perror("uucico server: execl");
+ sprintf(Username, "USER=%s", pw->pw_name);
+ sprintf(ubuf, "-u%s", pw->pw_name);
+ if ((s = fork()) < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ _exit(1);
+ } else if (s == 0) {
+ dologin(pw, sinp);
+ setgid(pw->pw_gid);
+ initgroups(pw->pw_name, pw->pw_gid);
+ chdir(pw->pw_dir);
+ setuid(pw->pw_uid);
+ execl(pw->pw_shell, "uucico", ubuf, NULL);
+ syslog(LOG_ERR, "execl: %m");
+ _exit(1);
+ }
}
-readline(p, n)
-register char *p;
-register int n;
+readline(start, num, pass)
+char start[];
+int num, pass;
{
char c;
+ register char *p = start;
+ register int n = num;
while (n-- > 0) {
if (read(0, &c, 1) <= 0)
return(-1);
c &= 0177;
- if (c == '\n' || c == '\r') {
+ if (c == '\n' || c == '\r' || c == '\0') {
+ if (p == start && pass) {
+ n++;
+ continue;
+ }
*p = '\0';
return(0);
}
+ if (c == 025) {
+ n = num;
+ p = start;
+ continue;
+ }
*p++ = c;
}
return(-1);
}
-#include <utmp.h>
-#ifdef BSD4_2
-#include <fcntl.h>
-#endif BSD4_2
-
-#define SCPYN(a, b) strncpy(a, b, sizeof (a))
-
-struct utmp utmp;
dologout()
{
union wait status;
- int pid, wtmp;
+ int pid;
+ char line[32];
-#ifdef BSDINETD
while ((pid=wait((int *)&status)) > 0) {
-#else !BSDINETD
- while ((pid=wait3((int *)&status,WNOHANG,0)) > 0) {
-#endif !BSDINETD
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- sprintf(utmp.ut_line, "uucp%.4d", pid);
- SCPYN(utmp.ut_name, "");
- SCPYN(utmp.ut_host, "");
- (void) time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ sprintf(line, "uu%d", pid);
+ logout(line);
+ logwtmp(line, "", "");
}
}
@@ -265,7 +224,8 @@ struct sockaddr_in *sin;
{
char line[32];
char remotehost[32];
- int wtmp, f;
+ int f;
+ time_t cur_time;
struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr,
sizeof (struct in_addr), AF_INET);
@@ -275,26 +235,22 @@ struct sockaddr_in *sin;
} else
strncpy(remotehost, inet_ntoa(sin->sin_addr),
sizeof (remotehost));
- wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND);
- if (wtmp >= 0) {
- /* hack, but must be unique and no tty line */
- sprintf(line, "uucp%.4d", getpid());
- SCPYN(utmp.ut_line, line);
- SCPYN(utmp.ut_name, pw->pw_name);
- SCPYN(utmp.ut_host, remotehost);
- time(&utmp.ut_time);
- (void) write(wtmp, (char *)&utmp, sizeof (utmp));
- (void) close(wtmp);
- }
+ sprintf(line, "uu%d", getpid());
+ /* hack, but must be unique and no tty line */
+ time(&cur_time);
if ((f = open(_PATH_LASTLOG, O_RDWR)) >= 0) {
struct lastlog ll;
- time(&ll.ll_time);
- lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), 0);
- strcpy(line, remotehost);
+ ll.ll_time = cur_time;
+ lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), L_SET);
SCPYN(ll.ll_line, line);
SCPYN(ll.ll_host, remotehost);
(void) write(f, (char *) &ll, sizeof ll);
(void) close(f);
}
+ utmp.ut_time = cur_time;
+ SCPYN(utmp.ut_line, line);
+ SCPYN(utmp.ut_name, pw->pw_name);
+ SCPYN(utmp.ut_host, remotehost);
+ login(&utmp);
}
diff --git a/libexec/xtend/Makefile b/libexec/xtend/Makefile
new file mode 100644
index 000000000000..4b9ade3ca6e0
--- /dev/null
+++ b/libexec/xtend/Makefile
@@ -0,0 +1,11 @@
+# Makefile for xtend (Stark) 10/30/93
+
+BINMODE= 4555
+
+PROG= xtend
+SRCS= xtend.c status.c packet.c user.c
+CFLAGS+=-I.
+
+MAN8= xtend.8
+
+.include <bsd.prog.mk>
diff --git a/libexec/xtend/packet.c b/libexec/xtend/packet.c
new file mode 100644
index 000000000000..bc75fcb9393d
--- /dev/null
+++ b/libexec/xtend/packet.c
@@ -0,0 +1,317 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+
+char *X10housenames[] = {
+ "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L", "M", "N", "O", "P",
+ NULL
+};
+
+char *X10cmdnames[] = {
+ "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ "AllUnitsOff", "AllLightsOn", "On", "Off", "Dim", "Bright", "AllLightsOff",
+ "ExtendedCode", "HailRequest", "HailAcknowledge", "PreSetDim0", "PreSetDim1",
+ "ExtendedData", "StatusOn", "StatusOff", "StatusRequest",
+ NULL
+};
+
+/*
+ * Log a packet and update device status accordingly
+ */
+
+logpacket(p)
+unsigned char *p;
+{
+ fprintf(Log, "%s: %s %s ", thedate(),
+ X10housenames[p[1]], X10cmdnames[p[2]]);
+ if(p[0] & TW_RCV_LOCAL) fprintf(Log, "(loc,");
+ else fprintf(Log, "(rem,");
+ if(p[0] & TW_RCV_ERROR) fprintf(Log, "err)");
+ else fprintf(Log, " ok)");
+ fprintf(Log, "\n");
+}
+
+/*
+ * Process a received packet p, updating device status information both
+ * in core and on disk.
+ */
+
+processpacket(p)
+unsigned char *p;
+{
+ int i, j, h, k;
+ STATUS *s;
+
+ /*
+ * If the packet had the error flag set, there is no other useful info.
+ */
+ if(p[0] & TW_RCV_ERROR) return;
+ /*
+ * First update in-core status information for the device.
+ */
+ h = p[1]; k = p[2];
+ if(k < 16) { /* We received a unit code, to select a particular device */
+ s = &Status[h][k];
+ s->selected = SELECTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ } else { /* We received a key code, to execute some function */
+ /*
+ * Change in status depends on the key code received
+ */
+ if(k == DIM) {
+ /*
+ * We can't really track DIM/BRIGHT properly the way things are right
+ * now. The TW523 reports the first, fourth, seventh, etc. Dim packet.
+ * We don't really have any way to tell when gaps occur, to cancel
+ * selection. For now, we'll assume that successive sequences of
+ * Dim/Bright commands are never transmitted without some other
+ * intervening command, and we make a good guess about how many units of
+ * dim/bright are represented by each packet actually reported by the
+ * TW523.
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness -= 2;
+ if(s->brightness < 0) s->brightness = 0;
+ s->selected = DIMMING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed */
+ s->brightness -=3;
+ if(s->brightness < 0) s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if(k == BRIGHT) {
+ /*
+ * Same problem here...
+ */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ switch(s->selected) {
+ case SELECTED: /* Selected, but not being dimmed or brightened */
+ if(s->onoff == 0) {
+ s->onoff = 1;
+ s->brightness = 15;
+ }
+ s->brightness += 2;
+ if(s->brightness > 15) s->brightness = 15;
+ s->selected = BRIGHTENING;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case DIMMING: /* Selected and being dimmed (an error) */
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ case BRIGHTENING: /* Selected and being brightened */
+ s->brightness +=3;
+ if(s->brightness > 15) s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else { /* Other key codes besides Bright and Dim */
+ /*
+ * We cancel brightening and dimming on ALL units on ALL house codes,
+ * because the arrival of a different packet indicates a gap that
+ * terminates any prior sequence of brightening and dimming
+ */
+ for(j = 0; j < 16; j++) {
+ for(i = 0; i < 16; i++) {
+ s = &Status[j][i];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ switch(k) {
+ case ALLUNITSOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ break;
+ case ALLLIGHTSON:
+ /* Does AllLightsOn cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->brightness = 15;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case UNITOFF:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case ALLLIGHTSOFF:
+ /* Does AllLightsOff cancel selectedness of non-lights? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->devcap & ISLIGHT) {
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDCODE:
+ break;
+ case HAILREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = HAILED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case HAILACKNOWLEDGE:
+ /* Do these commands cancel selection of devices not affected? */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == HAILED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case PRESETDIM0:
+ case PRESETDIM1:
+ /* I don't really understand these */
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == SELECTED) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case EXTENDEDDATA:
+ /* Who knows? The TW523 can't receive these anyway. */
+ break;
+ case STATUSON:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected == REQUESTED) {
+ s->onoff = 1;
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ case STATUSOFF:
+ for(i = 0; i < 16; i++) {
+ if(s->selected == REQUESTED) {
+ s = &Status[h][i];
+ s->onoff = 0;
+ s->selected = IDLE;
+ s->brightness = 0;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ case STATUSREQUEST:
+ for(i = 0; i < 16; i++) {
+ s = &Status[h][i];
+ if(s->selected) {
+ s->selected = REQUESTED;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/libexec/xtend/paths.h b/libexec/xtend/paths.h
new file mode 100644
index 000000000000..ad49443c5397
--- /dev/null
+++ b/libexec/xtend/paths.h
@@ -0,0 +1,11 @@
+/*
+ * Pathnames for files used by xtend
+ */
+
+#define X10DIR "/var/spool/xten/"
+#define X10LOGNAME "Log"
+#define X10STATNAME "Status"
+#define X10DUMPNAME "status.out"
+#define TWPATH "/dev/tw0"
+#define SOCKPATH "/var/run/tw523"
+#define PIDPATH "/var/run/xtend.pid"
diff --git a/libexec/xtend/status.c b/libexec/xtend/status.c
new file mode 100644
index 000000000000..6249577b4585
--- /dev/null
+++ b/libexec/xtend/status.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+/*
+ * Initialize the status table from the status files
+ */
+
+initstatus()
+{
+ int h, i;
+
+ if(lseek(status, 0, SEEK_SET) != 0) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ return;
+ }
+ if(read(status, Status, 16*16*sizeof(STATUS)) != 16*16*sizeof(STATUS)) {
+ fprintf(Log, "%s: Read error on status file\n", thedate());
+ return;
+ }
+}
+
+/*
+ * Checkpoint status of any devices whose status has changed
+ * and notify anyone monitoring those devices.
+ */
+
+checkpoint_status()
+{
+ int h, i, k, offset;
+
+ offset = 0;
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].changed) {
+ if(lseek(status, offset, SEEK_SET) != offset) {
+ fprintf(Log, "%s: Seek error on status file\n", thedate());
+ } else {
+ if(write(status, &Status[h][i], sizeof(STATUS)) != sizeof(STATUS)) {
+ fprintf(Log, "%s: Write error on status file\n", thedate());
+ }
+ }
+ Status[h][i].changed = 0;
+ for(k = 0; k < MAXMON; k++) {
+ if(Monitor[k].inuse
+ && Monitor[k].house == h && Monitor[k].unit == i) {
+ /*
+ * Arrange to catch SIGPIPE in case client has gone away.
+ */
+ extern int client;
+ extern void clientgone();
+ void (*prev)();
+
+ client = k;
+ prev = signal(SIGPIPE, clientgone);
+ printstatus(Monitor[k].user, &Status[h][i]);
+ fflush(Monitor[k].user);
+ signal(SIGPIPE, prev);
+ }
+ }
+ }
+ offset += sizeof(STATUS);
+ }
+ }
+}
+
+int client;
+
+void clientgone()
+{
+ fprintf(Log, "%s: Deleting monitor table entry %d, client gone\n", thedate(), client);
+ fclose(Monitor[client].user);
+ Monitor[client].inuse = 0;
+}
diff --git a/libexec/xtend/user.c b/libexec/xtend/user.c
new file mode 100644
index 000000000000..15da74409bfc
--- /dev/null
+++ b/libexec/xtend/user.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+MONENTRY Monitor[MAXMON];
+
+/*
+ * Process a user command
+ */
+
+user_command()
+{
+ char h;
+ int i, k, c, n, error;
+ char cmd[512], dumppath[MAXPATHLEN+1], pkt[3];
+ FILE *dumpf;
+
+ error = 0;
+ if(fgets(cmd, 512, User) != NULL) {
+ if(sscanf(cmd, "status %c %d", &h, &i) == 2
+ && h >= 'A' && h <= 'P' && i >= 1 && i <= 16) {
+ h -= 'A';
+ i--;
+ printstatus(User, &Status[h][i]);
+ } else if(sscanf(cmd, "send %c %s %d", &h, cmd, &n) == 3
+ && h >= 'A' && h <= 'P' && (i = find(cmd, X10cmdnames)) >= 0) {
+ h -= 'A';
+ pkt[0] = h;
+ pkt[1] = i;
+ pkt[2] = n;
+ if(write(tw523, pkt, 3) != 3) {
+ fprintf(Log, "%s: Transmission error (packet [%s %s]:%d).\n",
+ thedate(), X10housenames[h], X10cmdnames[i], n);
+ error++;
+ } else {
+ fprintf(User, "OK\n");
+ }
+ } else if(!strcmp("dump", cmd)) {
+ strcpy(dumppath, X10DIR);
+ strcat(dumppath, X10DUMPNAME);
+ if((dumpf = fopen(dumppath, "w")) != NULL) {
+ for(h = 0; h < 16; h++) {
+ for(i = 0; i < 16; i++) {
+ if(Status[h][i].lastchange) {
+ fprintf(dumpf, "%s%d\t", X10housenames[h], i+1);
+ printstatus(dumpf, &Status[h][i]);
+ }
+ }
+ }
+ fclose(dumpf);
+ fprintf(User, "OK\n");
+ } else {
+ error++;
+ }
+ } else if(sscanf(cmd, "monitor %c %d", &h, &i) == 2
+ && h >= 'A' && h <= 'P' && i >= 1 && i <= 16) {
+ h -= 'A';
+ i--;
+ for(k = 0; k < MAXMON; k++) {
+ if(!Monitor[k].inuse) break;
+ }
+ if(k == MAXMON) {
+ error++;
+ } else {
+ Monitor[k].house = h;
+ Monitor[k].unit = i;
+ Monitor[k].user = User;
+ Monitor[k].inuse = 1;
+ fprintf(Log, "%s: Adding %c %d to monitor list (entry %d)\n",
+ thedate(), h+'A', i+1, k);
+ fprintf(User, "OK\n");
+ fflush(User);
+ User = NULL;
+ return(0); /* We don't want caller to close stream */
+ }
+ } else {
+ if(feof(User)) {
+ return(1);
+ } else {
+ error++;
+ }
+ }
+ } else {
+ error++;
+ }
+ if(error) {
+ fprintf(User, "ERROR\n");
+ }
+ fflush(User);
+ return(0);
+}
+
+find(s, tab)
+char *s;
+char *tab[];
+{
+ int i;
+
+ for(i = 0; tab[i] != NULL; i++) {
+ if(strcmp(s, tab[i]) == 0) return(i);
+ }
+ return(-1);
+}
+
+printstatus(f, s)
+FILE *f;
+STATUS *s;
+{
+ fprintf(f, "%s:%d", s->onoff ? "On" : "Off", s->brightness);
+ switch(s->selected) {
+ case IDLE:
+ fprintf(f, " (normal) "); break;
+ case SELECTED:
+ fprintf(f, " (selected) "); break;
+ case DIMMING:
+ fprintf(f, " (dimming) "); break;
+ case BRIGHTENING:
+ fprintf(f, " (brightening) "); break;
+ case REQUESTED:
+ fprintf(f, " (requested) "); break;
+ case HAILED:
+ fprintf(f, " (hailed) "); break;
+ default:
+ fprintf(f, " (bogus) "); break;
+ }
+ fprintf(f, "%s", ctime(&s->lastchange));
+}
+
diff --git a/libexec/xtend/xten.h b/libexec/xtend/xten.h
new file mode 100644
index 000000000000..fea7e1786039
--- /dev/null
+++ b/libexec/xtend/xten.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+extern char *X10housenames[];
+extern char *X10cmdnames[];
+
+#define ALLUNITSOFF 16
+#define ALLLIGHTSON 17
+#define UNITON 18
+#define UNITOFF 19
+#define DIM 20
+#define BRIGHT 21
+#define ALLLIGHTSOFF 22
+#define EXTENDEDCODE 23
+#define HAILREQUEST 24
+#define HAILACKNOWLEDGE 25
+#define PRESETDIM0 26
+#define PRESETDIM1 27
+#define EXTENDEDDATA 28
+#define STATUSON 29
+#define STATUSOFF 30
+#define STATUSREQUEST 31
+
+/*
+ * Flags for first byte of received packet
+ */
+
+#define TW_RCV_LOCAL 1 /* The packet arrived during a local transmission */
+#define TW_RCV_ERROR 2 /* An invalid/corrupted packet was received */
+
diff --git a/libexec/xtend/xtend.8 b/libexec/xtend/xtend.8
new file mode 100644
index 000000000000..e6ac50ac5602
--- /dev/null
+++ b/libexec/xtend/xtend.8
@@ -0,0 +1,174 @@
+.\" Copyright (c) 1992, 1993 Eugene W. Stark
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Eugene W. Stark.
+.\" 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Th XTEND 8 "30 Oct 1993"
+.Dd Oct 30, 1993
+.Dt XTEND 8
+.Os BSD FreeBSD
+.Sh NAME
+xtend \- X-10 daemon
+.Sh SYNOPSIS
+.Nm xtend
+.Sh DESCRIPTION
+.Nm Xtend
+interfaces between user-level programs and the TW523 X-10 controller.
+It logs all packets received from the TW523, attempts to track the
+status of all X-10 devices, and accepts socket connections from user-level
+client programs that need to manipulate X-10 devices.
+.Pp
+When
+.Nm xtend
+is started, it forks, releases the controlling terminal, then opens
+its log file, where it subsequently records all X-10 activity and
+diagnostic messages. It then begins processing packets received from
+the TW523 and accepting connections one at a time from clients
+wishing to issue X-10 commands. The usual place to start xtend would
+be from the
+.Pa /etc/rc.local
+startup script.
+.Pp
+Sending
+.Nm xtend
+a SIGHUP causes it to close and reopen its log file. This is useful
+in shell scripts that rotate the log files to keep them from growing
+indefinitely.
+If
+.Nm xtend
+receives a SIGTERM, it shuts down gracefully and exits.
+A SIGPIPE causes
+.Nm xtend
+to abort the current client connection.
+.Pp
+.Nm Xtend
+communicates with client processes by a simple protocol in which a one-line
+command is sent by the client, and is acknowledged by a one-line response
+from the daemon.
+.Pp
+.Nm Xtend
+understands four types of commands. The command
+.Bl -tag
+.It status H U
+.El
+.Pp
+where H is a single letter house code, and U is a numeric unit code,
+causes
+.Nm xtend
+to respond with one line of status information about the specified device.
+The command
+.Bl -tag
+.It send H U N
+.El
+.Pp
+where H is a single-letter house code, U is either a numeric unit code
+or a function code (see source file
+.Pa xtend/packet.c
+) for a list, and N is a number indicating the number of times (usually 2)
+the packet is to be transmitted without gaps,
+causes
+.Nm xtend
+to perform the specified X-10 transmission. If the transmission was apparently
+successful, a single-line response containing
+.B
+OK
+is issued, otherwise a single-line response containing
+.B
+ERROR
+is produced.
+The command
+.Bl -tag
+.It dump
+.El
+.Pp
+causes
+.Nm xtend
+to dump the current status of all devices to an ASCII file in the spool
+directory. The response
+.B
+OK
+is issued, regardless of whether the status dump was successful.
+The command
+.Bl -tag
+.It monitor H U
+.El
+.Pp
+causes
+.Nm xtend
+to add the current client socket connection to a list of clients that are to
+be notified about activity concerning the specified X-10 device.
+The single-line acknowledgement
+.B
+OK
+is returned if the maximum (currently 5) number of such clients was not
+exceeded, otherwise
+.B
+ERROR
+is returned.
+.Nm Xtend
+then returns to its normal mode of accepting connections from clients.
+However, each subsequent change in the status of the specified device will
+cause
+.Nm xtend
+to write one line of status information for the device (in the same
+format as produced by the
+.B
+status
+command) to the saved socket. This feature is useful for writing programs
+that need to monitor the activity of devices, like motion detectors, that can
+perform X-10 transmissions.
+.Sh OPTIONS
+None.
+.Sh SEE ALSO
+.Xr xten 1
+.Xr tw 4
+.Sh FILES
+.Bl -tag -width /var/spool/xten/Status -compact
+.It Pa /dev/tw0
+the TW523 special file
+.It Pa /var/run/tw523
+socket for client connections
+.It Pa /var/run/xtend.pid
+pid file
+.It Pa /var/spool/xten/Log
+log file
+.It Pa /var/spool/xten/Status
+device status file (binary)
+.It Pa /var/spool/status.out
+ASCII dump of device status
+.El
+.Sh BUGS
+There is currently no timeout on client socket connections, so a hung
+client program can prevent other clients from accessing the daemon.
+.Pp
+.Nm Xtend
+does the best it can at trying to track device status, but there is
+usually no way it can tell when a device has been operated manually.
+This is due to the fact that most X-10 devices are not able to
+respond to queries about their status.
+.Sh AUTHOR
+Eugene W. Stark (stark@cs.sunysb.edu)
diff --git a/libexec/xtend/xtend.c b/libexec/xtend/xtend.c
new file mode 100644
index 000000000000..4372481008c9
--- /dev/null
+++ b/libexec/xtend/xtend.c
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * xtend - X-10 daemon
+ * Eugene W. Stark (stark@cs.sunysb.edu)
+ * January 14, 1993
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "xtend.h"
+#include "xten.h"
+#include "paths.h"
+
+FILE *Log; /* Log file */
+FILE *User; /* User connection */
+STATUS Status[16][16]; /* Device status table */
+int status; /* Status file descriptor */
+int tw523; /* tw523 controller */
+int sock; /* socket for user */
+jmp_buf mainloop; /* longjmp point after SIGHUP */
+void onhup(); /* SIGHUP handler */
+void onterm(); /* SIGTERM handler */
+void onpipe(); /* SIGPIPE handler */
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *twpath = TWPATH;
+ char *sockpath = SOCKPATH;
+ char logpath[MAXPATHLEN+1];
+ char statpath[MAXPATHLEN+1];
+ struct sockaddr_un sa;
+ struct timeval tv;
+ int user;
+ int fd;
+ FILE *pidf;
+
+ /*
+ * Open the log file before doing anything
+ */
+ strcpy(logpath, X10DIR);
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+
+ /*
+ * Next fork like a proper daemon
+ */
+ switch(fork()) {
+ case -1:
+ fprintf(Log, "%s: %s unable to fork\n", thedate(), argv[0]);
+ exit(1);
+ case 0:
+ break;
+ default:
+ exit(0);
+ }
+ fprintf(Log, "%s: %s[%d] started\n", thedate(), argv[0], getpid());
+
+ /*
+ * Release the controlling terminal so we don't get any signals from it.
+ */
+ setpgrp(0, getpid());
+ if ((fd = open("/dev/tty", 2)) >= 0)
+ {
+ ioctl(fd, TIOCNOTTY, (char*)0);
+ close(fd);
+ }
+
+ /*
+ * Get ahold of the TW523 device
+ */
+ if((tw523 = open(twpath, O_RDWR)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), twpath);
+ exit(1);
+ }
+ fprintf(Log, "%s: %s successfully opened\n", thedate(), twpath);
+
+ /*
+ * Initialize the status table
+ */
+ strcpy(statpath, X10DIR);
+ strcat(statpath, X10STATNAME);
+ if((status = open(statpath, O_RDWR)) < 0) {
+ if((status = open(statpath, O_RDWR | O_CREAT, 0666)) < 0) {
+ fprintf(Log, "%s: Can't open %s\n", thedate(), statpath);
+ exit(1);
+ }
+ if(write(status, Status, 16 * 16 * sizeof(STATUS))
+ != 16 * 16 * sizeof(STATUS)) {
+ fprintf(Log, "%s: Error initializing status file\n", thedate());
+ exit(1);
+ }
+ }
+ initstatus();
+
+ /*
+ * Put our pid in a file so we can be signalled by shell scripts
+ */
+ if((pidf = fopen(PIDPATH, "w")) == NULL) {
+ fprintf(Log, "%s: Error writing pid file: %s\n", thedate(), PIDPATH);
+ exit(1);
+ }
+ fprintf(pidf, "%d\n", getpid());
+ fclose(pidf);
+
+ /*
+ * Set up socket to accept user commands
+ */
+ if((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ fprintf(Log, "%s: Can't create socket\n", thedate());
+ exit(1);
+ }
+ strcpy(sa.sun_path, sockpath);
+ sa.sun_family = AF_UNIX;
+ unlink(sockpath);
+ if(bind(sock, (struct sockaddr *)(&sa), strlen(sa.sun_path) + 2) < 0) {
+ fprintf(Log, "%s: Can't bind socket to %s\n", thedate(), sockpath);
+ exit(1);
+ }
+ if(listen(sock, 5) < 0) {
+ fprintf(Log, "%s: Can't listen on socket\n", thedate());
+ exit(1);
+ }
+
+ signal(SIGHUP, onhup);
+ signal(SIGTERM, onterm);
+ signal(SIGPIPE, onpipe);
+ /*
+ * Return here on SIGHUP after closing and reopening log file.
+ * Also on SIGPIPE after closing user connection.
+ */
+ setjmp(mainloop);
+
+ /*
+ * Now start the main processing loop.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ while(1) {
+ fd_set fs;
+ unsigned char rpkt[3];
+ int sel, h, k;
+ STATUS *s;
+
+ FD_ZERO(&fs);
+ FD_SET(tw523, &fs);
+ if(User != NULL) FD_SET(user, &fs);
+ else FD_SET(sock, &fs);
+ sel = select(FD_SETSIZE, &fs, 0, 0, &tv);
+ if(sel == 0) {
+ /*
+ * Cancel brightening and dimming on ALL units on ALL house codes,
+ * because the fact that we haven't gotten a packet for awhile means
+ * that there was a gap in transmission.
+ */
+ for(h = 0; h < 16; h++) {
+ for(k = 0; k < 16; k++) {
+ s = &Status[h][k];
+ if(s->selected == BRIGHTENING || s->selected == DIMMING) {
+ s->selected = IDLE;
+ s->lastchange = time(NULL);
+ s->changed = 1;
+ }
+ }
+ }
+ fflush(Log);
+ checkpoint_status();
+ /*
+ * Now that we've done this stuff, we'll set the timeout a little
+ * longer, so we don't keep looping too frequently.
+ */
+ tv.tv_sec = 60;
+ tv.tv_usec = 0;
+ continue;
+ }
+ /*
+ * While there is stuff happening, we keep a short timeout, so we
+ * don't get stuck for some unknown reason, and so we can keep the
+ * brightening and dimming data up-to-date.
+ */
+ tv.tv_sec = 0;
+ tv.tv_usec = 250000;
+ if(FD_ISSET(tw523, &fs)) { /* X10 data arriving from TW523 */
+ if(read(tw523, rpkt, 3) < 3) {
+ fprintf(Log, "%s: Error reading from TW523\n", thedate());
+ } else {
+ logpacket(rpkt);
+ processpacket(rpkt);
+ }
+ } else if(FD_ISSET(user, &fs)) {
+ if(User != NULL) {
+ if(user_command()) {
+ fprintf(Log, "%s: Closing user connection\n", thedate());
+ fclose(User);
+ User = NULL;
+ }
+ } else {
+ /* "Can't" happen */
+ }
+ } else if(FD_ISSET(sock, &fs)) { /* Accept a connection */
+ if (User == NULL) {
+ int len = sizeof(struct sockaddr_un);
+ if((user = accept(sock, (struct sockaddr *)(&sa), &len)) >= 0) {
+ fprintf(Log, "%s: Accepting user connection\n", thedate());
+ if((User = fdopen(user, "w+")) == NULL) {
+ fprintf(Log, "%s: Can't attach socket to stream\n", thedate());
+ }
+ } else {
+ fprintf(Log, "%s: Failure in attempt to accept connection\n", thedate());
+ }
+ } else {
+ /* "Can't happen */
+ }
+ }
+ }
+ /* Not reached */
+}
+
+char *thedate()
+{
+ char *cp, *cp1;
+ time_t tod;
+
+ tod = time(NULL);
+ cp = cp1 = ctime(&tod);
+ while(*cp1 != '\n') cp1++;
+ *cp1 = '\0';
+ return(cp);
+}
+
+/*
+ * When SIGHUP received, close and reopen the Log file
+ */
+
+void onhup()
+{
+ char logpath[MAXPATHLEN+1];
+
+ fprintf(Log, "%s: SIGHUP received, reopening Log\n", thedate());
+ fclose(Log);
+ strcpy(logpath, X10DIR);
+ strcat(logpath, X10LOGNAME);
+ if((Log = fopen(logpath, "a")) == NULL) {
+ fprintf(stderr, "Can't open log file %s\n", logpath);
+ exit(1);
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
+
+/*
+ * When SIGTERM received, just exit normally
+ */
+
+void onterm()
+{
+ fprintf(Log, "%s: SIGTERM received, shutting down\n", thedate());
+ exit(0);
+}
+
+/*
+ * When SIGPIPE received, reset user connection
+ */
+
+void onpipe()
+{
+ fprintf(Log, "%s: SIGPIPE received, resetting user connection\n",
+ thedate());
+ if(User != NULL) {
+ fclose(User);
+ User = NULL;
+ }
+ longjmp(mainloop, 1);
+ /* No return */
+}
diff --git a/libexec/xtend/xtend.h b/libexec/xtend/xtend.h
new file mode 100644
index 000000000000..d52ea9bc8427
--- /dev/null
+++ b/libexec/xtend/xtend.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1992, 1993 Eugene W. Stark
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Eugene W. Stark.
+ * 4. 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 BY EUGENE W. STARK (THE AUTHOR) ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Device capabilities
+ */
+
+#define ISLIGHT 1 /* Is device a light? */
+#define CANQUERY 2 /* Responds to status query */
+
+/*
+ * Device status
+ */
+
+typedef enum {
+ IDLE,
+ SELECTED,
+ DIMMING,
+ BRIGHTENING,
+ REQUESTED,
+ HAILED
+ } SELECT;
+
+typedef struct {
+ unsigned int devcap; /* device capabilities */
+ unsigned int changed; /* status changed since last checkpoint? */
+ time_t lastchange; /* time status last changed */
+ SELECT selected; /* select status of device */
+ unsigned int onoff; /* nonzero if on */
+ unsigned int brightness; /* value in range 0-15 */
+} STATUS;
+
+typedef struct {
+ int inuse; /* Is entry in use? */
+ FILE *user; /* Socket to notify user */
+ int house; /* House code of device to monitor */
+ int unit; /* Unit code of device to monitor */
+} MONENTRY;
+
+#define MAXMON 5 /* Maximum number of monitor entries */
+
+extern FILE *Log; /* Log file */
+extern FILE *User; /* User connection */
+extern STATUS Status[16][16]; /* Device status table */
+extern int status; /* Status file descriptor */
+extern int tw523; /* tw523 controller */
+extern MONENTRY Monitor[MAXMON];/* Monitor table */
+
+extern char *thedate();