Correct math and limerick.
[dragonfly.git] / contrib / opie / opieauto.c
blob731c6fda5897f796a433ba61ac1f906ee10ca7ff
1 /* opieauto.c: The opieauto program.
3 %%% copyright-cmetz-96
4 This software is Copyright 1996-2001 by Craig Metz, All Rights Reserved.
5 The Inner Net License Version 3 applies to this software.
6 You should have received a copy of the license with this software. If
7 you didn't get a copy, you may request one from <license@inner.net>.
9 History:
11 Created by cmetz for OPIE 2.4 based on previously released
12 test code. Use opiestrncpy().
15 #include "opie_cfg.h"
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #if HAVE_SYS_TIME_H
20 #include <sys/time.h>
21 #endif /* HAVE_SYS_TIME_H */
22 #include <stdio.h>
23 #include <errno.h>
24 #if HAVE_STRING_H
25 #include <string.h>
26 #endif /* HAVE_STRING_H */
27 #include <getopt.h>
28 #if HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif /* HAVE_STDLIB_H */
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif /* HAVE_UNISTD_H */
34 #include <sys/stat.h>
36 #include "opie.h"
38 #ifndef max
39 #define max(x, y) (((x) > (y)) ? (x) : (y))
40 #endif /* max */
42 int window = 10;
43 char *myname = NULL;
45 uid_t myuid = 0;
47 #define MAXCLIENTS 2
48 int parents, s[MAXCLIENTS + 1];
50 char cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1];
52 struct cachedotp {
53 struct cachedotp *next;
54 int algorithm, base, current;
55 struct opie_otpkey basekey;
56 char seed[OPIE_SEED_MAX+1];
59 struct cachedotp *head = NULL;
61 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
63 void baile(x) {
64 fprintf(stderr, "%s: %s: %s(%d)\n", myname, x, strerror(errno), errno);
65 exit(1);
68 void bail(x) {
69 fprintf(stderr, "%s: %s\n", myname, x);
70 exit(1);
73 void zerocache(void)
75 struct cachedotp *c = head, *c2;
77 while(c) {
78 c2 = c->next;
79 memset(c, 0, sizeof(struct cachedotp));
80 c = c2;
84 int doreq(int fd)
86 int algorithm, sequence, i;
87 char *seed = NULL, *response = NULL;
89 if (((cmd[0] != 'S') && (cmd[0] != 's')) || (cmd[1] != '=') || (cmd[2] != ' ')) {
90 #if DEBUG
91 fprintf(stderr, "%s: got bogus command: %s\n", myname, cmd);
92 #endif /* DEBUG */
93 goto error;
97 char *c;
99 if (((algorithm = strtoul(&cmd[3], &c, 10)) < 3) || (algorithm > 5) || (*c != ' ')) {
100 #if DEBUG
101 fprintf(stderr, "%s: got bogus algorithm: %s\n", myname, cmd);
102 #endif /* DEBUG */
103 goto error;
106 if (((sequence = strtoul(c + 1, &c, 10)) <= OPIE_SEQUENCE_RESTRICT) || (sequence > OPIE_SEQUENCE_MAX)) {
107 #if DEBUG
108 fprintf(stderr, "%s: got bogus sequence: %s\n", myname, cmd);
109 #endif /* DEBUG */
110 goto error;
113 if (cmd[0] == 'S') {
114 if (!(c = strchr(seed = c + 1, ' '))) {
115 #if DEBUG
116 fprintf(stderr, "%s: got bogus seed: %s\n", myname, cmd);
117 #endif /* DEBUG */
118 goto error;
121 *c = 0;
123 if (!(c = strchr(response = c + 1, '\n'))) {
124 #if DEBUG
125 fprintf(stderr, "%s: got bogus response: %s\n", myname, cmd);
126 #endif /* DEBUG */
127 goto error;
130 *c = 0;
131 } else {
132 if (!(c = strchr(seed = c + 1, '\n'))) {
133 #if DEBUG
134 fprintf(stderr, "%s: got bogus seed: %s\n", myname, cmd);
135 #endif /* DEBUG */
136 goto error;
139 *c = 0;
143 #if DEBUG
144 fprintf(stderr, "got cmd=%c, algorithm=%d sequence=%d seed=+%s+ response=+%s+ on fd %d\n", cmd[0], algorithm, sequence, seed, response, fd);
145 #endif /* DEBUG */
147 seed = strdup(seed);
149 if (sequence < 10) {
150 #if DEBUG
151 fprintf(stderr, "sequence < 10; can't do it\n");
152 #endif /* DEBUG */
153 sprintf(cmd, "%c- %d %d %s\n", cmd[0], algorithm, sequence, seed);
157 struct cachedotp **c;
159 for (c = &head; *c && (strcmp((*c)->seed, seed) || ((*c)->algorithm != algorithm)); c = &((*c)->next));
160 if (!(*c)) {
161 if (cmd[0] == 's') {
162 #if DEBUG
163 fprintf(stderr, "(seed, algorithm) not found for s command\n");
164 #endif /* DEBUG */
165 sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, seed);
166 goto out;
169 if (!(*c = malloc(sizeof(struct cachedotp))))
170 baile("malloc");
171 memset(*c, 0, sizeof(struct cachedotp));
173 (*c)->algorithm = algorithm;
174 opiestrncpy((*c)->seed, seed, OPIE_SEED_MAX);
177 if (cmd[0] == 'S') {
178 (*c)->base = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT);
179 (*c)->current = sequence;
181 if (!opieatob8(&(*c)->basekey, response))
182 goto error;
184 sprintf(cmd, "S+ %d %d %s\n", algorithm, sequence, (*c)->seed);
185 } else {
186 if (sequence != ((*c)->current - 1)) {
187 #if DEBUG
188 fprintf(stderr, "out of sequence: sequence=%d, base=%d, current=%d\n", sequence, (*c)->base, (*c)->current);
189 #endif /* DEBUG */
190 sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, (*c)->seed);
191 goto out;
194 if (sequence < (*c)->base) {
195 #if DEBUG
196 fprintf(stderr, "attempt to generate below base: sequence=%d, base=%d, current=%d\n", sequence, (*c)->base, (*c)->current);
197 #endif /* DEBUG */
198 sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, (*c)->seed);
199 goto out;
202 (*c)->current = sequence;
203 i = sequence - (*c)->base;
205 struct opie_otpkey key;
206 char buffer[16+1];
208 key = (*c)->basekey;
209 while(i--)
210 opiehash(&key, algorithm);
212 opiebtoa8(buffer, &key);
213 sprintf(cmd, "s+ %d %d %s %s\n", algorithm, sequence, (*c)->seed, buffer);
217 printf("%c otp-%s %d %s (%d/%d)\n", cmd[0], algids[algorithm], sequence, (*c)->seed, sequence - (*c)->base, window);
218 fflush(stdout);
220 if (sequence == (*c)->base) {
221 struct cachedotp *c2 = *c;
222 *c = (*c)->next;
223 memset(c2, 0, sizeof(struct cachedotp));
224 free(c2);
228 out:
229 write(fd, cmd, i = strlen(cmd));
230 free(seed);
231 return 0;
233 error:
234 fprintf(stderr, "Invalid command on fd %d\n", fd);
235 if (seed)
236 free(seed);
237 return -1;
240 static void usage()
242 fprintf(stderr, "usage: %s [-v] [-h] [-q] [-n <number of OTPs>]\n", myname);
243 exit(1);
246 int main(int argc, char **argv)
248 int i;
249 struct stat st;
250 char *sockpath;
252 if (myname = strrchr(argv[0], '/'))
253 myname++;
254 else
255 myname = argv[0];
257 while((i = getopt(argc, argv, "w:hv")) != EOF) {
258 switch(i) {
259 case 'v':
260 opieversion();
262 case 'w':
263 if (!(window = atoi(optarg))) {
264 fprintf(stderr, "%s: invalid number of OTPs: %s\n", myname, optarg);
265 exit(1);
267 break;
269 default:
270 usage();
275 uid_t myeuid;
277 if (!(myuid = getuid()) || !(myeuid = geteuid()) || (myuid != myeuid))
278 bail("this program must not be run with superuser priveleges or setuid.");
281 if (atexit(zerocache) < 0)
282 baile("atexit");
285 struct sockaddr_un sun;
287 memset(&sun, 0, sizeof(struct sockaddr_un));
288 sun.sun_family = AF_UNIX;
291 char *c;
292 char *c2 = "/.opieauto";
294 if (!(c = getenv("HOME")))
295 bail("getenv(HOME) failed -- no HOME variable?");
297 if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1))
298 bail("your HOME is too long");
300 strcpy(sun.sun_path, c);
301 strcat(sun.sun_path, c2);
302 sockpath = strdup(sun.sun_path);
305 if ((parents = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
306 baile("socket");
308 if (unlink(sockpath) && (errno != ENOENT))
309 baile("unlink");
311 if (umask(0177) < 0)
312 baile("umask");
314 if (bind(parents, (struct sockaddr *)&sun, sizeof(struct sockaddr_un)))
315 baile("bind");
317 if (stat(sockpath, &st) < 0)
318 baile("stat");
320 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600))
321 bail("socket permissions and/or ownership were not correctly created.");
323 if (listen(parents, 1) < 0)
324 baile("listen");
328 fd_set fds, rfds, efds;
329 int maxfd = parents;
330 int i, j;
332 FD_ZERO(&fds);
333 FD_SET(parents, &fds);
335 while(1) {
336 memcpy(&rfds, &fds, sizeof(fd_set));
338 if (select(maxfd + 1, &rfds, NULL, NULL, NULL) < 0)
339 baile("select");
341 for (i = 0; s[i]; i++) {
342 if (!FD_ISSET(s[i], &rfds))
343 continue;
345 if (((j = read(s[i], cmd, sizeof(cmd)-1)) <= 0) || ((cmd[j] = 0) || doreq(s[i]))) {
346 close(s[i]);
347 FD_CLR(s[i], &fds);
349 if (s[i] == maxfd)
350 maxfd--;
352 for (j = i; s[j]; s[j] = s[j + 1], j++);
353 FD_SET(parents, &fds);
354 i--;
355 continue;
359 if (FD_ISSET(parents, &rfds)) {
360 for (i = 0; s[i]; i++)
361 if (i > MAXCLIENTS)
362 bail("this message never printed");
364 if (stat(sockpath, &st) < 0)
365 baile("stat");
367 if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600))
368 bail("socket permissions and/or ownership has been messed with.");
370 if ((s[i] = accept(parents, NULL, 0)) < 0)
371 baile("accept");
373 FD_SET(s[i], &fds);
374 if (s[i] > maxfd)
375 maxfd = s[i];
377 sprintf(cmd, "C+ %d\n", window);
378 if (write(s[i], cmd, j = strlen(cmd)) != j)
379 baile("write");
381 if (++i == MAXCLIENTS)
382 FD_CLR(parents, &fds);