11c9bd843Sdinak /* 21c9bd843Sdinak * CDDL HEADER START 31c9bd843Sdinak * 41c9bd843Sdinak * The contents of this file are subject to the terms of the 51c9bd843Sdinak * Common Development and Distribution License (the "License"). 61c9bd843Sdinak * You may not use this file except in compliance with the License. 71c9bd843Sdinak * 81c9bd843Sdinak * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91c9bd843Sdinak * or http://www.opensolaris.org/os/licensing. 101c9bd843Sdinak * See the License for the specific language governing permissions 111c9bd843Sdinak * and limitations under the License. 121c9bd843Sdinak * 131c9bd843Sdinak * When distributing Covered Code, include this CDDL HEADER in each 141c9bd843Sdinak * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151c9bd843Sdinak * If applicable, add the following below this CDDL HEADER, with the 161c9bd843Sdinak * fields enclosed by brackets "[]" replaced with your own identifying 171c9bd843Sdinak * information: Portions Copyright [yyyy] [name of copyright owner] 181c9bd843Sdinak * 191c9bd843Sdinak * CDDL HEADER END 201c9bd843Sdinak */ 2141cf421dSDina K Nimeh 221c9bd843Sdinak /* 2341cf421dSDina K Nimeh * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24*05d57413SDan McDonald * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. 251c9bd843Sdinak */ 261c9bd843Sdinak 271c9bd843Sdinak #include <stdio.h> 2826ff1ce9Sdinak #include <unistd.h> 2926ff1ce9Sdinak #include <errno.h> 301c9bd843Sdinak #include <string.h> 311c9bd843Sdinak #include <fcntl.h> 321c9bd843Sdinak #include <locale.h> 3319193bb6SDina K Nimeh #include <stdarg.h> 341c9bd843Sdinak #include <cryptoutil.h> 3526ff1ce9Sdinak #include <pthread.h> 3626ff1ce9Sdinak 37*05d57413SDan McDonald #pragma init(pkcs11_random_init) 387b79d846SDina K Nimeh 3926ff1ce9Sdinak static pthread_mutex_t random_mutex = PTHREAD_MUTEX_INITIALIZER; 4026ff1ce9Sdinak static pthread_mutex_t urandom_mutex = PTHREAD_MUTEX_INITIALIZER; 4126ff1ce9Sdinak 427b79d846SDina K Nimeh static pthread_mutex_t random_seed_mutex = PTHREAD_MUTEX_INITIALIZER; 437b79d846SDina K Nimeh static pthread_mutex_t urandom_seed_mutex = PTHREAD_MUTEX_INITIALIZER; 4426ff1ce9Sdinak 4526ff1ce9Sdinak #define RANDOM_DEVICE "/dev/random" /* random device name */ 4626ff1ce9Sdinak #define URANDOM_DEVICE "/dev/urandom" /* urandom device name */ 4726ff1ce9Sdinak 4826ff1ce9Sdinak static int random_fd = -1; 4926ff1ce9Sdinak static int urandom_fd = -1; 5026ff1ce9Sdinak 517b79d846SDina K Nimeh static int random_seed_fd = -1; 527b79d846SDina K Nimeh static int urandom_seed_fd = -1; 537b79d846SDina K Nimeh 547b79d846SDina K Nimeh 5526ff1ce9Sdinak /* 5626ff1ce9Sdinak * Equivalent of open(2) insulated from EINTR. 5726ff1ce9Sdinak * Also sets close-on-exec. 5826ff1ce9Sdinak */ 5919193bb6SDina K Nimeh int 6019193bb6SDina K Nimeh open_nointr(const char *path, int oflag, ...) 6126ff1ce9Sdinak { 6226ff1ce9Sdinak int fd; 6319193bb6SDina K Nimeh mode_t pmode; 6419193bb6SDina K Nimeh va_list alist; 6519193bb6SDina K Nimeh 6619193bb6SDina K Nimeh va_start(alist, oflag); 6719193bb6SDina K Nimeh pmode = va_arg(alist, mode_t); 6819193bb6SDina K Nimeh va_end(alist); 6926ff1ce9Sdinak 7026ff1ce9Sdinak do { 7119193bb6SDina K Nimeh if ((fd = open(path, oflag, pmode)) >= 0) { 7226ff1ce9Sdinak (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 7326ff1ce9Sdinak break; 7426ff1ce9Sdinak } 7526ff1ce9Sdinak /* errno definitely set by failed open() */ 7626ff1ce9Sdinak } while (errno == EINTR); 7726ff1ce9Sdinak return (fd); 7826ff1ce9Sdinak } 7926ff1ce9Sdinak 8026ff1ce9Sdinak /* 8126ff1ce9Sdinak * Equivalent of read(2) insulated from EINTR. 8226ff1ce9Sdinak */ 8319193bb6SDina K Nimeh ssize_t 8419193bb6SDina K Nimeh readn_nointr(int fd, void *dbuf, size_t dlen) 8526ff1ce9Sdinak { 8626ff1ce9Sdinak char *marker = dbuf; 8726ff1ce9Sdinak size_t left = dlen; 8826ff1ce9Sdinak ssize_t nread = 0, err; 8926ff1ce9Sdinak 9026ff1ce9Sdinak for (err = 0; left > 0 && nread != -1; marker += nread, left -= nread) { 9126ff1ce9Sdinak if ((nread = read(fd, marker, left)) < 0) { 9226ff1ce9Sdinak if (errno == EINTR) { /* keep trying */ 9326ff1ce9Sdinak nread = 0; 9426ff1ce9Sdinak continue; 9526ff1ce9Sdinak } 9626ff1ce9Sdinak err = nread; /* hard error */ 9726ff1ce9Sdinak break; 9819193bb6SDina K Nimeh } else if (nread == 0) { 9919193bb6SDina K Nimeh break; 10019193bb6SDina K Nimeh } 10119193bb6SDina K Nimeh } 10219193bb6SDina K Nimeh return (err != 0 ? err : dlen - left); 10319193bb6SDina K Nimeh } 10419193bb6SDina K Nimeh 10519193bb6SDina K Nimeh /* 10619193bb6SDina K Nimeh * Equivalent of write(2) insulated from EINTR. 10719193bb6SDina K Nimeh */ 10819193bb6SDina K Nimeh ssize_t 10919193bb6SDina K Nimeh writen_nointr(int fd, void *dbuf, size_t dlen) 11019193bb6SDina K Nimeh { 11119193bb6SDina K Nimeh char *marker = dbuf; 11219193bb6SDina K Nimeh size_t left = dlen; 11319193bb6SDina K Nimeh ssize_t nwrite = 0, err; 11419193bb6SDina K Nimeh 11519193bb6SDina K Nimeh for (err = 0; left > 0 && nwrite != -1; marker += nwrite, 11619193bb6SDina K Nimeh left -= nwrite) { 11719193bb6SDina K Nimeh if ((nwrite = write(fd, marker, left)) < 0) { 11819193bb6SDina K Nimeh if (errno == EINTR) { /* keep trying */ 11919193bb6SDina K Nimeh nwrite = 0; 12019193bb6SDina K Nimeh continue; 12119193bb6SDina K Nimeh } 12219193bb6SDina K Nimeh err = nwrite; /* hard error */ 12319193bb6SDina K Nimeh break; 12419193bb6SDina K Nimeh } else if (nwrite == 0) { 12519193bb6SDina K Nimeh break; 12626ff1ce9Sdinak } 12726ff1ce9Sdinak } 12826ff1ce9Sdinak return (err != 0 ? err : dlen - left); 12926ff1ce9Sdinak } 13026ff1ce9Sdinak 13126ff1ce9Sdinak /* 13226ff1ce9Sdinak * Opens the random number generator devices if not already open. 13326ff1ce9Sdinak * Always returns the opened fd of the device, or error. 13426ff1ce9Sdinak */ 1357b79d846SDina K Nimeh static int 1367b79d846SDina K Nimeh pkcs11_open_common(int *fd, pthread_mutex_t *mtx, const char *dev, int oflag) 13726ff1ce9Sdinak { 1387b79d846SDina K Nimeh (void) pthread_mutex_lock(mtx); 1397b79d846SDina K Nimeh if (*fd < 0) 1407b79d846SDina K Nimeh *fd = open_nointr(dev, oflag); 1417b79d846SDina K Nimeh (void) pthread_mutex_unlock(mtx); 14241cf421dSDina K Nimeh 1437b79d846SDina K Nimeh return (*fd); 14426ff1ce9Sdinak } 14526ff1ce9Sdinak 1467b79d846SDina K Nimeh static int 1477b79d846SDina K Nimeh pkcs11_open_random(void) 1487b79d846SDina K Nimeh { 1497b79d846SDina K Nimeh return (pkcs11_open_common(&random_fd, &random_mutex, 1507b79d846SDina K Nimeh RANDOM_DEVICE, O_RDONLY)); 1517b79d846SDina K Nimeh } 1527b79d846SDina K Nimeh 1537b79d846SDina K Nimeh static int 15426ff1ce9Sdinak pkcs11_open_urandom(void) 15526ff1ce9Sdinak { 1567b79d846SDina K Nimeh return (pkcs11_open_common(&urandom_fd, &urandom_mutex, 1577b79d846SDina K Nimeh URANDOM_DEVICE, O_RDONLY)); 1587b79d846SDina K Nimeh } 1597b79d846SDina K Nimeh 1607b79d846SDina K Nimeh static int 1617b79d846SDina K Nimeh pkcs11_open_random_seed(void) 1627b79d846SDina K Nimeh { 1637b79d846SDina K Nimeh return (pkcs11_open_common(&random_seed_fd, &random_seed_mutex, 1647b79d846SDina K Nimeh RANDOM_DEVICE, O_WRONLY)); 1657b79d846SDina K Nimeh } 1667b79d846SDina K Nimeh 1677b79d846SDina K Nimeh static int 1687b79d846SDina K Nimeh pkcs11_open_urandom_seed(void) 1697b79d846SDina K Nimeh { 1707b79d846SDina K Nimeh return (pkcs11_open_common(&urandom_seed_fd, &urandom_seed_mutex, 1717b79d846SDina K Nimeh URANDOM_DEVICE, O_WRONLY)); 17226ff1ce9Sdinak } 17326ff1ce9Sdinak 17426ff1ce9Sdinak /* 17526ff1ce9Sdinak * Close the random number generator devices if already open. 17626ff1ce9Sdinak */ 1777b79d846SDina K Nimeh static void 1787b79d846SDina K Nimeh pkcs11_close_common(int *fd, pthread_mutex_t *mtx) 1797b79d846SDina K Nimeh { 1807b79d846SDina K Nimeh (void) pthread_mutex_lock(mtx); 1817b79d846SDina K Nimeh (void) close(*fd); 1827b79d846SDina K Nimeh *fd = -1; 1837b79d846SDina K Nimeh (void) pthread_mutex_unlock(mtx); 1847b79d846SDina K Nimeh } 1857b79d846SDina K Nimeh 186*05d57413SDan McDonald static void 18726ff1ce9Sdinak pkcs11_close_random(void) 18826ff1ce9Sdinak { 1897b79d846SDina K Nimeh pkcs11_close_common(&random_fd, &random_mutex); 19026ff1ce9Sdinak } 19126ff1ce9Sdinak 192*05d57413SDan McDonald static void 19326ff1ce9Sdinak pkcs11_close_urandom(void) 19426ff1ce9Sdinak { 1957b79d846SDina K Nimeh pkcs11_close_common(&urandom_fd, &urandom_mutex); 1967b79d846SDina K Nimeh } 1977b79d846SDina K Nimeh 1987b79d846SDina K Nimeh static void 1997b79d846SDina K Nimeh pkcs11_close_random_seed(void) 2007b79d846SDina K Nimeh { 2017b79d846SDina K Nimeh pkcs11_close_common(&random_seed_fd, &random_seed_mutex); 2027b79d846SDina K Nimeh } 2037b79d846SDina K Nimeh 204*05d57413SDan McDonald static void 2057b79d846SDina K Nimeh pkcs11_close_urandom_seed(void) 2067b79d846SDina K Nimeh { 2077b79d846SDina K Nimeh pkcs11_close_common(&urandom_seed_fd, &urandom_seed_mutex); 2087b79d846SDina K Nimeh } 2097b79d846SDina K Nimeh 2107b79d846SDina K Nimeh /* 21141cf421dSDina K Nimeh * Read from the random number generator devices. 21241cf421dSDina K Nimeh */ 21341cf421dSDina K Nimeh static size_t 21441cf421dSDina K Nimeh pkcs11_read_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen) 21541cf421dSDina K Nimeh { 21641cf421dSDina K Nimeh size_t n; 21741cf421dSDina K Nimeh 21841cf421dSDina K Nimeh (void) pthread_mutex_lock(mtx); 21941cf421dSDina K Nimeh n = readn_nointr(*fd, dbuf, dlen); 22041cf421dSDina K Nimeh (void) pthread_mutex_unlock(mtx); 22141cf421dSDina K Nimeh 22241cf421dSDina K Nimeh return (n); 22341cf421dSDina K Nimeh } 22441cf421dSDina K Nimeh 22541cf421dSDina K Nimeh static size_t 22641cf421dSDina K Nimeh pkcs11_read_random(void *dbuf, size_t dlen) 22741cf421dSDina K Nimeh { 22841cf421dSDina K Nimeh return (pkcs11_read_common(&random_fd, &random_mutex, dbuf, dlen)); 22941cf421dSDina K Nimeh } 23041cf421dSDina K Nimeh 23141cf421dSDina K Nimeh static size_t 23241cf421dSDina K Nimeh pkcs11_read_urandom(void *dbuf, size_t dlen) 23341cf421dSDina K Nimeh { 23441cf421dSDina K Nimeh return (pkcs11_read_common(&urandom_fd, &urandom_mutex, dbuf, dlen)); 23541cf421dSDina K Nimeh } 23641cf421dSDina K Nimeh 23741cf421dSDina K Nimeh /* 23841cf421dSDina K Nimeh * Write to the random number generator devices. 23941cf421dSDina K Nimeh */ 24041cf421dSDina K Nimeh static size_t 24141cf421dSDina K Nimeh pkcs11_write_common(int *fd, pthread_mutex_t *mtx, void *dbuf, size_t dlen) 24241cf421dSDina K Nimeh { 24341cf421dSDina K Nimeh size_t n; 24441cf421dSDina K Nimeh 24541cf421dSDina K Nimeh (void) pthread_mutex_lock(mtx); 24641cf421dSDina K Nimeh n = writen_nointr(*fd, dbuf, dlen); 24741cf421dSDina K Nimeh (void) pthread_mutex_unlock(mtx); 24841cf421dSDina K Nimeh 24941cf421dSDina K Nimeh return (n); 25041cf421dSDina K Nimeh } 25141cf421dSDina K Nimeh 25241cf421dSDina K Nimeh static size_t 25341cf421dSDina K Nimeh pkcs11_write_random_seed(void *dbuf, size_t dlen) 25441cf421dSDina K Nimeh { 25541cf421dSDina K Nimeh return (pkcs11_write_common(&random_seed_fd, &random_seed_mutex, 25641cf421dSDina K Nimeh dbuf, dlen)); 25741cf421dSDina K Nimeh } 25841cf421dSDina K Nimeh 25941cf421dSDina K Nimeh static size_t 26041cf421dSDina K Nimeh pkcs11_write_urandom_seed(void *dbuf, size_t dlen) 26141cf421dSDina K Nimeh { 26241cf421dSDina K Nimeh return (pkcs11_write_common(&urandom_seed_fd, &urandom_seed_mutex, 26341cf421dSDina K Nimeh dbuf, dlen)); 26441cf421dSDina K Nimeh } 26541cf421dSDina K Nimeh 26641cf421dSDina K Nimeh /* 2677b79d846SDina K Nimeh * Seed /dev/random with the data in the buffer. 2687b79d846SDina K Nimeh */ 2697b79d846SDina K Nimeh int 2707b79d846SDina K Nimeh pkcs11_seed_random(void *sbuf, size_t slen) 2717b79d846SDina K Nimeh { 27241cf421dSDina K Nimeh int rv; 27341cf421dSDina K Nimeh 2747b79d846SDina K Nimeh if (sbuf == NULL || slen == 0) 2757b79d846SDina K Nimeh return (0); 2767b79d846SDina K Nimeh 2777b79d846SDina K Nimeh /* Seeding error could mean it's not supported (errno = EACCES) */ 2787b79d846SDina K Nimeh if (pkcs11_open_random_seed() < 0) 2797b79d846SDina K Nimeh return (-1); 2807b79d846SDina K Nimeh 28141cf421dSDina K Nimeh rv = -1; 28241cf421dSDina K Nimeh if (pkcs11_write_random_seed(sbuf, slen) == slen) 28341cf421dSDina K Nimeh rv = 0; 28441cf421dSDina K Nimeh 2857b79d846SDina K Nimeh pkcs11_close_random_seed(); 28641cf421dSDina K Nimeh return (rv); 2877b79d846SDina K Nimeh } 2887b79d846SDina K Nimeh 2897b79d846SDina K Nimeh /* 2907b79d846SDina K Nimeh * Seed /dev/urandom with the data in the buffer. 2917b79d846SDina K Nimeh */ 2927b79d846SDina K Nimeh int 2937b79d846SDina K Nimeh pkcs11_seed_urandom(void *sbuf, size_t slen) 2947b79d846SDina K Nimeh { 29541cf421dSDina K Nimeh int rv; 29641cf421dSDina K Nimeh 2977b79d846SDina K Nimeh if (sbuf == NULL || slen == 0) 2987b79d846SDina K Nimeh return (0); 2997b79d846SDina K Nimeh 3007b79d846SDina K Nimeh /* Seeding error could mean it's not supported (errno = EACCES) */ 3017b79d846SDina K Nimeh if (pkcs11_open_urandom_seed() < 0) 3027b79d846SDina K Nimeh return (-1); 3037b79d846SDina K Nimeh 30441cf421dSDina K Nimeh rv = -1; 30541cf421dSDina K Nimeh if (pkcs11_write_urandom_seed(sbuf, slen) == slen) 30641cf421dSDina K Nimeh rv = 0; 30741cf421dSDina K Nimeh 3087b79d846SDina K Nimeh pkcs11_close_urandom_seed(); 30941cf421dSDina K Nimeh return (rv); 3107b79d846SDina K Nimeh } 3117b79d846SDina K Nimeh 3127b79d846SDina K Nimeh /* 3137b79d846SDina K Nimeh * Put the requested amount of random data into a preallocated buffer. 3147b79d846SDina K Nimeh * Good for token key data, persistent objects. 3157b79d846SDina K Nimeh */ 3167b79d846SDina K Nimeh int 3177b79d846SDina K Nimeh pkcs11_get_random(void *dbuf, size_t dlen) 3187b79d846SDina K Nimeh { 3197b79d846SDina K Nimeh if (dbuf == NULL || dlen == 0) 3207b79d846SDina K Nimeh return (0); 3217b79d846SDina K Nimeh 3227b79d846SDina K Nimeh /* Read random data directly from /dev/random */ 3237b79d846SDina K Nimeh if (pkcs11_open_random() < 0) 3247b79d846SDina K Nimeh return (-1); 3257b79d846SDina K Nimeh 32641cf421dSDina K Nimeh if (pkcs11_read_random(dbuf, dlen) == dlen) 3277b79d846SDina K Nimeh return (0); 3287b79d846SDina K Nimeh return (-1); 32926ff1ce9Sdinak } 3301c9bd843Sdinak 3311c9bd843Sdinak /* 3321c9bd843Sdinak * Put the requested amount of random data into a preallocated buffer. 3331c9bd843Sdinak * Good for passphrase salts, initialization vectors. 3341c9bd843Sdinak */ 3351c9bd843Sdinak int 3367b79d846SDina K Nimeh pkcs11_get_urandom(void *dbuf, size_t dlen) 3371c9bd843Sdinak { 3381c9bd843Sdinak if (dbuf == NULL || dlen == 0) 3391c9bd843Sdinak return (0); 3401c9bd843Sdinak 3411c9bd843Sdinak /* Read random data directly from /dev/urandom */ 34226ff1ce9Sdinak if (pkcs11_open_urandom() < 0) 3431c9bd843Sdinak return (-1); 34426ff1ce9Sdinak 34541cf421dSDina K Nimeh if (pkcs11_read_urandom(dbuf, dlen) == dlen) 34626ff1ce9Sdinak return (0); 34726ff1ce9Sdinak return (-1); 34826ff1ce9Sdinak } 34926ff1ce9Sdinak 35026ff1ce9Sdinak /* 3517b79d846SDina K Nimeh * Same as pkcs11_get_urandom but ensures non zero data. 35226ff1ce9Sdinak */ 35326ff1ce9Sdinak int 3547b79d846SDina K Nimeh pkcs11_get_nzero_urandom(void *dbuf, size_t dlen) 35526ff1ce9Sdinak { 35626ff1ce9Sdinak char extrarand[32]; 35726ff1ce9Sdinak size_t bytesleft = 0; 35826ff1ce9Sdinak size_t i = 0; 35926ff1ce9Sdinak 36026ff1ce9Sdinak /* Start with some random data */ 3617b79d846SDina K Nimeh if (pkcs11_get_urandom(dbuf, dlen) < 0) 36226ff1ce9Sdinak return (-1); 36326ff1ce9Sdinak 36426ff1ce9Sdinak /* Walk through data replacing any 0 bytes with more random data */ 36526ff1ce9Sdinak while (i < dlen) { 36626ff1ce9Sdinak if (((char *)dbuf)[i] != 0) { 36726ff1ce9Sdinak i++; 36826ff1ce9Sdinak continue; 36926ff1ce9Sdinak } 37026ff1ce9Sdinak 37126ff1ce9Sdinak if (bytesleft == 0) { 37226ff1ce9Sdinak bytesleft = sizeof (extrarand); 3737b79d846SDina K Nimeh if (pkcs11_get_urandom(extrarand, bytesleft) < 0) 37426ff1ce9Sdinak return (-1); 37526ff1ce9Sdinak } 37626ff1ce9Sdinak bytesleft--; 37726ff1ce9Sdinak 37826ff1ce9Sdinak ((char *)dbuf)[i] = extrarand[bytesleft]; 37926ff1ce9Sdinak } 38026ff1ce9Sdinak return (0); 3811c9bd843Sdinak } 382*05d57413SDan McDonald 383*05d57413SDan McDonald static void 384*05d57413SDan McDonald pkcs11_random_prepare(void) 385*05d57413SDan McDonald { 386*05d57413SDan McDonald /* 387*05d57413SDan McDonald * NOTE - None of these are acquired more than one at a time. 388*05d57413SDan McDonald * I can therefore acquire all four without fear of deadlock. 389*05d57413SDan McDonald */ 390*05d57413SDan McDonald (void) pthread_mutex_lock(&random_mutex); 391*05d57413SDan McDonald (void) pthread_mutex_lock(&urandom_mutex); 392*05d57413SDan McDonald (void) pthread_mutex_lock(&random_seed_mutex); 393*05d57413SDan McDonald (void) pthread_mutex_lock(&urandom_seed_mutex); 394*05d57413SDan McDonald } 395*05d57413SDan McDonald 396*05d57413SDan McDonald static void 397*05d57413SDan McDonald pkcs11_random_parent_post(void) 398*05d57413SDan McDonald { 399*05d57413SDan McDonald /* Drop the mutexes and get back to work! */ 400*05d57413SDan McDonald (void) pthread_mutex_unlock(&urandom_seed_mutex); 401*05d57413SDan McDonald (void) pthread_mutex_unlock(&random_seed_mutex); 402*05d57413SDan McDonald (void) pthread_mutex_unlock(&urandom_mutex); 403*05d57413SDan McDonald (void) pthread_mutex_unlock(&random_mutex); 404*05d57413SDan McDonald } 405*05d57413SDan McDonald 406*05d57413SDan McDonald static void 407*05d57413SDan McDonald pkcs11_random_child_post(void) 408*05d57413SDan McDonald { 409*05d57413SDan McDonald pkcs11_random_parent_post(); 410*05d57413SDan McDonald 411*05d57413SDan McDonald /* Also, close the FDs, just in case. */ 412*05d57413SDan McDonald pkcs11_close_random(); 413*05d57413SDan McDonald pkcs11_close_urandom(); 414*05d57413SDan McDonald pkcs11_close_random_seed(); 415*05d57413SDan McDonald pkcs11_close_urandom_seed(); 416*05d57413SDan McDonald } 417*05d57413SDan McDonald 418*05d57413SDan McDonald static void 419*05d57413SDan McDonald pkcs11_random_init(void) 420*05d57413SDan McDonald { 421*05d57413SDan McDonald (void) pthread_atfork(pkcs11_random_prepare, pkcs11_random_parent_post, 422*05d57413SDan McDonald pkcs11_random_child_post); 423*05d57413SDan McDonald } 424