diff options
author | pst <pst@FreeBSD.org> | 1997-02-06 17:52:29 +0000 |
---|---|---|
committer | pst <pst@FreeBSD.org> | 1997-02-06 17:52:29 +0000 |
commit | 2dfcbf193123fd16b26454eeffa4bbd014e52c53 (patch) | |
tree | ec9d150c9da4390c2d223a04ac002523cbfd7f36 /contrib/opie/opiepasswd.c | |
download | FreeBSD-src-2dfcbf193123fd16b26454eeffa4bbd014e52c53.zip FreeBSD-src-2dfcbf193123fd16b26454eeffa4bbd014e52c53.tar.gz |
Initial import of OPIE v2.3 from
ftp://ftp.nrl.navy.mil/pub/security/opie/
Diffstat (limited to 'contrib/opie/opiepasswd.c')
-rw-r--r-- | contrib/opie/opiepasswd.c | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/contrib/opie/opiepasswd.c b/contrib/opie/opiepasswd.c new file mode 100644 index 0000000..719b68f --- /dev/null +++ b/contrib/opie/opiepasswd.c @@ -0,0 +1,429 @@ +/* opiepasswd.c: Add/change an OTP password in the key database. + +%%% portions-copyright-cmetz +Portions of this software are Copyright 1996 by Craig Metz, All Rights +Reserved. The Inner Net License Version 2 applies to these portions of +the software. +You should have received a copy of the license with this software. If +you didn't get a copy, you may request one from <license@inner.net>. + +Portions of this software are Copyright 1995 by Randall Atkinson and Dan +McDonald, All Rights Reserved. All Rights under this copyright are assigned +to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and +License Agreement applies to this software. + + History: + + Modified by cmetz for OPIE 2.3. Got of some variables and made some + local to where they're used. Split out the finishing code. Use + opielookup() instead of opiechallenge() to find user. Three + strikes on prompts. Use opiepasswd()'s new calling + convention. Changed OPIE_PASS_{MAX,MIN} to + OPIE_SECRET_{MAX,MIN}. Handle automatic reinits happenning + below us. Got rid of unneeded headers. Use new opieatob8() + return value convention. Added -f flag. Added SHA support. + Modified by cmetz for OPIE 2.22. Finally got rid of the lock + filename kluge by implementing refcounts for locks. + Use opiepasswd() to update key file. Error if we can't + write to the key file. Check for minimum seed length. + Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to + opiestripcrlf. Check opiereadpass() return value. + Minor optimization. Change calls to opiereadpass() to + use echo arg. Use opiereadpass() where we can. + Make everything static. Ifdef around some headers. + Changed use of gethostname() to uname(). Got rid of + the need for buf[]. Properly check return value of + opieatob8. Check seed length. Always generate proper- + length seeds. + Modified at NRL for OPIE 2.1. Minor autoconf changes. + Modified heavily at NRL for OPIE 2.0. + Written at Bellcore for the S/Key Version 1 software distribution + (skeyinit.c). +*/ +#include "opie_cfg.h" + +#if HAVE_PWD_H +#include <pwd.h> +#endif /* HAVE_PWD_H */ +#include <stdio.h> +#if HAVE_STRING_H +#include <string.h> +#endif /* HAVE_STRING_H */ +#include <stdio.h> +#include <sys/types.h> +#if HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif /* HAVE_STDLIB_H */ + +#include "opie.h" + +#define MODE_DEFAULT 0 +#define MODE_CONSOLE 1 +#define MODE_DISABLE 2 + +extern int optind; +extern char *optarg; + +char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; +char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; + +static VOIDRET usage FUNCTION((myname), char *myname) +{ + fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname); + exit(1); +} + +static VOIDRET finish FUNCTION((name), char *name) +{ + struct opie opie; + char buf[OPIE_RESPONSE_MAX + 1]; + + if (name) { + if (opiechallenge(&opie, name, buf)) { + fprintf(stderr, "Error verifying database.\n"); + finish(NULL); + } + printf("\nID %s ", opie.opie_principal); + if (opie.opie_val && (opie.opie_val[0] == '*')) { + printf("is disabled.\n"); + finish(NULL); + } + printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed); + { + char key[8]; + if (!opieatob8(key, opie.opie_val)) { + fprintf(stderr, "Error verifying key -- possible database corruption.\n"); + finish(NULL); + } + printf("%s\n", opiebtoe(buf, key)); + } + } + + while(!opieunlock()); + exit(name ? 0 : 1); +} + +int main FUNCTION((argc, argv), int argc AND char *argv[]) +{ + struct opie opie; + int rval, n = 499, i, mode = MODE_DEFAULT, force = 0; + char seed[18]; + struct passwd *pp; + + memset(seed, 0, sizeof(seed)); + + if (!(pp = getpwuid(getuid()))) { + fprintf(stderr, "Who are you?"); + return 1; + } + + while ((i = getopt(argc, argv, "fhvcn:s:")) != EOF) { + switch (i) { + case 'v': + opieversion(); + case 'f': +#if INSECURE_OVERRIDE + force = 1; +#else /* INSECURE_OVERRIDE */ + fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); +#endif /* INSECURE_OVERRIDE */ + break; + case 'c': + mode = MODE_CONSOLE; + break; + case 'd': + mode = MODE_DISABLE; + break; + case 'n': + i = atoi(optarg); + if (!(i > 0 && i < 10000)) { + printf("Sequence numbers must be > 0 and < 10000\n"); + finish(NULL); + } + n = i; + break; + case 's': + i = strlen(optarg); + if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) { + printf("Seeds must be between %d and %d characters long.\n", + OPIE_SEED_MIN, OPIE_SEED_MAX); + finish(NULL); + } + strncpy(seed, optarg, sizeof(seed)); + seed[sizeof(seed) - 1] = 0; + break; + default: + usage(argv[0]); + } + } + + if (argc - optind >= 1) { + if (strcmp(argv[optind], pp->pw_name)) { + if (getuid()) { + printf("Only root can change others' passwords.\n"); + exit(1); + } + if ((pp = getpwnam(argv[optind])) == NULL) { + printf("%s: user unknown.\n", argv[optind]); + exit(1); + } + } + } + + opielock(pp->pw_name); + rval = opielookup(&opie, pp->pw_name); + + switch (rval) { + case 0: + printf("Updating %s:\n", pp->pw_name); + break; + case 1: + printf("Adding %s:\n", pp->pw_name); + break; + case 2: + fprintf(stderr, "Error: Can't update key database.\n"); + exit(1); + default: + fprintf(stderr, "Error reading key database\n"); + exit(1); + } + + if (seed[0]) { + i = strlen(seed); + if (i > OPIE_SEED_MAX) { + fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX); + finish(NULL); + } + if (i < OPIE_SEED_MIN) { + fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN); + finish(NULL); + } + } else { + if (!rval) + strcpy(seed, opie.opie_seed); + + if (opienewseed(seed) < 0) { + fprintf(stderr, "Error updating seed.\n"); + finish(NULL); + } + } + + if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) { + fprintf(stderr, "You must use a different seed for the new OTP sequence.\n"); + finish(NULL); + } + + switch(mode) { + case MODE_DEFAULT: + { + char tmp[OPIE_RESPONSE_MAX + 2]; + + printf("You need the response from an OTP generator.\n"); +#if DEBUG + if (!rval) { +#else /* DEBUG */ + if (!rval && getuid()) { +#endif /* DEBUG */ + char oseed[OPIE_SEED_MAX + 1]; + int on; + + if (opiechallenge(&opie, pp->pw_name, tmp)) { + fprintf(stderr, "Error issuing challenge.\n"); + finish(NULL); + } + on = opiegetsequence(&opie); + { + char *c; + if (c = strrchr(tmp, ' ')) + strncpy(oseed, c + 1, sizeof(oseed)); + else { +#if DEBUG + fprintf(stderr, "opiepasswd: bogus challenge\n"); +#endif /* DEBUG */ + finish(NULL); + } + } + printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp); + if (!opiereadpass(tmp, sizeof(tmp), 1)) + tmp[0] = 0; + i = opieverify(&opie, tmp); + if (!tmp[0]) { + fprintf(stderr, "Error reading response.\n"); + finish(NULL); + } + if (i) { + fprintf(stderr, "Error verifying response.\n"); +#if DEBUG + fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i); +#endif /* DEBUG */ + finish(NULL); + } + { + char nseed[OPIE_SEED_MAX + 1]; + int nn; + + if (opiechallenge(&opie, pp->pw_name, tmp)) { + fprintf(stderr, "Error verifying database.\n"); + finish(NULL); + } + + nn = opiegetsequence(&opie); + { + char *c; + if (c = strrchr(tmp, ' ')) + strncpy(nseed, c + 1, sizeof(nseed)); + else { +#if DEBUG + fprintf(stderr, "opiepasswd: bogus challenge\n"); +#endif /* DEBUG */ + finish(NULL); + } + } + + opieverify(&opie, ""); + nn++; + + if ((nn != on) || strcmp(oseed, nseed)) + finish(pp->pw_name); + } + } + printf("New secret pass phrase:"); + for (i = 0;; i++) { + if (i > 2) + finish(NULL); + printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed); + if (!opiereadpass(tmp, sizeof(tmp), 1)) { + fprintf(stderr, "Error reading response.\n"); + finish(NULL); + } + if (tmp[0] == '?') { + printf("Enter the response from your OTP calculator: \n"); + continue; + } + if (tmp[0] == '\0') { + fprintf(stderr, "Secret pass phrase unchanged.\n"); + finish(NULL); + } + + if (!(rval = opiepasswd(&opie, 0, pp->pw_name, n, seed, tmp))) + finish(pp->pw_name); + + if (rval < 0) { + fprintf(stderr, "Error updating key database.\n"); + finish(NULL); + } + printf("\tThat is not a valid OTP response.\n"); + } + } + break; + case MODE_CONSOLE: + { + char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1]; + /* Get user's secret password */ + fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n"); + fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n"); + fprintf(stderr, "Then run opiepasswd without the -c parameter.\n"); + if (opieinsecure()) { + fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); + if (force) + fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); + else + finish(NULL); + }; + printf("Using %s to compute responses.\n", algnames[MDX]); + if (!rval && getuid()) { + printf("Enter old secret pass phrase: "); + if (!opiereadpass(passwd, sizeof(passwd), 0)) { + fprintf(stderr, "Error reading secret pass phrase!\n"); + finish(NULL); + } + if (!passwd[0]) { + fprintf(stderr, "Secret pass phrase unchanged.\n"); + finish(NULL); + } + { + char key[8]; + char tbuf[OPIE_RESPONSE_MAX + 1]; + + if (opiekeycrunch(MDX, key, opie.opie_seed, passwd) != 0) { + fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]); + finish(NULL); + } + memset(passwd, 0, sizeof(passwd)); + i = opie.opie_n - 1; + while (i-- != 0) + opiehash(key, MDX); + opiebtoe(tbuf, key); + if (opieverify(&opie, tbuf)) { + fprintf(stderr, "Sorry.\n"); + finish(NULL); + } + } + } + for (i = 0;; i++) { + if (i > 2) + finish(NULL); + printf("Enter new secret pass phrase: "); + if (!opiereadpass(passwd, sizeof(passwd), 0)) { + fprintf(stderr, "Error reading secret pass phrase.\n"); + finish(NULL); + } + if (!passwd[0] || feof(stdin)) { + fprintf(stderr, "Secret pass phrase unchanged.\n"); + finish(NULL); + } + if (opiepasscheck(passwd)) { + memset(passwd, 0, sizeof(passwd)); + fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); + continue; + } + printf("Again new secret pass phrase: "); + if (!opiereadpass(passwd2, sizeof(passwd2), 0)) { + fprintf(stderr, "Error reading secret pass phrase.\n"); + finish(NULL); + } + if (feof(stdin)) { + fprintf(stderr, "Secret pass phrase unchanged.\n"); + finish(NULL); + } + if (!passwd[0] || !strcmp(passwd, passwd2)) + break; + fprintf(stderr, "Sorry, no match.\n"); + } + memset(passwd2, 0, sizeof(passwd2)); + if (opiepasswd(&opie, 1, pp->pw_name, n, seed, passwd)) { + fprintf(stderr, "Error updating key database.\n"); + finish(NULL); + } + finish(pp->pw_name); + } + case MODE_DISABLE: + { + char tmp[4]; + int i; + + for (i = 0;; i++) { + if (i > 2) + finish(NULL); + + printf("Disable %s's OTP access? (yes or no) ", pp->pw_name); + if (!opiereadpass(tmp, sizeof(tmp), 1)) { + fprintf(stderr, "Error reading entry.\n"); + finish(NULL); + } + if (!strcmp(tmp, "no")) + finish(NULL); + if (!strcmp(tmp, "yes")) { + if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) { + fprintf(stderr, "Error updating key database.\n"); + finish(NULL); + } + finish(pp->pw_name); + } + } + } + } +} |