]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/random-util.c
util-lib: split out IO related calls to io-util.[ch]
[thirdparty/systemd.git] / src / basic / random-util.c
CommitLineData
3df3e884
RC
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
3df3e884 20#include <errno.h>
3df3e884 21#include <fcntl.h>
3ffd4af2
LP
22#include <linux/random.h>
23#include <stdint.h>
a67dab34 24#ifdef HAVE_SYS_AUXV_H
3df3e884 25#include <sys/auxv.h>
a67dab34 26#endif
3ffd4af2
LP
27#include <sys/stat.h>
28#include <sys/types.h>
29#include <time.h>
3df3e884 30
3ffd4af2 31#include "fd-util.h"
c004493c 32#include "io-util.h"
3ffd4af2 33#include "missing.h"
3df3e884
RC
34#include "random-util.h"
35#include "time-util.h"
3df3e884
RC
36#include "util.h"
37
38int dev_urandom(void *p, size_t n) {
39 static int have_syscall = -1;
40
41 _cleanup_close_ int fd = -1;
42 int r;
43
44 /* Gathers some randomness from the kernel. This call will
45 * never block, and will always return some data from the
46 * kernel, regardless if the random pool is fully initialized
47 * or not. It thus makes no guarantee for the quality of the
48 * returned entropy, but is good enough for or usual usecases
49 * of seeding the hash functions for hashtable */
50
51 /* Use the getrandom() syscall unless we know we don't have
52 * it, or when the requested size is too large for it. */
53 if (have_syscall != 0 || (size_t) (int) n != n) {
54 r = getrandom(p, n, GRND_NONBLOCK);
55 if (r == (int) n) {
56 have_syscall = true;
57 return 0;
58 }
59
60 if (r < 0) {
61 if (errno == ENOSYS)
62 /* we lack the syscall, continue with
63 * reading from /dev/urandom */
64 have_syscall = false;
65 else if (errno == EAGAIN)
66 /* not enough entropy for now. Let's
67 * remember to use the syscall the
68 * next time, again, but also read
69 * from /dev/urandom for now, which
70 * doesn't care about the current
71 * amount of entropy. */
72 have_syscall = true;
73 else
74 return -errno;
75 } else
76 /* too short read? */
77 return -ENODATA;
78 }
79
80 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
81 if (fd < 0)
82 return errno == ENOENT ? -ENOSYS : -errno;
83
84 return loop_read_exact(fd, p, n, true);
85}
86
87void initialize_srand(void) {
88 static bool srand_called = false;
89 unsigned x;
90#ifdef HAVE_SYS_AUXV_H
91 void *auxv;
92#endif
93
94 if (srand_called)
95 return;
96
97 x = 0;
98
99#ifdef HAVE_SYS_AUXV_H
100 /* The kernel provides us with a bit of entropy in auxv, so
101 * let's try to make use of that to seed the pseudo-random
102 * generator. It's better than nothing... */
103
104 auxv = (void*) getauxval(AT_RANDOM);
105 if (auxv)
106 x ^= *(unsigned*) auxv;
107#endif
108
109 x ^= (unsigned) now(CLOCK_REALTIME);
110 x ^= (unsigned) gettid();
111
112 srand(x);
113 srand_called = true;
114}
115
116void random_bytes(void *p, size_t n) {
117 uint8_t *q;
118 int r;
119
120 r = dev_urandom(p, n);
121 if (r >= 0)
122 return;
123
124 /* If some idiot made /dev/urandom unavailable to us, he'll
125 * get a PRNG instead. */
126
127 initialize_srand();
128
129 for (q = p; q < (uint8_t*) p + n; q ++)
130 *q = rand();
131}