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.3 2006/03/22 21:22:39 drhodus 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];
126 memset(seed
, 0, sizeof(seed
));
129 username
= getlogin();
130 pp
= getpwnam(username
);
131 if (username
== NULL
|| pp
== NULL
|| pp
->pw_uid
!= ruid
)
134 fprintf(stderr
, "Who are you?");
138 while ((i
= getopt(argc
, argv
, "fhvcn:s:d")) != EOF
) {
143 #if INSECURE_OVERRIDE
144 force
= OPIEPASSWD_FORCE
;
145 #else /* INSECURE_OVERRIDE */
146 fprintf(stderr
, "Sorry, but the -f option is not supported by this build of OPIE.\n");
147 #endif /* INSECURE_OVERRIDE */
157 if (!(i
> 0 && i
< 10000)) {
158 printf("Sequence numbers must be > 0 and < 10000\n");
165 if ((i
> OPIE_SEED_MAX
) || (i
< OPIE_SEED_MIN
)) {
166 printf("Seeds must be between %d and %d characters long.\n",
167 OPIE_SEED_MIN
, OPIE_SEED_MAX
);
170 opiestrncpy(seed
, optarg
, sizeof(seed
));
177 if (argc
- optind
>= 1) {
178 if (strcmp(argv
[optind
], pp
->pw_name
)) {
180 printf("Only root can change others' passwords.\n");
183 if ((pp
= getpwnam(argv
[optind
])) == NULL
) {
184 printf("%s: user unknown.\n", argv
[optind
]);
190 opielock(pp
->pw_name
);
191 rval
= opielookup(&opie
, pp
->pw_name
);
195 printf("Updating %s:\n", pp
->pw_name
);
198 printf("Adding %s:\n", pp
->pw_name
);
201 fprintf(stderr
, "Error: Can't update key database.\n");
204 fprintf(stderr
, "Error reading key database\n");
210 if (i
> OPIE_SEED_MAX
) {
211 fprintf(stderr
, "Seeds must be less than %d characters long.", OPIE_SEED_MAX
);
214 if (i
< OPIE_SEED_MIN
) {
215 fprintf(stderr
, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN
);
220 strcpy(seed
, opie
.opie_seed
);
222 if (opienewseed(seed
) < 0) {
223 fprintf(stderr
, "Error updating seed.\n");
228 if (opie
.opie_seed
&& opie
.opie_seed
[0] && !strcmp(opie
.opie_seed
, seed
)) {
229 fprintf(stderr
, "You must use a different seed for the new OTP sequence.\n");
236 char tmp
[OPIE_RESPONSE_MAX
+ 2];
238 printf("You need the response from an OTP generator.\n");
242 if (!rval
&& getuid()) {
244 char oseed
[OPIE_SEED_MAX
+ 1];
247 if (opiechallenge(&opie
, pp
->pw_name
, tmp
)) {
248 fprintf(stderr
, "Error issuing challenge.\n");
251 on
= opiegetsequence(&opie
);
254 if (c
= strrchr(tmp
, ' '))
255 opiestrncpy(oseed
, c
+ 1, sizeof(oseed
));
258 fprintf(stderr
, "opiepasswd: bogus challenge\n");
263 printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp
);
264 if (!opiereadpass(tmp
, sizeof(tmp
), 1))
266 i
= opieverify(&opie
, tmp
);
268 fprintf(stderr
, "Error reading response.\n");
272 fprintf(stderr
, "Error verifying response.\n");
274 fprintf(stderr
, "opiepasswd: opieverify() returned %d\n", i
);
279 char nseed
[OPIE_SEED_MAX
+ 1];
282 if (opiechallenge(&opie
, pp
->pw_name
, tmp
)) {
283 fprintf(stderr
, "Error verifying database.\n");
287 nn
= opiegetsequence(&opie
);
290 if (c
= strrchr(tmp
, ' '))
291 opiestrncpy(nseed
, c
+ 1, sizeof(nseed
));
294 fprintf(stderr
, "opiepasswd: bogus challenge\n");
300 opieverify(&opie
, "");
303 if ((nn
!= on
) || strcmp(oseed
, nseed
))
307 printf("New secret pass phrase:");
311 printf("\n\totp-%s %d %s\n\tResponse: ", algids
[MDX
], n
, seed
);
312 if (!opiereadpass(tmp
, sizeof(tmp
), 1)) {
313 fprintf(stderr
, "Error reading response.\n");
317 printf("Enter the response from your OTP calculator: \n");
320 if (tmp
[0] == '\0') {
321 fprintf(stderr
, "Secret pass phrase unchanged.\n");
325 if (!(rval
= opiepasswd(&opie
, force
, pp
->pw_name
, n
, seed
, tmp
)))
329 fprintf(stderr
, "Error updating key database.\n");
332 printf("\tThat is not a valid OTP response.\n");
338 char passwd
[OPIE_SECRET_MAX
+ 1], passwd2
[OPIE_SECRET_MAX
+ 1];
339 /* Get user's secret password */
340 fprintf(stderr
, "Only use this method from the console; NEVER from remote. If you are using\n");
341 fprintf(stderr
, "telnet, xterm, or a dial-in, type ^C now or exit with no password.\n");
342 fprintf(stderr
, "Then run opiepasswd without the -c parameter.\n");
343 if (opieinsecure() && !force
) {
344 fprintf(stderr
, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
346 fprintf(stderr
, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
350 printf("Using %s to compute responses.\n", algnames
[MDX
]);
351 if (!rval
&& getuid()) {
352 printf("Enter old secret pass phrase: ");
353 if (!opiereadpass(passwd
, sizeof(passwd
), 0)) {
354 fprintf(stderr
, "Error reading secret pass phrase!\n");
358 fprintf(stderr
, "Secret pass phrase unchanged.\n");
362 struct opie_otpkey key
;
363 char tbuf
[OPIE_RESPONSE_MAX
+ 1];
365 if (opiekeycrunch(MDX
, &key
, opie
.opie_seed
, passwd
) != 0) {
366 fprintf(stderr
, "%s: key crunch failed. Secret pass phrase unchanged\n", argv
[0]);
369 memset(passwd
, 0, sizeof(passwd
));
373 opiebtoe(tbuf
, &key
);
374 if (opieverify(&opie
, tbuf
)) {
375 fprintf(stderr
, "Sorry.\n");
383 printf("Enter new secret pass phrase: ");
384 if (!opiereadpass(passwd
, sizeof(passwd
), 0)) {
385 fprintf(stderr
, "Error reading secret pass phrase.\n");
388 if (!passwd
[0] || feof(stdin
)) {
389 fprintf(stderr
, "Secret pass phrase unchanged.\n");
392 if (opiepasscheck(passwd
)) {
393 memset(passwd
, 0, sizeof(passwd
));
394 fprintf(stderr
, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN
, OPIE_SECRET_MAX
);
397 printf("Again new secret pass phrase: ");
398 if (!opiereadpass(passwd2
, sizeof(passwd2
), 0)) {
399 fprintf(stderr
, "Error reading secret pass phrase.\n");
403 fprintf(stderr
, "Secret pass phrase unchanged.\n");
406 if (!passwd
[0] || !strcmp(passwd
, passwd2
))
408 fprintf(stderr
, "Sorry, no match.\n");
410 memset(passwd2
, 0, sizeof(passwd2
));
411 if (opiepasswd(&opie
, 1 | force
, pp
->pw_name
, n
, seed
, passwd
)) {
412 fprintf(stderr
, "Error updating key database.\n");
426 printf("Disable %s's OTP access? (yes or no) ", pp
->pw_name
);
427 if (!opiereadpass(tmp
, sizeof(tmp
), 1)) {
428 fprintf(stderr
, "Error reading entry.\n");
431 if (!strcmp(tmp
, "no"))
433 if (!strcmp(tmp
, "yes")) {
434 if (opiepasswd(&opie
, 0, pp
->pw_name
, n
, seed
, NULL
)) {
435 fprintf(stderr
, "Error updating key database.\n");