Resync patch with contrib.
[dragonfly.git] / contrib / opie / opiekey.c
blob8fade927ec43f0b42d49473150aedc85e7e11f07
1 /* opiekey.c: Stand-alone program for computing responses to OTP challenges.
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.
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>.
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.
19 History:
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).
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 $
44 #include "opie_cfg.h"
46 #include <stdio.h>
47 #include <string.h>
48 #include <stdlib.h>
50 #include "opie.h"
52 #ifdef __MSDOS__
53 #include <dos.h>
54 #endif
56 #if HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif /* HAVE_FCNTL_H */
60 extern char *optarg;
61 extern int optind, opterr;
63 int aflag = 0;
65 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
66 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
68 /******** Begin real source code ***************/
70 static VOIDRET usage FUNCTION((s), char *s)
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);
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
83 struct _rtrans {
84 int type;
85 char *name;
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 }
99 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
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);
106 if (secret[0] && (flags & 1)) {
107 char verify[OPIE_SECRET_MAX + 1];
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);
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);
122 memset(verify, 0, sizeof(verify));
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);
131 int main FUNCTION((argc, argv), int argc AND char *argv[])
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;
148 if (slash = strchr(argv[0], '/'))
149 slash++;
150 else
151 slash = argv[0];
153 if (!strcmp(slash, "key") || strstr(slash, "md4"))
154 algorithm = 4;
156 if (strstr(slash, "md5"))
157 algorithm = 5;
159 if (strstr(slash, "sha"))
160 algorithm = 3;
162 while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
163 switch (i) {
164 case 'v':
165 opieversion();
167 case 'n':
168 count = atoi(optarg);
169 break;
171 case 'x':
172 hex = 1;
173 break;
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;
183 case '4':
184 /* use MD4 algorithm */
185 algorithm = 4;
186 break;
188 case '5':
189 /* use MD5 algorithm */
190 algorithm = 5;
191 break;
193 case 'a':
194 aflag = 1;
195 break;
197 case 't':
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);
205 type = r->type;
207 break;
209 case 's':
210 algorithm = 3;
211 break;
213 default:
214 usage(argv[0]);
218 if ((argc - optind) < 2)
219 usage(argv[0]);
221 fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
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);
229 /* get seed string, which is last parameter */
230 seed = argv[optind + 1];
232 i = strlen(seed);
234 if (i > OPIE_SEED_MAX) {
235 fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
236 exit(1);
238 if (i < OPIE_SEED_MIN) {
239 fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
240 exit(1);
244 fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
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);
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);
266 if (opienewseed(strcpy(newseed, seed)) < 0) {
267 fprintf(stderr, "Error updating seed.\n");
268 goto error;
271 if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) {
272 fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
273 goto error;
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 */
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;
291 for (i = 0; i <= (keynum - count); i++)
292 opiehash(&key, algorithm);
295 char buf[OPIE_SEED_MAX + 48 + 1];
296 char *c;
298 for (; i <= keynum; i++) {
299 if (count > 1)
300 printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
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));
332 break;
334 puts(response);
335 opiehash(&key, algorithm);
339 memset(secret, 0, sizeof(secret));
340 memset(newsecret, 0, sizeof(newsecret));
341 return 0;
343 error:
344 memset(secret, 0, sizeof(secret));
345 memset(newsecret, 0, sizeof(newsecret));
346 return 1;