xref: /netbsd-src/sbin/rndctl/rndctl.c (revision 1ffa7b76c40339c17a0fb2a09fac93f287cfc046)
1 /*	$NetBSD: rndctl.c,v 1.13 2002/08/18 23:45:48 gmcgarry 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 	{ "tape",    RND_TYPE_TAPE },
54 	{ "tty",     RND_TYPE_TTY },
55 	{ "rng",     RND_TYPE_RNG },
56 	{ NULL,      0 }
57 };
58 
59 static void usage(void);
60 u_int32_t find_type(char *name);
61 char *find_name(u_int32_t);
62 void do_ioctl(rndctl_t *);
63 char * strflags(u_int32_t);
64 void do_list(int, u_int32_t, char *);
65 void do_stats(void);
66 
67 static void
68 usage(void)
69 {
70 
71 	fprintf(stderr, "usage: %s -CEce [-t devtype] [-d devname]\n",
72 	    getprogname());
73 	fprintf(stderr, "       %s -ls [-t devtype] [-d devname]\n",
74 	    getprogname());
75 	exit(1);
76 }
77 
78 u_int32_t
79 find_type(char *name)
80 {
81 	arg_t *a;
82 
83 	a = source_types;
84 
85 	while (a->a_name != NULL) {
86 		if (strcmp(a->a_name, name) == 0)
87 			return (a->a_type);
88 		a++;
89 	}
90 
91 	errx(1, "device name %s unknown", name);
92 	return (0);
93 }
94 
95 char *
96 find_name(u_int32_t type)
97 {
98 	arg_t *a;
99 
100 	a = source_types;
101 
102 	while (a->a_name != NULL) {
103 		if (type == a->a_type)
104 			return (a->a_name);
105 		a++;
106 	}
107 
108 	warnx("device type %u unknown", type);
109 	return ("???");
110 }
111 
112 void
113 do_ioctl(rndctl_t *rctl)
114 {
115 	int fd;
116 	int res;
117 
118 	fd = open("/dev/urandom", O_RDONLY, 0644);
119 	if (fd < 0)
120 		err(1, "open");
121 
122 	res = ioctl(fd, RNDCTL, rctl);
123 	if (res < 0)
124 		err(1, "ioctl(RNDCTL)");
125 
126 	close(fd);
127 }
128 
129 char *
130 strflags(u_int32_t fl)
131 {
132 	static char str[512];
133 
134 	str[0] = 0;
135 	if (fl & RND_FLAG_NO_ESTIMATE)
136 		;
137 	else
138 		strcat(str, "estimate");
139 
140 	if (fl & RND_FLAG_NO_COLLECT)
141 		;
142 	else {
143 		if (str[0])
144 			strcat(str, ", ");
145 		strcat(str, "collect");
146 	}
147 
148 	return (str);
149 }
150 
151 #define HEADER "Source                 Bits Type      Flags\n"
152 
153 void
154 do_list(int all, u_int32_t type, char *name)
155 {
156 	rndstat_t rstat;
157 	rndstat_name_t rstat_name;
158 	int fd;
159 	int res;
160 	u_int32_t start;
161 
162 	fd = open("/dev/urandom", O_RDONLY, 0644);
163 	if (fd < 0)
164 		err(1, "open");
165 
166 	if (all == 0 && type == 0xff) {
167 		strncpy(rstat_name.name, name, 16);
168 		res = ioctl(fd, RNDGETSRCNAME, &rstat_name);
169 		if (res < 0)
170 			err(1, "ioctl(RNDGETSRCNAME)");
171 		printf(HEADER);
172 		printf("%-16s %10u %-4s %s\n",
173 		    rstat_name.source.name,
174 		    rstat_name.source.total,
175 		    find_name(rstat_name.source.type),
176 		    strflags(rstat_name.source.flags));
177 		close(fd);
178 		return;
179 	}
180 
181 	/*
182 	 * Run through all the devices present in the system, and either
183 	 * print out ones that match, or print out all of them.
184 	 */
185 	printf(HEADER);
186 	start = 0;
187 	for (;;) {
188 		rstat.count = RND_MAXSTATCOUNT;
189 		rstat.start = start;
190 		res = ioctl(fd, RNDGETSRCNUM, &rstat);
191 		if (res < 0)
192 			err(1, "ioctl(RNDGETSRCNUM)");
193 
194 		if (rstat.count == 0)
195 			break;
196 
197 		for (res = 0; res < rstat.count; res++) {
198 			if (all != 0 ||
199 			    type == rstat.source[res].type)
200 				printf("%-16s %10u %-4s %s\n",
201 				    rstat.source[res].name,
202 				    rstat.source[res].total,
203 				    find_name(rstat.source[res].type),
204 				    strflags(rstat.source[res].flags));
205 		}
206 		start += rstat.count;
207 	}
208 
209 	close(fd);
210 }
211 
212 void
213 do_stats()
214 {
215 	rndpoolstat_t rs;
216 	int fd;
217 
218 	fd = open("/dev/urandom", O_RDONLY, 0644);
219 	if (fd < 0)
220 		err(1, "open");
221 
222 	if (ioctl(fd, RNDGETPOOLSTAT, &rs) < 0)
223 		err(1, "ioctl(RNDGETPOOLSTAT)");
224 
225 	printf("\t%9u bits mixed into pool\n", rs.added);
226 	printf("\t%9u bits currently stored in pool (max %u)\n",
227 	    rs.curentropy, rs.maxentropy);
228 	printf("\t%9u bits of entropy discarded due to full pool\n",
229 	    rs.discarded);
230 	printf("\t%9u hard-random bits generated\n", rs.removed);
231 	printf("\t%9u pseudo-random bits generated\n", rs.generated);
232 
233 	close(fd);
234 }
235 
236 int
237 main(int argc, char **argv)
238 {
239 	rndctl_t rctl;
240 	int ch, cmd, lflag, mflag, sflag;
241 	u_int32_t type;
242 	char name[16];
243 
244 	rctl.mask = 0;
245 	rctl.flags = 0;
246 
247 	cmd = 0;
248 	lflag = 0;
249 	mflag = 0;
250 	sflag = 0;
251 	type = 0xff;
252 
253 	while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1)
254 		switch (ch) {
255 		case 'C':
256 			rctl.flags |= RND_FLAG_NO_COLLECT;
257 			rctl.mask |= RND_FLAG_NO_COLLECT;
258 			mflag++;
259 			break;
260 		case 'E':
261 			rctl.flags |= RND_FLAG_NO_ESTIMATE;
262 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
263 			mflag++;
264 			break;
265 		case 'c':
266 			rctl.flags &= ~RND_FLAG_NO_COLLECT;
267 			rctl.mask |= RND_FLAG_NO_COLLECT;
268 			mflag++;
269 			break;
270 		case 'e':
271 			rctl.flags &= ~RND_FLAG_NO_ESTIMATE;
272 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
273 			mflag++;
274 			break;
275 		case 'l':
276 			lflag++;
277 			break;
278 		case 't':
279 			if (cmd != 0)
280 				usage();
281 			cmd = 't';
282 
283 			type = find_type(optarg);
284 			break;
285 		case 'd':
286 			if (cmd != 0)
287 				usage();
288 			cmd = 'd';
289 
290 			type = 0xff;
291 			strncpy(name, optarg, 16);
292 			break;
293 		case 's':
294 			sflag++;
295 			break;
296 		case '?':
297 		default:
298 			usage();
299 		}
300 
301 	/*
302 	 * Cannot list and modify at the same time.
303 	 */
304 	if ((lflag != 0 || sflag != 0) && mflag != 0)
305 		usage();
306 
307 	/*
308 	 * Bomb out on no-ops.
309 	 */
310 	if (lflag == 0 && mflag == 0 && sflag == 0)
311 		usage();
312 
313 	/*
314 	 * If not listing, we need a device name or a type.
315 	 */
316 	if (lflag == 0 && cmd == 0 && sflag == 0)
317 		usage();
318 
319 	/*
320 	 * Modify request.
321 	 */
322 	if (mflag != 0) {
323 		rctl.type = type;
324 		strncpy(rctl.name, name, 16);
325 		do_ioctl(&rctl);
326 
327 		exit(0);
328 	}
329 
330 	/*
331 	 * List sources.
332 	 */
333 	if (lflag != 0)
334 		do_list(cmd == 0, type, name);
335 
336 	if (sflag != 0)
337 		do_stats();
338 
339 	exit(0);
340 }
341