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