Install improved skey access code

This commit is contained in:
Paul Traina 1994-09-29 18:58:39 +00:00
parent 46cf1ccdf3
commit d7e9de5e6e
4 changed files with 504 additions and 10 deletions

View File

@ -1,8 +1,30 @@
# First word says if UNIX passwords are to be permitted or denied.
# remainder of the rule is a networknumber and mask. A rule matches a
# host if any of its addresses satisfies:
#
# network = (address & mask)
#
#what network mask
permit 0.0.0.0 0.0.0.0
# This file controls whether UNIX passwords are to be permitted. Rules
# are matched in order, and the search terminates when the first matching
# rule has been found.
#
# Each rule has the form:
#
# permit condition condition...
# deny condition condition...
#
# Where "permit" or "deny" may be followed by zero or more conditions.
#
# A rule is matched when all conditions are satisfied. A rule without
# conditions is always satisfied.
#
# Examples of conditions are:
#
# hostname wzv.win.tue.nl
# internet 131.155.210.0 255.255.255.0
# port ttya
# user root
# group wheel
#
# The old S/Key form (permit/deny netnumber netmask) is still supported.
#
#permit user uugiga # uucp login via modem or internet
#permit port ttyb # local
#permit port console # local
#deny # anything else
permit # permit plaintext passwords all the time

View File

@ -1,7 +1,10 @@
# @(#)Makefile 5.4 (Berkeley) 5/7/91
LIB= skey
SRCS= authfile.c md4.c put.c skey_crypt.c skeylogin.c skeysubr.c
CFLAGS+=-DMPU8086
SRCS= skeyaccess.c md4.c put.c skey_crypt.c skeylogin.c skeysubr.c
MAN5= skey.access.5
CFLAGS+=-DMPU8086 -DPERMIT_CONSOLE
.include <bsd.lib.mk>

86
lib/libskey/skey.access.5 Normal file
View File

@ -0,0 +1,86 @@
.TH SKEY.ACCESS 5
.SH NAME
skey.access \- S/Key password control table
.SH DESCRIPTION
The S/Key password control table (default
.IR /etc/skey.access )
is used by \fIlogin\fR-like programs to determine when UNIX passwords
may be used to access the system.
.IP \(bu
When the table does not exist, there are no password restrictions. The
user may enter the UNIX password or the S/Key one.
.IP \(bu
When the table does exist, UNIX passwords are permitted only when
explicitly specified.
.IP \(bu
For the sake of sanity, UNIX passwords are always permitted on the
systems console.
.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:
.sp
.in +5
permit condition condition...
.br
deny condition condition...
.in
.PP
where
.I permit
and
.I deny
may be followed by zero or more conditions. Comments begin with a `#\'
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
.I deny
on it.
.SH CONDITIONS
.IP "hostname wzv.win.tue.nl"
True when the login comes from host wzv.win.tue.nl.
.IP "internet 131.155.210.0 255.255.255.0"
True when the remote host has an internet address in network
131.155.210. The general form of a net/mask rule is:
.sp
.ti +5
internet net mask
.sp
The expression is true when the host has an internet address for which
the bitwise and of
.I address
and
.I mask
equals
.IR net.
.IP "port ttya"
True when the login terminal is equal to
.IR /dev/ttya .
Remember that UNIX passwords are always permitted with logins on the
system console.
.IP "user uucp"
True when the user attempts to log in as
.IR uucp .
.IP "group wheel"
True when the user attempts to log in as a member of the
.I wheel
group.
.SH COMPATIBILITY
For the sake of backwards compatibility, the
.I internet
keyword may be omitted from net/mask patterns.
.SH DIAGNOSTICS
Syntax errors are reported to the syslogd. When an error is found
the rule is skipped.
.SH FILES
/etc/skey.access, password control table
.SH AUTHOR
.nf
Wietse Venema
Eindhoven University of Technology
The Netherlands

383
lib/libskey/skeyaccess.c Normal file
View File

@ -0,0 +1,383 @@
/*
* Figure out if UNIX passwords are permitted for any combination of user
* name, group member, terminal port, host_name or network:
*
* Programmatic interface: skeyaccess(char *user, char *port, char *host)
*
* Specify a null character pointer where information is not available.
*
* 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]
*
* Author: Wietse Venema, Eindhoven University of Technology.
*/
#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 *first_token();
static int line_number;
static void unget_token();
static char *get_token();
static char *need_token();
static char *need_internet_addr();
/*
* 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)
static int match_internet_addr();
static int match_group();
static int match_token();
static int is_internet_addr();
#define MAX_ADDR 32
#define PERMIT 1
#define DENY 0
struct login_info {
char *host_name; /* host name */
struct in_addr *internet_addr; /* null terminated list */
char *user; /* user name */
char *port; /* login port */
};
/* skeyaccess - find out if UNIX passwords are permitted */
int skeyaccess(user, port, host)
char *user;
char *port;
char *host;
{
struct hostent *hp;
struct login_info login_info;
struct in_addr internet_addr[MAX_ADDR + 1];
char hostname_buf[MAXHOSTNAMELEN + 1];
int i;
login_info.user = user;
login_info.port = port;
login_info.host_name = 0;
login_info.internet_addr = 0;
if (host) {
if (is_internet_addr(host)) { /* not DECnet */
internet_addr[0].s_addr = inet_addr(host);
internet_addr[1].s_addr = 0;
login_info.internet_addr = internet_addr;
} else {
if ((hp = gethostbyname(host)) != 0 && hp->h_addrtype == AF_INET) {
for (i = 0; i < MAX_ADDR && hp->h_addr_list[i]; i++)
memcpy((char *) &internet_addr[i],
hp->h_addr_list[i], hp->h_length);
internet_addr[i].s_addr = 0;
login_info.internet_addr = internet_addr;
host = hp->h_name;
}
strncpy(hostname_buf, host, MAXHOSTNAMELEN);
hostname_buf[MAXHOSTNAMELEN] = 0;
login_info.host_name = hostname_buf;
}
}
/*
* 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 == 0) {
printf("none\n");
} else {
for (i = 0; login_info.internet_addr[i].s_addr; i++)
printf("%s%s", inet_ntoa(login_info.internet_addr[i]),
login_info.internet_addr[i + 1].s_addr ? " " : "\n");
}
#endif
return (_skeyaccess(&login_info));
}
/* _skeyaccess - find out if UNIX passwords are permitted */
int _skeyaccess(login_info)
struct login_info *login_info;
{
FILE *fp;
char buf[BUFSIZ];
char *tok;
int match;
int permission;
#ifdef PERMIT_CONSOLE
if (login_info->port != 0 && strcasecmp(login_info->port, "console") == 0)
return (1);
#endif
/*
* 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)
return (PERMIT);
/*
* 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;
}
}
}
fclose(fp);
return (match ? permission : DENY);
}
/* match_internet_addr - match internet network address */
static int match_internet_addr(login_info)
struct login_info *login_info;
{
char *tok;
long pattern;
long mask;
struct in_addr *addrp;
struct hostent *hp;
if (login_info->internet_addr == 0)
return (0);
if ((tok = need_internet_addr()) == 0)
return (0);
pattern = inet_addr(tok);
if ((tok = need_internet_addr()) == 0)
return (0);
mask = inet_addr(tok);
/*
* See if any of the addresses matches a pattern in the control file.
* Report and skip the address if it does not belong to the remote host.
* Assume localhost == localhost.domain.
*/
#define NEQ(x,y) (strcasecmp((x),(y)) != 0)
for (addrp = login_info->internet_addr; addrp->s_addr; addrp++) {
if ((addrp->s_addr & mask) == pattern) {
if (login_info->host_name != 0 &&
((hp = gethostbyaddr((char *) addrp, sizeof(*addrp), AF_INET)) == 0
|| (NEQ(login_info->host_name, hp->h_name)
&& NEQ(login_info->host_name, "localhost")))) {
syslog(LOG_ERR, "address %s not registered for host %s",
inet_ntoa(*addrp), login_info->host_name);
continue;
}
return (1);
}
}
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
if (cp = strtok(buf, " \t"))
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 {
cp = strtok((char *) 0, " \t");
}
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;
{
int in_run = 0;
int runs = 0;
/* Count the number of runs of characters between the dots. */
while (*str) {
if (*str == '.') {
in_run = 0;
} else {
if (!isdigit(*str))
return (0);
if (in_run == 0) {
in_run = 1;
runs++;
}
}
str++;
}
return (runs == 4);
}
#ifdef TEST
main(argc, argv)
int argc;
char **argv;
{
if (argc != 3 && argc != 4) {
fprintf(stderr, "usage: %s user port [host_or_ip_address]\n", argv[0]);
exit(0);
}
openlog("login", LOG_PID, LOG_AUTH);
printf("%s\n", skeyaccess(argv[1], argv[2], argv[3]) ? "YES" : "NO");
return (0);
}
#endif