# # Better yet -- replace ad hoc file-based database with sqlite3. # --- otpw/conf.h.bak 2003-10-06 17:47:30.000000000 +0300 +++ otpw/conf.h 2007-11-22 02:18:26.022516231 +0200 @@ -10,29 +10,6 @@ #define OTPW_CONF_H /* - * List of shell commands that produce high entropy output. - * The output of all these commands will be hashed together with - * timing information to seed the random number generator - */ - -#define ENTROPY_CMDS \ -"head -c 20 /dev/urandom 2>&1", \ -"ls -lu /etc/. /tmp/. / /usr/. /bin/. /usr/bin/.", \ -"PATH=/usr/ucb:/bin:/usr/bin;ps lax", \ -"last | head -50", \ -"uptime;netstat -n;hostname;date;w", \ -"cd $HOME; cat .pgp/randseed.bin .ssh/random_seed .otpw 2>&1" -/* too slow: "PATH=/usr/bin/X11/;xwd -root -silent 2>&1||xwd -root 2>&1" */ - -/* - * Environment variable settings for the entropy generating - * shell commands - */ - -#define ENTROPY_ENV \ -"PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc:/usr/ucb" - -/* * Path for the one-time password file. Pathnames not starting with * a slash will be relative to the user's home directory. */ @@ -43,7 +20,20 @@ * Path for the temporary version of OTPW_FILE (needed for atomicity) */ -#define OTPW_TMP ".otpw.tmp" +static char OTPW_TMP[] __attribute__((unused)) = ".otpw.tmp.XXXXXX"; + +/* These chars accepted in password */ +static const unsigned char validchar[256] = { + ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, + ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, + ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, + ['y'] = 1, ['z'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, + ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, + ['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, + ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, + ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, + [':'] = 1, ['%'] = 1, ['='] = 1, ['+'] = 1, ['/'] = 1, +}; /* * Path for the one-time password lock symlink. --- otpw/Makefile.bak 2003-10-06 17:47:30.000000000 +0300 +++ otpw/Makefile 2007-11-22 02:11:39.125807778 +0200 @@ -9,16 +9,17 @@ VERSION=1.3 CC=gcc -CFLAGS=-O -ggdb -W -Wall +#ARCHFLAGS=-m32 +CFLAGS=-O2 -fPIC -pie -ggdb -W -Wall $(ARCHFLAGS) TARGETS=otpw-gen demologin pam_otpw.so all: $(TARGETS) otpw-gen: otpw-gen.o rmd160.o md.o - $(CC) -o $@ $+ + $(CC) $(CFLAGS) -o $@ $+ -lrt demologin: demologin.o otpw.o rmd160.o md.o - $(CC) -o $@ $+ -lcrypt + $(CC) $(CFLAGS) -o $@ $+ -lcrypt -lrt otpw-gen.o: otpw-gen.c md.h conf.h otpw.o: otpw.c otpw.h md.h conf.h @@ -27,7 +28,7 @@ rmd160.o: rmd160.c rmd160.h otpw-l.o: otpw-l.c otpw.c otpw.h md.h conf.h pam_otpw.o: pam_otpw.c otpw.h md.h conf.h pam_otpw.so: pam_otpw.o otpw-l.o rmd160.o md.o - ld --shared -o $@ $+ -lcrypt -lpam -lpam_misc + $(CC) -shared -Wl,-E -Wl,-soname,$@ -o $@ $+ -lcrypt -lpam -lpam_misc -lrt $(ARCHFLAGS) ship: all clean ci -sRel -l RCS/* --- otpw/otpw.c.bak 2003-10-06 17:47:30.000000000 +0300 +++ otpw/otpw.c 2007-11-22 02:16:25.989357775 +0200 @@ -45,7 +45,7 @@ void rbg_seed(unsigned char *r) pid_t pid; uid_t uid; pid_t ppid; - struct timeval t; + struct timespec tsp; } entropy; md_init(&md); @@ -63,7 +63,7 @@ void rbg_seed(unsigned char *r) entropy.uid = getuid(); entropy.pid = getpid(); entropy.ppid = getppid(); - gettimeofday(&entropy.t, NULL); + clock_gettime(CLOCK_REALTIME, &entropy.tsp); md_add(&md, (unsigned char *) &entropy, sizeof(entropy)); md_close(&md, r); @@ -73,11 +73,11 @@ void rbg_seed(unsigned char *r) void rbg_iter(unsigned char *r) { md_state md; - struct timeval t; + struct timespec tsp; md_init(&md); - gettimeofday(&t, NULL); - md_add(&md, (unsigned char *) &t, sizeof(t)); + clock_gettime(CLOCK_REALTIME, &tsp); + md_add(&md, (unsigned char *) &tsp, sizeof(tsp)); md_add(&md, r, MD_LEN); md_add(&md, "AutomaGic", 9); /* feel free to change this as a site key */ md_close(&md, r); @@ -382,14 +382,7 @@ int otpw_verify(struct challenge *ch, ch otpw[i*ch->pwlen + j] = 'O'; else if (password[l] == '\\') otpw[i*ch->pwlen + j] = '/'; - else if ((password[l] >= 'A' && password[l] <= 'Z') || - (password[l] >= 'a' && password[l] <= 'z') || - (password[l] >= '2' && password[l] <= '9') || - password[l] == ':' || - password[l] == '%' || - password[l] == '=' || - password[l] == '+' || - password[l] == '/') + else if (validchar[(unsigned char)password[l]]) otpw[i*ch->pwlen + j] = password[l]; l--; } --- otpw/otpw-gen.c.bak 2003-10-06 17:47:30.000000000 +0300 +++ otpw/otpw-gen.c 2007-11-22 02:17:55.593715592 +0200 @@ -21,6 +21,8 @@ static char const rcsid[] = #include #include #include +#include + #include "conf.h" #include "md.h" @@ -248,39 +250,6 @@ char word[2048][4] = { int debug = 0; -/* add the output and time of a shell command to message digest */ - -void gurgle(md_state *mdp, char *command) -{ - FILE *f; - char buf[128]; - long len = 0, l; - struct timeval t; - - f = popen(command, "r"); - gettimeofday(&t, NULL); - md_add(mdp, (unsigned char *) &t, sizeof(t)); - if (!f) { - fprintf(stderr, "External entropy source command '%s'\n" - "(one of several) failed.\n", command); - return; - } - while (!feof(f) && !ferror(f)) { - len += l = fread(buf, 1, sizeof(buf), f); - md_add(mdp, buf, l); - } - if (len == 0) - fprintf(stderr, "External entropy source command '%s'\n" - "returned no output.\n", command); - else - if (debug) - fprintf(stderr, "'%s' added %ld bytes.\n", command, len); - pclose(f); - gettimeofday(&t, NULL); - md_add(mdp, (unsigned char *) &t, sizeof(t)); -} - - /* A random bit generator. Hashes together various sources of entropy * to provide a 16 byte high quality random seed */ @@ -288,38 +257,39 @@ void gurgle(md_state *mdp, char *command void rbg_seed(unsigned char *r) { - /* shell commands that provide high entropy output for RNG */ - char *entropy_cmds[] = { - ENTROPY_CMDS - }; - char *entropy_env[] = { - ENTROPY_ENV - }; - unsigned i; md_state md; struct { clock_t clk; pid_t pid; uid_t uid; pid_t ppid; + struct timespec tsp; } entropy; - - md_init(&md); + FILE *rndfile; - /* get entropy via some shell commands */ - for (i = 0; i < sizeof(entropy_env)/sizeof(char*); i++) - putenv(entropy_env[i]); - for (i = 0; i < sizeof(entropy_cmds)/sizeof(char*); i++) - gurgle(&md, entropy_cmds[i]); + md_init(&md); - /* other minor sources of entropy */ + /* minor sources of entropy */ entropy.clk = clock(); entropy.uid = getuid(); entropy.pid = getpid(); entropy.ppid = getppid(); - + clock_gettime(CLOCK_REALTIME, &entropy.tsp); md_add(&md, (unsigned char *) &entropy, sizeof(entropy)); + rndfile = fopen("/dev/urandom", "r"); + if (rndfile == NULL) + rndfile = fopen("/dev/random", "r"); + if (rndfile != NULL) { + char rndbuf[64]; + + setbuf(rndfile, NULL); + if (fread(rndbuf, sizeof(rndbuf), 1, rndfile) == 1) + md_add(&md, rndbuf, sizeof(rndbuf)); + memset(rndbuf, 0, sizeof(rndbuf)); + fclose(rndfile); + } + md_close(&md, r); } @@ -329,11 +299,13 @@ void rbg_seed(unsigned char *r) void rbg_iter(unsigned char *r) { md_state md; - struct timeval t; + struct timespec tsp; md_init(&md); - gettimeofday(&t, NULL); - md_add(&md, (unsigned char *) &t, sizeof(t)); + clock_gettime(CLOCK_REALTIME, &tsp); + md_add(&md, (unsigned char *) &tsp, sizeof(tsp)); + clock_gettime(CLOCK_MONOTONIC, &tsp); + md_add(&md, (unsigned char *) &tsp, sizeof(tsp)); md_add(&md, r, MD_LEN); md_add(&md, "AutomaGic", 9); /* feel free to change this as a site key */ md_close(&md, r); @@ -381,14 +353,7 @@ void pwnorm(char *password) { *dst++ = 'O'; else if (*src == '\\') *dst++ = '/'; - else if ((*src >= 'A' && *src <= 'Z') || - (*src >= 'a' && *src <= 'z') || - (*src >= '2' && *src <= '9') || - *src == ':' || - *src == '%' || - *src == '=' || - *src == '+' || - *src == '/') + else if (validchar[(unsigned char)*src]) *dst++ = *src; else if (*src == '\0') { *dst++ = *src; @@ -529,6 +494,8 @@ int main(int argc, char **argv) int cols; time_t t; char *hbuf; + int saved_errno; + int fd; assert(md_selftest() == 0); assert(OTPW_HLEN * 6 < MD_LEN * 8); @@ -714,9 +681,16 @@ int main(int argc, char **argv) password1[strlen(password1)-1] = 0; fprintf(stderr, "\n\nCreating '%s%s'.\n", fnoutp, fnout); - f = fopen(OTPW_TMP, "w"); + fd = mkstemp(OTPW_TMP); + if (fd == -1) { + fprintf(stderr, "Can't create temporary file '%s", OTPW_TMP); + perror("'"); + exit(1); + } + + f = fdopen(fd, "w"); if (!f) { - fprintf(stderr, "Can't write to '" OTPW_TMP); + fprintf(stderr, "Can't fdopen '%s", OTPW_TMP); perror("'"); exit(1); } @@ -787,15 +761,42 @@ int main(int argc, char **argv) memcpy(hbuf + i*HBUFLEN, hbuf + k*HBUFLEN, HBUFLEN); } - fclose(f); + if (fflush(f) == EOF) { + saved_errno = errno; + fprintf(stderr, "Can't fflush '%s", OTPW_TMP); + errno = saved_errno; + perror("'"); + exit(1); + } + + if (fsync(fileno(f)) == -1) { + saved_errno = errno; + fprintf(stderr, "Can't fsync '%s", OTPW_TMP); + errno = saved_errno; + perror("'"); + exit(1); + } + + if (fclose(f) == EOF) { + saved_errno = errno; + fprintf(stderr, "Can't fclose '%s", OTPW_TMP); + errno = saved_errno; + perror("'"); + exit(1); + } + if (rename(OTPW_TMP, fnout)) { - fprintf(stderr, "Can't rename '" OTPW_TMP "' to '%s", fnout); + saved_errno = errno; + fprintf(stderr, "Can't rename '%s' to '%s", OTPW_TMP, fnout); + errno = saved_errno; perror("'"); exit(1); } + /* if we overwrite OTPW_FILE, then any remaining lock is now meaningless */ if (pwd) unlink(OTPW_LOCK); return 0; } +