1 /* opiepasswd.c: Add/change an OTP password in the key database.
3 %%% portions-copyright-cmetz-96
4 Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
5 Reserved. The Inner Net License Version 2 applies to these portions of
7 You should have received a copy of the license with this software. If
8 you didn't get a copy, you may request one from <license@inner.net>.
10 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
11 McDonald, All Rights Reserved. All Rights under this copyright are assigned
12 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
13 License Agreement applies to this software.
17 Modified by cmetz for OPIE 2.4. Use struct opie_key for key blocks.
19 Modified by cmetz for OPIE 2.32. Use OPIE_SEED_MAX instead of
20 hard coding the length. Unlock user on failed lookup.
21 Modified by cmetz for OPIE 2.3. Got of some variables and made some
22 local to where they're used. Split out the finishing code. Use
23 opielookup() instead of opiechallenge() to find user. Three
24 strikes on prompts. Use opiepasswd()'s new calling
25 convention. Changed OPIE_PASS_{MAX,MIN} to
26 OPIE_SECRET_{MAX,MIN}. Handle automatic reinits happenning
27 below us. Got rid of unneeded headers. Use new opieatob8()
28 return value convention. Added -f flag. Added SHA support.
29 Modified by cmetz for OPIE 2.22. Finally got rid of the lock
30 filename kluge by implementing refcounts for locks.
31 Use opiepasswd() to update key file. Error if we can't
32 write to the key file. Check for minimum seed length.
33 Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to
34 opiestripcrlf. Check opiereadpass() return value.
35 Minor optimization. Change calls to opiereadpass() to
36 use echo arg. Use opiereadpass() where we can.
37 Make everything static. Ifdef around some headers.
38 Changed use of gethostname() to uname(). Got rid of
39 the need for buf[]. Properly check return value of
40 opieatob8. Check seed length. Always generate proper-
42 Modified at NRL for OPIE 2.1. Minor autoconf changes.
43 Modified heavily at NRL for OPIE 2.0.
44 Written at Bellcore for the S/Key Version 1 software distribution
47 $FreeBSD: src/contrib/opie/opiepasswd.c,v 1.1.1.2.6.3 2002/07/15 14:48:43 des Exp $
53 #endif /* HAVE_PWD_H */
57 #endif /* HAVE_STRING_H */
59 #include <sys/types.h>
62 #endif /* HAVE_UNISTD_H */
65 #endif /* HAVE_STDLIB_H */
69 #define MODE_DEFAULT 0
70 #define MODE_CONSOLE 1
71 #define MODE_DISABLE 2
76 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
77 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
79 static VOIDRET usage FUNCTION((myname), char *myname)
81 fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname);
85 static VOIDRET finish FUNCTION((name), char *name)
88 char buf[OPIE_RESPONSE_MAX + 1];
91 if (opiechallenge(&opie, name, buf)) {
92 fprintf(stderr, "Error verifying database.\n");
95 printf("\nID %s ", opie.opie_principal);
96 if (opie.opie_val && (opie.opie_val[0] == '*')) {
97 printf("is disabled.\n");
100 printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed);
102 struct opie_otpkey key;
104 if (!opieatob8(&key, opie.opie_val)) {
105 fprintf(stderr, "Error verifying key -- possible database corruption.\n");
108 printf("%s\n", opiebtoe(buf, &key));
112 while(!opieunlock());
116 int main FUNCTION((argc, argv), int argc AND char *argv[])
119 int rval, n = 499, i, mode = MODE_DEFAULT, force = 0;
120 char seed[OPIE_SEED_MAX+1];
123 memset(seed, 0, sizeof(seed));
125 if (!(pp = getpwnam(getlogin()))) {
126 fprintf(stderr, "Who are you?");
130 while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) {
135 #if INSECURE_OVERRIDE
136 force = OPIEPASSWD_FORCE;
137 #else /* INSECURE_OVERRIDE */
138 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
139 #endif /* INSECURE_OVERRIDE */
149 if (!(i > 0 && i < 10000)) {
150 printf("Sequence numbers must be > 0 and < 10000\n");
157 if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) {
158 printf("Seeds must be between %d and %d characters long.\n",
159 OPIE_SEED_MIN, OPIE_SEED_MAX);
162 opiestrncpy(seed, optarg, sizeof(seed));
169 if (argc - optind >= 1) {
170 if (strcmp(argv[optind], pp->pw_name)) {
172 printf("Only root can change others' passwords.\n");
175 if ((pp = getpwnam(argv[optind])) == NULL) {
176 printf("%s: user unknown.\n", argv[optind]);
182 opielock(pp->pw_name);
183 rval = opielookup(&opie, pp->pw_name);
187 printf("Updating %s:\n", pp->pw_name);
190 printf("Adding %s:\n", pp->pw_name);
193 fprintf(stderr, "Error: Can't update key database.\n");
196 fprintf(stderr, "Error reading key database\n");
202 if (i > OPIE_SEED_MAX) {
203 fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX);
206 if (i < OPIE_SEED_MIN) {
207 fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN);
212 strcpy(seed, opie.opie_seed);
214 if (opienewseed(seed) < 0) {
215 fprintf(stderr, "Error updating seed.\n");
220 if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) {
221 fprintf(stderr, "You must use a different seed for the new OTP sequence.\n");
228 char tmp[OPIE_RESPONSE_MAX + 2];
230 printf("You need the response from an OTP generator.\n");
234 if (!rval && getuid()) {
236 char oseed[OPIE_SEED_MAX + 1];
239 if (opiechallenge(&opie, pp->pw_name, tmp)) {
240 fprintf(stderr, "Error issuing challenge.\n");
243 on = opiegetsequence(&opie);
246 if (c = strrchr(tmp, ' '))
247 opiestrncpy(oseed, c + 1, sizeof(oseed));
250 fprintf(stderr, "opiepasswd: bogus challenge\n");
255 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp);
256 if (!opiereadpass(tmp, sizeof(tmp), 1))
258 i = opieverify(&opie, tmp);
260 fprintf(stderr, "Error reading response.\n");
264 fprintf(stderr, "Error verifying response.\n");
266 fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i);
271 char nseed[OPIE_SEED_MAX + 1];
274 if (opiechallenge(&opie, pp->pw_name, tmp)) {
275 fprintf(stderr, "Error verifying database.\n");
279 nn = opiegetsequence(&opie);
282 if (c = strrchr(tmp, ' '))
283 opiestrncpy(nseed, c + 1, sizeof(nseed));
286 fprintf(stderr, "opiepasswd: bogus challenge\n");
292 opieverify(&opie, "");
295 if ((nn != on) || strcmp(oseed, nseed))
299 printf("New secret pass phrase:");
303 printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed);
304 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
305 fprintf(stderr, "Error reading response.\n");
309 printf("Enter the response from your OTP calculator: \n");
312 if (tmp[0] == '\0') {
313 fprintf(stderr, "Secret pass phrase unchanged.\n");
317 if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp)))
321 fprintf(stderr, "Error updating key database.\n");
324 printf("\tThat is not a valid OTP response.\n");
330 char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1];
331 /* Get user's secret password */
332 fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n");
333 fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
334 fprintf(stderr, "Then run opiepasswd without the -c parameter.\n");
335 if (opieinsecure() && !force) {
336 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
338 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
342 printf("Using %s to compute responses.\n", algnames[MDX]);
343 if (!rval && getuid()) {
344 printf("Enter old secret pass phrase: ");
345 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
346 fprintf(stderr, "Error reading secret pass phrase!\n");
350 fprintf(stderr, "Secret pass phrase unchanged.\n");
354 struct opie_otpkey key;
355 char tbuf[OPIE_RESPONSE_MAX + 1];
357 if (opiekeycrunch(MDX, &key, opie.opie_seed, passwd) != 0) {
358 fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]);
361 memset(passwd, 0, sizeof(passwd));
365 opiebtoe(tbuf, &key);
366 if (opieverify(&opie, tbuf)) {
367 fprintf(stderr, "Sorry.\n");
375 printf("Enter new secret pass phrase: ");
376 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
377 fprintf(stderr, "Error reading secret pass phrase.\n");
380 if (!passwd[0] || feof(stdin)) {
381 fprintf(stderr, "Secret pass phrase unchanged.\n");
384 if (opiepasscheck(passwd)) {
385 memset(passwd, 0, sizeof(passwd));
386 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
389 printf("Again new secret pass phrase: ");
390 if (!opiereadpass(passwd2, sizeof(passwd2), 0)) {
391 fprintf(stderr, "Error reading secret pass phrase.\n");
395 fprintf(stderr, "Secret pass phrase unchanged.\n");
398 if (!passwd[0] || !strcmp(passwd, passwd2))
400 fprintf(stderr, "Sorry, no match.\n");
402 memset(passwd2, 0, sizeof(passwd2));
403 if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) {
404 fprintf(stderr, "Error updating key database.\n");
418 printf("Disable %s's OTP access? (yes or no) ", pp->pw_name);
419 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
420 fprintf(stderr, "Error reading entry.\n");
423 if (!strcmp(tmp, "no"))
425 if (!strcmp(tmp, "yes")) {
426 if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) {
427 fprintf(stderr, "Error updating key database.\n");