Axe S/Key. OPIE is the legal successor.
This commit is contained in:
parent
132463cacb
commit
ccdee0d9f4
@ -6,14 +6,12 @@
|
||||
#
|
||||
# csu must be built before all shared libaries for ELF.
|
||||
# libcom_err must be built before libkrb, libpam and libss.
|
||||
# libcrypt must be built before libkrb, libpam and libskey.
|
||||
# libcrypt must be built before libkrb and libpam.
|
||||
# msun must be built before libg++ and libstdc++.
|
||||
# libmd must be built before libatm, libopie, libradius, libskey, and
|
||||
# libtacplus.
|
||||
# libmd must be built before libatm, libopie, libradius, and libtacplus.
|
||||
# libncurses must be built before libdialog, libedit and libreadline.
|
||||
# libopie must be built before libpam.
|
||||
# libradius must be built before libpam.
|
||||
# libskey must be built before libpam.
|
||||
# libtacplus must be built before libpam.
|
||||
# libutil must be built before libpam.
|
||||
# libsbuf must be built before libcam.
|
||||
@ -21,7 +19,7 @@
|
||||
# Otherwise, the SUBDIR list should be in alphabetical order.
|
||||
|
||||
SUBDIR= ${_csu} libcom_err libcrypt msun libmd \
|
||||
libncurses libradius libskey libtacplus libutil libsbuf \
|
||||
libncurses libradius libtacplus libutil libsbuf \
|
||||
${_compat} libalias libatm ${_libbind} libbz2 libc ${_libc_r} \
|
||||
libcalendar libcam libcompat libdevinfo libdevstat libdisk \
|
||||
libedit libfetch libform libftpio libgnumalloc ${_libio} libipsec \
|
||||
|
@ -1,23 +0,0 @@
|
||||
# @(#)Makefile 5.4 (Berkeley) 5/7/91
|
||||
# $FreeBSD$
|
||||
|
||||
LIB= skey
|
||||
SRCS= skeyaccess.c put.c skey_crypt.c skey_getpass.c skeylogin.c skeysubr.c
|
||||
INCS= skey.h
|
||||
MAN= skey.1
|
||||
MAN+= skey.3
|
||||
MLINKS= skey.3 skeylookup.3 skey.3 skeyverify.3 skey.3 skeychallenge.3 \
|
||||
skey.3 skeyinfo.3 skey.3 skeyaccess.3 skey.3 skey_getpass.3 \
|
||||
skey.3 skey_crypt.3
|
||||
MAN+= skey.access.5
|
||||
|
||||
CFLAGS+=-DPERMIT_CONSOLE -D_SKEY_INTERNAL -I${.CURDIR}
|
||||
CFLAGS+=-W -Wall
|
||||
.if ${MACHINE_ARCH} == "i386"
|
||||
CFLAGS+=-Werror
|
||||
.endif
|
||||
|
||||
DPADD+= ${LIBCRYPT} ${LIBMD}
|
||||
LDADD+= -lcrypt -lmd
|
||||
|
||||
.include <bsd.lib.mk>
|
@ -1,19 +0,0 @@
|
||||
#ifdef MD5
|
||||
/* S/Key can use MD5 now, if defined... */
|
||||
#include <md5.h>
|
||||
|
||||
#define MDXFinal MD5Final
|
||||
#define MDXInit MD5Init
|
||||
#define MDXUpdate MD5Update
|
||||
#define MDX_CTX MD5_CTX
|
||||
#else
|
||||
|
||||
/* By default, use MD4 for compatibility */
|
||||
#include <md4.h>
|
||||
|
||||
#define MDXFinal MD4Final
|
||||
#define MDXInit MD4Init
|
||||
#define MDXUpdate MD4Update
|
||||
#define MDX_CTX MD4_CTX
|
||||
|
||||
#endif
|
@ -1,6 +0,0 @@
|
||||
/* $FreeBSD$ (FreeBSD) */
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_SKEYACCESS "/etc/skey.access"
|
||||
#define _PATH_SKEYFILE "/etc/skeykeys"
|
2293
lib/libskey/put.c
2293
lib/libskey/put.c
File diff suppressed because it is too large
Load Diff
@ -1,91 +0,0 @@
|
||||
.\" @(#)skey.1 1.1 10/28/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 28, 1993
|
||||
.Dt KEY 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm S/key
|
||||
.Nd "a procedure to use one time passwords for accessing computer systems"
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is a procedure for using one time password to authenticate access to
|
||||
computer systems.
|
||||
It uses 64 bits of information transformed by the
|
||||
MD4 algorithm.
|
||||
The user supplies the 64 bits in the form of 6 English
|
||||
words that are generated by a secure computer.
|
||||
Example use of the
|
||||
.Nm
|
||||
program
|
||||
.Nm key :
|
||||
.Bd -literal -offset indent
|
||||
>key 99 th91334
|
||||
Enter password: <your secret password is entered here>
|
||||
OMEN US HORN OMIT BACK AHOY
|
||||
>
|
||||
.Ed
|
||||
.Pp
|
||||
The programs that are part of the
|
||||
.Nm
|
||||
system are
|
||||
.Nm keyinit , key ,
|
||||
and
|
||||
.Nm keyinfo .
|
||||
.Nm Keyinit
|
||||
is used to get your ID set up,
|
||||
.Nm key
|
||||
is
|
||||
used to get the one time password each time,
|
||||
.Nm keyinfo
|
||||
is used to extract information from the
|
||||
.Nm
|
||||
database.
|
||||
.Pp
|
||||
When you run
|
||||
.Nm keyinit
|
||||
you inform the system of your
|
||||
secret password.
|
||||
Running
|
||||
.Nm key
|
||||
then generates the
|
||||
one-time passwords, and also requires your secret
|
||||
password.
|
||||
If however, you misspell your password
|
||||
while running
|
||||
.Nm key ,
|
||||
you will get a list of passwords
|
||||
that will not work, and no indication about the problem.
|
||||
.Pp
|
||||
Password sequence numbers count backward from 99.
|
||||
If you don't know this, the syntax for
|
||||
.Nm key
|
||||
will be confusing.
|
||||
.Pp
|
||||
You can enter the passwords using small letters, even
|
||||
though the
|
||||
.Nm key
|
||||
program gives them in caps.
|
||||
.Pp
|
||||
.Tn Macintosh
|
||||
and a general purpose
|
||||
.Tn PC
|
||||
use are available.
|
||||
.Pp
|
||||
Under
|
||||
.Fx ,
|
||||
you can control, with
|
||||
.Pa /etc/skey.access ,
|
||||
from which hosts and/or networks the use of
|
||||
.Nm
|
||||
passwords is obligated.
|
||||
.Sh SEE ALSO
|
||||
.Xr key 1 ,
|
||||
.Xr keyinfo 1 ,
|
||||
.Xr keyinit 1 ,
|
||||
.Xr skey.access 5
|
||||
.Sh AUTHORS
|
||||
.An Phil Karn
|
||||
.An Neil M. Haller
|
||||
.An John S. Walden
|
||||
.An Scott Chasin
|
@ -1,163 +0,0 @@
|
||||
.\" Copyright (c) 1996
|
||||
.\" David L. Nugent. All Rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 22, 1996
|
||||
.Dt SKEY 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm skeylookup ,
|
||||
.Nm skeyverify ,
|
||||
.Nm skeychallenge ,
|
||||
.Nm skeyinfo ,
|
||||
.Nm skeyaccess ,
|
||||
.Nm skey_getpass ,
|
||||
.Nm skey_crypt
|
||||
.Nd library routines for S/Key password control table access
|
||||
.Sh LIBRARY
|
||||
.Lb libskey
|
||||
.Sh SYNOPSIS
|
||||
.Fd #include <stdio.h>
|
||||
.Fd #include <skey.h>
|
||||
.Ft int
|
||||
.Fn skeylookup "struct skey *mp" "const char *name"
|
||||
.Ft int
|
||||
.Fn skeyverify "struct skey *mp" "char *response"
|
||||
.Ft int
|
||||
.Fn skeychallenge "struct skey *mp" "const char *name" "char *challenge"
|
||||
.Ft int
|
||||
.Fn skeyinfo "struct skey *mp" "const char *name" "char *ss"
|
||||
.Ft int
|
||||
.Fn skeyaccess "char *user" "const char *port" "const char *host" "const char *addr"
|
||||
.Ft char *
|
||||
.Fn skey_getpass "const char *prompt" "struct passwd *pwd" "int pwok"
|
||||
.Ft const char *
|
||||
.Fn skey_crypt "char *pp" "char *salt" "struct passwd *pwd" "int pwok"
|
||||
.Sh DESCRIPTION
|
||||
These routes support the S/Key one time password system used for
|
||||
accessing computer systems.
|
||||
See
|
||||
.Xr skey 1
|
||||
for more information about the S/Key system itself.
|
||||
.Pp
|
||||
.Pp
|
||||
.Fn skeylookup
|
||||
finds an entry in the one-time password database.
|
||||
On success (an entry is found corresponding to the given name),
|
||||
they skey structure passed by the caller is filled and 0 is
|
||||
returned, with the file read/write pointer positioned at the
|
||||
beginning of the record found.
|
||||
If no entry is found corresponding to the given name, the file
|
||||
read/write pointer is positioned at end of file and the routine
|
||||
returns 1.
|
||||
If the database cannot be opened or an access error occurs,
|
||||
.Fn skeylookup
|
||||
returns -1.
|
||||
.Pp
|
||||
The
|
||||
.Fn skeyinfo
|
||||
function looks up skey info for user 'name'.
|
||||
If successful, the caller's skey structure is filled and
|
||||
.Fn skeyinfo
|
||||
returns 0.
|
||||
If an optional challenge string buffer is given, it is updated.
|
||||
If unsuccessful (e.g. if the name is unknown, or the database
|
||||
cannot be accessed) -1 is returned.
|
||||
.Pp
|
||||
.Fn skeychallenge
|
||||
returns an skey challenge string for 'name'.
|
||||
If successful, the caller's skey structure is filled, and
|
||||
the function returns 0, with the file read/write pointer
|
||||
left at the start of the record.
|
||||
If unsuccessful (ie. the name was not found), the function
|
||||
returns -1 and the database is closed.
|
||||
.Pp
|
||||
.Fn skeyverify
|
||||
verifies a response to an s/key challenge.
|
||||
If this function returns 0, the verify was successful and
|
||||
the database was updated.
|
||||
If 1 is returned, the verify failed and the database remains
|
||||
unchanged.
|
||||
If -1 is returned, some sort of error occurred with the database,
|
||||
and the database is left unchanged.
|
||||
The s/key database is always closed by this call.
|
||||
.Pp
|
||||
The
|
||||
.Fn skey_getpass
|
||||
function may be used to read regular or s/key passwords.
|
||||
The prompt to use is passed to the function, along with the
|
||||
full (secure) struct passwd for the user to be verified.
|
||||
.Fn skey_getpass
|
||||
uses the standard library getpass on the first attempt at
|
||||
retrieving the user's password, and if that is blank, turns
|
||||
echo back on and retrieves the S/Key password.
|
||||
In either case, the entered string is returned back to the
|
||||
caller.
|
||||
.Pp
|
||||
The
|
||||
.Fn skey_crypt
|
||||
is a wrapper function for the standard library
|
||||
.Xr crypt 3 ,
|
||||
which returns the encrypted UNIX password if either the given
|
||||
s/key or regular passwords are ok.
|
||||
.Fn skey_crypt
|
||||
first attempts verification of the given password via the skey
|
||||
method, and will return the encrypted password from the
|
||||
passwd structure if it can be verified, as though the user had
|
||||
actually entered the correct UNIX password.
|
||||
If s/key password verification does not work, then the password
|
||||
is encrypted in the usual way and the result passed back to the
|
||||
caller.
|
||||
If the passwd structure pointer is NULL,
|
||||
.Fn skey_crypt
|
||||
returns a non-NULL string which could not possibly be a valid
|
||||
UNIX password (namely, a string containing ":").
|
||||
.Pp
|
||||
The
|
||||
.Fn skeyaccess
|
||||
function determines whether traditional UNIX (non-S/Key) passwords
|
||||
are permitted for any combination of user name, group member,
|
||||
terminal port, host name, and network. If UNIX passwords are allowed,
|
||||
.Fn skeyaccess
|
||||
returns a non-zero value. If UNIX passwords are not allowed, it
|
||||
returns 0. See
|
||||
.Xr skey.access 5
|
||||
for more information on the layout and structure of the
|
||||
skey.access configuration file which this function uses.
|
||||
.Sh RETURN VALUES
|
||||
See above.
|
||||
.Sh SEE ALSO
|
||||
.Xr skey 1 ,
|
||||
.Xr skey.access 5
|
||||
.Sh BUGS
|
||||
No advisory locking is done on the s/key database to guard against
|
||||
simultaneous access from multiple processes.
|
||||
This is not normally a problem when keys are added to or updated
|
||||
in the file, but may be problematic when keys are removed.
|
||||
.Sh AUTHORS
|
||||
.An Phil Karn ,
|
||||
.An Neil M. Haller ,
|
||||
.An John S. Walden ,
|
||||
.An Scott Chasin
|
@ -1,224 +0,0 @@
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 12, 2001
|
||||
.Dt SKEY.ACCESS 5
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm skey.access
|
||||
.Nd "S/Key password control table"
|
||||
.Sh DESCRIPTION
|
||||
The S/Key password control table
|
||||
.Pq Pa /etc/skey.access
|
||||
is used by
|
||||
.Nm login Ns \-like
|
||||
programs to determine when
|
||||
.Ux
|
||||
passwords may be used
|
||||
to access the system.
|
||||
.Bl -bullet
|
||||
.It
|
||||
When the table does not exist, there are no password restrictions.
|
||||
The user may enter the
|
||||
.Ux
|
||||
password or the S/Key one.
|
||||
.It
|
||||
When the table does exist,
|
||||
.Ux
|
||||
passwords are permitted only when
|
||||
explicitly specified.
|
||||
.It
|
||||
For the sake of sanity,
|
||||
.Ux
|
||||
passwords are always permitted on the
|
||||
systems console.
|
||||
.El
|
||||
.Sh TABLE FORMAT
|
||||
The format of the table is one rule per line.
|
||||
Rules are matched in order.
|
||||
The search terminates when the first matching rule is found, or
|
||||
when the end of the table is reached.
|
||||
.Pp
|
||||
Rules have the form:
|
||||
.Pp
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.Ic permit
|
||||
.Ar condition condition ...
|
||||
.It
|
||||
.Ic deny
|
||||
.Ar condition condition ...
|
||||
.El
|
||||
.Pp
|
||||
where
|
||||
.Ic permit
|
||||
and
|
||||
.Ic deny
|
||||
may be followed by zero or more
|
||||
.Ar conditions .
|
||||
Comments begin with a
|
||||
.Ql #
|
||||
character, and extend through the end of the line.
|
||||
Empty lines or
|
||||
lines with only comments are ignored.
|
||||
.Pp
|
||||
A rule is matched when all conditions are satisfied.
|
||||
A rule without
|
||||
conditions is always satisfied.
|
||||
For example, the last entry could
|
||||
be a line with just the word
|
||||
.Ic deny
|
||||
on it.
|
||||
.Sh CONDITIONS
|
||||
.Bl -tag -width indent
|
||||
.It Ic hostname Ar wzv.win.tue.nl
|
||||
True when the login comes from host
|
||||
.Ar wzv.win.tue.nl .
|
||||
See the
|
||||
.Sx WARNINGS
|
||||
section below.
|
||||
.It Ic internet Ar 131.155.210.0 255.255.255.0
|
||||
True when the remote host has an internet address in network
|
||||
.Ar 131.155.210 .
|
||||
The general form of a net/mask rule is:
|
||||
.Pp
|
||||
.D1 Ic internet Ar net mask
|
||||
.Pp
|
||||
The expression is true when the host has an internet address for which
|
||||
the bitwise and of
|
||||
.Ar address
|
||||
and
|
||||
.Ar mask
|
||||
equals
|
||||
.Ar net .
|
||||
See the
|
||||
.Sx WARNINGS
|
||||
section below.
|
||||
.It Ic port Ar ttya
|
||||
True when the login terminal is equal to
|
||||
.Pa /dev/ttya .
|
||||
Remember that
|
||||
.Ux
|
||||
passwords are always permitted with logins on the
|
||||
system console.
|
||||
.It Ic user Ar uucp
|
||||
True when the user attempts to log in as
|
||||
.Ar uucp .
|
||||
.It Ic group Ar wheel
|
||||
True when the user attempts to log in as a member of the
|
||||
.Ar wheel
|
||||
group.
|
||||
.El
|
||||
.Sh COMPATIBILITY
|
||||
For the sake of backwards compatibility, the
|
||||
.Ic internet
|
||||
keyword may be omitted from net/mask patterns.
|
||||
.Sh WARNINGS
|
||||
When the S/Key control table
|
||||
.Pq Pa /etc/skey.access
|
||||
exists, users without S/Key passwords will be able to login only
|
||||
where its rules allow the use of
|
||||
.Ux
|
||||
passwords.
|
||||
In particular, this
|
||||
means that an invocation of
|
||||
.Xr login 1
|
||||
in a pseudo-tty (e.g. from
|
||||
within
|
||||
.Xr xterm 1
|
||||
or
|
||||
.Xr screen 1
|
||||
will be treated as a login
|
||||
that is neither from the console nor from the network, mandating the use
|
||||
of an S/Key password.
|
||||
Such an invocation of
|
||||
.Xr login 1
|
||||
will necessarily
|
||||
fail for those users who do not have an S/Key password.
|
||||
.Pp
|
||||
Several rule types depend on host name or address information obtained
|
||||
through the network.
|
||||
What follows is a list of conceivable attacks to force the system to permit
|
||||
.Ux
|
||||
passwords.
|
||||
.Ss "Host address spoofing (source routing)"
|
||||
An intruder configures a local interface to an address in a trusted
|
||||
network and connects to the victim using that source address.
|
||||
Given
|
||||
the wrong client address, the victim draws the wrong conclusion from
|
||||
rules based on host addresses or from rules based on host names derived
|
||||
from addresses.
|
||||
.Pp
|
||||
Remedies:
|
||||
.Bl -enum
|
||||
.It
|
||||
do not permit
|
||||
.Ux
|
||||
passwords with network logins;
|
||||
.It
|
||||
use network software that discards source routing information (e.g.\&
|
||||
a tcp wrapper).
|
||||
.El
|
||||
.Pp
|
||||
Almost every network server must look up the client host name using the
|
||||
client network address.
|
||||
The next obvious attack therefore is:
|
||||
.Ss "Host name spoofing (bad PTR record)"
|
||||
An intruder manipulates the name server system so that the client
|
||||
network address resolves to the name of a trusted host.
|
||||
Given the
|
||||
wrong host name, the victim draws the wrong conclusion from rules based
|
||||
on host names, or from rules based on addresses derived from host
|
||||
names.
|
||||
.Pp
|
||||
Remedies:
|
||||
.Bl -enum
|
||||
.It
|
||||
do not permit
|
||||
.Ux
|
||||
passwords with network logins;
|
||||
.It
|
||||
use
|
||||
network software that verifies that the hostname resolves to the client
|
||||
network address (e.g. a tcp wrapper).
|
||||
.El
|
||||
.Pp
|
||||
Some applications, such as the
|
||||
.Ux
|
||||
.Xr login 1
|
||||
program, must look up the
|
||||
client network address using the client host name.
|
||||
In addition to the
|
||||
previous two attacks, this opens up yet another possibility:
|
||||
.Ss "Host address spoofing (extra A record)"
|
||||
An intruder manipulates the name server system so that the client host
|
||||
name (also) resolves to a trusted address.
|
||||
.Pp
|
||||
Remedies:
|
||||
.Bl -enum
|
||||
.It
|
||||
do not permit
|
||||
.Ux
|
||||
passwords with network logins;
|
||||
.It
|
||||
the
|
||||
.Fn skeyaccess
|
||||
routines ignore network addresses that appear to
|
||||
belong to someone else.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
Syntax errors are reported to the
|
||||
.Xr syslogd 8 .
|
||||
When an error is found
|
||||
the rule is skipped.
|
||||
.Sh FILES
|
||||
.Bl -tag -width /etc/skey.access
|
||||
.It Pa /etc/skey.access
|
||||
password control table
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr login 1 ,
|
||||
.Xr syslogd 8
|
||||
.Sh AUTHORS
|
||||
.An Wietse Venema ,
|
||||
Eindhoven University of Technology,
|
||||
The Netherlands.
|
@ -1,60 +0,0 @@
|
||||
#ifndef _SKEY_H_
|
||||
#define _SKEY_H_
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
/* Server-side data structure for reading keys file during login */
|
||||
struct skey {
|
||||
FILE *keyfile;
|
||||
char buf[256];
|
||||
char *logname;
|
||||
int n;
|
||||
char *seed;
|
||||
char *val;
|
||||
long recstart; /*needed so reread of buffer is efficient*/
|
||||
};
|
||||
|
||||
#ifdef _SKEY_INTERNAL
|
||||
/* Client-side structure for scanning data stream for challenge */
|
||||
struct mc {
|
||||
char buf[256];
|
||||
int skip;
|
||||
int cnt;
|
||||
};
|
||||
|
||||
#define atob8 _sk_atob8
|
||||
#define btoa8 _sk_btoa8
|
||||
#define btoe _sk_btoe
|
||||
#define etob _sk_etob
|
||||
#define f _sk_f
|
||||
#define htoi _sk_htoi
|
||||
#define keycrunch _sk_keycrunch
|
||||
#define put8 _sk_put8
|
||||
#define readpass _sk_readpass
|
||||
#define rip _sk_rip
|
||||
#define sevenbit _sk_sevenbit
|
||||
|
||||
void f __P((char *x));
|
||||
int keycrunch __P((char *result,const char *seed,const char *passwd));
|
||||
char *btoe __P((char *engout,char *c));
|
||||
char *put8 __P((char *out,char *s));
|
||||
int atob8 __P((char *out, char *in));
|
||||
int btoa8 __P((char *out, char *in));
|
||||
int htoi __P((char c));
|
||||
int etob __P((char *out,char *e));
|
||||
void sevenbit __P((char *s));
|
||||
char *readpass __P((char *buf, int n));
|
||||
void rip __P((char *buf));
|
||||
#endif /* _SKEY_INTERNAL */
|
||||
|
||||
/* Simplified application programming interface. */
|
||||
#include <pwd.h>
|
||||
int skeylookup __P((struct skey *mp, const char *name));
|
||||
int skeyverify __P((struct skey *mp, char *response));
|
||||
int skeychallenge __P((struct skey *mp, const char *name, char *challenge));
|
||||
int skeyinfo __P((struct skey *mp, const char* name, char *ss));
|
||||
int skeyaccess __P((char *user, const char *port, const char *host, const char *addr));
|
||||
char *skey_getpass __P((const char *prompt, struct passwd * pwd, int pwok));
|
||||
const char *skey_crypt __P((char *pp, char *salt, struct passwd *pwd, int pwok));
|
||||
|
||||
#endif /* _SKEY_H_ */
|
@ -1,38 +0,0 @@
|
||||
/* Author: Wietse Venema, Eindhoven University of Technology. */
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "skey.h"
|
||||
|
||||
/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */
|
||||
|
||||
const char *skey_crypt(pp, salt, pwd, pwok)
|
||||
char *pp;
|
||||
char *salt;
|
||||
struct passwd *pwd;
|
||||
int pwok;
|
||||
{
|
||||
struct skey skey;
|
||||
char *p;
|
||||
|
||||
/* Try s/key authentication even when the UNIX password is permitted. */
|
||||
|
||||
if (pwd != 0 && skeyinfo(&skey, pwd->pw_name, (char *) 0) == 0
|
||||
&& skeyverify(&skey, pp) == 0) {
|
||||
/* s/key authentication succeeded */
|
||||
return (pwd->pw_passwd);
|
||||
}
|
||||
|
||||
/* When s/key authentication does not work, always invoke crypt(). */
|
||||
|
||||
p = crypt(pp, salt);
|
||||
if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0)
|
||||
return (pwd->pw_passwd);
|
||||
|
||||
/* The user does not exist or entered bad input. */
|
||||
|
||||
return (":");
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <skey.h>
|
||||
|
||||
/* skey_getpass - read regular or s/key password */
|
||||
|
||||
char *skey_getpass(prompt, pwd, pwok)
|
||||
const char *prompt;
|
||||
struct passwd *pwd;
|
||||
int pwok;
|
||||
{
|
||||
static char buf[128];
|
||||
struct skey skey;
|
||||
char *pass;
|
||||
int sflag;
|
||||
|
||||
/* Attempt an s/key challenge. */
|
||||
sflag = (pwd == NULL || skeyinfo(&skey, pwd->pw_name, buf));
|
||||
if (!sflag) {
|
||||
printf("%s\n", buf);
|
||||
if (!pwok)
|
||||
printf("(s/key required)\n");
|
||||
}
|
||||
|
||||
pass = getpass(prompt);
|
||||
|
||||
/* Give S/Key users a chance to do it with echo on. */
|
||||
if (!sflag && !feof(stdin) && *pass == '\0') {
|
||||
fputs(" (turning echo on)\n", stdout);
|
||||
fputs(prompt, stdout);
|
||||
fflush(stdout);
|
||||
fgets(buf, sizeof(buf), stdin);
|
||||
rip(buf);
|
||||
return (buf);
|
||||
} else
|
||||
return (pass);
|
||||
}
|
@ -1,588 +0,0 @@
|
||||
/*
|
||||
* Figure out if UNIX passwords are permitted for any combination of user
|
||||
* name, group member, terminal port, host_name or network:
|
||||
*
|
||||
* Programmatic interface: skeyaccess(user, port, host, addr)
|
||||
*
|
||||
* All arguments are null-terminated strings. Specify a null character pointer
|
||||
* where information is not available.
|
||||
*
|
||||
* When no address information is given this code performs the host (internet)
|
||||
* address lookup itself. It rejects addresses that appear to belong to
|
||||
* someone else.
|
||||
*
|
||||
* When compiled with -DPERMIT_CONSOLE always permits UNIX passwords with
|
||||
* console logins, no matter what the configuration file says.
|
||||
*
|
||||
* To build a stand-alone test version, compile with -DTEST and run it off an
|
||||
* skey.access file in the current directory:
|
||||
*
|
||||
* Command-line interface: ./skeyaccess user port [host_or_ip_addr]
|
||||
*
|
||||
* Errors are reported via syslogd.
|
||||
*
|
||||
* Author: Wietse Venema, Eindhoven University of Technology.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <grp.h>
|
||||
#include <ctype.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "pathnames.h"
|
||||
|
||||
/*
|
||||
* Token input with one-deep pushback.
|
||||
*/
|
||||
static char *prev_token = 0; /* push-back buffer */
|
||||
static char *line_pointer = NULL;
|
||||
static char *first_token __P((char *, int, FILE *));
|
||||
static int line_number;
|
||||
static void unget_token __P((char *));
|
||||
static char *get_token __P((void));
|
||||
static char *need_token __P((void));
|
||||
static char *need_internet_addr __P((void));
|
||||
|
||||
/*
|
||||
* Various forms of token matching.
|
||||
*/
|
||||
#define match_host_name(l) match_token((l)->host_name)
|
||||
#define match_port(l) match_token((l)->port)
|
||||
#define match_user(l) match_token((l)->user)
|
||||
struct login_info;
|
||||
static int match_internet_addr __P((struct login_info *));
|
||||
static int match_group __P((struct login_info *));
|
||||
static int match_token __P((char *));
|
||||
static int is_internet_addr __P((char *));
|
||||
static struct addrinfo *convert_internet_addr __P((char *));
|
||||
static struct addrinfo *lookup_internet_addr __P((char *));
|
||||
|
||||
#define MAX_ADDR 32
|
||||
#define PERMIT 1
|
||||
#define DENY 0
|
||||
|
||||
#ifndef CONSOLE
|
||||
#define CONSOLE "console"
|
||||
#endif
|
||||
#ifndef VTY_PREFIX
|
||||
#define VTY_PREFIX "ttyv"
|
||||
#endif
|
||||
|
||||
struct login_info {
|
||||
char *host_name; /* host name */
|
||||
struct addrinfo *internet_addr; /* addrinfo chain */
|
||||
char *user; /* user name */
|
||||
char *port; /* login port */
|
||||
};
|
||||
|
||||
static int _skeyaccess __P((FILE *, struct login_info *));
|
||||
int skeyaccess __P((char *, char *, char *, char *));
|
||||
|
||||
/* skeyaccess - find out if UNIX passwords are permitted */
|
||||
|
||||
int skeyaccess(user, port, host, addr)
|
||||
char *user;
|
||||
char *port;
|
||||
char *host;
|
||||
char *addr;
|
||||
{
|
||||
FILE *fp;
|
||||
struct login_info login_info;
|
||||
int result;
|
||||
|
||||
/*
|
||||
* Assume no restriction on the use of UNIX passwords when the s/key
|
||||
* acces table does not exist.
|
||||
*/
|
||||
if ((fp = fopen(_PATH_SKEYACCESS, "r")) == 0) {
|
||||
#ifdef TEST
|
||||
fprintf(stderr, "No file %s, thus no access control\n", _PATH_SKEYACCESS);
|
||||
#endif
|
||||
return (PERMIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bundle up the arguments in a structure so we won't have to drag around
|
||||
* boring long argument lists.
|
||||
*
|
||||
* Look up the host address when only the name is given. We try to reject
|
||||
* addresses that belong to someone else.
|
||||
*/
|
||||
login_info.user = user;
|
||||
login_info.port = port;
|
||||
|
||||
if (host != NULL && !is_internet_addr(host)) {
|
||||
login_info.host_name = host;
|
||||
} else {
|
||||
login_info.host_name = NULL;
|
||||
}
|
||||
|
||||
if (addr != NULL && is_internet_addr(addr)) {
|
||||
login_info.internet_addr = convert_internet_addr(addr);
|
||||
} else if (host != NULL) {
|
||||
if (is_internet_addr(host)) {
|
||||
login_info.internet_addr = convert_internet_addr(host);
|
||||
} else {
|
||||
login_info.internet_addr = lookup_internet_addr(host);
|
||||
}
|
||||
} else {
|
||||
login_info.internet_addr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print what we think the user wants us to do.
|
||||
*/
|
||||
#ifdef TEST
|
||||
printf("port: %s\n", login_info.port);
|
||||
printf("user: %s\n", login_info.user);
|
||||
printf("host: %s\n", login_info.host_name ? login_info.host_name : "none");
|
||||
printf("addr: ");
|
||||
if (login_info.internet_addr == NULL) {
|
||||
printf("none\n");
|
||||
} else {
|
||||
struct addrinfo *res;
|
||||
char haddr[NI_MAXHOST];
|
||||
|
||||
for (res = login_info.internet_addr; res; res = res->ai_next) {
|
||||
getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr),
|
||||
NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||
printf("%s%s", haddr, res->ai_next ? " " : "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
result = _skeyaccess(fp, &login_info);
|
||||
fclose(fp);
|
||||
if (login_info.internet_addr)
|
||||
freeaddrinfo(login_info.internet_addr);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* _skeyaccess - find out if UNIX passwords are permitted */
|
||||
|
||||
static int _skeyaccess(fp, login_info)
|
||||
FILE *fp;
|
||||
struct login_info *login_info;
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
char *tok;
|
||||
int match;
|
||||
int permission=DENY;
|
||||
|
||||
#ifdef PERMIT_CONSOLE
|
||||
if (login_info->port != 0 &&
|
||||
(strcmp(login_info->port, CONSOLE) == 0 ||
|
||||
strncmp(login_info->port, VTY_PREFIX, sizeof(VTY_PREFIX) - 1) == 0
|
||||
)
|
||||
)
|
||||
return (1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Scan the s/key access table until we find an entry that matches. If no
|
||||
* match is found, assume that UNIX passwords are disallowed.
|
||||
*/
|
||||
match = 0;
|
||||
while (match == 0 && (tok = first_token(buf, sizeof(buf), fp))) {
|
||||
if (strncasecmp(tok, "permit", 4) == 0) {
|
||||
permission = PERMIT;
|
||||
} else if (strncasecmp(tok, "deny", 4) == 0) {
|
||||
permission = DENY;
|
||||
} else {
|
||||
syslog(LOG_ERR, "%s: line %d: bad permission: %s",
|
||||
_PATH_SKEYACCESS, line_number, tok);
|
||||
continue; /* error */
|
||||
}
|
||||
|
||||
/*
|
||||
* Process all conditions in this entry until we find one that fails.
|
||||
*/
|
||||
match = 1;
|
||||
while (match != 0 && (tok = get_token())) {
|
||||
if (strcasecmp(tok, "hostname") == 0) {
|
||||
match = match_host_name(login_info);
|
||||
} else if (strcasecmp(tok, "port") == 0) {
|
||||
match = match_port(login_info);
|
||||
} else if (strcasecmp(tok, "user") == 0) {
|
||||
match = match_user(login_info);
|
||||
} else if (strcasecmp(tok, "group") == 0) {
|
||||
match = match_group(login_info);
|
||||
} else if (strcasecmp(tok, "internet") == 0) {
|
||||
match = match_internet_addr(login_info);
|
||||
} else if (is_internet_addr(tok)) {
|
||||
unget_token(tok);
|
||||
match = match_internet_addr(login_info);
|
||||
} else {
|
||||
syslog(LOG_ERR, "%s: line %d: bad condition: %s",
|
||||
_PATH_SKEYACCESS, line_number, tok);
|
||||
match = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (match ? permission : DENY);
|
||||
}
|
||||
|
||||
/* translate IPv4 mapped IPv6 address to IPv4 address */
|
||||
|
||||
static void
|
||||
ai_unmapped(struct addrinfo *ai)
|
||||
{
|
||||
struct sockaddr_in6 *sin6;
|
||||
struct sockaddr_in *sin4;
|
||||
u_int32_t addr;
|
||||
int port;
|
||||
|
||||
if (ai->ai_family != AF_INET6)
|
||||
return;
|
||||
sin6 = (struct sockaddr_in6 *)ai->ai_addr;
|
||||
if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
|
||||
return;
|
||||
sin4 = (struct sockaddr_in *)ai->ai_addr;
|
||||
addr = *(u_int32_t *)&sin6->sin6_addr.s6_addr[12];
|
||||
port = sin6->sin6_port;
|
||||
memset(sin4, 0, sizeof(struct sockaddr_in));
|
||||
sin4->sin_addr.s_addr = addr;
|
||||
sin4->sin_port = port;
|
||||
sin4->sin_family = AF_INET;
|
||||
sin4->sin_len = sizeof(struct sockaddr_in);
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
/* match_internet_addr - match internet network address */
|
||||
|
||||
static int match_internet_addr(login_info)
|
||||
struct login_info *login_info;
|
||||
{
|
||||
char *tok;
|
||||
struct addrinfo *res;
|
||||
struct sockaddr_storage pattern, mask;
|
||||
struct sockaddr_in *addr4, *pattern4, *mask4;
|
||||
struct sockaddr_in6 *addr6, *pattern6, *mask6;
|
||||
int i, match;
|
||||
|
||||
if (login_info->internet_addr == NULL)
|
||||
return (0);
|
||||
if ((tok = need_internet_addr()) == 0)
|
||||
return (0);
|
||||
if ((res = convert_internet_addr(tok)) == NULL)
|
||||
return (0);
|
||||
memcpy(&pattern, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(res);
|
||||
if ((tok = need_internet_addr()) == 0)
|
||||
return (0);
|
||||
if ((res = convert_internet_addr(tok)) == NULL)
|
||||
return (0);
|
||||
memcpy(&mask, res->ai_addr, res->ai_addrlen);
|
||||
freeaddrinfo(res);
|
||||
if (pattern.ss_family != mask.ss_family)
|
||||
return (0);
|
||||
mask4 = (struct sockaddr_in *)&mask;
|
||||
pattern4 = (struct sockaddr_in *)&pattern;
|
||||
mask6 = (struct sockaddr_in6 *)&mask;
|
||||
pattern6 = (struct sockaddr_in6 *)&pattern;
|
||||
|
||||
/*
|
||||
* See if any of the addresses matches a pattern in the control file. We
|
||||
* have already tried to drop addresses that belong to someone else.
|
||||
*/
|
||||
|
||||
for (res = login_info->internet_addr; res; res = res->ai_next) {
|
||||
ai_unmapped(res);
|
||||
if (res->ai_family != pattern.ss_family)
|
||||
continue;
|
||||
switch (res->ai_family) {
|
||||
case AF_INET:
|
||||
addr4 = (struct sockaddr_in *)res->ai_addr;
|
||||
if (addr4->sin_addr.s_addr != INADDR_NONE &&
|
||||
(addr4->sin_addr.s_addr & mask4->sin_addr.s_addr) == pattern4->sin_addr.s_addr)
|
||||
return (1);
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr6 = (struct sockaddr_in6 *)res->ai_addr;
|
||||
if (pattern6->sin6_scope_id != 0 &&
|
||||
addr6->sin6_scope_id != pattern6->sin6_scope_id)
|
||||
break;
|
||||
match = 1;
|
||||
for (i = 0; i < 16; ++i) {
|
||||
if ((addr6->sin6_addr.s6_addr[i] & mask6->sin6_addr.s6_addr[i]) != pattern6->sin6_addr.s6_addr[i]) {
|
||||
match = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match)
|
||||
return (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* match_group - match username against group */
|
||||
|
||||
static int match_group(login_info)
|
||||
struct login_info *login_info;
|
||||
{
|
||||
struct group *group;
|
||||
char *tok;
|
||||
char **memp;
|
||||
|
||||
if ((tok = need_token()) && (group = getgrnam(tok))) {
|
||||
for (memp = group->gr_mem; *memp; memp++)
|
||||
if (strcmp(login_info->user, *memp) == 0)
|
||||
return (1);
|
||||
}
|
||||
return (0); /* XXX endgrent() */
|
||||
}
|
||||
|
||||
/* match_token - get and match token */
|
||||
|
||||
static int match_token(str)
|
||||
char *str;
|
||||
{
|
||||
char *tok;
|
||||
|
||||
return (str && (tok = need_token()) && strcasecmp(str, tok) == 0);
|
||||
}
|
||||
|
||||
/* first_token - read line and return first token */
|
||||
|
||||
static char *first_token(buf, len, fp)
|
||||
char *buf;
|
||||
int len;
|
||||
FILE *fp;
|
||||
{
|
||||
char *cp;
|
||||
|
||||
prev_token = 0;
|
||||
for (;;) {
|
||||
if (fgets(buf, len, fp) == 0)
|
||||
return (0);
|
||||
line_number++;
|
||||
buf[strcspn(buf, "\r\n#")] = 0;
|
||||
#ifdef TEST
|
||||
if (buf[0])
|
||||
printf("rule: %s\n", buf);
|
||||
#endif
|
||||
line_pointer = buf;
|
||||
while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
if (cp != NULL)
|
||||
return (cp);
|
||||
}
|
||||
}
|
||||
|
||||
/* unget_token - push back last token */
|
||||
|
||||
static void unget_token(cp)
|
||||
char *cp;
|
||||
{
|
||||
prev_token = cp;
|
||||
}
|
||||
|
||||
/* get_token - retrieve next token from buffer */
|
||||
|
||||
static char *get_token()
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if ( (cp = prev_token) ) {
|
||||
prev_token = 0;
|
||||
} else {
|
||||
while ((cp = strsep(&line_pointer, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
}
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/* need_token - complain if next token is not available */
|
||||
|
||||
static char *need_token()
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if ((cp = get_token()) == 0)
|
||||
syslog(LOG_ERR, "%s: line %d: premature end of rule",
|
||||
_PATH_SKEYACCESS, line_number);
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/* need_internet_addr - complain if next token is not an internet address */
|
||||
|
||||
static char *need_internet_addr()
|
||||
{
|
||||
char *cp;
|
||||
|
||||
if ((cp = get_token()) == 0) {
|
||||
syslog(LOG_ERR, "%s: line %d: internet address expected",
|
||||
_PATH_SKEYACCESS, line_number);
|
||||
return (0);
|
||||
} else if (!is_internet_addr(cp)) {
|
||||
syslog(LOG_ERR, "%s: line %d: bad internet address: %s",
|
||||
_PATH_SKEYACCESS, line_number, cp);
|
||||
return (0);
|
||||
} else {
|
||||
return (cp);
|
||||
}
|
||||
}
|
||||
|
||||
/* is_internet_addr - determine if string is a dotted quad decimal address */
|
||||
|
||||
static int is_internet_addr(str)
|
||||
char *str;
|
||||
{
|
||||
struct addrinfo *res;
|
||||
|
||||
if ((res = convert_internet_addr(str)) != NULL)
|
||||
freeaddrinfo(res);
|
||||
return (res != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Nuke addrinfo entry from list.
|
||||
* XXX: Depending on the implementation of KAME's getaddrinfo(3).
|
||||
*/
|
||||
static void nuke_ai(aip)
|
||||
struct addrinfo **aip;
|
||||
{
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = *aip;
|
||||
*aip = ai->ai_next;
|
||||
if (ai->ai_canonname) {
|
||||
if (ai->ai_next && !ai->ai_next->ai_canonname)
|
||||
ai->ai_next->ai_canonname = ai->ai_canonname;
|
||||
else
|
||||
free(ai->ai_canonname);
|
||||
}
|
||||
free(ai);
|
||||
}
|
||||
|
||||
/* lookup_internet_addr - look up internet addresses with extreme prejudice */
|
||||
|
||||
static struct addrinfo *lookup_internet_addr(host)
|
||||
char *host;
|
||||
{
|
||||
struct addrinfo hints, *res0, *res, **resp;
|
||||
char hname[NI_MAXHOST], haddr[NI_MAXHOST];
|
||||
int error;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
|
||||
if (getaddrinfo(host, NULL, &hints, &res0) != 0)
|
||||
return (NULL);
|
||||
if (res0->ai_canonname == NULL) {
|
||||
freeaddrinfo(res0);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wipe addresses that appear to belong to someone else. We will get
|
||||
* false alarms when when the hostname comes from DNS, while its
|
||||
* addresses are listed under different names in local databases.
|
||||
*/
|
||||
#define NEQ(x,y) (strcasecmp((x),(y)) != 0)
|
||||
#define NEQ3(x,y,n) (strncasecmp((x),(y), (n)) != 0)
|
||||
|
||||
resp = &res0;
|
||||
while ((res = *resp) != NULL) {
|
||||
if (res->ai_family != AF_INET && res->ai_family != AF_INET6) {
|
||||
nuke_ai(resp);
|
||||
continue;
|
||||
}
|
||||
error = getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
hname, sizeof(hname),
|
||||
NULL, 0, NI_NAMEREQD | NI_WITHSCOPEID);
|
||||
if (error) {
|
||||
getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr),
|
||||
NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||
syslog(LOG_ERR, "address %s not registered for host %s",
|
||||
haddr, res0->ai_canonname);
|
||||
nuke_ai(resp);
|
||||
continue;
|
||||
}
|
||||
if (NEQ(res0->ai_canonname, hname) &&
|
||||
NEQ3(res0->ai_canonname, "localhost.", 10)) {
|
||||
getnameinfo(res->ai_addr, res->ai_addrlen, haddr, sizeof(haddr),
|
||||
NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID);
|
||||
syslog(LOG_ERR, "address %s registered for host %s and %s",
|
||||
haddr, hname, res0->ai_canonname);
|
||||
nuke_ai(resp);
|
||||
continue;
|
||||
}
|
||||
resp = &res->ai_next;
|
||||
}
|
||||
return (res0);
|
||||
}
|
||||
|
||||
/* convert_internet_addr - convert string to internet address */
|
||||
|
||||
static struct addrinfo *convert_internet_addr(string)
|
||||
char *string;
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||
if (getaddrinfo(string, NULL, &hints, &res) != 0)
|
||||
return (NULL);
|
||||
return (res);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
struct addrinfo hints, *res;
|
||||
char host[MAXHOSTNAMELEN + 1];
|
||||
int verdict;
|
||||
char *user;
|
||||
char *port;
|
||||
|
||||
if (argc != 3 && argc != 4) {
|
||||
fprintf(stderr, "usage: %s user port [host_or_ip_address]\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
if (_PATH_SKEYACCESS[0] != '/')
|
||||
printf("Warning: this program uses control file: %s\n", _PATH_SKEYACCESS);
|
||||
openlog("login", LOG_PID, LOG_AUTH);
|
||||
|
||||
user = argv[1];
|
||||
port = argv[2];
|
||||
if (argv[3]) {
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
|
||||
if (getaddrinfo(argv[3], NULL, &hints, &res) == 0) {
|
||||
if (res->ai_canonname == NULL)
|
||||
strncpy(host, argv[3], MAXHOSTNAMELEN);
|
||||
else
|
||||
strncpy(host, res->ai_canonname, MAXHOSTNAMELEN);
|
||||
freeaddrinfo(res);
|
||||
} else
|
||||
strncpy(host, argv[3], MAXHOSTNAMELEN);
|
||||
host[MAXHOSTNAMELEN] = 0;
|
||||
}
|
||||
verdict = skeyaccess(user, port, argv[3] ? host : (char *) 0, (char *) 0);
|
||||
printf("UNIX passwords %spermitted\n", verdict ? "" : "NOT ");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,343 +0,0 @@
|
||||
/* Login code for S/KEY Authentication. S/KEY is a trademark
|
||||
* of Bellcore.
|
||||
*
|
||||
* Mink is the former name of the S/KEY authentication system.
|
||||
* Many references for mink may still be found in this program.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "skey.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
static char *skipspace __P((char *));
|
||||
|
||||
#define setpriority(x,y,z) /* nothing */
|
||||
|
||||
static const char *month[12] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
/* Look up skey info for user 'name'. If successful, fill in the caller's
|
||||
* skey structure and return 0. If unsuccessful (e.g., if name is unknown)
|
||||
* return -1. If an optional challenge string buffer is given, update it.
|
||||
*
|
||||
* The file read/write pointer is left at the start of the
|
||||
* record.
|
||||
*/
|
||||
int
|
||||
skeyinfo(mp,name,ss)
|
||||
struct skey *mp;
|
||||
const char *name;
|
||||
char *ss;
|
||||
{
|
||||
int rval;
|
||||
|
||||
rval = skeylookup(mp,name);
|
||||
switch(rval){
|
||||
case -1: /* File error */
|
||||
return -1;
|
||||
case 0: /* Lookup succeeded */
|
||||
if (ss != 0) {
|
||||
sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
|
||||
fclose(mp->keyfile);
|
||||
}
|
||||
return 0;
|
||||
case 1: /* User not found */
|
||||
fclose(mp->keyfile);
|
||||
return -1;
|
||||
}
|
||||
return -1; /* Can't happen */
|
||||
}
|
||||
|
||||
/* Return a skey challenge string for user 'name'. If successful,
|
||||
* fill in the caller's skey structure and return 0. If unsuccessful
|
||||
* (e.g., if name is unknown) return -1.
|
||||
*
|
||||
* The file read/write pointer is left at the start of the
|
||||
* record.
|
||||
*/
|
||||
int
|
||||
skeychallenge(mp,name, ss)
|
||||
struct skey *mp;
|
||||
const char *name;
|
||||
char *ss;
|
||||
{
|
||||
int rval;
|
||||
|
||||
rval = skeylookup(mp,name);
|
||||
switch(rval){
|
||||
case -1: /* File error */
|
||||
return -1;
|
||||
case 0: /* Lookup succeeded, issue challenge */
|
||||
sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
|
||||
return 0;
|
||||
case 1: /* User not found */
|
||||
fclose(mp->keyfile);
|
||||
return -1;
|
||||
}
|
||||
return -1; /* Can't happen */
|
||||
}
|
||||
|
||||
/* Find an entry in the One-time Password database.
|
||||
* Return codes:
|
||||
* -1: error in opening database
|
||||
* 0: entry found, file R/W pointer positioned at beginning of record
|
||||
* 1: entry not found, file R/W pointer positioned at EOF
|
||||
*/
|
||||
int
|
||||
skeylookup(mp,name)
|
||||
struct skey *mp;
|
||||
const char *name;
|
||||
{
|
||||
int found;
|
||||
size_t len;
|
||||
long recstart = 0;
|
||||
char *cp, *p;
|
||||
struct stat statbuf;
|
||||
mode_t oldmask;
|
||||
|
||||
/* See if the _PATH_SKEYFILE exists, and create it if not */
|
||||
if(stat(_PATH_SKEYFILE,&statbuf) == -1 && errno == ENOENT){
|
||||
oldmask = umask(S_IRWXG|S_IRWXO);
|
||||
mp->keyfile = fopen(_PATH_SKEYFILE,"w+");
|
||||
(void)umask(oldmask);
|
||||
} else {
|
||||
/* Otherwise open normally for update */
|
||||
mp->keyfile = fopen(_PATH_SKEYFILE,"r+");
|
||||
}
|
||||
if(mp->keyfile == NULL)
|
||||
return -1;
|
||||
|
||||
/* Look up user name in database */
|
||||
len = strlen(name);
|
||||
if(len > UT_NAMESIZE)
|
||||
len = UT_NAMESIZE;
|
||||
found = 0;
|
||||
while(!feof(mp->keyfile)){
|
||||
recstart = ftell(mp->keyfile);
|
||||
mp->recstart = recstart;
|
||||
if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
|
||||
break;
|
||||
}
|
||||
rip(mp->buf);
|
||||
if(mp->buf[0] == '#')
|
||||
continue; /* Comment */
|
||||
p = mp->buf;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
if((mp->logname = cp) == NULL)
|
||||
continue;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
if(cp == NULL)
|
||||
continue;
|
||||
mp->n = atoi(cp);
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
if((mp->seed = cp) == NULL)
|
||||
continue;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
if((mp->val = cp) == NULL)
|
||||
continue;
|
||||
if(strlen(mp->logname) == len
|
||||
&& strncmp(mp->logname,name,len) == 0){
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(found){
|
||||
fseek(mp->keyfile,recstart,0);
|
||||
return 0;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
/* Verify response to a s/key challenge.
|
||||
*
|
||||
* Return codes:
|
||||
* -1: Error of some sort; database unchanged
|
||||
* 0: Verify successful, database updated
|
||||
* 1: Verify failed, database unchanged
|
||||
*
|
||||
* The database file is always closed by this call.
|
||||
*/
|
||||
int
|
||||
skeyverify(mp,response)
|
||||
struct skey *mp;
|
||||
char *response;
|
||||
{
|
||||
char key[8];
|
||||
char fkey[8];
|
||||
char filekey[8];
|
||||
time_t now;
|
||||
struct tm *tm;
|
||||
char tbuf[27], fbuf[20];
|
||||
char *cp, *p;
|
||||
|
||||
time(&now);
|
||||
tm = localtime(&now);
|
||||
/* can't use %b here, because it can be in national form */
|
||||
strftime(fbuf, sizeof(fbuf), "%d,%Y %T", tm);
|
||||
snprintf(tbuf, sizeof(tbuf), " %s %s", month[tm->tm_mon], fbuf);
|
||||
|
||||
if(response == NULL){
|
||||
fclose(mp->keyfile);
|
||||
return -1;
|
||||
}
|
||||
rip(response);
|
||||
|
||||
/* Convert response to binary */
|
||||
if(etob(key,response) != 1 && atob8(key,response) != 0){
|
||||
/* Neither english words or ascii hex */
|
||||
fclose(mp->keyfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Compute fkey = f(key) */
|
||||
memcpy(fkey,key,sizeof(key));
|
||||
f(fkey);
|
||||
/* in order to make the window of update as short as possible
|
||||
we must do the comparison here and if OK write it back
|
||||
other wise the same password can be used twice to get in
|
||||
to the system
|
||||
*/
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, -4);
|
||||
|
||||
/* reread the file record NOW*/
|
||||
|
||||
fseek(mp->keyfile,mp->recstart,0);
|
||||
if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
|
||||
setpriority(PRIO_PROCESS, 0, 0);
|
||||
fclose(mp->keyfile);
|
||||
return -1;
|
||||
}
|
||||
rip(mp->buf);
|
||||
p = mp->buf;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
mp->logname = cp;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
mp->seed = cp;
|
||||
while ((cp = strsep(&p, " \t")) != NULL && *cp == '\0')
|
||||
;
|
||||
mp->val = cp;
|
||||
/* And convert file value to hex for comparison */
|
||||
atob8(filekey,mp->val);
|
||||
|
||||
/* Do actual comparison */
|
||||
if(memcmp(filekey,fkey,8) != 0){
|
||||
/* Wrong response */
|
||||
setpriority(PRIO_PROCESS, 0, 0);
|
||||
fclose(mp->keyfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Update key in database by overwriting entire record. Note
|
||||
* that we must write exactly the same number of bytes as in
|
||||
* the original record (note fixed width field for N)
|
||||
*/
|
||||
btoa8(mp->val,key);
|
||||
mp->n--;
|
||||
fseek(mp->keyfile,mp->recstart,0);
|
||||
fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
|
||||
mp->val, tbuf);
|
||||
|
||||
fclose(mp->keyfile);
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Convert 8-byte hex-ascii string to binary array
|
||||
* Returns 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
atob8(out,in)
|
||||
register char *out,*in;
|
||||
{
|
||||
register int i;
|
||||
register int val;
|
||||
|
||||
if(in == NULL || out == NULL)
|
||||
return -1;
|
||||
|
||||
for(i=0;i<8;i++){
|
||||
if((in = skipspace(in)) == NULL)
|
||||
return -1;
|
||||
if((val = htoi(*in++)) == -1)
|
||||
return -1;
|
||||
*out = val << 4;
|
||||
|
||||
if((in = skipspace(in)) == NULL)
|
||||
return -1;
|
||||
if((val = htoi(*in++)) == -1)
|
||||
return -1;
|
||||
*out++ |= val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
char *
|
||||
skipspace(cp)
|
||||
register char *cp;
|
||||
{
|
||||
while(*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
|
||||
if(*cp == '\0')
|
||||
return NULL;
|
||||
else
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* Convert 8-byte binary array to hex-ascii string */
|
||||
int
|
||||
btoa8(out,in)
|
||||
register char *out,*in;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if(in == NULL || out == NULL)
|
||||
return -1;
|
||||
|
||||
for(i=0;i<8;i++){
|
||||
sprintf(out,"%02x",*in++ & 0xff);
|
||||
out += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Convert hex digit to binary integer */
|
||||
int
|
||||
htoi(c)
|
||||
register char c;
|
||||
{
|
||||
if('0' <= c && c <= '9')
|
||||
return c - '0';
|
||||
if('a' <= c && c <= 'f')
|
||||
return 10 + c - 'a';
|
||||
if('A' <= c && c <= 'F')
|
||||
return 10 + c - 'A';
|
||||
return -1;
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "skey.h"
|
||||
#include "mdx.h"
|
||||
|
||||
/* Crunch a key:
|
||||
* concatenate the seed and the password, run through MDX and
|
||||
* collapse to 64 bits. This is defined as the user's starting key.
|
||||
*/
|
||||
int
|
||||
keycrunch(result,seed,passwd)
|
||||
char *result; /* 8-byte result */
|
||||
const char *seed; /* Seed, any length */
|
||||
const char *passwd; /* Password, any length */
|
||||
{
|
||||
char *buf;
|
||||
MDX_CTX md;
|
||||
u_int32_t results[4];
|
||||
unsigned int buflen;
|
||||
|
||||
buflen = strlen(seed) + strlen(passwd);
|
||||
if((buf = malloc(buflen+1)) == NULL)
|
||||
return -1;
|
||||
strcpy(buf,seed);
|
||||
strcat(buf,passwd);
|
||||
|
||||
/* Crunch the key through MD[45] */
|
||||
sevenbit(buf);
|
||||
MDXInit(&md);
|
||||
MDXUpdate(&md,(unsigned char *)buf,buflen);
|
||||
MDXFinal((unsigned char *)results,&md);
|
||||
free(buf);
|
||||
|
||||
results[0] ^= results[2];
|
||||
results[1] ^= results[3];
|
||||
|
||||
memcpy(result,(char *)results,8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */
|
||||
void
|
||||
f(x)
|
||||
char *x;
|
||||
{
|
||||
MDX_CTX md;
|
||||
u_int32_t results[4];
|
||||
|
||||
MDXInit(&md);
|
||||
MDXUpdate(&md,(unsigned char *)x,8);
|
||||
MDXFinal((unsigned char *)results,&md);
|
||||
/* Fold 128 to 64 bits */
|
||||
results[0] ^= results[2];
|
||||
results[1] ^= results[3];
|
||||
|
||||
memcpy(x,(char *)results,8);
|
||||
}
|
||||
|
||||
/* Strip trailing cr/lf from a line of text */
|
||||
void
|
||||
rip(buf)
|
||||
char *buf;
|
||||
{
|
||||
buf[strcspn(buf, "\r\n")] = 0;
|
||||
}
|
||||
|
||||
static struct termios saved_ttymode;
|
||||
|
||||
static void interrupt __P((int));
|
||||
|
||||
static void interrupt(sig)
|
||||
int sig;
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &saved_ttymode);
|
||||
err(1, "interrupted by signal %s", sys_siglist[sig]);
|
||||
}
|
||||
|
||||
char *
|
||||
readpass(buf,n)
|
||||
char *buf;
|
||||
int n;
|
||||
{
|
||||
struct termios noecho_ttymode;
|
||||
void (*oldsig) __P((int));
|
||||
|
||||
/* Save normal line editing modes */
|
||||
tcgetattr(0, &saved_ttymode);
|
||||
if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
|
||||
signal(SIGINT, interrupt);
|
||||
|
||||
/* Turn off echoing */
|
||||
tcgetattr(0, &noecho_ttymode);
|
||||
noecho_ttymode.c_lflag &= ~ECHO;
|
||||
tcsetattr(0, TCSANOW, &noecho_ttymode);
|
||||
fgets(buf,n,stdin);
|
||||
rip(buf);
|
||||
|
||||
/* Restore previous tty modes */
|
||||
tcsetattr(0, TCSANOW, &saved_ttymode);
|
||||
if (oldsig != SIG_IGN)
|
||||
signal(SIGINT, oldsig);
|
||||
|
||||
/*
|
||||
after the secret key is taken from the keyboard, the line feed is
|
||||
written to standard error instead of standard output. That means that
|
||||
anyone using the program from a terminal won't notice, but capturing
|
||||
standard output will get the key words without a newline in front of
|
||||
them.
|
||||
*/
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
sevenbit(buf);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
sevenbit(s)
|
||||
char *s;
|
||||
{
|
||||
/* make sure there are only 7 bit code in the line*/
|
||||
while(*s){
|
||||
*s &= 0x7f;
|
||||
s++;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user