opiepasswd.c revision 59118
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). 4422347Spst*/ 4522347Spst#include "opie_cfg.h" 4622347Spst 4722347Spst#if HAVE_PWD_H 4822347Spst#include <pwd.h> 4922347Spst#endif /* HAVE_PWD_H */ 5022347Spst#include <stdio.h> 5122347Spst#if HAVE_STRING_H 5222347Spst#include <string.h> 5322347Spst#endif /* HAVE_STRING_H */ 5422347Spst#include <stdio.h> 5522347Spst#include <sys/types.h> 5622347Spst#if HAVE_UNISTD_H 5722347Spst#include <unistd.h> 5822347Spst#endif /* HAVE_UNISTD_H */ 5922347Spst#if HAVE_STDLIB_H 6022347Spst#include <stdlib.h> 6122347Spst#endif /* HAVE_STDLIB_H */ 6222347Spst 6322347Spst#include "opie.h" 6422347Spst 6522347Spst#define MODE_DEFAULT 0 6622347Spst#define MODE_CONSOLE 1 6722347Spst#define MODE_DISABLE 2 6822347Spst 6922347Spstextern int optind; 7022347Spstextern char *optarg; 7122347Spst 7222347Spstchar *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" }; 7322347Spstchar *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 7422347Spst 7522347Spststatic VOIDRET usage FUNCTION((myname), char *myname) 7622347Spst{ 7722347Spst fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname); 7822347Spst exit(1); 7922347Spst} 8022347Spst 8122347Spststatic VOIDRET finish FUNCTION((name), char *name) 8222347Spst{ 8322347Spst struct opie opie; 8422347Spst char buf[OPIE_RESPONSE_MAX + 1]; 8522347Spst 8622347Spst if (name) { 8722347Spst if (opiechallenge(&opie, name, buf)) { 8822347Spst fprintf(stderr, "Error verifying database.\n"); 8922347Spst finish(NULL); 9022347Spst } 9122347Spst printf("\nID %s ", opie.opie_principal); 9222347Spst if (opie.opie_val && (opie.opie_val[0] == '*')) { 9322347Spst printf("is disabled.\n"); 9422347Spst finish(NULL); 9522347Spst } 9622347Spst printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed); 9722347Spst { 9822347Spst char key[8]; 9922347Spst if (!opieatob8(key, opie.opie_val)) { 10022347Spst fprintf(stderr, "Error verifying key -- possible database corruption.\n"); 10122347Spst finish(NULL); 10222347Spst } 10322347Spst printf("%s\n", opiebtoe(buf, key)); 10422347Spst } 10522347Spst } 10622347Spst 10722347Spst while(!opieunlock()); 10822347Spst exit(name ? 0 : 1); 10922347Spst} 11022347Spst 11122347Spstint main FUNCTION((argc, argv), int argc AND char *argv[]) 11222347Spst{ 11322347Spst struct opie opie; 11422347Spst int rval, n = 499, i, mode = MODE_DEFAULT, force = 0; 11559118Skris char seed[OPIE_SEED_MAX+1]; 11622347Spst struct passwd *pp; 11722347Spst 11822347Spst memset(seed, 0, sizeof(seed)); 11922347Spst 12022347Spst if (!(pp = getpwuid(getuid()))) { 12122347Spst fprintf(stderr, "Who are you?"); 12222347Spst return 1; 12322347Spst } 12422347Spst 12529964Sache while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) { 12622347Spst switch (i) { 12722347Spst case 'v': 12822347Spst opieversion(); 12922347Spst case 'f': 13022347Spst#if INSECURE_OVERRIDE 13159118Skris force = OPIEPASSWD_FORCE; 13222347Spst#else /* INSECURE_OVERRIDE */ 13322347Spst fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 13422347Spst#endif /* INSECURE_OVERRIDE */ 13522347Spst break; 13622347Spst case 'c': 13722347Spst mode = MODE_CONSOLE; 13822347Spst break; 13922347Spst case 'd': 14022347Spst mode = MODE_DISABLE; 14122347Spst break; 14222347Spst case 'n': 14322347Spst i = atoi(optarg); 14422347Spst if (!(i > 0 && i < 10000)) { 14522347Spst printf("Sequence numbers must be > 0 and < 10000\n"); 14622347Spst finish(NULL); 14722347Spst } 14822347Spst n = i; 14922347Spst break; 15022347Spst case 's': 15122347Spst i = strlen(optarg); 15222347Spst if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) { 15322347Spst printf("Seeds must be between %d and %d characters long.\n", 15422347Spst OPIE_SEED_MIN, OPIE_SEED_MAX); 15522347Spst finish(NULL); 15622347Spst } 15722347Spst strncpy(seed, optarg, sizeof(seed)); 15822347Spst seed[sizeof(seed) - 1] = 0; 15922347Spst break; 16022347Spst default: 16122347Spst usage(argv[0]); 16222347Spst } 16322347Spst } 16422347Spst 16522347Spst if (argc - optind >= 1) { 16622347Spst if (strcmp(argv[optind], pp->pw_name)) { 16722347Spst if (getuid()) { 16822347Spst printf("Only root can change others' passwords.\n"); 16922347Spst exit(1); 17022347Spst } 17122347Spst if ((pp = getpwnam(argv[optind])) == NULL) { 17222347Spst printf("%s: user unknown.\n", argv[optind]); 17322347Spst exit(1); 17422347Spst } 17522347Spst } 17622347Spst } 17722347Spst 17822347Spst opielock(pp->pw_name); 17922347Spst rval = opielookup(&opie, pp->pw_name); 18022347Spst 18122347Spst switch (rval) { 18222347Spst case 0: 18322347Spst printf("Updating %s:\n", pp->pw_name); 18422347Spst break; 18522347Spst case 1: 18622347Spst printf("Adding %s:\n", pp->pw_name); 18722347Spst break; 18822347Spst case 2: 18922347Spst fprintf(stderr, "Error: Can't update key database.\n"); 19059118Skris finish(NULL); 19122347Spst default: 19222347Spst fprintf(stderr, "Error reading key database\n"); 19359118Skris finish(NULL); 19422347Spst } 19522347Spst 19622347Spst if (seed[0]) { 19722347Spst i = strlen(seed); 19822347Spst if (i > OPIE_SEED_MAX) { 19922347Spst fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX); 20022347Spst finish(NULL); 20122347Spst } 20222347Spst if (i < OPIE_SEED_MIN) { 20322347Spst fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN); 20422347Spst finish(NULL); 20522347Spst } 20622347Spst } else { 20722347Spst if (!rval) 20822347Spst strcpy(seed, opie.opie_seed); 20922347Spst 21022347Spst if (opienewseed(seed) < 0) { 21122347Spst fprintf(stderr, "Error updating seed.\n"); 21222347Spst finish(NULL); 21322347Spst } 21422347Spst } 21522347Spst 21622347Spst if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) { 21722347Spst fprintf(stderr, "You must use a different seed for the new OTP sequence.\n"); 21822347Spst finish(NULL); 21922347Spst } 22022347Spst 22122347Spst switch(mode) { 22222347Spst case MODE_DEFAULT: 22322347Spst { 22422347Spst char tmp[OPIE_RESPONSE_MAX + 2]; 22522347Spst 22622347Spst printf("You need the response from an OTP generator.\n"); 22722347Spst#if DEBUG 22822347Spst if (!rval) { 22922347Spst#else /* DEBUG */ 23022347Spst if (!rval && getuid()) { 23122347Spst#endif /* DEBUG */ 23222347Spst char oseed[OPIE_SEED_MAX + 1]; 23322347Spst int on; 23422347Spst 23522347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 23622347Spst fprintf(stderr, "Error issuing challenge.\n"); 23722347Spst finish(NULL); 23822347Spst } 23922347Spst on = opiegetsequence(&opie); 24022347Spst { 24122347Spst char *c; 24222347Spst if (c = strrchr(tmp, ' ')) 24322347Spst strncpy(oseed, c + 1, sizeof(oseed)); 24422347Spst else { 24522347Spst#if DEBUG 24622347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 24722347Spst#endif /* DEBUG */ 24822347Spst finish(NULL); 24922347Spst } 25022347Spst } 25122347Spst printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp); 25222347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) 25322347Spst tmp[0] = 0; 25422347Spst i = opieverify(&opie, tmp); 25522347Spst if (!tmp[0]) { 25622347Spst fprintf(stderr, "Error reading response.\n"); 25722347Spst finish(NULL); 25822347Spst } 25922347Spst if (i) { 26022347Spst fprintf(stderr, "Error verifying response.\n"); 26122347Spst#if DEBUG 26222347Spst fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i); 26322347Spst#endif /* DEBUG */ 26422347Spst finish(NULL); 26522347Spst } 26622347Spst { 26722347Spst char nseed[OPIE_SEED_MAX + 1]; 26822347Spst int nn; 26922347Spst 27022347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 27122347Spst fprintf(stderr, "Error verifying database.\n"); 27222347Spst finish(NULL); 27322347Spst } 27422347Spst 27522347Spst nn = opiegetsequence(&opie); 27622347Spst { 27722347Spst char *c; 27822347Spst if (c = strrchr(tmp, ' ')) 27922347Spst strncpy(nseed, c + 1, sizeof(nseed)); 28022347Spst else { 28122347Spst#if DEBUG 28222347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 28322347Spst#endif /* DEBUG */ 28422347Spst finish(NULL); 28522347Spst } 28622347Spst } 28722347Spst 28822347Spst opieverify(&opie, ""); 28922347Spst nn++; 29022347Spst 29122347Spst if ((nn != on) || strcmp(oseed, nseed)) 29222347Spst finish(pp->pw_name); 29322347Spst } 29422347Spst } 29522347Spst printf("New secret pass phrase:"); 29622347Spst for (i = 0;; i++) { 29722347Spst if (i > 2) 29822347Spst finish(NULL); 29922347Spst printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed); 30022347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 30122347Spst fprintf(stderr, "Error reading response.\n"); 30222347Spst finish(NULL); 30322347Spst } 30422347Spst if (tmp[0] == '?') { 30522347Spst printf("Enter the response from your OTP calculator: \n"); 30622347Spst continue; 30722347Spst } 30822347Spst if (tmp[0] == '\0') { 30922347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 31022347Spst finish(NULL); 31122347Spst } 31222347Spst 31359118Skris if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp))) 31422347Spst finish(pp->pw_name); 31522347Spst 31622347Spst if (rval < 0) { 31722347Spst fprintf(stderr, "Error updating key database.\n"); 31822347Spst finish(NULL); 31922347Spst } 32022347Spst printf("\tThat is not a valid OTP response.\n"); 32122347Spst } 32222347Spst } 32322347Spst break; 32422347Spst case MODE_CONSOLE: 32522347Spst { 32622347Spst char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1]; 32722347Spst /* Get user's secret password */ 32822347Spst fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n"); 32922347Spst fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n"); 33022347Spst fprintf(stderr, "Then run opiepasswd without the -c parameter.\n"); 33159118Skris if (opieinsecure() && !force) { 33222347Spst fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 33322347Spst if (force) 33422347Spst fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 33522347Spst else 33622347Spst finish(NULL); 33722347Spst }; 33822347Spst printf("Using %s to compute responses.\n", algnames[MDX]); 33922347Spst if (!rval && getuid()) { 34022347Spst printf("Enter old secret pass phrase: "); 34122347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 34222347Spst fprintf(stderr, "Error reading secret pass phrase!\n"); 34322347Spst finish(NULL); 34422347Spst } 34522347Spst if (!passwd[0]) { 34622347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 34722347Spst finish(NULL); 34822347Spst } 34922347Spst { 35022347Spst char key[8]; 35122347Spst char tbuf[OPIE_RESPONSE_MAX + 1]; 35222347Spst 35322347Spst if (opiekeycrunch(MDX, key, opie.opie_seed, passwd) != 0) { 35422347Spst fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]); 35522347Spst finish(NULL); 35622347Spst } 35722347Spst memset(passwd, 0, sizeof(passwd)); 35822347Spst i = opie.opie_n - 1; 35922347Spst while (i-- != 0) 36022347Spst opiehash(key, MDX); 36122347Spst opiebtoe(tbuf, key); 36222347Spst if (opieverify(&opie, tbuf)) { 36322347Spst fprintf(stderr, "Sorry.\n"); 36422347Spst finish(NULL); 36522347Spst } 36622347Spst } 36722347Spst } 36822347Spst for (i = 0;; i++) { 36922347Spst if (i > 2) 37022347Spst finish(NULL); 37122347Spst printf("Enter new secret pass phrase: "); 37222347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 37322347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 37422347Spst finish(NULL); 37522347Spst } 37622347Spst if (!passwd[0] || feof(stdin)) { 37722347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 37822347Spst finish(NULL); 37922347Spst } 38022347Spst if (opiepasscheck(passwd)) { 38122347Spst memset(passwd, 0, sizeof(passwd)); 38222347Spst fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 38322347Spst continue; 38422347Spst } 38522347Spst printf("Again new secret pass phrase: "); 38622347Spst if (!opiereadpass(passwd2, sizeof(passwd2), 0)) { 38722347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 38822347Spst finish(NULL); 38922347Spst } 39022347Spst if (feof(stdin)) { 39122347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 39222347Spst finish(NULL); 39322347Spst } 39422347Spst if (!passwd[0] || !strcmp(passwd, passwd2)) 39522347Spst break; 39622347Spst fprintf(stderr, "Sorry, no match.\n"); 39722347Spst } 39822347Spst memset(passwd2, 0, sizeof(passwd2)); 39959118Skris if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) { 40022347Spst fprintf(stderr, "Error updating key database.\n"); 40122347Spst finish(NULL); 40222347Spst } 40322347Spst finish(pp->pw_name); 40422347Spst } 40522347Spst case MODE_DISABLE: 40622347Spst { 40722347Spst char tmp[4]; 40822347Spst int i; 40922347Spst 41022347Spst for (i = 0;; i++) { 41122347Spst if (i > 2) 41222347Spst finish(NULL); 41322347Spst 41422347Spst printf("Disable %s's OTP access? (yes or no) ", pp->pw_name); 41522347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 41622347Spst fprintf(stderr, "Error reading entry.\n"); 41722347Spst finish(NULL); 41822347Spst } 41922347Spst if (!strcmp(tmp, "no")) 42022347Spst finish(NULL); 42122347Spst if (!strcmp(tmp, "yes")) { 42222347Spst if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) { 42322347Spst fprintf(stderr, "Error updating key database.\n"); 42422347Spst finish(NULL); 42522347Spst } 42622347Spst finish(pp->pw_name); 42722347Spst } 42822347Spst } 42922347Spst } 43022347Spst } 43122347Spst} 432