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 $
48 $DragonFly: src/contrib/opie/opiepasswd.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
54 #endif /* HAVE_PWD_H */
58 #endif /* HAVE_STRING_H */
60 #include <sys/types.h>
63 #endif /* HAVE_UNISTD_H */
66 #endif /* HAVE_STDLIB_H */
70 #define MODE_DEFAULT 0
71 #define MODE_CONSOLE 1
72 #define MODE_DISABLE 2
77 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
78 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
80 static VOIDRET usage FUNCTION((myname), char *myname)
82 fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n [-s seed] [username]\n", myname);
86 static VOIDRET finish FUNCTION((name), char *name)
89 char buf[OPIE_RESPONSE_MAX + 1];
92 if (opiechallenge(&opie, name, buf)) {
93 fprintf(stderr, "Error verifying database.\n");
96 printf("\nID %s ", opie.opie_principal);
97 if (opie.opie_val && (opie.opie_val[0] == '*')) {
98 printf("is disabled.\n");
101 printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed);
103 struct opie_otpkey key;
105 if (!opieatob8(&key, opie.opie_val)) {
106 fprintf(stderr, "Error verifying key -- possible database corruption.\n");
109 printf("%s\n", opiebtoe(buf, &key));
113 while(!opieunlock());
117 int main FUNCTION((argc, argv), int argc AND char *argv[])
120 int rval, n = 499, i, mode = MODE_DEFAULT, force = 0;
121 char seed[OPIE_SEED_MAX+1];
124 memset(seed, 0, sizeof(seed));
126 if (!(pp = getpwnam(getlogin()))) {
127 fprintf(stderr, "Who are you?");
131 while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) {
136 #if INSECURE_OVERRIDE
137 force = OPIEPASSWD_FORCE;
138 #else /* INSECURE_OVERRIDE */
139 fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
140 #endif /* INSECURE_OVERRIDE */
150 if (!(i > 0 && i < 10000)) {
151 printf("Sequence numbers must be > 0 and < 10000\n");
158 if ((i > OPIE_SEED_MAX) || (i < OPIE_SEED_MIN)) {
159 printf("Seeds must be between %d and %d characters long.\n",
160 OPIE_SEED_MIN, OPIE_SEED_MAX);
163 opiestrncpy(seed, optarg, sizeof(seed));
170 if (argc - optind >= 1) {
171 if (strcmp(argv[optind], pp->pw_name)) {
173 printf("Only root can change others' passwords.\n");
176 if ((pp = getpwnam(argv[optind])) == NULL) {
177 printf("%s: user unknown.\n", argv[optind]);
183 opielock(pp->pw_name);
184 rval = opielookup(&opie, pp->pw_name);
188 printf("Updating %s:\n", pp->pw_name);
191 printf("Adding %s:\n", pp->pw_name);
194 fprintf(stderr, "Error: Can't update key database.\n");
197 fprintf(stderr, "Error reading key database\n");
203 if (i > OPIE_SEED_MAX) {
204 fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX);
207 if (i < OPIE_SEED_MIN) {
208 fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN);
213 strcpy(seed, opie.opie_seed);
215 if (opienewseed(seed) < 0) {
216 fprintf(stderr, "Error updating seed.\n");
221 if (opie.opie_seed && opie.opie_seed[0] && !strcmp(opie.opie_seed, seed)) {
222 fprintf(stderr, "You must use a different seed for the new OTP sequence.\n");
229 char tmp[OPIE_RESPONSE_MAX + 2];
231 printf("You need the response from an OTP generator.\n");
235 if (!rval && getuid()) {
237 char oseed[OPIE_SEED_MAX + 1];
240 if (opiechallenge(&opie, pp->pw_name, tmp)) {
241 fprintf(stderr, "Error issuing challenge.\n");
244 on = opiegetsequence(&opie);
247 if (c = strrchr(tmp, ' '))
248 opiestrncpy(oseed, c + 1, sizeof(oseed));
251 fprintf(stderr, "opiepasswd: bogus challenge\n");
256 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp);
257 if (!opiereadpass(tmp, sizeof(tmp), 1))
259 i = opieverify(&opie, tmp);
261 fprintf(stderr, "Error reading response.\n");
265 fprintf(stderr, "Error verifying response.\n");
267 fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i);
272 char nseed[OPIE_SEED_MAX + 1];
275 if (opiechallenge(&opie, pp->pw_name, tmp)) {
276 fprintf(stderr, "Error verifying database.\n");
280 nn = opiegetsequence(&opie);
283 if (c = strrchr(tmp, ' '))
284 opiestrncpy(nseed, c + 1, sizeof(nseed));
287 fprintf(stderr, "opiepasswd: bogus challenge\n");
293 opieverify(&opie, "");
296 if ((nn != on) || strcmp(oseed, nseed))
300 printf("New secret pass phrase:");
304 printf("\n\totp-%s %d %s\n\tResponse: ", algids[MDX], n, seed);
305 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
306 fprintf(stderr, "Error reading response.\n");
310 printf("Enter the response from your OTP calculator: \n");
313 if (tmp[0] == '\0') {
314 fprintf(stderr, "Secret pass phrase unchanged.\n");
318 if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp)))
322 fprintf(stderr, "Error updating key database.\n");
325 printf("\tThat is not a valid OTP response.\n");
331 char passwd[OPIE_SECRET_MAX + 1], passwd2[OPIE_SECRET_MAX + 1];
332 /* Get user's secret password */
333 fprintf(stderr, "Only use this method from the console; NEVER from remote. If you are using\n");
334 fprintf(stderr, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
335 fprintf(stderr, "Then run opiepasswd without the -c parameter.\n");
336 if (opieinsecure() && !force) {
337 fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
339 fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
343 printf("Using %s to compute responses.\n", algnames[MDX]);
344 if (!rval && getuid()) {
345 printf("Enter old secret pass phrase: ");
346 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
347 fprintf(stderr, "Error reading secret pass phrase!\n");
351 fprintf(stderr, "Secret pass phrase unchanged.\n");
355 struct opie_otpkey key;
356 char tbuf[OPIE_RESPONSE_MAX + 1];
358 if (opiekeycrunch(MDX, &key, opie.opie_seed, passwd) != 0) {
359 fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]);
362 memset(passwd, 0, sizeof(passwd));
366 opiebtoe(tbuf, &key);
367 if (opieverify(&opie, tbuf)) {
368 fprintf(stderr, "Sorry.\n");
376 printf("Enter new secret pass phrase: ");
377 if (!opiereadpass(passwd, sizeof(passwd), 0)) {
378 fprintf(stderr, "Error reading secret pass phrase.\n");
381 if (!passwd[0] || feof(stdin)) {
382 fprintf(stderr, "Secret pass phrase unchanged.\n");
385 if (opiepasscheck(passwd)) {
386 memset(passwd, 0, sizeof(passwd));
387 fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
390 printf("Again new secret pass phrase: ");
391 if (!opiereadpass(passwd2, sizeof(passwd2), 0)) {
392 fprintf(stderr, "Error reading secret pass phrase.\n");
396 fprintf(stderr, "Secret pass phrase unchanged.\n");
399 if (!passwd[0] || !strcmp(passwd, passwd2))
401 fprintf(stderr, "Sorry, no match.\n");
403 memset(passwd2, 0, sizeof(passwd2));
404 if (opiepasswd(&opie, 1 | force, pp->pw_name, n, seed, passwd)) {
405 fprintf(stderr, "Error updating key database.\n");
419 printf("Disable %s's OTP access? (yes or no) ", pp->pw_name);
420 if (!opiereadpass(tmp, sizeof(tmp), 1)) {
421 fprintf(stderr, "Error reading entry.\n");
424 if (!strcmp(tmp, "no"))
426 if (!strcmp(tmp, "yes")) {
427 if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) {
428 fprintf(stderr, "Error updating key database.\n");