]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/mcookie.c
mcookie: cleanup usage()
[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 <fcntl.h>
25 #include <getopt.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/time.h>
30 #include <unistd.h>
31
32 #define BUFFERSIZE 4096
33
34 struct rngs {
35 const char *path;
36 int minlength, maxlength;
37 } rngs[] = {
38 {"/dev/random", 16, 16}, /* 16 bytes = 128 bits suffice */
39 {"/proc/interrupts", 0, 0},
40 {"/proc/slabinfo", 0, 0},
41 {"/proc/stat", 0, 0},
42 {"/dev/urandom", 32, 64},
43 };
44
45 #define RNGS (sizeof(rngs)/sizeof(struct rngs))
46
47 /* The basic function to hash a file */
48 static off_t hash_file(struct MD5Context *ctx, int fd)
49 {
50 off_t count = 0;
51 ssize_t r;
52 unsigned char buf[BUFFERSIZE];
53
54 while ((r = read(fd, buf, sizeof(buf))) > 0) {
55 MD5Update(ctx, buf, r);
56 count += r;
57 }
58 /* Separate files with a null byte */
59 buf[0] = '\0';
60 MD5Update(ctx, buf, 1);
61 return count;
62 }
63
64 static void __attribute__ ((__noreturn__)) usage(FILE * out)
65 {
66 fputs(_("\nUsage:\n"), out);
67 fprintf(out,
68 _(" %s [options]\n"), program_invocation_short_name);
69
70 fputs(_("\nOptions:\n"), out);
71 fputs(_(" -f, --file <file> use file as a cookie seed\n"
72 " -v, --verbose explain what is being done\n"
73 " -V, --version output version information and exit\n"
74 " -h, --help display this help and exit\n\n"), out);
75
76 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
77 }
78
79 int main(int argc, char **argv)
80 {
81 size_t i;
82 struct MD5Context ctx;
83 unsigned char digest[MD5LENGTH];
84 unsigned char buf[BUFFERSIZE];
85 int fd;
86 int c;
87 pid_t pid;
88 char *file = NULL;
89 int verbose = 0;
90 int r;
91 struct timeval tv;
92 struct timezone tz;
93
94 static const struct option longopts[] = {
95 {"file", required_argument, NULL, 'f'},
96 {"verbose", no_argument, NULL, 'v'},
97 {"version", no_argument, NULL, 'V'},
98 {"help", no_argument, NULL, 'h'},
99 {NULL, 0, NULL, 0}
100 };
101
102 setlocale(LC_ALL, "");
103 bindtextdomain(PACKAGE, LOCALEDIR);
104 textdomain(PACKAGE);
105
106 while ((c =
107 getopt_long(argc, argv, "f:vVh", longopts, NULL)) != -1)
108 switch (c) {
109 case 'v':
110 verbose = 1;
111 break;
112 case 'f':
113 file = optarg;
114 break;
115 case 'V':
116 printf(_("%s from %s\n"),
117 program_invocation_short_name,
118 PACKAGE_STRING);
119 return EXIT_SUCCESS;
120 case 'h':
121 usage(stdout);
122 default:
123 usage(stderr);
124 }
125
126 MD5Init(&ctx);
127 gettimeofday(&tv, &tz);
128 MD5Update(&ctx, (unsigned char *) &tv, sizeof(tv));
129
130 pid = getppid();
131 MD5Update(&ctx, (unsigned char *) &pid, sizeof(pid));
132 pid = getpid();
133 MD5Update(&ctx, (unsigned char *) &pid, sizeof(pid));
134
135 if (file) {
136 int count = 0;
137
138 if (file[0] == '-' && !file[1])
139 fd = STDIN_FILENO;
140 else
141 fd = open(file, O_RDONLY);
142
143 if (fd < 0) {
144 warn(_("Could not open %s"), file);
145 } else {
146 count = hash_file(&ctx, fd);
147 if (verbose)
148 fprintf(stderr,
149 _("Got %d bytes from %s\n"), count,
150 file);
151
152 if (fd != STDIN_FILENO)
153 if (close(fd))
154 err(EXIT_FAILURE,
155 _("closing %s failed"), file);
156 }
157 }
158
159 for (i = 0; i < RNGS; i++) {
160 if ((fd = open(rngs[i].path, O_RDONLY | O_NONBLOCK)) >= 0) {
161 int count = sizeof(buf);
162
163 if (rngs[i].maxlength && count > rngs[i].maxlength)
164 count = rngs[i].maxlength;
165 r = read(fd, buf, count);
166 if (r > 0)
167 MD5Update(&ctx, buf, r);
168 else
169 r = 0;
170 close(fd);
171 if (verbose)
172 fprintf(stderr,
173 _("Got %d bytes from %s\n"), r,
174 rngs[i].path);
175 if (rngs[i].minlength && r >= rngs[i].minlength)
176 break;
177 } else if (verbose)
178 warn(_("Could not open %s"), rngs[i].path);
179 }
180
181 MD5Final(digest, &ctx);
182 for (i = 0; i < MD5LENGTH; i++)
183 printf("%02x", digest[i]);
184 putchar('\n');
185
186 /*
187 * The following is important for cases like disk full,
188 * so shell scripts can bomb out properly rather than
189 * think they succeeded.
190 */
191 if (fflush(stdout) < 0 || fclose(stdout) < 0)
192 return EXIT_FAILURE;
193
194 return EXIT_SUCCESS;
195 }