]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * No copyright is claimed. This code is in the public domain; do with | |
3 | * it what you wish. | |
4 | * | |
5 | * mcookie.c -- Generates random numbers for xauth | |
6 | * Created: Fri Feb 3 10:42:48 1995 by faith@cs.unc.edu | |
7 | * Revised: Fri Mar 19 07:48:01 1999 by faith@acm.org | |
8 | * Public Domain 1995, 1999 Rickard E. Faith (faith@acm.org) | |
9 | * This program comes with ABSOLUTELY NO WARRANTY. | |
10 | * | |
11 | * This program gathers some random bits of data and used the MD5 | |
12 | * message-digest algorithm to generate a 128-bit hexadecimal number for | |
13 | * use with xauth(1). | |
14 | * | |
15 | * NOTE: Unless /dev/random is available, this program does not actually | |
16 | * gather 128 bits of random information, so the magic cookie generated | |
17 | * will be considerably easier to guess than one might expect. | |
18 | * | |
19 | * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> | |
20 | * - added Native Language Support | |
21 | * 1999-03-21 aeb: Added some fragments of code from Colin Plumb. | |
22 | * | |
23 | */ | |
24 | ||
25 | #include "c.h" | |
26 | #include "md5.h" | |
27 | #include "nls.h" | |
28 | #include "closestream.h" | |
29 | #include "randutils.h" | |
30 | #include "strutils.h" | |
31 | #include "xalloc.h" | |
32 | #include "all-io.h" | |
33 | ||
34 | #include <fcntl.h> | |
35 | #include <getopt.h> | |
36 | #include <stdbool.h> | |
37 | #include <stddef.h> | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <sys/time.h> | |
41 | #include <unistd.h> | |
42 | ||
43 | enum { | |
44 | BUFFERSIZE = 4096, | |
45 | RAND_BYTES = 128 | |
46 | }; | |
47 | ||
48 | struct mcookie_control { | |
49 | struct UL_MD5Context ctx; | |
50 | char **files; | |
51 | size_t nfiles; | |
52 | uint64_t maxsz; | |
53 | ||
54 | bool verbose; | |
55 | }; | |
56 | ||
57 | /* The basic function to hash a file */ | |
58 | static uint64_t hash_file(struct mcookie_control *ctl, int fd) | |
59 | { | |
60 | unsigned char buf[BUFFERSIZE]; | |
61 | uint64_t wanted, count; | |
62 | ||
63 | wanted = ctl->maxsz ? ctl->maxsz : sizeof(buf); | |
64 | ||
65 | for (count = 0; count < wanted; ) { | |
66 | size_t rdsz = sizeof(buf); | |
67 | ssize_t r; | |
68 | ||
69 | if (wanted - count < rdsz) | |
70 | rdsz = wanted - count; | |
71 | ||
72 | r = read_all(fd, (char *) buf, rdsz); | |
73 | if (r <= 0) | |
74 | break; | |
75 | ul_MD5Update(&ctl->ctx, buf, r); | |
76 | count += r; | |
77 | } | |
78 | /* Separate files with a null byte */ | |
79 | buf[0] = '\0'; | |
80 | ul_MD5Update(&ctl->ctx, buf, 1); | |
81 | return count; | |
82 | } | |
83 | ||
84 | static void __attribute__((__noreturn__)) usage(void) | |
85 | { | |
86 | FILE *out = stdout; | |
87 | fputs(USAGE_HEADER, out); | |
88 | fprintf(out, _(" %s [options]\n"), program_invocation_short_name); | |
89 | ||
90 | fputs(USAGE_SEPARATOR, out); | |
91 | fputs(_("Generate magic cookies for xauth.\n"), out); | |
92 | ||
93 | fputs(USAGE_OPTIONS, out); | |
94 | fputs(_(" -f, --file <file> use file as a cookie seed\n"), out); | |
95 | fputs(_(" -m, --max-size <num> limit how much is read from seed files\n"), out); | |
96 | fputs(_(" -v, --verbose explain what is being done\n"), out); | |
97 | ||
98 | fputs(USAGE_SEPARATOR, out); | |
99 | fprintf(out, USAGE_HELP_OPTIONS(23)); | |
100 | ||
101 | fputs(USAGE_ARGUMENTS, out); | |
102 | fprintf(out, USAGE_ARG_SIZE(_("<num>"))); | |
103 | ||
104 | fprintf(out, USAGE_MAN_TAIL("mcookie(1)")); | |
105 | ||
106 | exit(EXIT_SUCCESS); | |
107 | } | |
108 | ||
109 | static void randomness_from_files(struct mcookie_control *ctl) | |
110 | { | |
111 | size_t i; | |
112 | ||
113 | for (i = 0; i < ctl->nfiles; i++) { | |
114 | const char *fname = ctl->files[i]; | |
115 | size_t count; | |
116 | int fd; | |
117 | ||
118 | if (*fname == '-' && !*(fname + 1)) | |
119 | fd = STDIN_FILENO; | |
120 | else | |
121 | fd = open(fname, O_RDONLY); | |
122 | ||
123 | if (fd < 0) { | |
124 | warn(_("cannot open %s"), fname); | |
125 | } else { | |
126 | count = hash_file(ctl, fd); | |
127 | if (ctl->verbose) | |
128 | fprintf(stderr, | |
129 | P_("Got %zu byte from %s\n", | |
130 | "Got %zu bytes from %s\n", count), | |
131 | count, fname); | |
132 | ||
133 | if (fd != STDIN_FILENO && close(fd)) | |
134 | err(EXIT_FAILURE, _("closing %s failed"), fname); | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | int main(int argc, char **argv) | |
140 | { | |
141 | struct mcookie_control ctl = { .verbose = 0 }; | |
142 | size_t i; | |
143 | unsigned char digest[UL_MD5LENGTH]; | |
144 | unsigned char buf[RAND_BYTES]; | |
145 | int c; | |
146 | ||
147 | static const struct option longopts[] = { | |
148 | {"file", required_argument, NULL, 'f'}, | |
149 | {"max-size", required_argument, NULL, 'm'}, | |
150 | {"verbose", no_argument, NULL, 'v'}, | |
151 | {"version", no_argument, NULL, 'V'}, | |
152 | {"help", no_argument, NULL, 'h'}, | |
153 | {NULL, 0, NULL, 0} | |
154 | }; | |
155 | ||
156 | setlocale(LC_ALL, ""); | |
157 | bindtextdomain(PACKAGE, LOCALEDIR); | |
158 | textdomain(PACKAGE); | |
159 | close_stdout_atexit(); | |
160 | ||
161 | while ((c = getopt_long(argc, argv, "f:m:vVh", longopts, NULL)) != -1) { | |
162 | switch (c) { | |
163 | case 'v': | |
164 | ctl.verbose = 1; | |
165 | break; | |
166 | case 'f': | |
167 | if (!ctl.files) | |
168 | ctl.files = xmalloc(sizeof(char *) * argc); | |
169 | ctl.files[ctl.nfiles++] = optarg; | |
170 | break; | |
171 | case 'm': | |
172 | ctl.maxsz = strtosize_or_err(optarg, | |
173 | _("failed to parse length")); | |
174 | break; | |
175 | ||
176 | case 'V': | |
177 | print_version(EXIT_SUCCESS); | |
178 | case 'h': | |
179 | usage(); | |
180 | default: | |
181 | errtryhelp(EXIT_FAILURE); | |
182 | } | |
183 | } | |
184 | ||
185 | if (ctl.maxsz && ctl.nfiles == 0) | |
186 | warnx(_("--max-size ignored when used without --file")); | |
187 | ||
188 | ul_MD5Init(&ctl.ctx); | |
189 | randomness_from_files(&ctl); | |
190 | free(ctl.files); | |
191 | ||
192 | ul_random_get_bytes(&buf, RAND_BYTES); | |
193 | ul_MD5Update(&ctl.ctx, buf, RAND_BYTES); | |
194 | if (ctl.verbose) | |
195 | fprintf(stderr, P_("Got %d byte from %s\n", | |
196 | "Got %d bytes from %s\n", RAND_BYTES), | |
197 | RAND_BYTES, random_tell_source()); | |
198 | ||
199 | ul_MD5Final(digest, &ctl.ctx); | |
200 | for (i = 0; i < UL_MD5LENGTH; i++) | |
201 | printf("%02x", digest[i]); | |
202 | putchar('\n'); | |
203 | ||
204 | return EXIT_SUCCESS; | |
205 | } |