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