]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/mcookie.c
Merge branch 'refactor-tests' of https://github.com/Ajchler/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
96 fputs(USAGE_ARGUMENTS, out);
97 printf(USAGE_ARG_SIZE(_("<num>")));
98
99 printf(USAGE_MAN_TAIL("mcookie(1)"));
100
101 exit(EXIT_SUCCESS);
102 }
103
104 static void randomness_from_files(struct mcookie_control *ctl)
105 {
106 size_t i;
107
108 for (i = 0; i < ctl->nfiles; i++) {
109 const char *fname = ctl->files[i];
110 size_t count;
111 int fd;
112
113 if (*fname == '-' && !*(fname + 1))
114 fd = STDIN_FILENO;
115 else
116 fd = open(fname, O_RDONLY);
117
118 if (fd < 0) {
119 warn(_("cannot open %s"), fname);
120 } else {
121 count = hash_file(ctl, fd);
122 if (ctl->verbose)
123 fprintf(stderr,
124 P_("Got %zu byte from %s\n",
125 "Got %zu bytes from %s\n", count),
126 count, fname);
127
128 if (fd != STDIN_FILENO && close(fd))
129 err(EXIT_FAILURE, _("closing %s failed"), fname);
130 }
131 }
132 }
133
134 int main(int argc, char **argv)
135 {
136 struct mcookie_control ctl = { .verbose = 0 };
137 size_t i;
138 unsigned char digest[UL_MD5LENGTH];
139 unsigned char buf[RAND_BYTES];
140 int c;
141
142 static const struct option longopts[] = {
143 {"file", required_argument, NULL, 'f'},
144 {"max-size", required_argument, NULL, 'm'},
145 {"verbose", no_argument, NULL, 'v'},
146 {"version", no_argument, NULL, 'V'},
147 {"help", no_argument, NULL, 'h'},
148 {NULL, 0, NULL, 0}
149 };
150
151 setlocale(LC_ALL, "");
152 bindtextdomain(PACKAGE, LOCALEDIR);
153 textdomain(PACKAGE);
154 close_stdout_atexit();
155
156 while ((c = getopt_long(argc, argv, "f:m:vVh", longopts, NULL)) != -1) {
157 switch (c) {
158 case 'v':
159 ctl.verbose = 1;
160 break;
161 case 'f':
162 if (!ctl.files)
163 ctl.files = xmalloc(sizeof(char *) * argc);
164 ctl.files[ctl.nfiles++] = optarg;
165 break;
166 case 'm':
167 ctl.maxsz = strtosize_or_err(optarg,
168 _("failed to parse length"));
169 break;
170
171 case 'V':
172 print_version(EXIT_SUCCESS);
173 case 'h':
174 usage();
175 default:
176 errtryhelp(EXIT_FAILURE);
177 }
178 }
179
180 if (ctl.maxsz && ctl.nfiles == 0)
181 warnx(_("--max-size ignored when used without --file"));
182
183 ul_MD5Init(&ctl.ctx);
184 randomness_from_files(&ctl);
185 free(ctl.files);
186
187 ul_random_get_bytes(&buf, RAND_BYTES);
188 ul_MD5Update(&ctl.ctx, buf, RAND_BYTES);
189 if (ctl.verbose)
190 fprintf(stderr, P_("Got %d byte from %s\n",
191 "Got %d bytes from %s\n", RAND_BYTES),
192 RAND_BYTES, random_tell_source());
193
194 ul_MD5Final(digest, &ctl.ctx);
195 for (i = 0; i < UL_MD5LENGTH; i++)
196 printf("%02x", digest[i]);
197 putchar('\n');
198
199 return EXIT_SUCCESS;
200 }