xref: /trueos/contrib/opie/libopie/generator.c (revision b38a0011c18c49fcb516cc2b4f5d751565e53f44)
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$
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 "opie.h"
53 
54 static char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
55 
56 #if OPIEAUTO
57 #ifndef max
58 #define max(x, y) (((x) > (y)) ? (x) : (y))
59 #endif /* max */
60 
61 static int opieauto_connect FUNCTION_NOARGS
62 {
63   int s;
64   struct sockaddr_un sun;
65   char buffer[1024];
66   char *c, *c2 ="/.opieauto";
67   uid_t myuid = getuid(), myeuid = geteuid();
68 
69   if (!myuid || !myeuid || (myuid != myeuid)) {
70 #if DEBUG
71     syslog(LOG_DEBUG, "opieauto_connect: superuser and/or setuid not allowed");
72 #endif /* DEBUG */
73     return -1;
74   };
75 
76   memset(&sun, 0, sizeof(struct sockaddr_un));
77   sun.sun_family = AF_UNIX;
78 
79   if (!(c = getenv("HOME"))) {
80 #if DEBUG
81     syslog(LOG_DEBUG, "opieauto_connect: no HOME variable?");
82 #endif /* DEBUG */
83     return -1;
84   };
85 
86   if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) {
87 #if DEBUG
88     syslog(LOG_DEBUG, "opieauto_connect: HOME is too long: %s", c);
89 #endif /* DEBUG */
90     return -1;
91   };
92 
93   strcpy(sun.sun_path, c);
94   strcat(sun.sun_path, c2);
95 
96   if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
97 #if DEBUG
98     syslog(LOG_DEBUG, "opieauto_connect: socket: %s(%d)", strerror(errno), errno);
99 #endif /* DEBUG */
100     return -1;
101   };
102 
103   {
104     struct stat st;
105 
106     if (stat(sun.sun_path, &st) < 0) {
107 #if DEBUG
108       syslog(LOG_DEBUG, "opieauto_connect: stat: %s(%d)\n", strerror(errno), errno);
109 #endif /* DEBUG */
110       goto ret;
111     };
112 
113     if (connect(s, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) {
114 #if DEBUG
115       syslog(LOG_DEBUG, "opieauto_connect: connect: %s(%d)\n", strerror(errno), errno);
116 #endif /* DEBUG */
117       goto ret;
118     };
119 
120     if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) {
121 #if DEBUG
122       syslog(LOG_DEBUG, "opieauto_connect: something's fishy about the socket\n");
123 #endif /* DEBUG */
124       goto ret;
125     };
126   };
127 
128   return s;
129 
130 ret:
131   close(s);
132   return -1;
133 };
134 #endif /* OPIEAUTO */
135 
136 int opiegenerator FUNCTION((challenge, secret, response), char *challenge AND char *secret AND char *response)
137 {
138   int algorithm;
139   int sequence;
140   char *seed;
141   struct opie_otpkey key;
142   int i;
143   int exts;
144 #if OPIEAUTO
145   int s;
146   int window;
147   char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
148   char *c;
149 #endif /* OPIEAUTO */
150 
151   if (!(challenge = strstr(challenge, "otp-")))
152     return 1;
153 
154   challenge += 4;
155 
156   if (__opieparsechallenge(challenge, &algorithm, &sequence, &seed, &exts))
157     return 1;
158 
159   if ((sequence < 2) || (sequence > 9999))
160     return 1;
161 
162   if (*secret) {
163     if (opiepasscheck(secret))
164       return -2;
165 
166     if (i = opiekeycrunch(algorithm, &key, seed, secret))
167       return i;
168 
169     if (sequence <= OPIE_SEQUENCE_RESTRICT) {
170       if (!(exts & 1))
171 	return 1;
172 
173       {
174 	char newseed[OPIE_SEED_MAX + 1];
175 	struct opie_otpkey newkey;
176 	char *c;
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 };
398