drm/linux: Restore wait_event*() functionality
[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: head/contrib/opie/libopie/generator.c 257264 2013-10-28 18:24:31Z sbruno $
33 */
34
35 #include "opie_cfg.h"
36 #if HAVE_STRING_H
37 #include <string.h>
38 #endif /* HAVE_STRING_H */
39 #if OPIEAUTO
40 #include <errno.h>
41 #if HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif /* HAVE_STDLIB_H */
44 #include <sys/stat.h>
45
46 #include <sys/socket.h>
47 #include <sys/un.h>
48 #endif /* OPIEAUTO */
49 #if DEBUG
50 #include <syslog.h>
51 #endif /* DEBUG */
52 #include <stdio.h>
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)) != 0)
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 buf[OPIE_SEED_MAX + 48 + 1];
178
179         while (sequence-- != 0)
180           opiehash(&key, algorithm);
181
182         if (opienewseed(strcpy(newseed, seed)) < 0)
183           return -1;
184
185         if (opiekeycrunch(algorithm, &newkey, newseed, secret))
186           return -1;
187
188         for (i = 0; i < 499; i++)
189           opiehash(&newkey, algorithm);
190
191         strcpy(response, "init-hex:");
192         strcat(response, opiebtoh(buf, &key));
193         if (snprintf(buf, sizeof(buf), ":%s 499 %s:", algids[algorithm],
194             newseed) >= sizeof(buf)) {
195 #ifdef DEBUG
196           syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at init-hex");
197 #endif /* DEBUG */
198           return -1;
199         }
200         strcat(response, buf);
201         strcat(response, opiebtoh(buf, &newkey));
202       };
203     };
204   };
205
206 #if OPIEAUTO
207   if ((s = opieauto_connect()) >= 0) {
208     if ((i = read(s, cmd, sizeof(cmd)-1)) < 0) {
209 #if DEBUG
210       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
211 #endif /* DEBUG */
212       close(s);
213       s = -1;
214       goto l0;
215     };
216     cmd[i] = 0;
217     if ((cmd[0] != 'C') || (cmd[1] != '+') || (cmd[2] != ' ')) {
218 #if DEBUG
219       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing C+ response: %s\n", cmd);
220 #endif /* DEBUG */
221       close(s);
222       s = -1;
223       goto l0;
224     };
225
226     window = strtoul(&cmd[3], &c, 10);
227     if (!window || (window >= (OPIE_SEQUENCE_MAX - OPIE_SEQUENCE_RESTRICT)) || !isspace(*c)) {
228 #if DEBUG
229       syslog(LOG_DEBUG, "opiegenerator: got bogus option response: %s\n", cmd);
230 #endif /* DEBUG */
231       close(s);
232       s = -1;
233       goto l0;
234     };
235   };
236
237 l0:
238   if (*secret) {
239     int j;
240
241     if (s < 0) {
242       j = 0;
243       goto l1;
244     };
245
246     j = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
247
248     for (i = j; i > 0; i--)
249       opiehash(&key, algorithm);
250
251     {
252       char buf[16+1];
253
254       opiebtoa8(buf, &key);
255
256       if (snprintf(cmd, sizeof(cmd), "S= %d %d %s %s\n", algorithm, sequence,
257           seed, buf) >= sizeof(cmd)) {
258 #if DEBUG
259         syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at S=\n");
260 #endif /* DEBUG */
261         goto l1;
262       }
263     }
264
265     if (write(s, cmd, i = strlen(cmd)) != i) {
266 #if DEBUG
267       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
268 #endif /* DEBUG */
269       goto l1;
270     };
271
272     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
273 #if DEBUG
274       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
275 #endif /* DEBUG */
276     };
277     close(s);
278
279     cmd[i] = 0;
280     i = strlen(seed);
281     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')) {
282 #if DEBUG
283       syslog(LOG_DEBUG, "opiegenerator: got invalid/failing S+ response: %s\n", cmd);
284 #endif /* DEBUG */
285     };
286
287 l1:
288     for (i = sequence - j; i > 0; i--)
289       opiehash(&key, algorithm);
290
291     opiebtoh(response, &key);
292   } else {
293     if (s < 0)
294       goto l2;
295
296     if ((snprintf(cmd, sizeof(cmd), "s= %d %d %s\n", algorithm, sequence,
297         seed) >= sizeof(cmd))) {
298 #if DEBUG
299       syslog(LOG_DEBUG, "opiegenerator: snprintf truncation at s=\n");
300 #endif /* DEBUG */
301       goto l2;
302     }
303
304     if (write(s, cmd, i = strlen(cmd)) != i) {
305 #if DEBUG
306       syslog(LOG_DEBUG, "opiegenerator: write: %s(%d)\n", strerror(errno), errno);
307 #endif /* DEBUG */
308       goto l2;
309     };
310
311     if ((i = read(s, cmd, sizeof(cmd))) < 0) {
312 #if DEBUG
313       syslog(LOG_DEBUG, "opiegenerator: read: %s(%d)\n", strerror(errno), errno);
314 #endif /* DEBUG */
315       goto l2;
316     };
317     close(s);
318
319     i = strlen(seed);
320
321     if ((cmd[0] != 's') || (cmd[2] != ' ') || (strtoul(&cmd[3], &c, 10) != algorithm) || (strtoul(c + 1, &c, 10) != sequence) || strncmp(++c, seed, i)) {
322 #if DEBUG
323       if (c)
324         *c = 0;
325       else
326         cmd[3] = 0;
327       
328       syslog(LOG_DEBUG, "opiegenerator: got bogus/invalid s response: %s\n", cmd);
329 #endif /* DEBUG */
330       goto l2;
331     };
332
333     c += i;
334
335     if (cmd[1] == '-') {
336 #if DEBUG
337       if (*c != '\n') {
338         *c = 0;
339         syslog(LOG_DEBUG, "opiegenerator: got invalid s- response: %s\n", cmd);
340       };
341 #endif /* DEBUG */
342       goto l2;
343     };
344
345     if (cmd[1] != '+') {
346 #if DEBUG
347       *c = 0;
348       syslog(LOG_DEBUG, "opiegenerator: got invalid s response: %s\n", cmd);
349 #endif /* DEBUG */
350       goto l2;
351     };
352
353     {
354       char *c2;
355
356       if (!(c2 = strchr(++c, '\n'))) {
357 #if DEBUG
358         *c = 0;
359         syslog(LOG_DEBUG, "opiegenerator: got invalid s+ response: %s\n", cmd);
360 #endif /* DEBUG */
361         goto l2;
362       };
363
364       *c2++ = 0;
365     };
366
367     if (!opieatob8(&key, c))
368       goto l2;
369
370     opiebtoh(response, &key);
371   };
372
373   if (s >= 0)
374     close(s);
375 #else /* OPIEAUTO */
376   if (*secret) {
377     while (sequence-- != 0)
378       opiehash(&key, algorithm);
379
380     opiebtoh(response, &key);
381   } else
382     return -2;
383 #endif /* OPIEAUTO */
384
385   return 0;
386
387 #if OPIEAUTO
388 l2:
389 #if DEBUG
390   syslog(LOG_DEBUG, "opiegenerator: no opieauto response available.\n");
391 #endif /* DEBUG */
392   if (s >= 0)
393     close(s);
394
395   return -2;
396 #endif /* OPIEAUTO */
397 };