192906Smarkm/* opieauto.c: The opieauto program. 292906Smarkm 392906Smarkm%%% copyright-cmetz-96 492906SmarkmThis software is Copyright 1996-2001 by Craig Metz, All Rights Reserved. 592906SmarkmThe Inner Net License Version 3 applies to this software. 692906SmarkmYou should have received a copy of the license with this software. If 792906Smarkmyou didn't get a copy, you may request one from <license@inner.net>. 892906Smarkm 992906Smarkm History: 1092906Smarkm 1192906Smarkm Created by cmetz for OPIE 2.4 based on previously released 1292906Smarkm test code. Use opiestrncpy(). 1392906Smarkm*/ 1492906Smarkm 1592906Smarkm#include "opie_cfg.h" 1692906Smarkm#include <sys/types.h> 1792906Smarkm#include <sys/socket.h> 1892906Smarkm#include <sys/un.h> 1992906Smarkm#if HAVE_SYS_TIME_H 2092906Smarkm#include <sys/time.h> 2192906Smarkm#endif /* HAVE_SYS_TIME_H */ 2292906Smarkm#include <stdio.h> 2392906Smarkm#include <errno.h> 2492906Smarkm#if HAVE_STRING_H 2592906Smarkm#include <string.h> 2692906Smarkm#endif /* HAVE_STRING_H */ 2792906Smarkm#include <getopt.h> 2892906Smarkm#if HAVE_STDLIB_H 2992906Smarkm#include <stdlib.h> 3092906Smarkm#endif /* HAVE_STDLIB_H */ 3192906Smarkm#if HAVE_UNISTD_H 3292906Smarkm#include <unistd.h> 3392906Smarkm#endif /* HAVE_UNISTD_H */ 3492906Smarkm#include <sys/stat.h> 3592906Smarkm 3692906Smarkm#include "opie.h" 3792906Smarkm 3892906Smarkm#ifndef max 3992906Smarkm#define max(x, y) (((x) > (y)) ? (x) : (y)) 4092906Smarkm#endif /* max */ 4192906Smarkm 4292906Smarkmint window = 10; 4392906Smarkmchar *myname = NULL; 4492906Smarkm 4592906Smarkmuid_t myuid = 0; 4692906Smarkm 4792906Smarkm#define MAXCLIENTS 2 4892906Smarkmint parents, s[MAXCLIENTS + 1]; 4992906Smarkm 5092906Smarkmchar cmd[1+1+1+1+4+1+OPIE_SEED_MAX+1+4+1+4+1+4+1+4+1]; 5192906Smarkm 5292906Smarkmstruct cachedotp { 5392906Smarkm struct cachedotp *next; 5492906Smarkm int algorithm, base, current; 5592906Smarkm struct opie_otpkey basekey; 5692906Smarkm char seed[OPIE_SEED_MAX+1]; 5792906Smarkm}; 5892906Smarkm 5992906Smarkmstruct cachedotp *head = NULL; 6092906Smarkm 6192906Smarkmchar *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" }; 6292906Smarkm 6392906Smarkmvoid baile(x) { 6492906Smarkm fprintf(stderr, "%s: %s: %s(%d)\n", myname, x, strerror(errno), errno); 6592906Smarkm exit(1); 6692906Smarkm} 6792906Smarkm 6892906Smarkmvoid bail(x) { 6992906Smarkm fprintf(stderr, "%s: %s\n", myname, x); 7092906Smarkm exit(1); 7192906Smarkm} 7292906Smarkm 7392906Smarkmvoid zerocache(void) 7492906Smarkm{ 7592906Smarkm struct cachedotp *c = head, *c2; 7692906Smarkm 7792906Smarkm while(c) { 7892906Smarkm c2 = c->next; 7992906Smarkm memset(c, 0, sizeof(struct cachedotp)); 8092906Smarkm c = c2; 8192906Smarkm }; 8292906Smarkm}; 8392906Smarkm 8492906Smarkmint doreq(int fd) 8592906Smarkm{ 8692906Smarkm int algorithm, sequence, i; 8792906Smarkm char *seed = NULL, *response = NULL; 8892906Smarkm 8992906Smarkm if (((cmd[0] != 'S') && (cmd[0] != 's')) || (cmd[1] != '=') || (cmd[2] != ' ')) { 9092906Smarkm#if DEBUG 9192906Smarkm fprintf(stderr, "%s: got bogus command: %s\n", myname, cmd); 9292906Smarkm#endif /* DEBUG */ 9392906Smarkm goto error; 9492906Smarkm }; 9592906Smarkm 9692906Smarkm { 9792906Smarkm char *c; 9892906Smarkm 9992906Smarkm if (((algorithm = strtoul(&cmd[3], &c, 10)) < 3) || (algorithm > 5) || (*c != ' ')) { 10092906Smarkm#if DEBUG 10192906Smarkm fprintf(stderr, "%s: got bogus algorithm: %s\n", myname, cmd); 10292906Smarkm#endif /* DEBUG */ 10392906Smarkm goto error; 10492906Smarkm }; 10592906Smarkm 10692906Smarkm if (((sequence = strtoul(c + 1, &c, 10)) <= OPIE_SEQUENCE_RESTRICT) || (sequence > OPIE_SEQUENCE_MAX)) { 10792906Smarkm#if DEBUG 10892906Smarkm fprintf(stderr, "%s: got bogus sequence: %s\n", myname, cmd); 10992906Smarkm#endif /* DEBUG */ 11092906Smarkm goto error; 11192906Smarkm }; 11292906Smarkm 11392906Smarkm if (cmd[0] == 'S') { 11492906Smarkm if (!(c = strchr(seed = c + 1, ' '))) { 11592906Smarkm#if DEBUG 11692906Smarkm fprintf(stderr, "%s: got bogus seed: %s\n", myname, cmd); 11792906Smarkm#endif /* DEBUG */ 11892906Smarkm goto error; 11992906Smarkm }; 12092906Smarkm 12192906Smarkm *c = 0; 12292906Smarkm 12392906Smarkm if (!(c = strchr(response = c + 1, '\n'))) { 12492906Smarkm#if DEBUG 12592906Smarkm fprintf(stderr, "%s: got bogus response: %s\n", myname, cmd); 12692906Smarkm#endif /* DEBUG */ 12792906Smarkm goto error; 12892906Smarkm }; 12992906Smarkm 13092906Smarkm *c = 0; 13192906Smarkm } else { 13292906Smarkm if (!(c = strchr(seed = c + 1, '\n'))) { 13392906Smarkm#if DEBUG 13492906Smarkm fprintf(stderr, "%s: got bogus seed: %s\n", myname, cmd); 13592906Smarkm#endif /* DEBUG */ 13692906Smarkm goto error; 13792906Smarkm }; 13892906Smarkm 13992906Smarkm *c = 0; 14092906Smarkm }; 14192906Smarkm }; 14292906Smarkm 14392906Smarkm#if DEBUG 14492906Smarkm fprintf(stderr, "got cmd=%c, algorithm=%d sequence=%d seed=+%s+ response=+%s+ on fd %d\n", cmd[0], algorithm, sequence, seed, response, fd); 14592906Smarkm#endif /* DEBUG */ 14692906Smarkm 14792906Smarkm seed = strdup(seed); 14892906Smarkm 14992906Smarkm if (sequence < 10) { 15092906Smarkm#if DEBUG 15192906Smarkm fprintf(stderr, "sequence < 10; can't do it\n"); 15292906Smarkm#endif /* DEBUG */ 15392906Smarkm sprintf(cmd, "%c- %d %d %s\n", cmd[0], algorithm, sequence, seed); 15492906Smarkm }; 15592906Smarkm 15692906Smarkm { 15792906Smarkm struct cachedotp **c; 15892906Smarkm 15992906Smarkm for (c = &head; *c && (strcmp((*c)->seed, seed) || ((*c)->algorithm != algorithm)); c = &((*c)->next)); 16092906Smarkm if (!(*c)) { 16192906Smarkm if (cmd[0] == 's') { 16292906Smarkm#if DEBUG 16392906Smarkm fprintf(stderr, "(seed, algorithm) not found for s command\n"); 16492906Smarkm#endif /* DEBUG */ 16592906Smarkm sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, seed); 16692906Smarkm goto out; 16792906Smarkm } 16892906Smarkm 16992906Smarkm if (!(*c = malloc(sizeof(struct cachedotp)))) 17092906Smarkm baile("malloc"); 17192906Smarkm memset(*c, 0, sizeof(struct cachedotp)); 17292906Smarkm 17392906Smarkm (*c)->algorithm = algorithm; 17492906Smarkm opiestrncpy((*c)->seed, seed, OPIE_SEED_MAX); 17592906Smarkm }; 17692906Smarkm 17792906Smarkm if (cmd[0] == 'S') { 17892906Smarkm (*c)->base = max(sequence - window + 1, OPIE_SEQUENCE_RESTRICT); 17992906Smarkm (*c)->current = sequence; 18092906Smarkm 18192906Smarkm if (!opieatob8(&(*c)->basekey, response)) 18292906Smarkm goto error; 18392906Smarkm 18492906Smarkm sprintf(cmd, "S+ %d %d %s\n", algorithm, sequence, (*c)->seed); 18592906Smarkm } else { 18692906Smarkm if (sequence != ((*c)->current - 1)) { 18792906Smarkm#if DEBUG 18892906Smarkm fprintf(stderr, "out of sequence: sequence=%d, base=%d, current=%d\n", sequence, (*c)->base, (*c)->current); 18992906Smarkm#endif /* DEBUG */ 19092906Smarkm sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, (*c)->seed); 19192906Smarkm goto out; 19292906Smarkm }; 19392906Smarkm 19492906Smarkm if (sequence < (*c)->base) { 19592906Smarkm#if DEBUG 19692906Smarkm fprintf(stderr, "attempt to generate below base: sequence=%d, base=%d, current=%d\n", sequence, (*c)->base, (*c)->current); 19792906Smarkm#endif /* DEBUG */ 19892906Smarkm sprintf(cmd, "s- %d %d %s\n", algorithm, sequence, (*c)->seed); 19992906Smarkm goto out; 20092906Smarkm }; 20192906Smarkm 20292906Smarkm (*c)->current = sequence; 20392906Smarkm i = sequence - (*c)->base; 20492906Smarkm { 20592906Smarkm struct opie_otpkey key; 20692906Smarkm char buffer[16+1]; 20792906Smarkm 20892906Smarkm key = (*c)->basekey; 20992906Smarkm while(i--) 21092906Smarkm opiehash(&key, algorithm); 21192906Smarkm 21292906Smarkm opiebtoa8(buffer, &key); 21392906Smarkm sprintf(cmd, "s+ %d %d %s %s\n", algorithm, sequence, (*c)->seed, buffer); 21492906Smarkm }; 21592906Smarkm }; 21692906Smarkm 21792906Smarkm printf("%c otp-%s %d %s (%d/%d)\n", cmd[0], algids[algorithm], sequence, (*c)->seed, sequence - (*c)->base, window); 21892906Smarkm fflush(stdout); 21992906Smarkm 22092906Smarkm if (sequence == (*c)->base) { 22192906Smarkm struct cachedotp *c2 = *c; 22292906Smarkm *c = (*c)->next; 22392906Smarkm memset(c2, 0, sizeof(struct cachedotp)); 22492906Smarkm free(c2); 22592906Smarkm }; 22692906Smarkm }; 22792906Smarkm 22892906Smarkmout: 22992906Smarkm write(fd, cmd, i = strlen(cmd)); 23092906Smarkm free(seed); 23192906Smarkm return 0; 23292906Smarkm 23392906Smarkmerror: 23492906Smarkm fprintf(stderr, "Invalid command on fd %d\n", fd); 23592906Smarkm if (seed) 23692906Smarkm free(seed); 23792906Smarkm return -1; 23892906Smarkm} 23992906Smarkm 24092906Smarkmstatic void usage() 24192906Smarkm{ 24292906Smarkm fprintf(stderr, "usage: %s [-v] [-h] [-q] [-n <number of OTPs>]\n", myname); 24392906Smarkm exit(1); 24492906Smarkm} 24592906Smarkm 24692906Smarkmint main(int argc, char **argv) 24792906Smarkm{ 24892906Smarkm int i; 24992906Smarkm struct stat st; 25092906Smarkm char *sockpath; 25192906Smarkm 25292906Smarkm if (myname = strrchr(argv[0], '/')) 25392906Smarkm myname++; 25492906Smarkm else 25592906Smarkm myname = argv[0]; 25692906Smarkm 25792906Smarkm while((i = getopt(argc, argv, "w:hv")) != EOF) { 25892906Smarkm switch(i) { 25992906Smarkm case 'v': 26092906Smarkm opieversion(); 26192906Smarkm 26292906Smarkm case 'w': 26392906Smarkm if (!(window = atoi(optarg))) { 26492906Smarkm fprintf(stderr, "%s: invalid number of OTPs: %s\n", myname, optarg); 26592906Smarkm exit(1); 26692906Smarkm }; 26792906Smarkm break; 26892906Smarkm 26992906Smarkm default: 27092906Smarkm usage(); 27192906Smarkm } 27292906Smarkm }; 27392906Smarkm 27492906Smarkm { 27592906Smarkm uid_t myeuid; 27692906Smarkm 27792906Smarkm if (!(myuid = getuid()) || !(myeuid = geteuid()) || (myuid != myeuid)) 27892906Smarkm bail("this program must not be run with superuser priveleges or setuid."); 27992906Smarkm }; 28092906Smarkm 28192906Smarkm if (atexit(zerocache) < 0) 28292906Smarkm baile("atexit"); 28392906Smarkm 28492906Smarkm { 28592906Smarkm struct sockaddr_un sun; 28692906Smarkm 28792906Smarkm memset(&sun, 0, sizeof(struct sockaddr_un)); 28892906Smarkm sun.sun_family = AF_UNIX; 28992906Smarkm 29092906Smarkm { 29192906Smarkm char *c; 29292906Smarkm char *c2 = "/.opieauto"; 29392906Smarkm 29492906Smarkm if (!(c = getenv("HOME"))) 29592906Smarkm bail("getenv(HOME) failed -- no HOME variable?"); 29692906Smarkm 29792906Smarkm if (strlen(c) > (sizeof(sun.sun_path) - strlen(c2) - 1)) 29892906Smarkm bail("your HOME is too long"); 29992906Smarkm 30092906Smarkm strcpy(sun.sun_path, c); 30192906Smarkm strcat(sun.sun_path, c2); 30292906Smarkm sockpath = strdup(sun.sun_path); 30392906Smarkm }; 30492906Smarkm 30592906Smarkm if ((parents = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) 30692906Smarkm baile("socket"); 30792906Smarkm 30892906Smarkm if (unlink(sockpath) && (errno != ENOENT)) 30992906Smarkm baile("unlink"); 31092906Smarkm 31192906Smarkm if (umask(0177) < 0) 31292906Smarkm baile("umask"); 31392906Smarkm 31492906Smarkm if (bind(parents, (struct sockaddr *)&sun, sizeof(struct sockaddr_un))) 31592906Smarkm baile("bind"); 31692906Smarkm 31792906Smarkm if (stat(sockpath, &st) < 0) 31892906Smarkm baile("stat"); 31992906Smarkm 32092906Smarkm if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) 32192906Smarkm bail("socket permissions and/or ownership were not correctly created."); 32292906Smarkm 32392906Smarkm if (listen(parents, 1) < 0) 32492906Smarkm baile("listen"); 32592906Smarkm }; 32692906Smarkm 32792906Smarkm { 32892906Smarkm fd_set fds, rfds, efds; 32992906Smarkm int maxfd = parents; 33092906Smarkm int i, j; 33192906Smarkm 33292906Smarkm FD_ZERO(&fds); 33392906Smarkm FD_SET(parents, &fds); 33492906Smarkm 33592906Smarkm while(1) { 33692906Smarkm memcpy(&rfds, &fds, sizeof(fd_set)); 33792906Smarkm 33892906Smarkm if (select(maxfd + 1, &rfds, NULL, NULL, NULL) < 0) 33992906Smarkm baile("select"); 34092906Smarkm 34192906Smarkm for (i = 0; s[i]; i++) { 34292906Smarkm if (!FD_ISSET(s[i], &rfds)) 34392906Smarkm continue; 34492906Smarkm 34592906Smarkm if (((j = read(s[i], cmd, sizeof(cmd)-1)) <= 0) || ((cmd[j] = 0) || doreq(s[i]))) { 34692906Smarkm close(s[i]); 34792906Smarkm FD_CLR(s[i], &fds); 34892906Smarkm 34992906Smarkm if (s[i] == maxfd) 35092906Smarkm maxfd--; 35192906Smarkm 35292906Smarkm for (j = i; s[j]; s[j] = s[j + 1], j++); 35392906Smarkm FD_SET(parents, &fds); 35492906Smarkm i--; 35592906Smarkm continue; 35692906Smarkm }; 35792906Smarkm }; 35892906Smarkm 35992906Smarkm if (FD_ISSET(parents, &rfds)) { 36092906Smarkm for (i = 0; s[i]; i++) 36192906Smarkm if (i > MAXCLIENTS) 36292906Smarkm bail("this message never printed"); 36392906Smarkm 36492906Smarkm if (stat(sockpath, &st) < 0) 36592906Smarkm baile("stat"); 36692906Smarkm 36792906Smarkm if ((st.st_uid != myuid) || (!S_ISSOCK(st.st_mode)) || ((st.st_mode & 07777) != 0600)) 36892906Smarkm bail("socket permissions and/or ownership has been messed with."); 36992906Smarkm 37092906Smarkm if ((s[i] = accept(parents, NULL, 0)) < 0) 37192906Smarkm baile("accept"); 37292906Smarkm 37392906Smarkm FD_SET(s[i], &fds); 37492906Smarkm if (s[i] > maxfd) 37592906Smarkm maxfd = s[i]; 37692906Smarkm 37792906Smarkm sprintf(cmd, "C+ %d\n", window); 37892906Smarkm if (write(s[i], cmd, j = strlen(cmd)) != j) 37992906Smarkm baile("write"); 38092906Smarkm 38192906Smarkm if (++i == MAXCLIENTS) 38292906Smarkm FD_CLR(parents, &fds); 38392906Smarkm } 38492906Smarkm } 38592906Smarkm } 38692906Smarkm} 387