Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / opie / libopie / generator.c
1 /* generator.c: The opiegenerator() library function.
2
3 %%% portions-copyright-cmetz-96
4 Portions of this software are Copyright 1996-1999 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         History:
11
12         Modified by cmetz for OPIE 2.4. Added opieauto code based on
13                 previously released test code. Renamed buffer to challenge.
14                 Use struct opie_otpkey for keys.
15         Modified by cmetz for OPIE 2.32. If secret=NULL, always return
16                 as if opieauto returned "get the secret". Renamed
17                 _opieparsechallenge() to __opieparsechallenge(). Check
18                 challenge for extended response support and don't send
19                 an init-hex response if extended response support isn't
20                 indicated in the challenge.
21         Modified by cmetz for OPIE 2.31. Renamed "init" to "init-hex".
22                 Removed active attack protection support. Fixed fairly
23                 bug in how init response was computed (i.e., dead wrong).
24         Modified by cmetz for OPIE 2.3. Use _opieparsechallenge(). ifdef
25                 around string.h. Output hex responses by default, output
26                 OTP re-init extended responses (same secret) if sequence
27                 number falls below 10.
28         Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
29                 Bug fixes.
30         Created at NRL for OPIE 2.2.
31
32 $FreeBSD: src/contrib/opie/libopie/generator.c,v 1.3.6.2 2002/07/15 14:48:47 des Exp $
33 $DragonFly: src/contrib/opie/libopie/generator.c,v 1.2 2003/06/17 04:24:05 dillon Exp $
34 */
35
36 #include "opie_cfg.h"
37 #if HAVE_STRING_H
38 #include <string.h>
39 #endif /* HAVE_STRING_H */
40 #if OPIEAUTO
41 #include <errno.h>
42 #if HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif /* HAVE_STDLIB_H */
45 #include <sys/stat.h>
46
47 #include <sys/socket.h>
48 #include <sys/un.h>
49 #endif /* OPIEAUTO */
50 #if DEBUG
51 #include <syslog.h>
52 #endif /* DEBUG */
53 #include "opie.h"
54
55 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
56
57 #if OPIEAUTO
58 #ifndef max
59 #define max(x, y) (((x) > (y)) ? (x) : (y))
60 #endif /* max */
61
62 static int opieauto_connect FUNCTION_NOARGS
63 {
64   int s;
65   struct sockaddr_un sun;
66   char buffer[1024];
67   char *c, *c2 ="/.opieauto";
68   uid_t myuid = getuid(), myeuid = geteuid();
69
70   if (!myuid || !myeuid || (myuid != myeuid)) {
71 #if DEBUG
72     syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
73 #endif /* DEBUG */
74     return -1;
75   };
76
77   memset(&sun, 0, sizeof(struct sockaddr_un));
78   sun.sun_family = AF_UNIX;
79
80   if (!(c = getenv("HOME"))) {
81 #if DEBUG
82     syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
83 #endif /* DEBUG */
84     return -1;
85   };
86
87   if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
88 #if DEBUG
89     syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
90 #endif /* DEBUG */
91     return -1;
92   };
93
94   strcpy(sun.sun_path, c);
95   strcat(sun.sun_path, c2);
96
97   if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
98 #if DEBUG
99     syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
100 #endif /* DEBUG */
101     return -1;
102   };
103
104   {
105     struct stat st;
106
107     if (stat(sun.sun_path, &st) < 0) {
108 #if DEBUG
109       syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
110 #endif /* DEBUG */
111       goto ret;
112     };
113
114     if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
115 #if DEBUG
116       syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
117 #endif /* DEBUG */
118       goto ret;
119     };
120
121     if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
122 #if DEBUG
123       syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
124 #endif /* DEBUG */
125       goto ret;
126     };
127   };
128
129   return s;
130
131 ret:
132   close(s);
133   return -1;
134 };
135 #endif /* OPIEAUTO */
136
137 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
138 {
139   int algorithm;
140   int sequence;
141   char *seed;
142   struct opie_otpkey key;
143   int i;
144   int exts;
145 #if OPIEAUTO
146   int s;
147   int window;
148   char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
149   char *c;
150 #endif /* OPIEAUTO */
151
152   if (!(challenge = strstr(challenge, "otp-")))
153     return 1;
154
155   challenge += 4;
156
157   if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
158     return 1;
159
160   if ((sequence < 2) || (sequence > 9999))
161     return 1;
162
163   if (*secret) {
164     if (opiepasscheck(secret))
165       return -2;
166
167     if (i = opiekeycrunch(algorithm, &key, seed, secret))
168       return i;
169
170     if (sequence <= OPIE_SEQUENCE_RESTRICT) {
171       if (!(exts & 1))
172         return 1;
173
174       {
175         char newseed[OPIE_SEED_MAX + 1];
176         struct opie_otpkey newkey;
177         char *c;
178         char buf[OPIE_SEED_MAX + 48 + 1];
179
180         while (sequence-- != 0)
181           opiehash(&key, algorithm);
182
183         if (opienewseed(strcpy(newseed, seed)) < 0)
184           return -1;
185
186         if (opiekeycrunch(algorithm, &newkey, newseed, secret))
187           return -1;
188
189         for (i = 0; i < 499; i++)
190           opiehash(&newkey, algorithm);
191
192         strcpy(response, "init-hex:");
193         strcat(response, opiebtoh(buf, &key));
194         if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
195             newseed) >= sizeof(buf)) {
196 #ifdef DEBUG
197           syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
198 #endif /* DEBUG */
199           return -1;
200         }
201         strcat(response, buf);
202         strcat(response, opiebtoh(buf, &newkey));
203       };
204     };
205   };
206
207 #if OPIEAUTO
208   if ((s = opieauto_connect()) >= 0) {
209     if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
210 #if DEBUG
211       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
212 #endif /* DEBUG */
213       close(s);
214       s = -1;
215       goto l0;
216     };
217     cmd[i] = 0;
218     if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
219 #if DEBUG
220       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
221 #endif /* DEBUG */
222       close(s);
223       s = -1;
224       goto l0;
225     };
226
227     window = strtoul(&cmd[3], &c, 10);
228     if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
229 #if DEBUG
230       syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
231 #endif /* DEBUG */
232       close(s);
233       s = -1;
234       goto l0;
235     };
236   };
237
238 l0:
239   if (*secret) {
240     int j;
241
242     if (s < 0) {
243       j = 0;
244       goto l1;
245     };
246
247     j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
248
249     for (i = j; i > 0; i--)
250       opiehash(&key, algorithm);
251
252     {
253       char buf[16+1];
254
255       opiebtoa8(buf, &key);
256
257       if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
258           seed, buf) >= sizeof(cmd)) {
259 #if DEBUG
260         syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
261 #endif /* DEBUG */
262         goto l1;
263       }
264     }
265
266     if (write(s, cmd, i = strlen(cmd)) != i) {
267 #if DEBUG
268       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
269 #endif /* DEBUG */
270       goto l1;
271     };
272
273     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
274 #if DEBUG
275       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
276 #endif /* DEBUG */
277     };
278     close(s);
279
280     cmd[i] = 0;
281     i = strlen(seed);
282     if ((cmd[0] != 'S') || (cmd[1] != '+') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i) || (*(c + i) != '\n')) {
283 #if DEBUG
284       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
285 #endif /* DEBUG */
286     };
287
288 l1:
289     for (i = sequence - j; i > 0; i--)
290       opiehash(&key, algorithm);
291
292     opiebtoh(response, &key);
293   } else {
294     if (s < 0)
295       goto l2;
296
297     if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
298         seed) >= sizeof(cmd))) {
299 #if DEBUG
300       syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
301 #endif /* DEBUG */
302       goto l2;
303     }
304
305     if (write(s, cmd, i = strlen(cmd)) != i) {
306 #if DEBUG
307       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
308 #endif /* DEBUG */
309       goto l2;
310     };
311
312     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
313 #if DEBUG
314       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
315 #endif /* DEBUG */
316       goto l2;
317     };
318     close(s);
319
320     i = strlen(seed);
321
322     if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
323 #if DEBUG
324       if (c)
325         *c = 0;
326       else
327         cmd[3] = 0;
328       
329       syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
330 #endif /* DEBUG */
331       goto l2;
332     };
333
334     c += i;
335
336     if (cmd[1] == '-') {
337 #if DEBUG
338       if (*c != '\n') {
339         *c = 0;
340         syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
341       };
342 #endif /* DEBUG */
343       goto l2;
344     };
345
346     if (cmd[1] != '+') {
347 #if DEBUG
348       *c = 0;
349       syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
350 #endif /* DEBUG */
351       goto l2;
352     };
353
354     {
355       char *c2;
356
357       if (!(c2 = strchr(++c, '\n'))) {
358 #if DEBUG
359         *c = 0;
360         syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
361 #endif /* DEBUG */
362         goto l2;
363       };
364
365       *c2++ = 0;
366     };
367
368     if (!opieatob8(&key, c))
369       goto l2;
370
371     opiebtoh(response, &key);
372   };
373
374   if (s >= 0)
375     close(s);
376 #else /* OPIEAUTO */
377   if (*secret) {
378     while (sequence-- != 0)
379       opiehash(&key, algorithm);
380
381     opiebtoh(response, &key);
382   } else
383     return -2;
384 #endif /* OPIEAUTO */
385
386   return 0;
387
388 #if OPIEAUTO
389 l2:
390 #if DEBUG
391   syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
392 #endif /* DEBUG */
393   if (s >= 0)
394     close(s);
395
396   return -2;
397 #endif /* OPIEAUTO */
398 };