]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/opie/opiepasswd.c
This commit was generated by cvs2svn to compensate for changes in r92444,
[FreeBSD/FreeBSD.git] / contrib / opie / opiepasswd.c
1 /* opiepasswd.c: Add/change an OTP password in the key database.
2
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
6 the software.
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>.
9
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.
14
15         History:
16
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-
39                 length seeds.
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
43                 (skeyinit.c).
44
45  $FreeBSD$
46 */
47 #include "opie_cfg.h"
48
49 #if HAVE_PWD_H
50 #include <pwd.h>
51 #endif /* HAVE_PWD_H */
52 #include <stdio.h>
53 #if HAVE_STRING_H
54 #include <string.h>
55 #endif /* HAVE_STRING_H */
56 #include <stdio.h>
57 #include <sys/types.h>
58 #if HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif /* HAVE_UNISTD_H */
61 #if HAVE_STDLIB_H
62 #include <stdlib.h>
63 #endif /* HAVE_STDLIB_H */
64
65 #include "opie.h"
66
67 #define MODE_DEFAULT 0
68 #define MODE_CONSOLE 1
69 #define MODE_DISABLE 2
70
71 extern int optind;
72 extern char *optarg;
73
74 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
75 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
76
77 static VOIDRET usage FUNCTION((myname), char *myname)
78 {
79   fprintf(stderr, "usage: %s [-v] [-h] [-c|-d] [-f] [-n initial_sequence_number]\n                            [-s seed] [username]\n", myname);
80   exit(1);
81 }
82
83 static VOIDRET finish FUNCTION((name), char *name)
84 {
85   struct opie opie;
86   char buf[OPIE_RESPONSE_MAX + 1];
87
88   if (name) {
89     if (opiechallenge(&opie, name, buf)) {
90       fprintf(stderr, "Error verifying database.\n");
91       finish(NULL);
92     }
93     printf("\nID %s ", opie.opie_principal);
94     if (opie.opie_val && (opie.opie_val[0] == '*')) {
95       printf("is disabled.\n");
96       finish(NULL);
97     }
98     printf("OTP key is %d %s\n", opie.opie_n, opie.opie_seed);
99     {
100       char key[8];
101       if (!opieatob8(key, opie.opie_val)) {
102         fprintf(stderr, "Error verifying key -- possible database corruption.\n");
103         finish(NULL);
104       }
105       printf("%s\n", opiebtoe(buf, key));
106     }
107   }
108
109   while(!opieunlock());
110   exit(name ? 0 : 1);
111 }
112
113 int main FUNCTION((argc, argv), int argc AND char *argv[])
114 {
115   struct opie opie;
116   int rval, n = 499, i, mode = MODE_DEFAULT, force = 0;
117   char seed[OPIE_SEED_MAX+1];
118   struct passwd *pp;
119
120   memset(seed, 0, sizeof(seed));
121
122   if (!(pp = getpwnam(getlogin()))) {
123     fprintf(stderr, "Who are you?");
124     return 1;
125   }
126
127   while ((i = getopt(argc, argv, "fhvcn:s:d")) != EOF) {
128     switch (i) {
129     case 'v':
130       opieversion();
131     case 'f':
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 */
137       break;
138     case 'c':
139       mode = MODE_CONSOLE;
140       break;
141     case 'd':
142       mode = MODE_DISABLE;
143       break;
144     case 'n':
145       i = atoi(optarg);
146       if (!(i > 0 && i < 10000)) {
147         printf("Sequence numbers must be > 0 and < 10000\n");
148         finish(NULL);
149       }
150       n = i;
151       break;
152     case 's':
153       i = strlen(optarg);
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);
157         finish(NULL);
158       }
159       strncpy(seed, optarg, sizeof(seed));
160       seed[sizeof(seed) - 1] = 0;
161       break;
162     default:
163       usage(argv[0]);
164     }
165   }
166
167   if (argc - optind >= 1) {
168     if (strcmp(argv[optind], pp->pw_name)) {
169       if (getuid()) {
170         printf("Only root can change others' passwords.\n");
171         exit(1);
172       }
173       if ((pp = getpwnam(argv[optind])) == NULL) {
174         printf("%s: user unknown.\n", argv[optind]);
175         exit(1);
176       }
177     }
178   }
179
180   opielock(pp->pw_name);
181   rval = opielookup(&opie, pp->pw_name);
182
183   switch (rval) {
184   case 0:
185     printf("Updating %s:\n", pp->pw_name);
186     break;
187   case 1:
188     printf("Adding %s:\n", pp->pw_name);
189     break;
190   case 2:
191     fprintf(stderr, "Error: Can't update key database.\n");
192     finish(NULL);
193   default:
194     fprintf(stderr, "Error reading key database\n");
195     finish(NULL);
196   }
197
198   if (seed[0]) {
199     i = strlen(seed);
200     if (i > OPIE_SEED_MAX) {
201       fprintf(stderr, "Seeds must be less than %d characters long.", OPIE_SEED_MAX);
202       finish(NULL);
203     }
204     if (i < OPIE_SEED_MIN) {
205       fprintf(stderr, "Seeds must be greater than %d characters long.", OPIE_SEED_MIN);
206       finish(NULL);
207     }
208   } else {
209     if (!rval)
210       strcpy(seed, opie.opie_seed);
211
212     if (opienewseed(seed) < 0) {
213       fprintf(stderr, "Error updating seed.\n");
214       finish(NULL);
215     }
216   }
217
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");
220     finish(NULL);
221   }
222   
223   switch(mode) {
224   case MODE_DEFAULT:
225     {
226       char tmp[OPIE_RESPONSE_MAX + 2];
227       
228       printf("You need the response from an OTP generator.\n");
229 #if DEBUG
230       if (!rval) {
231 #else /* DEBUG */
232       if (!rval && getuid()) {
233 #endif /* DEBUG */
234         char oseed[OPIE_SEED_MAX + 1];
235         int on;
236
237         if (opiechallenge(&opie, pp->pw_name, tmp)) {
238           fprintf(stderr, "Error issuing challenge.\n");
239           finish(NULL);
240         }
241         on = opiegetsequence(&opie);
242         {
243           char *c;
244           if (c = strrchr(tmp, ' '))
245             strncpy(oseed, c + 1, sizeof(oseed));
246           else {
247 #if DEBUG
248             fprintf(stderr, "opiepasswd: bogus challenge\n");
249 #endif /* DEBUG */
250             finish(NULL);
251           }
252         }
253         printf("Old secret pass phrase:\n\t%s\n\tResponse: ", tmp);
254         if (!opiereadpass(tmp, sizeof(tmp), 1))
255           tmp[0] = 0;
256         i = opieverify(&opie, tmp);
257         if (!tmp[0]) {
258           fprintf(stderr, "Error reading response.\n");
259           finish(NULL);
260         }
261         if (i) {
262           fprintf(stderr, "Error verifying response.\n");
263 #if DEBUG
264           fprintf(stderr, "opiepasswd: opieverify() returned %d\n", i);
265 #endif /* DEBUG */
266           finish(NULL);
267         }
268         {
269           char nseed[OPIE_SEED_MAX + 1];
270           int nn;
271
272           if (opiechallenge(&opie, pp->pw_name, tmp)) {
273             fprintf(stderr, "Error verifying database.\n");
274             finish(NULL);
275           }
276
277           nn = opiegetsequence(&opie);
278           {
279             char *c;
280             if (c = strrchr(tmp, ' '))
281               strncpy(nseed, c + 1, sizeof(nseed));
282             else {
283 #if DEBUG
284               fprintf(stderr, "opiepasswd: bogus challenge\n");
285 #endif /* DEBUG */
286               finish(NULL);
287             }
288           }
289
290           opieverify(&opie, "");
291           nn++;
292
293           if ((nn != on) || strcmp(oseed, nseed))
294             finish(pp->pw_name);
295         }
296       }
297       printf("New secret pass phrase:");
298       for (i = 0;; i++) {
299         if (i > 2)
300           finish(NULL);
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");
304           finish(NULL);
305         }
306         if (tmp[0] == '?') {
307           printf("Enter the response from your OTP calculator: \n");
308           continue;
309         }
310         if (tmp[0] == '\0') {
311           fprintf(stderr, "Secret pass phrase unchanged.\n");
312           finish(NULL);
313         }
314         
315         if (!(rval = opiepasswd(&opie, force, pp->pw_name, n, seed, tmp)))
316           finish(pp->pw_name);
317         
318         if (rval < 0) {
319           fprintf(stderr, "Error updating key database.\n");
320           finish(NULL);
321         }
322         printf("\tThat is not a valid OTP response.\n");
323       }
324     }
325     break;
326   case MODE_CONSOLE:
327     {
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");
335         if (force)
336           fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
337         else
338           finish(NULL);
339       };
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");
345           finish(NULL);
346         }
347         if (!passwd[0]) {
348           fprintf(stderr, "Secret pass phrase unchanged.\n");
349           finish(NULL);
350         }
351         {
352           char key[8];
353           char tbuf[OPIE_RESPONSE_MAX + 1];
354           
355           if (opiekeycrunch(MDX, key, opie.opie_seed, passwd) != 0) {
356             fprintf(stderr, "%s: key crunch failed. Secret pass phrase unchanged\n", argv[0]);
357             finish(NULL);
358           }
359           memset(passwd, 0, sizeof(passwd));
360           i = opie.opie_n - 1;
361           while (i-- != 0)
362             opiehash(key, MDX);
363           opiebtoe(tbuf, key);
364           if (opieverify(&opie, tbuf)) {
365             fprintf(stderr, "Sorry.\n");
366             finish(NULL);
367           }
368         }
369       }
370       for (i = 0;; i++) {
371         if (i > 2)
372           finish(NULL);
373         printf("Enter new secret pass phrase: ");
374         if (!opiereadpass(passwd, sizeof(passwd), 0)) {
375           fprintf(stderr, "Error reading secret pass phrase.\n");
376           finish(NULL);
377         }
378         if (!passwd[0] || feof(stdin)) {
379           fprintf(stderr, "Secret pass phrase unchanged.\n");
380           finish(NULL);
381         }
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);
385           continue;
386         }
387         printf("Again new secret pass phrase: ");
388         if (!opiereadpass(passwd2, sizeof(passwd2), 0)) {
389           fprintf(stderr, "Error reading secret pass phrase.\n");
390           finish(NULL);
391         }
392         if (feof(stdin)) {
393           fprintf(stderr, "Secret pass phrase unchanged.\n");
394           finish(NULL);
395         }
396         if (!passwd[0] || !strcmp(passwd, passwd2))
397           break;
398         fprintf(stderr, "Sorry, no match.\n");
399       }
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");
403         finish(NULL);
404       }
405       finish(pp->pw_name);
406     }
407   case MODE_DISABLE:
408     {
409       char tmp[4];
410       int i;
411
412       for (i = 0;; i++) {
413         if (i > 2)
414           finish(NULL);
415         
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");
419           finish(NULL);
420         }
421         if (!strcmp(tmp, "no"))
422           finish(NULL);
423         if (!strcmp(tmp, "yes")) {
424           if (opiepasswd(&opie, 0, pp->pw_name, n, seed, NULL)) {
425             fprintf(stderr, "Error updating key database.\n");
426             finish(NULL);
427           }
428           finish(pp->pw_name);
429         }
430       }
431     }
432   }
433 }