| /* mcookie.c -- Generates random numbers for xauth |
| * Created: Fri Feb 3 10:42:48 1995 by faith@cs.unc.edu |
| * Revised: Fri Mar 19 07:48:01 1999 by faith@acm.org |
| * Public Domain 1995, 1999 Rickard E. Faith (faith@acm.org) |
| * This program comes with ABSOLUTELY NO WARRANTY. |
| * |
| * This program gathers some random bits of data and used the MD5 |
| * message-digest algorithm to generate a 128-bit hexadecimal number for |
| * use with xauth(1). |
| * |
| * NOTE: Unless /dev/random is available, this program does not actually |
| * gather 128 bits of random information, so the magic cookie generated |
| * will be considerably easier to guess than one might expect. |
| * |
| * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> |
| * - added Native Language Support |
| * 1999-03-21 aeb: Added some fragments of code from Colin Plumb. |
| * |
| */ |
| |
| #include "c.h" |
| #include "md5.h" |
| #include "nls.h" |
| #include "closestream.h" |
| #include "randutils.h" |
| #include "strutils.h" |
| #include "xalloc.h" |
| #include "all-io.h" |
| |
| #include <fcntl.h> |
| #include <getopt.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/time.h> |
| #include <unistd.h> |
| |
| enum { |
| BUFFERSIZE = 4096, |
| RAND_BYTES = 128 |
| }; |
| |
| struct mcookie_control { |
| struct UL_MD5Context ctx; |
| char **files; |
| size_t nfiles; |
| uint64_t maxsz; |
| |
| unsigned int verbose:1; |
| }; |
| |
| /* The basic function to hash a file */ |
| static uint64_t hash_file(struct mcookie_control *ctl, int fd) |
| { |
| unsigned char buf[BUFFERSIZE]; |
| uint64_t wanted, count; |
| |
| wanted = ctl->maxsz ? ctl->maxsz : sizeof(buf); |
| |
| for (count = 0; count < wanted; ) { |
| size_t rdsz = sizeof(buf); |
| ssize_t r; |
| |
| if (wanted - count < rdsz) |
| rdsz = wanted - count; |
| |
| r = read_all(fd, (char *) buf, rdsz); |
| if (r < 0) |
| break; |
| ul_MD5Update(&ctl->ctx, buf, r); |
| count += r; |
| } |
| /* Separate files with a null byte */ |
| buf[0] = '\0'; |
| ul_MD5Update(&ctl->ctx, buf, 1); |
| return count; |
| } |
| |
| static void __attribute__((__noreturn__)) usage(void) |
| { |
| FILE *out = stdout; |
| fputs(USAGE_HEADER, out); |
| fprintf(out, _(" %s [options]\n"), program_invocation_short_name); |
| |
| fputs(USAGE_SEPARATOR, out); |
| fputs(_("Generate magic cookies for xauth.\n"), out); |
| |
| fputs(USAGE_OPTIONS, out); |
| fputs(_(" -f, --file <file> use file as a cookie seed\n"), out); |
| fputs(_(" -m, --max-size <num> limit how much is read from seed files\n"), out); |
| fputs(_(" -v, --verbose explain what is being done\n"), out); |
| |
| fputs(USAGE_SEPARATOR, out); |
| printf(USAGE_HELP_OPTIONS(23)); |
| printf(USAGE_MAN_TAIL("mcookie(1)")); |
| |
| exit(EXIT_SUCCESS); |
| } |
| |
| static void randomness_from_files(struct mcookie_control *ctl) |
| { |
| size_t i; |
| |
| for (i = 0; i < ctl->nfiles; i++) { |
| const char *fname = ctl->files[i]; |
| size_t count; |
| int fd; |
| |
| if (*fname == '-' && !*(fname + 1)) |
| fd = STDIN_FILENO; |
| else |
| fd = open(fname, O_RDONLY); |
| |
| if (fd < 0) { |
| warn(_("cannot open %s"), fname); |
| } else { |
| count = hash_file(ctl, fd); |
| if (ctl->verbose) |
| fprintf(stderr, |
| P_("Got %zu byte from %s\n", |
| "Got %zu bytes from %s\n", count), |
| count, fname); |
| |
| if (fd != STDIN_FILENO && close(fd)) |
| err(EXIT_FAILURE, _("closing %s failed"), fname); |
| } |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| struct mcookie_control ctl = { .verbose = 0 }; |
| size_t i; |
| unsigned char digest[UL_MD5LENGTH]; |
| unsigned char buf[RAND_BYTES]; |
| int c; |
| |
| static const struct option longopts[] = { |
| {"file", required_argument, NULL, 'f'}, |
| {"max-size", required_argument, NULL, 'm'}, |
| {"verbose", no_argument, NULL, 'v'}, |
| {"version", no_argument, NULL, 'V'}, |
| {"help", no_argument, NULL, 'h'}, |
| {NULL, 0, NULL, 0} |
| }; |
| |
| setlocale(LC_ALL, ""); |
| bindtextdomain(PACKAGE, LOCALEDIR); |
| textdomain(PACKAGE); |
| atexit(close_stdout); |
| |
| while ((c = getopt_long(argc, argv, "f:m:vVh", longopts, NULL)) != -1) { |
| switch (c) { |
| case 'v': |
| ctl.verbose = 1; |
| break; |
| case 'f': |
| if (!ctl.files) |
| ctl.files = xmalloc(sizeof(char *) * argc); |
| ctl.files[ctl.nfiles++] = optarg; |
| break; |
| case 'm': |
| ctl.maxsz = strtosize_or_err(optarg, |
| _("failed to parse length")); |
| break; |
| case 'V': |
| printf(UTIL_LINUX_VERSION); |
| return EXIT_SUCCESS; |
| case 'h': |
| usage(); |
| default: |
| errtryhelp(EXIT_FAILURE); |
| } |
| } |
| |
| if (ctl.maxsz && ctl.nfiles == 0) |
| warnx(_("--max-size ignored when used without --file")); |
| |
| ul_MD5Init(&ctl.ctx); |
| randomness_from_files(&ctl); |
| free(ctl.files); |
| |
| random_get_bytes(&buf, RAND_BYTES); |
| ul_MD5Update(&ctl.ctx, buf, RAND_BYTES); |
| if (ctl.verbose) |
| fprintf(stderr, P_("Got %d byte from %s\n", |
| "Got %d bytes from %s\n", RAND_BYTES), |
| RAND_BYTES, random_tell_source()); |
| |
| ul_MD5Final(digest, &ctl.ctx); |
| for (i = 0; i < UL_MD5LENGTH; i++) |
| printf("%02x", digest[i]); |
| putchar('\n'); |
| |
| return EXIT_SUCCESS; |
| } |