Axe S/Key. OPIE is the legal successor.

This commit is contained in:
Mark Murray 2001-07-09 17:52:34 +00:00
parent 132463cacb
commit ccdee0d9f4
14 changed files with 3 additions and 4025 deletions

View File

@ -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 \

View File

@ -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>

View File

@ -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

View File

@ -1,6 +0,0 @@
/* $FreeBSD$ (FreeBSD) */
#include <paths.h>
#define _PATH_SKEYACCESS "/etc/skey.access"
#define _PATH_SKEYFILE "/etc/skeykeys"

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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_ */

View File

@ -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 (":");
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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++;
}
}