1) Added s/key support .
authorGuido van Rooij <guido@gvr.win.tue.nl>
Thu, 19 May 1994 18:13:18 +0000 (18:13 +0000)
committerGuido van Rooij <guido@gvr.win.tue.nl>
Thu, 19 May 1994 18:13:18 +0000 (18:13 +0000)
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

39 files changed:
etc/Makefile
etc/login.access [new file with mode: 0644]
etc/skey.access [new file with mode: 0644]
lib/Makefile
lib/libskey/Makefile [new file with mode: 0644]
lib/libskey/authfile.c [new file with mode: 0644]
lib/libskey/md4.c [new file with mode: 0644]
lib/libskey/md4.h [new file with mode: 0644]
lib/libskey/put.c [new file with mode: 0644]
lib/libskey/skey.h [new file with mode: 0644]
lib/libskey/skey_crypt.c [new file with mode: 0644]
lib/libskey/skeylogin.c [new file with mode: 0644]
lib/libskey/skeysubr.c [new file with mode: 0644]
libexec/ftpd/Makefile
libexec/ftpd/ftpd.c
libexec/ftpd/skey-stuff.c [new file with mode: 0644]
libexec/rexecd/Makefile
libexec/rexecd/rexecd.c
share/man/man5/Makefile
share/man/man5/login.access.5 [new file with mode: 0644]
share/man/man5/skey.access.5 [new file with mode: 0644]
usr.bin/Makefile
usr.bin/key/Makefile [new file with mode: 0644]
usr.bin/key/README.WZV [new file with mode: 0644]
usr.bin/key/key.1 [new file with mode: 0644]
usr.bin/key/skey.1 [new file with mode: 0644]
usr.bin/key/skey.c [new file with mode: 0644]
usr.bin/keyinfo/Makefile [new file with mode: 0644]
usr.bin/keyinfo/keyinfo.1 [new file with mode: 0644]
usr.bin/keyinfo/keyinfo.sh [new file with mode: 0644]
usr.bin/keyinit/Makefile [new file with mode: 0644]
usr.bin/keyinit/keyinit.1 [new file with mode: 0644]
usr.bin/keyinit/skeyinit.c [new file with mode: 0644]
usr.bin/login/Makefile
usr.bin/login/README [new file with mode: 0644]
usr.bin/login/login.access.5 [new file with mode: 0644]
usr.bin/login/login.c
usr.bin/login/login_access.c [new file with mode: 0644]
usr.bin/login/login_skey.c [new file with mode: 0644]

index e5a8166..2c4cdb9 100644 (file)
@@ -1,5 +1,5 @@
 #      from: @(#)Makefile      5.11 (Berkeley) 5/21/91
 #      from: @(#)Makefile      5.11 (Berkeley) 5/21/91
-#      $Id: Makefile,v 1.58 1994/05/17 13:03:34 jkh Exp $
+#      $Id: Makefile,v 1.59 1994/05/19 12:29:28 rgrimes Exp $
 
 NOOBJ= noobj
 
 
 NOOBJ= noobj
 
@@ -9,8 +9,9 @@ BINOWN= root
 BINGRP= wheel
 BIN1=  aliases csh.cshrc csh.login csh.logout dm.conf \
        ftpusers gettytab group hosts host.conf hosts.equiv hosts.lpd \
 BINGRP= wheel
 BIN1=  aliases csh.cshrc csh.login csh.logout dm.conf \
        ftpusers gettytab group hosts host.conf hosts.equiv hosts.lpd \
-       inetd.conf manpath.config motd myname netstart networks phones \
-       printcap protocols rc rc.local remote security services shells \
+       inetd.conf login.access manpath.config motd myname netstart \
+       networks phones printcap protocols rc rc.local remote \
+       security services shells skey.access \
        syslog.conf ttys etc.${MACHINE}/disktab rpc
 
 # -rw-rw-rw-
        syslog.conf ttys etc.${MACHINE}/disktab rpc
 
 # -rw-rw-rw-
diff --git a/etc/login.access b/etc/login.access
new file mode 100644 (file)
index 0000000..5cf5454
--- /dev/null
@@ -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.
+#
diff --git a/etc/skey.access b/etc/skey.access
new file mode 100644 (file)
index 0000000..22cdb69
--- /dev/null
@@ -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
index 89f276c..6b7ed85 100644 (file)
@@ -1,7 +1,7 @@
 #      @(#)Makefile    5.25.1.1 (Berkeley) 5/7/91
 
 SUBDIR=        csu.${MACHINE} libc libcurses libm libmalloc libpthread \
 #      @(#)Makefile    5.25.1.1 (Berkeley) 5/7/91
 
 SUBDIR=        csu.${MACHINE} libc libcurses libm libmalloc libpthread \
-       libresolv librpcsvc libtelnet libterm libutil liby
+       libresolv librpcsvc libskey libtelnet libterm libutil liby
 
 .if exists(libcrypt)
 .if !defined(NOCRYPT)
 
 .if exists(libcrypt)
 .if !defined(NOCRYPT)
diff --git a/lib/libskey/Makefile b/lib/libskey/Makefile
new file mode 100644 (file)
index 0000000..ecf4833
--- /dev/null
@@ -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>
+
diff --git a/lib/libskey/authfile.c b/lib/libskey/authfile.c
new file mode 100644 (file)
index 0000000..32b920a
--- /dev/null
@@ -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;
+}
diff --git a/lib/libskey/md4.c b/lib/libskey/md4.c
new file mode 100644 (file)
index 0000000..96bc7d0
--- /dev/null
@@ -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 */
diff --git a/lib/libskey/md4.h b/lib/libskey/md4.h
new file mode 100644 (file)
index 0000000..5f2e031
--- /dev/null
@@ -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 */
diff --git a/lib/libskey/put.c b/lib/libskey/put.c
new file mode 100644 (file)
index 0000000..1ef1ec0
--- /dev/null
@@ -0,0 +1,2289 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include "skey.h"
+
+static unsigned long extract __ARGS((char *s,int start,int length));
+static void standard __ARGS((char *word));
+static void insert __ARGS((char *s, int x, int start, int length));
+static int wsrch __ARGS((char *w,int low,int high));
+
+/* Dictionary for integer-word translations */
+char Wp[2048][4] = {
+"A",
+"ABE",
+"ACE",
+"ACT",
+"AD",
+"ADA",
+"ADD",
+"AGO",
+"AID",
+"AIM",
+"AIR",
+"ALL",
+"ALP",
+"AM",
+"AMY",
+"AN",
+"ANA",
+"AND",
+"ANN",
+"ANT",
+"ANY",
+"APE",
+"APS",
+"APT",
+"ARC",
+"ARE",
+"ARK",
+"ARM",
+"ART",
+"AS",
+"ASH",
+"ASK",
+"AT",
+"ATE",
+"AUG",
+"AUK",
+"AVE",
+"AWE",
+"AWK",
+"AWL",
+"AWN",
+"AX",
+"AYE",
+"BAD",
+"BAG",
+"BAH",
+"BAM",
+"BAN",
+"BAR",
+"BAT",
+"BAY",
+"BE",
+"BED",
+"BEE",
+"BEG",
+"BEN",
+"BET",
+"BEY",
+"BIB",
+"BID",
+"BIG",
+"BIN",
+"BIT",
+"BOB",
+"BOG",
+"BON",
+"BOO",
+"BOP",
+"BOW",
+"BOY",
+"BUB",
+"BUD",
+"BUG",
+"BUM",
+"BUN",
+"BUS",
+"BUT",
+"BUY",
+"BY",
+"BYE",
+"CAB",
+"CAL",
+"CAM",
+"CAN",
+"CAP",
+"CAR",
+"CAT",
+"CAW",
+"COD",
+"COG",
+"COL",
+"CON",
+"COO",
+"COP",
+"COT",
+"COW",
+"COY",
+"CRY",
+"CUB",
+"CUE",
+"CUP",
+"CUR",
+"CUT",
+"DAB",
+"DAD",
+"DAM",
+"DAN",
+"DAR",
+"DAY",
+"DEE",
+"DEL",
+"DEN",
+"DES",
+"DEW",
+"DID",
+"DIE",
+"DIG",
+"DIN",
+"DIP",
+"DO",
+"DOE",
+"DOG",
+"DON",
+"DOT",
+"DOW",
+"DRY",
+"DUB",
+"DUD",
+"DUE",
+"DUG",
+"DUN",
+"EAR",
+"EAT",
+"ED",
+"EEL",
+"EGG",
+"EGO",
+"ELI",
+"ELK",
+"ELM",
+"ELY",
+"EM",
+"END",
+"EST",
+"ETC",
+"EVA",
+"EVE",
+"EWE",
+"EYE",
+"FAD",
+"FAN",
+"FAR",
+"FAT",
+"FAY",
+"FED",
+"FEE",
+"FEW",
+"FIB",
+"FIG",
+"FIN",
+"FIR",
+"FIT",
+"FLO",
+"FLY",
+"FOE",
+"FOG",
+"FOR",
+"FRY",
+"FUM",
+"FUN",
+"FUR",
+"GAB",
+"GAD",
+"GAG",
+"GAL",
+"GAM",
+"GAP",
+"GAS",
+"GAY",
+"GEE",
+"GEL",
+"GEM",
+"GET",
+"GIG",
+"GIL",
+"GIN",
+"GO",
+"GOT",
+"GUM",
+"GUN",
+"GUS",
+"GUT",
+"GUY",
+"GYM",
+"GYP",
+"HA",
+"HAD",
+"HAL",
+"HAM",
+"HAN",
+"HAP",
+"HAS",
+"HAT",
+"HAW",
+"HAY",
+"HE",
+"HEM",
+"HEN",
+"HER",
+"HEW",
+"HEY",
+"HI",
+"HID",
+"HIM",
+"HIP",
+"HIS",
+"HIT",
+"HO",
+"HOB",
+"HOC",
+"HOE",
+"HOG",
+"HOP",
+"HOT",
+"HOW",
+"HUB",
+"HUE",
+"HUG",
+"HUH",
+"HUM",
+"HUT",
+"I",
+"ICY",
+"IDA",
+"IF",
+"IKE",
+"ILL",
+"INK",
+"INN",
+"IO",
+"ION",
+"IQ",
+"IRA",
+"IRE",
+"IRK",
+"IS",
+"IT",
+"ITS",
+"IVY",
+"JAB",
+"JAG",
+"JAM",
+"JAN",
+"JAR",
+"JAW",
+"JAY",
+"JET",
+"JIG",
+"JIM",
+"JO",
+"JOB",
+"JOE",
+"JOG",
+"JOT",
+"JOY",
+"JUG",
+"JUT",
+"KAY",
+"KEG",
+"KEN",
+"KEY",
+"KID",
+"KIM",
+"KIN",
+"KIT",
+"LA",
+"LAB",
+"LAC",
+"LAD",
+"LAG",
+"LAM",
+"LAP",
+"LAW",
+"LAY",
+"LEA",
+"LED",
+"LEE",
+"LEG",
+"LEN",
+"LEO",
+"LET",
+"LEW",
+"LID",
+"LIE",
+"LIN",
+"LIP",
+"LIT",
+"LO",
+"LOB",
+"LOG",
+"LOP",
+"LOS",
+"LOT",
+"LOU",
+"LOW",
+"LOY",
+"LUG",
+"LYE",
+"MA",
+"MAC",
+"MAD",
+"MAE",
+"MAN",
+"MAO",
+"MAP",
+"MAT",
+"MAW",
+"MAY",
+"ME",
+"MEG",
+"MEL",
+"MEN",
+"MET",
+"MEW",
+"MID",
+"MIN",
+"MIT",
+"MOB",
+"MOD",
+"MOE",
+"MOO",
+"MOP",
+"MOS",
+"MOT",
+"MOW",
+"MUD",
+"MUG",
+"MUM",
+"MY",
+"NAB",
+"NAG",
+"NAN",
+"NAP",
+"NAT",
+"NAY",
+"NE",
+"NED",
+"NEE",
+"NET",
+"NEW",
+"NIB",
+"NIL",
+"NIP",
+"NIT",
+"NO",
+"NOB",
+"NOD",
+"NON",
+"NOR",
+"NOT",
+"NOV",
+"NOW",
+"NU",
+"NUN",
+"NUT",
+"O",
+"OAF",
+"OAK",
+"OAR",
+"OAT",
+"ODD",
+"ODE",
+"OF",
+"OFF",
+"OFT",
+"OH",
+"OIL",
+"OK",
+"OLD",
+"ON",
+"ONE",
+"OR",
+"ORB",
+"ORE",
+"ORR",
+"OS",
+"OTT",
+"OUR",
+"OUT",
+"OVA",
+"OW",
+"OWE",
+"OWL",
+"OWN",
+"OX",
+"PA",
+"PAD",
+"PAL",
+"PAM",
+"PAN",
+"PAP",
+"PAR",
+"PAT",
+"PAW",
+"PAY",
+"PEA",
+"PEG",
+"PEN",
+"PEP",
+"PER",
+"PET",
+"PEW",
+"PHI",
+"PI",
+"PIE",
+"PIN",
+"PIT",
+"PLY",
+"PO",
+"POD",
+"POE",
+"POP",
+"POT",
+"POW",
+"PRO",
+"PRY",
+"PUB",
+"PUG",
+"PUN",
+"PUP",
+"PUT",
+"QUO",
+"RAG",
+"RAM",
+"RAN",
+"RAP",
+"RAT",
+"RAW",
+"RAY",
+"REB",
+"RED",
+"REP",
+"RET",
+"RIB",
+"RID",
+"RIG",
+"RIM",
+"RIO",
+"RIP",
+"ROB",
+"ROD",
+"ROE",
+"RON",
+"ROT",
+"ROW",
+"ROY",
+"RUB",
+"RUE",
+"RUG",
+"RUM",
+"RUN",
+"RYE",
+"SAC",
+"SAD",
+"SAG",
+"SAL",
+"SAM",
+"SAN",
+"SAP",
+"SAT",
+"SAW",
+"SAY",
+"SEA",
+"SEC",
+"SEE",
+"SEN",
+"SET",
+"SEW",
+"SHE",
+"SHY",
+"SIN",
+"SIP",
+"SIR",
+"SIS",
+"SIT",
+"SKI",
+"SKY",
+"SLY",
+"SO",
+"SOB",
+"SOD",
+"SON",
+"SOP",
+"SOW",
+"SOY",
+"SPA",
+"SPY",
+"SUB",
+"SUD",
+"SUE",
+"SUM",
+"SUN",
+"SUP",
+"TAB",
+"TAD",
+"TAG",
+"TAN",
+"TAP",
+"TAR",
+"TEA",
+"TED",
+"TEE",
+"TEN",
+"THE",
+"THY",
+"TIC",
+"TIE",
+"TIM",
+"TIN",
+"TIP",
+"TO",
+"TOE",
+"TOG",
+"TOM",
+"TON",
+"TOO",
+"TOP",
+"TOW",
+"TOY",
+"TRY",
+"TUB",
+"TUG",
+"TUM",
+"TUN",
+"TWO",
+"UN",
+"UP",
+"US",
+"USE",
+"VAN",
+"VAT",
+"VET",
+"VIE",
+"WAD",
+"WAG",
+"WAR",
+"WAS",
+"WAY",
+"WE",
+"WEB",
+"WED",
+"WEE",
+"WET",
+"WHO",
+"WHY",
+"WIN",
+"WIT",
+"WOK",
+"WON",
+"WOO",
+"WOW",
+"WRY",
+"WU",
+"YAM",
+"YAP",
+"YAW",
+"YE",
+"YEA",
+"YES",
+"YET",
+"YOU",
+"ABED",
+"ABEL",
+"ABET",
+"ABLE",
+"ABUT",
+"ACHE",
+"ACID",
+"ACME",
+"ACRE",
+"ACTA",
+"ACTS",
+"ADAM",
+"ADDS",
+"ADEN",
+"AFAR",
+"AFRO",
+"AGEE",
+"AHEM",
+"AHOY",
+"AIDA",
+"AIDE",
+"AIDS",
+"AIRY",
+"AJAR",
+"AKIN",
+"ALAN",
+"ALEC",
+"ALGA",
+"ALIA",
+"ALLY",
+"ALMA",
+"ALOE",
+"ALSO",
+"ALTO",
+"ALUM",
+"ALVA",
+"AMEN",
+"AMES",
+"AMID",
+"AMMO",
+"AMOK",
+"AMOS",
+"AMRA",
+"ANDY",
+"ANEW",
+"ANNA",
+"ANNE",
+"ANTE",
+"ANTI",
+"AQUA",
+"ARAB",
+"ARCH",
+"AREA",
+"ARGO",
+"ARID",
+"ARMY",
+"ARTS",
+"ARTY",
+"ASIA",
+"ASKS",
+"ATOM",
+"AUNT",
+"AURA",
+"AUTO",
+"AVER",
+"AVID",
+"AVIS",
+"AVON",
+"AVOW",
+"AWAY",
+"AWRY",
+"BABE",
+"BABY",
+"BACH",
+"BACK",
+"BADE",
+"BAIL",
+"BAIT",
+"BAKE",
+"BALD",
+"BALE",
+"BALI",
+"BALK",
+"BALL",
+"BALM",
+"BAND",
+"BANE",
+"BANG",
+"BANK",
+"BARB",
+"BARD",
+"BARE",
+"BARK",
+"BARN",
+"BARR",
+"BASE",
+"BASH",
+"BASK",
+"BASS",
+"BATE",
+"BATH",
+"BAWD",
+"BAWL",
+"BEAD",
+"BEAK",
+"BEAM",
+"BEAN",
+"BEAR",
+"BEAT",
+"BEAU",
+"BECK",
+"BEEF",
+"BEEN",
+"BEER",
+"BEET",
+"BELA",
+"BELL",
+"BELT",
+"BEND",
+"BENT",
+"BERG",
+"BERN",
+"BERT",
+"BESS",
+"BEST",
+"BETA",
+"BETH",
+"BHOY",
+"BIAS",
+"BIDE",
+"BIEN",
+"BILE",
+"BILK",
+"BILL",
+"BIND",
+"BING",
+"BIRD",
+"BITE",
+"BITS",
+"BLAB",
+"BLAT",
+"BLED",
+"BLEW",
+"BLOB",
+"BLOC",
+"BLOT",
+"BLOW",
+"BLUE",
+"BLUM",
+"BLUR",
+"BOAR",
+"BOAT",
+"BOCA",
+"BOCK",
+"BODE",
+"BODY",
+"BOGY",
+"BOHR",
+"BOIL",
+"BOLD",
+"BOLO",
+"BOLT",
+"BOMB",
+"BONA",
+"BOND",
+"BONE",
+"BONG",
+"BONN",
+"BONY",
+"BOOK",
+"BOOM",
+"BOON",
+"BOOT",
+"BORE",
+"BORG",
+"BORN",
+"BOSE",
+"BOSS",
+"BOTH",
+"BOUT",
+"BOWL",
+"BOYD",
+"BRAD",
+"BRAE",
+"BRAG",
+"BRAN",
+"BRAY",
+"BRED",
+"BREW",
+"BRIG",
+"BRIM",
+"BROW",
+"BUCK",
+"BUDD",
+"BUFF",
+"BULB",
+"BULK",
+"BULL",
+"BUNK",
+"BUNT",
+"BUOY",
+"BURG",
+"BURL",
+"BURN",
+"BURR",
+"BURT",
+"BURY",
+"BUSH",
+"BUSS",
+"BUST",
+"BUSY",
+"BYTE",
+"CADY",
+"CAFE",
+"CAGE",
+"CAIN",
+"CAKE",
+"CALF",
+"CALL",
+"CALM",
+"CAME",
+"CANE",
+"CANT",
+"CARD",
+"CARE",
+"CARL",
+"CARR",
+"CART",
+"CASE",
+"CASH",
+"CASK",
+"CAST",
+"CAVE",
+"CEIL",
+"CELL",
+"CENT",
+"CERN",
+"CHAD",
+"CHAR",
+"CHAT",
+"CHAW",
+"CHEF",
+"CHEN",
+"CHEW",
+"CHIC",
+"CHIN",
+"CHOU",
+"CHOW",
+"CHUB",
+"CHUG",
+"CHUM",
+"CITE",
+"CITY",
+"CLAD",
+"CLAM",
+"CLAN",
+"CLAW",
+"CLAY",
+"CLOD",
+"CLOG",
+"CLOT",
+"CLUB",
+"CLUE",
+"COAL",
+"COAT",
+"COCA",
+"COCK",
+"COCO",
+"CODA",
+"CODE",
+"CODY",
+"COED",
+"COIL",
+"COIN",
+"COKE",
+"COLA",
+"COLD",
+"COLT",
+"COMA",
+"COMB",
+"COME",
+"COOK",
+"COOL",
+"COON",
+"COOT",
+"CORD",
+"CORE",
+"CORK",
+"CORN",
+"COST",
+"COVE",
+"COWL",
+"CRAB",
+"CRAG",
+"CRAM",
+"CRAY",
+"CREW",
+"CRIB",
+"CROW",
+"CRUD",
+"CUBA",
+"CUBE",
+"CUFF",
+"CULL",
+"CULT",
+"CUNY",
+"CURB",
+"CURD",
+"CURE",
+"CURL",
+"CURT",
+"CUTS",
+"DADE",
+"DALE",
+"DAME",
+"DANA",
+"DANE",
+"DANG",
+"DANK",
+"DARE",
+"DARK",
+"DARN",
+"DART",
+"DASH",
+"DATA",
+"DATE",
+"DAVE",
+"DAVY",
+"DAWN",
+"DAYS",
+"DEAD",
+"DEAF",
+"DEAL",
+"DEAN",
+"DEAR",
+"DEBT",
+"DECK",
+"DEED",
+"DEEM",
+"DEER",
+"DEFT",
+"DEFY",
+"DELL",
+"DENT",
+"DENY",
+"DESK",
+"DIAL",
+"DICE",
+"DIED",
+"DIET",
+"DIME",
+"DINE",
+"DING",
+"DINT",
+"DIRE",
+"DIRT",
+"DISC",
+"DISH",
+"DISK",
+"DIVE",
+"DOCK",
+"DOES",
+"DOLE",
+"DOLL",
+"DOLT",
+"DOME",
+"DONE",
+"DOOM",
+"DOOR",
+"DORA",
+"DOSE",
+"DOTE",
+"DOUG",
+"DOUR",
+"DOVE",
+"DOWN",
+"DRAB",
+"DRAG",
+"DRAM",
+"DRAW",
+"DREW",
+"DRUB",
+"DRUG",
+"DRUM",
+"DUAL",
+"DUCK",
+"DUCT",
+"DUEL",
+"DUET",
+"DUKE",
+"DULL",
+"DUMB",
+"DUNE",
+"DUNK",
+"DUSK",
+"DUST",
+"DUTY",
+"EACH",
+"EARL",
+"EARN",
+"EASE",
+"EAST",
+"EASY",
+"EBEN",
+"ECHO",
+"EDDY",
+"EDEN",
+"EDGE",
+"EDGY",
+"EDIT",
+"EDNA",
+"EGAN",
+"ELAN",
+"ELBA",
+"ELLA",
+"ELSE",
+"EMIL",
+"EMIT",
+"EMMA",
+"ENDS",
+"ERIC",
+"EROS",
+"EVEN",
+"EVER",
+"EVIL",
+"EYED",
+"FACE",
+"FACT",
+"FADE",
+"FAIL",
+"FAIN",
+"FAIR",
+"FAKE",
+"FALL",
+"FAME",
+"FANG",
+"FARM",
+"FAST",
+"FATE",
+"FAWN",
+"FEAR",
+"FEAT",
+"FEED",
+"FEEL",
+"FEET",
+"FELL",
+"FELT",
+"FEND",
+"FERN",
+"FEST",
+"FEUD",
+"FIEF",
+"FIGS",
+"FILE",
+"FILL",
+"FILM",
+"FIND",
+"FINE",
+"FINK",
+"FIRE",
+"FIRM",
+"FISH",
+"FISK",
+"FIST",
+"FITS",
+"FIVE",
+"FLAG",
+"FLAK",
+"FLAM",
+"FLAT",
+"FLAW",
+"FLEA",
+"FLED",
+"FLEW",
+"FLIT",
+"FLOC",
+"FLOG",
+"FLOW",
+"FLUB",
+"FLUE",
+"FOAL",
+"FOAM",
+"FOGY",
+"FOIL",
+"FOLD",
+"FOLK",
+"FOND",
+"FONT",
+"FOOD",
+"FOOL",
+"FOOT",
+"FORD",
+"FORE",
+"FORK",
+"FORM",
+"FORT",
+"FOSS",
+"FOUL",
+"FOUR",
+"FOWL",
+"FRAU",
+"FRAY",
+"FRED",
+"FREE",
+"FRET",
+"FREY",
+"FROG",
+"FROM",
+"FUEL",
+"FULL",
+"FUME",
+"FUND",
+"FUNK",
+"FURY",
+"FUSE",
+"FUSS",
+"GAFF",
+"GAGE",
+"GAIL",
+"GAIN",
+"GAIT",
+"GALA",
+"GALE",
+"GALL",
+"GALT",
+"GAME",
+"GANG",
+"GARB",
+"GARY",
+"GASH",
+"GATE",
+"GAUL",
+"GAUR",
+"GAVE",
+"GAWK",
+"GEAR",
+"GELD",
+"GENE",
+"GENT",
+"GERM",
+"GETS",
+"GIBE",
+"GIFT",
+"GILD",
+"GILL",
+"GILT",
+"GINA",
+"GIRD",
+"GIRL",
+"GIST",
+"GIVE",
+"GLAD",
+"GLEE",
+"GLEN",
+"GLIB",
+"GLOB",
+"GLOM",
+"GLOW",
+"GLUE",
+"GLUM",
+"GLUT",
+"GOAD",
+"GOAL",
+"GOAT",
+"GOER",
+"GOES",
+"GOLD",
+"GOLF",
+"GONE",
+"GONG",
+"GOOD",
+"GOOF",
+"GORE",
+"GORY",
+"GOSH",
+"GOUT",
+"GOWN",
+"GRAB",
+"GRAD",
+"GRAY",
+"GREG",
+"GREW",
+"GREY",
+"GRID",
+"GRIM",
+"GRIN",
+"GRIT",
+"GROW",
+"GRUB",
+"GULF",
+"GULL",
+"GUNK",
+"GURU",
+"GUSH",
+"GUST",
+"GWEN",
+"GWYN",
+"HAAG",
+"HAAS",
+"HACK",
+"HAIL",
+"HAIR",
+"HALE",
+"HALF",
+"HALL",
+"HALO",
+"HALT",
+"HAND",
+"HANG",
+"HANK",
+"HANS",
+"HARD",
+"HARK",
+"HARM",
+"HART",
+"HASH",
+"HAST",
+"HATE",
+"HATH",
+"HAUL",
+"HAVE",
+"HAWK",
+"HAYS",
+"HEAD",
+"HEAL",
+"HEAR",
+"HEAT",
+"HEBE",
+"HECK",
+"HEED",
+"HEEL",
+"HEFT",
+"HELD",
+"HELL",
+"HELM",
+"HERB",
+"HERD",
+"HERE",
+"HERO",
+"HERS",
+"HESS",
+"HEWN",
+"HICK",
+"HIDE",
+"HIGH",
+"HIKE",
+"HILL",
+"HILT",
+"HIND",
+"HINT",
+"HIRE",
+"HISS",
+"HIVE",
+"HOBO",
+"HOCK",
+"HOFF",
+"HOLD",
+"HOLE",
+"HOLM",
+"HOLT",
+"HOME",
+"HONE",
+"HONK",
+"HOOD",
+"HOOF",
+"HOOK",
+"HOOT",
+"HORN",
+"HOSE",
+"HOST",
+"HOUR",
+"HOVE",
+"HOWE",
+"HOWL",
+"HOYT",
+"HUCK",
+"HUED",
+"HUFF",
+"HUGE",
+"HUGH",
+"HUGO",
+"HULK",
+"HULL",
+"HUNK",
+"HUNT",
+"HURD",
+"HURL",
+"HURT",
+"HUSH",
+"HYDE",
+"HYMN",
+"IBIS",
+"ICON",
+"IDEA",
+"IDLE",
+"IFFY",
+"INCA",
+"INCH",
+"INTO",
+"IONS",
+"IOTA",
+"IOWA",
+"IRIS",
+"IRMA",
+"IRON",
+"ISLE",
+"ITCH",
+"ITEM",
+"IVAN",
+"JACK",
+"JADE",
+"JAIL",
+"JAKE",
+"JANE",
+"JAVA",
+"JEAN",
+"JEFF",
+"JERK",
+"JESS",
+"JEST",
+"JIBE",
+"JILL",
+"JILT",
+"JIVE",
+"JOAN",
+"JOBS",
+"JOCK",
+"JOEL",
+"JOEY",
+"JOHN",
+"JOIN",
+"JOKE",
+"JOLT",
+"JOVE",
+"JUDD",
+"JUDE",
+"JUDO",
+"JUDY",
+"JUJU",
+"JUKE",
+"JULY",
+"JUNE",
+"JUNK",
+"JUNO",
+"JURY",
+"JUST",
+"JUTE",
+"KAHN",
+"KALE",
+"KANE",
+"KANT",
+"KARL",
+"KATE",
+"KEEL",
+"KEEN",
+"KENO",
+"KENT",
+"KERN",
+"KERR",
+"KEYS",
+"KICK",
+"KILL",
+"KIND",
+"KING",
+"KIRK",
+"KISS",
+"KITE",
+"KLAN",
+"KNEE",
+"KNEW",
+"KNIT",
+"KNOB",
+"KNOT",
+"KNOW",
+"KOCH",
+"KONG",
+"KUDO",
+"KURD",
+"KURT",
+"KYLE",
+"LACE",
+"LACK",
+"LACY",
+"LADY",
+"LAID",
+"LAIN",
+"LAIR",
+"LAKE",
+"LAMB",
+"LAME",
+"LAND",
+"LANE",
+"LANG",
+"LARD",
+"LARK",
+"LASS",
+"LAST",
+"LATE",
+"LAUD",
+"LAVA",
+"LAWN",
+"LAWS",
+"LAYS",
+"LEAD",
+"LEAF",
+"LEAK",
+"LEAN",
+"LEAR",
+"LEEK",
+"LEER",
+"LEFT",
+"LEND",
+"LENS",
+"LENT",
+"LEON",
+"LESK",
+"LESS",
+"LEST",
+"LETS",
+"LIAR",
+"LICE",
+"LICK",
+"LIED",
+"LIEN",
+"LIES",
+"LIEU",
+"LIFE",
+"LIFT",
+"LIKE",
+"LILA",
+"LILT",
+"LILY",
+"LIMA",
+"LIMB",
+"LIME",
+"LIND",
+"LINE",
+"LINK",
+"LINT",
+"LION",
+"LISA",
+"LIST",
+"LIVE",
+"LOAD",
+"LOAF",
+"LOAM",
+"LOAN",
+"LOCK",
+"LOFT",
+"LOGE",
+"LOIS",
+"LOLA",
+"LONE",
+"LONG",
+"LOOK",
+"LOON",
+"LOOT",
+"LORD",
+"LORE",
+"LOSE",
+"LOSS",
+"LOST",
+"LOUD",
+"LOVE",
+"LOWE",
+"LUCK",
+"LUCY",
+"LUGE",
+"LUKE",
+"LULU",
+"LUND",
+"LUNG",
+"LURA",
+"LURE",
+"LURK",
+"LUSH",
+"LUST",
+"LYLE",
+"LYNN",
+"LYON",
+"LYRA",
+"MACE",
+"MADE",
+"MAGI",
+"MAID",
+"MAIL",
+"MAIN",
+"MAKE",
+"MALE",
+"MALI",
+"MALL",
+"MALT",
+"MANA",
+"MANN",
+"MANY",
+"MARC",
+"MARE",
+"MARK",
+"MARS",
+"MART",
+"MARY",
+"MASH",
+"MASK",
+"MASS",
+"MAST",
+"MATE",
+"MATH",
+"MAUL",
+"MAYO",
+"MEAD",
+"MEAL",
+"MEAN",
+"MEAT",
+"MEEK",
+"MEET",
+"MELD",
+"MELT",
+"MEMO",
+"MEND",
+"MENU",
+"MERT",
+"MESH",
+"MESS",
+"MICE",
+"MIKE",
+"MILD",
+"MILE",
+"MILK",
+"MILL",
+"MILT",
+"MIMI",
+"MIND",
+"MINE",
+"MINI",
+"MINK",
+"MINT",
+"MIRE",
+"MISS",
+"MIST",
+"MITE",
+"MITT",
+"MOAN",
+"MOAT",
+"MOCK",
+"MODE",
+"MOLD",
+"MOLE",
+"MOLL",
+"MOLT",
+"MONA",
+"MONK",
+"MONT",
+"MOOD",
+"MOON",
+"MOOR",
+"MOOT",
+"MORE",
+"MORN",
+"MORT",
+"MOSS",
+"MOST",
+"MOTH",
+"MOVE",
+"MUCH",
+"MUCK",
+"MUDD",
+"MUFF",
+"MULE",
+"MULL",
+"MURK",
+"MUSH",
+"MUST",
+"MUTE",
+"MUTT",
+"MYRA",
+"MYTH",
+"NAGY",
+"NAIL",
+"NAIR",
+"NAME",
+"NARY",
+"NASH",
+"NAVE",
+"NAVY",
+"NEAL",
+"NEAR",
+"NEAT",
+"NECK",
+"NEED",
+"NEIL",
+"NELL",
+"NEON",
+"NERO",
+"NESS",
+"NEST",
+"NEWS",
+"NEWT",
+"NIBS",
+"NICE",
+"NICK",
+"NILE",
+"NINA",
+"NINE",
+"NOAH",
+"NODE",
+"NOEL",
+"NOLL",
+"NONE",
+"NOOK",
+"NOON",
+"NORM",
+"NOSE",
+"NOTE",
+"NOUN",
+"NOVA",
+"NUDE",
+"NULL",
+"NUMB",
+"OATH",
+"OBEY",
+"OBOE",
+"ODIN",
+"OHIO",
+"OILY",
+"OINT",
+"OKAY",
+"OLAF",
+"OLDY",
+"OLGA",
+"OLIN",
+"OMAN",
+"OMEN",
+"OMIT",
+"ONCE",
+"ONES",
+"ONLY",
+"ONTO",
+"ONUS",
+"ORAL",
+"ORGY",
+"OSLO",
+"OTIS",
+"OTTO",
+"OUCH",
+"OUST",
+"OUTS",
+"OVAL",
+"OVEN",
+"OVER",
+"OWLY",
+"OWNS",
+"QUAD",
+"QUIT",
+"QUOD",
+"RACE",
+"RACK",
+"RACY",
+"RAFT",
+"RAGE",
+"RAID",
+"RAIL",
+"RAIN",
+"RAKE",
+"RANK",
+"RANT",
+"RARE",
+"RASH",
+"RATE",
+"RAVE",
+"RAYS",
+"READ",
+"REAL",
+"REAM",
+"REAR",
+"RECK",
+"REED",
+"REEF",
+"REEK",
+"REEL",
+"REID",
+"REIN",
+"RENA",
+"REND",
+"RENT",
+"REST",
+"RICE",
+"RICH",
+"RICK",
+"RIDE",
+"RIFT",
+"RILL",
+"RIME",
+"RING",
+"RINK",
+"RISE",
+"RISK",
+"RITE",
+"ROAD",
+"ROAM",
+"ROAR",
+"ROBE",
+"ROCK",
+"RODE",
+"ROIL",
+"ROLL",
+"ROME",
+"ROOD",
+"ROOF",
+"ROOK",
+"ROOM",
+"ROOT",
+"ROSA",
+"ROSE",
+"ROSS",
+"ROSY",
+"ROTH",
+"ROUT",
+"ROVE",
+"ROWE",
+"ROWS",
+"RUBE",
+"RUBY",
+"RUDE",
+"RUDY",
+"RUIN",
+"RULE",
+"RUNG",
+"RUNS",
+"RUNT",
+"RUSE",
+"RUSH",
+"RUSK",
+"RUSS",
+"RUST",
+"RUTH",
+"SACK",
+"SAFE",
+"SAGE",
+"SAID",
+"SAIL",
+"SALE",
+"SALK",
+"SALT",
+"SAME",
+"SAND",
+"SANE",
+"SANG",
+"SANK",
+"SARA",
+"SAUL",
+"SAVE",
+"SAYS",
+"SCAN",
+"SCAR",
+"SCAT",
+"SCOT",
+"SEAL",
+"SEAM",
+"SEAR",
+"SEAT",
+"SEED",
+"SEEK",
+"SEEM",
+"SEEN",
+"SEES",
+"SELF",
+"SELL",
+"SEND",
+"SENT",
+"SETS",
+"SEWN",
+"SHAG",
+"SHAM",
+"SHAW",
+"SHAY",
+"SHED",
+"SHIM",
+"SHIN",
+"SHOD",
+"SHOE",
+"SHOT",
+"SHOW",
+"SHUN",
+"SHUT",
+"SICK",
+"SIDE",
+"SIFT",
+"SIGH",
+"SIGN",
+"SILK",
+"SILL",
+"SILO",
+"SILT",
+"SINE",
+"SING",
+"SINK",
+"SIRE",
+"SITE",
+"SITS",
+"SITU",
+"SKAT",
+"SKEW",
+"SKID",
+"SKIM",
+"SKIN",
+"SKIT",
+"SLAB",
+"SLAM",
+"SLAT",
+"SLAY",
+"SLED",
+"SLEW",
+"SLID",
+"SLIM",
+"SLIT",
+"SLOB",
+"SLOG",
+"SLOT",
+"SLOW",
+"SLUG",
+"SLUM",
+"SLUR",
+"SMOG",
+"SMUG",
+"SNAG",
+"SNOB",
+"SNOW",
+"SNUB",
+"SNUG",
+"SOAK",
+"SOAR",
+"SOCK",
+"SODA",
+"SOFA",
+"SOFT",
+"SOIL",
+"SOLD",
+"SOME",
+"SONG",
+"SOON",
+"SOOT",
+"SORE",
+"SORT",
+"SOUL",
+"SOUR",
+"SOWN",
+"STAB",
+"STAG",
+"STAN",
+"STAR",
+"STAY",
+"STEM",
+"STEW",
+"STIR",
+"STOW",
+"STUB",
+"STUN",
+"SUCH",
+"SUDS",
+"SUIT",
+"SULK",
+"SUMS",
+"SUNG",
+"SUNK",
+"SURE",
+"SURF",
+"SWAB",
+"SWAG",
+"SWAM",
+"SWAN",
+"SWAT",
+"SWAY",
+"SWIM",
+"SWUM",
+"TACK",
+"TACT",
+"TAIL",
+"TAKE",
+"TALE",
+"TALK",
+"TALL",
+"TANK",
+"TASK",
+"TATE",
+"TAUT",
+"TEAL",
+"TEAM",
+"TEAR",
+"TECH",
+"TEEM",
+"TEEN",
+"TEET",
+"TELL",
+"TEND",
+"TENT",
+"TERM",
+"TERN",
+"TESS",
+"TEST",
+"THAN",
+"THAT",
+"THEE",
+"THEM",
+"THEN",
+"THEY",
+"THIN",
+"THIS",
+"THUD",
+"THUG",
+"TICK",
+"TIDE",
+"TIDY",
+"TIED",
+"TIER",
+"TILE",
+"TILL",
+"TILT",
+"TIME",
+"TINA",
+"TINE",
+"TINT",
+"TINY",
+"TIRE",
+"TOAD",
+"TOGO",
+"TOIL",
+"TOLD",
+"TOLL",
+"TONE",
+"TONG",
+"TONY",
+"TOOK",
+"TOOL",
+"TOOT",
+"TORE",
+"TORN",
+"TOTE",
+"TOUR",
+"TOUT",
+"TOWN",
+"TRAG",
+"TRAM",
+"TRAY",
+"TREE",
+"TREK",
+"TRIG",
+"TRIM",
+"TRIO",
+"TROD",
+"TROT",
+"TROY",
+"TRUE",
+"TUBA",
+"TUBE",
+"TUCK",
+"TUFT",
+"TUNA",
+"TUNE",
+"TUNG",
+"TURF",
+"TURN",
+"TUSK",
+"TWIG",
+"TWIN",
+"TWIT",
+"ULAN",
+"UNIT",
+"URGE",
+"USED",
+"USER",
+"USES",
+"UTAH",
+"VAIL",
+"VAIN",
+"VALE",
+"VARY",
+"VASE",
+"VAST",
+"VEAL",
+"VEDA",
+"VEIL",
+"VEIN",
+"VEND",
+"VENT",
+"VERB",
+"VERY",
+"VETO",
+"VICE",
+"VIEW",
+"VINE",
+"VISE",
+"VOID",
+"VOLT",
+"VOTE",
+"WACK",
+"WADE",
+"WAGE",
+"WAIL",
+"WAIT",
+"WAKE",
+"WALE",
+"WALK",
+"WALL",
+"WALT",
+"WAND",
+"WANE",
+"WANG",
+"WANT",
+"WARD",
+"WARM",
+"WARN",
+"WART",
+"WASH",
+"WAST",
+"WATS",
+"WATT",
+"WAVE",
+"WAVY",
+"WAYS",
+"WEAK",
+"WEAL",
+"WEAN",
+"WEAR",
+"WEED",
+"WEEK",
+"WEIR",
+"WELD",
+"WELL",
+"WELT",
+"WENT",
+"WERE",
+"WERT",
+"WEST",
+"WHAM",
+"WHAT",
+"WHEE",
+"WHEN",
+"WHET",
+"WHOA",
+"WHOM",
+"WICK",
+"WIFE",
+"WILD",
+"WILL",
+"WIND",
+"WINE",
+"WING",
+"WINK",
+"WINO",
+"WIRE",
+"WISE",
+"WISH",
+"WITH",
+"WOLF",
+"WONT",
+"WOOD",
+"WOOL",
+"WORD",
+"WORE",
+"WORK",
+"WORM",
+"WORN",
+"WOVE",
+"WRIT",
+"WYNN",
+"YALE",
+"YANG",
+"YANK",
+"YARD",
+"YARN",
+"YAWL",
+"YAWN",
+"YEAH",
+"YEAR",
+"YELL",
+"YOGA",
+"YOKE"
+};
+
+/* Encode 8 bytes in 'c' as a string of English words.
+ * Returns a pointer to a static buffer
+ */
+char *
+btoe(engout,c)
+char *c, *engout;
+{
+       char cp[9];     /* add in room for the parity 2 bits*/
+       int p,i ;
+
+       engout[0] = '\0';
+       memcpy(cp, c,8);
+       /* compute parity */
+       for(p = 0,i = 0; i < 64;i += 2)
+               p += extract(cp,i,2);
+
+       cp[8] = (char)p << 6;
+       strncat(engout,&Wp[extract(cp, 0,11)][0],4);
+       strcat(engout," ");
+       strncat(engout,&Wp[extract(cp,11,11)][0],4);
+       strcat(engout," ");
+       strncat(engout,&Wp[extract(cp,22,11)][0],4);
+       strcat(engout," ");
+       strncat(engout,&Wp[extract(cp,33,11)][0],4);
+       strcat(engout," ");
+       strncat(engout,&Wp[extract(cp,44,11)][0],4);
+       strcat(engout," ");
+       strncat(engout,&Wp[extract(cp,55,11)][0],4);
+#ifdef notdef
+       printf("engout is %s\n\r",engout);
+#endif
+       return(engout);
+}
+
+/* convert English to binary   
+ * returns 1 OK - all good words and parity is OK   
+ *         0 word not in data base
+ *        -1 badly formed in put ie > 4 char word
+ *        -2 words OK but parity is wrong
+ */
+int
+etob(out, e)
+char *out;
+char *e;
+{
+       char *word;
+       int i, p, v,l, low,high;
+       char b[9];
+       char input[36];
+
+       if(e == NULL)
+               return -1;
+
+       strncpy(input,e,sizeof(input));
+       memset(b, 0, sizeof(b));
+       memset(out, 0, 8);
+       for(i=0,p=0;i<6;i++,p+=11){
+               if((word = strtok(i == 0 ? input : NULL," ")) == NULL)
+                       return -1;
+               l = strlen(word);
+               if(l > 4 || l < 1){
+                       return -1;
+               } else if(l < 4){
+                       low = 0;
+                       high = 570;
+               } else {
+                       low = 571;
+                       high = 2047;
+               }
+               standard(word);
+               if( (v = wsrch(word,low,high)) < 0 )
+                       return 0;
+               insert(b,v,p,11);
+       }
+
+       /* now check the parity of what we got */
+       for(p = 0, i = 0; i < 64; i +=2)
+               p += extract(b, i, 2);
+
+       if( (p & 3) != extract(b, 64,2) )
+               return -2;
+
+       memcpy(out,b,8);
+
+       return 1;
+}
+/* Display 8 bytes as a series of 16-bit hex digits */
+char *
+put8(out,s)
+char *out;
+char *s;
+{
+       sprintf(out,"%02X%02X %02X%02X %02X%02X %02X%02X",
+               s[0] & 0xff,s[1] & 0xff,s[2] & 0xff,
+               s[3] & 0xff,s[4] & 0xff,s[5] & 0xff,
+               s[6] & 0xff,s[7] & 0xff);
+       return out;
+}
+#ifdef notdef
+/* Encode 8 bytes in 'cp' as stream of ascii letters.
+ * Provided as a possible alternative to btoe()
+ */
+char *
+btoc(cp)
+char *cp;
+{
+       int i;
+       static char out[31];
+
+       /* code out put by characters 6 bits each added to 0x21 (!)*/
+       for(i=0;i <= 10;i++){
+               /* last one is only 4 bits not 6*/
+               out[i] = '!'+ extract(cp,6*i,i >= 10 ? 4:6);
+       }
+       out[i] = '\0';
+       return(out);
+}
+#endif
+
+/* Internal subroutines for word encoding/decoding */
+
+/* Dictionary binary search */
+static int
+wsrch(w,low,high)
+char *w;
+int low, high;
+{
+       int i,j;
+
+       for(;;){
+               i = (low + high)/2;
+               if((j = strncmp(w,Wp[i],4)) == 0)
+                       return i;       /* Found it */
+               if(high == low+1){
+                       /* Avoid effects of integer truncation in /2 */
+                       if(strncmp(w,Wp[high],4) == 0)
+                               return high;
+                       else
+                               return -1;
+               }
+               if(low >= high)
+                       return -1;      /* I don't *think* this can happen...*/
+               if(j < 0)
+                       high = i;       /* Search lower half */
+               else
+                       low = i;        /* Search upper half */
+       }
+}
+static void
+insert(s, x, start, length)
+char *s;
+int x;
+int  start, length;
+{
+       unsigned char cl;
+       unsigned char cc;
+       unsigned char cr;
+       unsigned long y;
+       int shift;
+
+       assert(length <= 11);
+       assert(start >= 0);
+       assert(length >= 0);
+       assert(start +length <= 66);
+
+       shift = ((8  -(( start + length) % 8))%8);
+       y = (long) x << shift;
+       cl = (y >> 16) & 0xff;
+       cc = (y >> 8) & 0xff;
+       cr = y & 0xff;
+       if(shift + length > 16){
+               s[start /8] |= cl;
+               s[start/8 +1] |= cc;
+               s[start/8 +2] |= cr;
+       } else if(shift +length > 8){
+               s[start/8] |= cc;
+               s[start/8 + 1] |= cr;
+       } else {
+               s[start/8] |= cr;
+       }
+}
+
+static void
+standard(word)
+register char *word;
+{
+       while(*word){
+               if(!isascii(*word))
+                       break;
+               if(islower(*word))
+                       *word = toupper(*word);
+               if(*word == '1')
+                       *word = 'L';
+               if(*word == '0')
+                       *word = 'O';
+               if(*word == '5')
+                       *word = 'S';
+               word++;
+       }
+}
+
+/* Extract 'length' bits from the char array 's' starting with bit 'start' */
+static unsigned long
+extract(s, start, length)
+char *s;
+int start, length;
+{
+       unsigned char cl;
+       unsigned char cc;
+       unsigned char cr;
+       unsigned long x;
+
+       assert(length <= 11);
+       assert(start >= 0);
+       assert(length >= 0);
+       assert(start +length <= 66);
+
+       cl = s[start/8];
+       cc = s[start/8 +1];
+       cr = s[start/8 +2];
+       x = ((long)(cl<<8 | cc) <<8  | cr) ;
+       x = x >> (24 - (length + (start %8)));
+       x =( x & (0xffff >> (16-length) )   );
+       return(x);
+}
+
diff --git a/lib/libskey/skey.h b/lib/libskey/skey.h
new file mode 100644 (file)
index 0000000..1544713
--- /dev/null
@@ -0,0 +1,42 @@
+#if    defined(__TURBOC__) || defined(__STDC__) || defined(LATTICE)
+#define        ANSIPROTO       1
+#endif
+
+#ifndef        __ARGS
+#ifdef ANSIPROTO
+#define        __ARGS(x)       x
+#else
+#define        __ARGS(x)       ()
+#endif
+#endif
+
+/* 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*/
+
+
+};
+
+/* Client-side structure for scanning data stream for challenge */
+struct mc {
+       char buf[256];
+       int skip;
+       int cnt;
+};
+
+void f __ARGS((char *x));
+int keycrunch __ARGS((char *result,char *seed,char *passwd));
+char *btoe __ARGS((char *engout,char *c));
+char *put8 __ARGS((char *out,char *s));
+int etob __ARGS((char *out,char *e));
+void rip __ARGS((char *buf));
+int skeychallenge __ARGS((struct skey *mp,char *name, char *challenge));
+int skeylookup __ARGS((struct skey *mp,char *name));
+int skeyverify __ARGS((struct skey *mp,char *response));
+int skeyverify __ARGS((struct skey *mp,char *response));
diff --git a/lib/libskey/skey_crypt.c b/lib/libskey/skey_crypt.c
new file mode 100644 (file)
index 0000000..ca1024f
--- /dev/null
@@ -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 (":");
+}
diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c
new file mode 100644 (file)
index 0000000..bc49cb7
--- /dev/null
@@ -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;
+}
diff --git a/lib/libskey/skeysubr.c b/lib/libskey/skeysubr.c
new file mode 100644 (file)
index 0000000..9762f1a
--- /dev/null
@@ -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++;
+       }
+}
index fe7ffd1..91b1a73 100644 (file)
@@ -2,16 +2,19 @@
 
 
 PROG=  ftpd
 
 
 PROG=  ftpd
-CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp -DSETPROCTITLE
-SRCS=  ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c
+CFLAGS+=-I${.CURDIR}/../../usr.bin/ftp -I${.CURDIR}/../../lib \
+       -DSETPROCTITLE -DSKEY
+SRCS=  ftpd.c ftpcmd.c glob.c logwtmp.c popen.c vers.c skey-stuff.c
 MAN8=  ftpd.8
 CLEANFILES+=ftpcmd.c y.tab.h
 .PATH: ${.CURDIR}/../../usr.bin/ftp
 
 MAN8=  ftpd.8
 CLEANFILES+=ftpcmd.c y.tab.h
 .PATH: ${.CURDIR}/../../usr.bin/ftp
 
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
+
 .if exists(/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
 LDADD+= -lcrypt
 .endif
 
 .if exists(/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
 LDADD+= -lcrypt
 .endif
 
-
 .include <bsd.prog.mk>
 .include <bsd.prog.mk>
index 2638e8d..701d2a2 100644 (file)
@@ -144,6 +144,11 @@ char       *LastArgv = NULL;       /* end of argv */
 char   proctitle[BUFSIZ];      /* initial part of title */
 #endif /* SETPROCTITLE */
 
 char   proctitle[BUFSIZ];      /* initial part of title */
 #endif /* SETPROCTITLE */
 
+#ifdef SKEY
+int    pwok = 0;
+char   *skey_challenge();
+char   *skey_crypt();
+#endif
 main(argc, argv, envp)
        int argc;
        char *argv[];
 main(argc, argv, envp)
        int argc;
        char *argv[];
@@ -151,6 +156,9 @@ main(argc, argv, envp)
 {
        int addrlen, on = 1, tos;
        char *cp;
 {
        int addrlen, on = 1, tos;
        char *cp;
+#ifdef SKEY
+       char addr_string[20];   /* XXX */
+#endif
 
        /*
         * LOG_NDELAY sets up the logging connection immediately,
 
        /*
         * LOG_NDELAY sets up the logging connection immediately,
@@ -162,6 +170,10 @@ main(argc, argv, envp)
                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
                exit(1);
        }
                syslog(LOG_ERR, "getpeername (%s): %m",argv[0]);
                exit(1);
        }
+#ifdef SKEY
+       strcpy(addr_string, inet_ntoa(his_addr.sin_addr));
+       pwok = authfile(addr_string);
+#endif
        addrlen = sizeof (ctrl_addr);
        if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
        addrlen = sizeof (ctrl_addr);
        if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) {
                syslog(LOG_ERR, "getsockname (%s): %m",argv[0]);
@@ -384,7 +396,11 @@ user(name)
                        return;
                }
        }
                        return;
                }
        }
+#ifdef SKEY
+       reply(331, "%s", skey_challenge(name, pw, pwok));
+#else
        reply(331, "Password required for %s.", name);
        reply(331, "Password required for %s.", name);
+#endif
        askpasswd = 1;
        /*
         * Delay before reading passwd after first failed
        askpasswd = 1;
        /*
         * Delay before reading passwd after first failed
@@ -448,7 +464,11 @@ pass(passwd)
                        salt = "xx";
                else
                        salt = pw->pw_passwd;
                        salt = "xx";
                else
                        salt = pw->pw_passwd;
+#ifdef SKEY
+               xpasswd = skey_crypt(passwd, salt, pw, pwok);
+#else
                xpasswd = crypt(passwd, salt);
                xpasswd = crypt(passwd, salt);
+#endif
                /* The strcmp does not catch null passwords! */
                if (pw == NULL || *pw->pw_passwd == '\0' ||
                    strcmp(xpasswd, pw->pw_passwd)) {
                /* The strcmp does not catch null passwords! */
                if (pw == NULL || *pw->pw_passwd == '\0' ||
                    strcmp(xpasswd, pw->pw_passwd)) {
diff --git a/libexec/ftpd/skey-stuff.c b/libexec/ftpd/skey-stuff.c
new file mode 100644 (file)
index 0000000..c4e4912
--- /dev/null
@@ -0,0 +1,23 @@
+/* Author: Wietse Venema, Eindhoven University of Technology. */
+
+#include <stdio.h>
+#include <pwd.h>
+
+#include "libskey/skey.h"
+
+/* skey_challenge - additional password prompt stuff */
+
+char   *skey_challenge(name, pwd, pwok)
+char   *name;
+struct passwd *pwd;
+int     pwok;
+{
+    static char buf[128];
+    struct skey skey;
+
+    /* Display s/key challenge where appropriate. */
+
+    if (pwd == 0 || skeychallenge(&skey, pwd->pw_name, buf) != 0)
+       sprintf(buf, "Password required for %s.", name);
+    return (buf);
+}
index 093e9a6..5916212 100644 (file)
@@ -2,6 +2,12 @@
 
 PROG=  rexecd
 MAN8=  rexecd.8
 
 PROG=  rexecd
 MAN8=  rexecd.8
+CFLAGS+= -DSKEY
+
+.PATH: ${.CURDIR}/../../usr.bin/key
+
+DPADD+= /usr/lib/libskey.a
+LDADD+= -lskey
 
 .if exists(/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
 
 .if exists(/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
index a88f92b..ff2704b 100644 (file)
@@ -98,7 +98,13 @@ doit(f, fromp)
        struct sockaddr_in *fromp;
 {
        char cmdbuf[NCARGS+1], *cp, *namep;
        struct sockaddr_in *fromp;
 {
        char cmdbuf[NCARGS+1], *cp, *namep;
+#ifdef SKEY
+       char *skey_crypt();
+       int permit_passwd = authfile(inet_ntoa(fromp->sin_addr));
+       char user[16], pass[100];
+#else /* SKEY */
        char user[16], pass[16];
        char user[16], pass[16];
+#endif /* SKEY */
        struct passwd *pwd;
        int s;
        u_short port;
        struct passwd *pwd;
        int s;
        u_short port;
@@ -154,7 +160,11 @@ doit(f, fromp)
        }
        endpwent();
        if (*pwd->pw_passwd != '\0') {
        }
        endpwent();
        if (*pwd->pw_passwd != '\0') {
+#ifdef SKEY
+               namep = skey_crypt(pass, pwd->pw_passwd, pwd, permit_passwd);
+#else /* SKEY */
                namep = crypt(pass, pwd->pw_passwd);
                namep = crypt(pass, pwd->pw_passwd);
+#endif /* SKEY */
                if (strcmp(namep, pwd->pw_passwd)) {
                        error("Password incorrect.\n");
                        exit(1);
                if (strcmp(namep, pwd->pw_passwd)) {
                        error("Password incorrect.\n");
                        exit(1);
index 4fe2321..9f05dfc 100644 (file)
@@ -2,10 +2,10 @@
 # Clean up and added pcfs, humm should pcfs be a subdir i386?
 
 MAN5=  a.out.5 acct.5 core.5 dir.5 disktab.5 \
 # Clean up and added pcfs, humm should pcfs be a subdir i386?
 
 MAN5=  a.out.5 acct.5 core.5 dir.5 disktab.5 \
-       fs.5 fstab.5 group.5 hosts.5 networks.5 \
-       passwd.5 pcfs.5 phones.5 printcap.5 \
+       fs.5 fstab.5 group.5 hosts.5 login.access.5 \
+       networks.5 passwd.5 pcfs.5 phones.5 printcap.5 \
        protocols.5 remote.5 resolver.5 services.5 \
        protocols.5 remote.5 resolver.5 services.5 \
-       shells.5 stab.5 types.5 utmp.5
+       shells.5 skey.access.5 stab.5 types.5 utmp.5
 
 MLINKS=        fs.5 inode.5 utmp.5 wtmp.5 utmp.5 lastlog.5
 
 
 MLINKS=        fs.5 inode.5 utmp.5 wtmp.5 utmp.5 lastlog.5
 
diff --git a/share/man/man5/login.access.5 b/share/man/man5/login.access.5
new file mode 100644 (file)
index 0000000..effa71e
--- /dev/null
@@ -0,0 +1,45 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt SKEY.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm login.access
+.Nd Login access control table
+.Sh DESCRIPTION
+The
+.Nm login.access
+file specifies (user, host) combinations and/or (user, tty) 
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the 
+.Nm login.access
+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.
+.Pp
+Each line of the login access control table has 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
+or wildcards.  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 ".") or
+wildcards.
+.Pp
+The following wildcards are supported: ALL matches any string; LOCAL
+matches any string that does not contain a "." character.
+.Sh FILES
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+The
+.Nm login.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr login 1
+.Sh AUTHOR
+Guido van Rooij
diff --git a/share/man/man5/skey.access.5 b/share/man/man5/skey.access.5
new file mode 100644 (file)
index 0000000..0892437
--- /dev/null
@@ -0,0 +1,34 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt SKEY.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm skey.access
+.Nd List of S/Key obligated host adresses
+.Sh DESCRIPTION
+The
+.Nm skey.access
+file contains a number of lines specifying host IP adresses
+for which the use of S/Key passwords is obligated.
+.Pp
+The first word of each line says if UNIX passwords are 
+to be permitted or denied. When denied, only S/Key passwords
+are allowed.
+The  remainder of the rule is a networknumber and mask. A rule matches a
+host if any of its addresses satisfies:
+       network = (address & mask)
+.Sh FILES
+.Bl -tag -width /etc/skey.access -compact
+.It Pa /etc/skey.access
+The
+.Nm skey.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr skey 1 ,
+.Xr keyinit 1 ,
+.Xr key 1 ,
+.Xr keyinfo 1
+.Sh AUTHOR
+Guido van Rooij
index 4264e4c..cde9822 100644 (file)
@@ -5,16 +5,16 @@ SUBDIR=       ar at basename bdes biff cal calendar cap_mkdb checknr chat chpass \
         cksum cmp col colcrt colrm column comm compress crontab ctags cut \
        dirname du elvis elvisrecover env error expand f2c false file find \
        finger fmt fold fpr from fsplit fstat ftp getopt gprof groups head \
         cksum cmp col colcrt colrm column comm compress crontab ctags cut \
        dirname du elvis elvisrecover env error expand f2c false file find \
        finger fmt fold fpr from fsplit fstat ftp getopt gprof groups head \
-       hexdump id indent ipcrm ipcs join ktrace last lastcomm leave lex \
-       locate lock logger login logname look lorder m4 machine mail make \
-       mesg mkdep mkfifo mkstr more msgs mt netstat nfsstat nice nm nohup \
-       pagesize passwd paste printenv printf quota ranlib rdist ref renice \
-       rev rlogin rpcgen rpcinfo rsh rup ruptime rusers rwall rwho script \
-       sed shar showmount size soelim split strings strip su symorder \
-       syscons tail talk tcopy tee telnet tftp time tip tn3270 touch tput \
-       tr true tset tsort tty ul uname unexpand unifdef uniq unvis users \
-       uudecode uuencode vacation vgrind vi vis vmstat w wall wc what \
-       whereis which who whoami whois window write xargs xinstall xstr \
-       yacc yes
+       hexdump id indent ipcrm ipcs join key keyinfo keyinit ktrace last \
+       lastcomm leave lex locate lock logger login logname look lorder \
+       m4 machine mail make mesg mkdep mkfifo mkstr more msgs mt netstat \
+       nfsstat nice nm nohup pagesize passwd paste printenv printf quota \
+       ranlib rdist ref renice rev rlogin rpcgen rpcinfo rsh rup ruptime \
+       rusers rwall rwho script sed shar showmount size soelim split \
+       strings strip su symorder syscons tail talk tcopy tee telnet \
+       tftp time tip tn3270 touch tput tr true tset tsort tty ul \
+       uname unexpand unifdef uniq unvis users uudecode uuencode \
+       vacation vgrind vi vis vmstat w wall wc what whereis which \
+       who whoami whois window write xargs xinstall xstr yacc yes
        
 .include <bsd.subdir.mk>
        
 .include <bsd.subdir.mk>
diff --git a/usr.bin/key/Makefile b/usr.bin/key/Makefile
new file mode 100644 (file)
index 0000000..b8553ab
--- /dev/null
@@ -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>
+
diff --git a/usr.bin/key/README.WZV b/usr.bin/key/README.WZV
new file mode 100644 (file)
index 0000000..a13f3b5
--- /dev/null
@@ -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.
diff --git a/usr.bin/key/key.1 b/usr.bin/key/key.1
new file mode 100644 (file)
index 0000000..d9da463
--- /dev/null
@@ -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
diff --git a/usr.bin/key/skey.1 b/usr.bin/key/skey.1
new file mode 100644 (file)
index 0000000..0a8b1b6
--- /dev/null
@@ -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
diff --git a/usr.bin/key/skey.c b/usr.bin/key/skey.c
new file mode 100644 (file)
index 0000000..e025312
--- /dev/null
@@ -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);
+}
+
diff --git a/usr.bin/keyinfo/Makefile b/usr.bin/keyinfo/Makefile
new file mode 100644 (file)
index 0000000..41baee6
--- /dev/null
@@ -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>
diff --git a/usr.bin/keyinfo/keyinfo.1 b/usr.bin/keyinfo/keyinfo.1
new file mode 100644 (file)
index 0000000..b12aa96
--- /dev/null
@@ -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
diff --git a/usr.bin/keyinfo/keyinfo.sh b/usr.bin/keyinfo/keyinfo.sh
new file mode 100644 (file)
index 0000000..5879442
--- /dev/null
@@ -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
+}
diff --git a/usr.bin/keyinit/Makefile b/usr.bin/keyinit/Makefile
new file mode 100644 (file)
index 0000000..4c44d30
--- /dev/null
@@ -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>
diff --git a/usr.bin/keyinit/keyinit.1 b/usr.bin/keyinit/keyinit.1
new file mode 100644 (file)
index 0000000..2fe2d03
--- /dev/null
@@ -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
diff --git a/usr.bin/keyinit/skeyinit.c b/usr.bin/keyinit/skeyinit.c
new file mode 100644 (file)
index 0000000..d13bd6b
--- /dev/null
@@ -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;
+}
index 20ae828..5ee1672 100644 (file)
@@ -1,11 +1,14 @@
 #      @(#)Makefile    5.6 (Berkeley) 6/24/90
 
 PROG=  login
 #      @(#)Makefile    5.6 (Berkeley) 6/24/90
 
 PROG=  login
-SRCS=  klogin.c login.c
-DPADD= ${LIBUTIL}
-LDADD= -lutil
+MAN5=  login.access.5
+SRCS=  klogin.c login.c login_access.c login_skey.c 
+DPADD= ${LIBUTIL} /usr/lib/libskey.a
+LDADD= -lutil -lskey
 BINOWN=        root
 BINMODE=4555
 BINOWN=        root
 BINMODE=4555
+#CFLAGS+=-DLOGIN_ACCESS -DSKEY -DLOGALL -I${.CURDIR}/../../lib
+CFLAGS+=-DLOGIN_ACCESS -DSKEY -I${.CURDIR}/../../lib
 
 .if exists(${DESTDIR}/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
 
 .if exists(${DESTDIR}/usr/lib/libcrypt.a)
 DPADD+= ${LIBCRYPT}
diff --git a/usr.bin/login/README b/usr.bin/login/README
new file mode 100644 (file)
index 0000000..6ad7a10
--- /dev/null
@@ -0,0 +1,10 @@
+This login has additional functionalities. They are all based on (part of)
+Wietse Venema's logdaemon package.
+
+
+The following defines can be used:
+1) LOGIN_ACCESS to allow access control on a per tty/user combination
+2) SKEY to allow the use of s/key one time passwords
+3) LOGALL to log all logins
+
+-Guido
diff --git a/usr.bin/login/login.access.5 b/usr.bin/login/login.access.5
new file mode 100644 (file)
index 0000000..45719b9
--- /dev/null
@@ -0,0 +1,50 @@
+.\" this is comment
+.Dd April 30, 1994
+.Dt SKEY.ACCESS 5
+.Os FreeBSD 1.2
+.Sh NAME
+.Nm login.access
+.Nd Login access control table
+.Sh DESCRIPTION
+The
+.Nm login.access
+file specifies (user, host) combinations and/or (user, tty) 
+combinations for which a login will be either accepted or refused.
+.Pp
+When someone logs in, the 
+.Nm login.access
+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.
+.Pp
+Each line of the login access control table has 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.
+
+.Bl -tag -width /etc/login.access -compact
+.It Pa /etc/login.access
+The
+.Nm login.access
+file resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr login 1
+.Sh AUTHOR
+Guido van Rooij
index ad1d4d6..ab0adf8 100644 (file)
@@ -117,6 +117,10 @@ main(argc, argv)
        char *domain, *salt, *ttyn;
        char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
        char localhost[MAXHOSTNAMELEN];
        char *domain, *salt, *ttyn;
        char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
        char localhost[MAXHOSTNAMELEN];
+#ifdef SKEY
+       int permit_passwd = 0;
+       char *skey_getpass(), *skey_crypt();
+#endif /* SKEY */
 
        (void)signal(SIGALRM, timedout);
        (void)alarm((u_int)timeout);
 
        (void)signal(SIGALRM, timedout);
        (void)alarm((u_int)timeout);
@@ -152,9 +156,11 @@ main(argc, argv)
                                exit(1);
                        }
                        hflag = 1;
                                exit(1);
                        }
                        hflag = 1;
+#ifndef SKEY
                        if (domain && (p = index(optarg, '.')) &&
                            strcasecmp(p, domain) == 0)
                                *p = 0;
                        if (domain && (p = index(optarg, '.')) &&
                            strcasecmp(p, domain) == 0)
                                *p = 0;
+#endif /* SKEY */
                        hostname = optarg;
                        break;
                case 'p':
                        hostname = optarg;
                        break;
                case 'p':
@@ -190,6 +196,10 @@ main(argc, argv)
        else
                tty = ttyn;
 
        else
                tty = ttyn;
 
+#ifdef SKEY
+       permit_passwd = (hostname == 0 || authfile(hostname) != 0);
+#endif
+
        for (cnt = 0;; ask = 1) {
                if (ask) {
                        fflag = 0;
        for (cnt = 0;; ask = 1) {
                if (ask) {
                        fflag = 0;
@@ -248,7 +258,11 @@ main(argc, argv)
 
                (void)setpriority(PRIO_PROCESS, 0, -4);
 
 
                (void)setpriority(PRIO_PROCESS, 0, -4);
 
+#ifdef SKEY
+               p = skey_getpass("Password:", pwd, permit_passwd);
+#else
                p = getpass("Password:");
                p = getpass("Password:");
+#endif /* SKEY */
 
                if (pwd) {
 #ifdef KERBEROS
 
                if (pwd) {
 #ifdef KERBEROS
@@ -256,9 +270,19 @@ main(argc, argv)
                        if (rval == 0)
                                authok = 1;
                        else if (rval == 1)
                        if (rval == 0)
                                authok = 1;
                        else if (rval == 1)
+#ifdef SKEY
+                               rval = strcmp(skey_crypt(p, salt, pwd, permit_passwd), 
+                                             pwd->pw_passwd);
+#else
                                rval = strcmp(crypt(p, salt), pwd->pw_passwd);
                                rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+#endif /* SKEY */
+#else
+#ifdef SKEY
+                       rval = strcmp(skey_crypt(p, salt, pwd, permit_passwd), 
+                                     pwd->pw_passwd);
 #else
                        rval = strcmp(crypt(p, salt), pwd->pw_passwd);
 #else
                        rval = strcmp(crypt(p, salt), pwd->pw_passwd);
+#endif /* SKEY */
 #endif
                }
                bzero(p, strlen(p));
 #endif
                }
                bzero(p, strlen(p));
@@ -393,6 +417,18 @@ main(argc, argv)
                (void)printf("Warning: no Kerberos tickets issued.\n");
 #endif
 
                (void)printf("Warning: no Kerberos tickets issued.\n");
 #endif
 
+#ifdef LOGALL
+       /*
+        * Syslog each successful login, so we don't have to watch hundreds
+        * of wtmp or lastlogin files.
+        */
+       if (hostname) {
+               syslog(LOG_INFO, "login from %s as %s", hostname, pwd->pw_name);
+       } else {
+               syslog(LOG_INFO, "login on %s as %s", tty, pwd->pw_name);
+       }
+#endif
+
        if (!quietlog) {
                (void)printf(
 "Copyright (c) 1980,1983,1986,1988,1990,1991 The Regents of the University\n%s",
        if (!quietlog) {
                (void)printf(
 "Copyright (c) 1980,1983,1986,1988,1990,1991 The Regents of the University\n%s",
@@ -405,6 +441,19 @@ main(argc, argv)
                            (st.st_mtime > st.st_atime) ? "new " : "");
        }
 
                            (st.st_mtime > st.st_atime) ? "new " : "");
        }
 
+#ifdef LOGIN_ACCESS
+       if (login_access(pwd->pw_name, hostname ? hostname : tty) == 0) {
+               printf("Permission denied\n");
+               if (hostname)
+                       syslog(LOG_NOTICE, "%s LOGIN REFUSED FROM %s",
+                               pwd->pw_name, hostname);
+               else
+                       syslog(LOG_NOTICE, "%s LOGIN REFUSED ON %s",
+                               pwd->pw_name, tty);
+               sleepexit(1);
+       }
+#endif
+
        (void)signal(SIGALRM, SIG_DFL);
        (void)signal(SIGQUIT, SIG_DFL);
        (void)signal(SIGINT, SIG_DFL);
        (void)signal(SIGALRM, SIG_DFL);
        (void)signal(SIGQUIT, SIG_DFL);
        (void)signal(SIGINT, SIG_DFL);
diff --git a/usr.bin/login/login_access.c b/usr.bin/login/login_access.c
new file mode 100644 (file)
index 0000000..16a6ee6
--- /dev/null
@@ -0,0 +1,240 @@
+ /*
+  * This module implements a simple but effective form of login access
+  * control based on login names and on host (or domain) names, internet
+  * addresses (or network numbers), or on terminal line names in case of
+  * non-networked logins. Diagnostics are reported through syslog(3).
+  * 
+  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
+  */
+
+#ifdef LOGIN_ACCESS
+#ifndef lint
+static char sccsid[] = "%Z% %M% %I% %E% %U%";
+#endif
+
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <grp.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+extern struct group *getgrnam();
+extern int errno;
+
+ /* Path name of the access control file. */
+
+#ifndef        TABLE
+#define TABLE  "/etc/login.access"
+#endif
+
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+
+static char fs[] = ":";                        /* field separator */
+static char sep[] = ", \t";            /* list-element separator */
+
+ /* Constants to be used in assignments only, not in comparisons... */
+
+#define YES             1
+#define NO              0
+
+static int list_match();
+static int user_match();
+static int from_match();
+static int string_match();
+
+/* login_access - match username/group and host/tty with access control file */
+
+login_access(user, from)
+char   *user;
+char   *from;
+{
+    FILE   *fp;
+    char    line[BUFSIZ];
+    char   *perm;                      /* becomes permission field */
+    char   *users;                     /* becomes list of login names */
+    char   *froms;                     /* becomes list of terminals or hosts */
+    int     match = NO;
+    int     end;
+    int     lineno = 0;                        /* for diagnostics */
+
+    /*
+     * Process the table one line at a time and stop at the first match.
+     * Blank lines and lines that begin with a '#' character are ignored.
+     * Non-comment lines are broken at the ':' character. All fields are
+     * mandatory. The first field should be a "+" or "-" character. A
+     * non-existing table means no access control.
+     */
+
+    if (fp = fopen(TABLE, "r")) {
+       while (!match && fgets(line, sizeof(line), fp)) {
+           lineno++;
+           if (line[end = strlen(line) - 1] != '\n') {
+               syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
+                      TABLE, lineno);
+               continue;
+           }
+           if (line[0] == '#')
+               continue;                       /* comment line */
+           while (end > 0 && isspace(line[end - 1]))
+               end--;
+           line[end] = 0;                      /* strip trailing whitespace */
+           if (line[0] == 0)                   /* skip blank lines */
+               continue;
+           if (!(perm = strtok(line, fs))
+               || !(users = strtok((char *) 0, fs))
+               || !(froms = strtok((char *) 0, fs))
+               || strtok((char *) 0, fs)) {
+               syslog(LOG_ERR, "%s: line %d: bad field count", TABLE, lineno);
+               continue;
+           }
+           if (perm[0] != '+' && perm[0] != '-') {
+               syslog(LOG_ERR, "%s: line %d: bad first field", TABLE, lineno);
+               continue;
+           }
+           match = (list_match(froms, from, from_match)
+                    && list_match(users, user, user_match));
+       }
+       (void) fclose(fp);
+    } else if (errno != ENOENT) {
+       syslog(LOG_ERR, "cannot open %s: %m", TABLE);
+    }
+    return (match == 0 || (line[0] == '+'));
+}
+
+/* list_match - match an item against a list of tokens with exceptions */
+
+static int list_match(list, item, match_fn)
+char   *list;
+char   *item;
+int   (*match_fn) ();
+{
+    char   *tok;
+    int     match = NO;
+
+    /*
+     * Process tokens one at a time. We have exhausted all possible matches
+     * when we reach an "EXCEPT" token or the end of the list. If we do find
+     * a match, look for an "EXCEPT" list and recurse to determine whether
+     * the match is affected by any exceptions.
+     */
+
+    for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) {
+       if (strcasecmp(tok, "EXCEPT") == 0)     /* EXCEPT: give up */
+           break;
+       if (match = (*match_fn) (tok, item))    /* YES */
+           break;
+    }
+    /* Process exceptions to matches. */
+
+    if (match != NO) {
+       while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+            /* VOID */ ;
+       if (tok == 0 || list_match((char *) 0, item, match_fn) == NO)
+           return (match);
+    }
+    return (NO);
+}
+
+/* netgroup_match - match group against machine or user */
+
+static int netgroup_match(group, machine, user)
+char   *machine;
+char   *user;
+{
+#ifdef NIS
+    static char *mydomain = 0;
+
+    if (mydomain == 0)
+       yp_get_default_domain(&mydomain);
+    return (innetgr(group, machine, user, mydomain));
+#else
+    syslog(LOG_ERR, "NIS netgroup support not configured");
+#endif
+}
+
+/* user_match - match a username against one token */
+
+static int user_match(tok, string)
+char   *tok;
+char   *string;
+{
+    struct group *group;
+    int     i;
+
+    /*
+     * If a token has the magic value "ALL" the match always succeeds.
+     * Otherwise, return YES if the token fully matches the username, or if
+     * the token is a group that contains the username.
+     */
+
+    if (tok[0] == '@') {                       /* netgroup */
+       return (netgroup_match(tok + 1, (char *) 0, string));
+    } else if (string_match(tok, string)) {    /* ALL or exact match */
+       return (YES);
+    } else if (group = getgrnam(tok)) {                /* try group membership */
+       for (i = 0; group->gr_mem[i]; i++)
+           if (strcasecmp(string, group->gr_mem[i]) == 0)
+               return (YES);
+    }
+    return (NO);
+}
+
+/* from_match - match a host or tty against a list of tokens */
+
+static int from_match(tok, string)
+char   *tok;
+char   *string;
+{
+    int     tok_len;
+    int     str_len;
+
+    /*
+     * If a token has the magic value "ALL" the match always succeeds. Return
+     * YES if the token fully matches the string. If the token is a domain
+     * name, return YES if it matches the last fields of the string. If the
+     * token has the magic value "LOCAL", return YES if the string does not
+     * contain a "." character. If the token is a network number, return YES
+     * if it matches the head of the string.
+     */
+
+    if (tok[0] == '@') {                       /* netgroup */
+       return (netgroup_match(tok + 1, string, (char *) 0));
+    } else if (string_match(tok, string)) {    /* ALL or exact match */
+       return (YES);
+    } else if (tok[0] == '.') {                        /* domain: match last fields */
+       if ((str_len = strlen(string)) > (tok_len = strlen(tok))
+           && strcasecmp(tok, string + str_len - tok_len) == 0)
+           return (YES);
+    } else if (strcasecmp(tok, "LOCAL") == 0) {        /* local: no dots */
+       if (strchr(string, '.') == 0)
+           return (YES);
+    } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
+              && strncmp(tok, string, tok_len) == 0) {
+       return (YES);
+    }
+    return (NO);
+}
+
+/* string_match - match a string against one token */
+
+static int string_match(tok, string)
+char   *tok;
+char   *string;
+{
+
+    /*
+     * If the token has the magic value "ALL" the match always succeeds.
+     * Otherwise, return YES if the token fully matches the string.
+     */
+
+    if (strcasecmp(tok, "ALL") == 0) {         /* all: always matches */
+       return (YES);
+    } else if (strcasecmp(tok, string) == 0) { /* try exact match */
+       return (YES);
+    }
+    return (NO);
+}
+#endif /* LOGIN_ACCES */
diff --git a/usr.bin/login/login_skey.c b/usr.bin/login/login_skey.c
new file mode 100644 (file)
index 0000000..066e00d
--- /dev/null
@@ -0,0 +1,105 @@
+ /* Portions taken from the skey distribution on Oct 21 1993 */
+#ifdef SKEY
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <termios.h>
+#include <pwd.h>
+#include <syslog.h>
+
+#include "libskey/skey.h"
+
+/* skey_getpass - read regular or s/key password */
+
+char   *skey_getpass(prompt, pwd, pwok)
+char   *prompt;
+struct passwd *pwd;
+int     pwok;
+{
+    static char buf[128];
+    struct skey skey;
+    char   *cp;
+    void    rip();
+    struct termios saved_ttymode;
+    struct termios noecho_ttymode;
+    char   *username = pwd ? pwd->pw_name : "nope";
+    int     sflag;
+
+    /* Attempt an s/key challenge. */
+
+    if ((sflag = skeychallenge(&skey, username, buf)) == 0) {
+       printf("%s\n", buf);
+    }
+    if (!pwok) {
+       printf("(s/key required)\n");
+    }
+    fputs(prompt, stdout);
+    fflush(stdout);
+
+    /* Save current input modes and turn echo off. */
+
+    tcgetattr(0, &saved_ttymode);
+    tcgetattr(0, &noecho_ttymode);
+    noecho_ttymode.c_lflag &= ~ECHO;
+    tcsetattr(0, TCSANOW, &noecho_ttymode);
+
+    /* Read password. */
+
+    buf[0] = 0;
+    fgets(buf, sizeof(buf), stdin);
+    rip(buf);
+
+    /* Restore previous input modes. */
+
+    tcsetattr(0, TCSANOW, &saved_ttymode);
+
+    /* Give S/Key users a chance to do it with echo on. */
+
+    if (sflag == 0 && feof(stdin) == 0 && buf[0] == 0) {
+       fputs(" (turning echo on)\n", stdout);
+       fputs(prompt, stdout);
+       fflush(stdout);
+       fgets(buf, sizeof(buf), stdin);
+       rip(buf);
+    } else {
+       putchar('\n');
+    }
+    return (buf);
+}
+
+/* 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 */
+       if (skey.n < 5)
+           printf("Warning! Change s/key password soon\n");
+       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 (":");
+}
+#endif SKEY