opiepasswd.c revision 92914
122347Spst/* opiepasswd.c: Add/change an OTP password in the key database. 222347Spst 329964Sache%%% portions-copyright-cmetz-96 492914SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 522347SpstReserved. The Inner Net License Version 2 applies to these portions of 622347Spstthe software. 722347SpstYou should have received a copy of the license with this software. If 822347Spstyou didn't get a copy, you may request one from <license@inner.net>. 922347Spst 1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1322347SpstLicense Agreement applies to this software. 1422347Spst 1522347Spst History: 1622347Spst 1792914Smarkm Modified by cmetz for OPIE 2.4. Use struct opie_key for key blocks. 1892914Smarkm Use opiestrncpy(). 1959118Skris Modified by cmetz for OPIE 2.32. Use OPIE_SEED_MAX instead of 2059118Skris hard coding the length. Unlock user on failed lookup. 2122347Spst Modified by cmetz for OPIE 2.3. Got of some variables and made some 2222347Spst local to where they're used. Split out the finishing code. Use 2322347Spst opielookup() instead of opiechallenge() to find user. Three 2422347Spst strikes on prompts. Use opiepasswd()'s new calling 2522347Spst convention. Changed OPIE_PASS_{MAX,MIN} to 2622347Spst OPIE_SECRET_{MAX,MIN}. Handle automatic reinits happenning 2722347Spst below us. Got rid of unneeded headers. Use new opieatob8() 2822347Spst return value convention. Added -f flag. Added SHA support. 2922347Spst Modified by cmetz for OPIE 2.22. Finally got rid of the lock 3022347Spst filename kluge by implementing refcounts for locks. 3122347Spst Use opiepasswd() to update key file. Error if we can't 3222347Spst write to the key file. Check for minimum seed length. 3322347Spst Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to 3422347Spst opiestripcrlf. Check opiereadpass() return value. 3522347Spst Minor optimization. Change calls to opiereadpass() to 3622347Spst use echo arg. Use opiereadpass() where we can. 3722347Spst Make everything static. Ifdef around some headers. 3822347Spst Changed use of gethostname() to uname(). Got rid of 3922347Spst the need for buf[]. Properly check return value of 4022347Spst opieatob8. Check seed length. Always generate proper- 4122347Spst length seeds. 4222347Spst Modified at NRL for OPIE 2.1. Minor autoconf changes. 4322347Spst Modified heavily at NRL for OPIE 2.0. 4422347Spst Written at Bellcore for the S/Key Version 1 software distribution 4522347Spst (skeyinit.c). 4679710Smarkm 4779710Smarkm $FreeBSD: head/contrib/opie/opiepasswd.c 92914 2002-03-21 23:42:52Z markm $ 4822347Spst*/ 4922347Spst#include "opie_cfg.h" 5022347Spst 5122347Spst#if HAVE_PWD_H 5222347Spst#include <pwd.h> 5322347Spst#endif /* HAVE_PWD_H */ 5422347Spst#include <stdio.h> 5522347Spst#if HAVE_STRING_H 5622347Spst#include <string.h> 5722347Spst#endif /* HAVE_STRING_H */ 5822347Spst#include <stdio.h> 5922347Spst#include <sys/types.h> 6022347Spst#if HAVE_UNISTD_H 6122347Spst#include <unistd.h> 6222347Spst#endif /* HAVE_UNISTD_H */ 6322347Spst#if HAVE_STDLIB_H 6422347Spst#include <stdlib.h> 6522347Spst#endif /* HAVE_STDLIB_H */ 6622347Spst 6722347Spst#include "opie.h" 6822347Spst 6922347Spst#define MODE_DEFAULT 0 7022347Spst#define MODE_CONSOLE 1 7122347Spst#define MODE_DISABLE 2 7222347Spst 7322347Spstextern int optind; 7422347Spstextern char *optarg; 7522347Spst 7622347Spstchar *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; 7722347Spstchar *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 7822347Spst 7922347Spststatic VOIDRET usage FUNCTION((myname), char *myname) 8022347Spst{ 8122347Spst fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname); 8222347Spst exit(1); 8322347Spst} 8422347Spst 8522347Spststatic VOIDRET finish FUNCTION((name), char *name) 8622347Spst{ 8722347Spst struct opie opie; 8822347Spst char buf[OPIE_RESPONSE_MAX + 1]; 8922347Spst 9022347Spst if (name) { 9122347Spst if (opiechallenge(&opie, name, buf)) { 9222347Spst fprintf(stderr, "Error verifying database.\n"); 9322347Spst finish(NULL); 9422347Spst } 9522347Spst printf("\nID %s ", opie.opie_principal); 9622347Spst if (opie.opie_val && (opie.opie_val[0] == '*')) { 9722347Spst printf("is disabled.\n"); 9822347Spst finish(NULL); 9922347Spst } 10022347Spst printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed); 10122347Spst { 10292914Smarkm struct opie_otpkey key; 10392914Smarkm 10492914Smarkm if (!opieatob8(&key, opie.opie_val)) { 10522347Spst fprintf(stderr, "Error verifying key -- possible database corruption.\n"); 10622347Spst finish(NULL); 10722347Spst } 10892914Smarkm printf("%s\n", opiebtoe(buf, &key)); 10922347Spst } 11022347Spst } 11122347Spst 11222347Spst while(!opieunlock()); 11322347Spst exit(name ? 0 : 1); 11422347Spst} 11522347Spst 11622347Spstint main FUNCTION((argc, argv), int argc AND char *argv[]) 11722347Spst{ 11822347Spst struct opie opie; 11922347Spst int rval, n = 499, i, mode = MODE_DEFAULT, force = 0; 12059118Skris char seed[OPIE_SEED_MAX+1]; 12122347Spst struct passwd *pp; 12222347Spst 12322347Spst memset(seed, 0, sizeof(seed)); 12422347Spst 12579710Smarkm if (!(pp = getpwnam(getlogin()))) { 12622347Spst fprintf(stderr, "Who are you?"); 12722347Spst return 1; 12822347Spst } 12922347Spst 13029964Sache while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) { 13122347Spst switch (i) { 13222347Spst case 'v': 13322347Spst opieversion(); 13422347Spst case 'f': 13522347Spst#if INSECURE_OVERRIDE 13659118Skris force = OPIEPASSWD_FORCE; 13722347Spst#else /* INSECURE_OVERRIDE */ 13822347Spst fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 13922347Spst#endif /* INSECURE_OVERRIDE */ 14022347Spst break; 14122347Spst case 'c': 14222347Spst mode = MODE_CONSOLE; 14322347Spst break; 14422347Spst case 'd': 14522347Spst mode = MODE_DISABLE; 14622347Spst break; 14722347Spst case 'n': 14822347Spst i = atoi(optarg); 14922347Spst if (!(i > 0 && i < 10000)) { 15022347Spst printf("Sequence numbers must be > 0 and < 10000\n"); 15122347Spst finish(NULL); 15222347Spst } 15322347Spst n = i; 15422347Spst break; 15522347Spst case 's': 15622347Spst i = strlen(optarg); 15722347Spst if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) { 15822347Spst printf("Seeds must be between %d and %d characters long.\n", 15922347Spst OPIE_SEED_MIN, OPIE_SEED_MAX); 16022347Spst finish(NULL); 16122347Spst } 16292914Smarkm opiestrncpy(seed, optarg, sizeof(seed)); 16322347Spst break; 16422347Spst default: 16522347Spst usage(argv[0]); 16622347Spst } 16722347Spst } 16822347Spst 16922347Spst if (argc - optind >= 1) { 17022347Spst if (strcmp(argv[optind], pp->pw_name)) { 17122347Spst if (getuid()) { 17222347Spst printf("Only root can change others' passwords.\n"); 17322347Spst exit(1); 17422347Spst } 17522347Spst if ((pp = getpwnam(argv[optind])) == NULL) { 17622347Spst printf("%s: user unknown.\n", argv[optind]); 17722347Spst exit(1); 17822347Spst } 17922347Spst } 18022347Spst } 18122347Spst 18222347Spst opielock(pp->pw_name); 18322347Spst rval = opielookup(&opie, pp->pw_name); 18422347Spst 18522347Spst switch (rval) { 18622347Spst case 0: 18722347Spst printf("Updating %s:\n", pp->pw_name); 18822347Spst break; 18922347Spst case 1: 19022347Spst printf("Adding %s:\n", pp->pw_name); 19122347Spst break; 19222347Spst case 2: 19322347Spst fprintf(stderr, "Error: Can't update key database.\n"); 19459118Skris finish(NULL); 19522347Spst default: 19622347Spst fprintf(stderr, "Error reading key database\n"); 19759118Skris finish(NULL); 19822347Spst } 19922347Spst 20022347Spst if (seed[0]) { 20122347Spst i = strlen(seed); 20222347Spst if (i > OPIE_SEED_MAX) { 20322347Spst fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX); 20422347Spst finish(NULL); 20522347Spst } 20622347Spst if (i < OPIE_SEED_MIN) { 20722347Spst fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN); 20822347Spst finish(NULL); 20922347Spst } 21022347Spst } else { 21122347Spst if (!rval) 21222347Spst strcpy(seed, opie.opie_seed); 21322347Spst 21422347Spst if (opienewseed(seed) < 0) { 21522347Spst fprintf(stderr, "Error updating seed.\n"); 21622347Spst finish(NULL); 21722347Spst } 21822347Spst } 21922347Spst 22022347Spst if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) { 22122347Spst fprintf(stderr, "You must use a different seed for the new OTP sequence.\n"); 22222347Spst finish(NULL); 22322347Spst } 22422347Spst 22522347Spst switch(mode) { 22622347Spst case MODE_DEFAULT: 22722347Spst { 22822347Spst char tmp[OPIE_RESPONSE_MAX + 2]; 22922347Spst 23022347Spst printf("You need the response from an OTP generator.\n"); 23122347Spst#if DEBUG 23222347Spst if (!rval) { 23322347Spst#else /* DEBUG */ 23422347Spst if (!rval && getuid()) { 23522347Spst#endif /* DEBUG */ 23622347Spst char oseed[OPIE_SEED_MAX + 1]; 23722347Spst int on; 23822347Spst 23922347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 24022347Spst fprintf(stderr, "Error issuing challenge.\n"); 24122347Spst finish(NULL); 24222347Spst } 24322347Spst on = opiegetsequence(&opie); 24422347Spst { 24522347Spst char *c; 24622347Spst if (c = strrchr(tmp, ' ')) 24792914Smarkm opiestrncpy(oseed, c + 1, sizeof(oseed)); 24822347Spst else { 24922347Spst#if DEBUG 25022347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 25122347Spst#endif /* DEBUG */ 25222347Spst finish(NULL); 25322347Spst } 25422347Spst } 25522347Spst printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp); 25622347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) 25722347Spst tmp[0] = 0; 25822347Spst i = opieverify(&opie, tmp); 25922347Spst if (!tmp[0]) { 26022347Spst fprintf(stderr, "Error reading response.\n"); 26122347Spst finish(NULL); 26222347Spst } 26322347Spst if (i) { 26422347Spst fprintf(stderr, "Error verifying response.\n"); 26522347Spst#if DEBUG 26622347Spst fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i); 26722347Spst#endif /* DEBUG */ 26822347Spst finish(NULL); 26922347Spst } 27022347Spst { 27122347Spst char nseed[OPIE_SEED_MAX + 1]; 27222347Spst int nn; 27322347Spst 27422347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 27522347Spst fprintf(stderr, "Error verifying database.\n"); 27622347Spst finish(NULL); 27722347Spst } 27822347Spst 27922347Spst nn = opiegetsequence(&opie); 28022347Spst { 28122347Spst char *c; 28222347Spst if (c = strrchr(tmp, ' ')) 28392914Smarkm opiestrncpy(nseed, c + 1, sizeof(nseed)); 28422347Spst else { 28522347Spst#if DEBUG 28622347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 28722347Spst#endif /* DEBUG */ 28822347Spst finish(NULL); 28922347Spst } 29022347Spst } 29122347Spst 29222347Spst opieverify(&opie, ""); 29322347Spst nn++; 29422347Spst 29522347Spst if ((nn != on) || strcmp(oseed, nseed)) 29622347Spst finish(pp->pw_name); 29722347Spst } 29822347Spst } 29922347Spst printf("New secret pass phrase:"); 30022347Spst for (i = 0;; i++) { 30122347Spst if (i > 2) 30222347Spst finish(NULL); 30322347Spst printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed); 30422347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 30522347Spst fprintf(stderr, "Error reading response.\n"); 30622347Spst finish(NULL); 30722347Spst } 30822347Spst if (tmp[0] == '?') { 30922347Spst printf("Enter the response from your OTP calculator: \n"); 31022347Spst continue; 31122347Spst } 31222347Spst if (tmp[0] == '\0') { 31322347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 31422347Spst finish(NULL); 31522347Spst } 31622347Spst 31759118Skris if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp))) 31822347Spst finish(pp->pw_name); 31922347Spst 32022347Spst if (rval < 0) { 32122347Spst fprintf(stderr, "Error updating key database.\n"); 32222347Spst finish(NULL); 32322347Spst } 32422347Spst printf("\tThat is not a valid OTP response.\n"); 32522347Spst } 32622347Spst } 32722347Spst break; 32822347Spst case MODE_CONSOLE: 32922347Spst { 33022347Spst char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1]; 33122347Spst /* Get user's secret password */ 33222347Spst fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n"); 33322347Spst fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n"); 33422347Spst fprintf(stderr, "Then run opiepasswd without the -c parameter.\n"); 33559118Skris if (opieinsecure() && !force) { 33622347Spst fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 33722347Spst if (force) 33822347Spst fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 33922347Spst else 34022347Spst finish(NULL); 34122347Spst }; 34222347Spst printf("Using %s to compute responses.\n", algnames[MDX]); 34322347Spst if (!rval && getuid()) { 34422347Spst printf("Enter old secret pass phrase: "); 34522347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 34622347Spst fprintf(stderr, "Error reading secret pass phrase!\n"); 34722347Spst finish(NULL); 34822347Spst } 34922347Spst if (!passwd[0]) { 35022347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 35122347Spst finish(NULL); 35222347Spst } 35322347Spst { 35492914Smarkm struct opie_otpkey key; 35522347Spst char tbuf[OPIE_RESPONSE_MAX + 1]; 35622347Spst 35792914Smarkm if (opiekeycrunch(MDX, &key, opie.opie_seed, passwd) != 0) { 35822347Spst fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]); 35922347Spst finish(NULL); 36022347Spst } 36122347Spst memset(passwd, 0, sizeof(passwd)); 36222347Spst i = opie.opie_n - 1; 36322347Spst while (i-- != 0) 36492914Smarkm opiehash(&key, MDX); 36592914Smarkm opiebtoe(tbuf, &key); 36622347Spst if (opieverify(&opie, tbuf)) { 36722347Spst fprintf(stderr, "Sorry.\n"); 36822347Spst finish(NULL); 36922347Spst } 37022347Spst } 37122347Spst } 37222347Spst for (i = 0;; i++) { 37322347Spst if (i > 2) 37422347Spst finish(NULL); 37522347Spst printf("Enter new secret pass phrase: "); 37622347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 37722347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 37822347Spst finish(NULL); 37922347Spst } 38022347Spst if (!passwd[0] || feof(stdin)) { 38122347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 38222347Spst finish(NULL); 38322347Spst } 38422347Spst if (opiepasscheck(passwd)) { 38522347Spst memset(passwd, 0, sizeof(passwd)); 38622347Spst fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 38722347Spst continue; 38822347Spst } 38922347Spst printf("Again new secret pass phrase: "); 39022347Spst if (!opiereadpass(passwd2, sizeof(passwd2), 0)) { 39122347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 39222347Spst finish(NULL); 39322347Spst } 39422347Spst if (feof(stdin)) { 39522347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 39622347Spst finish(NULL); 39722347Spst } 39822347Spst if (!passwd[0] || !strcmp(passwd, passwd2)) 39922347Spst break; 40022347Spst fprintf(stderr, "Sorry, no match.\n"); 40122347Spst } 40222347Spst memset(passwd2, 0, sizeof(passwd2)); 40359118Skris if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) { 40422347Spst fprintf(stderr, "Error updating key database.\n"); 40522347Spst finish(NULL); 40622347Spst } 40722347Spst finish(pp->pw_name); 40822347Spst } 40922347Spst case MODE_DISABLE: 41022347Spst { 41122347Spst char tmp[4]; 41222347Spst int i; 41322347Spst 41422347Spst for (i = 0;; i++) { 41522347Spst if (i > 2) 41622347Spst finish(NULL); 41722347Spst 41822347Spst printf("Disable %s's OTP access? (yes or no) ", pp->pw_name); 41922347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 42022347Spst fprintf(stderr, "Error reading entry.\n"); 42122347Spst finish(NULL); 42222347Spst } 42322347Spst if (!strcmp(tmp, "no")) 42422347Spst finish(NULL); 42522347Spst if (!strcmp(tmp, "yes")) { 42622347Spst if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) { 42722347Spst fprintf(stderr, "Error updating key database.\n"); 42822347Spst finish(NULL); 42922347Spst } 43022347Spst finish(pp->pw_name); 43122347Spst } 43222347Spst } 43322347Spst } 43422347Spst } 43522347Spst} 436