diff options
author | 2002-05-16 03:50:42 +0000 | |
---|---|---|
committer | 2002-05-16 03:50:42 +0000 | |
commit | fc7f3601ee932ec9c65cea8778ce19514e39d038 (patch) | |
tree | 6f10865f714d48be4d9706cdd4c23f5351446c48 | |
parent | Re-enable RNG on the 5601 (it needs to be disabled on some 5805 variants, (diff) | |
download | wireguard-openbsd-fc7f3601ee932ec9c65cea8778ce19514e39d038.tar.xz wireguard-openbsd-fc7f3601ee932ec9c65cea8778ce19514e39d038.zip |
Change S/Key stuff from using a flat file (/etc/skeykeys) to a directory
where each user gets their own file, which is owned by that user.
An old S/Key database may be converted by running "skeyinit -C" as root.
Programs that need to access the S/Key database no longer need to be
setuid root. They must now be setgid auth instead.
-rw-r--r-- | include/paths.h | 3 | ||||
-rw-r--r-- | lib/libskey/shlib_version | 2 | ||||
-rw-r--r-- | lib/libskey/skey.3 | 5 | ||||
-rw-r--r-- | lib/libskey/skey.h | 12 | ||||
-rw-r--r-- | lib/libskey/skeylogin.c | 577 | ||||
-rw-r--r-- | usr.bin/skeyaudit/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/skeyaudit/skeyaudit.1 | 14 | ||||
-rw-r--r-- | usr.bin/skeyaudit/skeyaudit.c | 11 | ||||
-rw-r--r-- | usr.bin/skeyinit/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/skeyinit/skeyinit.1 | 54 | ||||
-rw-r--r-- | usr.bin/skeyinit/skeyinit.c | 298 |
11 files changed, 462 insertions, 526 deletions
diff --git a/include/paths.h b/include/paths.h index f9ff85dc591..181bd2fc2e1 100644 --- a/include/paths.h +++ b/include/paths.h @@ -1,4 +1,4 @@ -/* $OpenBSD: paths.h,v 1.18 2000/06/10 20:01:06 deraadt Exp $ */ +/* $OpenBSD: paths.h,v 1.19 2002/05/16 03:50:42 millert Exp $ */ /* $NetBSD: paths.h,v 1.7 1994/10/26 00:56:12 cgd Exp $ */ /* @@ -66,7 +66,6 @@ #define _PATH_RSH "/usr/bin/rsh" #define _PATH_SENDMAIL "/usr/sbin/sendmail" #define _PATH_SHELLS "/etc/shells" -#define _PATH_SKEYKEYS "/etc/skeykeys" #define _PATH_TTY "/dev/tty" #define _PATH_UNIX "/bsd" #define _PATH_VI "/usr/bin/vi" diff --git a/lib/libskey/shlib_version b/lib/libskey/shlib_version index b52599a164f..012c14171d3 100644 --- a/lib/libskey/shlib_version +++ b/lib/libskey/shlib_version @@ -1,2 +1,2 @@ -major=2 +major=3 minor=0 diff --git a/lib/libskey/skey.3 b/lib/libskey/skey.3 index 81e344b6561..11540cf1706 100644 --- a/lib/libskey/skey.3 +++ b/lib/libskey/skey.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: skey.3,v 1.3 2002/04/30 16:31:42 mpech Exp $ +.\" $OpenBSD: skey.3,v 1.4 2002/05/16 03:50:42 millert Exp $ .\" .\" Copyright (c) 2001 Todd C. Miller <Todd.Miller@courtesan.com> .\" All rights reserved. @@ -333,6 +333,9 @@ The S/Key database remains open after a call to If no error was encountered accessing the S/Key database, the read/write file pointer is set to the beginning of the record or at EOF if there are no more records. +.br +Because it exposes other users' S/Key records, only the superuser may use +.Fn skeygetnext . .Pp The .Fn skeylookup diff --git a/lib/libskey/skey.h b/lib/libskey/skey.h index 37d9bd269fe..750dd8095f2 100644 --- a/lib/libskey/skey.h +++ b/lib/libskey/skey.h @@ -10,23 +10,22 @@ * * Main client header * - * $OpenBSD: skey.h,v 1.17 2002/02/16 21:27:28 millert Exp $ + * $OpenBSD: skey.h,v 1.18 2002/05/16 03:50:42 millert Exp $ */ #ifndef _SKEY_H_ #define _SKEY_H_ 1 -#include <sys/cdefs.h> +#include <dirent.h> /* Server-side data structure for reading keys file during login */ struct skey { FILE *keyfile; + DIR *keydir; char *logname; char *seed; char *val; - int n; - int len; - long recstart; /* needed so reread of buffer is efficient */ + unsigned int n; char buf[256]; }; @@ -61,6 +60,9 @@ struct mc { /* Location of random file for bogus challenges */ #define _SKEY_RAND_FILE_PATH_ "/var/db/host.random" +/* Directory for S/Key per-user files */ +#define _PATH_SKEYDIR "/etc/skey" + __BEGIN_DECLS void f(char *); int keycrunch(char *, char *, char *); diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c index 0cd761b75ed..34f3996611a 100644 --- a/lib/libskey/skeylogin.c +++ b/lib/libskey/skeylogin.c @@ -9,8 +9,8 @@ * Angelos D. Keromytis <adk@adk.gr> * * S/Key verification check, lookups, and authentication. - * - * $OpenBSD: skeylogin.c,v 1.41 2002/02/16 21:27:28 millert Exp $ + * + * $OpenBSD: skeylogin.c,v 1.42 2002/05/16 03:50:42 millert Exp $ */ #include <sys/param.h> @@ -20,7 +20,6 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/resource.h> -#include <sys/types.h> #include <ctype.h> #include <err.h> @@ -41,8 +40,8 @@ static char *tgetline(int, char *, size_t, int); /* * Return an 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). + * 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. @@ -61,7 +60,7 @@ skeychallenge(mp, name, ss) (void)sprintf(ss, "otp-%.*s %d %.*s", SKEY_MAX_HASHNAME_LEN, skey_get_algorithm(), mp->n - 1, SKEY_MAX_SEED_LEN, mp->seed); - return(0); + return (0); case 1: /* User not found */ (void)fclose(mp->keyfile); @@ -70,126 +69,99 @@ skeychallenge(mp, name, ss) default: /* File error */ skey_fakeprompt(name, ss); - return(-1); + return (-1); } } -/* +/* * Find an entry in the One-time Password database and lock it. * * Return codes: * -1: error in opening database or unable to lock entry * 0: entry found, file R/W pointer positioned at beginning of record - * 1: entry not found, file R/W pointer positioned at EOF + * 1: entry not found */ int skeylookup(mp, name) struct skey *mp; char *name; { - FILE *keyfile; - int rval; - int locked = 0; - long recstart = 0; - char *cp, *ht = NULL; struct stat statbuf; - struct flock fl; + size_t nread; + char *cp, filename[PATH_MAX]; + FILE *keyfile; + int fd; - /* Open _PATH_SKEYKEYS if it exists, else return an error */ - if (stat(_PATH_SKEYKEYS, &statbuf) == 0 && - (keyfile = mp->keyfile = fopen(_PATH_SKEYKEYS, "r+")) != NULL) { - if ((statbuf.st_mode & 0007777) != 0600) - fchmod(fileno(keyfile), 0600); - } else { - mp->keyfile = NULL; - return(-1); + /* Open the user's databse entry, creating it as needed. */ + /* XXX - really want "/etc/skeys/L/USER" where L is 1st char of USER */ + mp->keyfile = NULL; + if (snprintf(filename, sizeof(filename), "%s/%s", _PATH_SKEYDIR, + name) >= sizeof(filename)) { + errno = ENAMETOOLONG; + return (-1); + } + if ((fd = open(filename, O_RDWR | O_NOFOLLOW | O_NONBLOCK, + S_IRUSR | S_IWUSR)) == -1) { + if (errno == ENOENT) + goto not_found; + return (-1); } - /* Look up user name in database */ - while (!feof(keyfile)) { - mp->recstart = recstart = ftell(keyfile); - if (fgets(mp->buf, sizeof(mp->buf), keyfile) == NULL) - break; - if (mp->buf[0] == '#') - continue; /* Comment */ - mp->len = strlen(mp->buf); - cp = mp->buf + mp->len - 1; - while (cp >= mp->buf && (*cp == '\n' || *cp == '\r')) - *cp-- = '\0'; - if ((mp->logname = strtok(mp->buf, " \t")) == NULL || - strcmp(mp->logname, name) != 0) - continue; - if ((cp = strtok(NULL, " \t")) == NULL) - continue; - /* Save hash type if specified, else use md4 */ - if (isalpha(*cp)) { - ht = cp; - if ((cp = strtok(NULL, " \t")) == NULL) - continue; - } else { - ht = "md4"; - } - mp->n = atoi(cp); - if ((mp->seed = strtok(NULL, " \t")) == NULL) - continue; - if ((mp->val = strtok(NULL, " \t")) == NULL) - continue; - - /* Set hash type */ - if (ht && skey_set_algorithm(ht) == NULL) { - warnx("Unknown hash algorithm %s, using %s", ht, - skey_get_algorithm()); - } - (void)fseek(keyfile, recstart, SEEK_SET); - - /* If we already aquired the lock we are done */ - if (locked) - return(0); - - /* Ortherwise, we must lock the record */ - fl.l_start = mp->recstart; - fl.l_len = mp->len; - fl.l_pid = getpid(); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - - /* If we get the lock on the first try we are done */ - rval = fcntl(fileno(mp->keyfile), F_SETLK, &fl); - if (rval == 0) - return(0); - else if (errno != EAGAIN) - break; - - /* - * Wait until we our lock is granted... - * Since we didn't get the lock on the first try, someone - * else may have modified the record. We need to make - * sure the entry hasn't changed name (it could have been - * commented out) and re-read it. - */ - if (fcntl(fileno(mp->keyfile), F_SETLKW, &fl) == -1) - break; - - rval = fread(mp->logname, fl.l_len, 1, mp->keyfile); - if (rval != fl.l_len || - memcmp(mp->logname, name, rval) != 0) { - /* username no longer matches so unlock */ - fl.l_type = F_UNLCK; - fcntl(fileno(mp->keyfile), F_SETLK, &fl); - } else { - locked = 1; - } - (void)fseek(keyfile, recstart, SEEK_SET); + /* Lock and stat the user's skey file. */ + if (flock(fd, LOCK_EX) != 0 || fstat(fd, &statbuf) != 0) { + close(fd); + return (-1); + } + if (statbuf.st_size == 0) + goto not_found; + + /* Sanity checks. */ + if ((statbuf.st_mode & ALLPERMS) != (S_IRUSR | S_IWUSR) || + !S_ISREG(statbuf.st_mode) || statbuf.st_nlink != 1 || + (keyfile = fdopen(fd, "r+")) == NULL) { + close(fd); + return (-1); } - /* No entry found, fill in what we can... */ + /* At this point, we are committed. */ + memset(mp, 0, sizeof(*mp)); + mp->keyfile = keyfile; + + if ((nread = fread(mp->buf, 1, sizeof(mp->buf), keyfile)) == 0 || + !isspace(mp->buf[nread - 1])) + goto bad_keyfile; + mp->buf[nread - 1] = '\0'; + + if ((mp->logname = strtok(mp->buf, " \t\n\r")) == NULL || + strcmp(mp->logname, name) != 0) + goto bad_keyfile; + if ((cp = strtok(NULL, " \t\n\r")) == NULL) + goto bad_keyfile; + if (skey_set_algorithm(cp) == NULL) + goto bad_keyfile; + if ((cp = strtok(NULL, " \t\n\r")) == NULL) + goto bad_keyfile; + mp->n = atoi(cp); /* XXX - use strtol() */ + if ((mp->seed = strtok(NULL, " \t\n\r")) == NULL) + goto bad_keyfile; + if ((mp->val = strtok(NULL, " \t\n\r")) == NULL) + goto bad_keyfile; + + (void)fseek(keyfile, 0L, SEEK_SET); + return (0); + + bad_keyfile: + fclose(keyfile); + return (-1); + + not_found: + /* No existing entry, fill in what we can and return */ memset(mp, 0, sizeof(*mp)); strlcpy(mp->buf, name, sizeof(mp->buf)); mp->logname = mp->buf; - mp->len = strlen(mp->buf); - mp->keyfile = keyfile; - mp->recstart = ftell(keyfile); - return(1); + if (fd != -1) + close(fd); + return (1); } /* @@ -198,92 +170,38 @@ skeylookup(mp, name) * Return codes: * -1: error in opening database * 0: next entry found and stored in mp - * 1: no more entries, file R/W pointer positioned at EOF + * 1: no more entries, keydir is closed. */ int skeygetnext(mp) struct skey *mp; { + struct dirent entry, *dp; int rval; - int locked = 0; - char *cp; - struct stat statbuf; - struct flock fl; - - /* Open _PATH_SKEYKEYS if it exists, else return an error */ - if (mp->keyfile == NULL) { - if (stat(_PATH_SKEYKEYS, &statbuf) == 0 && - (mp->keyfile = fopen(_PATH_SKEYKEYS, "r+")) != NULL) { - if ((statbuf.st_mode & 0007777) != 0600) - fchmod(fileno(mp->keyfile), 0600); - } else { - return(-1); - } - } else { - /* Unlock existing record */ - fl.l_start = mp->recstart; - fl.l_len = mp->len; - fl.l_pid = getpid(); - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; - - fcntl(fileno(mp->keyfile), F_SETLK, &fl); - } - /* Look up next user in database */ - while (!feof(mp->keyfile)) { - mp->recstart = ftell(mp->keyfile); - if (fgets(mp->buf, sizeof(mp->buf), mp->keyfile) != mp->buf) - break; - if (mp->buf[0] == '#') - continue; /* Comment */ - mp->len = strlen(mp->buf); - cp = mp->buf + mp->len - 1; - while (cp >= mp->buf && (*cp == '\n' || *cp == '\r')) - *cp-- = '\0'; - if ((mp->logname = strtok(mp->buf, " \t")) == NULL) - continue; - if ((cp = strtok(NULL, " \t")) == NULL) - continue; - /* Save hash type if specified, else use md4 */ - if (isalpha(*cp)) { - 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 we already locked the record, we are done */ - if (locked) - break; + if (mp->keyfile != NULL) { + fclose(mp->keyfile); + mp->keyfile = NULL; + } - /* Got a real entry, lock it */ - fl.l_start = mp->recstart; - fl.l_len = mp->len; - fl.l_pid = getpid(); - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; + /* Open _PATH_SKEYDIR if it exists, else return an error */ + if (mp->keydir == NULL && (mp->keydir = opendir(_PATH_SKEYDIR)) == NULL) + return (-1); - rval = fcntl(fileno(mp->keyfile), F_SETLK, &fl); - if (rval == 0) + rval = 1; + while ((readdir_r(mp->keydir, &entry, &dp)) == 0 && dp == &entry) { + /* Skip dot files and zero-length files. */ + if (entry.d_name[0] != '.' && + (rval = skeylookup(mp, entry.d_name) != 1)) break; - else if (errno != EAGAIN) - return(-1); - - /* - * Someone else has the entry locked, wait - * until the lock is free, then re-read the entry. - */ - rval = fcntl(fileno(mp->keyfile), F_SETLKW, &fl); - if (rval == -1) /* Can't get exclusive lock */ - return(-1); - locked = 1; - (void)fseek(mp->keyfile, mp->recstart, SEEK_SET); + }; + + if (dp == NULL) { + closedir(mp->keydir); + mp->keydir = NULL; } - return(feof(mp->keyfile)); + + return (rval); } /* @@ -304,106 +222,72 @@ skeyverify(mp, response) char key[SKEY_BINKEY_SIZE]; char fkey[SKEY_BINKEY_SIZE]; char filekey[SKEY_BINKEY_SIZE]; - time_t now; - struct tm *tm; - struct flock fl; - char tbuf[27]; + size_t nread; char *cp; - int len; + + if (response == NULL) + goto verify_failure; /* * The record should already be locked but lock it again * just to be safe. We don't wait for the lock to become * available since we should already have it... */ - fl.l_start = mp->recstart; - 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_SETLK, &fl) != 0) { - (void)fclose(mp->keyfile); - mp->keyfile = NULL; - return(-1); - } - - time(&now); - tm = localtime(&now); - (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm); - - if (response == NULL) { - (void)fclose(mp->keyfile); - mp->keyfile = NULL; - return(-1); - } - rip(response); + if (flock(fileno(mp->keyfile), LOCK_EX | LOCK_NB) != 0) + goto verify_failure; /* Convert response to binary */ - if (etob(key, response) != 1 && atob8(key, response) != 0) { - /* Neither english words nor ascii hex */ - (void)fclose(mp->keyfile); - mp->keyfile = NULL; - return(-1); - } + rip(response); + if (etob(key, response) != 1 && atob8(key, response) != 0) + goto verify_failure; /* Neither english words nor ascii hex */ /* Compute fkey = f(key) */ (void)memcpy(fkey, key, sizeof(key)); - (void)fflush(stdout); f(fkey); - /* Reread the file record NOW */ - (void)fseek(mp->keyfile, mp->recstart, SEEK_SET); - if (fgets(mp->buf, sizeof(mp->buf), mp->keyfile) == NULL) { - (void)fclose(mp->keyfile); - mp->keyfile = NULL; - return(-1); - } - len = strlen(mp->buf) - 1; - cp = mp->buf + len; - while (cp >= mp->buf && (*cp == '\n' || *cp == '\r')) - *cp-- = '\0'; - mp->logname = strtok(mp->buf, " \t"); - cp = strtok(NULL, " \t") ; - if (isalpha(*cp)) - cp = strtok(NULL, " \t") ; - mp->seed = strtok(NULL, " \t"); - mp->val = strtok(NULL, " \t"); - /* And convert file value to hex for comparison */ + /* + * Reread the file record NOW in case it has been modified. + * The only field we really need to worry about is mp->val. + */ + (void)fseek(mp->keyfile, 0L, SEEK_SET); + if ((nread = fread(mp->buf, 1, sizeof(mp->buf), mp->keyfile)) == 0 || + !isspace(mp->buf[nread - 1])) + goto verify_failure; + if ((mp->logname = strtok(mp->buf, " \t\r\n")) == NULL) + goto verify_failure; + if ((cp = strtok(NULL, " \t\r\n")) == NULL) + goto verify_failure; + if ((cp = strtok(NULL, " \t\r\n")) == NULL) + goto verify_failure; + if ((mp->seed = strtok(NULL, " \t\r\n")) == NULL) + goto verify_failure; + if ((mp->val = strtok(NULL, " \t\r\n")) == NULL) + goto verify_failure; + + /* Convert file value to hex and compare. */ atob8(filekey, mp->val); - - /* Do actual comparison */ - if (memcmp(filekey, fkey, SKEY_BINKEY_SIZE) != 0){ - /* Wrong response */ - (void)fclose(mp->keyfile); - mp->keyfile = NULL; - return(1); - } + if (memcmp(filekey, fkey, SKEY_BINKEY_SIZE) != 0) + goto verify_failure; /* Wrong response */ /* - * 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) + * Update key in database. + * XXX - check return values of things that write to disk. */ btoa8(mp->val,key); mp->n--; - (void)fseek(mp->keyfile, mp->recstart, SEEK_SET); - len -= strlen(mp->logname) + strlen(skey_get_algorithm()) + - strlen(mp->val) + strlen(tbuf) + 9; - /* - * If we run out of room it is because we read an old-style - * md4 entry without an explicit hash type. - */ - if (len < strlen(mp->seed)) - (void)fprintf(mp->keyfile, "%s %04d %-16s %s %-21s\n", - mp->logname, mp->n, mp->seed, mp->val, tbuf); - else - (void)fprintf(mp->keyfile, "%s %s %04d %-*s %s %-21s\n", - mp->logname, skey_get_algorithm(), mp->n, - len, mp->seed, mp->val, tbuf); + (void)fseek(mp->keyfile, 0L, SEEK_SET); + (void)fprintf(mp->keyfile, "%s\n%s\n%04d\n%s\n%s\n", mp->logname, + skey_get_algorithm(), mp->n, mp->seed, mp->val); + (void)fflush(mp->keyfile); + (void)ftruncate(fileno(mp->keyfile), ftello(mp->keyfile)); + (void)fclose(mp->keyfile); + mp->keyfile = NULL; + return (0); + verify_failure: (void)fclose(mp->keyfile); mp->keyfile = NULL; - return(0); + return (-1); } /* @@ -418,15 +302,15 @@ skey_haskey(username) { struct skey skey; int i; - + i = skeylookup(&skey, username); if (skey.keyfile != NULL) { fclose(skey.keyfile); skey.keyfile = NULL; } - return(i); + return (i); } - + /* * skey_keyinfo() * @@ -444,15 +328,15 @@ skey_keyinfo(username) i = skeychallenge(&skey, username, str); if (i == -1) - return(0); + return (0); if (skey.keyfile != NULL) { fclose(skey.keyfile); skey.keyfile = NULL; } - return(str); + return (str); } - + /* * skey_passcheck() * @@ -472,12 +356,12 @@ skey_passcheck(username, passwd) i = skeylookup(&skey, username); if (i == -1 || i == 1) - return(-1); + return (-1); if (skeyverify(&skey, passwd) == 0) - return(skey.n); + return (skey.n); - return(-1); + return (-1); } #define ROUND(x) (((x)[0] << 24) + (((x)[1]) << 16) + (((x)[2]) << 8) + \ @@ -488,18 +372,18 @@ skey_passcheck(username, passwd) */ static u_int32_t hash_collapse(s) - u_char *s; + u_char *s; { - int len, target; + int len, target; u_int32_t i; - + if ((strlen(s) % sizeof(u_int32_t)) == 0) target = strlen(s); /* Multiple of 4 */ else target = strlen(s) - (strlen(s) % sizeof(u_int32_t)); - + for (i = 0, len = 0; len < target; len += 4) - i ^= ROUND(s + len); + i ^= ROUND(s + len); return i; } @@ -576,7 +460,7 @@ skey_fakeprompt(username, skeyprompt) SHA1Update(&ctx, secret, secretlen); SHA1Update(&ctx, username, strlen(username)); SHA1End(&ctx, up); - + /* Zero out */ memset(secret, 0, secretlen); @@ -584,9 +468,9 @@ skey_fakeprompt(username, skeyprompt) SHA1Init(&ctx); SHA1Update(&ctx, up, strlen(up)); SHA1End(&ctx, up); - + ptr = hash_collapse(up + 4); - + for (i = 4; i < 9; i++) { pbuf[i] = (ptr % 10) + '0'; ptr /= 10; @@ -663,9 +547,9 @@ skey_authenticate(username) "\nWarning! Key initialization needed soon. (%d logins left)\n", skey.n); } - return(0); + return (0); } - return(-1); + return (-1); } /* @@ -676,26 +560,23 @@ skey_authenticate(username) * 0: Database updated * * The database file is always closed by this call. + * XXX - do we still need this function? */ int skeyzero(mp) struct skey *mp; { + int rval; /* - * Seek to the right place and write comment character - * which effectively zero's out the entry. + * We truncate the file rather than unlinking it since we + * may not have write perms on the directory. */ - (void)fseek(mp->keyfile, mp->recstart, SEEK_SET); - if (fputc('#', mp->keyfile) == EOF) { - fclose(mp->keyfile); - mp->keyfile = NULL; - return(-1); - } - + fflush(mp->keyfile); + rval = ftruncate(fileno(mp->keyfile), (off_t)0); (void)fclose(mp->keyfile); mp->keyfile = NULL; - return(0); + return (rval); } /* @@ -709,18 +590,10 @@ int skey_unlock(mp) struct skey *mp; { - struct flock fl; - if (mp->logname == NULL || mp->keyfile == NULL) - return(-1); - - fl.l_start = mp->recstart; - fl.l_len = mp->len; - fl.l_pid = getpid(); - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; + return (-1); - return(fcntl(fileno(mp->keyfile), F_SETLK, &fl)); + return (flock(fileno(mp->keyfile), LOCK_UN)); } /* @@ -728,63 +601,63 @@ skey_unlock(mp) */ static char * tgetline(fd, buf, bufsiz, timeout) - int fd; - char *buf; - size_t bufsiz; - int timeout; + int fd; + char *buf; + size_t bufsiz; + int timeout; { - size_t left; - int n; - fd_set *readfds = NULL; - struct timeval tv; - char c; - char *cp; - - if (bufsiz == 0) - return(NULL); /* sanity */ - - cp = buf; - left = bufsiz; - - /* - * Timeout of <= 0 means no timeout. - */ - if (timeout > 0) { - /* Setup for select(2) */ - n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask); - if ((readfds = (fd_set *) malloc(n)) == NULL) - return(NULL); - (void) memset(readfds, 0, n); - - /* Set timeout for select */ - tv.tv_sec = timeout; - tv.tv_usec = 0; - - while (--left) { - FD_SET(fd, readfds); - - /* Make sure there is something to read (or timeout) */ - while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 && - (errno == EINTR || errno == EAGAIN)) - ; - if (n == 0) { - free(readfds); - return(NULL); /* timeout */ - } - - /* Read a character, exit loop on error, EOF or EOL */ - n = read(fd, &c, 1); - if (n != 1 || c == '\n' || c == '\r') - break; - *cp++ = c; - } - free(readfds); - } else { - /* Keep reading until out of space, EOF, error, or newline */ - while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r') - *cp++ = c; - } - *cp = '\0'; - - return(cp == buf ? NULL : buf); + size_t left; + int n; + fd_set *readfds = NULL; + struct timeval tv; + char c; + char *cp; + + if (bufsiz == 0) + return (NULL); /* sanity */ + + cp = buf; + left = bufsiz; + + /* + * Timeout of <= 0 means no timeout. + */ + if (timeout > 0) { + /* Setup for select(2) */ + n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask); + if ((readfds = (fd_set *) malloc(n)) == NULL) + return (NULL); + (void) memset(readfds, 0, n); + + /* Set timeout for select */ + tv.tv_sec = timeout; + tv.tv_usec = 0; + + while (--left) { + FD_SET(fd, readfds); + + /* Make sure there is something to read (or timeout) */ + while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 && + (errno == EINTR || errno == EAGAIN)) + ; + if (n == 0) { + free(readfds); + return (NULL); /* timeout */ + } + + /* Read a character, exit loop on error, EOF or EOL */ + n = read(fd, &c, 1); + if (n != 1 || c == '\n' || c == '\r') + break; + *cp++ = c; + } + free(readfds); + } else { + /* Keep reading until out of space, EOF, error, or newline */ + while (--left && (n = read(fd, &c, 1)) == 1 && c != '\n' && c != '\r') + *cp++ = c; + } + *cp = '\0'; + + return (cp == buf ? NULL : buf); } diff --git a/usr.bin/skeyaudit/Makefile b/usr.bin/skeyaudit/Makefile index 967b6727fbb..00f643b060d 100644 --- a/usr.bin/skeyaudit/Makefile +++ b/usr.bin/skeyaudit/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.2 1997/09/21 11:50:51 deraadt Exp $ +# $OpenBSD: Makefile,v 1.3 2002/05/16 03:50:42 millert Exp $ PROG= skeyaudit -BINOWN= root -BINMODE=4555 +BINGRP= auth +BINMODE=2555 DPADD= ${LIBSKEY} LDADD= -lskey diff --git a/usr.bin/skeyaudit/skeyaudit.1 b/usr.bin/skeyaudit/skeyaudit.1 index 2fa5b00e1fa..30192984c03 100644 --- a/usr.bin/skeyaudit/skeyaudit.1 +++ b/usr.bin/skeyaudit/skeyaudit.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: skeyaudit.1,v 1.8 2000/11/09 17:52:38 aaron Exp $ +.\" $OpenBSD: skeyaudit.1,v 1.9 2002/05/16 03:50:42 millert Exp $ .\" .Dd 22 July 1997 .Dt SKEYAUDIT 1 @@ -13,8 +13,8 @@ .Op Fl l Ar limit .Sh DESCRIPTION .Nm -searches through the file -.Pa /etc/skeykeys +searches through the files in +.Pa /etc/skey for users whose S/Key sequence number is less than .Ar limit , and mails them a reminder to run @@ -25,7 +25,7 @@ The options are as follows: .Bl -tag -width Ds .It Fl a Check all keys in -.Pa /etc/skeykeys . +.Pa /etc/skey This option is only available to the superuser and is useful to run regularly via .Xr cron 8 . @@ -37,9 +37,9 @@ The limit used to determine whether or not a user should be notified. The default is to notify if there are fewer than 12 keys left. .El .Sh FILES -.Bl -tag -width /etc/skeykeys -compact -.It Pa /etc/skeykeys -S/Key key information database +.Bl -tag -width /etc/skey +.It Pa /etc/skey +directory containing user entries for S/Key .El .Sh SEE ALSO .Xr skey 1 , diff --git a/usr.bin/skeyaudit/skeyaudit.c b/usr.bin/skeyaudit/skeyaudit.c index 9a8f576fdf9..900d255cb6c 100644 --- a/usr.bin/skeyaudit/skeyaudit.c +++ b/usr.bin/skeyaudit/skeyaudit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: skeyaudit.c,v 1.12 2002/02/16 21:27:52 millert Exp $ */ +/* $OpenBSD: skeyaudit.c,v 1.13 2002/05/16 03:50:42 millert Exp $ */ /* * Copyright (c) 1997, 2000 Todd C. Miller <Todd.Miller@courtesan.com> @@ -58,9 +58,6 @@ main(argc, argv) int ch, errs = 0, left = 0, aflag = 0, iflag = 0, limit = 12; char *name; - if (geteuid() != 0) - errx(1, "must be setuid root"); - while ((ch = getopt(argc, argv, "ail:")) != -1) switch(ch) { case 'a': @@ -100,7 +97,7 @@ main(argc, argv) notify(pw, left, iflag); } if (ch == -1) - errx(-1, "cannot open %s", _PATH_SKEYKEYS); + errx(-1, "cannot open %s", _PATH_SKEYDIR); else (void)fclose(key.keyfile); } else { @@ -116,11 +113,11 @@ main(argc, argv) left = key.n - 1; break; case -1: /* File error */ - errx(errs, "cannot open %s", _PATH_SKEYKEYS); + errx(errs, "cannot open %s", _PATH_SKEYDIR); break; case 1: /* Unknown user */ warnx("%s is not listed in %s", name, - _PATH_SKEYKEYS); + _PATH_SKEYDIR); } (void)fclose(key.keyfile); diff --git a/usr.bin/skeyinit/Makefile b/usr.bin/skeyinit/Makefile index f2beaf1f55e..d4cea9f3d10 100644 --- a/usr.bin/skeyinit/Makefile +++ b/usr.bin/skeyinit/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.6 1997/09/21 11:50:55 deraadt Exp $ +# $OpenBSD: Makefile,v 1.7 2002/05/16 03:50:42 millert Exp $ PROG= skeyinit -BINOWN=root -BINMODE=4555 +BINGRP=auth +BINMODE=2555 DPADD= ${LIBSKEY} LDADD= -lskey diff --git a/usr.bin/skeyinit/skeyinit.1 b/usr.bin/skeyinit/skeyinit.1 index d11e1825702..91ba68e3338 100644 --- a/usr.bin/skeyinit/skeyinit.1 +++ b/usr.bin/skeyinit/skeyinit.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: skeyinit.1,v 1.20 2001/06/20 22:25:08 millert Exp $ +.\" $OpenBSD: skeyinit.1,v 1.21 2002/05/16 03:50:42 millert Exp $ .\" $NetBSD: skeyinit.1,v 1.4 1995/07/07 22:24:09 jtc Exp $ .\" @(#)skeyinit.1 1.1 10/28/93 .\" @@ -11,7 +11,12 @@ .Sh SYNOPSIS .Nm skeyinit .Op Fl s +.Op Fl x .Op Fl z +.Op Fl C +.Op Fl D +.Op Fl E +.Op Fl a Ar auth-type .Op Fl n Ar count .Oo .Fl md4 | Fl md5 | Fl sha1 | @@ -49,8 +54,25 @@ S/Key challenge and allowed to proceed if it is correct. .Pp The options are as follows: .Bl -tag -width Ds -.It Fl x -Displays pass phrase in hexadecimal instead of ASCII. +.It Fl C +Converts from the old-style +.Pa /etc/skeykeys +database to a new-style database where user records are stored in the +.Pa /etc/skey +directory. +If an entry already exists in the new-style database it will not +be overwritten. +.Pa +.It Fl D +Disables access to the S/Key database. +Only the superuser may use the +.Fl D +option. +.It Fl E +Enables access to the S/Key database. +Only the superuser may use the +.Fl E +option. .It Fl s Set secure mode where the user is expected to have used a secure machine to generate the first one-time password. @@ -76,8 +98,15 @@ count and seed. You can then "cut-and-paste" or type the words into the .Nm window. +.It Fl x +Displays pass phrase in hexadecimal instead of ASCII. .It Fl z Allows the user to zero their S/Key entry. +.It Fl a Ar auth-type +Specify an authentication type such as +.Dq krb4 +or +.Dq krb5 . .It Fl n Ar count Start the .Nm skey @@ -99,17 +128,20 @@ By default the current user is operated on. .Sh ERRORS .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 . +.Pa /etc/skey +does not exist or is not accessable by the user. +The superuser may enable +.Nm +via the +.Fl E +flag. .El .Sh FILES -.Bl -tag -width /etc/skeykeys -.It Pa /etc/skeykeys -database of information for S/Key system +.Bl -tag -width /etc/skey +.It Pa /etc/skey +directory containing user entries for S/Key .El .Sh SEE ALSO .Xr skey 1 .Sh AUTHORS -Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin +Phil Karn, Neil M. Haller, John S. Walden, Scott Chasin, Todd Miller diff --git a/usr.bin/skeyinit/skeyinit.c b/usr.bin/skeyinit/skeyinit.c index 791bc429e73..c340f0ec003 100644 --- a/usr.bin/skeyinit/skeyinit.c +++ b/usr.bin/skeyinit/skeyinit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: skeyinit.c,v 1.31 2002/02/16 21:27:52 millert Exp $ */ +/* $OpenBSD: skeyinit.c,v 1.32 2002/05/16 03:50:42 millert Exp $ */ /* OpenBSD S/Key (skeyinit.c) * @@ -14,12 +14,13 @@ #include <sys/param.h> #include <sys/file.h> -#include <sys/time.h> #include <sys/resource.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <ctype.h> #include <err.h> #include <errno.h> -#include <ctype.h> #include <pwd.h> #include <readpassphrase.h> #include <stdio.h> @@ -31,37 +32,35 @@ #include <utmp.h> #include <skey.h> +#include <bsd_auth.h> #ifndef SKEY_NAMELEN #define SKEY_NAMELEN 4 #endif -void lockeof(struct skey *, char *); void usage(char *); void secure_mode(int *, char *, char *, char *, char *, size_t); void normal_mode(char *, int, char *, char *, char *); void timedout(int); +void convert_db(void); +void enable_db(int); int main(argc, argv) int argc; char *argv[]; { - int rval, i, l, n=0, defaultsetup=1, zerokey=0, hexmode=0; - int oldmd4=0; - time_t now; - size_t seedlen; + int rval, i, l, n, defaultsetup, zerokey, hexmode, enable, convert; char hostname[MAXHOSTNAMELEN]; - char passwd[SKEY_MAX_PW_LEN+2]; - char seed[SKEY_MAX_SEED_LEN+2], defaultseed[SKEY_MAX_SEED_LEN+1]; - char tbuf[27], buf[256], key[SKEY_BINKEY_SIZE]; - char lastc, me[UT_NAMESIZE+1], *salt, *p, *ht=NULL; + char seed[SKEY_MAX_SEED_LEN + 2], defaultseed[SKEY_MAX_SEED_LEN + 1]; + char buf[256], key[SKEY_BINKEY_SIZE], filename[PATH_MAX], *ht; + char lastc, me[UT_NAMESIZE + 1], *p, *auth_type; struct skey skey; struct passwd *pp; - struct tm *tm; - if (geteuid() != 0) - errx(1, "must be setuid root."); + n = zerokey = hexmode = enable = convert = 0; + defaultsetup = 1; + ht = auth_type = NULL; /* Build up a default seed based on the hostname and time */ if (gethostname(hostname, sizeof(hostname)) < 0) @@ -75,9 +74,6 @@ main(argc, argv) *p++ = hostname[i]; } *p = '\0'; - (void)time(&now); - (void)sprintf(tbuf, "%05ld", (long) (now % 100000)); - (void)strncat(defaultseed, tbuf, sizeof(defaultseed) - 5); if ((pp = getpwuid(getuid())) == NULL) err(1, "no user with uid %d", getuid()); @@ -85,14 +81,19 @@ main(argc, argv) if ((pp = getpwnam(me)) == NULL) err(1, "Who are you?"); - salt = pp->pw_passwd; for (i = 1; i < argc && argv[i][0] == '-' && strcmp(argv[i], "--");) { if (argv[i][2] == '\0') { /* Single character switch */ switch (argv[i][1]) { + case 'a': + if (argv[++i] == NULL || argv[i][0] == '\0') + usage(argv[0]); + auth_type = argv[i]; + break; case 's': defaultsetup = 0; + auth_type = "skey"; break; case 'x': hexmode = 1; @@ -107,6 +108,15 @@ main(argc, argv) errx(1, "count must be > 0 and < %d", SKEY_MAX_SEQ); break; + case 'C': + convert = 1; + break; + case 'D': + enable = -1; + break; + case 'E': + enable = 1; + break; default: usage(argv[0]); } @@ -119,11 +129,21 @@ main(argc, argv) } i++; } + argv += i; + argc -= i; - /* check for optional user string */ - if (argc - i > 1) { + if (argc > 1 || (enable && convert) || (enable && argc) || + (convert && argc)) usage(argv[0]); - } else if (argv[i]) { + + /* Handle -C, -D, and -E */ + if (enable) + enable_db(enable); + if (convert) + convert_db(); + + /* Check for optional user string. */ + if (argc == 1) { if ((pp = getpwnam(argv[i])) == NULL) { if (getuid() == 0) { static struct passwd _pp; @@ -134,42 +154,23 @@ main(argc, argv) } else { errx(1, "User unknown: %s", argv[i]); } - } else if (strcmp(pp->pw_name, me) != 0) { - if (getuid() != 0) { - /* Only root can change other's passwds */ - errx(1, "Permission denied."); - } + } else if (strcmp(pp->pw_name, me) != 0 && getuid() != 0) { + /* Only root can change other's S/Keys. */ + errx(1, "Permission denied."); } } 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); + fputs("Reminder - Only use this method if you are directly " + "connected\n or have an encrypted channel. If " + "you are using telnet,\n hit return now and use " + "skeyinit -s.\n", stderr); if (getuid() != 0) { - /* 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 { - fflush(stdout); - readpassphrase("Password: ", passwd, sizeof(passwd), 0); - if (strcmp(crypt(passwd, salt), pp->pw_passwd)) { - if (passwd[0]) - warnx("Password incorrect."); - exit(1); - } - } + if ((pp = pw_dup(pp)) == NULL) + err(1, NULL); + if (!auth_userokay(pp->pw_name, auth_type, NULL, NULL)) + errx(1, "Password incorrect"); } /* @@ -229,17 +230,24 @@ main(argc, argv) errx(1, "You have no entry to zero."); (void)printf("[Adding %s with %s]\n", pp->pw_name, ht ? ht : skey_get_algorithm()); - lockeof(&skey, pp->pw_name); + if (snprintf(filename, sizeof(filename), "%s/%s", + _PATH_SKEYDIR, pp->pw_name) >= sizeof(filename)) { + errno = ENAMETOOLONG; + err(1, "Cannot create S/Key entry"); + } + if ((l = open(filename, O_RDWR | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR)) == -1 || + flock(l, LOCK_EX) != 0 || + (skey.keyfile = fdopen(l, "r+")) == NULL) + err(1, "Cannot create S/Key entry"); break; } + if (fchown(fileno(skey.keyfile), pp->pw_uid, -1) != 0 || + fchmod(fileno(skey.keyfile), S_IRUSR | S_IWUSR) != 0) + err(1, "can't set owner/mode for %s", pp->pw_name); if (n == 0) n = 99; - /* 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; - /* Set hash type if asked to */ if (ht && strcmp(ht, skey_get_algorithm()) != 0) skey_set_algorithm(ht); @@ -251,55 +259,14 @@ main(argc, argv) normal_mode(pp->pw_name, n, key, seed, defaultseed); alarm(0); - (void)time(&now); - tm = localtime(&now); - (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm); - - /* 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; - } - - /* If new entry is longer than the old, comment out the old. */ - if (nlen > skey.len) { - (void)skeyzero(&skey); - /* 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); - } - } - + /* XXX - why use malloc here? */ if ((skey.val = (char *)malloc(16 + 1)) == NULL) err(1, "Can't allocate memory"); btoa8(skey.val, key); - /* 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 %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)fseek(skey.keyfile, 0L, SEEK_SET); + (void)fprintf(skey.keyfile, "%s\n%s\n%04d\n%s\n%s\n", + pp->pw_name, skey_get_algorithm(), n, seed, skey.val); (void)fclose(skey.keyfile); (void)printf("\nID %s skey is otp-%s %d %s\n", pp->pw_name, @@ -310,35 +277,6 @@ main(argc, argv) } 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; -} - -void secure_mode(count, key, seed, defaultseed, buf, bufsiz) int *count; char *key; @@ -483,6 +421,97 @@ normal_mode(username, n, key, seed, defaultseed) f(key); } +void +enable_db(op) + int op; +{ + if (op == 1) { + /* enable */ + if (mkdir(_PATH_SKEYDIR, 01730) != 0 && errno != EEXIST) + err(1, "can't mkdir %s", _PATH_SKEYDIR); + if (chmod(_PATH_SKEYDIR, 01730) != 0) + err(1, "can't chmod %s", _PATH_SKEYDIR); + } else { + /* disable */ + if (chmod(_PATH_SKEYDIR, 0) != 0 && errno != ENOENT) + err(1, "can't chmod %s", _PATH_SKEYDIR); + } + exit(0); +} + +#define _PATH_SKEYKEYS "/etc/skeykeys" +void +convert_db(void) +{ + struct passwd *pp; + uid_t uid; + FILE *keyfile; + FILE *newfile; + char buf[256], *logname, *hashtype, *seed, *val, *cp; + char filename[PATH_MAX]; + int fd, n; + + if ((keyfile = fopen(_PATH_SKEYKEYS, "r")) == NULL) + err(1, "can't open %s", _PATH_SKEYKEYS); + if (flock(fileno(keyfile), LOCK_EX) != 0) + err(1, "can't lock %s", _PATH_SKEYKEYS); + if (mkdir(_PATH_SKEYDIR, 01730) != 0 && errno != EEXIST) + err(1, "can't mkdir %s", _PATH_SKEYDIR); + if (chmod(_PATH_SKEYDIR, 01730) != 0) + err(1, "can't chmod %s", _PATH_SKEYDIR); + + /* + * Loop over each entry in _PATH_SKEYKEYS, creating a file + * in _PATH_SKEYDIR for each one. + */ + while (fgets(buf, sizeof(buf), keyfile) != NULL) { + if (buf[0] == '#') + continue; + if ((logname = strtok(buf, " \t")) == NULL) + continue; + if ((cp = strtok(NULL, " \t")) == NULL) + continue; + if (isalpha(*cp)) { + hashtype = cp; + if ((cp = strtok(NULL, " \t")) == NULL) + continue; + } else + hashtype = "md4"; + n = atoi(cp); + if ((seed = strtok(NULL, " \t")) == NULL) + continue; + if ((val = strtok(NULL, " \t")) == NULL) + continue; + + if ((pp = getpwnam(logname)) != NULL) + uid = pp->pw_uid; + else + uid = 0; + + /* Now write the new-style record. */ + if (snprintf(filename, sizeof(filename), "%s/%s", _PATH_SKEYDIR, + logname) >= sizeof(filename)) { + errno = ENAMETOOLONG; + warn("%s", logname); + continue; + } + fd = open(filename, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd == -1 || flock(fd, LOCK_EX) != 0 || + (newfile = fdopen(fd, "r+")) == NULL) { + warn("%s", logname); + continue; + } + (void)fprintf(newfile, "%s\n%s\n%04d\n%s\n%s\n", logname, + hashtype, n, seed, val); + (void)fchown(fileno(newfile), uid, -1); + (void)fclose(newfile); + } + printf("%s has been populated. NOTE: %s has *not* been removed.\n" + "It should be removed once you have verified that the new keys " + "work.\n", _PATH_SKEYDIR, _PATH_SKEYKEYS); + exit(0); +} + #define TIMEOUT_MSG "Timed out waiting for input.\n" void timedout(signo) @@ -497,7 +526,8 @@ void usage(s) char *s; { - (void)fprintf(stderr, - "Usage: %s [-s] [-x] [-z] [-n count] [-md4|-md5|-sha1|-rmd160] [user]\n", s); + (void)fprintf(stderr, "usage: %s [-s] [-x] [-z] [-C] [-D] [-E] " + "[-a auth_type] [-n count]\n " + "[-md4|-md5|-sha1|-rmd160] [user]\n", s); exit(1); } |