summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.bin/skeyinit/skeyinit.18
-rw-r--r--usr.bin/skeyinit/skeyinit.c443
2 files changed, 288 insertions, 163 deletions
diff --git a/usr.bin/skeyinit/skeyinit.1 b/usr.bin/skeyinit/skeyinit.1
index f7bc468ab89..d11e1825702 100644
--- a/usr.bin/skeyinit/skeyinit.1
+++ b/usr.bin/skeyinit/skeyinit.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: skeyinit.1,v 1.19 2000/11/09 17:52:39 aaron Exp $
+.\" $OpenBSD: skeyinit.1,v 1.20 2001/06/20 22:25:08 millert Exp $
.\" $NetBSD: skeyinit.1,v 1.4 1995/07/07 22:24:09 jtc Exp $
.\" @(#)skeyinit.1 1.1 10/28/93
.\"
@@ -97,16 +97,18 @@ The username to be changed/added.
By default the current user is operated on.
.El
.Sh ERRORS
-.Bl -tag -width "skey disabled"
-.It skey disabled
+.Bl -tag -compact -width "skey disabled"
+.It "skey disabled"
.Pa /etc/skeykeys
does not exist.
It must be created by the superuser in order to use
.Nm skeyinit .
+.El
.Sh FILES
.Bl -tag -width /etc/skeykeys
.It Pa /etc/skeykeys
database of information for S/Key system
+.El
.Sh SEE ALSO
.Xr skey 1
.Sh AUTHORS
diff --git a/usr.bin/skeyinit/skeyinit.c b/usr.bin/skeyinit/skeyinit.c
index 7f3407dae25..7ab7378f276 100644
--- a/usr.bin/skeyinit/skeyinit.c
+++ b/usr.bin/skeyinit/skeyinit.c
@@ -1,17 +1,15 @@
-/* $OpenBSD: skeyinit.c,v 1.27 2001/01/26 16:27:04 millert Exp $ */
+/* $OpenBSD: skeyinit.c,v 1.28 2001/06/20 22:25:08 millert Exp $ */
-/* S/KEY v1.1b (skeyinit.c)
+/* OpenBSD S/Key (skeyinit.c)
*
* Authors:
* Neil M. Haller <nmh@thumper.bellcore.com>
* Philip R. Karn <karn@chicago.qualcomm.com>
* John S. Walden <jsw@thumper.bellcore.com>
* Scott Chasin <chasin@crimelab.com>
- *
- * Modifications:
* Todd C. Miller <Todd.Miller@courtesan.com>
*
- * S/KEY initialization and seed update
+ * S/Key initialization and seed update
*/
#include <sys/param.h>
@@ -23,6 +21,7 @@
#include <errno.h>
#include <ctype.h>
#include <pwd.h>
+#include <readpassphrase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,20 +36,26 @@
#define SKEY_NAMELEN 4
#endif
+void lockeof __P((struct skey *, char *));
void usage __P((char *));
+void secure_mode __P((int *, char *, char *, char *, char *, size_t));
+void normal_mode __P((char *, int, char *, char *, char *));
+void timedout __P((int));
int
main(argc, argv)
int argc;
char *argv[];
{
- int rval, nn, i, l, n=0, defaultsetup=1, zerokey=0, hexmode=0;
+ int rval, i, l, n=0, defaultsetup=1, zerokey=0, hexmode=0;
+ int oldmd4=0;
time_t now;
+ size_t seedlen;
char hostname[MAXHOSTNAMELEN];
- char passwd[SKEY_MAX_PW_LEN+2], passwd2[SKEY_MAX_PW_LEN+2];
+ char passwd[SKEY_MAX_PW_LEN+2];
char seed[SKEY_MAX_SEED_LEN+2], defaultseed[SKEY_MAX_SEED_LEN+1];
- char tbuf[27], buf[80], key[SKEY_BINKEY_SIZE];
- char lastc, me[UT_NAMESIZE+1], *salt, *p, *pw, *ht=NULL;
+ char tbuf[27], buf[256], key[SKEY_BINKEY_SIZE];
+ char lastc, me[UT_NAMESIZE+1], *salt, *p, *ht=NULL;
struct skey skey;
struct passwd *pp;
struct tm *tm;
@@ -58,6 +63,7 @@ main(argc, argv)
if (geteuid() != 0)
errx(1, "must be setuid root.");
+ /* Build up a default seed based on the hostname and time */
if (gethostname(hostname, sizeof(hostname)) < 0)
err(1, "gethostname");
for (i = 0, p = defaultseed; hostname[i] && i < SKEY_NAMELEN; i++) {
@@ -136,20 +142,41 @@ main(argc, argv)
}
}
+ if (defaultsetup)
+ fputs("Reminder - Only use this method if you are directly connected\n or have an encrypted channel. If you are using telnet\n or rlogin, hit return now and use skeyinit -s.\n", stderr);
+
if (getuid() != 0) {
- pw = getpass("Password (or `s/key'):");
- if (strcasecmp(pw, "s/key") == 0) {
- if (skey_haskey(me))
- exit(1);
- if (skey_authenticate(me))
+ /* XXX - use BSD auth */
+ passwd[0] = '\0';
+ if (!defaultsetup && skeychallenge(&skey, me, buf) == 0) {
+ printf("Enter S/Key password below or hit return twice "
+ "to enter standard password.\n%s\n", buf);
+ fflush(stdout);
+ if (!readpassphrase("S/Key Password: ", passwd,
+ sizeof(passwd), 0) || passwd[0] == '\0') {
+ readpassphrase("S/Key Password: [echo on] ",
+ passwd, sizeof(passwd), RPP_ECHO_ON);
+ }
+ }
+ if (passwd[0]) {
+ if (skeyverify(&skey, passwd) != 0)
errx(1, "Password incorrect.");
} else {
- p = crypt(pw, salt);
- if (strcmp(p, pp->pw_passwd))
- errx(1, "Password incorrect.");
+ fflush(stdout);
+ readpassphrase("Password: ", passwd, sizeof(passwd), 0);
+ if (strcmp(crypt(passwd, salt), pp->pw_passwd)) {
+ if (passwd[0])
+ warnx("Password incorrect.");
+ exit(1);
+ }
}
}
+ /*
+ * Lookup and lock the record we are about to modify.
+ * If this is a new entry this will prevent other users
+ * from appending new entries (and clobbering ours).
+ */
rval = skeylookup(&skey, pp->pw_name);
switch (rval) {
case -1:
@@ -163,9 +190,10 @@ main(argc, argv)
if (zerokey)
exit(skeyzero(&skey, pp->pw_name));
- (void)printf("[Updating %s]\n", pp->pw_name);
- (void)printf("Old key: [%s] %s\n", skey_get_algorithm(),
- skey.seed);
+ (void)printf("[Updating %s with %s]\n", pp->pw_name,
+ ht ? ht : skey_get_algorithm());
+ (void)printf("Old seed: [%s] %s\n",
+ skey_get_algorithm(), skey.seed);
/*
* Sanity check old seed.
@@ -181,10 +209,7 @@ main(argc, argv)
}
}
- /*
- * Let's be nice if they have an skey.seed that
- * ends in 0-8 just add one
- */
+ /* If the seed ends in 0-8 just add one. */
if (l > 0) {
lastc = skey.seed[l - 1];
if (isdigit(lastc) && lastc != '9') {
@@ -202,172 +227,270 @@ main(argc, argv)
case 1:
if (zerokey)
errx(1, "You have no entry to zero.");
- (void)printf("[Adding %s]\n", pp->pw_name);
+ (void)printf("[Adding %s with %s]\n", pp->pw_name,
+ ht ? ht : skey_get_algorithm());
+ lockeof(&skey, pp->pw_name);
break;
}
if (n == 0)
n = 99;
- /* Set hash type if asked to */
- if (ht) {
- /* Need to zero out old key when changing algorithm */
- if (strcmp(ht, skey_get_algorithm()) && skey_set_algorithm(ht))
- zerokey = 1;
- }
+ /* Do we have an old-style md4 entry? */
+ if (rval == 0 && strcmp("md4", skey_get_algorithm()) == 0 &&
+ strcmp("md4", skey.logname + strlen(skey.logname) + 1) != 0)
+ oldmd4 = 1;
- if (!defaultsetup) {
- (void)printf("You need the 6 english words generated from the \"skey\" command.\n");
- for (i = 0; ; i++) {
- if (i >= 2)
- exit(1);
+ /* Set hash type if asked to */
+ if (ht && strcmp(ht, skey_get_algorithm()) != 0)
+ skey_set_algorithm(ht);
- (void)printf("Enter sequence count from 1 to %d: ",
- SKEY_MAX_SEQ);
- (void)fgets(buf, sizeof(buf), stdin);
- n = atoi(buf);
- if (n > 0 && n < SKEY_MAX_SEQ)
- break; /* Valid range */
- (void)printf("Error: Count must be > 0 and < %d\n",
- SKEY_MAX_SEQ);
- }
+ alarm(180);
+ if (!defaultsetup)
+ secure_mode(&n, key, seed, defaultseed, buf, sizeof(buf));
+ else
+ normal_mode(pp->pw_name, n, key, seed, defaultseed);
+ alarm(0);
- for (i = 0;; i++) {
- if (i >= 2)
- exit(1);
+ (void)time(&now);
+ tm = localtime(&now);
+ (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
- (void)printf("Enter new key [default %s]: ",
- defaultseed);
- (void)fgets(seed, sizeof(seed), stdin);
- rip(seed);
- if (seed[0] == '\0')
- (void)strcpy(seed, defaultseed);
- for (p = seed; *p; p++) {
- if (isalpha(*p)) {
- if (isupper(*p))
- *p = tolower(*p);
- } else if (!isdigit(*p)) {
- (void)puts("Error: seed may only contain alpha numeric characters");
- break;
- }
- }
- if (*p == '\0')
- break; /* Valid seed */
- }
- if (strlen(seed) > SKEY_MAX_SEED_LEN) {
- (void)printf("Notice: Seed truncated to %d characters.\n",
- SKEY_MAX_SEED_LEN);
- seed[SKEY_MAX_SEED_LEN] = '\0';
+ /* If this is an exiting entry, compute the line length and seed pad */
+ seedlen = SKEY_MAX_SEED_LEN;
+ if (rval == 0) {
+ int nlen;
+
+ nlen = strlen(pp->pw_name) + 1 + strlen(skey_get_algorithm()) +
+ 1 + 4 + 1 + strlen(seed) + 1 + 16 + 1 + strlen(tbuf) + 1;
+
+ /*
+ * If there was no hash type (md4) add one unless we
+ * are short on space.
+ */
+ if (oldmd4) {
+ if (nlen > skey.len)
+ nlen -= 4;
+ else
+ oldmd4 = 0;
}
- for (i = 0;; i++) {
- if (i >= 2)
- exit(1);
+ /* If new entry is longer than the old, comment out the old. */
+ if (nlen > skey.len) {
+ (void)skeyzero(&skey, pp->pw_name);
+ /* Re-open keys file and seek to the end */
+ if (skeylookup(&skey, pp->pw_name) == -1)
+ err(1, "cannot reopen database");
+ lockeof(&skey, pp->pw_name);
+ } else {
+ /* Compute how much to space-pad the seed */
+ seedlen = strlen(seed) + (skey.len - nlen);
+ }
+ }
- (void)printf("otp-%s %d %s\nS/Key access password: ",
- skey_get_algorithm(), n, seed);
- (void)fgets(buf, sizeof(buf), stdin);
- rip(buf);
- backspace(buf);
+ if ((skey.val = (char *)malloc(16 + 1)) == NULL)
+ err(1, "Can't allocate memory");
+ btoa8(skey.val, key);
- if (buf[0] == '?') {
- (void)puts("Enter 6 English words from secure S/Key calculation.");
- continue;
- } else if (buf[0] == '\0')
- exit(1);
- if (etob(key, buf) == 1 || atob8(key, buf) == 0)
- break; /* Valid format */
- (void)puts("Invalid format - try again with 6 English words.");
- }
- } else {
- /* Get user's secret password */
- fputs("Reminder - Only use this method if you are directly connected\n or have an encrypted channel. If you are using telnet\n or rlogin, exit with no password and use skeyinit -s.\n", stderr);
+ /* Don't save algorithm type for md4 (maintain record length) */
+ /* XXX - should check return values of fprintf + fclose */
+ if (oldmd4)
+ (void)fprintf(skey.keyfile, "%s %04d %-* %s %-21s\n",
+ pp->pw_name, n, seedlen, seed, skey.val, tbuf);
+ else
+ (void)fprintf(skey.keyfile, "%s %s %04d %-*s %s %-21s\n",
+ pp->pw_name, skey_get_algorithm(), n, seedlen, seed,
+ skey.val, tbuf);
+ (void)fclose(skey.keyfile);
- for (i = 0;; i++) {
- if (i > 2)
- exit(1);
+ (void)printf("\nID %s skey is otp-%s %d %s\n", pp->pw_name,
+ skey_get_algorithm(), n, seed);
+ (void)printf("Next login password: %s\n\n",
+ hexmode ? put8(buf, key) : btoe(buf, key));
+ exit(0);
+}
- (void)fputs("Enter secret password: ", stderr);
- readpass(passwd, sizeof(passwd));
- if (passwd[0] == '\0')
- exit(1);
+void
+lockeof(mp, user)
+ struct skey *mp;
+ char *user;
+{
+ struct flock fl;
+
+ fseek(mp->keyfile, 0, SEEK_END);
+dolock:
+ fl.l_start = ftell(mp->keyfile);
+ fl.l_len = mp->len;
+ fl.l_pid = getpid();
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+
+ if (fcntl(fileno(mp->keyfile), F_SETLKW, &fl) == -1)
+ err(1, "Can't lock database");
+
+ /* Make sure we are still at the end. */
+ fseek(mp->keyfile, 0, SEEK_END);
+ if (fl.l_start == ftell(mp->keyfile))
+ return; /* still at EOF */
+
+ fclose(mp->keyfile);
+ if (skeylookup(mp, user) != 1)
+ errx(1, "user %s already added", user);
+ goto dolock;
+}
- if (strlen(passwd) < SKEY_MIN_PW_LEN) {
- (void)fprintf(stderr,
- "Your password must be at least %d characters long.\n", SKEY_MIN_PW_LEN);
- continue;
- } else if (strcmp(passwd, pp->pw_name) == 0) {
- (void)fputs("Your password may not be the same as your user name.\n", stderr);
- continue;
- } else if (strspn(passwd, "abcdefghijklmnopqrstuvwxyz") == strlen(passwd)) {
- (void)fputs("Your password must contain more than just lower case letters.\nWhitespace, numbers, and puctuation are suggested.\n", stderr);
- continue;
- }
+void
+secure_mode(count, key, seed, defaultseed, buf, bufsiz)
+ int *count;
+ char *key;
+ char *seed;
+ char *defaultseed;
+ char *buf;
+ size_t bufsiz;
+{
+ int i, n;
+ char *p;
+
+ (void)puts("You need the 6 words generated from the \"skey\" command.");
+ for (i = 0; ; i++) {
+ if (i >= 2)
+ exit(1);
+
+ (void)printf("Enter sequence count from 1 to %d: ",
+ SKEY_MAX_SEQ);
+ (void)fgets(buf, bufsiz, stdin);
+ clearerr(stdin);
+ n = atoi(buf);
+ if (n > 0 && n < SKEY_MAX_SEQ)
+ break; /* Valid range */
+ (void)fprintf(stderr, "ERROR: Count must be between 1 and %d\n",
+ SKEY_MAX_SEQ);
+ }
- (void)fputs("Again secret password: ", stderr);
- readpass(passwd2, sizeof(passwd));
+ for (i = 0; ; i++) {
+ if (i >= 2)
+ exit(1);
- if (strcmp(passwd, passwd2) == 0)
+ (void)printf("Enter new seed [default %s]: ",
+ defaultseed);
+ (void)fgets(seed, SKEY_MAX_SEED_LEN+2, stdin); /* XXX */
+ clearerr(stdin);
+ rip(seed);
+ if (strlen(seed) > SKEY_MAX_SEED_LEN) {
+ (void)fprintf(stderr, "ERROR: Seed must be between 1 "
+ "and %d characters in length\n", SKEY_MAX_SEED_LEN);
+ continue;
+ }
+ if (seed[0] == '\0')
+ (void)strcpy(seed, defaultseed);
+ for (p = seed; *p; p++) {
+ if (isspace(*p)) {
+ (void)fputs("ERROR: Seed must not contain "
+ "any spaces\n", stderr);
break;
-
- (void)fputs("Passwords do not match.\n", stderr);
+ } else if (isalpha(*p)) {
+ if (isupper(*p))
+ *p = tolower(*p);
+ } else if (!isdigit(*p)) {
+ (void)fputs("ERROR: Seed must be purely "
+ "alphanumeric\n", stderr);
+ break;
+ }
}
-
- /* Crunch seed and password into starting key */
- (void)strcpy(seed, defaultseed);
- if (keycrunch(key, seed, passwd) != 0)
- err(2, "key crunch failed");
-
- nn = n;
- while (nn-- != 0)
- f(key);
+ if (*p == '\0')
+ break; /* Valid seed */
}
- (void)time(&now);
- tm = localtime(&now);
- (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
- if ((skey.val = (char *)malloc(16 + 1)) == NULL)
- err(1, "Can't allocate memory");
-
- /* Zero out old key if necesary (entry would change size) */
- if (zerokey) {
- (void)skeyzero(&skey, pp->pw_name);
- /* Re-open keys file and seek to the end */
- if (skeylookup(&skey, pp->pw_name) == -1)
- err(1, "cannot open database");
+ for (i = 0; ; i++) {
+ if (i >= 2)
+ exit(1);
+
+ (void)printf("otp-%s %d %s\nS/Key access password: ",
+ skey_get_algorithm(), n, seed);
+ (void)fgets(buf, bufsiz, stdin);
+ clearerr(stdin);
+ rip(buf);
+ backspace(buf);
+
+ if (buf[0] == '?') {
+ (void)puts("Enter 6 words from secure S/Key calculation.");
+ continue;
+ } else if (buf[0] == '\0')
+ exit(1);
+
+ if (etob(key, buf) == 1 || atob8(key, buf) == 0)
+ break; /* Valid format */
+ (void)fputs("ERROR: Invalid format - try again with the 6 words.\n",
+ stderr);
}
+ *count= n;
+}
- btoa8(skey.val, key);
+void
+normal_mode(username, n, key, seed, defaultseed)
+ char *username;
+ int n;
+ char *key;
+ char *seed;
+ char *defaultseed;
+{
+ int i, nn;
+ char passwd[SKEY_MAX_PW_LEN+2], passwd2[SKEY_MAX_PW_LEN+2];
+
+ /* Get user's secret passphrase */
+ for (i = 0; ; i++) {
+ if (i > 2)
+ exit(1);
+
+ if (readpassphrase("Enter secret passphrase: ", passwd,
+ sizeof(passwd), 0) == NULL || passwd[0] == '\0')
+ exit(1);
+
+ if (strlen(passwd) < SKEY_MIN_PW_LEN) {
+ (void)fprintf(stderr,
+ "ERROR: Your passphrase must be at least %d "
+ "characters long.\n", SKEY_MIN_PW_LEN);
+ continue;
+ } else if (strcmp(passwd, username) == 0) {
+ (void)fputs("ERROR: Your passphrase may not be the "
+ "same as your user name.\n", stderr);
+ continue;
+ } else if (strspn(passwd, "abcdefghijklmnopqrstuvwxyz") ==
+ strlen(passwd)) {
+ (void)fputs("ERROR: Your passphrase must contain more "
+ "than just lower case letters.\nWhitespace, "
+ "numbers, and puctuation are suggested.\n", stderr);
+ continue;
+ } else if (strlen(passwd) > 63) {
+ (void)fprintf(stderr, "WARNING: Your passphrase is "
+ "longer than the recommended maximum length of 63\n");
+ }
+ /* XXX - should check for passphrase that is really too long */
- /*
- * Obtain an exclusive lock on the key file so we don't
- * clobber someone authenticating themselves at the same time.
- */
- for (i = 0; i < 300; i++) {
- if ((rval = flock(fileno(skey.keyfile), LOCK_EX|LOCK_NB)) == 0
- || errno != EWOULDBLOCK)
+ if (readpassphrase("Again secret passphrase: ", passwd2,
+ sizeof(passwd2), 0) && strcmp(passwd, passwd2) == 0)
break;
- usleep(100000); /* Sleep for 0.1 seconds */
- }
- if (rval == -1) { /* Can't get exclusive lock */
- errno = EAGAIN;
- err(1, "cannot open database");
+
+ (void)fputs("Passphrases do not match.\n", stderr);
}
- /* Don't save algorithm type for md4 (keep record length same) */
- if (strcmp(skey_get_algorithm(), "md4") == 0)
- (void)fprintf(skey.keyfile, "%s %04d %-16s %s %-21s\n",
- pp->pw_name, n, seed, skey.val, tbuf);
- else
- (void)fprintf(skey.keyfile, "%s %s %04d %-16s %s %-21s\n",
- pp->pw_name, skey_get_algorithm(), n, seed, skey.val, tbuf);
+ /* Crunch seed and passphrase into starting key */
+ (void)strcpy(seed, defaultseed);
+ if (keycrunch(key, seed, passwd) != 0)
+ err(2, "key crunch failed");
- (void)fclose(skey.keyfile);
+ nn = n;
+ while (nn-- != 0)
+ f(key);
+}
- (void)printf("\nID %s skey is otp-%s %d %s\n", pp->pw_name,
- skey_get_algorithm(), n, seed);
- (void)printf("Next login password: %s\n\n",
- hexmode ? put8(buf, key) : btoe(buf, key));
- exit(0);
+#define TIMEOUT_MSG "Timed out waiting for input.\n"
+void
+timedout(signo)
+ int signo;
+{
+
+ write(STDERR_FILENO, TIMEOUT_MSG, sizeof(TIMEOUT_MSG) - 1);
+ _exit(1);
}
void