Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / opie / opiekey.c
1 /* opiekey.c: Stand-alone program for computing responses to OTP challenges.
2
3  Takes a sequence number and seed (presumably from an OPIE challenge)
4  as command line arguments, prompts for the user's secret pass phrase,
5  and outputs a response.
6
7 %%% portions-copyright-cmetz-96
8 Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
9 Reserved. The Inner Net License Version 2 applies to these portions of
10 the software.
11 You should have received a copy of the license with this software. If
12 you didn't get a copy, you may request one from <license@inner.net>.
13
14 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
15 McDonald, All Rights Reserved. All Rights under this copyright are assigned
16 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
17 License Agreement applies to this software.
18
19         History:
20
21         Modified by cmetz for OPIE 2.4. Use struct opie_key for key blocks.
22         Modified by cmetz for OPIE 2.31. Renamed "init" and RESPONSE_INIT
23                 to "init-hex" and RESPONSE_INIT_HEX. Removed active attack
24                 protection support.
25         Modified by cmetz for OPIE 2.3. OPIE_PASS_MAX changed to
26                 OPIE_SECRET_MAX. Added extended responses, which created
27                 lots of changes. Eliminated extra variable. Added -x and
28                 -t to help. Added -f flag. Added SHA support.
29         Modified by cmetz for OPIE 2.22. Print newline after seed too long
30                 message. Check for minimum seed length. Correct a grammar
31                 error.
32         Modified at NRL for OPIE 2.2. Check opiereadpass() return.
33                 Change opiereadpass() calls to add echo arg. Use FUNCTION
34                 definition et al. Check seed length here, too. Added back
35                 hex output. Reworked final output function.
36         Modified at NRL for OPIE 2.0.
37         Written at Bellcore for the S/Key Version 1 software distribution
38                 (skey.c).
39
40 $FreeBSD: src/contrib/opie/opiekey.c,v 1.1.1.2.6.4 2002/07/15 14:48:43 des Exp $
41 $DragonFly: src/contrib/opie/opiekey.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
42
43 */
44 #include "opie_cfg.h"
45
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 #include "opie.h"
51
52 #ifdef  __MSDOS__
53 #include <dos.h>
54 #endif
55
56 #if HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif /* HAVE_FCNTL_H */
59
60 extern char *optarg;
61 extern int optind, opterr;
62
63 int aflag = 0;
64
65 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
66 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
67
68 /******** Begin real source code ***************/
69
70 static VOIDRET usage FUNCTION((s), char *s)
71 {
72   fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s);
73   exit(1);
74 }
75
76 #define RESPONSE_STANDARD  0
77 #define RESPONSE_WORD      1
78 #define RESPONSE_HEX       2
79 #define RESPONSE_INIT_HEX  3
80 #define RESPONSE_INIT_WORD 4
81 #define RESPONSE_UNKNOWN   5
82
83 struct _rtrans {
84   int type;
85   char *name;
86 };
87
88 static struct _rtrans rtrans[] = {
89   { RESPONSE_WORD, "word" },
90   { RESPONSE_HEX, "hex" },
91   { RESPONSE_INIT_HEX, "init-hex" },
92   { RESPONSE_INIT_WORD, "init-word" },
93   { RESPONSE_STANDARD, "" },
94   { RESPONSE_STANDARD, "standard" },
95   { RESPONSE_STANDARD, "otp" },
96   { RESPONSE_UNKNOWN, NULL }
97 };
98
99 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
100 {
101   fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra);
102   if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) {
103     fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
104     exit(1);
105   }
106   if (secret[0] && (flags & 1)) {
107     char verify[OPIE_SECRET_MAX + 1];
108
109     fprintf(stderr, "Again %ssecret pass phrase: ", promptextra);
110     if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) {
111       fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
112       memset(verify, 0, sizeof(verify));
113       memset(secret, 0, sizeof(secret));
114       exit(1);
115     }
116     if (verify[0] && strcmp(verify, secret)) {
117       fprintf(stderr, "They don't match. Try again.\n");
118       memset(verify, 0, sizeof(verify));
119       memset(secret, 0, sizeof(secret));
120       exit(1);
121     }
122     memset(verify, 0, sizeof(verify));
123   }
124   if (!(flags & 2) && !aflag && opiepasscheck(secret)) {
125     memset(secret, 0, sizeof(secret));
126     fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
127     exit(1);
128   };
129 }
130
131 int main FUNCTION((argc, argv), int argc AND char *argv[])
132 {
133   /* variable declarations */
134   unsigned algorithm = MDX;     /* default algorithm per Makefile's MDX
135                                    symbol */
136   int keynum = 0;
137   int i;
138   int count = 1;
139   char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1];
140   struct opie_otpkey key, newkey;
141   char *seed, newseed[OPIE_SEED_MAX + 1];
142   char response[OPIE_RESPONSE_MAX + 1];
143   char *slash;
144   int hex = 0;
145   int type = RESPONSE_STANDARD;
146   int force = 0;
147
148   if (slash = strchr(argv[0], '/'))
149     slash++;
150   else
151     slash = argv[0];
152
153   if (!strcmp(slash, "key") || strstr(slash, "md4"))
154     algorithm = 4;
155
156   if (strstr(slash, "md5"))
157     algorithm = 5;
158
159   if (strstr(slash, "sha"))
160     algorithm = 3;
161
162   while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
163     switch (i) {
164     case 'v':
165       opieversion();
166
167     case 'n':
168       count = atoi(optarg);
169       break;
170
171     case 'x':
172       hex = 1;
173       break;
174
175     case 'f':
176 #if INSECURE_OVERRIDE
177       force = 1;
178 #else /* INSECURE_OVERRIDE */
179       fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
180 #endif /* INSECURE_OVERRIDE */
181       break;
182
183     case '4':
184       /* use MD4 algorithm */
185       algorithm = 4;
186       break;
187
188     case '5':
189       /* use MD5 algorithm */
190       algorithm = 5;
191       break;
192
193     case 'a':
194       aflag = 1;
195       break;
196
197     case 't':
198       {
199         struct _rtrans *r;
200         for (r = rtrans; r->name && strcmp(r->name, optarg); r++);
201         if (!r->name) {
202           fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg);
203           exit(1);
204         }
205         type = r->type;
206       }
207       break;
208
209     case 's':
210       algorithm = 3;
211       break;
212
213     default:
214       usage(argv[0]);
215     }
216   }
217
218   if ((argc - optind) < 2)
219     usage(argv[0]);
220
221   fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
222
223   /* get sequence number, which is next-to-last parameter */
224   keynum = atoi(argv[optind]);
225   if (keynum < 1) {
226     fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
227     exit(1);
228   }
229   /* get seed string, which is last parameter */
230   seed = argv[optind + 1];
231   {
232     i = strlen(seed);
233
234     if (i > OPIE_SEED_MAX) {
235       fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
236       exit(1);
237     }
238     if (i < OPIE_SEED_MIN) {
239       fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
240       exit(1);
241     }
242   }
243
244   fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
245
246   if (opieinsecure()) {
247     fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
248 #if INSECURE_OVERRIDE
249     if (force)
250       fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
251     else
252 #endif /* INSECURE_OVERRIDE */
253       exit(1);
254   }
255
256   if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) {
257 #if RETYPE
258     getsecret(secret, "old ", 1);
259 #else /* RETYPE */
260     getsecret(secret, "old ", 0);
261 #endif /* RETYPE */
262     getsecret(newsecret, "new ", 1);
263     if (!newsecret[0])
264       strcpy(newsecret, secret);
265
266     if (opienewseed(strcpy(newseed, seed)) < 0) {
267       fprintf(stderr, "Error updating seed.\n");
268       goto error;
269     }
270
271     if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) {
272       fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
273       goto error;
274     }
275
276     for (i = 0; i < 499; i++)
277       opiehash(&newkey, algorithm);
278   } else
279 #if RETYPE
280     getsecret(secret, "", 1);
281 #else /* RETYPE */
282     getsecret(secret, "", 0);
283 #endif /* RETYPE */
284
285   /* Crunch seed and secret password into starting key normally */
286   if (opiekeycrunch(algorithm, &key, seed, secret)) {
287     fprintf(stderr, "%s: key crunch failed\n", argv[0]);
288     goto error;
289   }
290
291   for (i = 0; i <= (keynum - count); i++)
292     opiehash(&key, algorithm);
293
294   {
295     char buf[OPIE_SEED_MAX + 48 + 1];
296     char *c;
297
298     for (; i <= keynum; i++) {
299       if (count > 1)
300         printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
301       
302       switch(type) {
303       case RESPONSE_STANDARD:
304         if (hex)
305           opiebtoh(response, &key);
306         else
307           opiebtoe(response, &key);
308         break;
309       case RESPONSE_WORD:
310         strcpy(response, "word:");
311         strcat(response, opiebtoe(buf, &key));
312         break;
313       case RESPONSE_HEX:
314         strcpy(response, "hex:");
315         strcat(response, opiebtoh(buf, &key));
316         break;
317       case RESPONSE_INIT_HEX:
318       case RESPONSE_INIT_WORD:
319         if (type == RESPONSE_INIT_HEX) {
320           strcpy(response, "init-hex:");
321           strcat(response, opiebtoh(buf, &key));
322           sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
323           strcat(response, buf);
324           strcat(response, opiebtoh(buf, &newkey));
325         } else {
326           strcpy(response, "init-word:");
327           strcat(response, opiebtoe(buf, &key));
328           sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
329           strcat(response, buf);
330           strcat(response, opiebtoe(buf, &newkey));
331         }
332         break;
333       }
334       puts(response);
335       opiehash(&key, algorithm);
336     }
337   }
338
339   memset(secret, 0, sizeof(secret));
340   memset(newsecret, 0, sizeof(newsecret));
341   return 0;
342
343 error:
344   memset(secret, 0, sizeof(secret));
345   memset(newsecret, 0, sizeof(newsecret));
346   return 1;
347 }