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-1997 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.3. Got of some variables and made some
18 local to where they're used. Split out the finishing code. Use
19 opielookup() instead of opiechallenge() to find user. Three
20 strikes on prompts. Use opiepasswd()'s new calling
21 convention. Changed OPIE_PASS_{MAX,MIN} to
22 OPIE_SECRET_{MAX,MIN}. Handle automatic reinits happenning
23 below us. Got rid of unneeded headers. Use new opieatob8()
24 return value convention. Added -f flag. Added SHA support.
25 Modified by cmetz for OPIE 2.22. Finally got rid of the lock
26 filename kluge by implementing refcounts for locks.
27 Use opiepasswd() to update key file. Error if we can't
28 write to the key file. Check for minimum seed length.
29 Modified at NRL for OPIE 2.2. Changed opiestrip_crlf to
30 opiestripcrlf. Check opiereadpass() return value.
31 Minor optimization. Change calls to opiereadpass() to
32 use echo arg. Use opiereadpass() where we can.
33 Make everything static. Ifdef around some headers.
34 Changed use of gethostname() to uname(). Got rid of
35 the need for buf[]. Properly check return value of
36 opieatob8. Check seed length. Always generate proper-
38 Modified at NRL for OPIE 2.1. Minor autoconf changes.
39 Modified heavily at NRL for OPIE 2.0.
40 Written at Bellcore for the S/Key Version 1 software distribution
47 #endif /* HAVE_PWD_H */
51 #endif /* HAVE_STRING_H */
53 #include <sys/types.h>
56 #endif /* HAVE_UNISTD_H */
59 #endif /* HAVE_STDLIB_H */
63 #define MODE_DEFAULT 0
64 #define MODE_CONSOLE 1
65 #define MODE_DISABLE 2
70 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
71 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
73 static VOIDRET usage FUNCTION((myname), char *myname)
75 fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname);
79 static VOIDRET finish FUNCTION((name), char *name)
82 char buf[OPIE_RESPONSE_MAX + 1];
85 if (opiechallenge(&opie, name, buf)) {
86 fprintf(stderr, "Error verifying database.\n");
89 printf("\nID %s ", opie.opie_principal);
90 if (opie.opie_val && (opie.opie_val[0] == '*')) {
91 printf("is disabled.\n");
94 printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed);
97 if (!opieatob8(key, opie.opie_val)) {
98 fprintf(stderr, "Error verifying key -- possible database corruption.\n");
101 printf("%s\n", opiebtoe(buf, key));
105 while(!opieunlock());
109 int main FUNCTION((argc, argv), int argc AND char *argv[])
112 int rval, n = 499, i, mode = MODE_DEFAULT, force = 0;
116 memset(seed, 0, sizeof(seed));
118 if (!(pp = getpwuid(getuid()))) {
119 fprintf(stderr, "Who are you?");
123 while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) {
128 #if INSECURE_OVERRIDE
130 #else /* INSECURE_OVERRIDE */
131 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
132 #endif /* INSECURE_OVERRIDE */
142 if (!(i > 0 && i < 10000)) {
143 printf("Sequence numbers must be > 0 and < 10000\n");
150 if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) {
151 printf("Seeds must be between %d and %d characters long.\n",
152 OPIE_SEED_MIN, OPIE_SEED_MAX);
155 strncpy(seed, optarg, sizeof(seed));
156 seed[sizeof(seed) - 1] = 0;
163 if (argc - optind >= 1) {
164 if (strcmp(argv[optind], pp->pw_name)) {
166 printf("Only root can change others' passwords.\n");
169 if ((pp = getpwnam(argv[optind])) == NULL) {
170 printf("%s: user unknown.\n", argv[optind]);
176 opielock(pp->pw_name);
177 rval = opielookup(&opie, pp->pw_name);
181 printf("Updating %s:\n", pp->pw_name);
184 printf("Adding %s:\n", pp->pw_name);
187 fprintf(stderr, "Error: Can't update key database.\n");
190 fprintf(stderr, "Error reading key database\n");
196 if (i > OPIE_SEED_MAX) {
197 fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX);
200 if (i < OPIE_SEED_MIN) {
201 fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN);
206 strcpy(seed, opie.opie_seed);
208 if (opienewseed(seed) < 0) {
209 fprintf(stderr, "Error updating seed.\n");
214 if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) {
215 fprintf(stderr, "You must use a different seed for the new OTP sequence.\n");
222 char tmp[OPIE_RESPONSE_MAX + 2];
224 printf("You need the response from an OTP generator.\n");
228 if (!rval && getuid()) {
230 char oseed[OPIE_SEED_MAX + 1];
233 if (opiechallenge(&opie, pp->pw_name, tmp)) {
234 fprintf(stderr, "Error issuing challenge.\n");
237 on = opiegetsequence(&opie);
240 if (c = strrchr(tmp, ' '))
241 strncpy(oseed, c + 1, sizeof(oseed));
244 fprintf(stderr, "opiepasswd: bogus challenge\n");
249 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp);
250 if (!opiereadpass(tmp, sizeof(tmp), 1))
252 i = opieverify(&opie, tmp);
254 fprintf(stderr, "Error reading response.\n");
258 fprintf(stderr, "Error verifying response.\n");
260 fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i);
265 char nseed[OPIE_SEED_MAX + 1];
268 if (opiechallenge(&opie, pp->pw_name, tmp)) {
269 fprintf(stderr, "Error verifying database.\n");
273 nn = opiegetsequence(&opie);
276 if (c = strrchr(tmp, ' '))
277 strncpy(nseed, c + 1, sizeof(nseed));
280 fprintf(stderr, "opiepasswd: bogus challenge\n");
286 opieverify(&opie, "");
289 if ((nn != on) || strcmp(oseed, nseed))
293 printf("New secret pass phrase:");
297 printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed);
298 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
299 fprintf(stderr, "Error reading response.\n");
303 printf("Enter the response from your OTP calculator: \n");
306 if (tmp[0] == '\0') {
307 fprintf(stderr, "Secret pass phrase unchanged.\n");
311 if (!(rval = opiepasswd(&opie, 0, pp->pw_name, n, seed, tmp)))
315 fprintf(stderr, "Error updating key database.\n");
318 printf("\tThat is not a valid OTP response.\n");
324 char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1];
325 /* Get user's secret password */
326 fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n");
327 fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
328 fprintf(stderr, "Then run opiepasswd without the -c parameter.\n");
329 if (opieinsecure()) {
330 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
332 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
336 printf("Using %s to compute responses.\n", algnames[MDX]);
337 if (!rval && getuid()) {
338 printf("Enter old secret pass phrase: ");
339 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
340 fprintf(stderr, "Error reading secret pass phrase!\n");
344 fprintf(stderr, "Secret pass phrase unchanged.\n");
349 char tbuf[OPIE_RESPONSE_MAX + 1];
351 if (opiekeycrunch(MDX, key, opie.opie_seed, passwd) != 0) {
352 fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]);
355 memset(passwd, 0, sizeof(passwd));
360 if (opieverify(&opie, tbuf)) {
361 fprintf(stderr, "Sorry.\n");
369 printf("Enter new secret pass phrase: ");
370 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
371 fprintf(stderr, "Error reading secret pass phrase.\n");
374 if (!passwd[0] || feof(stdin)) {
375 fprintf(stderr, "Secret pass phrase unchanged.\n");
378 if (opiepasscheck(passwd)) {
379 memset(passwd, 0, sizeof(passwd));
380 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
383 printf("Again new secret pass phrase: ");
384 if (!opiereadpass(passwd2, sizeof(passwd2), 0)) {
385 fprintf(stderr, "Error reading secret pass phrase.\n");
389 fprintf(stderr, "Secret pass phrase unchanged.\n");
392 if (!passwd[0] || !strcmp(passwd, passwd2))
394 fprintf(stderr, "Sorry, no match.\n");
396 memset(passwd2, 0, sizeof(passwd2));
397 if (opiepasswd(&opie, 1, pp->pw_name, n, seed, passwd)) {
398 fprintf(stderr, "Error updating key database.\n");
412 printf("Disable %s's OTP access? (yes or no) ", pp->pw_name);
413 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
414 fprintf(stderr, "Error reading entry.\n");
417 if (!strcmp(tmp, "no"))
419 if (!strcmp(tmp, "yes")) {
420 if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) {
421 fprintf(stderr, "Error updating key database.\n");