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