emacs/lib/getrandom.c

188 lines
5.5 KiB
C
Raw Normal View History

Update from Gnulib This incorporates: 2020-06-27 getloadavg: don’t depend on fopen-gnu 2020-06-25 c-dtoastr, c-ldtoastr: new modules 2020-06-01 getloadavg: fix double-increment bug 2020-06-01 tempname: use getrandom, not getentropy 2020-05-31 tempname: merge from glibc and coreutils 2020-05-31 getentropy: work around a macOS and Solaris problem 2020-05-31 fnmatch: merge from glibc 2020-05-30 unistd: remove conflicting declaration of getrandom 2020-05-30 don't assume that UNICODE is not defined 2020-05-29 fix compilation error on native Windows 2020-05-28 avoid dynamic loading of Windows API functions when possible 2020-05-28 at-internal: make more robust in multithreaded applications 2020-05-28 getloadavg: make more robust in multithreaded applications 2020-05-27 getloadavg: make more robust in multithreaded applications 2020-05-26 count-one-bits: fix MSVC specific code 2020-05-25 getentropy, getrandom: new modules 2020-05-24 open, openat: really support O_CLOEXEC 2020-05-23 verify: document ‘assume’ better 2020-05-21 regex: configure better with "clang -fsanitize=leak" 2020-05-21 memmem: configure better with "clang -fsanitize=undefined" 2020-05-19 ftoastr: fix ifndef typo * build-aux/config.guess, build-aux/config.sub, doc/misc/texinfo.tex: * lib/count-one-bits.h, lib/ftoastr.c, lib/ftoastr.h: * lib/getloadavg.c, lib/gettimeofday.c, lib/libc-config.h: * lib/open.c, lib/openat-proc.c, lib/tempname.c, lib/tempname.h: * lib/unistd.in.h, lib/verify.h, m4/memmem.m4, m4/regex.m4: * m4/unistd_h.m4: Update from Gnulib. * lib/getrandom.c, lib/sys_random.in.h: * m4/getrandom.m4, m4/sys_random_h.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
2020-06-27 10:00:17 -07:00
/* Obtain a series of random bytes.
Copyright 2020 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
#include <config.h>
#include <sys/random.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <unistd.h>
#if defined _WIN32 && ! defined __CYGWIN__
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# if HAVE_BCRYPT_H
# include <bcrypt.h>
# else
# include <ntdef.h> /* NTSTATUS */
typedef void * BCRYPT_ALG_HANDLE;
# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002
# if HAVE_LIB_BCRYPT
extern NTSTATUS WINAPI BCryptGenRandom (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
# endif
# endif
Update from Gnulib This incorporates: 2020-06-27 getloadavg: don’t depend on fopen-gnu 2020-06-25 c-dtoastr, c-ldtoastr: new modules 2020-06-01 getloadavg: fix double-increment bug 2020-06-01 tempname: use getrandom, not getentropy 2020-05-31 tempname: merge from glibc and coreutils 2020-05-31 getentropy: work around a macOS and Solaris problem 2020-05-31 fnmatch: merge from glibc 2020-05-30 unistd: remove conflicting declaration of getrandom 2020-05-30 don't assume that UNICODE is not defined 2020-05-29 fix compilation error on native Windows 2020-05-28 avoid dynamic loading of Windows API functions when possible 2020-05-28 at-internal: make more robust in multithreaded applications 2020-05-28 getloadavg: make more robust in multithreaded applications 2020-05-27 getloadavg: make more robust in multithreaded applications 2020-05-26 count-one-bits: fix MSVC specific code 2020-05-25 getentropy, getrandom: new modules 2020-05-24 open, openat: really support O_CLOEXEC 2020-05-23 verify: document ‘assume’ better 2020-05-21 regex: configure better with "clang -fsanitize=leak" 2020-05-21 memmem: configure better with "clang -fsanitize=undefined" 2020-05-19 ftoastr: fix ifndef typo * build-aux/config.guess, build-aux/config.sub, doc/misc/texinfo.tex: * lib/count-one-bits.h, lib/ftoastr.c, lib/ftoastr.h: * lib/getloadavg.c, lib/gettimeofday.c, lib/libc-config.h: * lib/open.c, lib/openat-proc.c, lib/tempname.c, lib/tempname.h: * lib/unistd.in.h, lib/verify.h, m4/memmem.m4, m4/regex.m4: * m4/unistd_h.m4: Update from Gnulib. * lib/getrandom.c, lib/sys_random.in.h: * m4/getrandom.m4, m4/sys_random_h.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
2020-06-27 10:00:17 -07:00
# if !HAVE_LIB_BCRYPT
# include <wincrypt.h>
# ifndef CRYPT_VERIFY_CONTEXT
# define CRYPT_VERIFY_CONTEXT 0xF0000000
# endif
# endif
#endif
#include "minmax.h"
#if defined _WIN32 && ! defined __CYGWIN__
/* Don't assume that UNICODE is not defined. */
# undef LoadLibrary
# define LoadLibrary LoadLibraryA
# undef CryptAcquireContext
# define CryptAcquireContext CryptAcquireContextA
# if !HAVE_LIB_BCRYPT
/* Avoid warnings from gcc -Wcast-function-type. */
# define GetProcAddress \
(void *) GetProcAddress
/* BCryptGenRandom with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag works only
starting with Windows 7. */
typedef NTSTATUS (WINAPI * BCryptGenRandomFuncType) (BCRYPT_ALG_HANDLE, UCHAR *, ULONG, ULONG);
static BCryptGenRandomFuncType BCryptGenRandomFunc = NULL;
static BOOL initialized = FALSE;
static void
initialize (void)
{
HMODULE bcrypt = LoadLibrary ("bcrypt.dll");
if (bcrypt != NULL)
{
BCryptGenRandomFunc =
(BCryptGenRandomFuncType) GetProcAddress (bcrypt, "BCryptGenRandom");
}
initialized = TRUE;
}
# else
# define BCryptGenRandomFunc BCryptGenRandom
# endif
#else
/* These devices exist on all platforms except native Windows. */
/* Name of a device through which the kernel returns high quality random
numbers, from an entropy pool. When the pool is empty, the call blocks
until entropy sources have added enough bits of entropy. */
# ifndef NAME_OF_RANDOM_DEVICE
# define NAME_OF_RANDOM_DEVICE "/dev/random"
# endif
/* Name of a device through which the kernel returns random or pseudo-random
numbers. It uses an entropy pool, but, in order to avoid blocking, adds
bits generated by a pseudo-random number generator, as needed. */
# ifndef NAME_OF_NONCE_DEVICE
# define NAME_OF_NONCE_DEVICE "/dev/urandom"
# endif
#endif
/* Set BUFFER (of size LENGTH) to random bytes under the control of FLAGS.
Return the number of bytes written (> 0).
Upon error, return -1 and set errno. */
ssize_t
getrandom (void *buffer, size_t length, unsigned int flags)
#undef getrandom
{
#if defined _WIN32 && ! defined __CYGWIN__
/* BCryptGenRandom, defined in <bcrypt.h>
<https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom>
with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag
works in Windows 7 and newer. */
static int bcrypt_not_working /* = 0 */;
if (!bcrypt_not_working)
{
# if !HAVE_LIB_BCRYPT
if (!initialized)
initialize ();
# endif
if (BCryptGenRandomFunc != NULL
&& BCryptGenRandomFunc (NULL, buffer, length,
BCRYPT_USE_SYSTEM_PREFERRED_RNG)
== 0 /*STATUS_SUCCESS*/)
return length;
bcrypt_not_working = 1;
}
# if !HAVE_LIB_BCRYPT
/* CryptGenRandom, defined in <wincrypt.h>
<https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom>
works in older releases as well, but is now deprecated.
CryptAcquireContext, defined in <wincrypt.h>
<https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptacquirecontexta> */
{
static int crypt_initialized /* = 0 */;
static HCRYPTPROV provider;
if (!crypt_initialized)
{
if (CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFY_CONTEXT))
crypt_initialized = 1;
else
crypt_initialized = -1;
}
if (crypt_initialized >= 0)
{
if (!CryptGenRandom (provider, length, buffer))
{
errno = EIO;
return -1;
}
return length;
}
}
# endif
errno = ENOSYS;
return -1;
#elif HAVE_GETRANDOM
return getrandom (buffer, length, flags);
#else
static int randfd[2] = { -1, -1 };
bool devrandom = (flags & GRND_RANDOM) != 0;
int fd = randfd[devrandom];
if (fd < 0)
{
static char const randdevice[][MAX (sizeof NAME_OF_NONCE_DEVICE,
sizeof NAME_OF_RANDOM_DEVICE)]
= { NAME_OF_NONCE_DEVICE, NAME_OF_RANDOM_DEVICE };
int oflags = (O_RDONLY + O_CLOEXEC
+ (flags & GRND_NONBLOCK ? O_NONBLOCK : 0));
fd = open (randdevice[devrandom], oflags);
if (fd < 0)
return fd;
randfd[devrandom] = fd;
}
return read (fd, buffer, length);
#endif
}