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