AMD64 - AUDIT RUN - Fix format strings, size_t, and other issues
[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 #include <stdio.h>
38 #if HAVE_STRING_H
39 #include <string.h>
40 #endif /* HAVE_STRING_H */
41 #if OPIEAUTO
42 #include <errno.h>
43 #if HAVE_STDLIB_H
44 #include <stdlib.h>
45 #endif /* HAVE_STDLIB_H */
46 #include <sys/stat.h>
47
48 #include <sys/socket.h>
49 #include <sys/un.h>
50 #endif /* OPIEAUTO */
51 #if DEBUG
52 #include <syslog.h>
53 #endif /* DEBUG */
54 #include "opie.h"
55
56 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
57
58 #if OPIEAUTO
59 #ifndef max
60 #define max(x, y) (((x) > (y)) ? (x) : (y))
61 #endif /* max */
62
63 static int opieauto_connect FUNCTION_NOARGS
64 {
65   int s;
66   struct sockaddr_un sun;
67   char buffer[1024];
68   char *c, *c2 ="/.opieauto";
69   uid_t myuid = getuid(), myeuid = geteuid();
70
71   if (!myuid || !myeuid || (myuid != myeuid)) {
72 #if DEBUG
73     syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
74 #endif /* DEBUG */
75     return -1;
76   };
77
78   memset(&sun, 0, sizeof(struct sockaddr_un));
79   sun.sun_family = AF_UNIX;
80
81   if (!(c = getenv("HOME"))) {
82 #if DEBUG
83     syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
84 #endif /* DEBUG */
85     return -1;
86   };
87
88   if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
89 #if DEBUG
90     syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
91 #endif /* DEBUG */
92     return -1;
93   };
94
95   strcpy(sun.sun_path, c);
96   strcat(sun.sun_path, c2);
97
98   if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
99 #if DEBUG
100     syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
101 #endif /* DEBUG */
102     return -1;
103   };
104
105   {
106     struct stat st;
107
108     if (stat(sun.sun_path, &st) < 0) {
109 #if DEBUG
110       syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
111 #endif /* DEBUG */
112       goto ret;
113     };
114
115     if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
116 #if DEBUG
117       syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
118 #endif /* DEBUG */
119       goto ret;
120     };
121
122     if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
123 #if DEBUG
124       syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
125 #endif /* DEBUG */
126       goto ret;
127     };
128   };
129
130   return s;
131
132 ret:
133   close(s);
134   return -1;
135 };
136 #endif /* OPIEAUTO */
137
138 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
139 {
140   int algorithm;
141   int sequence;
142   char *seed;
143   struct opie_otpkey key;
144   int i;
145   int exts;
146 #if OPIEAUTO
147   int s;
148   int window;
149   char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
150   char *c;
151 #endif /* OPIEAUTO */
152
153   if (!(challenge = strstr(challenge, "otp-")))
154     return 1;
155
156   challenge += 4;
157
158   if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
159     return 1;
160
161   if ((sequence < 2) || (sequence > 9999))
162     return 1;
163
164   if (*secret) {
165     if (opiepasscheck(secret))
166       return -2;
167
168     if (i = opiekeycrunch(algorithm, &key, seed, secret))
169       return i;
170
171     if (sequence <= OPIE_SEQUENCE_RESTRICT) {
172       if (!(exts & 1))
173         return 1;
174
175       {
176         char newseed[OPIE_SEED_MAX + 1];
177         struct opie_otpkey newkey;
178         char *c;
179         char buf[OPIE_SEED_MAX + 48 + 1];
180
181         while (sequence-- != 0)
182           opiehash(&key, algorithm);
183
184         if (opienewseed(strcpy(newseed, seed)) < 0)
185           return -1;
186
187         if (opiekeycrunch(algorithm, &newkey, newseed, secret))
188           return -1;
189
190         for (i = 0; i < 499; i++)
191           opiehash(&newkey, algorithm);
192
193         strcpy(response, "init-hex:");
194         strcat(response, opiebtoh(buf, &key));
195         if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
196             newseed) >= sizeof(buf)) {
197 #ifdef DEBUG
198           syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
199 #endif /* DEBUG */
200           return -1;
201         }
202         strcat(response, buf);
203         strcat(response, opiebtoh(buf, &newkey));
204       };
205     };
206   };
207
208 #if OPIEAUTO
209   if ((s = opieauto_connect()) >= 0) {
210     if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
211 #if DEBUG
212       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
213 #endif /* DEBUG */
214       close(s);
215       s = -1;
216       goto l0;
217     };
218     cmd[i] = 0;
219     if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
220 #if DEBUG
221       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
222 #endif /* DEBUG */
223       close(s);
224       s = -1;
225       goto l0;
226     };
227
228     window = strtoul(&cmd[3], &c, 10);
229     if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
230 #if DEBUG
231       syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
232 #endif /* DEBUG */
233       close(s);
234       s = -1;
235       goto l0;
236     };
237   };
238
239 l0:
240   if (*secret) {
241     int j;
242
243     if (s < 0) {
244       j = 0;
245       goto l1;
246     };
247
248     j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
249
250     for (i = j; i > 0; i--)
251       opiehash(&key, algorithm);
252
253     {
254       char buf[16+1];
255
256       opiebtoa8(buf, &key);
257
258       if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
259           seed, buf) >= sizeof(cmd)) {
260 #if DEBUG
261         syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
262 #endif /* DEBUG */
263         goto l1;
264       }
265     }
266
267     if (write(s, cmd, i = strlen(cmd)) != i) {
268 #if DEBUG
269       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
270 #endif /* DEBUG */
271       goto l1;
272     };
273
274     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
275 #if DEBUG
276       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
277 #endif /* DEBUG */
278     };
279     close(s);
280
281     cmd[i] = 0;
282     i = strlen(seed);
283     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')) {
284 #if DEBUG
285       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
286 #endif /* DEBUG */
287     };
288
289 l1:
290     for (i = sequence - j; i > 0; i--)
291       opiehash(&key, algorithm);
292
293     opiebtoh(response, &key);
294   } else {
295     if (s < 0)
296       goto l2;
297
298     if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
299         seed) >= sizeof(cmd))) {
300 #if DEBUG
301       syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
302 #endif /* DEBUG */
303       goto l2;
304     }
305
306     if (write(s, cmd, i = strlen(cmd)) != i) {
307 #if DEBUG
308       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
309 #endif /* DEBUG */
310       goto l2;
311     };
312
313     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
314 #if DEBUG
315       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
316 #endif /* DEBUG */
317       goto l2;
318     };
319     close(s);
320
321     i = strlen(seed);
322
323     if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
324 #if DEBUG
325       if (c)
326         *c = 0;
327       else
328         cmd[3] = 0;
329       
330       syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
331 #endif /* DEBUG */
332       goto l2;
333     };
334
335     c += i;
336
337     if (cmd[1] == '-') {
338 #if DEBUG
339       if (*c != '\n') {
340         *c = 0;
341         syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
342       };
343 #endif /* DEBUG */
344       goto l2;
345     };
346
347     if (cmd[1] != '+') {
348 #if DEBUG
349       *c = 0;
350       syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
351 #endif /* DEBUG */
352       goto l2;
353     };
354
355     {
356       char *c2;
357
358       if (!(c2 = strchr(++c, '\n'))) {
359 #if DEBUG
360         *c = 0;
361         syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
362 #endif /* DEBUG */
363         goto l2;
364       };
365
366       *c2++ = 0;
367     };
368
369     if (!opieatob8(&key, c))
370       goto l2;
371
372     opiebtoh(response, &key);
373   };
374
375   if (s >= 0)
376     close(s);
377 #else /* OPIEAUTO */
378   if (*secret) {
379     while (sequence-- != 0)
380       opiehash(&key, algorithm);
381
382     opiebtoh(response, &key);
383   } else
384     return -2;
385 #endif /* OPIEAUTO */
386
387   return 0;
388
389 #if OPIEAUTO
390 l2:
391 #if DEBUG
392   syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
393 #endif /* DEBUG */
394   if (s >= 0)
395     close(s);
396
397   return -2;
398 #endif /* OPIEAUTO */
399 };