]> Savannah Git Hosting - gnulib.git/commitdiff
getrandom: Add support for native Windows.
authorBruno Haible <bruno@clisp.org>
Sun, 31 May 2020 16:23:04 +0000 (18:23 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 31 May 2020 16:23:04 +0000 (18:23 +0200)
* lib/getrandom.c: Include <errno.h>, <windows.h>, <bcrypt.h>,
<wincrypt.h>.
(CRYPT_VERIFY_CONTEXT): New macro.
(LoadLibrary, CryptAcquireContext): Redirect to the variant with suffix
'A'.
(GetProcAddress): New macro.
(BCryptGenRandomFuncType): New type.
(BCryptGenRandomFunc, initialized): New variables.
(initialize): New function.
(getrandom): On native Windows, use <bcrypt.h> API when available, and
<wincrypt.h> API as fallback.
* m4/getrandom.m4 (gl_FUNC_GETRANDOM): Set LIB_GETRANDOM.
* modules/getrandom (Link): New section.
* modules/getentropy (Link): Likewise.
* modules/getrandom-tests (Makefile.am): Link test-getrandom against
$(LIB_GETRANDOM).
* modules/getentropy-tests (Makefile.am): Link test-getentropy against
$(LIB_GETRANDOM).
* modules/sys_random-c++-tests (Makefile.am): Link test-sys_random-c++
against $(LIB_GETRANDOM).
* doc/glibc-functions/getrandom.texi: Mention the native Windows
support.

ChangeLog
doc/glibc-functions/getrandom.texi
lib/getrandom.c
m4/getrandom.m4
modules/getentropy
modules/getentropy-tests
modules/getrandom
modules/getrandom-tests
modules/sys_random-c++-tests

index f7c9b4dfb0c7d49501b7588afe2200e3dc3d86a6..072d2d49af924a854a4dc85e4b26122457ed83cd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2020-05-31  Bruno Haible  <bruno@clisp.org>
+
+       getrandom: Add support for native Windows.
+       * lib/getrandom.c: Include <errno.h>, <windows.h>, <bcrypt.h>,
+       <wincrypt.h>.
+       (CRYPT_VERIFY_CONTEXT): New macro.
+       (LoadLibrary, CryptAcquireContext): Redirect to the variant with suffix
+       'A'.
+       (GetProcAddress): New macro.
+       (BCryptGenRandomFuncType): New type.
+       (BCryptGenRandomFunc, initialized): New variables.
+       (initialize): New function.
+       (getrandom): On native Windows, use <bcrypt.h> API when available, and
+       <wincrypt.h> API as fallback.
+       * m4/getrandom.m4 (gl_FUNC_GETRANDOM): Set LIB_GETRANDOM.
+       * modules/getrandom (Link): New section.
+       * modules/getentropy (Link): Likewise.
+       * modules/getrandom-tests (Makefile.am): Link test-getrandom against
+       $(LIB_GETRANDOM).
+       * modules/getentropy-tests (Makefile.am): Link test-getentropy against
+       $(LIB_GETRANDOM).
+       * modules/sys_random-c++-tests (Makefile.am): Link test-sys_random-c++
+       against $(LIB_GETRANDOM).
+       * doc/glibc-functions/getrandom.texi: Mention the native Windows
+       support.
+
 2020-05-31  Bruno Haible  <bruno@clisp.org>
 
        getrandom: Simplify the determination of the random number devices.
index 2d935565372a0360ec5b60e6abc01ceeb9847c8d..99712c77b711cadcf6acae76713e12ce61a9c0f4 100644 (file)
@@ -22,7 +22,7 @@ Portability problems fixed by Gnulib:
 @item
 This function is missing on some platforms:
 glibc 2.24, Mac OS X 10.5, FreeBSD 11.0, NetBSD 5.0, OpenBSD 3.8,
-Solaris 11.0, Android 9.0.
+Solaris 11.0, mingw, MSVC 14, Android 9.0.
 @item
 This function has a different return type on some platforms:
 Solaris 11.4.
@@ -32,5 +32,5 @@ Portability problems not fixed by Gnulib:
 @itemize
 @item
 This function is missing on some platforms:
-Minix 3.1.8, IRIX 6.5, mingw, MSVC 14.
+Minix 3.1.8, IRIX 6.5.
 @end itemize
index 0cc3dc3d8507f582e9c42f30630361e0c65a855e..ad49cae896a590ddf1c882b034852da326395e5b 100644 (file)
 
 #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>
+# include <bcrypt.h>
+# 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.  */
-#if !(defined _WIN32 && ! defined __CYGWIN__)
 
 /* 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
@@ -52,7 +103,56 @@ ssize_t
 getrandom (void *buffer, size_t length, unsigned int flags)
 #undef getrandom
 {
-#if HAVE_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 };
index 779c6ad8329f8cf10d1ab384286c408c954e81ae..37fb10023a0be821808849c038aefab77a535396 100644 (file)
@@ -1,4 +1,4 @@
-# getrandom.m4 serial 4
+# getrandom.m4 serial 5
 dnl Copyright 2020 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -33,4 +33,32 @@ AC_DEFUN([gl_FUNC_GETRANDOM],
       REPLACE_GETRANDOM=1
     fi
   fi
+
+  case "$host_os" in
+    mingw*)
+      AC_CACHE_CHECK([whether the bcrypt library is guaranteed to be present],
+        [gl_cv_lib_assume_bcrypt],
+        [AC_COMPILE_IFELSE(
+           [AC_LANG_PROGRAM(
+              [[#include <windows.h>]],
+              [[#if !(_WIN32_WINNT >= _WIN32_WINNT_WIN7)
+                  cannot assume it
+                #endif
+              ]])
+           ],
+           [gl_cv_lib_assume_bcrypt=yes],
+           [gl_cv_lib_assume_bcrypt=no])
+        ])
+      if test $gl_cv_lib_assume_bcrypt = yes; then
+        AC_DEFINE([HAVE_LIB_BCRYPT], [1],
+          [Define to 1 if the bcrypt library is guaranteed to be present.])
+        LIB_GETRANDOM='-lbcrypt'
+      else
+        LIB_GETRANDOM='-ladvapi32'
+      fi
+      ;;
+    *)
+      LIB_GETRANDOM= ;;
+  esac
+  AC_SUBST([LIB_GETRANDOM])
 ])
index 9696c1e1d5ee2bc309f42d329675bf05b11eef48..680aa4716b5a525f9ed2e793918f7ef1f6a21dba 100644 (file)
@@ -22,6 +22,9 @@ Makefile.am:
 Include:
 <unistd.h>
 
+Link:
+$(LIB_GETRANDOM)
+
 License:
 LGPL
 
index b5c4b1144ec89b75cac1e3d3464444eb8102a3a6..7ad786109cec6dc006026550854feaa9617ef8af 100644 (file)
@@ -10,3 +10,4 @@ configure.ac:
 Makefile.am:
 TESTS += test-getentropy
 check_PROGRAMS += test-getentropy
+test_getentropy_LDADD = $(LDADD) $(LIB_GETRANDOM)
index 8aa4be2b781005b23b4535e1a08b595c425ae331..76437eb5adb0e9c36f78dea20555f969ae46f43d 100644 (file)
@@ -23,6 +23,9 @@ Makefile.am:
 Include:
 <sys/random.h>
 
+Link:
+$(LIB_GETRANDOM)
+
 License:
 LGPL
 
index 8982173613471ce3ba3c7dcdf08a7f3ff064be40..b7f64dd2052ab57182aabacca7b5d00ea038f2ef 100644 (file)
@@ -10,3 +10,4 @@ configure.ac:
 Makefile.am:
 TESTS += test-getrandom
 check_PROGRAMS += test-getrandom
+test_getrandom_LDADD = $(LDADD) @LIB_GETRANDOM@
index e07d81f0e7b5bb25db0719263d93a059c2595122..5b3c505fd4836da0d61fa0d77f6eb36eb53970a2 100644 (file)
@@ -15,4 +15,5 @@ if ANSICXX
 TESTS += test-sys_random-c++
 check_PROGRAMS += test-sys_random-c++
 test_sys_random_c___SOURCES = test-sys_random-c++.cc
+test_sys_random_c___LDADD = $(LDADD) $(LIB_GETRANDOM)
 endif