#include <unistd.h>
#include <fcntl.h>
+/* get randomness from either getrandom, arc4random or /dev/urandom */
+
+#if defined(HAVE_GETRANDOM) && HAVE_DECL_GETRANDOM != 0
+# include <sys/random.h>
+# define USE_GETRANDOM
+#elif defined(HAVE_ARC4RANDOM)
+# if defined(HAVE_LIBBSD)
+# include <bsd/stdlib.h>
+# endif
+# define USE_ARC4RANDOM
+#else
+# define USE_RANDOM_DEV
+#endif
+
static int init_refcount = 0;
+#if defined(USE_RANDOM_DEV)
static int urandom_fd;
+#endif
void random_fill(void *buf, size_t size)
{
- size_t pos;
- ssize_t ret;
-
i_assert(init_refcount > 0);
i_assert(size < SSIZE_T_MAX);
+#if defined(USE_ARC4RANDOM)
+ arc4random_buf(buf, size);
+#else
+ size_t pos;
+ ssize_t ret;
+
for (pos = 0; pos < size; ) {
+# if defined(USE_GETRANDOM)
+ ret = getrandom(buf, size - pos, 0);
+# else
ret = read(urandom_fd, (char *) buf + pos, size - pos);
+# endif
if (unlikely(ret <= 0)) {
if (ret == 0)
- i_fatal("EOF when reading from "DEV_URANDOM_PATH);
+ i_fatal("read("DEV_URANDOM_PATH") failed: EOF");
else if (errno != EINTR)
+# if defined(USE_RANDOM_DEV)
i_fatal("read("DEV_URANDOM_PATH") failed: %m");
+# elif defined(USE_GETRANDOM)
+ i_fatal("getrandom() failed: %m");
+# endif
} else {
pos += ret;
}
}
+#endif /* defined(USE_ARC4RANDOM) */
}
void random_init(void)
if (init_refcount++ > 0)
return;
-
+#if defined(USE_RANDOM_DEV)
urandom_fd = open(DEV_URANDOM_PATH, O_RDONLY);
if (urandom_fd == -1) {
if (errno == ENOENT) {
- i_fatal(DEV_URANDOM_PATH" doesn't exist, "
+ i_fatal("open("DEV_URANDOM_PATH") failed: doesn't exist,"
"currently we require it");
} else {
- i_fatal("Can't open "DEV_URANDOM_PATH": %m");
+ i_fatal("open("DEV_URANDOM_PATH") failed: %m");
}
}
-
+ fd_close_on_exec(urandom_fd, TRUE);
+#endif
random_fill(&seed, sizeof(seed));
srand(seed);
-
- fd_close_on_exec(urandom_fd, TRUE);
}
void random_deinit(void)
{
if (--init_refcount > 0)
return;
-
+#if defined(USE_RANDOM_DEV)
i_close_fd(&urandom_fd);
-}
-
-#ifdef HAVE_ARC4RANDOM
-#ifdef HAVE_LIBBSD
-#include <bsd/stdlib.h>
#endif
-
-void random_fill_weak(void *buf, size_t size)
-{
- arc4random_buf(buf, size);
}
-
-#else
-
-void random_fill_weak(void *buf, size_t size)
-{
- unsigned char *cbuf = buf;
-
- for (; size > 0; size--)
- *cbuf++ = (unsigned char)rand();
-}
-
-#endif
#ifndef RANDGEN_H
#define RANDGEN_H
-/* Fill given buffer with semi-strong randomness, usually from /dev/urandom. */
+/* Fill given buffer with semi-strong randomness */
void random_fill(void *buf, size_t size);
-/* Fill given buffer with weak randomness, ie. with rand(). This is better if
- no real randomness is required, as reading from /dev/urandom usually also
- consumes /dev/random entropy, which may disturb other processes. */
-void random_fill_weak(void *buf, size_t size);
+#define random_fill_weak(buf,size) random_fill((buf), (size))
-/* may be called multiple times */
+/* may be called multiple times,
+ and are called by default in lib_init */
void random_init(void);
void random_deinit(void);