xref: /netbsd/sbin/rndctl/rndctl.c (revision bf9ec67e)
1 /*	$NetBSD: rndctl.c,v 1.12 2002/05/19 09:47:10 enami Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 Michael Graff.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the author nor the names of other contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <sys/rnd.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <err.h>
42 #include <string.h>
43 
44 typedef struct {
45 	char *a_name;
46 	u_int32_t a_type;
47 } arg_t;
48 
49 arg_t source_types[] = {
50 	{ "???",     RND_TYPE_UNKNOWN },
51 	{ "disk",    RND_TYPE_DISK },
52 	{ "net",     RND_TYPE_NET },
53 	{ "net",     RND_TYPE_NET },
54 	{ "tape",    RND_TYPE_TAPE },
55 	{ "tty",     RND_TYPE_TTY },
56 	{ "rng",     RND_TYPE_RNG },
57 	{ NULL,      0 }
58 };
59 
60 static void usage(void);
61 u_int32_t find_type(char *name);
62 char *find_name(u_int32_t);
63 void do_ioctl(rndctl_t *);
64 char * strflags(u_int32_t);
65 void do_list(int, u_int32_t, char *);
66 void do_stats(void);
67 
68 static void
69 usage(void)
70 {
71 
72 	fprintf(stderr, "usage: %s -CEce [-t devtype] [-d devname]\n",
73 	    getprogname());
74 	fprintf(stderr, "       %s -ls [-t devtype] [-d devname]\n",
75 	    getprogname());
76 	exit(1);
77 }
78 
79 u_int32_t
80 find_type(char *name)
81 {
82 	arg_t *a;
83 
84 	a = source_types;
85 
86 	while (a->a_name != NULL) {
87 		if (strcmp(a->a_name, name) == 0)
88 			return (a->a_type);
89 		a++;
90 	}
91 
92 	errx(1, "device name %s unknown", name);
93 	return (0);
94 }
95 
96 char *
97 find_name(u_int32_t type)
98 {
99 	arg_t *a;
100 
101 	a = source_types;
102 
103 	while (a->a_name != NULL) {
104 		if (type == a->a_type)
105 			return (a->a_name);
106 		a++;
107 	}
108 
109 	warnx("device type %u unknown", type);
110 	return ("???");
111 }
112 
113 void
114 do_ioctl(rndctl_t *rctl)
115 {
116 	int fd;
117 	int res;
118 
119 	fd = open("/dev/urandom", O_RDONLY, 0644);
120 	if (fd < 0)
121 		err(1, "open");
122 
123 	res = ioctl(fd, RNDCTL, rctl);
124 	if (res < 0)
125 		err(1, "ioctl(RNDCTL)");
126 
127 	close(fd);
128 }
129 
130 char *
131 strflags(u_int32_t fl)
132 {
133 	static char str[512];
134 
135 	str[0] = 0;
136 	if (fl & RND_FLAG_NO_ESTIMATE)
137 		;
138 	else
139 		strcat(str, "estimate");
140 
141 	if (fl & RND_FLAG_NO_COLLECT)
142 		;
143 	else {
144 		if (str[0])
145 			strcat(str, ", ");
146 		strcat(str, "collect");
147 	}
148 
149 	return (str);
150 }
151 
152 #define HEADER "Source                 Bits Type      Flags\n"
153 
154 void
155 do_list(int all, u_int32_t type, char *name)
156 {
157 	rndstat_t rstat;
158 	rndstat_name_t rstat_name;
159 	int fd;
160 	int res;
161 	u_int32_t start;
162 
163 	fd = open("/dev/urandom", O_RDONLY, 0644);
164 	if (fd < 0)
165 		err(1, "open");
166 
167 	if (all == 0 && type == 0xff) {
168 		strncpy(rstat_name.name, name, 16);
169 		res = ioctl(fd, RNDGETSRCNAME, &rstat_name);
170 		if (res < 0)
171 			err(1, "ioctl(RNDGETSRCNAME)");
172 		printf(HEADER);
173 		printf("%-16s %10u %-4s %s\n",
174 		    rstat_name.source.name,
175 		    rstat_name.source.total,
176 		    find_name(rstat_name.source.type),
177 		    strflags(rstat_name.source.flags));
178 		close(fd);
179 		return;
180 	}
181 
182 	/*
183 	 * Run through all the devices present in the system, and either
184 	 * print out ones that match, or print out all of them.
185 	 */
186 	printf(HEADER);
187 	start = 0;
188 	for (;;) {
189 		rstat.count = RND_MAXSTATCOUNT;
190 		rstat.start = start;
191 		res = ioctl(fd, RNDGETSRCNUM, &rstat);
192 		if (res < 0)
193 			err(1, "ioctl(RNDGETSRCNUM)");
194 
195 		if (rstat.count == 0)
196 			break;
197 
198 		for (res = 0; res < rstat.count; res++) {
199 			if (all != 0 ||
200 			    type == rstat.source[res].type)
201 				printf("%-16s %10u %-4s %s\n",
202 				    rstat.source[res].name,
203 				    rstat.source[res].total,
204 				    find_name(rstat.source[res].type),
205 				    strflags(rstat.source[res].flags));
206 		}
207 		start += rstat.count;
208 	}
209 
210 	close(fd);
211 }
212 
213 void
214 do_stats()
215 {
216 	rndpoolstat_t rs;
217 	int fd;
218 
219 	fd = open("/dev/urandom", O_RDONLY, 0644);
220 	if (fd < 0)
221 		err(1, "open");
222 
223 	if (ioctl(fd, RNDGETPOOLSTAT, &rs) < 0)
224 		err(1, "ioctl(RNDGETPOOLSTAT)");
225 
226 	printf("\t%9u bits mixed into pool\n", rs.added);
227 	printf("\t%9u bits currently stored in pool (max %u)\n",
228 	    rs.curentropy, rs.maxentropy);
229 	printf("\t%9u bits of entropy discarded due to full pool\n",
230 	    rs.discarded);
231 	printf("\t%9u hard-random bits generated\n", rs.removed);
232 	printf("\t%9u pseudo-random bits generated\n", rs.generated);
233 
234 	close(fd);
235 }
236 
237 int
238 main(int argc, char **argv)
239 {
240 	rndctl_t rctl;
241 	int ch, cmd, lflag, mflag, sflag;
242 	u_int32_t type;
243 	char name[16];
244 
245 	rctl.mask = 0;
246 	rctl.flags = 0;
247 
248 	cmd = 0;
249 	lflag = 0;
250 	mflag = 0;
251 	sflag = 0;
252 	type = 0xff;
253 
254 	while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1)
255 		switch (ch) {
256 		case 'C':
257 			rctl.flags |= RND_FLAG_NO_COLLECT;
258 			rctl.mask |= RND_FLAG_NO_COLLECT;
259 			mflag++;
260 			break;
261 		case 'E':
262 			rctl.flags |= RND_FLAG_NO_ESTIMATE;
263 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
264 			mflag++;
265 			break;
266 		case 'c':
267 			rctl.flags &= ~RND_FLAG_NO_COLLECT;
268 			rctl.mask |= RND_FLAG_NO_COLLECT;
269 			mflag++;
270 			break;
271 		case 'e':
272 			rctl.flags &= ~RND_FLAG_NO_ESTIMATE;
273 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
274 			mflag++;
275 			break;
276 		case 'l':
277 			lflag++;
278 			break;
279 		case 't':
280 			if (cmd != 0)
281 				usage();
282 			cmd = 't';
283 
284 			type = find_type(optarg);
285 			break;
286 		case 'd':
287 			if (cmd != 0)
288 				usage();
289 			cmd = 'd';
290 
291 			type = 0xff;
292 			strncpy(name, optarg, 16);
293 			break;
294 		case 's':
295 			sflag++;
296 			break;
297 		case '?':
298 		default:
299 			usage();
300 		}
301 
302 	/*
303 	 * Cannot list and modify at the same time.
304 	 */
305 	if ((lflag != 0 || sflag != 0) && mflag != 0)
306 		usage();
307 
308 	/*
309 	 * Bomb out on no-ops.
310 	 */
311 	if (lflag == 0 && mflag == 0 && sflag == 0)
312 		usage();
313 
314 	/*
315 	 * If not listing, we need a device name or a type.
316 	 */
317 	if (lflag == 0 && cmd == 0 && sflag == 0)
318 		usage();
319 
320 	/*
321 	 * Modify request.
322 	 */
323 	if (mflag != 0) {
324 		rctl.type = type;
325 		strncpy(rctl.name, name, 16);
326 		do_ioctl(&rctl);
327 
328 		exit(0);
329 	}
330 
331 	/*
332 	 * List sources.
333 	 */
334 	if (lflag != 0)
335 		do_list(cmd == 0, type, name);
336 
337 	if (sflag != 0)
338 		do_stats();
339 
340 	exit(0);
341 }
342