Initial revision
This commit is contained in:
parent
7bf314246a
commit
08a0aca6e2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=3065
295
usr.sbin/pppd/RELNOTES
Normal file
295
usr.sbin/pppd/RELNOTES
Normal 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
12
usr.sbin/pppd/args.h
Normal 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
904
usr.sbin/pppd/auth.c
Normal 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
18
usr.sbin/pppd/callout.h
Normal 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
823
usr.sbin/pppd/chap.c
Normal 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
112
usr.sbin/pppd/chap.h
Normal 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
773
usr.sbin/pppd/fsm.c
Normal 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
127
usr.sbin/pppd/fsm.h
Normal 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
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
68
usr.sbin/pppd/ipcp.h
Normal 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
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
87
usr.sbin/pppd/lcp.h
Normal 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
122
usr.sbin/pppd/lock.c
Normal 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
70
usr.sbin/pppd/magic.c
Normal 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
24
usr.sbin/pppd/magic.h
Normal 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
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
304
usr.sbin/pppd/md5.c
Normal 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
58
usr.sbin/pppd/md5.h
Normal 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
1452
usr.sbin/pppd/options.c
Normal file
File diff suppressed because it is too large
Load Diff
5
usr.sbin/pppd/patchlevel.h
Normal file
5
usr.sbin/pppd/patchlevel.h
Normal 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
19
usr.sbin/pppd/pathnames.h
Normal 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
41
usr.sbin/pppd/ppp.h
Normal 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
701
usr.sbin/pppd/pppd.8
Normal 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
215
usr.sbin/pppd/pppd.h
Normal 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
743
usr.sbin/pppd/sys-bsd.c
Normal 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
830
usr.sbin/pppd/sys-linux.c
Normal 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
730
usr.sbin/pppd/sys-str.c
Normal 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
663
usr.sbin/pppd/sys-ultrix.c
Normal 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
561
usr.sbin/pppd/upap.c
Normal 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
91
usr.sbin/pppd/upap.h
Normal 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 *));
|
Loading…
Reference in New Issue
Block a user