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$ 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]; 121156997Scperciva char *username; 122156997Scperciva uid_t ruid; 12322347Spst struct passwd *pp; 12422347Spst 12522347Spst memset(seed, 0, sizeof(seed)); 12622347Spst 127156997Scperciva ruid = getuid(); 128156997Scperciva username = getlogin(); 129156997Scperciva pp = getpwnam(username); 130156997Scperciva if (username == NULL || pp == NULL || pp->pw_uid != ruid) 131156997Scperciva pp = getpwuid(ruid); 132156997Scperciva if (pp == NULL) { 13322347Spst fprintf(stderr, "Who are you?"); 13422347Spst return 1; 13522347Spst } 13622347Spst 13729964Sache while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) { 13822347Spst switch (i) { 13922347Spst case 'v': 14022347Spst opieversion(); 14122347Spst case 'f': 14222347Spst#if INSECURE_OVERRIDE 14359118Skris force = OPIEPASSWD_FORCE; 14422347Spst#else /* INSECURE_OVERRIDE */ 14522347Spst fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n"); 14622347Spst#endif /* INSECURE_OVERRIDE */ 14722347Spst break; 14822347Spst case 'c': 14922347Spst mode = MODE_CONSOLE; 15022347Spst break; 15122347Spst case 'd': 15222347Spst mode = MODE_DISABLE; 15322347Spst break; 15422347Spst case 'n': 15522347Spst i = atoi(optarg); 15622347Spst if (!(i > 0 && i < 10000)) { 15722347Spst printf("Sequence numbers must be > 0 and < 10000\n"); 15822347Spst finish(NULL); 15922347Spst } 16022347Spst n = i; 16122347Spst break; 16222347Spst case 's': 16322347Spst i = strlen(optarg); 16422347Spst if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) { 16522347Spst printf("Seeds must be between %d and %d characters long.\n", 16622347Spst OPIE_SEED_MIN, OPIE_SEED_MAX); 16722347Spst finish(NULL); 16822347Spst } 16992914Smarkm opiestrncpy(seed, optarg, sizeof(seed)); 17022347Spst break; 17122347Spst default: 17222347Spst usage(argv[0]); 17322347Spst } 17422347Spst } 17522347Spst 17622347Spst if (argc - optind >= 1) { 17722347Spst if (strcmp(argv[optind], pp->pw_name)) { 17822347Spst if (getuid()) { 17922347Spst printf("Only root can change others' passwords.\n"); 18022347Spst exit(1); 18122347Spst } 18222347Spst if ((pp = getpwnam(argv[optind])) == NULL) { 18322347Spst printf("%s: user unknown.\n", argv[optind]); 18422347Spst exit(1); 18522347Spst } 18622347Spst } 18722347Spst } 18822347Spst 18922347Spst opielock(pp->pw_name); 19022347Spst rval = opielookup(&opie, pp->pw_name); 19122347Spst 19222347Spst switch (rval) { 19322347Spst case 0: 19422347Spst printf("Updating %s:\n", pp->pw_name); 19522347Spst break; 19622347Spst case 1: 19722347Spst printf("Adding %s:\n", pp->pw_name); 19822347Spst break; 19922347Spst case 2: 20022347Spst fprintf(stderr, "Error: Can't update key database.\n"); 20159118Skris finish(NULL); 20222347Spst default: 20322347Spst fprintf(stderr, "Error reading key database\n"); 20459118Skris finish(NULL); 20522347Spst } 20622347Spst 20722347Spst if (seed[0]) { 20822347Spst i = strlen(seed); 20922347Spst if (i > OPIE_SEED_MAX) { 21022347Spst fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX); 21122347Spst finish(NULL); 21222347Spst } 21322347Spst if (i < OPIE_SEED_MIN) { 21422347Spst fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN); 21522347Spst finish(NULL); 21622347Spst } 21722347Spst } else { 21822347Spst if (!rval) 21922347Spst strcpy(seed, opie.opie_seed); 22022347Spst 22122347Spst if (opienewseed(seed) < 0) { 22222347Spst fprintf(stderr, "Error updating seed.\n"); 22322347Spst finish(NULL); 22422347Spst } 22522347Spst } 22622347Spst 22722347Spst if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) { 22822347Spst fprintf(stderr, "You must use a different seed for the new OTP sequence.\n"); 22922347Spst finish(NULL); 23022347Spst } 23122347Spst 23222347Spst switch(mode) { 23322347Spst case MODE_DEFAULT: 23422347Spst { 23522347Spst char tmp[OPIE_RESPONSE_MAX + 2]; 23622347Spst 23722347Spst printf("You need the response from an OTP generator.\n"); 23822347Spst#if DEBUG 23922347Spst if (!rval) { 24022347Spst#else /* DEBUG */ 24122347Spst if (!rval && getuid()) { 24222347Spst#endif /* DEBUG */ 24322347Spst char oseed[OPIE_SEED_MAX + 1]; 24422347Spst int on; 24522347Spst 24622347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 24722347Spst fprintf(stderr, "Error issuing challenge.\n"); 24822347Spst finish(NULL); 24922347Spst } 25022347Spst on = opiegetsequence(&opie); 25122347Spst { 25222347Spst char *c; 25322347Spst if (c = strrchr(tmp, ' ')) 25492914Smarkm opiestrncpy(oseed, c + 1, sizeof(oseed)); 25522347Spst else { 25622347Spst#if DEBUG 25722347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 25822347Spst#endif /* DEBUG */ 25922347Spst finish(NULL); 26022347Spst } 26122347Spst } 26222347Spst printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp); 26322347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) 26422347Spst tmp[0] = 0; 26522347Spst i = opieverify(&opie, tmp); 26622347Spst if (!tmp[0]) { 26722347Spst fprintf(stderr, "Error reading response.\n"); 26822347Spst finish(NULL); 26922347Spst } 27022347Spst if (i) { 27122347Spst fprintf(stderr, "Error verifying response.\n"); 27222347Spst#if DEBUG 27322347Spst fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i); 27422347Spst#endif /* DEBUG */ 27522347Spst finish(NULL); 27622347Spst } 27722347Spst { 27822347Spst char nseed[OPIE_SEED_MAX + 1]; 27922347Spst int nn; 28022347Spst 28122347Spst if (opiechallenge(&opie, pp->pw_name, tmp)) { 28222347Spst fprintf(stderr, "Error verifying database.\n"); 28322347Spst finish(NULL); 28422347Spst } 28522347Spst 28622347Spst nn = opiegetsequence(&opie); 28722347Spst { 28822347Spst char *c; 28922347Spst if (c = strrchr(tmp, ' ')) 29092914Smarkm opiestrncpy(nseed, c + 1, sizeof(nseed)); 29122347Spst else { 29222347Spst#if DEBUG 29322347Spst fprintf(stderr, "opiepasswd: bogus challenge\n"); 29422347Spst#endif /* DEBUG */ 29522347Spst finish(NULL); 29622347Spst } 29722347Spst } 29822347Spst 29922347Spst opieverify(&opie, ""); 30022347Spst nn++; 30122347Spst 30222347Spst if ((nn != on) || strcmp(oseed, nseed)) 30322347Spst finish(pp->pw_name); 30422347Spst } 30522347Spst } 30622347Spst printf("New secret pass phrase:"); 30722347Spst for (i = 0;; i++) { 30822347Spst if (i > 2) 30922347Spst finish(NULL); 31022347Spst printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed); 31122347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 31222347Spst fprintf(stderr, "Error reading response.\n"); 31322347Spst finish(NULL); 31422347Spst } 31522347Spst if (tmp[0] == '?') { 31622347Spst printf("Enter the response from your OTP calculator: \n"); 31722347Spst continue; 31822347Spst } 31922347Spst if (tmp[0] == '\0') { 32022347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 32122347Spst finish(NULL); 32222347Spst } 32322347Spst 32459118Skris if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp))) 32522347Spst finish(pp->pw_name); 32622347Spst 32722347Spst if (rval < 0) { 32822347Spst fprintf(stderr, "Error updating key database.\n"); 32922347Spst finish(NULL); 33022347Spst } 33122347Spst printf("\tThat is not a valid OTP response.\n"); 33222347Spst } 33322347Spst } 33422347Spst break; 33522347Spst case MODE_CONSOLE: 33622347Spst { 33722347Spst char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1]; 33822347Spst /* Get user's secret password */ 33922347Spst fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n"); 34022347Spst fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n"); 34122347Spst fprintf(stderr, "Then run opiepasswd without the -c parameter.\n"); 34259118Skris if (opieinsecure() && !force) { 34322347Spst fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n"); 34422347Spst if (force) 34522347Spst fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n"); 34622347Spst else 34722347Spst finish(NULL); 34822347Spst }; 34922347Spst printf("Using %s to compute responses.\n", algnames[MDX]); 35022347Spst if (!rval && getuid()) { 35122347Spst printf("Enter old secret pass phrase: "); 35222347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 35322347Spst fprintf(stderr, "Error reading secret pass phrase!\n"); 35422347Spst finish(NULL); 35522347Spst } 35622347Spst if (!passwd[0]) { 35722347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 35822347Spst finish(NULL); 35922347Spst } 36022347Spst { 36192914Smarkm struct opie_otpkey key; 36222347Spst char tbuf[OPIE_RESPONSE_MAX + 1]; 36322347Spst 36492914Smarkm if (opiekeycrunch(MDX, &key, opie.opie_seed, passwd) != 0) { 36522347Spst fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]); 36622347Spst finish(NULL); 36722347Spst } 36822347Spst memset(passwd, 0, sizeof(passwd)); 36922347Spst i = opie.opie_n - 1; 37022347Spst while (i-- != 0) 37192914Smarkm opiehash(&key, MDX); 37292914Smarkm opiebtoe(tbuf, &key); 37322347Spst if (opieverify(&opie, tbuf)) { 37422347Spst fprintf(stderr, "Sorry.\n"); 37522347Spst finish(NULL); 37622347Spst } 37722347Spst } 37822347Spst } 37922347Spst for (i = 0;; i++) { 38022347Spst if (i > 2) 38122347Spst finish(NULL); 38222347Spst printf("Enter new secret pass phrase: "); 38322347Spst if (!opiereadpass(passwd, sizeof(passwd), 0)) { 38422347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 38522347Spst finish(NULL); 38622347Spst } 38722347Spst if (!passwd[0] || feof(stdin)) { 38822347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 38922347Spst finish(NULL); 39022347Spst } 39122347Spst if (opiepasscheck(passwd)) { 39222347Spst memset(passwd, 0, sizeof(passwd)); 39322347Spst fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX); 39422347Spst continue; 39522347Spst } 39622347Spst printf("Again new secret pass phrase: "); 39722347Spst if (!opiereadpass(passwd2, sizeof(passwd2), 0)) { 39822347Spst fprintf(stderr, "Error reading secret pass phrase.\n"); 39922347Spst finish(NULL); 40022347Spst } 40122347Spst if (feof(stdin)) { 40222347Spst fprintf(stderr, "Secret pass phrase unchanged.\n"); 40322347Spst finish(NULL); 40422347Spst } 40522347Spst if (!passwd[0] || !strcmp(passwd, passwd2)) 40622347Spst break; 40722347Spst fprintf(stderr, "Sorry, no match.\n"); 40822347Spst } 40922347Spst memset(passwd2, 0, sizeof(passwd2)); 41059118Skris if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) { 41122347Spst fprintf(stderr, "Error updating key database.\n"); 41222347Spst finish(NULL); 41322347Spst } 41422347Spst finish(pp->pw_name); 41522347Spst } 41622347Spst case MODE_DISABLE: 41722347Spst { 41822347Spst char tmp[4]; 41922347Spst int i; 42022347Spst 42122347Spst for (i = 0;; i++) { 42222347Spst if (i > 2) 42322347Spst finish(NULL); 42422347Spst 42522347Spst printf("Disable %s's OTP access? (yes or no) ", pp->pw_name); 42622347Spst if (!opiereadpass(tmp, sizeof(tmp), 1)) { 42722347Spst fprintf(stderr, "Error reading entry.\n"); 42822347Spst finish(NULL); 42922347Spst } 43022347Spst if (!strcmp(tmp, "no")) 43122347Spst finish(NULL); 43222347Spst if (!strcmp(tmp, "yes")) { 43322347Spst if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) { 43422347Spst fprintf(stderr, "Error updating key database.\n"); 43522347Spst finish(NULL); 43622347Spst } 43722347Spst finish(pp->pw_name); 43822347Spst } 43922347Spst } 44022347Spst } 44122347Spst } 44222347Spst} 443