diff options
author | svn2git <svn2git@FreeBSD.org> | 1994-07-01 00:00:00 -0800 |
---|---|---|
committer | svn2git <svn2git@FreeBSD.org> | 1994-07-01 00:00:00 -0800 |
commit | 5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch) | |
tree | e779b5a6edddbb949b7990751b12d6f25304ba86 /libexec | |
parent | a16f65c7d117419bd266c28a1901ef129a337569 (diff) | |
download | src-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')
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, <c); - 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, + ¬ime)) == -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, - ¬ime)) == -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(); |