14db9ae91SMark Murray /*- 2d1b06863SMark Murray * Copyright (c) 2000-2015 Mark R V Murray 34db9ae91SMark Murray * All rights reserved. 44db9ae91SMark Murray * 54db9ae91SMark Murray * Redistribution and use in source and binary forms, with or without 64db9ae91SMark Murray * modification, are permitted provided that the following conditions 74db9ae91SMark Murray * are met: 84db9ae91SMark Murray * 1. Redistributions of source code must retain the above copyright 94db9ae91SMark Murray * notice, this list of conditions and the following disclaimer 104db9ae91SMark Murray * in this position and unchanged. 114db9ae91SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 124db9ae91SMark Murray * notice, this list of conditions and the following disclaimer in the 134db9ae91SMark Murray * documentation and/or other materials provided with the distribution. 144db9ae91SMark Murray * 154db9ae91SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 164db9ae91SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 174db9ae91SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 184db9ae91SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 194db9ae91SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 204db9ae91SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 214db9ae91SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 224db9ae91SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 234db9ae91SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 244db9ae91SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 254db9ae91SMark Murray * 264db9ae91SMark Murray */ 274db9ae91SMark Murray 28aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30aad970f1SDavid E. O'Brien 314db9ae91SMark Murray #include <sys/param.h> 324db9ae91SMark Murray #include <sys/systm.h> 33fb919e4dSMark Murray #include <sys/bus.h> 344db9ae91SMark Murray #include <sys/conf.h> 354db9ae91SMark Murray #include <sys/fcntl.h> 36fb919e4dSMark Murray #include <sys/filio.h> 374db9ae91SMark Murray #include <sys/kernel.h> 3802c986abSMark Murray #include <sys/kthread.h> 39fb919e4dSMark Murray #include <sys/lock.h> 4041ee9f1cSPoul-Henning Kamp #include <sys/module.h> 4110cb2424SMark Murray #include <sys/malloc.h> 42d1b06863SMark Murray #include <sys/poll.h> 43b40ce416SJulian Elischer #include <sys/proc.h> 44f02e47dcSMark Murray #include <sys/random.h> 45d1b06863SMark Murray #include <sys/sbuf.h> 46d1b06863SMark Murray #include <sys/selinfo.h> 4710cb2424SMark Murray #include <sys/sysctl.h> 4810cb2424SMark Murray #include <sys/systm.h> 49fb919e4dSMark Murray #include <sys/uio.h> 5002c986abSMark Murray #include <sys/unistd.h> 514db9ae91SMark Murray 52d1b06863SMark Murray #include <crypto/rijndael/rijndael-api-fst.h> 53d1b06863SMark Murray #include <crypto/sha2/sha2.h> 54d1b06863SMark Murray 55d1b06863SMark Murray #include <dev/random/hash.h> 5602c986abSMark Murray #include <dev/random/randomdev.h> 57095ed2c9SMark Murray #include <dev/random/random_harvestq.h> 584db9ae91SMark Murray 59d1b06863SMark Murray #include "opt_random.h" 60d1b06863SMark Murray 61d1b06863SMark Murray #if defined(RANDOM_DUMMY) && defined(RANDOM_YARROW) 62d1b06863SMark Murray #error "Cannot define both RANDOM_DUMMY and RANDOM_YARROW" 63d1b06863SMark Murray #endif 64d1b06863SMark Murray 653aa77530SMark Murray #define RANDOM_UNIT 0 66e7806b4cSMark Murray 67d1b06863SMark Murray static d_read_t randomdev_read; 68d1b06863SMark Murray static d_write_t randomdev_write; 69d1b06863SMark Murray static d_poll_t randomdev_poll; 7010cb2424SMark Murray static d_ioctl_t randomdev_ioctl; 714db9ae91SMark Murray 724db9ae91SMark Murray static struct cdevsw random_cdevsw = { 737ac40f5fSPoul-Henning Kamp .d_name = "random", 7410cb2424SMark Murray .d_version = D_VERSION, 75d1b06863SMark Murray .d_read = randomdev_read, 76d1b06863SMark Murray .d_write = randomdev_write, 77d1b06863SMark Murray .d_poll = randomdev_poll, 7810cb2424SMark Murray .d_ioctl = randomdev_ioctl, 794db9ae91SMark Murray }; 804db9ae91SMark Murray 814db9ae91SMark Murray /* For use with make_dev(9)/destroy_dev(9). */ 8289c9c53dSPoul-Henning Kamp static struct cdev *random_dev; 834db9ae91SMark Murray 8410cb2424SMark Murray /* Set up the sysctl root node for the entropy device */ 85d1b06863SMark Murray SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Cryptographically Secure Random Number Generator"); 864db9ae91SMark Murray 8710cb2424SMark Murray MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); 884db9ae91SMark Murray 89d1b06863SMark Murray #if defined(RANDOM_DUMMY) 90d1b06863SMark Murray 91d1b06863SMark Murray /*- 92d1b06863SMark Murray * Dummy "always block" pseudo algorithm, used when there is no real 93d1b06863SMark Murray * random(4) driver to provide a CSPRNG. 94d1b06863SMark Murray */ 95d1b06863SMark Murray 96d1b06863SMark Murray static u_int 97d1b06863SMark Murray dummy_random_zero(void) 98d1b06863SMark Murray { 99d1b06863SMark Murray 100d1b06863SMark Murray return (0); 101d1b06863SMark Murray } 102d1b06863SMark Murray 103d1b06863SMark Murray static void 104d1b06863SMark Murray dummy_random(void) 105d1b06863SMark Murray { 106d1b06863SMark Murray } 107d1b06863SMark Murray 108d1b06863SMark Murray struct random_algorithm random_alg_context = { 109d1b06863SMark Murray .ra_ident = "Dummy", 1103aa77530SMark Murray .ra_init_alg = NULL, 1113aa77530SMark Murray .ra_deinit_alg = NULL, 112d1b06863SMark Murray .ra_pre_read = dummy_random, 113d1b06863SMark Murray .ra_read = (random_alg_read_t *)dummy_random_zero, 114d1b06863SMark Murray .ra_write = (random_alg_write_t *)dummy_random_zero, 1153aa77530SMark Murray .ra_reseed = dummy_random, 1163aa77530SMark Murray .ra_seeded = (random_alg_seeded_t *)dummy_random_zero, 117d1b06863SMark Murray .ra_event_processor = NULL, 118d1b06863SMark Murray .ra_poolcount = 0, 119d1b06863SMark Murray }; 120d1b06863SMark Murray 121d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 122d1b06863SMark Murray 123d1b06863SMark Murray LIST_HEAD(sources_head, random_sources); 124d1b06863SMark Murray static struct sources_head source_list = LIST_HEAD_INITIALIZER(source_list); 125d1b06863SMark Murray static u_int read_rate; 126d1b06863SMark Murray 1273aa77530SMark Murray static void 1283aa77530SMark Murray random_alg_context_ra_init_alg(void *data) 1293aa77530SMark Murray { 1303aa77530SMark Murray 1313aa77530SMark Murray random_alg_context.ra_init_alg(data); 1323aa77530SMark Murray } 1333aa77530SMark Murray 1343aa77530SMark Murray static void 1353aa77530SMark Murray random_alg_context_ra_deinit_alg(void *data) 1363aa77530SMark Murray { 1373aa77530SMark Murray 1383aa77530SMark Murray random_alg_context.ra_deinit_alg(data); 1393aa77530SMark Murray } 1403aa77530SMark Murray 1413aa77530SMark Murray SYSINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_init_alg, NULL); 1423aa77530SMark Murray SYSUNINIT(random_device, SI_SUB_RANDOM, SI_ORDER_THIRD, random_alg_context_ra_deinit_alg, NULL); 1433aa77530SMark Murray 144d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 145d1b06863SMark Murray 146d1b06863SMark Murray static struct selinfo rsel; 147d1b06863SMark Murray 148d1b06863SMark Murray /* 149d1b06863SMark Murray * This is the read uio(9) interface for random(4). 150d1b06863SMark Murray */ 151d1b06863SMark Murray /* ARGSUSED */ 152d1b06863SMark Murray static int 153d1b06863SMark Murray randomdev_read(struct cdev *dev __unused, struct uio *uio, int flags) 154d1b06863SMark Murray { 155d1b06863SMark Murray uint8_t *random_buf; 156*b712101cSMark Murray int error; 157*b712101cSMark Murray ssize_t read_len, total_read, c; 158d1b06863SMark Murray 159d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 160d1b06863SMark Murray random_alg_context.ra_pre_read(); 161d1b06863SMark Murray /* (Un)Blocking logic */ 162d1b06863SMark Murray error = 0; 1633aa77530SMark Murray while (!random_alg_context.ra_seeded()) { 164d1b06863SMark Murray if (flags & O_NONBLOCK) { 165d1b06863SMark Murray error = EWOULDBLOCK; 166d1b06863SMark Murray break; 167d1b06863SMark Murray } 1683aa77530SMark Murray tsleep(&random_alg_context, 0, "randseed", hz/10); 169d1b06863SMark Murray /* keep tapping away at the pre-read until we seed/unblock. */ 170d1b06863SMark Murray random_alg_context.ra_pre_read(); 1713aa77530SMark Murray printf("random: %s unblock wait\n", __func__); 172d1b06863SMark Murray } 173d1b06863SMark Murray if (error == 0) { 174d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 175d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 176d1b06863SMark Murray read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); 177d1b06863SMark Murray #endif 178*b712101cSMark Murray total_read = 0; 179d1b06863SMark Murray while (uio->uio_resid && !error) { 180*b712101cSMark Murray read_len = uio->uio_resid; 181*b712101cSMark Murray /* 182*b712101cSMark Murray * Belt-and-braces. 183*b712101cSMark Murray * Round up the read length to a crypto block size multiple, 184*b712101cSMark Murray * which is what the underlying generator is expecting. 185*b712101cSMark Murray * See the random_buf size requirements in the Yarrow/Fortuna code. 186*b712101cSMark Murray */ 187*b712101cSMark Murray read_len += RANDOM_BLOCKSIZE; 188*b712101cSMark Murray read_len -= read_len % RANDOM_BLOCKSIZE; 189*b712101cSMark Murray read_len = MIN(read_len, PAGE_SIZE); 190*b712101cSMark Murray random_alg_context.ra_read(random_buf, read_len); 191*b712101cSMark Murray c = MIN(uio->uio_resid, read_len); 192d1b06863SMark Murray error = uiomove(random_buf, c, uio); 193*b712101cSMark Murray total_read += c; 194d1b06863SMark Murray } 195*b712101cSMark Murray if (total_read != uio->uio_resid && (error == ERESTART || error == EINTR) ) 196d1b06863SMark Murray /* Return partial read, not error. */ 197d1b06863SMark Murray error = 0; 198d1b06863SMark Murray } 199d1b06863SMark Murray free(random_buf, M_ENTROPY); 200d1b06863SMark Murray return (error); 201d1b06863SMark Murray } 202d1b06863SMark Murray 203d1b06863SMark Murray /*- 204d1b06863SMark Murray * Kernel API version of read_random(). 205d1b06863SMark Murray * This is similar to random_alg_read(), 206d1b06863SMark Murray * except it doesn't interface with uio(9). 207d1b06863SMark Murray * It cannot assumed that random_buf is a multiple of 208d1b06863SMark Murray * RANDOM_BLOCKSIZE bytes. 209d1b06863SMark Murray */ 210d1b06863SMark Murray u_int 211d1b06863SMark Murray read_random(void *random_buf, u_int len) 212d1b06863SMark Murray { 213d1b06863SMark Murray u_int read_len, total_read, c; 214d1b06863SMark Murray uint8_t local_buf[len + RANDOM_BLOCKSIZE]; 215d1b06863SMark Murray 216d1b06863SMark Murray KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); 217d1b06863SMark Murray random_alg_context.ra_pre_read(); 218d1b06863SMark Murray /* (Un)Blocking logic; if not seeded, return nothing. */ 219d1b06863SMark Murray if (random_alg_context.ra_seeded()) { 220d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 221d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 222d1b06863SMark Murray read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); 223d1b06863SMark Murray #endif 224d1b06863SMark Murray read_len = len; 225*b712101cSMark Murray /* 226*b712101cSMark Murray * Belt-and-braces. 227*b712101cSMark Murray * Round up the read length to a crypto block size multiple, 228*b712101cSMark Murray * which is what the underlying generator is expecting. 229*b712101cSMark Murray */ 230*b712101cSMark Murray read_len += RANDOM_BLOCKSIZE; 231*b712101cSMark Murray read_len -= read_len % RANDOM_BLOCKSIZE; 232d1b06863SMark Murray total_read = 0; 233d1b06863SMark Murray while (read_len) { 234d1b06863SMark Murray c = MIN(read_len, PAGE_SIZE); 235d1b06863SMark Murray random_alg_context.ra_read(&local_buf[total_read], c); 236d1b06863SMark Murray read_len -= c; 237d1b06863SMark Murray total_read += c; 238d1b06863SMark Murray } 239d1b06863SMark Murray memcpy(random_buf, local_buf, len); 240d1b06863SMark Murray } else 241d1b06863SMark Murray len = 0; 242d1b06863SMark Murray return (len); 243d1b06863SMark Murray } 244d1b06863SMark Murray 245d1b06863SMark Murray /* ARGSUSED */ 246d1b06863SMark Murray static int 247d1b06863SMark Murray randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) 248d1b06863SMark Murray { 249d1b06863SMark Murray uint8_t *random_buf; 250d1b06863SMark Murray int c, error = 0; 251d1b06863SMark Murray ssize_t nbytes; 252d1b06863SMark Murray 253d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 254d1b06863SMark Murray nbytes = uio->uio_resid; 255d1b06863SMark Murray while (uio->uio_resid > 0 && error == 0) { 256d1b06863SMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 257d1b06863SMark Murray error = uiomove(random_buf, c, uio); 258d1b06863SMark Murray if (error) 259d1b06863SMark Murray break; 260d1b06863SMark Murray random_alg_context.ra_write(random_buf, c); 261d1b06863SMark Murray tsleep(&random_alg_context, 0, "randwr", hz/10); 262d1b06863SMark Murray } 263d1b06863SMark Murray if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) 264d1b06863SMark Murray /* Partial write, not error. */ 265d1b06863SMark Murray error = 0; 266d1b06863SMark Murray free(random_buf, M_ENTROPY); 267d1b06863SMark Murray return (error); 268d1b06863SMark Murray } 269d1b06863SMark Murray 270d1b06863SMark Murray /* ARGSUSED */ 271d1b06863SMark Murray static int 272d1b06863SMark Murray randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 273d1b06863SMark Murray { 274d1b06863SMark Murray 275d1b06863SMark Murray if (events & (POLLIN | POLLRDNORM)) { 276d1b06863SMark Murray if (random_alg_context.ra_seeded()) 277d1b06863SMark Murray events &= (POLLIN | POLLRDNORM); 278d1b06863SMark Murray else 279d1b06863SMark Murray selrecord(td, &rsel); 280d1b06863SMark Murray } 281d1b06863SMark Murray return (events); 282d1b06863SMark Murray } 283d1b06863SMark Murray 284d1b06863SMark Murray /* This will be called by the entropy processor when it seeds itself and becomes secure */ 285d1b06863SMark Murray void 286d1b06863SMark Murray randomdev_unblock(void) 287d1b06863SMark Murray { 288d1b06863SMark Murray 289d1b06863SMark Murray selwakeuppri(&rsel, PUSER); 290d1b06863SMark Murray wakeup(&random_alg_context); 291d1b06863SMark Murray printf("random: unblocking device.\n"); 292d1b06863SMark Murray /* Do random(9) a favour while we are about it. */ 293d1b06863SMark Murray (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); 294d1b06863SMark Murray } 295d1b06863SMark Murray 296e1199601SMark Murray /* ARGSUSED */ 2974db9ae91SMark Murray static int 29810cb2424SMark Murray randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 299e1199601SMark Murray int flags __unused, struct thread *td __unused) 3004d87a031SMark Murray { 301e7806b4cSMark Murray int error = 0; 302e7806b4cSMark Murray 30341bc9751SMark Murray switch (cmd) { 30441bc9751SMark Murray /* Really handled in upper layer */ 30541bc9751SMark Murray case FIOASYNC: 30641bc9751SMark Murray case FIONBIO: 307e7806b4cSMark Murray break; 30841bc9751SMark Murray default: 309e7806b4cSMark Murray error = ENOTTY; 3104d87a031SMark Murray } 31110cb2424SMark Murray 312e7806b4cSMark Murray return (error); 31341bc9751SMark Murray } 3144d87a031SMark Murray 315d1b06863SMark Murray void 316d1b06863SMark Murray random_source_register(struct random_source *rsource) 317d1b06863SMark Murray { 318d1b06863SMark Murray #if defined(RANDOM_DUMMY) 319d1b06863SMark Murray (void)rsource; 320d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 321d1b06863SMark Murray struct random_sources *rrs; 322d1b06863SMark Murray 323d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 324d1b06863SMark Murray 325d1b06863SMark Murray rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK); 326d1b06863SMark Murray rrs->rrs_source = rsource; 327d1b06863SMark Murray 328d1b06863SMark Murray printf("random: registering fast source %s\n", rsource->rs_ident); 329d1b06863SMark Murray LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); 330d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 331d1b06863SMark Murray } 332d1b06863SMark Murray 333d1b06863SMark Murray void 334d1b06863SMark Murray random_source_deregister(struct random_source *rsource) 335d1b06863SMark Murray { 336d1b06863SMark Murray #if defined(RANDOM_DUMMY) 337d1b06863SMark Murray (void)rsource; 338d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 339d1b06863SMark Murray struct random_sources *rrs = NULL; 340d1b06863SMark Murray 341d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 342d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) 343d1b06863SMark Murray if (rrs->rrs_source == rsource) { 344d1b06863SMark Murray LIST_REMOVE(rrs, rrs_entries); 345d1b06863SMark Murray break; 346d1b06863SMark Murray } 347d1b06863SMark Murray if (rrs != NULL) 348d1b06863SMark Murray free(rrs, M_ENTROPY); 349d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 350d1b06863SMark Murray } 351d1b06863SMark Murray 352d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 353d1b06863SMark Murray /* 354d1b06863SMark Murray * Run through all fast sources reading entropy for the given 355d1b06863SMark Murray * number of rounds, which should be a multiple of the number 356d1b06863SMark Murray * of entropy accumulation pools in use; 2 for Yarrow and 32 357d1b06863SMark Murray * for Fortuna. 358d1b06863SMark Murray * 359d1b06863SMark Murray * BEWARE!!! 360d1b06863SMark Murray * This function runs inside the RNG thread! Don't do anything silly! 36110cb2424SMark Murray */ 36210cb2424SMark Murray void 363d1b06863SMark Murray random_sources_feed(void) 364a6278a2aSMark Murray { 365d1b06863SMark Murray uint32_t entropy[HARVESTSIZE]; 366d1b06863SMark Murray struct random_sources *rrs; 367d1b06863SMark Murray u_int i, n, local_read_rate; 368a6278a2aSMark Murray 369d1b06863SMark Murray /* 370d1b06863SMark Murray * Step over all of live entropy sources, and feed their output 371d1b06863SMark Murray * to the system-wide RNG. 372d1b06863SMark Murray */ 373d1b06863SMark Murray /* XXX: FIX!! Next lines as an atomic operation? */ 374d1b06863SMark Murray local_read_rate = read_rate; 375d1b06863SMark Murray read_rate = RANDOM_ALG_READ_RATE_MINIMUM; 376d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 377d1b06863SMark Murray for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) { 378d1b06863SMark Murray n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); 379d1b06863SMark Murray KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); 380d1b06863SMark Murray random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); 3815711939bSDavid E. O'Brien } 382d1b06863SMark Murray } 383d1b06863SMark Murray explicit_bzero(entropy, sizeof(entropy)); 384d1b06863SMark Murray } 385d1b06863SMark Murray 386d1b06863SMark Murray static int 387d1b06863SMark Murray random_source_handler(SYSCTL_HANDLER_ARGS) 388d1b06863SMark Murray { 389d1b06863SMark Murray struct random_sources *rrs; 390d1b06863SMark Murray struct sbuf sbuf; 391d1b06863SMark Murray int error, count; 392d1b06863SMark Murray 393d1b06863SMark Murray sbuf_new_for_sysctl(&sbuf, NULL, 64, req); 394d1b06863SMark Murray count = 0; 395d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 396d1b06863SMark Murray sbuf_cat(&sbuf, (count++ ? ",'" : "'")); 397d1b06863SMark Murray sbuf_cat(&sbuf, rrs->rrs_source->rs_ident); 398d1b06863SMark Murray sbuf_cat(&sbuf, "'"); 399d1b06863SMark Murray } 400d1b06863SMark Murray error = sbuf_finish(&sbuf); 401d1b06863SMark Murray sbuf_delete(&sbuf); 402d1b06863SMark Murray return (error); 403d1b06863SMark Murray } 404d1b06863SMark Murray SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 405d1b06863SMark Murray NULL, 0, random_source_handler, "A", 406d1b06863SMark Murray "List of active fast entropy sources."); 407d1b06863SMark Murray #endif /* !defined(RANDOM_DUMMY) */ 4085711939bSDavid E. O'Brien 409e1199601SMark Murray /* ARGSUSED */ 410a6278a2aSMark Murray static int 41110cb2424SMark Murray randomdev_modevent(module_t mod __unused, int type, void *data __unused) 4124db9ae91SMark Murray { 413e7806b4cSMark Murray int error = 0; 4144d87a031SMark Murray 4154db9ae91SMark Murray switch (type) { 4164db9ae91SMark Murray case MOD_LOAD: 417d1b06863SMark Murray printf("random: entropy device external interface\n"); 41810cb2424SMark Murray random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 4193aa77530SMark Murray RANDOM_UNIT, NULL, UID_ROOT, GID_WHEEL, 0644, "random"); 42010cb2424SMark Murray make_dev_alias(random_dev, "urandom"); /* compatibility */ 421e7806b4cSMark Murray break; 4224db9ae91SMark Murray case MOD_UNLOAD: 423c9ec235cSMark Murray destroy_dev(random_dev); 424e7806b4cSMark Murray break; 4254db9ae91SMark Murray case MOD_SHUTDOWN: 426e7806b4cSMark Murray break; 4273e019deaSPoul-Henning Kamp default: 4283e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 4293e019deaSPoul-Henning Kamp break; 4304db9ae91SMark Murray } 431e7806b4cSMark Murray return (error); 4324db9ae91SMark Murray } 4334db9ae91SMark Murray 434d1b06863SMark Murray static moduledata_t randomdev_mod = { 435d1b06863SMark Murray "random_device", 436d1b06863SMark Murray randomdev_modevent, 437d1b06863SMark Murray 0 438d1b06863SMark Murray }; 43910cb2424SMark Murray 440d1b06863SMark Murray DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 441d1b06863SMark Murray MODULE_VERSION(random_device, 1); 442