Initial revision

This commit is contained in:
Garrett Wollman 1994-09-25 02:11:26 +00:00
parent 7bf314246a
commit 08a0aca6e2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=3065
30 changed files with 14133 additions and 0 deletions

295
usr.sbin/pppd/RELNOTES Normal file
View File

@ -0,0 +1,295 @@
pppd-2.1.1 release notes
Paul Mackerras 27 May 1994
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 1548, 1549, 1332 and 1334
- security has been improved
- functionality has been improved in various ways.
NEW FEATURES
* The option negotiation automaton has been updated to RFC1548. 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.
RFC1548 defines the "passive" option to mean 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.
* More systems are supported: in addition to SunOS 4.x and BSD/Net-2
derived systems, Ultrix and Linux are supported, thanks to Robert
Olsson, Per Sundstrom, Michael Callahan and Al Longyear.
* Options can be taken from files as well as the command line. pppd
reads options from the files /etc/ppp/options and ~/.ppprc before
looking at the command line, and /etc/ppp/options.<ttyname> after
interpreting the options on 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. In addition, the
`file' option causes pppd to read options from a file. pppd will
report and error and exit if ~/.ppprc or the file given as the
argument to the `file' option cannot be read by the user who invoked
pppd.
* 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.
* If desired, pppd will output LCP echo-request frames periodically
while the link is up, and take the link down if no replies are
received to a user-configurable number of echo-requests. This can be
used to detect that the serial connection has been broken on those
systems which don't have hardware modem control lines.
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.
The behaviour where pppd refuses to run unless the /etc/ppp/options
file is present and readable by pppd is now the default behaviour. If
you really want pppd to run without the presence of the
/etc/ppp/options file, you will have to include -DREQ_SYSOPTIONS=0 on
the compilation command line.
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 an inactivity timeout and demand dialing.
* implement link quality monitoring.
* implement other network control protocols.

12
usr.sbin/pppd/args.h Normal file
View File

@ -0,0 +1,12 @@
/*
* neat macro from ka9q to "do the right thing" with ansi prototypes
* $Id: args.h,v 1.1 1993/11/11 03:54:25 paulus Exp $
*/
#ifndef __ARGS
#ifdef __STDC__
#define __ARGS(x) x
#else
#define __ARGS(x) ()
#endif
#endif

904
usr.sbin/pppd/auth.c Normal file
View File

@ -0,0 +1,904 @@
/*
* 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.6 1994/05/25 06:25:05 paulus 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>
#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 null_login __ARGS((int));
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();
phase = PHASE_DEAD;
syslog(LOG_NOTICE, "Connection terminated.");
}
/*
* LCP has gone down; it will either die or try to re-establish.
*/
void
link_down(unit)
int unit;
{
phase = PHASE_TERMINATE;
}
/*
* 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 itself, and it refused:
* treat it as though it authenticated with PAP using a username
* of "" and a password of "". If that's not OK, boot it out.
*/
if (wo->neg_upap && !null_login(unit)) {
syslog(LOG_WARNING, "peer refused to authenticate");
lcp_close(unit);
phase = PHASE_TERMINATE;
return;
}
}
phase = PHASE_AUTHENTICATE;
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) {
phase = PHASE_NETWORK;
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);
phase = PHASE_TERMINATE;
}
/*
* 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) {
phase = PHASE_NETWORK;
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);
bit = 0;
}
/*
* If there is no more authentication still being done,
* proceed to the network phase.
*/
if ((auth_pending[unit] &= ~bit) == 0) {
phase = PHASE_NETWORK;
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;
}
/*
* null_login - Check if a username of "" and a password of "" are
* acceptable, and iff so, set the list of acceptable IP addresses
* and return 1.
*/
static int
null_login(unit)
int unit;
{
char *filename;
FILE *f;
int i, ret;
struct wordlist *addrs;
char secret[MAXWORDLEN];
/*
* Open the file of upap secrets and scan for a suitable secret.
* We don't accept a wildcard client.
*/
filename = _PATH_UPAPFILE;
addrs = NULL;
f = fopen(filename, "r");
if (f == NULL)
return 0;
check_access(f, filename);
i = scan_authfile(f, "", our_name, secret, &addrs, filename);
ret = i >= 0 && (i & NONWILD_CLIENT) != 0 && secret[0] == 0;
if (ret) {
if (addresses[unit] != NULL)
free_wordlist(addresses[unit]);
addresses[unit] = addrs;
}
fclose(f);
return ret;
}
/*
* 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;
int save_addrs;
{
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;
/* don't allow loopback or multicast address */
if (bad_ip_adrs(addr))
return 0;
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 */
}
/*
* bad_ip_adrs - return 1 if the IP address is one we don't want
* to use, such as an address in the loopback net or a multicast address.
* addr is in network byte order.
*/
int
bad_ip_adrs(addr)
u_long addr;
{
addr = ntohl(addr);
return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
}
/*
* 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 = addr_last = 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;
}
}

18
usr.sbin/pppd/callout.h Normal file
View File

@ -0,0 +1,18 @@
/* Note: This is a copy of /usr/include/sys/callout.h with the c_func */
/* member of struct callout changed from a pointer to a function of type int*/
/* to a pointer to a function of type void (generic pointer) as per */
/* ANSI C */
/* $Id: callout.h,v 1.1 1993/11/11 03:54:25 paulus Exp $ */
#ifndef _ppp_callout_h
#define _ppp_callout_h
struct callout {
int c_time; /* incremental time */
caddr_t c_arg; /* argument to routine */
void (*c_func)(); /* routine (changed to void (*)() */
struct callout *c_next;
};
#endif /*!_ppp_callout_h*/

823
usr.sbin/pppd/chap.c Normal file
View File

@ -0,0 +1,823 @@
/*
* chap.c - Crytographic Handshake Authentication Protocol.
*
* Copyright (c) 1991 Gregory M. Christy.
* 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 Gregory M. Christy. The name of the author may not be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char rcsid[] = "$Id: chap.c,v 1.3 1994/04/18 04:01:07 paulus Exp $";
#endif
/*
* TODO:
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <syslog.h>
#include "ppp.h"
#include "pppd.h"
#include "chap.h"
#include "md5.h"
chap_state chap[NPPP]; /* CHAP state; one for each unit */
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));
static void ChapSendChallenge __ARGS((chap_state *));
static void ChapSendResponse __ARGS((chap_state *));
static void ChapGenChallenge __ARGS((chap_state *));
extern double drand48 __ARGS((void));
extern void srand48 __ARGS((long));
/*
* ChapInit - Initialize a CHAP unit.
*/
void
ChapInit(unit)
int unit;
{
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 */
}
/*
* ChapAuthWithPeer - Authenticate us with our peer (start client).
*
*/
void
ChapAuthWithPeer(unit, our_name, digest)
int unit;
char *our_name;
int digest;
{
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;
}
/*
* ChapAuthPeer - Authenticate our peer (start server).
*/
void
ChapAuthPeer(unit, our_name, digest)
int unit;
char *our_name;
int digest;
{
chap_state *cstate = &chap[unit];
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;
}
/*
* ChapChallengeTimeout - Timeout expired on sending challenge.
*/
static void
ChapChallengeTimeout(arg)
caddr_t 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->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);
}
/*
* ChapLowerUp - The lower layer is up.
*
* Start up if we have pending requests.
*/
void
ChapLowerUp(unit)
int unit;
{
chap_state *cstate = &chap[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;
}
}
/*
* ChapLowerDown - The lower layer is down.
*
* Cancel all timeouts.
*/
void
ChapLowerDown(unit)
int unit;
{
chap_state *cstate = &chap[unit];
/* 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;
}
/*
* ChapProtocolReject - Peer doesn't grok CHAP.
*/
void
ChapProtocolReject(unit)
int unit;
{
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 */
}
/*
* ChapInput - Input CHAP packet.
*/
void
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;
/*
* 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 (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_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;
}
}
/*
* ChapReceiveChallenge - Receive Challenge and send Response.
*/
static void
ChapReceiveChallenge(cstate, inp, id, len)
chap_state *cstate;
u_char *inp;
int id;
int 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;
}
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);
}
/* cancel response send timeout if necessary */
if (cstate->clientstate == CHAPCS_RESPONSE)
UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
cstate->resp_id = id;
cstate->resp_transmits = 0;
/* generate MD based on negotiated type */
switch (cstate->resp_type) {
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;
default:
CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
return;
}
ChapSendResponse(cstate);
}
/*
* 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;
}
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 (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;
}
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));
}
}
ChapSendStatus(cstate, code);
if (code == CHAP_SUCCESS) {
old_state = cstate->serverstate;
cstate->serverstate = CHAPSS_OPEN;
if (old_state == CHAPSS_INITIAL_CHAL) {
auth_peer_success(cstate->unit, 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
*/
static void
ChapReceiveSuccess(cstate, inp, id, len)
chap_state *cstate;
u_char *inp;
u_char id;
int len;
{
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;
}
UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
/*
* Print message.
*/
if (len > 0)
PRINTMSG(inp, len);
cstate->clientstate = CHAPCS_OPEN;
auth_withpeer_success(cstate->unit, CHAP);
}
/*
* ChapReceiveFailure - Receive failure.
*/
static void
ChapReceiveFailure(cstate, inp, id, len)
chap_state *cstate;
u_char *inp;
u_char id;
int len;
{
u_char msglen;
u_char *msg;
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;
}
UNTIMEOUT(ChapResponseTimeout, (caddr_t) cstate);
/*
* Print message.
*/
if (len > 0)
PRINTMSG(inp, len);
syslog(LOG_ERR, "CHAP authentication failed");
auth_withpeer_fail(cstate->unit, CHAP);
}
/*
* ChapSendChallenge - Send an Authenticate challenge.
*/
static void
ChapSendChallenge(cstate)
chap_state *cstate;
{
u_char *outp;
int chal_len, name_len;
int outlen;
chal_len = cstate->chal_len;
name_len = strlen(cstate->chal_name);
outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
outp = outpacket_buf;
MAKEHEADER(outp, CHAP); /* paste in a CHAP header */
PUTCHAR(CHAP_CHALLENGE, outp);
PUTCHAR(cstate->chal_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(chal_len, outp); /* put length of challenge */
BCOPY(cstate->challenge, outp, chal_len);
INCPTR(chal_len, outp);
BCOPY(cstate->chal_name, outp, name_len); /* append hostname */
output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
TIMEOUT(ChapChallengeTimeout, (caddr_t) cstate, cstate->timeouttime);
++cstate->chal_transmits;
}
/*
* ChapSendStatus - Send a status response (ack or nak).
*/
static void
ChapSendStatus(cstate, code)
chap_state *cstate;
int code;
{
u_char *outp;
int outlen, msglen;
char msg[256];
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(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,
cstate->chal_id));
}
/*
* ChapGenChallenge is used to generate a pseudo-random challenge string of
* 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(cstate)
chap_state *cstate;
{
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 values as specified
* in *cstate.
*/
/* ARGSUSED */
static void
ChapSendResponse(cstate)
chap_state *cstate;
{
u_char *outp;
int outlen, md_len, name_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(cstate->resp_id, outp); /* copy id from challenge packet */
PUTSHORT(outlen, outp); /* packet length */
PUTCHAR(md_len, outp); /* length of MD */
BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */
INCPTR(md_len, outp);
BCOPY(cstate->resp_name, outp, name_len); /* append our name */
/* send the packet */
output(cstate->unit, outpacket_buf, outlen + DLLHEADERLEN);
cstate->clientstate = CHAPCS_RESPONSE;
TIMEOUT(ChapResponseTimeout, (caddr_t) cstate, cstate->timeouttime);
++cstate->resp_transmits;
}
/*
* ChapPrintPkt - print the contents of a CHAP packet.
*/
char *ChapCodenames[] = {
"Challenge", "Response", "Success", "Failure"
};
int
ChapPrintPkt(p, plen, printer, arg)
u_char *p;
int plen;
void (*printer) __ARGS((void *, char *, ...));
void *arg;
{
int code, id, len;
int clen, nlen;
u_char x;
if (plen < CHAP_HEADERLEN)
return 0;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < CHAP_HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
printer(arg, " %s", ChapCodenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= CHAP_HEADERLEN;
switch (code) {
case CHAP_CHALLENGE:
case CHAP_RESPONSE:
if (len < 1)
break;
clen = p[0];
if (len < clen + 1)
break;
++p;
nlen = len - clen - 1;
printer(arg, " <");
for (; clen > 0; --clen) {
GETCHAR(x, p);
printer(arg, "%.2x", x);
}
printer(arg, ">, name = ");
print_string((char *)p, nlen, printer, arg);
break;
case CHAP_FAILURE:
case CHAP_SUCCESS:
printer(arg, " ");
print_string((char *)p, len, printer, arg);
break;
default:
for (clen = len; clen > 0; --clen) {
GETCHAR(x, p);
printer(arg, " %.2x", x);
}
}
return len + CHAP_HEADERLEN;
}
#ifdef NO_DRAND48
double drand48()
{
return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
}
void srand48(seedval)
long seedval;
{
srand((int)seedval);
}
#endif

112
usr.sbin/pppd/chap.h Normal file
View File

@ -0,0 +1,112 @@
/*
* chap.h - Cryptographic Handshake Authentication Protocol definitions.
*
* Copyright (c) 1991 Gregory M. Christy
* 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 author.
*
* 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/04/11 07:13:44 paulus Exp $
*/
#ifndef __CHAP_INCLUDE__
/* Code + ID + length */
#define CHAP_HEADERLEN 4
/*
* CHAP codes.
*/
#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
/*
* 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 */
/*
* Each interface is described by a chap structure.
*/
typedef struct chap_state {
int unit; /* Interface unit number */
int clientstate; /* Client state */
int serverstate; /* Server state */
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 (peer) states.
*/
#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 (authenticator) states.
*/
#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_DEFTRANSMITS 10 /* max # times to send challenge */
extern chap_state chap[];
void ChapInit __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));
void ChapProtocolReject __ARGS((int));
int ChapPrintPkt __ARGS((u_char *, int,
void (*) __ARGS((void *, char *, ...)), void *));
#define __CHAP_INCLUDE__
#endif /* __CHAP_INCLUDE__ */

773
usr.sbin/pppd/fsm.c Normal file
View File

@ -0,0 +1,773 @@
/*
* fsm.c - {Link, IP} Control Protocol Finite State Machine.
*
* 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: fsm.c,v 1.3 1994/05/24 11:21:10 paulus Exp $";
#endif
/*
* TODO:
* Randomize fsm id on link/init.
* Deal with variable outgoing MTU.
*/
#include <stdio.h>
#include <sys/types.h>
#include <syslog.h>
#include "ppp.h"
#include "pppd.h"
#include "fsm.h"
extern char *proto_name();
static void fsm_timeout __ARGS((caddr_t));
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_sconfreq __ARGS((fsm *, int));
#define PROTO_NAME(f) ((f)->callbacks->proto_name)
int peer_mru[NPPP];
/*
* fsm_init - Initialize fsm.
*
* Initialize fsm state.
*/
void
fsm_init(f)
fsm *f;
{
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_lowerup - The lower layer is up.
*/
void
fsm_lowerup(f)
fsm *f;
{
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;
default:
FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
PROTO_NAME(f), f->state));
}
}
/*
* fsm_lowerdown - The lower layer is down.
*
* Cancel all timeouts and inform upper layers.
*/
void
fsm_lowerdown(f)
fsm *f;
{
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 */
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_open - Link is allowed to come up.
*/
void
fsm_open(f)
fsm *f;
{
switch( f->state ){
case INITIAL:
f->state = STARTING;
if( f->callbacks->starting )
(*f->callbacks->starting)(f);
break;
case CLOSED:
if( f->flags & OPT_SILENT )
f->state = STOPPED;
else {
/* Send an initial configure-request */
fsm_sconfreq(f, 0);
f->state = REQSENT;
}
break;
case CLOSING:
f->state = STOPPING;
/* fall through */
case STOPPED:
case OPENED:
if( f->flags & OPT_RESTART ){
fsm_lowerdown(f);
fsm_lowerup(f);
}
break;
}
}
/*
* fsm_close - Start closing connection.
*
* Cancel timeouts and either initiate close or possibly go directly to
* the CLOSED state.
*/
void
fsm_close(f)
fsm *f;
{
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 */
/* 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_timeout - Timeout expired.
*/
static void
fsm_timeout(arg)
caddr_t arg;
{
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));
}
}
/*
* fsm_input - Input packet.
*/
void
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 */
if( f->state == INITIAL || f->state == STARTING ){
FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
f->protocol, f->state));
return;
}
/*
* Action depends on code.
*/
switch (code) {
case CONFREQ:
fsm_rconfreq(f, id, inp, len);
break;
case CONFACK:
fsm_rconfack(f, id, inp, len);
break;
case CONFNAK:
case CONFREJ:
fsm_rconfnakrej(f, code, id, inp, len);
break;
case TERMREQ:
fsm_rtermreq(f, id);
break;
case TERMACK:
fsm_rtermack(f);
break;
case CODEREJ:
fsm_rcoderej(f, inp, len);
break;
default:
if( !f->callbacks->extcode
|| !(*f->callbacks->extcode)(f, code, id, inp, len) )
fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
break;
}
}
/*
* fsm_rconfreq - Receive Configure-Request.
*/
static void
fsm_rconfreq(f, id, inp, len)
fsm *f;
u_char id;
u_char *inp;
int len;
{
u_char *outp;
int code, reject_if_disagree;
FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
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 STOPPED:
/* Negotiation started by our peer */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = REQSENT;
break;
}
/*
* 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 */
else
code = CONFACK;
/* 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 */
} else
f->state = ACKSENT;
f->nakloops = 0;
} else {
/* we sent CONFACK or CONFREJ */
if (f->state != ACKRCVD)
f->state = REQSENT;
if( code == CONFNAK )
++f->nakloops;
}
}
/*
* fsm_rconfack - Receive Configure-Ack.
*/
static void
fsm_rconfack(f, id, inp, len)
fsm *f;
int id;
u_char *inp;
int len;
{
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;
}
f->reqid = -1;
switch (f->state) {
case CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
case REQSENT:
f->state = ACKRCVD;
f->retransmits = f->maxconfreqtransmits;
break;
case ACKRCVD:
/* Huh? an extra Ack? oh well... */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
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 */
fsm_sconfreq(f, 0); /* Send initial Configure-Request */
f->state = REQSENT;
break;
}
}
/*
* fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
*/
static void
fsm_rconfnakrej(f, code, id, inp, len)
fsm *f;
int code, id;
u_char *inp;
int len;
{
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;
}
f->reqid = -1;
switch (f->state) {
case CLOSED:
case STOPPED:
fsm_sdata(f, TERMACK, id, NULL, 0);
break;
case REQSENT:
case ACKSENT:
/* They didn't agree to what we wanted - try another request */
UNTIMEOUT(fsm_timeout, (caddr_t) f); /* Cancel timeout */
fsm_sconfreq(f, 0); /* Send Configure-Request */
break;
case ACKRCVD:
/* Got a Nak/reject when we had already had an Ack?? oh well... */
fsm_sconfreq(f, 0);
f->state = REQSENT;
break;
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;
}
}
/*
* fsm_rtermreq - Receive Terminate-Req.
*/
static void
fsm_rtermreq(f, id)
fsm *f;
int id;
{
FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
PROTO_NAME(f), id));
switch (f->state) {
case ACKRCVD:
case ACKSENT:
f->state = REQSENT; /* Start over but keep trying */
break;
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->retransmits = 0;
f->state = STOPPING;
TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
break;
}
fsm_sdata(f, TERMACK, id, NULL, 0);
}
/*
* fsm_rtermack - Receive Terminate-Ack.
*/
static void
fsm_rtermack(f)
fsm *f;
{
FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
switch (f->state) {
case CLOSING:
f->state = CLOSED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case STOPPING:
f->state = STOPPED;
if( f->callbacks->finished )
(*f->callbacks->finished)(f);
break;
case ACKRCVD:
f->state = REQSENT;
break;
case OPENED:
if (f->callbacks->down)
(*f->callbacks->down)(f); /* Inform upper layers */
fsm_sconfreq(f, 0);
break;
}
}
/*
* fsm_rcoderej - Receive an Code-Reject.
*/
static void
fsm_rcoderej(f, inp, len)
fsm *f;
u_char *inp;
int len;
{
u_char code, id;
FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
if (len < HEADERLEN) {
FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
return;
}
GETCHAR(code, inp);
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_protreject - Peer doesn't speak this protocol.
*
* Treat this as a catastrophic error (RXJ-).
*/
void
fsm_protreject(f)
fsm *f;
{
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;
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;
case OPENED:
if( f->callbacks->down )
(*f->callbacks->down)(f);
/* Init restart counter, send Terminate-Request */
f->retransmits = f->maxtermtransmits;
fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
TIMEOUT(fsm_timeout, (caddr_t) f, f->timeouttime);
--f->retransmits;
f->state = STOPPING;
break;
default:
FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
PROTO_NAME(f), f->state));
}
}
/*
* fsm_sconfreq - Send a Configure-Request.
*/
static void
fsm_sconfreq(f, retransmit)
fsm *f;
int retransmit;
{
u_char *outp;
int outlen, cilen;
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;
}
if( !retransmit ){
/* New request - reset retransmission counter, use new ID */
f->retransmits = f->maxconfreqtransmits;
f->reqid = ++f->id;
}
/*
* Make up the request packet
*/
outp = outpacket_buf + DLLHEADERLEN + HEADERLEN;
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;
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), f->reqid));
}
/*
* fsm_sdata - Send some data.
*
* 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;
{
u_char *outp;
int outlen;
/* Adjust length to be smaller than MTU */
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);
output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
PROTO_NAME(f), code, id));
}

127
usr.sbin/pppd/fsm.h Normal file
View File

@ -0,0 +1,127 @@
/*
* fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: fsm.h,v 1.2 1994/04/11 07:18:35 paulus Exp $
*/
/*
* Packet header = Code, id, length.
*/
#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
/*
* CP (LCP, IPCP, etc.) codes.
*/
#define CONFREQ 1 /* Configuration Request */
#define CONFACK 2 /* Configuration Ack */
#define CONFNAK 3 /* Configuration Nak */
#define CONFREJ 4 /* Configuration Reject */
#define TERMREQ 5 /* Termination Request */
#define TERMACK 6 /* Termination Ack */
#define CODEREJ 7 /* Code Reject */
/*
* Each FSM is described by a fsm_callbacks and a fsm structure.
*/
typedef struct fsm_callbacks {
void (*resetci)(); /* Reset our Configuration Information */
int (*cilen)(); /* Length of our Configuration Information */
void (*addci)(); /* Add our Configuration Information */
int (*ackci)(); /* ACK our Configuration Information */
int (*nakci)(); /* NAK our Configuration Information */
int (*rejci)(); /* Reject our Configuration Information */
int (*reqci)(); /* Request peer's Configuration Information */
void (*up)(); /* Called when fsm reaches OPENED state */
void (*down)(); /* Called when fsm leaves OPENED state */
void (*starting)(); /* Called when we want the lower layer */
void (*finished)(); /* Called when we don't want the lower layer */
void (*protreject)(); /* Called when Protocol-Reject received */
void (*retransmit)(); /* Retransmission is necessary */
int (*extcode)(); /* Called when unknown code received */
char *proto_name; /* String name for protocol (for messages) */
} fsm_callbacks;
typedef struct fsm {
int unit; /* Interface unit number */
int protocol; /* Data Link Layer Protocol field value */
int state; /* State */
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 left */
int maxtermtransmits; /* Maximum Terminate-Request transmissions */
int nakloops; /* Number of nak loops since last ack */
int maxnakloops; /* Maximum number of nak loops tolerated */
fsm_callbacks *callbacks; /* Callback routines */
} fsm;
/*
* Link states.
*/
#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 - indicate options controlling FSM operation
*/
#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 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_lowerup __ARGS((fsm *));
void fsm_lowerdown __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) */

1196
usr.sbin/pppd/ipcp.c Normal file

File diff suppressed because it is too large Load Diff

68
usr.sbin/pppd/ipcp.h Normal file
View File

@ -0,0 +1,68 @@
/*
* ipcp.h - IP Control Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: ipcp.h,v 1.3 1994/04/18 04:05:15 paulus Exp $
*/
/*
* Options.
*/
#define CI_ADDRS 1 /* IP Addresses */
#define CI_COMPRESSTYPE 2 /* Compression Type */
#define CI_ADDR 3
#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) */
#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_addr : 1; /* Negotiate IP Address? */
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? */
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_open __ARGS((int));
void ipcp_close __ARGS((int));
void ipcp_lowerup __ARGS((int));
void ipcp_lowerdown __ARGS((int));
void ipcp_input __ARGS((int, u_char *, int));
void ipcp_protrej __ARGS((int));
int ipcp_printpkt __ARGS((u_char *, int, void (*)(), void *));

1644
usr.sbin/pppd/lcp.c Normal file

File diff suppressed because it is too large Load Diff

87
usr.sbin/pppd/lcp.h Normal file
View File

@ -0,0 +1,87 @@
/*
* lcp.h - Link Control Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: lcp.h,v 1.4 1994/05/24 11:22:28 paulus Exp $
*/
/*
* Options.
*/
#define CI_MRU 1 /* Maximum Receive Unit */
#define CI_ASYNCMAP 2 /* Async Control Character Map */
#define CI_AUTHTYPE 3 /* Authentication Type */
#define CI_QUALITY 4 /* Quality Protocol */
#define CI_MAGICNUMBER 5 /* Magic Number */
#define CI_PCOMPRESSION 7 /* Protocol Field Compression */
#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
/*
* LCP-specific packet types.
*/
#define PROTREJ 8 /* Protocol Reject */
#define ECHOREQ 9 /* Echo Request */
#define ECHOREP 10 /* Echo Reply */
#define DISCREQ 11 /* Discard Request */
/*
* The state of options is described by an lcp_options structure.
*/
typedef struct lcp_options {
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? */
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 */
u_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[];
extern lcp_options lcp_wantoptions[];
extern lcp_options lcp_gotoptions[];
extern lcp_options lcp_allowoptions[];
extern lcp_options lcp_hisoptions[];
extern u_long xmit_accm[][8];
#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_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));
int lcp_printpkt __ARGS((u_char *, int,
void (*) __ARGS((void *, char *, ...)), void *));
extern int lcp_warnloops; /* Warn about a loopback this often */
#define DEFWARNLOOPS 10 /* Default value for above */

122
usr.sbin/pppd/lock.c Normal file
View File

@ -0,0 +1,122 @@
/*
* lock.c - lock/unlock the serial device.
*
* This code is derived from chat.c.
*/
static char rcsid[] = "$Id: lock.c,v 1.1 1994/04/18 23:41:52 paulus Exp $";
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#ifdef sun
# if defined(SUNOS) && SUNOS >= 41
# ifndef HDB
# define HDB
# endif
# endif
#endif
#ifndef LOCK_DIR
# ifdef __NetBSD__
# define PIDSTRING
# define LOCK_PREFIX "/var/spool/lock/LCK.."
# else
# ifdef HDB
# define PIDSTRING
# define LOCK_PREFIX "/usr/spool/locks/LCK.."
# else /* HDB */
# define LOCK_PREFIX "/usr/spool/uucp/LCK.."
# endif /* HDB */
# endif
#endif /* LOCK_DIR */
static char *lock_file;
/*
* Create a lock file for the named lock device
*/
int
lock(dev)
char *dev;
{
char hdb_lock_buffer[12];
int fd, pid, n;
char *p;
if ((p = strrchr(dev, '/')) != NULL)
dev = p + 1;
lock_file = malloc(strlen(LOCK_PREFIX) + strlen(dev) + 1);
if (lock_file == NULL)
novm("lock file name");
strcat(strcpy(lock_file, LOCK_PREFIX), dev);
while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
if (errno == EEXIST
&& (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
/* Read the lock file to find out who has the device locked */
#ifdef PIDSTRING
n = read(fd, hdb_lock_buffer, 11);
if (n > 0) {
hdb_lock_buffer[n] = 0;
pid = atoi(hdb_lock_buffer);
}
#else
n = read(fd, &pid, sizeof(pid));
#endif
if (n <= 0) {
syslog(LOG_ERR, "Can't read pid from lock file %s", lock_file);
close(fd);
} else {
if (kill(pid, 0) == -1 && errno == ESRCH) {
/* pid no longer exists - remove the lock file */
if (unlink(lock_file) == 0) {
close(fd);
syslog(LOG_NOTICE, "Removed stale lock on %s (pid %d)",
dev, pid);
continue;
} else
syslog(LOG_WARNING, "Couldn't remove stale lock on %s",
dev);
} else
syslog(LOG_NOTICE, "Device %s is locked by pid %d",
dev, pid);
}
close(fd);
} else
syslog(LOG_ERR, "Can't create lock file %s: %m", lock_file);
free(lock_file);
lock_file = NULL;
return -1;
}
# ifdef PIDSTRING
sprintf(hdb_lock_buffer, "%10d\n", getpid());
write(fd, hdb_lock_buffer, 11);
# else
pid = getpid();
write(fd, &pid, sizeof pid);
# endif
close(fd);
return 0;
}
/*
* Remove our lockfile
*/
unlock()
{
if (lock_file) {
unlink(lock_file);
free(lock_file);
lock_file = NULL;
}
}

70
usr.sbin/pppd/magic.c Normal file
View File

@ -0,0 +1,70 @@
/*
* magic.c - PPP Magic Number routines.
*
* 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: magic.c,v 1.1 1993/11/11 03:54:25 paulus Exp $";
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include "magic.h"
static u_long next; /* Next value to return */
extern u_long gethostid __ARGS((void));
extern long random __ARGS((void));
extern void srandom __ARGS((int));
/*
* magic_init - Initialize the magic number generator.
*
* Computes first magic number and seed for random number generator.
* Attempts to compute a random number seed which will not repeat.
* The current method uses the current hostid and current time.
*/
void magic_init()
{
struct timeval tv;
next = gethostid();
if (gettimeofday(&tv, NULL)) {
perror("gettimeofday");
exit(1);
}
next ^= (u_long) tv.tv_sec ^ (u_long) tv.tv_usec;
srandom((int) next);
}
/*
* magic - Returns the next magic number.
*/
u_long magic()
{
u_long m;
m = next;
next = (u_long) random();
return (m);
}

24
usr.sbin/pppd/magic.h Normal file
View File

@ -0,0 +1,24 @@
/*
* magic.h - PPP Magic Number definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: magic.h,v 1.1 1993/11/11 03:54:25 paulus Exp $
*/
#include "args.h"
void magic_init __ARGS((void)); /* Initialize the magic number generator */
u_long magic __ARGS((void)); /* Returns the next magic number */

1445
usr.sbin/pppd/main.c Normal file

File diff suppressed because it is too large Load Diff

304
usr.sbin/pppd/md5.c Normal file
View File

@ -0,0 +1,304 @@
/*
***********************************************************************
** md5.c -- the source code for MD5 routines **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#include "md5.h"
/*
***********************************************************************
** Message-digest routines: **
** To form the message digest for a message M **
** (1) Initialize a context buffer mdContext using MD5Init **
** (2) Call MD5Update on mdContext and M **
** (3) Call MD5Final on mdContext **
** The message digest is now in mdContext->digest[0...15] **
***********************************************************************
*/
/* forward declaration */
static void Transform ();
static unsigned char PADDING[64] = {
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* F, G, H and I are basic MD5 functions */
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */
/* Rotation is separate from addition to prevent recomputation */
#define FF(a, b, c, d, x, s, ac) \
{(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) \
{(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) \
{(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) \
{(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(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.
*/
void MD5Init (mdContext)
MD5_CTX *mdContext;
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
/* Load magic initialization constants.
*/
mdContext->buf[0] = (UINT4)0x67452301;
mdContext->buf[1] = (UINT4)0xefcdab89;
mdContext->buf[2] = (UINT4)0x98badcfe;
mdContext->buf[3] = (UINT4)0x10325476;
}
/* The routine MD5Update updates the message-digest context to
account for the presence of each of the characters inBuf[0..inLen-1]
in the message whose digest is being computed.
*/
void MD5Update (mdContext, inBuf, inLen)
MD5_CTX *mdContext;
unsigned char *inBuf;
unsigned int inLen;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* update number of bits */
if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])
mdContext->i[1]++;
mdContext->i[0] += ((UINT4)inLen << 3);
mdContext->i[1] += ((UINT4)inLen >> 29);
while (inLen--) {
/* add new character to buffer, increment mdi */
mdContext->in[mdi++] = *inBuf++;
/* transform if necessary */
if (mdi == 0x40) {
for (i = 0, ii = 0; i < 16; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
mdi = 0;
}
}
}
/* The routine MD5Final terminates the message-digest computation and
ends with the desired message digest in mdContext->digest[0...15].
*/
void MD5Final (mdContext)
MD5_CTX *mdContext;
{
UINT4 in[16];
int mdi;
unsigned int i, ii;
unsigned int padLen;
/* save number of bits */
in[14] = mdContext->i[0];
in[15] = mdContext->i[1];
/* compute number of bytes mod 64 */
mdi = (int)((mdContext->i[0] >> 3) & 0x3F);
/* pad out to 56 mod 64 */
padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);
MD5Update (mdContext, PADDING, padLen);
/* append length in bits and transform */
for (i = 0, ii = 0; i < 14; i++, ii += 4)
in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |
(((UINT4)mdContext->in[ii+2]) << 16) |
(((UINT4)mdContext->in[ii+1]) << 8) |
((UINT4)mdContext->in[ii]);
Transform (mdContext->buf, in);
/* store buffer in digest */
for (i = 0, ii = 0; i < 4; i++, ii += 4) {
mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);
mdContext->digest[ii+1] =
(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);
mdContext->digest[ii+2] =
(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);
mdContext->digest[ii+3] =
(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);
}
}
/* Basic MD5 step. Transforms buf based on in.
*/
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
/* Round 1 */
#define S11 7
#define S12 12
#define S13 17
#define S14 22
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, 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, 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, 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;
buf[2] += c;
buf[3] += d;
}
/*
***********************************************************************
** End of md5.c **
******************************** (cut) ********************************
*/

58
usr.sbin/pppd/md5.h Normal file
View File

@ -0,0 +1,58 @@
/*
***********************************************************************
** md5.h -- header file for implementation of MD5 **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
** Created: 2/17/90 RLR **
** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version **
** Revised (for MD5): RLR 4/27/91 **
** -- G modified to have y&~z instead of y&z **
** -- FF, GG, HH modified to add in last register done **
** -- Access pattern: round 2 works mod 5, round 3 works mod 3 **
** -- distinct additive constant for each step **
** -- round 4 added, working mod 7 **
***********************************************************************
*/
/*
***********************************************************************
** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. **
** **
** License to copy and use this software is granted provided that **
** it is identified as the "RSA Data Security, Inc. MD5 Message- **
** Digest Algorithm" in all material mentioning or referencing this **
** software or this function. **
** **
** License is also granted to make and use derivative works **
** provided that such works are identified as "derived from the RSA **
** Data Security, Inc. MD5 Message-Digest Algorithm" in all **
** material mentioning or referencing the derived work. **
** **
** RSA Data Security, Inc. makes no representations concerning **
** either the merchantability of this software or the suitability **
** of this software for any particular purpose. It is provided "as **
** is" without express or implied warranty of any kind. **
** **
** These notices must be retained in any copies of any part of this **
** documentation and/or software. **
***********************************************************************
*/
#ifndef __MD5_INCLUDE__
/* typedef a 32-bit type */
typedef unsigned long int UINT4;
/* Data structure for MD5 (Message-Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
void MD5Init ();
void MD5Update ();
void MD5Final ();
#define __MD5_INCLUDE__
#endif /* __MD5_INCLUDE__ */

1452
usr.sbin/pppd/options.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
/* $Id: patchlevel.h,v 1.10 1994/06/09 01:51:10 paulus Exp $ */
#define PATCHLEVEL 2
#define VERSION "2.1"
#define DATE "9 June 94"

19
usr.sbin/pppd/pathnames.h Normal file
View File

@ -0,0 +1,19 @@
/*
* define path names
*
* $Id: pathnames.h,v 1.4 1994/05/18 06:34:46 paulus Exp $
*/
#if defined(STREAMS) || defined(ultrix)
#define _PATH_PIDFILE "/etc/ppp"
#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"
#define _PATH_IPUP "/etc/ppp/ip-up"
#define _PATH_IPDOWN "/etc/ppp/ip-down"
#define _PATH_TTYOPT "/etc/ppp/options."
#define _PATH_USEROPT ".ppprc"

41
usr.sbin/pppd/ppp.h Normal file
View File

@ -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 1993/11/11 03:54:25 paulus 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__ */

701
usr.sbin/pppd/pppd.8 Normal file
View File

@ -0,0 +1,701 @@
.\" manual page [] for pppd 2.0
.\" $Id: pppd.8,v 1.7 1994/06/09 01:50:48 paulus Exp $
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
.\" IP indented paragraph
.\" TP hanging label
.TH PPPD 8
.SH NAME
pppd \- Point to Point Protocol daemon
.SH SYNOPSIS
.B pppd
[
.I options
] [
.I tty_name
] [
.I speed
]
.SH DESCRIPTION
.LP
The Point-to-Point Protocol (PPP) provides a method for transmitting
datagrams over serial point-to-point links. PPP
is composed of three parts: a method for encapsulating datagrams over
serial links, an extensible Link Control Protocol (LCP), and
a family of Network Control Protocols (NCP) for establishing
and configuring different network-layer protocols.
.LP
The encapsulation scheme is provided by driver code in the kernel.
.B pppd
provides the basic LCP, authentication support, and an
NCP for establishing and configuring the Internet Protocol (IP)
(called the IP Control Protocol, IPCP).
.SH FREQUENTLY USED OPTIONS
.TP
.I <tty_name>
Communicate over the named device. The string "/dev/"
is prepended if necessary. If no device name is given,
.I pppd
will use the controlling terminal, and will not fork to put itself in
the background.
.TP
.I <speed>
Set the baud rate to <speed>. On systems such as 4.4BSD and NetBSD,
any speed can be specified. Other systems (e.g. SunOS) allow only a
limited set of speeds.
.TP
.B asyncmap \fI<map>
Set the async character map to <map>.
This map describes which control characters cannot be successfully
received over the serial line.
.I pppd
will ask the peer to send these characters as a 2-byte escape sequence.
The argument is a 32 bit hex number
with each bit representing a character to escape.
Bit 0 (00000001) represents the character 0x00;
bit 31 (80000000) represents the character 0x1f or ^_.
If multiple \fBasyncmap\fR options are
given, the values are ORed together.
If no \fBasyncmap\fR option is given, no async character map will be
negotiated for the receive direction; the peer will then escape
\fIall\fR control characters.
.TP
.B auth
Require the peer to authenticate itself before allowing network
packets to be sent or received.
.TP
.B connect \fI<p>
Use the executable or shell command specified by \fI<p>\fR to set up the
serial line. This script would typically use the "chat" program to
dial the modem and start the remote ppp session.
.TP
.B crtscts
Use hardware flow control (i.e. RTS/CTS) to control the flow of data on
the serial port.
.TP
.B xonxoff
Use software flow control (i.e. XON/XOFF) to control the flow of data on
the serial port. This option is not implemented on BSD or Ultrix systems
at present.
.TP
.B -crtscts
A synonym for \fBxonxoff\fR.
.TP
.B defaultroute
Add a default route to the system routing tables, using the peer as
the gateway, when IPCP negotiation is successfully completed.
This entry is removed when the PPP connection is broken.
.TP
.B disconnect \fI<p>
Run the executable or shell command specified by \fI<p>\fR after
\fIpppd\fR has terminated the link. This script could, for example,
issue commands to the modem to cause it to hang up if hardware modem
control signals were not available.
.TP
.B escape \fIxx,yy,...
Specifies that certain characters should be escaped on transmission
(regardless of whether the peer requests them to be escaped with its
async control character map). The characters to be escaped are
specified as a list of hex numbers separated by commas. Note that
almost any character can be specified for the \fBescape\fR option,
unlike the \fBasyncmap\fR option which only allows control characters
to be specified. The characters which may not be escaped are those
with hex values 0x20 - 0x3f or 0x5e.
.TP
.B file \fI<f>
Read options from file <f> (the format is described below).
.TP
.B lock
Specifies that \fIpppd\fR should use a UUCP-style lock on the serial
device to ensure exclusive access to the device.
.TP
.B mru \fI<n>
Set the MRU [Maximum Receive Unit] value to <n> for negotiation.
.I pppd
will ask the peer to send packets of no more than <n> bytes.
The minimum MRU value is 128.
The default MRU value is 1500. A value of 296 is recommended for slow
links (40 bytes for TCP/IP header + 256 bytes of data).
.TP
.B netmask \fI<n>
Set the interface netmask to <n>, a 32 bit netmask in "decimal dot" notation
(e.g. 255.255.255.0).
.TP
.B passive
Enables the "passive" option in the LCP. With this option,
.I pppd
will attempt to initiate a connection; if no reply is received from
the peer,
.I pppd
will then just wait passively for a valid LCP packet from the peer
(instead of exiting, as it does without this option).
.TP
.B silent
With this option,
.I pppd
will not transmit LCP packets to initiate a connection until a valid
LCP packet is received from the peer (as for the "passive" option with
old versions of \fIpppd\fR).
.SH OPTIONS
.TP
.I <local_IP_address>\fB:\fI<remote_IP_address>
Set the local and/or remote interface IP addresses. Either one may be
omitted. The IP addresses can be specified with a host name or in
decimal dot notation (e.g. 150.234.56.78). The default local
address is the (first) IP address of the system (unless the
.B noipdefault
option is given). The remote address will be obtained from the peer
if not specified in any option. Thus, in simple cases, this option is
not required.
If a local and/or remote IP address is specified with this option,
.I pppd
will not accept a different value from the peer in the IPCP
negotiation, unless the
.B ipcp-accept-local
and/or
.B ipcp-accept-remote
options are given, respectively.
.TP
.B -all
Don't request or allow negotiation of any options for LCP and IPCP (use
default values).
.TP
.B -ac
Disable Address/Control compression negotiation (use default, i.e.
address/control field disabled).
.TP
.B -am
Disable asyncmap negotiation (use the default asyncmap, i.e. escape
all control characters).
.TP
.B -as \fI<n>
Same as
.B asyncmap \fI<n>
.TP
.B -d
Increase debugging level (same as the \fBdebug\fR option).
.TP
.B -detach
Don't fork to become a background process (otherwise
.I pppd
will do so if a serial device is specified).
.TP
.B -ip
Disable IP address negotiation (with this option, the remote IP
address must be specified with an option on the command line or in an
options file).
.TP
.B -mn
Disable magic number negotiation. With this option,
.I pppd
cannot detect a looped-back line.
.TP
.B -mru
Disable MRU [Maximum Receive Unit] negotiation (use default, i.e. 1500).
.TP
.B -p
Same as the
.B passive
option.
.TP
.B -pc
Disable protocol field compression negotiation (use default, i.e.
protocol field compression disabled).
.TP
.B +ua \fI<p>
Agree to authenticate using PAP [Password Authentication Protocol] if
requested by the peer, and
use the data in file <p> for the user and password to send to the
peer. The file contains the remote user name, followed by a newline,
followed by the remote password, followed by a newline. This option
is obsolescent.
.TP
.B +pap
Require the peer to authenticate itself using PAP.
.TP
.B -pap
Don't agree to authenticate using PAP.
.TP
.B +chap
Require the peer to authenticate itself using CHAP [Cryptographic
Handshake Authentication Protocol] authentication.
.TP
.B -chap
Don't agree to authenticate using CHAP.
.TP
.B -vj
Disable negotiation of Van Jacobson style IP header compression (use
default, i.e. no compression).
.TP
.B debug
Increase debugging level (same as \fB\-d\fR).
If this
option is given, \fIpppd\fR will log the contents of all control
packets sent or received in a readable form. The packets are logged
through syslog with facility \fIdaemon\fR and level \fIdebug\fR. This
information can be directed to a file by setting up /etc/syslog.conf
appropriately (see syslog.conf(5)). (If \fIpppd\fR is compiled with
extra debugging enabled, it will log messages using facility
\fIlocal2\fR instead of \fIdaemon\fR).
.TP
.B domain \fI<d>
Append the domain name <d> to the local host name for authentication
purposes. For example, if gethostname() returns the name porsche, but the
fully qualified domain name is porsche.Quotron.COM, you would use the
domain option to set the domain name to Quotron.COM.
.TP
.B modem
Use the modem control lines. On Ultrix, this option implies hardware
flow control, as for the \fBcrtscts\fR option. (This option is not fully
implemented.)
.TP
.B kdebug \fIn
Enable debugging code in the kernel-level PPP driver. The argument
\fIn\fR is a number which is the sum of the following values: 1 to
enable general debug messages, 2 to request that the contents of
received packets be printed, and 4 to request that the contents of
transmitted packets be printed.
.TP
.B local
Don't use the modem control lines.
.TP
.B mtu \fI<n>
Set the MTU [Maximum Transmit Unit] value to \fI<n>\fR. Unless the
peer requests a smaller value via MRU negotiation, \fIpppd\fR will
request that the kernel networking code send data packets of no more
than \fIn\fR bytes through the PPP network interface.
.TP
.B name \fI<n>
Set the name of the local system for authentication purposes to <n>.
.TP
.B user \fI<u>
Set the user name to use for authenticating this machine with the peer
using PAP to <u>.
.TP
.B usehostname
Enforce the use of the hostname as the name of the local system for
authentication purposes (overrides the
.B name
option).
.TP
.B remotename \fI<n>
Set the assumed name of the remote system for authentication purposes
to <n>.
.TP
.B proxyarp
Add an entry to this system's ARP [Address Resolution Protocol] table
with the IP address of the peer and the Ethernet address of this
system.
.TP
.B login
Use the system password database for authenticating the peer using
PAP.
.TP
.B noipdefault
Disables the default behaviour when no local IP address is specified,
which is to determine (if possible) the local IP address from the
hostname. With this option, the peer will have to supply the local IP
address during IPCP negotiation (unless it specified explicitly on the
command line or in an options file).
.TP
.B lcp-echo-interval \fI<n>
If this option is given, \fIpppd\fR will send an LCP echo-request
frame to the peer every \fIn\fR seconds. Under Linux, the
echo-request is sent when no packets have been received from the peer
for \fIn\fR seconds. Normally the peer should respond to the
echo-request by sending an echo-reply. This option can be used with
the \fIlcp-echo-failure\fR option to detect that the peer is no longer
connected.
.TP
.B lcp-echo-failure \fI<n>
If this option is given, \fIpppd\fR will presume the peer to be dead
if \fIn\fR LCP echo-requests are sent without receiving a valid LCP
echo-reply. If this happens, \fIpppd\fR will terminate the
connection. Use of this option requires a non-zero value for the
\fIlcp-echo-interval\fR parameter. This option can be used to enable
\fIpppd\fR to terminate after the physical connection has been broken
(e.g., the modem has hung up) in situations where no hardware modem
control lines are available.
.TP
.B lcp-restart \fI<n>
Set the LCP restart interval (retransmission timeout) to <n> seconds
(default 3).
.TP
.B lcp-max-terminate \fI<n>
Set the maximum number of LCP terminate-request transmissions to <n>
(default 3).
.TP
.B lcp-max-configure \fI<n>
Set the maximum number of LCP configure-request transmissions to <n>
(default 10).
.TP
.B lcp-max-failure \fI<n>
Set the maximum number of LCP configure-NAKs returned before starting
to send configure-Rejects instead to <n> (default 10).
.TP
.B ipcp-restart \fI<n>
Set the IPCP restart interval (retransmission timeout) to <n> seconds
(default 3).
.TP
.B ipcp-max-terminate \fI<n>
Set the maximum number of IPCP terminate-request transmissions to <n>
(default 3).
.TP
.B ipcp-max-configure \fI<n>
Set the maximum number of IPCP configure-request transmissions to <n>
(default 10).
.TP
.B ipcp-max-failure \fI<n>
Set the maximum number of IPCP configure-NAKs returned before starting
to send configure-Rejects instead to <n> (default 10).
.TP
.B pap-restart \fI<n>
Set the PAP restart interval (retransmission timeout) to <n> seconds
(default 3).
.TP
.B pap-max-authreq \fI<n>
Set the maximum number of PAP authenticate-request transmissions to
<n> (default 10).
.TP
.B chap-restart \fI<n>
Set the CHAP restart interval (retransmission timeout for challenges)
to <n> seconds (default 3).
.TP
.B chap-max-challenge \fI<n>
Set the maximum number of CHAP challenge transmissions to <n> (default
10).
.TP
.B chap-interval \fI<n>
If this option is given,
.I pppd
will rechallenge the peer every <n> seconds.
.TP
.B ipcp-accept-local
With this option,
.I pppd
will accept the peer's idea of our local IP address, even if the
local IP address was specified in an option.
.TP
.B ipcp-accept-remote
With this option,
.I pppd
will accept the peer's idea of its (remote) IP address, even if the
remote IP address was specified in an option.
.SH OPTIONS FILES
Options can be taken from files as well as the command line.
.I pppd
reads options from the files /etc/ppp/options and ~/.ppprc before
looking at the command line. An options file is parsed into a series
of words, delimited by whitespace. Whitespace can be included in a
word by enclosing the word in quotes ("). A backslash (\\) quotes the
following character. A hash (#) starts a comment, which continues
until the end of the line.
.SH AUTHENTICATION
.I pppd
provides system administrators with sufficient access control that PPP
access to a server machine can be provided to legitimate users without
fear of compromising the security of the server or the network it's
on. In part this is provided by the /etc/ppp/options file, where the
administrator can place options to require authentication whenever
.I pppd
is run, and in part by the PAP and CHAP secrets files, where the
administrator can restrict the set of IP addresses which individual
users may use.
.LP
The default behaviour of
.I pppd
is to agree to authenticate if requested, and to not
require authentication from the peer. However,
.I pppd
will not agree to
authenticate itself with a particular protocol if it has no secrets
which could be used to do so.
.LP
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
.I pppd
can be both a server
and client, and that different protocols can be used in the two
directions if desired.
.LP
A secrets file is parsed into words as for a options file. A secret
is specified by a line containing at least 3 words, in the order
client, 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, \fIpppd\fR takes the best match, i.e.
the match with the fewest wildcards.
.LP
Thus a secrets file contains both secrets for use in authenticating
other hosts, plus secrets which we use for authenticating ourselves to
others. Which secret to use is chosen based on the names of the host
(the `local name') and its peer (the `remote name'). The local name
is set as follows:
.TP 3
if the \fBusehostname\fR option is given,
then the local name is the hostname of this machine
(with the domain appended, if given)
.TP 3
else if the \fBname\fR option is given,
then use the argument of the first \fBname\fR option seen
.TP 3
else if the local IP address is specified with a hostname,
then use that name
.TP 3
else use the hostname of this machine (with the domain appended, if given)
.LP
When authenticating ourselves using PAP, there is also a `username'
which is the local name by default, but can be set with the \fBuser\fR
option or the \fB+ua\fR option.
.LP
The remote name is set as follows:
.TP 3
if the \fBremotename\fR option is given,
then use the argument of the last \fBremotename\fR option seen
.TP 3
else if the remote IP address is specified with a hostname,
then use that host name
.TP 3
else the remote name is the null string "".
.LP
Secrets are selected from the PAP secrets file as follows:
.TP 2
*
For authenticating the peer, look for a secret with client ==
username specified in the PAP authenticate-request, and server ==
local name.
.TP 2
*
For authenticating ourselves to the peer, look for a secret with
client == our username, server == remote name.
.LP
When authenticating the peer with PAP, a secret of "" matches any
password supplied by the peer. If the password doesn't match the
secret, the password is encrypted using crypt() and checked against
the secret again; thus secrets for authenticating the peer can be
stored in encrypted form. If the \fBlogin\fR option was specified, the
username and password are also checked against the system password
database. Thus, the system administrator can set up the pap-secrets
file to allow PPP access only to certain users, and to restrict the
set of IP addresses that each user can use.
.LP
Secrets are selected from the CHAP secrets file as follows:
.TP 2
*
For authenticating the peer, look for a secret with client == name
specified in the CHAP-Response message, and server == local name.
.TP 2
*
For authenticating ourselves to the peer, look for a secret with
client == local name, and server == name specified in the
CHAP-Challenge message.
.LP
Authentication must be satisfactorily completed before IPCP (or any
other Network Control Protocol) can be started. If authentication
fails, \fIpppd\fR will terminated the link (by closing LCP). If IPCP
negotiates an unacceptable IP address for the remote host, IPCP will
be closed. IP packets can only be sent or received when IPCP is open.
.LP
In some cases it is desirable to allow some hosts which can't
authenticate themselves to connect and use one of a restricted set of
IP addresses, even when the local host generally requires
authentication. If the peer refuses to authenticate itself when
requested, \fIpppd\fR takes that as equivalent to authenticating with
PAP using the empty string for the username and password. Thus, by
adding a line to the pap-secrets file which specifies the empty string
for the client and password, it is possible to allow restricted access
to hosts which refuse to authenticate themselves.
.SH ROUTING
.LP
When IPCP negotiation is completed successfully,
.I pppd
will inform the kernel of the local and remote IP addresses for the
ppp interface. This is sufficient to create a
host route to the remote end of the link, which will enable the peers
to exchange IP packets. Communication with other machines generally
requires further modification to routing tables and/or ARP (Address
Resolution Protocol) tables. In some cases this will be done
automatically through the actions of the \fIrouted\fR or \fIgated\fR
daemons, but in most cases some further intervention is required.
.LP
Sometimes it is desirable
to add a default route through the remote host, as in the case of a
machine whose only connection to the Internet is through the ppp
interface. The \fBdefaultroute\fR option causes \fIpppd\fR to create such a
default route when IPCP comes up, and delete it when the link is
terminated.
.LP
In some cases it is desirable to use proxy ARP, for example on a
server machine connected to a LAN, in order to allow other hosts to
communicate with the remote host. The \fBproxyarp\fR option causes \fIpppd\fR
to look for a network interface on the same subnet as the remote host
(an interface supporting broadcast and ARP, which is up and not a
point-to-point or loopback interface). If found, \fIpppd\fR creates a
permanent, published ARP entry with the IP address of the remote host
and the hardware address of the network interface found.
.SH EXAMPLES
.LP
In the simplest case, you can connect the serial ports of two machines
and issue a command like
.IP
pppd /dev/ttya 9600 passive
.LP
to each machine, assuming there is no \fIgetty\fR running on the
serial ports. If one machine has a \fIgetty\fR running, you can use
\fIkermit\fR or \fItip\fR on the other machine to log in to the first
machine and issue a command like
.IP
pppd passive
.LP
Then exit from the communications program (making sure the connection
isn't dropped), and issue a command like
.IP
pppd /dev/ttya 9600
.LP
The process of logging in to the other machine and starting \fIpppd\fR
can be automated by using the \fBconnect\fR option to run \fIchat\fR,
for example:
.IP
pppd /dev/ttya 38400 connect 'chat "" "" "login:" "username"
"Password:" "password" "% " "exec pppd passive"'
.LP
(Note however that running chat like this will leave the password
visible in the parameter list of pppd and chat.)
.LP
If your serial connection is any more complicated than a piece of
wire, you may need to arrange for some control characters to be
escaped. In particular, it is often useful to escape XON (^Q) and
XOFF (^S), using \fBasyncmap a0000\fR. If the path includes a telnet,
you probably should escape ^] as well (\fBasyncmap 200a0000\fR).
If the path includes an rlogin, you will need to use the \fBescape
ff\fR option on the end which is running the rlogin client, since many
rlogin implementations are not
transparent; they will remove the sequence [0xff, 0xff, 0x73, 0x73,
followed by any 8 bytes] from the stream.
.SH DIAGNOSTICS
.LP
Messages are sent to the syslog daemon using facility LOG_DAEMON.
(This can be overriden by recompiling \fIpppd\fR with the macro
LOG_PPP defined as the desired facility.) In order to see the error
and debug messages, you will need to edit your /etc/syslog.conf file
to direct the messages to the desired output device or file.
.LP
The \fBdebug\fR option causes the contents of all control packets sent
or received to be logged, that is, all LCP, PAP, CHAP or IPCP packets.
This can be useful if the PPP negotiation does not succeed.
If debugging is enabled at compile time, \fIpppd\fR uses facility
LOG_LOCAL2 instead of LOG_DAEMON, and the \fBdebug\fR option
causes additional debugging messages to be logged.
.LP
Debugging can also be enabled by sending a
SIGUSR1 to the
.I pppd
process.
Debugging may be disabled by sending a SIGUSR2 to the
.I pppd
process.
.SH FILES
.TP
.B /var/run/ppp\fIn\fB.pid \fR(BSD), \fB/etc/ppp/ppp\fIn\fB.pid \fR(SunOS)
Process-ID for \fIpppd\fR process on ppp interface unit \fIn\fR.
.TP
.B /etc/ppp/ip-up
A program or script which is executed when the link is available for
sending and receiving IP packets (that is, IPCP has come up). It is
executed with the parameters \fIinterface-name tty-device speed
local-IP-address remote-IP-address\fR.
.IP
This program or script is executed with the same real and effective
user-ID as \fIpppd\fR, that is, at least the effective user-ID and
possibly the real user-ID will be \fBroot\fR. This is so that it can
be used to manipulate routes, run privileged daemons (e.g.
\fBsendmail\fR), etc. Be careful that the contents of the
/etc/ppp/ip-up and /etc/ppp/ip-down scripts do not compromise your
system's security.
.TP
.B /etc/ppp/ip-down
A program or script which is executed when the link is no longer
available for sending and receiving IP packets. This script can be
used for undoing the effects of the /etc/ppp/ip-up script. It is
invoked with the same parameters as the ip-up script, and the same
security considerations apply, since it is executed with the same
effective and real user-IDs as \fIpppd\fR.
.TP
.B /etc/ppp/pap-secrets
Usernames, passwords and IP addresses for PAP authentication.
.TP
.B /etc/ppp/chap-secrets
Names, secrets and IP addresses for CHAP authentication.
.TP
.B /etc/ppp/options
System default options for
.I pppd,
read before user default options or command-line options.
.TP
.B ~/.ppprc
User default options, read before command-line options.
.TP
.B /etc/ppp/options.\fIttyname
System default options for the serial port being used, read after
command-line options.
.SH SEE ALSO
.TP
.B RFC1144
Jacobson, V.
.I Compressing TCP/IP headers for low-speed serial links.
1990 February.
.TP
.B RFC1321
Rivest, R.
.I The MD5 Message-Digest Algorithm.
1992 April.
.TP
.B RFC1332
McGregor, G.
.I PPP Internet Protocol Control Protocol (IPCP).
1992 May.
.TP
.B RFC1334
Lloyd, B.; Simpson, W.A.
.I PPP authentication protocols.
1992 October.
.TP
.B RFC1548
Simpson, W.A.
.I The Point\-to\-Point Protocol (PPP).
1993 December.
.TP
.B RFC1549
Simpson, W.A.
.I PPP in HDLC Framing.
1993 December
.SH NOTES
The following signals have the specified effect when sent to the
.I pppd
process.
.TP
.B SIGINT, SIGTERM
These signals cause \fIpppd\fR to terminate the link (by closing LCP),
restore the serial device settings, and exit.
.TP
.B SIGHUP
Indicates that the physical layer has been disconnected. \fIpppd\fR
will attempt to restore the serial device settings (this may produce
error messages on Suns), and then exit.
.SH BUGS
The use of the modem control lines and the effects of the \fBmodem\fR
and \fBlocal\fR options are not well defined.
.SH AUTHORS
Drew Perkins,
Brad Clements,
Karl Fox,
Greg Christy,
Brad Parker (brad@fcr.com),
Paul Mackerras (paulus@cs.anu.edu.au)

215
usr.sbin/pppd/pppd.h Normal file
View File

@ -0,0 +1,215 @@
/*
* pppd.h - PPP daemon 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: pppd.h,v 1.3 1994/05/26 06:43:42 paulus Exp $
*/
/*
* TODO:
*/
#ifndef __PPPD_H__
#define __PPPD_H__
#include "args.h"
#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 */
/*
* Global variables.
*/
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 outpacket_buf[]; /* buffer for outgoing packets */
extern int phase; /* See values below */
/*
* Values for phase.
*/
#define PHASE_DEAD 0
#define PHASE_ESTABLISH 1
#define PHASE_AUTHENTICATE 2
#define PHASE_NETWORK 3
#define PHASE_TERMINATE 4
/*
* Prototypes.
*/
void quit __ARGS((void)); /* Cleanup and exit */
void timeout __ARGS((void (*)(), caddr_t, int));
/* 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 */
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 */
/*
* Inline versions of get/put char/short/long.
* Pointer is advanced; we assume that both arguments
* are lvalues and will already be in registers.
* cp MUST be u_char *.
*/
#define GETCHAR(c, cp) { \
(c) = *(cp)++; \
}
#define PUTCHAR(c, cp) { \
*(cp)++ = (u_char) (c); \
}
#define GETSHORT(s, cp) { \
(s) = *(cp)++ << 8; \
(s) |= *(cp)++; \
}
#define PUTSHORT(s, cp) { \
*(cp)++ = (u_char) ((s) >> 8); \
*(cp)++ = (u_char) (s); \
}
#define GETLONG(l, cp) { \
(l) = *(cp)++ << 8; \
(l) |= *(cp)++; (l) <<= 8; \
(l) |= *(cp)++; (l) <<= 8; \
(l) |= *(cp)++; \
}
#define PUTLONG(l, cp) { \
*(cp)++ = (u_char) ((l) >> 24); \
*(cp)++ = (u_char) ((l) >> 16); \
*(cp)++ = (u_char) ((l) >> 8); \
*(cp)++ = (u_char) (l); \
}
#define INCPTR(n, cp) ((cp) += (n))
#define DECPTR(n, cp) ((cp) -= (n))
/*
* System dependent definitions for user-level 4.3BSD UNIX implementation.
*/
#define DEMUXPROTREJ(u, p) demuxprotrej(u, p)
#define TIMEOUT(r, f, t) timeout((r), (f), (t))
#define UNTIMEOUT(r, f) untimeout((r), (f))
#define BCOPY(s, d, l) memcpy(d, s, l)
#define BZERO(s, n) memset(s, 0, n)
#define EXIT(u) quit()
#define PRINTMSG(m, l) { m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); }
/*
* MAKEHEADER - Add Header fields to a packet.
*/
#define MAKEHEADER(p, t) { \
PUTCHAR(ALLSTATIONS, p); \
PUTCHAR(UI, p); \
PUTSHORT(t, p); }
#ifdef DEBUGALL
#define DEBUGMAIN 1
#define DEBUGFSM 1
#define DEBUGLCP 1
#define DEBUGIPCP 1
#define DEBUGUPAP 1
#define DEBUGCHAP 1
#endif
#ifndef LOG_PPP /* we use LOG_LOCAL2 for syslog by default */
#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUG) \
|| defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
|| defined(DEBUGCHAP)
#define LOG_PPP LOG_LOCAL2
#else
#define LOG_PPP LOG_DAEMON
#endif
#endif /* LOG_PPP */
#ifdef DEBUGMAIN
#define MAINDEBUG(x) if (debug) syslog x
#else
#define MAINDEBUG(x)
#endif
#ifdef DEBUGFSM
#define FSMDEBUG(x) if (debug) syslog x
#else
#define FSMDEBUG(x)
#endif
#ifdef DEBUGLCP
#define LCPDEBUG(x) if (debug) syslog x
#else
#define LCPDEBUG(x)
#endif
#ifdef DEBUGIPCP
#define IPCPDEBUG(x) if (debug) syslog x
#else
#define IPCPDEBUG(x)
#endif
#ifdef DEBUGUPAP
#define UPAPDEBUG(x) if (debug) syslog x
#else
#define UPAPDEBUG(x)
#endif
#ifdef DEBUGCHAP
#define CHAPDEBUG(x) if (debug) syslog x
#else
#define CHAPDEBUG(x)
#endif
#ifndef SIGTYPE
#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
#define SIGTYPE void
#else
#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__ */

743
usr.sbin/pppd/sys-bsd.c Normal file
View File

@ -0,0 +1,743 @@
/*
* 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.7 1994/05/30 06:10:07 paulus 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>
#if RTM_VERSION >= 3
#include <netinet/if_ether.h>
#endif
#include "pppd.h"
#include "ppp.h"
static int initdisc = -1; /* Initial TTY discipline */
extern int kdebugflag;
static int rtm_seq;
/*
* establish_ppp - Turn the serial port into a ppp interface.
*/
void
establish_ppp()
{
int pppdisc = PPPDISC;
int x;
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);
}
/*
* Enable debug in the driver if requested.
*/
if (kdebugflag) {
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
} else {
x |= (kdebugflag & 0xFF) * SC_DEBUG;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
}
}
}
/*
* disestablish_ppp - Restore the serial port to normal operation.
* This shouldn't call die() because it's called from die().
*/
void
disestablish_ppp()
{
int x;
char *s;
if (initdisc >= 0) {
/*
* Check whether the link seems not to be 8-bit clean.
*/
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
s = NULL;
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
case SC_RCV_B7_0:
s = "bit 7 set to 1";
break;
case SC_RCV_B7_1:
s = "bit 7 set to 0";
break;
case SC_RCV_EVNP:
s = "odd parity";
break;
case SC_RCV_ODDP:
s = "even parity";
break;
}
if (s != NULL) {
syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
syslog(LOG_WARNING, "All received characters had %s", s);
}
}
if (ioctl(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 (debug)
log_packet(p, len, "sent ");
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_set_xaccm - set the extended transmit ACCM for the interface.
*/
void
ppp_set_xaccm(unit, accm)
int unit;
ext_accm accm;
{
if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
}
/*
* ppp_recv_config - configure the receive-side characteristics of
* the ppp interface.
*/
void
ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
int unit, mru;
u_long asyncmap;
int pcomp, accomp;
{
int x;
if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
quit();
}
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();
}
}
/*
* sifvjcomp - config tcp header compression
*/
int
sifvjcomp(u, vjcomp, cidcomp, maxcid)
int u, vjcomp, cidcomp, maxcid;
{
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;
}
if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifup - Config the interface up and enable IP packets to pass.
*/
int
sifup(u)
int u;
{
struct ifreq ifr;
u_int x;
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;
}
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
return 0;
}
x |= SC_ENABLE_IP;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifdown - Config the interface down and disable IP.
*/
int
sifdown(u)
int u;
{
struct ifreq ifr;
u_int x;
int rv;
rv = 1;
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
rv = 0;
} else {
x &= ~SC_ENABLE_IP;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
rv = 0;
}
}
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
rv = 0;
} else {
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
rv = 0;
}
}
return rv;
}
/*
* 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)
int u;
u_long 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)
int u;
u_long 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)
int u;
u_long g;
{
return dodefaultroute(g, 's');
}
/*
* cifdefaultroute - delete a default route through the address given.
*/
int
cifdefaultroute(u, g)
int u;
u_long g;
{
return dodefaultroute(g, 'c');
}
/*
* dodefaultroute - talk to a routing socket to add/delete a default route.
*/
int
dodefaultroute(g, cmd)
u_long g;
int cmd;
{
int routes;
struct {
struct rt_msghdr hdr;
struct sockaddr_in dst;
struct sockaddr_in gway;
struct sockaddr_in mask;
} rtmsg;
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
syslog(LOG_ERR, "%cifdefaultroute: opening routing socket: %m", cmd);
return 0;
}
memset(&rtmsg, 0, sizeof(rtmsg));
rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY;
rtmsg.hdr.rtm_version = RTM_VERSION;
rtmsg.hdr.rtm_seq = ++rtm_seq;
rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
rtmsg.dst.sin_len = sizeof(rtmsg.dst);
rtmsg.dst.sin_family = AF_INET;
rtmsg.gway.sin_len = sizeof(rtmsg.gway);
rtmsg.gway.sin_family = AF_INET;
rtmsg.gway.sin_addr.s_addr = g;
rtmsg.mask.sin_len = sizeof(rtmsg.dst);
rtmsg.mask.sin_family = AF_INET;
rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
syslog(LOG_ERR, "%s default route: %m", cmd=='s'? "add": "delete");
close(routes);
return 0;
}
close(routes);
return 1;
}
#if RTM_VERSION >= 3
/*
* sifproxyarp - Make a proxy ARP entry for the peer.
*/
static struct {
struct rt_msghdr hdr;
struct sockaddr_inarp dst;
struct sockaddr_dl hwa;
char extra[128];
} arpmsg;
static int arpmsg_valid;
int
sifproxyarp(unit, hisaddr)
int unit;
u_long hisaddr;
{
int routes;
int l;
/*
* Get the hardware address of an interface on the same subnet
* as our local address.
*/
memset(&arpmsg, 0, sizeof(arpmsg));
if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
return 0;
}
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
return 0;
}
arpmsg.hdr.rtm_type = RTM_ADD;
arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
arpmsg.hdr.rtm_version = RTM_VERSION;
arpmsg.hdr.rtm_seq = ++rtm_seq;
arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
arpmsg.hdr.rtm_inits = RTV_EXPIRE;
arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
arpmsg.dst.sin_family = AF_INET;
arpmsg.dst.sin_addr.s_addr = hisaddr;
arpmsg.dst.sin_other = SIN_PROXY;
arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+ arpmsg.hwa.sdl_len;
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
syslog(LOG_ERR, "add proxy arp entry: %m");
close(routes);
return 0;
}
close(routes);
arpmsg_valid = 1;
return 1;
}
/*
* cifproxyarp - Delete the proxy ARP entry for the peer.
*/
int
cifproxyarp(unit, hisaddr)
int unit;
u_long hisaddr;
{
int routes;
if (!arpmsg_valid)
return 0;
arpmsg_valid = 0;
arpmsg.hdr.rtm_type = RTM_DELETE;
arpmsg.hdr.rtm_seq = ++rtm_seq;
if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
syslog(LOG_ERR, "sifproxyarp: opening routing socket: %m");
return 0;
}
if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
syslog(LOG_ERR, "delete proxy arp entry: %m");
close(routes);
return 0;
}
close(routes);
return 1;
}
#else /* RTM_VERSION */
/*
* sifproxyarp - Make a proxy ARP entry for the peer.
*/
int
sifproxyarp(unit, hisaddr)
int unit;
u_long hisaddr;
{
struct arpreq arpreq;
struct {
struct sockaddr_dl sdl;
char space[128];
} dls;
BZERO(&arpreq, sizeof(arpreq));
/*
* Get the hardware address of an interface on the same subnet
* as our local address.
*/
if (!get_ether_addr(hisaddr, &dls.sdl)) {
syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
return 0;
}
arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
arpreq.arp_ha.sa_family = AF_UNSPEC;
BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
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;
}
#endif /* RTM_VERSION */
/*
* 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_dl *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;
BCOPY(dla, hwaddr, dla->sdl_len);
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;
}

830
usr.sbin/pppd/sys-linux.c Normal file
View File

@ -0,0 +1,830 @@
/*
* sys-linux.c - System-dependent procedures for setting up
* PPP interfaces on Linux systems
*
* 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 <syslog.h>
#include <string.h>
#include <time.h>
#include <memory.h>
#include <utmp.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <mntent.h>
#include <net/if.h>
#include <linux/ppp.h>
#include <linux/route.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <signal.h>
#include "pppd.h"
#include "ppp.h"
#include "fsm.h"
#include "ipcp.h"
static int initdisc = -1; /* Initial TTY discipline */
static int prev_kdebugflag = 0;
extern int kdebugflag;
extern u_long netmask;
#define MAX_IFS 32
/* prototypes */
void die __ARGS((int));
/*
* SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
* if it exists.
*/
#define SET_SA_FAMILY(addr, family) \
memset ((char *) &(addr), '\0', sizeof(addr)); \
addr.sa_family = (family);
/*
* set_kdebugflag - Define the debugging level for the kernel
*/
int set_kdebugflag (int requested_level)
{
if (ioctl(fd, PPPIOCGDEBUG, &prev_kdebugflag) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCGDEBUG): %m");
return (0);
}
if (prev_kdebugflag != requested_level) {
if (ioctl(fd, PPPIOCSDEBUG, &requested_level) < 0) {
syslog (LOG_ERR, "ioctl(PPPIOCSDEBUG): %m");
return (0);
}
syslog(LOG_INFO, "set kernel debugging level to %d", requested_level);
}
return (1);
}
/*
* establish_ppp - Turn the serial port into a ppp interface.
*/
void establish_ppp (void)
{
int pppdisc = N_PPP;
int sig = SIGIO;
if (ioctl(fd, PPPIOCSINPSIG, &sig) == -1) {
syslog(LOG_ERR, "ioctl(PPPIOCSINPSIG): %m");
die(1);
}
if (ioctl(fd, TIOCEXCL, 0) < 0) {
syslog (LOG_WARNING, "ioctl(TIOCEXCL): %m");
}
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);
}
if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
die (1);
}
set_kdebugflag (kdebugflag);
}
/*
* disestablish_ppp - Restore the serial port to normal operation.
* This shouldn't call die() because it's called from die().
*/
void disestablish_ppp(void)
{
int x;
char *s;
if (initdisc >= 0) {
set_kdebugflag (prev_kdebugflag);
/*
* Check whether the link seems not to be 8-bit clean.
*/
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
s = NULL;
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
case SC_RCV_B7_0:
s = "bit 7 set to 1";
break;
case SC_RCV_B7_1:
s = "bit 7 set to 0";
break;
case SC_RCV_EVNP:
s = "odd parity";
break;
case SC_RCV_ODDP:
s = "even parity";
break;
}
if (s != NULL) {
syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
syslog(LOG_WARNING, "All received characters had %s", s);
}
}
if (ioctl(fd, TIOCSETD, &initdisc) < 0)
syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
if (ioctl(fd, TIOCNXCL, 0) < 0)
syslog (LOG_WARNING, "ioctl(TIOCNXCL): %m");
initdisc = -1;
}
}
/*
* output - Output PPP packet.
*/
void output (int unit, unsigned char *p, int len)
{
if (unit != 0)
MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
if (debug)
log_packet(p, len, "sent ");
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 (unsigned char *buf)
{
int len;
len = read(fd, buf, MTU + DLLHEADERLEN);
if (len < 0) {
if (errno == EWOULDBLOCK) {
#if 0
MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
#endif
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 (int unit,int mtu,u_long asyncmap,int pcomp,int accomp)
{
u_int x;
struct ifreq ifr;
MAINDEBUG ((LOG_DEBUG, "send_config: mtu = %d\n", mtu));
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();
}
MAINDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
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;
MAINDEBUG ((LOG_DEBUG, "send_config: flags = %x\n", x));
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
quit();
}
}
/*
* ppp_set_xaccm - set the extended transmit ACCM for the interface.
*/
void
ppp_set_xaccm(unit, accm)
int unit;
ext_accm accm;
{
MAINDEBUG ((LOG_DEBUG, "set_xaccm: %08lx %08lx %08lx %08lx\n",
accm[0], accm[1], accm[2], accm[3]));
if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
}
/*
* ppp_recv_config - configure the receive-side characteristics of
* the ppp interface.
*/
void ppp_recv_config (int unit,int mru,u_long asyncmap,int pcomp,int accomp)
{
u_int x;
MAINDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
MAINDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
if (ioctl(fd, PPPIOCRASYNCMAP, (caddr_t) &asyncmap) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCRASYNCMAP): %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;
MAINDEBUG ((LOG_DEBUG, "recv_config: flags = %x\n", x));
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
quit();
}
}
/*
* sifvjcomp - config tcp header compression
*/
int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
{
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;
}
if (vjcomp) {
if (ioctl (fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
syslog (LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
}
return 1;
}
/*
* sifup - Config the interface up and enable IP packets to pass.
*/
int sifup (int 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 | IFF_POINTOPOINT);
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifdown - Config the interface down and disable IP.
*/
int sifdown (int 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;
ifr.ifr_flags |= IFF_POINTOPOINT;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifaddr - Config the interface IP addresses and netmask.
*/
int sifaddr (int unit, int our_adr, int his_adr, int net_mask)
{
struct ifreq ifr;
struct rtentry rt;
SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
/*
* Set our IP address
*/
((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr;
if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
if (errno != EEXIST)
syslog (LOG_ERR, "ioctl(SIOCAIFADDR): %m");
else
syslog (LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
return (0);
}
/*
* Set the gateway address
*/
((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr;
if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
syslog (LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
return (0);
}
/*
* Set the netmask
*/
if (net_mask != 0) {
((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask;
if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
syslog (LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
return (0);
}
}
/*
* Add the device route
*/
memset (&rt, '\0', sizeof (rt));
SET_SA_FAMILY (rt.rt_dst, AF_INET);
SET_SA_FAMILY (rt.rt_gateway, AF_INET);
rt.rt_dev = ifname; /* MJC */
((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
rt.rt_flags = RTF_UP | RTF_HOST;
if (ioctl(s, SIOCADDRT, &rt) < 0) {
syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m");
return (0);
}
return 1;
}
/*
* cifaddr - Clear the interface IP addresses, and delete routes
* through the interface if possible.
*/
int cifaddr (int unit, int our_adr, int his_adr)
{
struct rtentry rt;
/*
* Delete the route through the device
*/
memset (&rt, '\0', sizeof (rt));
SET_SA_FAMILY (rt.rt_dst, AF_INET);
SET_SA_FAMILY (rt.rt_gateway, AF_INET);
rt.rt_dev = ifname; /* MJC */
((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
rt.rt_flags = RTF_UP | RTF_HOST;
if (ioctl(s, SIOCDELRT, &rt) < 0) {
syslog (LOG_ERR, "ioctl(SIOCDELRT) device route: %m");
return (0);
}
return 1;
}
/*
* path_to_route - determine the path to the proc file system data
*/
FILE *route_fd = (FILE *) 0;
static char route_buffer [100];
static char *path_to_route (void);
static int open_route_table (void);
static void close_route_table (void);
static int read_route_table (struct rtentry *rt);
static int defaultroute_exists (void);
/*
* path_to_route - find the path to the route tables in the proc file system
*/
static char *path_to_route (void)
{
struct mntent *mntent;
FILE *fp;
fp = fopen (MOUNTED, "r");
if (fp != 0) {
while ((mntent = getmntent (fp)) != 0) {
if (strcmp (mntent->mnt_type, MNTTYPE_IGNORE) == 0)
continue;
if (strcmp (mntent->mnt_type, "proc") == 0) {
strncpy (route_buffer, mntent->mnt_dir,
sizeof (route_buffer)-10);
route_buffer [sizeof (route_buffer)-10] = '\0';
strcat (route_buffer, "/net/route");
fclose (fp);
return (route_buffer);
}
}
fclose (fp);
}
syslog (LOG_ERR, "proc file system not mounted");
return 0;
}
/*
* open_route_table - open the interface to the route table
*/
static int open_route_table (void)
{
char *path;
if (route_fd != (FILE *) 0)
close_route_table();
path = path_to_route();
if (path == NULL)
return 0;
route_fd = fopen (path, "r");
if (route_fd == (FILE *) 0) {
syslog (LOG_ERR, "can not open %s: %m", path);
return 0;
}
/* read and discard the header line. */
if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0) {
close_route_table();
return 0;
}
return 1;
}
/*
* close_route_table - close the interface to the route table
*/
static void close_route_table (void)
{
if (route_fd != (FILE *) 0) {
fclose (route_fd);
route_fd = (FILE *) 0;
}
}
/*
* read_route_table - read the next entry from the route table
*/
static int read_route_table (struct rtentry *rt)
{
static char delims[] = " \t\n";
char *dev_ptr, *ptr, *dst_ptr, *gw_ptr, *flag_ptr;
if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
return 0;
memset (rt, '\0', sizeof (struct rtentry));
dev_ptr = strtok (route_buffer, delims); /* interface name */
dst_ptr = strtok (NULL, delims); /* destination address */
gw_ptr = strtok (NULL, delims); /* gateway */
flag_ptr = strtok (NULL, delims); /* flags */
#if 0
ptr = strtok (NULL, delims); /* reference count */
ptr = strtok (NULL, delims); /* useage count */
ptr = strtok (NULL, delims); /* metric */
ptr = strtok (NULL, delims); /* mask */
#endif
((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr =
strtoul (dst_ptr, NULL, 16);
((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr =
strtoul (gw_ptr, NULL, 16);
rt->rt_flags = (short) strtoul (flag_ptr, NULL, 16);
rt->rt_dev = dev_ptr;
return 1;
}
/*
* defaultroute_exists - determine if there is a default route
*/
static int defaultroute_exists (void)
{
struct rtentry rt;
int result = 0;
if (!open_route_table())
return 0;
while (read_route_table(&rt) != 0) {
if (rt.rt_flags & RTF_UP == 0)
continue;
if (((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr == 0L) {
syslog (LOG_ERR,
"ppp not replacing existing default route to %s[%s]",
rt.rt_dev,
inet_ntoa (((struct sockaddr_in *) &rt.rt_gateway)->
sin_addr.s_addr));
result = 1;
break;
}
}
close_route_table();
return result;
}
/*
* sifdefaultroute - assign a default route through the address given.
*/
int sifdefaultroute (int unit, int gateway)
{
struct rtentry rt;
if (defaultroute_exists())
return 0;
memset (&rt, '\0', sizeof (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 = gateway;
rt.rt_flags = RTF_UP | 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 (int unit, int gateway)
{
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 = gateway;
rt.rt_flags = RTF_UP | 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 (int unit, u_long his_adr)
{
struct arpreq arpreq;
memset (&arpreq, '\0', sizeof(arpreq));
/*
* Get the hardware address of an interface on the same subnet
* as our local address.
*/
if (!get_ether_addr(his_adr, &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 = his_adr;
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 (int unit, u_long his_adr)
{
struct arpreq arpreq;
memset (&arpreq, '\0', sizeof(arpreq));
SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
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.
*/
int get_ether_addr (u_long ipaddr, struct sockaddr *hwaddr)
{
struct ifreq *ifr, *ifend, *ifp;
int i;
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;
}
MAINDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
/*
* Scan through looking for an interface with an Internet
* address on the same subnet as `ipaddr'.
*/
ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
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));
MAINDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
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 *) &ifreq.ifr_addr)->sin_addr.s_addr;
MAINDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
ip_ntoa(ina), ntohl(mask)));
if (((ipaddr ^ ina) & mask) != 0)
continue;
break;
}
}
if (ifr >= ifend)
return 0;
syslog(LOG_INFO, "found interface %s for proxy arp", ifreq.ifr_name);
/*
* Now get the hardware address.
*/
if (ioctl (s, SIOCGIFHWADDR, &ifreq) < 0) {
syslog(LOG_ERR, "SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
return 0;
}
hwaddr->sa_family = ARPHRD_ETHER;
#ifndef old_ifr_hwaddr
memcpy (&hwaddr->sa_data, &ifreq.ifr_hwaddr, ETH_ALEN);
#else
memcpy (&hwaddr->sa_data, &ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
#endif
MAINDEBUG ((LOG_DEBUG,
"proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x",
(int) ((unsigned char *) &hwaddr->sa_data)[0],
(int) ((unsigned char *) &hwaddr->sa_data)[1],
(int) ((unsigned char *) &hwaddr->sa_data)[2],
(int) ((unsigned char *) &hwaddr->sa_data)[3],
(int) ((unsigned char *) &hwaddr->sa_data)[4],
(int) ((unsigned char *) &hwaddr->sa_data)[5]));
return 1;
}
/*
* 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(void)
{
int s, ok;
struct ifreq ifr;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 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;
}
int
logwtmp(line, name, host)
char *line, *name, *host;
{
struct utmp ut;
memset (&ut, 0, sizeof (ut));
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
(void)time(&ut.ut_time);
pututline (&ut); /* Write the line to the proper place */
endutent(); /* Indicate operation is complete */
}

730
usr.sbin/pppd/sys-str.c Normal file
View File

@ -0,0 +1,730 @@
/*
* 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 <string.h>
#include <time.h>
#include <utmp.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;
static int pushed_ppp;
extern int hungup; /* has the physical layer been disconnected? */
extern int kdebugflag;
#define PAI_FLAGS_B7_0 0x100
#define PAI_FLAGS_B7_1 0x200
#define PAI_FLAGS_PAR_EVEN 0x400
#define PAI_FLAGS_PAR_ODD 0x800
#define PAI_FLAGS_HIBITS 0xF00
/*
* 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++;
}
/* 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);
}
pushed_ppp = 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);
}
/* Set debug flags in driver */
if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
}
}
/*
* 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()
{
int flags;
char *s;
if (hungup) {
/* we can't push or pop modules after the stream has hung up */
str_module_count = 0;
return;
}
if (pushed_ppp) {
/*
* Check whether the link seems not to be 8-bit clean.
*/
if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
s = NULL;
switch (~flags & PAI_FLAGS_HIBITS) {
case PAI_FLAGS_B7_0:
s = "bit 7 set to 1";
break;
case PAI_FLAGS_B7_1:
s = "bit 7 set to 0";
break;
case PAI_FLAGS_PAR_EVEN:
s = "odd parity";
break;
case PAI_FLAGS_PAR_ODD:
s = "even parity";
break;
}
if (s != NULL) {
syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
syslog(LOG_WARNING, "All received characters had %s", s);
}
}
}
while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */
;
pushed_ppp = 0;
for (; str_module_count > 0; str_module_count--) {
if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
syslog(LOG_WARNING, "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!"));
if (debug)
log_packet(p, len, "sent ");
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? 1: 0);
if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
quit();
}
c = (accomp? 1: 0);
if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
quit();
}
}
/*
* ppp_set_xaccm - set the extended transmit ACCM for the interface.
*/
void
ppp_set_xaccm(unit, accm)
int unit;
ext_accm accm;
{
if (ioctl(fd, SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
}
/*
* ppp_recv_config - configure the receive-side characteristics of
* the ppp interface.
*/
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");
}
if (ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
}
c = 2 + (pcomp? 1: 0);
if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
}
c = 2 + (accomp? 1: 0);
if (ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
}
}
/*
* sifvjcomp - config tcp header compression
*/
int
sifvjcomp(u, vjcomp, cidcomp, maxcid)
int u, vjcomp, cidcomp, maxcid;
{
char x;
x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
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)
int 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)
int 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 u;
u_long 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)
int u;
u_long 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)
int u;
u_long 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)
int u;
u_long 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_WARNING, "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 (which also applies to logwtmp below):
*
* 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;
}
#define WTMPFILE "/usr/adm/wtmp"
int
logwtmp(line, name, host)
char *line, *name, *host;
{
int fd;
struct stat buf;
struct utmp ut;
if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
return;
if (!fstat(fd, &buf)) {
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
(void)time(&ut.ut_time);
if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
(void)ftruncate(fd, buf.st_size);
}
close(fd);
}

663
usr.sbin/pppd/sys-ultrix.c Normal file
View File

@ -0,0 +1,663 @@
/*
* sys-ultrix.c - System-dependent procedures for setting up
* PPP interfaces on Ultrix systems.
*
* 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-ultrix.c,v 1.4 1994/05/25 06:30:49 paulus Exp $";
#endif
/*
* TODO:
*/
#include <syslog.h>
#include <utmp.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <net/if.h>
#include <net/if_ppp.h>
#include <net/route.h>
#include <netinet/in.h>
#include "pppd.h"
#include "ppp.h"
static int initdisc = -1; /* Initial TTY discipline */
extern int kdebugflag;
/*
* establish_ppp - Turn the serial port into a ppp interface.
*/
void
establish_ppp()
{
int pppdisc = PPPDISC;
int x;
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);
}
/*
* Enable debug in the driver if requested.
*/
if (kdebugflag) {
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
} else {
x |= (kdebugflag & 0xFF) * SC_DEBUG;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
}
}
}
/*
* disestablish_ppp - Restore the serial port to normal operation.
* This shouldn't call die() because it's called from die().
*/
void
disestablish_ppp()
{
int x;
char *s;
if (initdisc >= 0) {
/*
* Check whether the link seems not to be 8-bit clean.
*/
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
s = NULL;
switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
case SC_RCV_B7_0:
s = "bit 7 set to 1";
break;
case SC_RCV_B7_1:
s = "bit 7 set to 0";
break;
case SC_RCV_EVNP:
s = "odd parity";
break;
case SC_RCV_ODDP:
s = "even parity";
break;
}
if (s != NULL) {
syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
syslog(LOG_WARNING, "All received characters had %s", s);
}
}
if (ioctl(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 (debug)
log_packet(p, len, "sent ");
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_set_xaccm - set the extended transmit ACCM for the interface.
*/
void
ppp_set_xaccm(unit, accm)
int unit;
ext_accm accm;
{
if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
}
/*
* ppp_recv_config - configure the receive-side characteristics of
* the ppp interface.
*/
void
ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
int unit, mru;
u_long asyncmap;
int pcomp, accomp;
{
int x;
if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
quit();
}
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();
}
}
/*
* sifvjcomp - config tcp header compression
*/
int
sifvjcomp(u, vjcomp, cidcomp, maxcid)
int u, vjcomp, cidcomp, maxcid;
{
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;
}
if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifup - Config the interface up and enable IP packets to pass.
*/
int
sifup(u)
{
struct ifreq ifr;
u_int x;
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;
}
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
return 0;
}
x |= SC_ENABLE_IP;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
return 0;
}
return 1;
}
/*
* sifdown - Config the interface down and disable IP.
*/
int
sifdown(u)
{
struct ifreq ifr;
u_int x;
int rv;
rv = 1;
if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
rv = 0;
} else {
x &= ~SC_ENABLE_IP;
if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
rv = 0;
}
}
strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
rv = 0;
} else {
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
rv = 0;
}
}
return rv;
}
/*
* 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);
/*
* 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_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 + sizeof(struct sockaddr)
);
}
if (ifr >= ifend)
return 0;
syslog(LOG_DEBUG, "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_DLI) {
/* && ifr->ifr_addr.sa_family == AF_LINK) { Per! Kolla !!! ROHACK */
/*
* Found the link-level address - copy it out
*/
dla = (struct sockaddr_dl *)&ifr->ifr_addr;
hwaddr->sa_family = AF_UNSPEC;
BCOPY(dla, hwaddr->sa_data, sizeof(hwaddr->sa_data));
return 1;
}
ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
);
}
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;
}
/*
Seems like strdup() is not part of string package in Ultrix.
If I understood the man-page on the sun this should work.
Robert Olsson
*/
char *strdup( in ) char *in;
{
char* dup;
if(! (dup = (char *) malloc( strlen( in ) +1 ))) return NULL;
(void) strcpy( dup, in );
return dup;
}
/*
* This logwtmp() implementation is subject to the following copyright:
*
* Copyright (c) 1988 The Regents of the University of California.
* 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 University of California, Berkeley. 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.
*/
#define WTMPFILE "/usr/adm/wtmp"
int
logwtmp(line, name, host)
char *line, *name, *host;
{
int fd;
struct stat buf;
struct utmp ut;
if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
return;
if (!fstat(fd, &buf)) {
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
(void)time(&ut.ut_time);
if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
(void)ftruncate(fd, buf.st_size);
}
close(fd);
}

561
usr.sbin/pppd/upap.c Normal file
View File

@ -0,0 +1,561 @@
/*
* upap.c - User/Password Authentication Protocol.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static char rcsid[] = "$Id: upap.c,v 1.2 1994/04/11 07:13:44 paulus Exp $";
#endif
/*
* TODO:
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <syslog.h>
#include "ppp.h"
#include "pppd.h"
#include "upap.h"
upap_state upap[NPPP]; /* UPAP state; one for each unit */
static void upap_timeout __ARGS((caddr_t));
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_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_state *u = &upap[unit];
u->us_unit = unit;
u->us_user = NULL;
u->us_userlen = 0;
u->us_passwd = NULL;
u->us_passwdlen = 0;
u->us_clientstate = UPAPCS_INITIAL;
u->us_serverstate = UPAPSS_INITIAL;
u->us_id = 0;
u->us_timeouttime = UPAP_DEFTIMEOUT;
u->us_maxtransmits = 10;
}
/*
* upap_authwithpeer - Authenticate us with our peer (start client).
*
* Set new state and send authenticate's.
*/
void
upap_authwithpeer(unit, user, password)
int unit;
char *user, *password;
{
upap_state *u = &upap[unit];
/* 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;
}
upap_sauthreq(u); /* Start protocol */
}
/*
* upap_authpeer - Authenticate our peer (start server).
*
* Set new state.
*/
void
upap_authpeer(unit)
int unit;
{
upap_state *u = &upap[unit];
/* 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;
}
/*
* upap_timeout - Timeout expired.
*/
static void
upap_timeout(arg)
caddr_t arg;
{
upap_state *u = (upap_state *) arg;
if (u->us_clientstate != UPAPCS_AUTHREQ)
return;
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_sauthreq(u); /* Send Authenticate-Request */
}
/*
* upap_lowerup - The lower layer is up.
*
* Start authenticating if pending.
*/
void
upap_lowerup(unit)
int unit;
{
upap_state *u = &upap[unit];
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;
}
/*
* upap_lowerdown - The lower layer is down.
*
* Cancel all timeouts.
*/
void
upap_lowerdown(unit)
int unit;
{
upap_state *u = &upap[unit];
if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
UNTIMEOUT(upap_timeout, (caddr_t) u); /* Cancel timeout */
u->us_clientstate = UPAPCS_INITIAL;
u->us_serverstate = UPAPSS_INITIAL;
}
/*
* upap_protrej - Peer doesn't speak this protocol.
*
* This shouldn't happen. In any case, pretend lower layer went down.
*/
void
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);
}
/*
* upap_input - Input UPAP packet.
*/
void
upap_input(unit, inpacket, l)
int unit;
u_char *inpacket;
int l;
{
upap_state *u = &upap[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 (l < UPAP_HEADERLEN) {
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."));
return;
}
if (len > l) {
UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
return;
}
len -= UPAP_HEADERLEN;
/*
* Action depends on code.
*/
switch (code) {
case UPAP_AUTHREQ:
upap_rauthreq(u, inp, id, len);
break;
case UPAP_AUTHACK:
upap_rauthack(u, inp, id, len);
break;
case UPAP_AUTHNAK:
upap_rauthnak(u, inp, id, len);
break;
default: /* XXX Need code reject */
break;
}
}
/*
* upap_rauth - Receive Authenticate.
*/
static void
upap_rauthreq(u, inp, id, len)
upap_state *u;
u_char *inp;
int id;
int len;
{
u_char ruserlen, rpasswdlen;
char *ruser, *rpasswd;
int retcode;
char *msg;
int msglen;
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."));
return;
}
GETCHAR(ruserlen, inp);
len -= sizeof (u_char) + ruserlen + sizeof (u_char);
if (len < 0) {
UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
ruser = (char *) inp;
INCPTR(ruserlen, inp);
GETCHAR(rpasswdlen, inp);
if (len < rpasswdlen) {
UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
return;
}
rpasswd = (char *) inp;
/*
* 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);
if (retcode == UPAP_AUTHACK) {
u->us_serverstate = UPAPSS_OPEN;
auth_peer_success(u->us_unit, UPAP);
} else {
u->us_serverstate = UPAPSS_BADAUTH;
auth_peer_fail(u->us_unit, UPAP);
}
}
/*
* upap_rauthack - Receive Authenticate-Ack.
*/
static void
upap_rauthack(u, inp, id, len)
upap_state *u;
u_char *inp;
int id;
int len;
{
u_char msglen;
char *msg;
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."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_OPEN;
auth_withpeer_success(u->us_unit, UPAP);
}
/*
* upap_rauthnak - Receive Authenticate-Nakk.
*/
static void
upap_rauthnak(u, inp, id, len)
upap_state *u;
u_char *inp;
int id;
int len;
{
u_char msglen;
char *msg;
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."));
return;
}
GETCHAR(msglen, inp);
len -= sizeof (u_char);
if (len < msglen) {
UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
return;
}
msg = (char *) inp;
PRINTMSG(msg, msglen);
u->us_clientstate = UPAPCS_BADAUTH;
syslog(LOG_ERR, "PAP authentication failed");
auth_withpeer_fail(u->us_unit, UPAP);
}
/*
* upap_sauthreq - Send an Authenticate-Request.
*/
static void
upap_sauthreq(u)
upap_state *u;
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
u->us_userlen + u->us_passwdlen;
outp = outpacket_buf;
MAKEHEADER(outp, UPAP);
PUTCHAR(UPAP_AUTHREQ, outp);
PUTCHAR(++u->us_id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(u->us_userlen, outp);
BCOPY(u->us_user, outp, u->us_userlen);
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));
TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
++u->us_transmits;
u->us_clientstate = UPAPCS_AUTHREQ;
}
/*
* upap_sresp - Send a response (ack or nak).
*/
static void
upap_sresp(u, code, id, msg, msglen)
upap_state *u;
u_char code, id;
char *msg;
int msglen;
{
u_char *outp;
int outlen;
outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
outp = outpacket_buf;
MAKEHEADER(outp, UPAP);
PUTCHAR(code, outp);
PUTCHAR(id, outp);
PUTSHORT(outlen, outp);
PUTCHAR(msglen, outp);
BCOPY(msg, outp, msglen);
output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
}
/*
* upap_printpkt - print the contents of a PAP packet.
*/
char *upap_codenames[] = {
"AuthReq", "AuthAck", "AuthNak"
};
int
upap_printpkt(p, plen, printer, arg)
u_char *p;
int plen;
void (*printer) __ARGS((void *, char *, ...));
void *arg;
{
int code, id, len;
int mlen, ulen, wlen;
char *user, *pwd, *msg;
u_char *pstart;
if (plen < UPAP_HEADERLEN)
return 0;
pstart = p;
GETCHAR(code, p);
GETCHAR(id, p);
GETSHORT(len, p);
if (len < UPAP_HEADERLEN || len > plen)
return 0;
if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
printer(arg, " %s", upap_codenames[code-1]);
else
printer(arg, " code=0x%x", code);
printer(arg, " id=0x%x", id);
len -= UPAP_HEADERLEN;
switch (code) {
case UPAP_AUTHREQ:
if (len < 1)
break;
ulen = p[0];
if (len < ulen + 2)
break;
wlen = p[ulen + 1];
if (len < ulen + wlen + 2)
break;
user = (char *) (p + 1);
pwd = (char *) (p + ulen + 2);
p += ulen + wlen + 2;
len -= ulen + wlen + 2;
printer(arg, " user=");
print_string(user, ulen, printer, arg);
printer(arg, " password=");
print_string(pwd, wlen, printer, arg);
break;
case UPAP_AUTHACK:
case UPAP_AUTHNAK:
if (len < 1)
break;
mlen = p[0];
if (len < mlen + 1)
break;
msg = (char *) (p + 1);
p += mlen + 1;
len -= mlen + 1;
printer(arg, "msg=");
print_string(msg, mlen, printer, arg);
break;
}
/* print the rest of the bytes in the packet */
for (; len > 0; --len) {
GETCHAR(code, p);
printer(arg, " %.2x", code);
}
return p - pstart;
}

91
usr.sbin/pppd/upap.h Normal file
View File

@ -0,0 +1,91 @@
/*
* upap.h - User/Password Authentication Protocol definitions.
*
* Copyright (c) 1989 Carnegie Mellon University.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by Carnegie Mellon University. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: upap.h,v 1.2 1994/04/11 07:13:44 paulus Exp $
*/
/*
* Packet header = Code, id, length.
*/
#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
/*
* UPAP codes.
*/
#define UPAP_AUTHREQ 1 /* Authenticate-Request */
#define UPAP_AUTHACK 2 /* Authenticate-Ack */
#define UPAP_AUTHNAK 3 /* Authenticate-Nak */
/*
* Each interface is described by upap structure.
*/
typedef struct upap_state {
int us_unit; /* Interface unit number */
char *us_user; /* User */
int us_userlen; /* User length */
char *us_passwd; /* Password */
int us_passwdlen; /* Password length */
int us_clientstate; /* Client state */
int us_serverstate; /* Server state */
u_char us_id; /* Current id */
int us_timeouttime; /* Timeout time in milliseconds */
int us_transmits; /* Number of auth-reqs sent */
int us_maxtransmits; /* Maximum number of auth-reqs to send */
} upap_state;
/*
* Client states.
*/
#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_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 */
/*
* Timeouts.
*/
#define UPAP_DEFTIMEOUT 3 /* Timeout time in seconds */
extern upap_state upap[];
void upap_init __ARGS((int));
void upap_authwithpeer __ARGS((int, char *, char *));
void upap_authpeer __ARGS((int));
void upap_lowerup __ARGS((int));
void upap_lowerdown __ARGS((int));
void upap_input __ARGS((int, u_char *, int));
void upap_protrej __ARGS((int));
int upap_printpkt __ARGS((u_char *, int,
void (*) __ARGS((void *, char *, ...)), void *));