Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / opie / opiekey.c
CommitLineData
984263bc
MD
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
8Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
9Reserved. The Inner Net License Version 2 applies to these portions of
10the software.
11You should have received a copy of the license with this software. If
12you didn't get a copy, you may request one from <license@inner.net>.
13
14Portions of this software are Copyright 1995 by Randall Atkinson and Dan
15McDonald, All Rights Reserved. All Rights under this copyright are assigned
16to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
17License 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 $
1de703da 41$DragonFly: src/contrib/opie/opiekey.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
984263bc
MD
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
60extern char *optarg;
61extern int optind, opterr;
62
63int aflag = 0;
64
65char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
66char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
67
68/******** Begin real source code ***************/
69
70static 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
83struct _rtrans {
84 int type;
85 char *name;
86};
87
88static 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
99static 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
131int 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
343error:
344 memset(secret, 0, sizeof(secret));
345 memset(newsecret, 0, sizeof(newsecret));
346 return 1;
347}