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 { 155*707d98feSEd Schouten 156*707d98feSEd Schouten return (read_random_uio(uio, (flags & O_NONBLOCK) != 0)); 157*707d98feSEd Schouten } 158*707d98feSEd Schouten 159*707d98feSEd Schouten int 160*707d98feSEd Schouten read_random_uio(struct uio *uio, bool nonblock) 161*707d98feSEd Schouten { 162d1b06863SMark Murray uint8_t *random_buf; 163b712101cSMark Murray int error; 164b712101cSMark Murray ssize_t read_len, total_read, c; 165d1b06863SMark Murray 166d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 167d1b06863SMark Murray random_alg_context.ra_pre_read(); 168d1b06863SMark Murray /* (Un)Blocking logic */ 169d1b06863SMark Murray error = 0; 1703aa77530SMark Murray while (!random_alg_context.ra_seeded()) { 171d1b06863SMark Murray if (flags & O_NONBLOCK) { 172d1b06863SMark Murray error = EWOULDBLOCK; 173d1b06863SMark Murray break; 174d1b06863SMark Murray } 1753aa77530SMark Murray tsleep(&random_alg_context, 0, "randseed", hz/10); 176d1b06863SMark Murray /* keep tapping away at the pre-read until we seed/unblock. */ 177d1b06863SMark Murray random_alg_context.ra_pre_read(); 1783aa77530SMark Murray printf("random: %s unblock wait\n", __func__); 179d1b06863SMark Murray } 180d1b06863SMark Murray if (error == 0) { 181d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 182d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 183d1b06863SMark Murray read_rate += (uio->uio_resid + sizeof(uint32_t))/sizeof(uint32_t); 184d1b06863SMark Murray #endif 185b712101cSMark Murray total_read = 0; 186d1b06863SMark Murray while (uio->uio_resid && !error) { 187b712101cSMark Murray read_len = uio->uio_resid; 188b712101cSMark Murray /* 189b712101cSMark Murray * Belt-and-braces. 190b712101cSMark Murray * Round up the read length to a crypto block size multiple, 191b712101cSMark Murray * which is what the underlying generator is expecting. 192b712101cSMark Murray * See the random_buf size requirements in the Yarrow/Fortuna code. 193b712101cSMark Murray */ 194b712101cSMark Murray read_len += RANDOM_BLOCKSIZE; 195b712101cSMark Murray read_len -= read_len % RANDOM_BLOCKSIZE; 196b712101cSMark Murray read_len = MIN(read_len, PAGE_SIZE); 197b712101cSMark Murray random_alg_context.ra_read(random_buf, read_len); 198b712101cSMark Murray c = MIN(uio->uio_resid, read_len); 199d1b06863SMark Murray error = uiomove(random_buf, c, uio); 200b712101cSMark Murray total_read += c; 201d1b06863SMark Murray } 202b712101cSMark Murray if (total_read != uio->uio_resid && (error == ERESTART || error == EINTR) ) 203d1b06863SMark Murray /* Return partial read, not error. */ 204d1b06863SMark Murray error = 0; 205d1b06863SMark Murray } 206d1b06863SMark Murray free(random_buf, M_ENTROPY); 207d1b06863SMark Murray return (error); 208d1b06863SMark Murray } 209d1b06863SMark Murray 210d1b06863SMark Murray /*- 211d1b06863SMark Murray * Kernel API version of read_random(). 212d1b06863SMark Murray * This is similar to random_alg_read(), 213d1b06863SMark Murray * except it doesn't interface with uio(9). 214d1b06863SMark Murray * It cannot assumed that random_buf is a multiple of 215d1b06863SMark Murray * RANDOM_BLOCKSIZE bytes. 216d1b06863SMark Murray */ 217d1b06863SMark Murray u_int 218d1b06863SMark Murray read_random(void *random_buf, u_int len) 219d1b06863SMark Murray { 220d1b06863SMark Murray u_int read_len, total_read, c; 221d1b06863SMark Murray uint8_t local_buf[len + RANDOM_BLOCKSIZE]; 222d1b06863SMark Murray 223d1b06863SMark Murray KASSERT(random_buf != NULL, ("No suitable random buffer in %s", __func__)); 224d1b06863SMark Murray random_alg_context.ra_pre_read(); 225d1b06863SMark Murray /* (Un)Blocking logic; if not seeded, return nothing. */ 226d1b06863SMark Murray if (random_alg_context.ra_seeded()) { 227d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 228d1b06863SMark Murray /* XXX: FIX!! Next line as an atomic operation? */ 229d1b06863SMark Murray read_rate += (len + sizeof(uint32_t))/sizeof(uint32_t); 230d1b06863SMark Murray #endif 231d1b06863SMark Murray read_len = len; 232b712101cSMark Murray /* 233b712101cSMark Murray * Belt-and-braces. 234b712101cSMark Murray * Round up the read length to a crypto block size multiple, 235b712101cSMark Murray * which is what the underlying generator is expecting. 236b712101cSMark Murray */ 237b712101cSMark Murray read_len += RANDOM_BLOCKSIZE; 238b712101cSMark Murray read_len -= read_len % RANDOM_BLOCKSIZE; 239d1b06863SMark Murray total_read = 0; 240d1b06863SMark Murray while (read_len) { 241d1b06863SMark Murray c = MIN(read_len, PAGE_SIZE); 242d1b06863SMark Murray random_alg_context.ra_read(&local_buf[total_read], c); 243d1b06863SMark Murray read_len -= c; 244d1b06863SMark Murray total_read += c; 245d1b06863SMark Murray } 246d1b06863SMark Murray memcpy(random_buf, local_buf, len); 247d1b06863SMark Murray } else 248d1b06863SMark Murray len = 0; 249d1b06863SMark Murray return (len); 250d1b06863SMark Murray } 251d1b06863SMark Murray 252d1b06863SMark Murray /* ARGSUSED */ 253d1b06863SMark Murray static int 254d1b06863SMark Murray randomdev_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) 255d1b06863SMark Murray { 256d1b06863SMark Murray uint8_t *random_buf; 257d1b06863SMark Murray int c, error = 0; 258d1b06863SMark Murray ssize_t nbytes; 259d1b06863SMark Murray 260d1b06863SMark Murray random_buf = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); 261d1b06863SMark Murray nbytes = uio->uio_resid; 262d1b06863SMark Murray while (uio->uio_resid > 0 && error == 0) { 263d1b06863SMark Murray c = MIN(uio->uio_resid, PAGE_SIZE); 264d1b06863SMark Murray error = uiomove(random_buf, c, uio); 265d1b06863SMark Murray if (error) 266d1b06863SMark Murray break; 267d1b06863SMark Murray random_alg_context.ra_write(random_buf, c); 268d1b06863SMark Murray tsleep(&random_alg_context, 0, "randwr", hz/10); 269d1b06863SMark Murray } 270d1b06863SMark Murray if (nbytes != uio->uio_resid && (error == ERESTART || error == EINTR)) 271d1b06863SMark Murray /* Partial write, not error. */ 272d1b06863SMark Murray error = 0; 273d1b06863SMark Murray free(random_buf, M_ENTROPY); 274d1b06863SMark Murray return (error); 275d1b06863SMark Murray } 276d1b06863SMark Murray 277d1b06863SMark Murray /* ARGSUSED */ 278d1b06863SMark Murray static int 279d1b06863SMark Murray randomdev_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 280d1b06863SMark Murray { 281d1b06863SMark Murray 282d1b06863SMark Murray if (events & (POLLIN | POLLRDNORM)) { 283d1b06863SMark Murray if (random_alg_context.ra_seeded()) 284d1b06863SMark Murray events &= (POLLIN | POLLRDNORM); 285d1b06863SMark Murray else 286d1b06863SMark Murray selrecord(td, &rsel); 287d1b06863SMark Murray } 288d1b06863SMark Murray return (events); 289d1b06863SMark Murray } 290d1b06863SMark Murray 291d1b06863SMark Murray /* This will be called by the entropy processor when it seeds itself and becomes secure */ 292d1b06863SMark Murray void 293d1b06863SMark Murray randomdev_unblock(void) 294d1b06863SMark Murray { 295d1b06863SMark Murray 296d1b06863SMark Murray selwakeuppri(&rsel, PUSER); 297d1b06863SMark Murray wakeup(&random_alg_context); 298d1b06863SMark Murray printf("random: unblocking device.\n"); 299d1b06863SMark Murray /* Do random(9) a favour while we are about it. */ 300d1b06863SMark Murray (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, ARC4_ENTR_HAVE); 301d1b06863SMark Murray } 302d1b06863SMark Murray 303e1199601SMark Murray /* ARGSUSED */ 3044db9ae91SMark Murray static int 30510cb2424SMark Murray randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, 306e1199601SMark Murray int flags __unused, struct thread *td __unused) 3074d87a031SMark Murray { 308e7806b4cSMark Murray int error = 0; 309e7806b4cSMark Murray 31041bc9751SMark Murray switch (cmd) { 31141bc9751SMark Murray /* Really handled in upper layer */ 31241bc9751SMark Murray case FIOASYNC: 31341bc9751SMark Murray case FIONBIO: 314e7806b4cSMark Murray break; 31541bc9751SMark Murray default: 316e7806b4cSMark Murray error = ENOTTY; 3174d87a031SMark Murray } 31810cb2424SMark Murray 319e7806b4cSMark Murray return (error); 32041bc9751SMark Murray } 3214d87a031SMark Murray 322d1b06863SMark Murray void 323d1b06863SMark Murray random_source_register(struct random_source *rsource) 324d1b06863SMark Murray { 325d1b06863SMark Murray #if defined(RANDOM_DUMMY) 326d1b06863SMark Murray (void)rsource; 327d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 328d1b06863SMark Murray struct random_sources *rrs; 329d1b06863SMark Murray 330d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 331d1b06863SMark Murray 332d1b06863SMark Murray rrs = malloc(sizeof(*rrs), M_ENTROPY, M_WAITOK); 333d1b06863SMark Murray rrs->rrs_source = rsource; 334d1b06863SMark Murray 335d1b06863SMark Murray printf("random: registering fast source %s\n", rsource->rs_ident); 336d1b06863SMark Murray LIST_INSERT_HEAD(&source_list, rrs, rrs_entries); 337d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 338d1b06863SMark Murray } 339d1b06863SMark Murray 340d1b06863SMark Murray void 341d1b06863SMark Murray random_source_deregister(struct random_source *rsource) 342d1b06863SMark Murray { 343d1b06863SMark Murray #if defined(RANDOM_DUMMY) 344d1b06863SMark Murray (void)rsource; 345d1b06863SMark Murray #else /* !defined(RANDOM_DUMMY) */ 346d1b06863SMark Murray struct random_sources *rrs = NULL; 347d1b06863SMark Murray 348d1b06863SMark Murray KASSERT(rsource != NULL, ("invalid input to %s", __func__)); 349d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) 350d1b06863SMark Murray if (rrs->rrs_source == rsource) { 351d1b06863SMark Murray LIST_REMOVE(rrs, rrs_entries); 352d1b06863SMark Murray break; 353d1b06863SMark Murray } 354d1b06863SMark Murray if (rrs != NULL) 355d1b06863SMark Murray free(rrs, M_ENTROPY); 356d1b06863SMark Murray #endif /* defined(RANDOM_DUMMY) */ 357d1b06863SMark Murray } 358d1b06863SMark Murray 359d1b06863SMark Murray #if !defined(RANDOM_DUMMY) 360d1b06863SMark Murray /* 361d1b06863SMark Murray * Run through all fast sources reading entropy for the given 362d1b06863SMark Murray * number of rounds, which should be a multiple of the number 363d1b06863SMark Murray * of entropy accumulation pools in use; 2 for Yarrow and 32 364d1b06863SMark Murray * for Fortuna. 365d1b06863SMark Murray * 366d1b06863SMark Murray * BEWARE!!! 367d1b06863SMark Murray * This function runs inside the RNG thread! Don't do anything silly! 36810cb2424SMark Murray */ 36910cb2424SMark Murray void 370d1b06863SMark Murray random_sources_feed(void) 371a6278a2aSMark Murray { 372d1b06863SMark Murray uint32_t entropy[HARVESTSIZE]; 373d1b06863SMark Murray struct random_sources *rrs; 374d1b06863SMark Murray u_int i, n, local_read_rate; 375a6278a2aSMark Murray 376d1b06863SMark Murray /* 377d1b06863SMark Murray * Step over all of live entropy sources, and feed their output 378d1b06863SMark Murray * to the system-wide RNG. 379d1b06863SMark Murray */ 380d1b06863SMark Murray /* XXX: FIX!! Next lines as an atomic operation? */ 381d1b06863SMark Murray local_read_rate = read_rate; 382d1b06863SMark Murray read_rate = RANDOM_ALG_READ_RATE_MINIMUM; 383d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 384d1b06863SMark Murray for (i = 0; i < random_alg_context.ra_poolcount*local_read_rate; i++) { 385d1b06863SMark Murray n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); 386d1b06863SMark Murray KASSERT((n > 0 && n <= sizeof(entropy)), ("very bad return from rs_read (= %d) in %s", n, __func__)); 387d1b06863SMark Murray random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); 3885711939bSDavid E. O'Brien } 389d1b06863SMark Murray } 390d1b06863SMark Murray explicit_bzero(entropy, sizeof(entropy)); 391d1b06863SMark Murray } 392d1b06863SMark Murray 393d1b06863SMark Murray static int 394d1b06863SMark Murray random_source_handler(SYSCTL_HANDLER_ARGS) 395d1b06863SMark Murray { 396d1b06863SMark Murray struct random_sources *rrs; 397d1b06863SMark Murray struct sbuf sbuf; 398d1b06863SMark Murray int error, count; 399d1b06863SMark Murray 400d1b06863SMark Murray sbuf_new_for_sysctl(&sbuf, NULL, 64, req); 401d1b06863SMark Murray count = 0; 402d1b06863SMark Murray LIST_FOREACH(rrs, &source_list, rrs_entries) { 403d1b06863SMark Murray sbuf_cat(&sbuf, (count++ ? ",'" : "'")); 404d1b06863SMark Murray sbuf_cat(&sbuf, rrs->rrs_source->rs_ident); 405d1b06863SMark Murray sbuf_cat(&sbuf, "'"); 406d1b06863SMark Murray } 407d1b06863SMark Murray error = sbuf_finish(&sbuf); 408d1b06863SMark Murray sbuf_delete(&sbuf); 409d1b06863SMark Murray return (error); 410d1b06863SMark Murray } 411d1b06863SMark Murray SYSCTL_PROC(_kern_random, OID_AUTO, random_sources, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 412d1b06863SMark Murray NULL, 0, random_source_handler, "A", 413d1b06863SMark Murray "List of active fast entropy sources."); 414d1b06863SMark Murray #endif /* !defined(RANDOM_DUMMY) */ 4155711939bSDavid E. O'Brien 416e1199601SMark Murray /* ARGSUSED */ 417a6278a2aSMark Murray static int 41810cb2424SMark Murray randomdev_modevent(module_t mod __unused, int type, void *data __unused) 4194db9ae91SMark Murray { 420e7806b4cSMark Murray int error = 0; 4214d87a031SMark Murray 4224db9ae91SMark Murray switch (type) { 4234db9ae91SMark Murray case MOD_LOAD: 424d1b06863SMark Murray printf("random: entropy device external interface\n"); 42510cb2424SMark Murray random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, 4263aa77530SMark Murray RANDOM_UNIT, NULL, UID_ROOT, GID_WHEEL, 0644, "random"); 42710cb2424SMark Murray make_dev_alias(random_dev, "urandom"); /* compatibility */ 428e7806b4cSMark Murray break; 4294db9ae91SMark Murray case MOD_UNLOAD: 430c9ec235cSMark Murray destroy_dev(random_dev); 431e7806b4cSMark Murray break; 4324db9ae91SMark Murray case MOD_SHUTDOWN: 433e7806b4cSMark Murray break; 4343e019deaSPoul-Henning Kamp default: 4353e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 4363e019deaSPoul-Henning Kamp break; 4374db9ae91SMark Murray } 438e7806b4cSMark Murray return (error); 4394db9ae91SMark Murray } 4404db9ae91SMark Murray 441d1b06863SMark Murray static moduledata_t randomdev_mod = { 442d1b06863SMark Murray "random_device", 443d1b06863SMark Murray randomdev_modevent, 444d1b06863SMark Murray 0 445d1b06863SMark Murray }; 44610cb2424SMark Murray 447d1b06863SMark Murray DECLARE_MODULE(random_device, randomdev_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 448d1b06863SMark Murray MODULE_VERSION(random_device, 1); 449