1) Added s/key support .

2  Added optional excessive login logging.
3) Added login acces control on a per host/tty base.
4) See skey(1) for skey descriptions and src/usr.bin/login/README
  for the logging and access control features.

-Guido
This commit is contained in:
Guido van Rooij 1994-05-19 18:13:11 +00:00
parent 9eb28b5fde
commit 110af3d672
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=1519
21 changed files with 4171 additions and 0 deletions

44
etc/login.access Normal file
View file

@ -0,0 +1,44 @@
# Login access control table.
#
# When someone logs in, the table is scanned for the first entry that
# matches the (user, host) combination, or, in case of non-networked
# logins, the first entry that matches the (user, tty) combination. The
# permissions field of that table entry determines whether the login will
# be accepted or refused.
#
# Format of the login access control table is three fields separated by a
# ":" character:
#
# permission : users : origins
#
# The first field should be a "+" (access granted) or "-" (access denied)
# character. The second field should be a list of one or more login names,
# group names, or ALL (always matches). The third field should be a list
# of one or more tty names (for non-networked logins), host names, domain
# names (begin with "."), host addresses, internet network numbers (end
# with "."), ALL (always matches) or LOCAL (matches any string that does
# not contain a "." character). If you run NIS you can use @netgroupname
# in host or user patterns.
#
# The EXCEPT operator makes it possible to write very compact rules.
#
# The group file is searched only when a name does not match that of the
# logged-in user. Only groups are matched in which users are explicitly
# listed: the program does not look at a user's primary group id value.
#
##############################################################################
#
# Disallow console logins to all but a few accounts.
#
#-:ALL EXCEPT wheel shutdown sync:console
#
# Disallow non-local logins to privileged accounts (group wheel).
#
#-:wheel:ALL EXCEPT LOCAL .win.tue.nl
#
# Some accounts are not allowed to login from anywhere:
#
#-:wsbscaro wsbsecr wsbspac wsbsym wscosor wstaiwde:ALL
#
# All other accounts are allowed to login from anywhere.
#

8
etc/skey.access Normal file
View file

@ -0,0 +1,8 @@
# 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

7
lib/libskey/Makefile Normal file
View file

@ -0,0 +1,7 @@
# @(#)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
.include <bsd.lib.mk>

170
lib/libskey/authfile.c Normal file
View file

@ -0,0 +1,170 @@
/* Portions taken from the skey distribution on Oct 21 1993 */
#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 <pwd.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>
#if (MAXHOSTNAMELEN < 64) /* AIX weirdness */
#undef MAXHOSTNAMELEN
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 255
#endif
#include "skey.h"
static int isaddr();
static int rdnets();
#define MAXADDR 16 /* how many addresses can a machine
* have? */
/*
* Turn host into an IP address and then look it up in the authorization
* database to determine if ordinary password logins are OK
*/
int authfile(host)
char *host;
{
char *addr[MAXADDR];
char **ap;
long n;
struct hostent *hp;
char **lp;
struct hostent *xp;
int addr_length;
if (strlen(host) == 0) {
/* Local login, okay */
return 1;
}
if (isaddr(host)) {
return rdnets(inet_addr(host));
} else {
/*
* Stash away a copy of the host address list because it will be
* clobbered by other gethostbyXXX() calls.
*/
hp = gethostbyname(host);
if (hp == NULL) {
syslog(LOG_ERR, "unknown host: %s", host);
return 0;
}
if (hp->h_addrtype != AF_INET) {
syslog(LOG_ERR, "unknown network family: %d", hp->h_addrtype);
return 0;
}
for (lp = hp->h_addr_list, ap = addr; ap < addr + MAXADDR; lp++, ap++) {
if (*lp == NULL) {
*ap = 0;
break;
} else {
if ((*ap = malloc(hp->h_length)) == 0) {
syslog(LOG_ERR, "out of memory");
return 0;
}
memcpy(*ap, *lp, hp->h_length);
}
}
addr_length = hp->h_length;
/*
* 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)
while (ap-- > addr) {
memcpy((char *) &n, *ap, addr_length);
if (rdnets(n)) {
if ((hp = gethostbyaddr(*ap, addr_length, AF_INET)) == 0
|| (NEQ(host, hp->h_name) && NEQ(host, "localhost"))) {
syslog(LOG_ERR, "IP address %s not registered for host %s",
inet_ntoa(*(struct in_addr *) * ap), host);
continue;
}
return 1;
}
}
return 0;
}
}
static int rdnets(host)
unsigned long host;
{
FILE *fp;
char buf[128],
*cp;
long pattern,
mask;
char *strtok();
int permit_it = 0;
fp = fopen("/etc/skey.access", "r");
if (fp == NULL)
return 1; /* XXX */
while (fgets(buf, sizeof(buf), fp), !feof(fp)) {
if (buf[0] == '#')
continue; /* Comment */
cp = strtok(buf, " \t");
if (cp == NULL)
continue;
/* two choices permit or deny */
if (strncasecmp(cp, "permit", 4) == 0) {
permit_it = 1;
} else {
if (strncasecmp(cp, "deny", 4) == 0) {
permit_it = 0;
} else {
continue; /* ignore this it is not
* permit/deny */
}
}
cp = strtok(NULL, " \t");
if (cp == NULL)
continue; /* Invalid line */
pattern = inet_addr(cp);
cp = strtok(NULL, " \t");
if (cp == NULL)
continue; /* Invalid line */
mask = inet_addr(cp);
if ((host & mask) == pattern) {
fclose(fp);
return permit_it;
}
}
fclose(fp);
return 0;
}
/*
* Return TRUE if string appears to be an IP address in dotted decimal;
* return FALSE otherwise (i.e., if string is a domain name)
*/
static int isaddr(s)
register char *s;
{
char c;
if (s == NULL)
return 1; /* Can't happen */
while ((c = *s++) != '\0') {
if (c != '[' && c != ']' && !isdigit(c) && c != '.')
return 0;
}
return 1;
}

316
lib/libskey/md4.c Normal file
View file

@ -0,0 +1,316 @@
/*
* md4.c -- Implementation of MD4 Message Digest Algorithm
* Updated: 2/16/90 by Ronald L. Rivest
* (C) 1990 RSA Data Security, Inc.
*
* Portability nits fixed and reformatted - 2/12/91 Phil Karn
*/
/*
* To use MD4:
* -- Include md4.h in your program
* -- Declare an MDstruct MD to hold the state of the digest computation.
* -- Initialize MD using MDbegin(&MD)
* -- For each full block (64 bytes) X you wish to process, call
* MDupdate(&MD,X,512)
* (512 is the number of bits in a full block.)
* -- For the last block (less than 64 bytes) you wish to process,
* MDupdate(&MD,X,n)
* where n is the number of bits in the partial block. A partial
* block terminates the computation, so every MD computation should
* terminate by processing a partial block, even if it has n = 0.
* -- The message digest is available in MD.buffer[0] ... MD.buffer[3].
* (Least-significant byte of each word should be output first.)
* -- You can print out the digest using MDprint(&MD)
*/
/* Implementation notes:
* This implementation assumes that longs are 32-bit quantities.
* If the machine stores the least-significant byte of an long in the
* least-addressed byte (eg., VAX and 8086), then LOWBYTEFIRST should be
* set to TRUE. Otherwise (eg., SUNS), LOWBYTEFIRST should be set to
* FALSE. Note that on machines with LOWBYTEFIRST FALSE the routine
* MDupdate modifies has a side-effect on its input array (the order of bytes
* in each word are reversed). If this is undesired a call to MDreverse(X) can
* reverse the bytes of X back into order after each call to MDupdate.
*/
#define TRUE 1
#define FALSE 0
#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
|| defined(vax) || defined (MIPSEL))
#define LOWBYTEFIRST TRUE /* Low order bytes are first in memory */
#else /* Almost all other machines are big-endian */
#define LOWBYTEFIRST FALSE
#endif
/* Compile-time includes */
#include <stdio.h>
#include "md4.h"
/* Compile-time declarations of MD4 ``magic constants'' */
#define I0 0x67452301 /* Initial values for MD buffer */
#define I1 0xefcdab89
#define I2 0x98badcfe
#define I3 0x10325476
#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
* (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
* Table 2, page 660.
*/
#define fs1 3 /* round 1 shift amounts */
#define fs2 7
#define fs3 11
#define fs4 19
#define gs1 3 /* round 2 shift amounts */
#define gs2 5
#define gs3 9
#define gs4 13
#define hs1 3 /* round 3 shift amounts */
#define hs2 9
#define hs3 11
#define hs4 15
/* Compile-time macro declarations for MD4.
* Note: The ``rot'' operator uses the variable ``tmp''.
* It assumes tmp is declared as unsigned long, so that the >>
* operator will shift in zeros rather than extending the sign bit.
*/
#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
#define h(X,Y,Z) (X^Y^Z)
#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
void MDreverse __ARGS((unsigned long *X));
/* MDprint(MDp)
* Print message digest buffer MDp as 32 hexadecimal digits.
* Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
* Each byte is printed with high-order hexadecimal digit first.
* This is a user-callable routine.
*/
void
MDprint(MDp)
MDptr MDp;
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<32;j=j+8)
printf("%02lx",(MDp->buffer[i]>>j) & 0xFF);
}
/* MDbegin(MDp)
* Initialize message digest buffer MDp.
* This is a user-callable routine.
*/
void
MDbegin(MDp)
MDptr MDp;
{
int i;
MDp->buffer[0] = I0;
MDp->buffer[1] = I1;
MDp->buffer[2] = I2;
MDp->buffer[3] = I3;
for(i=0;i<8;i++)
MDp->count[i] = 0;
MDp->done = 0;
}
/* MDreverse(X)
* Reverse the byte-ordering of every long in X.
* Assumes X is an array of 16 longs.
* The macro revx reverses the byte-ordering of the next word of X.
*/
#define revx { t = (*X << 16) | (*X >> 16); \
*X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
void
MDreverse(X)
unsigned long *X;
{
register unsigned long t;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
revx;
}
/* MDblock(MDp,X)
* Update message digest buffer MDp->buffer using 16-word data block X.
* Assumes all 16 words of X are full of data.
* Does not update MDp->count.
* This routine is not user-callable.
*/
static void
MDblock(MDp,X)
MDptr MDp;
unsigned long *X;
{
register unsigned long tmp, A, B, C, D;
#if LOWBYTEFIRST == FALSE
MDreverse(X);
#endif
A = MDp->buffer[0];
B = MDp->buffer[1];
C = MDp->buffer[2];
D = MDp->buffer[3];
/* Update the message digest buffer */
ff(A,B,C,D,0,fs1); /* Round 1 */
ff(D,A,B,C,1,fs2);
ff(C,D,A,B,2,fs3);
ff(B,C,D,A,3,fs4);
ff(A,B,C,D,4,fs1);
ff(D,A,B,C,5,fs2);
ff(C,D,A,B,6,fs3);
ff(B,C,D,A,7,fs4);
ff(A,B,C,D,8,fs1);
ff(D,A,B,C,9,fs2);
ff(C,D,A,B,10,fs3);
ff(B,C,D,A,11,fs4);
ff(A,B,C,D,12,fs1);
ff(D,A,B,C,13,fs2);
ff(C,D,A,B,14,fs3);
ff(B,C,D,A,15,fs4);
gg(A,B,C,D,0,gs1); /* Round 2 */
gg(D,A,B,C,4,gs2);
gg(C,D,A,B,8,gs3);
gg(B,C,D,A,12,gs4);
gg(A,B,C,D,1,gs1);
gg(D,A,B,C,5,gs2);
gg(C,D,A,B,9,gs3);
gg(B,C,D,A,13,gs4);
gg(A,B,C,D,2,gs1);
gg(D,A,B,C,6,gs2);
gg(C,D,A,B,10,gs3);
gg(B,C,D,A,14,gs4);
gg(A,B,C,D,3,gs1);
gg(D,A,B,C,7,gs2);
gg(C,D,A,B,11,gs3);
gg(B,C,D,A,15,gs4);
hh(A,B,C,D,0,hs1); /* Round 3 */
hh(D,A,B,C,8,hs2);
hh(C,D,A,B,4,hs3);
hh(B,C,D,A,12,hs4);
hh(A,B,C,D,2,hs1);
hh(D,A,B,C,10,hs2);
hh(C,D,A,B,6,hs3);
hh(B,C,D,A,14,hs4);
hh(A,B,C,D,1,hs1);
hh(D,A,B,C,9,hs2);
hh(C,D,A,B,5,hs3);
hh(B,C,D,A,13,hs4);
hh(A,B,C,D,3,hs1);
hh(D,A,B,C,11,hs2);
hh(C,D,A,B,7,hs3);
hh(B,C,D,A,15,hs4);
MDp->buffer[0] += A;
MDp->buffer[1] += B;
MDp->buffer[2] += C;
MDp->buffer[3] += D;
}
/* MDupdate(MDp,X,count)
* Input: MDp -- an MDptr
* X -- a pointer to an array of unsigned characters.
* count -- the number of bits of X to use.
* (if not a multiple of 8, uses high bits of last byte.)
* Update MDp using the number of bits of X given by count.
* This is the basic input routine for an MD4 user.
* The routine completes the MD computation when count < 512, so
* every MD computation should end with one call to MDupdate with a
* count less than 512. A call with count 0 will be ignored if the
* MD has already been terminated (done != 0), so an extra call with count
* 0 can be given as a ``courtesy close'' to force termination if desired.
*/
void
MDupdate(MDp,X,count)
MDptr MDp;
unsigned char *X;
unsigned int count;
{
int i,bit,byte,mask;
unsigned long tmp;
unsigned char XX[64];
unsigned char *p;
/* return with no error if this is a courtesy close with count
* zero and MDp->done is true.
*/
if(count == 0 && MDp->done)
return;
/* check to see if MD is already done and report error */
if(MDp->done){
printf("\nError: MDupdate MD already done.");
return;
}
/* Add count to MDp->count */
tmp = count;
p = MDp->count;
while(tmp){
tmp += *p;
*p++ = tmp;
tmp = tmp >> 8;
}
/* Process data */
if(count == 512){
/* Full block of data to handle */
MDblock(MDp,(unsigned long *)X);
} else if(count > 512){
/* Check for count too large */
printf("\nError: MDupdate called with illegal count value %ld.",count);
return;
} else {
/* partial block -- must be last block so finish up
* Find out how many bytes and residual bits there are
*/
byte = count >> 3;
bit = count & 7;
/* Copy X into XX since we need to modify it */
for(i=0;i<=byte;i++)
XX[i] = X[i];
for(i=byte+1;i<64;i++)
XX[i] = 0;
/* Add padding '1' bit and low-order zeros in last byte */
mask = 1 << (7 - bit);
XX[byte] = (XX[byte] | mask) & ~( mask - 1);
/* If room for bit count, finish up with this block */
if(byte <= 55){
for(i=0;i<8;i++)
XX[56+i] = MDp->count[i];
MDblock(MDp,(unsigned long *)XX);
} else {
/* need to do two blocks to finish up */
MDblock(MDp,(unsigned long *)XX);
for(i=0;i<56;i++)
XX[i] = 0;
for(i=0;i<8;i++)
XX[56+i] = MDp->count[i];
MDblock(MDp,(unsigned long *)XX);
}
/* Set flag saying we're done with MD computation */
MDp->done = 1;
}
}
/* End of md4.c */

50
lib/libskey/md4.h Normal file
View file

@ -0,0 +1,50 @@
#ifdef __STDC__
#define __ARGS(X) X /* For ANSI C */
#else
#define __ARGS(X) ()
#endif
/*
*
* md4.h -- Header file for implementation of MD4 Message Digest Algorithm
* Updated: 2/13/90 by Ronald L. Rivest
* (C) 1990 RSA Data Security, Inc.
* Reformatted and de-linted - 2/12/91 Phil Karn
*/
/* MDstruct is the data structure for a message digest computation. */
typedef struct {
unsigned long buffer[4];/* Holds 4-word result of MD computation */
unsigned char count[8]; /* Number of bits processed so far */
unsigned int done; /* Nonzero means MD computation finished */
} MDstruct, *MDptr;
/* MDbegin(MD)
* Input: MD -- an MDptr
* Initialize the MDstruct prepatory to doing a message digest computation.
*/
extern void MDbegin __ARGS((MDptr MDp));
/* MDupdate(MD,X,count)
* Input: MD -- an MDptr
* X -- a pointer to an array of unsigned characters.
* count -- the number of bits of X to use (an unsigned int).
* Updates MD using the first ``count'' bits of X.
* The array pointed to by X is not modified.
* If count is not a multiple of 8, MDupdate uses high bits of last byte.
* This is the basic input routine for a user.
* The routine terminates the MD computation when count < 512, so
* every MD computation should end with one call to MDupdate with a
* count less than 512. Zero is OK for a count.
*/
extern void MDupdate __ARGS((MDptr MDp,unsigned char *X,unsigned int count));
/* MDprint(MD)
* Input: MD -- an MDptr
* Prints message digest buffer MD as 32 hexadecimal digits.
* Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
* Each byte is printed with high-order hexadecimal digit first.
*/
extern void MDprint __ARGS((MDptr MDp));
/* End of md4.h */

2289
lib/libskey/put.c Normal file

File diff suppressed because it is too large Load diff

38
lib/libskey/skey_crypt.c Normal file
View file

@ -0,0 +1,38 @@
/* Author: Wietse Venema, Eindhoven University of Technology. */
#include <string.h>
#include <stdio.h>
#include <pwd.h>
#include "skey.h"
/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */
char *skey_crypt(pp, salt, pwd, pwok)
char *pp;
char *salt;
struct passwd *pwd;
int pwok;
{
struct skey skey;
char *p;
char *crypt();
/* Try s/key authentication even when the UNIX password is permitted. */
if (pwd != 0 && skeylookup(&skey, pwd->pw_name) == 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 (":");
}

328
lib/libskey/skeylogin.c Normal file
View file

@ -0,0 +1,328 @@
/* 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. */
#include <sys/param.h>
#ifdef QUOTA
#include <sys/quota.h>
#endif
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include "skey.h"
#define KEYFILE "/etc/skeykeys"
char *skipspace();
int skeylookup __ARGS((struct skey *mp,char *name));
#define setpriority(x,y,z) /* nothing */
/* Issue a skey challenge 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
getskeyprompt(mp,name,prompt)
struct skey *mp;
char *name;
char *prompt;
{
int rval;
sevenbit(name);
rval = skeylookup(mp,name);
strcpy(prompt,"s/key 55 latour1\n");
switch(rval){
case -1: /* File error */
return -1;
case 0: /* Lookup succeeded, return challenge */
sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed);
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;
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;
char *name;
{
int found;
int len;
long recstart;
char *cp;
struct stat statbuf;
/* See if the KEYFILE exists, and create it if not */
if(stat(KEYFILE,&statbuf) == -1 && errno == ENOENT){
mp->keyfile = fopen(KEYFILE,"w+");
(void) chmod(KEYFILE, 0644);
} else {
/* Otherwise open normally for update */
mp->keyfile = fopen(KEYFILE,"r+");
}
if(mp->keyfile == NULL)
return -1;
/* Look up user name in database */
len = strlen(name);
if( len > 8 ) len = 8; /* Added 8/2/91 - nmh */
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 */
if((mp->logname = strtok(mp->buf," \t")) == NULL)
continue;
if((cp = strtok(NULL," \t")) == NULL)
continue;
mp->n = atoi(cp);
if((mp->seed = strtok(NULL," \t")) == NULL)
continue;
if((mp->val = strtok(NULL," \t")) == 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;
{
struct timeval startval;
struct timeval endval;
long microsec;
char key[8];
char fkey[8];
char filekey[8];
time_t now;
struct tm *tm;
char tbuf[27],buf[60];
char me[80];
int rval;
char *cp;
time(&now);
tm = localtime(&now);
strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
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);
/*
gettimeofday(&startval, (char *)0 );
*/
/* 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);
mp->logname = strtok(mp->buf," \t");
cp = strtok(NULL," \t") ;
mp->seed = strtok(NULL," \t");
mp->val = strtok(NULL," \t");
/* 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);
/*
gettimeofday(&endval, (char *)0 );
microsec = (endval.tv_sec - startval.tv_sec) * 1000000 + (endval.tv_usec - startval.tv_usec);
fprintf(stderr, "window= %d micro seconds \n" , microsec);
*/
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
*/
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;
}
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;
}

225
lib/libskey/skeysubr.c Normal file
View file

@ -0,0 +1,225 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __MSDOS__
#include <dos.h>
#endif
#ifdef unix /* Assume POSIX */
#include <fcntl.h>
#include <termios.h>
#endif
#include "md4.h"
#include "skey.h"
#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
|| defined(vax) || defined (MIPSEL))
#define LITTLE_ENDIAN /* Low order bytes are first in memory */
#endif /* Almost all other machines are big-endian */
/* Crunch a key:
* concatenate the seed and the password, run through MD4 and
* collapse to 64 bits. This is defined as the user's starting key.
*/
int
keycrunch(result,seed,passwd)
char *result; /* 8-byte result */
char *seed; /* Seed, any length */
char *passwd; /* Password, any length */
{
char *buf;
MDstruct md;
unsigned int buflen;
#ifndef LITTLE_ENDIAN
int i;
register long tmp;
#endif
buflen = strlen(seed) + strlen(passwd);
if((buf = malloc(buflen+1)) == NULL)
return -1;
strcpy(buf,seed);
strcat(buf,passwd);
/* Crunch the key through MD4 */
sevenbit(buf);
MDbegin(&md);
MDupdate(&md,(unsigned char *)buf,8*buflen);
free(buf);
/* Fold result from 128 to 64 bits */
md.buffer[0] ^= md.buffer[2];
md.buffer[1] ^= md.buffer[3];
#ifdef LITTLE_ENDIAN
/* Only works on byte-addressed little-endian machines!! */
memcpy(result,(char *)md.buffer,8);
#else
/* Default (but slow) code that will convert to
* little-endian byte ordering on any machine
*/
for(i=0;i<2;i++){
tmp = md.buffer[i];
*result++ = tmp;
tmp >>= 8;
*result++ = tmp;
tmp >>= 8;
*result++ = tmp;
tmp >>= 8;
*result++ = tmp;
}
#endif
return 0;
}
/* The one-way function f(). Takes 8 bytes and returns 8 bytes in place */
void
f(x)
char *x;
{
MDstruct md;
#ifndef LITTLE_ENDIAN
register long tmp;
#endif
MDbegin(&md);
MDupdate(&md,(unsigned char *)x,64);
/* Fold 128 to 64 bits */
md.buffer[0] ^= md.buffer[2];
md.buffer[1] ^= md.buffer[3];
#ifdef LITTLE_ENDIAN
/* Only works on byte-addressed little-endian machines!! */
memcpy(x,(char *)md.buffer,8);
#else
/* Default (but slow) code that will convert to
* little-endian byte ordering on any machine
*/
tmp = md.buffer[0];
*x++ = tmp;
tmp >>= 8;
*x++ = tmp;
tmp >>= 8;
*x++ = tmp;
tmp >>= 8;
*x++ = tmp;
tmp = md.buffer[1];
*x++ = tmp;
tmp >>= 8;
*x++ = tmp;
tmp >>= 8;
*x++ = tmp;
tmp >>= 8;
*x = tmp;
#endif
}
/* Strip trailing cr/lf from a line of text */
void
rip(buf)
char *buf;
{
char *cp;
if((cp = strchr(buf,'\r')) != NULL)
*cp = '\0';
if((cp = strchr(buf,'\n')) != NULL)
*cp = '\0';
}
/************************/
#ifdef __MSDOS__
char *
readpass(buf,n)
char *buf;
int n;
{
int i;
char *cp;
for(cp=buf,i = 0; i < n ; i++)
if ((*cp++ = bdos(7,0,0)) == '\r')
break;
*cp = '\0';
printf("\n");
rip(buf);
return buf;
}
#else
char *
readpass(buf,n)
char *buf;
int n;
{
struct termios saved_ttymode;
struct termios noecho_ttymode;
/* Save normal line editing modes */
tcgetattr(0, &saved_ttymode);
/* 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);
/*
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;
}
#endif
/* removebackspaced over charaters from the string*/
backspace(buf)
char *buf;
{
char bs = 0x8;
char *cp = buf;
char *out = buf;
while(*cp){
if( *cp == bs ) {
if(out == buf){
cp++;
continue;
}
else {
cp++;
out--;
}
}
else {
*out++ = *cp++;
}
}
*out = '\0';
}
sevenbit(s)
char *s;
{
/* make sure there are only 7 bit code in the line*/
while(*s){
*s = 0x7f & ( *s);
s++;
}
}

21
usr.bin/key/Makefile Normal file
View file

@ -0,0 +1,21 @@
# @(#)Makefile 5.6 (Berkeley) 3/5/91
#
PROG= key
MAN1= key.1 skey.1
CFLAGS+=-I${.CURDIR}/../../lib
DPADD= /usr/bin/libskey.a
LDADD= -lskey
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
.endif
SRCS= skey.c
.include <bsd.prog.mk>

100
usr.bin/key/README.WZV Normal file
View file

@ -0,0 +1,100 @@
One of the nice things of S/Key is that it still leaves you the option
to use regular UNIX passwords. In fact, the presence of S/Key support
is completely invisible for a user until she has set up a password with
the keyinit command. You can permit regular UNIX passwords for local
logins, while at the same time insisting on S/Key passwords for logins
from outside.
ORIGIN
These files are modified versions of the s/key files found on
thumper.bellcore.com at 21 oct 1993. They have been fixed to
run on top of SunOS 4.1.3 and Solaris 2.3.
Installation is described at the end of this file.
USAGE
Use the keyinit command to set up a new series of s/key passwords.
wzv_6% keyinit
Updating wietse:
Old key: wz173500
Reminder - Only use this method if you are direct connected.
If you are using telnet or dial-in exit with no password and use keyinit -s.
Enter secret password:
Again secret password:
ID wietse s/key is 99 wz173501
BLAH BLA BLAH BLAH BLAH BLA
Be sure to make your secret password sufficiently long. Try using a
full sentence instead of just one single word.
You will have to do a "keyinit" on every system that you want to login
on using one-time passwords.
Whenever you log into an s/key protected system you will see
something like:
login: wietse
s/key 98 wz173501
Password:
In this case you can either enter your regular UNIX password or
your one-time s/key password. For example, I open a local window
to compute the password:
local% key 98 wz173501
Reminder - Do not use key while logged in via telnet or rlogin.
Enter secret password:
BLAH BLA BLAH BLAH BLAH BLA
The "BLAH BLA BLAH BLAH BLAH BLA" is the one-time s/key password.
If you have to type the one-time password in by hand, it is convenient
to have echo turned on so that you can correct typing errors. Just type
a newline at the "Password:" prompt:
login: wietse
s/key 98 wz173501
Password: (turning echo on)
Password:BLAH BLA BLAH BLAH BLAH BLA
The 98 in the challenge will be 97 the next time, and so on. You'll get
a warning when you are about to run out of s/key passwords, so that you
will have to run the keyinit command again.
Sometimes it is more practical to carry a piece of paper with a small
series of one-time passwords. You can generate the list with:
% key -n 10 98 wz173501
98: BLAH BLA BLAH BLAH BLAH BLA
97: ...
96: ...
Be careful when printing material like this!
INSTALLATION
To install, do: make sunos4 (or whatever), then: make install.
The UNIX password is always permitted with non-network logins. By
default, UNIX passwords are always permitted (the Bellcore code by
default disallows UNIX passwords but I think that is too painful). In
order to permit UNIX passwords only with logins from specific networks,
create a file /etc/skey.access. For example,
# 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 131.155.210.0 255.255.255.0
deny 0.0.0.0 0.0.0.0
This particular example will permit UNIX passwords with logins from any
host on network 131.155.210, but will insist on one-time passwords in
all other cases.

49
usr.bin/key/key.1 Normal file
View file

@ -0,0 +1,49 @@
.ll 6i
.pl 10.5i
.\" @(#)key.1 1.0 (Bellcore) 12/2/91
.\"
.lt 6.0i
.TH KEY 1 "2 December 1991"
.AT 3
.SH NAME
key \- Stand\-alone program for computing responses to S/Key challenges.
.SH SYNOPSIS
.B key [\-n <count>] <Sequence> <key>
.SH DESCRIPTION
.I key
Takes the optional count of the number of one time access
passwords to print
along with a (maximum) sequence number and key as command line args,
it prompts for the user's secret password, and produces both word
and hex format responses.
.SH EXAMPLE
.sh
Usage example:
.sp 0
>key \-n 5 99 th91334
.sp 0
Enter password: <your secret password is entered here>
.sp 0
OMEN US HORN OMIT BACK AHOY
.sp 0
.... 4 more passwords.
.sp 0
>
.LP
.SH OPTIONS
.LP
.B \-n <count>
the number of one time access passwords to print.
The default is one.
.SH DIAGNOSTICS
.SH BUGS
.LP
.SH SEE ALSO
.BR skey(1),
.BR keyinit(1),
.BR keysu(1),
.BR keyinfo(1)
.SH AUTHOR
Command by Phil Karn, Neil M. Haller, John S. Walden
.SH CONTACT
staff@thumper.bellcore.com

59
usr.bin/key/skey.1 Normal file
View file

@ -0,0 +1,59 @@
.ll 6i
.pl 10.5i
.\" @(#)skey.1 1.1 10/28/93
.\"
.lt 6.0i
.TH KEY 1 "28 October 1993"
.AT 3
.SH NAME
S/key \- A proceedure to use one time passwords for accessing computer systems.
.SH DESCRIPTION
.I S/key
is a proceedure for using one time password to authenticate access to
compter 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 S/key program
.I key
.sp
Usage example:
.sp 0
>key 99 th91334
.sp 0
Enter password: <your secret password is intered here>
.sp 0
OMEN US HORN OMIT BACK AHOY
.sp 0
>
.sp
The programs that are part of the S/Key system are keyinit, key, and
keyinfo. Keyinit is used to get your ID set up, key is
used to get the one time password each time,
keyinfo is used to extract information from the S/Key database.
.sp
When you run "keyinit" you inform the system of your
secret password. Running "key" then generates the
one-time passwords, and also requires your secret
password. If however, you misspell your password
while running "key", you will get a list of passwords
that will not work, and no indication about the problem.
.sp
Password sequence numbers count backward from 99. If you
don't know this, the syntax for "key" will be confusing.
.sp
You can enter the passwords using small letters, even
though the "key" program gives them in caps.
.sp
Macintosh and a general purpose PC use
are available.
.sp
Under FreeBSD, you can control, with /etc/skey.access, from which
hosts and/or networks the use of S/Key passwords is obligated.
.LP
.SH SEE ALSO
.BR keyinit(1),
.BR key(1),
.BR keyinfo(1)
.BR skey.access(5)
.SH AUTHOR
Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin

128
usr.bin/key/skey.c Normal file
View file

@ -0,0 +1,128 @@
/* Stand-alone program for computing responses to S/Key challenges.
* Takes the iteration count and seed as command line args, prompts
* for the user's key, and produces both word and hex format responses.
*
* Usage example:
* >skey 88 ka9q2
* Enter password:
* OMEN US HORN OMIT BACK AHOY
* C848 666B 6435 0A93
* >
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __MSDOS__
#include <dos.h>
#else /* Assume BSD unix */
#include <fcntl.h>
#endif
#include "libskey/md4.h"
#include "libskey/skey.h"
char *readpass();
void usage();
int getopt();
extern int optind;
extern char *optarg;
int
main(argc,argv)
int argc;
char *argv[];
{
int n,cnt,i;
char passwd[256],passwd2[256];
char key[8];
char *seed;
char buf[33];
char *slash;
cnt = 1;
while((i = getopt(argc,argv,"n:")) != EOF){
switch(i){
case 'n':
cnt = atoi(optarg);
break;
}
}
/* could be in the form <number>/<seed> */
if(argc <= optind + 1){
/*look for / in it */
if(argc <= optind){
usage(argv[0]);
return 1;
}
slash = strchr(argv[optind], '/');
if(slash == NULL){
usage(argv[0]);
return 1;
}
*slash++ = '\0';
seed = slash;
if((n = atoi(argv[optind])) < 0){
fprintf(stderr,"%s not positive\n",argv[optind]);
usage(argv[0]);
return 1;
}
}
else {
if((n = atoi(argv[optind])) < 0){
fprintf(stderr,"%s not positive\n",argv[optind]);
usage(argv[0]);
return 1;
}
seed = argv[++optind];
}
fprintf(stderr,"Reminder - Do not use this program while logged in via telnet or rlogin.\n");
/* Get user's secret password */
for(;;){
fprintf(stderr,"Enter secret password: ");
readpass(passwd,sizeof(passwd));
break;
/************
fprintf(stderr,"Again secret password: ");
readpass(passwd2,sizeof(passwd));
if(strcmp(passwd,passwd2) == 0) break;
fprintf(stderr, "Sorry no match\n");
**************/
}
/* Crunch seed and password into starting key */
if(keycrunch(key,seed,passwd) != 0){
fprintf(stderr,"%s: key crunch failed\n",argv[0]);
return 1;
}
if(cnt == 1){
while(n-- != 0)
f(key);
printf("%s\n",btoe(buf,key));
#ifdef HEXIN
printf("%s\n",put8(buf,key));
#endif
} else {
for(i=0;i<=n-cnt;i++)
f(key);
for(;i<=n;i++){
#ifdef HEXIN
printf("%d: %-29s %s\n",i,btoe(buf,key),put8(buf,key));
#else
printf("%d: %-29s\n",i,btoe(buf,key));
#endif
f(key);
}
}
return 0;
}
void
usage(s)
char *s;
{
fprintf(stderr,"Usage: %s [-n count] <sequence #>[/] <key> \n",s);
}

9
usr.bin/keyinfo/Makefile Normal file
View file

@ -0,0 +1,9 @@
# @(#)Makefile 5.5 (Berkeley) 7/1/90
MAN1= keyinfo.1
beforeinstall:
install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
${.CURDIR}/keyinfo.sh ${DESTDIR}${BINDIR}/keyinfo
.include <bsd.prog.mk>

40
usr.bin/keyinfo/keyinfo.1 Normal file
View file

@ -0,0 +1,40 @@
.ll 6i
.pl 10.5i
.\" @(#)keyinfo.1 1.1 (Bellcore) 7/20/93
.\"
.lt 6.0i
.TH KEYINFO 1 "20 July 1993"
.AT 3
.SH NAME
keyinfo \- display current S/Key sequence number and seed
.SH SYNOPSIS
.B keyinfo [username]
.SH DESCRIPTION
.I keyinfo
takes an optional user name and displays the user\'s current sequence
number and seed found in the S/Key database /etc/skeykeys.
.sp 1
The command can be useful when generating a list of passwords for use
on a field trip, by combining with the command
.I key
in the form:
.sp
>key \-n <number of passwords to print> `keyinfo`|lpr
.SH EXAMPLE
.sh
Usage example:
.sp 0
>keyinfo
.sp 0
0098 ws91340
.LP
.SH ARGUMENTS
.TP
.B username
The S/key user to display the information for. The default is
to display S/Key information on the user who invokes the command.
.SH SEE ALSO
.BR keyinit(1),
.BR key(1)
.SH AUTHOR
Command by Phil Karn, Neil M. Haller, John S. Walden

View file

@ -0,0 +1,10 @@
#!/bin/sh
# search /etc/skeykeys for the skey string for this user OR user specified
# in 1st parameter
PATH=/bin:/usr/bin
test -f /etc/skeykeys && {
WHO=${1-`id | sed 's/^[^(]*(\([^)]*\).*/\1/'`}
awk '/^'${WHO}'[ ]/ { print $2-1, $3 }' /etc/skeykeys
}

21
usr.bin/keyinit/Makefile Normal file
View file

@ -0,0 +1,21 @@
# @(#)Makefile 5.6 (Berkeley) 3/5/91
#
PROG= keyinit
MAN1= keyinit.1
CFLAGS+=-I${.CURDIR}/../../lib
DPADD= /usr/bin/libskey.a
LDADD= -lskey
.if exists(/usr/lib/libcrypt.a)
DPADD+= ${LIBCRYPT}
LDADD+= -lcrypt
.endif
SRCS= skeyinit.c
BINOWN= root
BINMODE=4555
.include <bsd.prog.mk>

64
usr.bin/keyinit/keyinit.1 Normal file
View file

@ -0,0 +1,64 @@
.ll 6i
.pl 10.5i
.\" @(#)keyinit.1 1.0 (Bellcore) 7/20/93
.\"
.lt 6.0i
.TH KEYINIT 1 "20 July 1993"
.AT 3
.SH NAME
keyinit \- Change password or add user to S/Key authentication system.
.SH SYNOPSIS
.B keyinit [\-s] [<user ID >]
.SH DESCRIPTION
.I keyinit
initializes the system so you can use S/Key one-time passwords to
login. The program will ask you to enter a secret pass phrase; enter a
phrase of several words in response. After the S/Key database has been
updated you can login using either your regular UNIX password or using
S/Key one-time passwords.
.PP
When logging in from another machine you can avoid typing a real
password over the network, by typing your S/Key pass phrase to the
\fIkey\fR command on the local machine: the program will respond with
the one-time password that you should use to log into the remote
machine. This is most conveniently done with cut-and-paste operations
using a mouse. Alternatively, you can pre-compute one-time passwords
using the \fIkey\fR command and carry them with you on a piece of paper.
.PP
\fIkeyinit\fR requires you to type your secret password, so it should
be used only on a secure terminal. For example, on the console of a
workstation. If you are using \fIkeyinit\fR while logged in over an
untrusted network, follow the instructions given below with the \-s
option.
.SH OPTIONS
.IP \-s
Set secure mode where the user is expected to have used a secure
machine to generate the first one time password. Without the \-s the
system will assume you are direct connected over secure communications
and prompt you for your secret password.
The \-s option also allows one to set the seed and count for complete
control of the parameters. You can use keyinit -s in compination with
the
.I key
command to set the seed and count if you do not like the defaults.
To do this run keyinit in one window and put in your count and seed
then run key in another window to generate the correct 6 english words
for that count and seed. You can then
"cut" and "paste" them or copy them into the keyinit window.
.sp
.LP
.B <user ID>
the ID for the user to be changed/added
.SH DIAGNOSTICS
.SH FILES
.TP
/etc/skeykeys data base of information for S/Key system.
.SH BUGS
.LP
.SH SEE ALSO
.BR skey(1),
.BR key(1),
.BR keysu(1),
.BR keyinfo(1)
.SH AUTHOR
Command by Phil Karn, Neil M. Haller, John S. Walden

195
usr.bin/keyinit/skeyinit.c Normal file
View file

@ -0,0 +1,195 @@
/* change password or add user to S/KEY authentication system.
* S/KEY is a tradmark of Bellcore */
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include "libskey/skey.h"
#include <stdio.h>
#include <time.h>
extern int optind;
extern char *optarg;
char * readpass();
int skeylookup __ARGS((struct skey *mp,char *name));
#define NAMELEN 2
int
main(argc,argv)
int argc;
char *argv[];
{
struct skey skey;
int rval,n,nn,i,defaultsetup;
char seed[18],tmp[80],key[8];
struct passwd *ppuser,*pp;
char defaultseed[17], passwd[256],passwd2[256] ;
time_t now;
struct tm *tm;
char tbuf[27],buf[60];
char lastc, me[80];
int l;
time(&now);
#if 0 /* Choose a more random seed */
tm = localtime(&now);
strftime(tbuf, sizeof(tbuf), "%M%j", tm);
#else
sprintf(tbuf, "%05ld", (long) (now % 100000));
#endif
gethostname(defaultseed,NAMELEN);
strcpy(&defaultseed[NAMELEN],tbuf);
pp = ppuser = getpwuid(getuid());
strcpy(me,pp->pw_name);
defaultsetup = 1;
if( argc > 1){
if(strcmp("-s", argv[1]) == 0)
defaultsetup = 0;
else
pp = getpwnam(argv[1]);
if(argc > 2)
pp = getpwnam(argv[2]);
}
if(pp == NULL){
printf("User unknown\n");
return 1;
}
if(strcmp( pp->pw_name,me) != 0){
if(getuid() != 0){
/* Only root can change other's passwds */
printf("Permission denied.\n");
return(1);
}
}
rval = skeylookup(&skey,pp->pw_name);
switch(rval){
case -1:
perror("error in opening database");
return 1;
case 0:
printf("Updating %s:\n",pp->pw_name);
printf("Old key: %s\n",skey.seed);
/* lets be nice if they have a skey.seed that ends in 0-8 just add one*/
l = strlen(skey.seed);
if( l > 0){
lastc = skey.seed[l-1];
if( isdigit(lastc) && lastc != '9' ){
strcpy(defaultseed, skey.seed);
defaultseed[l-1] = lastc + 1;
}
if( isdigit(lastc) && lastc == '9' && l < 16){
strcpy(defaultseed, skey.seed);
defaultseed[l-1] = '0';
defaultseed[l] = '0';
defaultseed[l+1] = '\0';
}
}
break;
case 1:
skey.val = 0; /* XXX */
printf("Adding %s:\n",pp->pw_name);
break;
}
n = 99;
if( ! defaultsetup){
printf("Reminder you need the 6 english words from the skey command.\n");
for(i=0;;i++){
if(i >= 2) exit(1);
printf("Enter sequence count from 1 to 10000: ");
fgets(tmp,sizeof(tmp),stdin);
n = atoi(tmp);
if(n > 0 && n < 10000)
break; /* Valid range */
printf("Count must be > 0 and < 10000\n");
}
}
if( !defaultsetup){
printf("Enter new key [default %s]: ", defaultseed);
fflush(stdout);
fgets(seed,sizeof(seed),stdin);
rip(seed);
if(strlen(seed) > 16){
printf("Seed truncated to 16 chars\n");
seed[16] = '\0';
}
if( seed[0] == '\0') strcpy(seed,defaultseed);
for(i=0;;i++){
if(i >= 2) exit(1);
printf("s/key %d %s\ns/key access password: ",n,seed);
fgets(tmp,sizeof(tmp),stdin);
rip(tmp);
backspace(tmp);
if(tmp[0] == '?'){
printf("Enter 6 English words from secure S/Key calculation.\n");
continue;
}
if(tmp[0] == '\0'){
exit(1);
}
if(etob(key,tmp) == 1 || atob8(key,tmp) == 0)
break; /* Valid format */
printf("Invalid format, try again with 6 English words.\n");
}
} else {
/* Get user's secret password */
fprintf(stderr,"Reminder - Only use this method if you are directly connected.\n");
fprintf(stderr,"If you are using telnet or rlogin exit with no password and use keyinit -s.\n");
for(i=0;;i++){
if(i >= 2) exit(1);
fprintf(stderr,"Enter secret password: ");
readpass(passwd,sizeof(passwd));
if(passwd[0] == '\0'){
exit(1);
}
fprintf(stderr,"Again secret password: ");
readpass(passwd2,sizeof(passwd));
if(passwd2[0] == '\0'){
exit(1);
}
if(strlen(passwd) < 4 && strlen(passwd2) < 4) {
fprintf(stderr, "Sorry your password must be longer\n\r");
exit(1);
}
if(strcmp(passwd,passwd2) == 0) break;
fprintf(stderr, "Sorry no match\n");
}
strcpy(seed,defaultseed);
/* Crunch seed and password into starting key */
if(keycrunch(key,seed,passwd) != 0){
fprintf(stderr,"%s: key crunch failed\n",argv[0]);
return 1;
}
nn = n;
while(nn-- != 0)
f(key);
}
time(&now);
tm = localtime(&now);
strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
if (skey.val == NULL)
skey.val = (char *) malloc(16+1);
btoa8(skey.val,key);
fprintf(skey.keyfile,"%s %04d %-16s %s %-21s\n",pp->pw_name,n,
seed,skey.val, tbuf);
fclose(skey.keyfile);
printf("\nID %s s/key is %d %s\n",pp->pw_name,n,seed);
printf("%s\n",btoe(buf,key));
#ifdef HEXIN
printf("%s\n",put8(buf,key));
#endif
return 0;
}