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-1998 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.32. Use OPIE_SEED_MAX instead of
18 hard coding the length. Unlock user on failed lookup.
19 Modified by cmetz for OPIE 2.3. Got of some variables and made some
20 local to where they're used. Split out the finishing code. Use
21 opielookup() instead of opiechallenge() to find user. Three
22 strikes on prompts. Use opiepasswd()'s new calling
23 convention. Changed OPIE_PASS_{MAX,MIN} to
24 OPIE_SECRET_{MAX,MIN}. Handle automatic reinits happenning
25 below us. Got rid of unneeded headers. Use new opieatob8()
26 return value convention. Added -f flag. Added SHA support.
27 Modified by cmetz for OPIE 2.22. Finally got rid of the lock
28 filename kluge by implementing refcounts for locks.
29 Use opiepasswd() to update key file. Error if we can't
30 write to the key file. Check for minimum seed length.
31 Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to
32 opiestripcrlf. Check opiereadpass() return value.
33 Minor optimization. Change calls to opiereadpass() to
34 use echo arg. Use opiereadpass() where we can.
35 Make everything static. Ifdef around some headers.
36 Changed use of gethostname() to uname(). Got rid of
37 the need for buf[]. Properly check return value of
38 opieatob8. Check seed length. Always generate proper-
40 Modified at NRL for OPIE 2.1. Minor autoconf changes.
41 Modified heavily at NRL for OPIE 2.0.
42 Written at Bellcore for the S/Key Version 1 software distribution
51 #endif /* HAVE_PWD_H */
55 #endif /* HAVE_STRING_H */
57 #include <sys/types.h>
60 #endif /* HAVE_UNISTD_H */
63 #endif /* HAVE_STDLIB_H */
67 #define MODE_DEFAULT 0
68 #define MODE_CONSOLE 1
69 #define MODE_DISABLE 2
74 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
75 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
77 static VOIDRET usage FUNCTION((myname), char *myname)
79 fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname);
83 static VOIDRET finish FUNCTION((name), char *name)
86 char buf[OPIE_RESPONSE_MAX + 1];
89 if (opiechallenge(&opie, name, buf)) {
90 fprintf(stderr, "Error verifying database.\n");
93 printf("\nID %s ", opie.opie_principal);
94 if (opie.opie_val && (opie.opie_val[0] == '*')) {
95 printf("is disabled.\n");
98 printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed);
101 if (!opieatob8(key, opie.opie_val)) {
102 fprintf(stderr, "Error verifying key -- possible database corruption.\n");
105 printf("%s\n", opiebtoe(buf, key));
109 while(!opieunlock());
113 int main FUNCTION((argc, argv), int argc AND char *argv[])
116 int rval, n = 499, i, mode = MODE_DEFAULT, force = 0;
117 char seed[OPIE_SEED_MAX+1];
120 memset(seed, 0, sizeof(seed));
122 if (!(pp = getpwnam(getlogin()))) {
123 fprintf(stderr, "Who are you?");
127 while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) {
132 #if INSECURE_OVERRIDE
133 force = OPIEPASSWD_FORCE;
134 #else /* INSECURE_OVERRIDE */
135 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
136 #endif /* INSECURE_OVERRIDE */
146 if (!(i > 0 && i < 10000)) {
147 printf("Sequence numbers must be > 0 and < 10000\n");
154 if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) {
155 printf("Seeds must be between %d and %d characters long.\n",
156 OPIE_SEED_MIN, OPIE_SEED_MAX);
159 strncpy(seed, optarg, sizeof(seed));
160 seed[sizeof(seed) - 1] = 0;
167 if (argc - optind >= 1) {
168 if (strcmp(argv[optind], pp->pw_name)) {
170 printf("Only root can change others' passwords.\n");
173 if ((pp = getpwnam(argv[optind])) == NULL) {
174 printf("%s: user unknown.\n", argv[optind]);
180 opielock(pp->pw_name);
181 rval = opielookup(&opie, pp->pw_name);
185 printf("Updating %s:\n", pp->pw_name);
188 printf("Adding %s:\n", pp->pw_name);
191 fprintf(stderr, "Error: Can't update key database.\n");
194 fprintf(stderr, "Error reading key database\n");
200 if (i > OPIE_SEED_MAX) {
201 fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX);
204 if (i < OPIE_SEED_MIN) {
205 fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN);
210 strcpy(seed, opie.opie_seed);
212 if (opienewseed(seed) < 0) {
213 fprintf(stderr, "Error updating seed.\n");
218 if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) {
219 fprintf(stderr, "You must use a different seed for the new OTP sequence.\n");
226 char tmp[OPIE_RESPONSE_MAX + 2];
228 printf("You need the response from an OTP generator.\n");
232 if (!rval && getuid()) {
234 char oseed[OPIE_SEED_MAX + 1];
237 if (opiechallenge(&opie, pp->pw_name, tmp)) {
238 fprintf(stderr, "Error issuing challenge.\n");
241 on = opiegetsequence(&opie);
244 if (c = strrchr(tmp, ' '))
245 strncpy(oseed, c + 1, sizeof(oseed));
248 fprintf(stderr, "opiepasswd: bogus challenge\n");
253 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp);
254 if (!opiereadpass(tmp, sizeof(tmp), 1))
256 i = opieverify(&opie, tmp);
258 fprintf(stderr, "Error reading response.\n");
262 fprintf(stderr, "Error verifying response.\n");
264 fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i);
269 char nseed[OPIE_SEED_MAX + 1];
272 if (opiechallenge(&opie, pp->pw_name, tmp)) {
273 fprintf(stderr, "Error verifying database.\n");
277 nn = opiegetsequence(&opie);
280 if (c = strrchr(tmp, ' '))
281 strncpy(nseed, c + 1, sizeof(nseed));
284 fprintf(stderr, "opiepasswd: bogus challenge\n");
290 opieverify(&opie, "");
293 if ((nn != on) || strcmp(oseed, nseed))
297 printf("New secret pass phrase:");
301 printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed);
302 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
303 fprintf(stderr, "Error reading response.\n");
307 printf("Enter the response from your OTP calculator: \n");
310 if (tmp[0] == '\0') {
311 fprintf(stderr, "Secret pass phrase unchanged.\n");
315 if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp)))
319 fprintf(stderr, "Error updating key database.\n");
322 printf("\tThat is not a valid OTP response.\n");
328 char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1];
329 /* Get user's secret password */
330 fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n");
331 fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
332 fprintf(stderr, "Then run opiepasswd without the -c parameter.\n");
333 if (opieinsecure() && !force) {
334 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
336 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
340 printf("Using %s to compute responses.\n", algnames[MDX]);
341 if (!rval && getuid()) {
342 printf("Enter old secret pass phrase: ");
343 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
344 fprintf(stderr, "Error reading secret pass phrase!\n");
348 fprintf(stderr, "Secret pass phrase unchanged.\n");
353 char tbuf[OPIE_RESPONSE_MAX + 1];
355 if (opiekeycrunch(MDX, key, opie.opie_seed, passwd) != 0) {
356 fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]);
359 memset(passwd, 0, sizeof(passwd));
364 if (opieverify(&opie, tbuf)) {
365 fprintf(stderr, "Sorry.\n");
373 printf("Enter new secret pass phrase: ");
374 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
375 fprintf(stderr, "Error reading secret pass phrase.\n");
378 if (!passwd[0] || feof(stdin)) {
379 fprintf(stderr, "Secret pass phrase unchanged.\n");
382 if (opiepasscheck(passwd)) {
383 memset(passwd, 0, sizeof(passwd));
384 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
387 printf("Again new secret pass phrase: ");
388 if (!opiereadpass(passwd2, sizeof(passwd2), 0)) {
389 fprintf(stderr, "Error reading secret pass phrase.\n");
393 fprintf(stderr, "Secret pass phrase unchanged.\n");
396 if (!passwd[0] || !strcmp(passwd, passwd2))
398 fprintf(stderr, "Sorry, no match.\n");
400 memset(passwd2, 0, sizeof(passwd2));
401 if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) {
402 fprintf(stderr, "Error updating key database.\n");
416 printf("Disable %s's OTP access? (yes or no) ", pp->pw_name);
417 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
418 fprintf(stderr, "Error reading entry.\n");
421 if (!strcmp(tmp, "no"))
423 if (!strcmp(tmp, "yes")) {
424 if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) {
425 fprintf(stderr, "Error updating key database.\n");