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