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