]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/mcookie.c
docs: cleanup public domain license texts
[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 <stddef.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <sys/time.h>
40 #include <unistd.h>
41
42 enum {
43 BUFFERSIZE = 4096,
44 RAND_BYTES = 128
45 };
46
47 struct mcookie_control {
48 struct UL_MD5Context ctx;
49 char **files;
50 size_t nfiles;
51 uint64_t maxsz;
52
53 unsigned int verbose:1;
54 };
55
56 /* The basic function to hash a file */
57 static uint64_t hash_file(struct mcookie_control *ctl, int fd)
58 {
59 unsigned char buf[BUFFERSIZE];
60 uint64_t wanted, count;
61
62 wanted = ctl->maxsz ? ctl->maxsz : sizeof(buf);
63
64 for (count = 0; count < wanted; ) {
65 size_t rdsz = sizeof(buf);
66 ssize_t r;
67
68 if (wanted - count < rdsz)
69 rdsz = wanted - count;
70
71 r = read_all(fd, (char *) buf, rdsz);
72 if (r <= 0)
73 break;
74 ul_MD5Update(&ctl->ctx, buf, r);
75 count += r;
76 }
77 /* Separate files with a null byte */
78 buf[0] = '\0';
79 ul_MD5Update(&ctl->ctx, buf, 1);
80 return count;
81 }
82
83 static void __attribute__((__noreturn__)) usage(void)
84 {
85 FILE *out = stdout;
86 fputs(USAGE_HEADER, out);
87 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
88
89 fputs(USAGE_SEPARATOR, out);
90 fputs(_("Generate magic cookies for xauth.\n"), out);
91
92 fputs(USAGE_OPTIONS, out);
93 fputs(_(" -f, --file <file> use file as a cookie seed\n"), out);
94 fputs(_(" -m, --max-size <num> limit how much is read from seed files\n"), out);
95 fputs(_(" -v, --verbose explain what is being done\n"), out);
96
97 fputs(USAGE_SEPARATOR, out);
98 fprintf(out, USAGE_HELP_OPTIONS(23));
99
100 fputs(USAGE_ARGUMENTS, out);
101 fprintf(out, USAGE_ARG_SIZE(_("<num>")));
102
103 fprintf(out, USAGE_MAN_TAIL("mcookie(1)"));
104
105 exit(EXIT_SUCCESS);
106 }
107
108 static void randomness_from_files(struct mcookie_control *ctl)
109 {
110 size_t i;
111
112 for (i = 0; i < ctl->nfiles; i++) {
113 const char *fname = ctl->files[i];
114 size_t count;
115 int fd;
116
117 if (*fname == '-' && !*(fname + 1))
118 fd = STDIN_FILENO;
119 else
120 fd = open(fname, O_RDONLY);
121
122 if (fd < 0) {
123 warn(_("cannot open %s"), fname);
124 } else {
125 count = hash_file(ctl, fd);
126 if (ctl->verbose)
127 fprintf(stderr,
128 P_("Got %zu byte from %s\n",
129 "Got %zu bytes from %s\n", count),
130 count, fname);
131
132 if (fd != STDIN_FILENO && close(fd))
133 err(EXIT_FAILURE, _("closing %s failed"), fname);
134 }
135 }
136 }
137
138 int main(int argc, char **argv)
139 {
140 struct mcookie_control ctl = { .verbose = 0 };
141 size_t i;
142 unsigned char digest[UL_MD5LENGTH];
143 unsigned char buf[RAND_BYTES];
144 int c;
145
146 static const struct option longopts[] = {
147 {"file", required_argument, NULL, 'f'},
148 {"max-size", required_argument, NULL, 'm'},
149 {"verbose", no_argument, NULL, 'v'},
150 {"version", no_argument, NULL, 'V'},
151 {"help", no_argument, NULL, 'h'},
152 {NULL, 0, NULL, 0}
153 };
154
155 setlocale(LC_ALL, "");
156 bindtextdomain(PACKAGE, LOCALEDIR);
157 textdomain(PACKAGE);
158 close_stdout_atexit();
159
160 while ((c = getopt_long(argc, argv, "f:m:vVh", longopts, NULL)) != -1) {
161 switch (c) {
162 case 'v':
163 ctl.verbose = 1;
164 break;
165 case 'f':
166 if (!ctl.files)
167 ctl.files = xmalloc(sizeof(char *) * argc);
168 ctl.files[ctl.nfiles++] = optarg;
169 break;
170 case 'm':
171 ctl.maxsz = strtosize_or_err(optarg,
172 _("failed to parse length"));
173 break;
174
175 case 'V':
176 print_version(EXIT_SUCCESS);
177 case 'h':
178 usage();
179 default:
180 errtryhelp(EXIT_FAILURE);
181 }
182 }
183
184 if (ctl.maxsz && ctl.nfiles == 0)
185 warnx(_("--max-size ignored when used without --file"));
186
187 ul_MD5Init(&ctl.ctx);
188 randomness_from_files(&ctl);
189 free(ctl.files);
190
191 ul_random_get_bytes(&buf, RAND_BYTES);
192 ul_MD5Update(&ctl.ctx, buf, RAND_BYTES);
193 if (ctl.verbose)
194 fprintf(stderr, P_("Got %d byte from %s\n",
195 "Got %d bytes from %s\n", RAND_BYTES),
196 RAND_BYTES, random_tell_source());
197
198 ul_MD5Final(digest, &ctl.ctx);
199 for (i = 0; i < UL_MD5LENGTH; i++)
200 printf("%02x", digest[i]);
201 putchar('\n');
202
203 return EXIT_SUCCESS;
204 }