]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/mcookie.c
c837fb39ce9e828b6d1dc0f83d6c237cba801b32
[thirdparty/util-linux.git] / misc-utils / mcookie.c
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 }