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: head/contrib/opie/opiepasswd.c 156997 2006-03-22 16:00:42Z cperciva $
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];
125 memset(seed
, 0, sizeof(seed
));
128 username
= getlogin();
129 pp
= getpwnam(username
);
130 if (username
== NULL
|| pp
== NULL
|| pp
->pw_uid
!= ruid
)
133 fprintf(stderr
, "Who are you?");
137 while ((i
= getopt(argc
, argv
, "fhvcn:s:d")) != EOF
) {
142 #if INSECURE_OVERRIDE
143 force
= OPIEPASSWD_FORCE
;
144 #else /* INSECURE_OVERRIDE */
145 fprintf(stderr
, "Sorry, but the -f option is not supported by this build of OPIE.\n");
146 #endif /* INSECURE_OVERRIDE */
156 if (!(i
> 0 && i
< 10000)) {
157 printf("Sequence numbers must be > 0 and < 10000\n");
164 if ((i
> OPIE_SEED_MAX
) || (i
< OPIE_SEED_MIN
)) {
165 printf("Seeds must be between %d and %d characters long.\n",
166 OPIE_SEED_MIN
, OPIE_SEED_MAX
);
169 opiestrncpy(seed
, optarg
, sizeof(seed
));
176 if (argc
- optind
>= 1) {
177 if (strcmp(argv
[optind
], pp
->pw_name
)) {
179 printf("Only root can change others' passwords.\n");
182 if ((pp
= getpwnam(argv
[optind
])) == NULL
) {
183 printf("%s: user unknown.\n", argv
[optind
]);
189 opielock(pp
->pw_name
);
190 rval
= opielookup(&opie
, pp
->pw_name
);
194 printf("Updating %s:\n", pp
->pw_name
);
197 printf("Adding %s:\n", pp
->pw_name
);
200 fprintf(stderr
, "Error: Can't update key database.\n");
203 fprintf(stderr
, "Error reading key database\n");
209 if (i
> OPIE_SEED_MAX
) {
210 fprintf(stderr
, "Seeds must be less than %d characters long.", OPIE_SEED_MAX
);
213 if (i
< OPIE_SEED_MIN
) {
214 fprintf(stderr
, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN
);
219 strcpy(seed
, opie
.opie_seed
);
221 if (opienewseed(seed
) < 0) {
222 fprintf(stderr
, "Error updating seed.\n");
227 if (opie
.opie_seed
&& opie
.opie_seed
[0] && !strcmp(opie
.opie_seed
, seed
)) {
228 fprintf(stderr
, "You must use a different seed for the new OTP sequence.\n");
235 char tmp
[OPIE_RESPONSE_MAX
+ 2];
237 printf("You need the response from an OTP generator.\n");
241 if (!rval
&& getuid()) {
243 char oseed
[OPIE_SEED_MAX
+ 1];
246 if (opiechallenge(&opie
, pp
->pw_name
, tmp
)) {
247 fprintf(stderr
, "Error issuing challenge.\n");
250 on
= opiegetsequence(&opie
);
253 if ((c
= strrchr(tmp
, ' ')) != NULL
)
254 opiestrncpy(oseed
, c
+ 1, sizeof(oseed
));
257 fprintf(stderr
, "opiepasswd: bogus challenge\n");
262 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp
);
263 if (!opiereadpass(tmp
, sizeof(tmp
), 1))
265 i
= opieverify(&opie
, tmp
);
267 fprintf(stderr
, "Error reading response.\n");
271 fprintf(stderr
, "Error verifying response.\n");
273 fprintf(stderr
, "opiepasswd: opieverify() returned %d\n", i
);
278 char nseed
[OPIE_SEED_MAX
+ 1];
281 if (opiechallenge(&opie
, pp
->pw_name
, tmp
)) {
282 fprintf(stderr
, "Error verifying database.\n");
286 nn
= opiegetsequence(&opie
);
289 if ((c
= strrchr(tmp
, ' ')) != NULL
)
290 opiestrncpy(nseed
, c
+ 1, sizeof(nseed
));
293 fprintf(stderr
, "opiepasswd: bogus challenge\n");
299 opieverify(&opie
, "");
302 if ((nn
!= on
) || strcmp(oseed
, nseed
))
306 printf("New secret pass phrase:");
310 printf("\n\totp-%s %d %s\n\tResponse: ", algids
[MDX
], n
, seed
);
311 if (!opiereadpass(tmp
, sizeof(tmp
), 1)) {
312 fprintf(stderr
, "Error reading response.\n");
316 printf("Enter the response from your OTP calculator: \n");
319 if (tmp
[0] == '\0') {
320 fprintf(stderr
, "Secret pass phrase unchanged.\n");
324 if (!(rval
= opiepasswd(&opie
, force
, pp
->pw_name
, n
, seed
, tmp
)))
328 fprintf(stderr
, "Error updating key database.\n");
331 printf("\tThat is not a valid OTP response.\n");
337 char passwd
[OPIE_SECRET_MAX
+ 1], passwd2
[OPIE_SECRET_MAX
+ 1];
338 /* Get user's secret password */
339 fprintf(stderr
, "Only use this method from the console; NEVER from remote. If you are using\n");
340 fprintf(stderr
, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
341 fprintf(stderr
, "Then run opiepasswd without the -c parameter.\n");
342 if (opieinsecure() && !force
) {
343 fprintf(stderr
, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
345 fprintf(stderr
, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
349 printf("Using %s to compute responses.\n", algnames
[MDX
]);
350 if (!rval
&& getuid()) {
351 printf("Enter old secret pass phrase: ");
352 if (!opiereadpass(passwd
, sizeof(passwd
), 0)) {
353 fprintf(stderr
, "Error reading secret pass phrase!\n");
357 fprintf(stderr
, "Secret pass phrase unchanged.\n");
361 struct opie_otpkey key
;
362 char tbuf
[OPIE_RESPONSE_MAX
+ 1];
364 if (opiekeycrunch(MDX
, &key
, opie
.opie_seed
, passwd
) != 0) {
365 fprintf(stderr
, "%s: key crunch failed. Secret pass phrase unchanged\n", argv
[0]);
368 memset(passwd
, 0, sizeof(passwd
));
372 opiebtoe(tbuf
, &key
);
373 if (opieverify(&opie
, tbuf
)) {
374 fprintf(stderr
, "Sorry.\n");
382 printf("Enter new secret pass phrase: ");
383 if (!opiereadpass(passwd
, sizeof(passwd
), 0)) {
384 fprintf(stderr
, "Error reading secret pass phrase.\n");
387 if (!passwd
[0] || feof(stdin
)) {
388 fprintf(stderr
, "Secret pass phrase unchanged.\n");
391 if (opiepasscheck(passwd
)) {
392 memset(passwd
, 0, sizeof(passwd
));
393 fprintf(stderr
, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN
, OPIE_SECRET_MAX
);
396 printf("Again new secret pass phrase: ");
397 if (!opiereadpass(passwd2
, sizeof(passwd2
), 0)) {
398 fprintf(stderr
, "Error reading secret pass phrase.\n");
402 fprintf(stderr
, "Secret pass phrase unchanged.\n");
405 if (!passwd
[0] || !strcmp(passwd
, passwd2
))
407 fprintf(stderr
, "Sorry, no match.\n");
409 memset(passwd2
, 0, sizeof(passwd2
));
410 if (opiepasswd(&opie
, 1 | force
, pp
->pw_name
, n
, seed
, passwd
)) {
411 fprintf(stderr
, "Error updating key database.\n");
425 printf("Disable %s's OTP access? (yes or no) ", pp
->pw_name
);
426 if (!opiereadpass(tmp
, sizeof(tmp
), 1)) {
427 fprintf(stderr
, "Error reading entry.\n");
430 if (!strcmp(tmp
, "no"))
432 if (!strcmp(tmp
, "yes")) {
433 if (opiepasswd(&opie
, 0, pp
->pw_name
, n
, seed
, NULL
)) {
434 fprintf(stderr
, "Error updating key database.\n");