199ca880aSopenharmony_ci/*** 299ca880aSopenharmony_ci This file is part of systemd. 399ca880aSopenharmony_ci 499ca880aSopenharmony_ci Copyright 2010 Lennart Poettering 599ca880aSopenharmony_ci 699ca880aSopenharmony_ci systemd is free software; you can redistribute it and/or modify it 799ca880aSopenharmony_ci under the terms of the GNU Lesser General Public License as published by 899ca880aSopenharmony_ci the Free Software Foundation; either version 2.1 of the License, or 999ca880aSopenharmony_ci (at your option) any later version. 1099ca880aSopenharmony_ci 1199ca880aSopenharmony_ci systemd is distributed in the hope that it will be useful, but 1299ca880aSopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1399ca880aSopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1499ca880aSopenharmony_ci Lesser General Public License for more details. 1599ca880aSopenharmony_ci 1699ca880aSopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1799ca880aSopenharmony_ci along with systemd; If not, see <http://www.gnu.org/licenses/>. 1899ca880aSopenharmony_ci***/ 1999ca880aSopenharmony_ci 2099ca880aSopenharmony_ci#include <stdint.h> 2199ca880aSopenharmony_ci#include <errno.h> 2299ca880aSopenharmony_ci#include <sys/types.h> 2399ca880aSopenharmony_ci#include <sys/stat.h> 2499ca880aSopenharmony_ci#include <fcntl.h> 2599ca880aSopenharmony_ci#include <time.h> 2699ca880aSopenharmony_ci#include <linux/random.h> 2799ca880aSopenharmony_ci 2899ca880aSopenharmony_ci#include "random-util.h" 2999ca880aSopenharmony_ci#include "time-util.h" 3099ca880aSopenharmony_ci#include "missing.h" 3199ca880aSopenharmony_ci#include "util.h" 3299ca880aSopenharmony_ci 3399ca880aSopenharmony_ciint dev_urandom(void *p, size_t n) { 3499ca880aSopenharmony_ci static int have_syscall = -1; 3599ca880aSopenharmony_ci 3699ca880aSopenharmony_ci _cleanup_close_ int fd = -1; 3799ca880aSopenharmony_ci int r; 3899ca880aSopenharmony_ci 3999ca880aSopenharmony_ci /* Gathers some randomness from the kernel. This call will 4099ca880aSopenharmony_ci * never block, and will always return some data from the 4199ca880aSopenharmony_ci * kernel, regardless if the random pool is fully initialized 4299ca880aSopenharmony_ci * or not. It thus makes no guarantee for the quality of the 4399ca880aSopenharmony_ci * returned entropy, but is good enough for or usual usecases 4499ca880aSopenharmony_ci * of seeding the hash functions for hashtable */ 4599ca880aSopenharmony_ci 4699ca880aSopenharmony_ci /* Use the getrandom() syscall unless we know we don't have 4799ca880aSopenharmony_ci * it, or when the requested size is too large for it. */ 4899ca880aSopenharmony_ci if (have_syscall != 0 || (size_t) (int) n != n) { 4999ca880aSopenharmony_ci r = getrandom(p, n, GRND_NONBLOCK); 5099ca880aSopenharmony_ci if (r == (int) n) { 5199ca880aSopenharmony_ci have_syscall = true; 5299ca880aSopenharmony_ci return 0; 5399ca880aSopenharmony_ci } 5499ca880aSopenharmony_ci 5599ca880aSopenharmony_ci if (r < 0) { 5699ca880aSopenharmony_ci if (errno == ENOSYS) 5799ca880aSopenharmony_ci /* we lack the syscall, continue with 5899ca880aSopenharmony_ci * reading from /dev/urandom */ 5999ca880aSopenharmony_ci have_syscall = false; 6099ca880aSopenharmony_ci else if (errno == EAGAIN) 6199ca880aSopenharmony_ci /* not enough entropy for now. Let's 6299ca880aSopenharmony_ci * remember to use the syscall the 6399ca880aSopenharmony_ci * next time, again, but also read 6499ca880aSopenharmony_ci * from /dev/urandom for now, which 6599ca880aSopenharmony_ci * doesn't care about the current 6699ca880aSopenharmony_ci * amount of entropy. */ 6799ca880aSopenharmony_ci have_syscall = true; 6899ca880aSopenharmony_ci else 6999ca880aSopenharmony_ci return -errno; 7099ca880aSopenharmony_ci } else 7199ca880aSopenharmony_ci /* too short read? */ 7299ca880aSopenharmony_ci return -ENODATA; 7399ca880aSopenharmony_ci } 7499ca880aSopenharmony_ci 7599ca880aSopenharmony_ci fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); 7699ca880aSopenharmony_ci if (fd < 0) 7799ca880aSopenharmony_ci return errno == ENOENT ? -ENOSYS : -errno; 7899ca880aSopenharmony_ci 7999ca880aSopenharmony_ci return loop_read_exact(fd, p, n, true); 8099ca880aSopenharmony_ci} 8199ca880aSopenharmony_ci 8299ca880aSopenharmony_civoid initialize_srand(void) { 8399ca880aSopenharmony_ci static bool srand_called = false; 8499ca880aSopenharmony_ci unsigned x; 8599ca880aSopenharmony_ci#ifdef HAVE_SYS_AUXV_H 8699ca880aSopenharmony_ci void *auxv; 8799ca880aSopenharmony_ci#endif 8899ca880aSopenharmony_ci 8999ca880aSopenharmony_ci if (srand_called) 9099ca880aSopenharmony_ci return; 9199ca880aSopenharmony_ci 9299ca880aSopenharmony_ci x = 0; 9399ca880aSopenharmony_ci 9499ca880aSopenharmony_ci#ifdef HAVE_SYS_AUXV_H 9599ca880aSopenharmony_ci /* The kernel provides us with a bit of entropy in auxv, so 9699ca880aSopenharmony_ci * let's try to make use of that to seed the pseudo-random 9799ca880aSopenharmony_ci * generator. It's better than nothing... */ 9899ca880aSopenharmony_ci 9999ca880aSopenharmony_ci auxv = (void*) getauxval(AT_RANDOM); 10099ca880aSopenharmony_ci if (auxv) 10199ca880aSopenharmony_ci x ^= *(unsigned*) auxv; 10299ca880aSopenharmony_ci#endif 10399ca880aSopenharmony_ci 10499ca880aSopenharmony_ci x ^= (unsigned) now(CLOCK_REALTIME); 10599ca880aSopenharmony_ci x ^= (unsigned) gettid(); 10699ca880aSopenharmony_ci 10799ca880aSopenharmony_ci srand(x); 10899ca880aSopenharmony_ci srand_called = true; 10999ca880aSopenharmony_ci} 11099ca880aSopenharmony_ci 11199ca880aSopenharmony_civoid random_bytes(void *p, size_t n) { 11299ca880aSopenharmony_ci uint8_t *q; 11399ca880aSopenharmony_ci int r; 11499ca880aSopenharmony_ci 11599ca880aSopenharmony_ci r = dev_urandom(p, n); 11699ca880aSopenharmony_ci if (r >= 0) 11799ca880aSopenharmony_ci return; 11899ca880aSopenharmony_ci 11999ca880aSopenharmony_ci /* If some idiot made /dev/urandom unavailable to us, he'll 12099ca880aSopenharmony_ci * get a PRNG instead. */ 12199ca880aSopenharmony_ci 12299ca880aSopenharmony_ci initialize_srand(); 12399ca880aSopenharmony_ci 12499ca880aSopenharmony_ci for (q = p; q < (uint8_t*) p + n; q ++) 12599ca880aSopenharmony_ci *q = rand(); 12699ca880aSopenharmony_ci} 127