]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
lib/misc: clean up random.c
authorVMware, Inc <>
Mon, 21 Nov 2011 23:56:39 +0000 (15:56 -0800)
committerMarcelo Vanzin <mvanzin@vmware.com>
Mon, 21 Nov 2011 23:56:39 +0000 (15:56 -0800)
Make things cleaner.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/lib/misc/random.c

index 5b7aa92c133168af86ff3cc74f15075cffab0d68..ce8062051ee16495936de5deef9f05de092b8170 100644 (file)
 #   include <errno.h>
 #   include <fcntl.h>
 #   include <unistd.h>
+
+#   define ESX_RANDOM_DEVICE     "/vmfs/devices/char/vmkdriver/urandom"
+#   define GENERIC_RANDOM_DEVICE "/dev/urandom"
 #endif
 
 #include "vmware.h"
 #include "random.h"
 
-#define ESX_RANDOM_DEVICE     "/vmfs/devices/char/vmkdriver/urandom"
-#define GENERIC_RANDOM_DEVICE "/dev/urandom"
-
 
+#if defined(_WIN32)
 /*
  *-----------------------------------------------------------------------------
  *
- * Random_Crypto --
+ * RandomBytesWin32 --
  *
  *      Generate 'size' bytes of cryptographically strong random bits in
- *      'buffer'. Use this function when you need non-predictable random
- *      bits, typically in security applications. Use Random_Quick below
- *      otherwise.
+ *      'buffer'.
  *
  * Results:
- *      TRUE on success
- *      FALSE on failure
- *
- * Side effects:
- *      None
+ *      TRUE   success
+ *      FALSE  failure
  *
  *-----------------------------------------------------------------------------
  */
-
-Bool
-Random_Crypto(unsigned int size,  // IN:
-              void *buffer)       // OUT:
+static Bool
+RandomBytesWin32(unsigned int size,  // IN:
+                 void *buffer)       // OUT:
 {
-#if defined(_WIN32)
    HCRYPTPROV csp;
 
    if (CryptAcquireContext(&csp, NULL, NULL, PROV_RSA_FULL,
                            CRYPT_VERIFYCONTEXT) == FALSE) {
-      Log("%s: CryptAcquireContext failed %d\n", __FUNCTION__,
-          GetLastError());
+      Log("%s: CryptAcquireContext failed %d\n", __FUNCTION__, GetLastError());
+
       return FALSE;
    }
 
@@ -83,67 +78,55 @@ Random_Crypto(unsigned int size,  // IN:
    }
 
    if (CryptReleaseContext(csp, 0) == FALSE) {
-      Log("%s: CryptReleaseContext failed %d\n", __FUNCTION__,
-          GetLastError());
+      Log("%s: CryptReleaseContext failed %d\n", __FUNCTION__, GetLastError());
 
       return FALSE;
    }
-#else
-   int fd;
-
-   /*
-    * We use /dev/urandom and not /dev/random because it is good enough and
-    * because it cannot block. --hpreg
-    *
-    * Bug 352496: On ESX, /dev/urandom is proxied into COS, and hence is
-    * expensive. The VMkernel RNG is available through VMFS and is not
-    * proxied. So we use that instead.
-    */
-
-#if defined(VMX86_SERVER)
-   /*
-    * ESX: attempt to use the wonderful random device.
-    */
-
-   fd = open(ESX_RANDOM_DEVICE, O_RDONLY);
-
-#if defined(VMX86_DEVEL)
-   /*
-    * On developer builds, attempt to fall back to the generic random
-    * device, even if it is much slower. This has a nice side-effect -
-    * some things built for ESX will actually work in a Linux hosted
-    * environment.
-    */
-
-   if (fd == -1) {
-      Log("%s: open of %s failed, attempting to use %s\n", __FUNCTION__,
-          ESX_RANDOM_DEVICE, GENERIC_RANDOM_DEVICE);
 
-      fd = open(GENERIC_RANDOM_DEVICE, O_RDONLY);
-   }
-#endif
+   return TRUE;
+}
 #else
-   fd = open(GENERIC_RANDOM_DEVICE, O_RDONLY);
-#endif
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RandomBytesPosix --
+ *
+ *      Generate 'size' bytes of random bits in 'buffer'.
+ *
+ * Results:
+ *      TRUE   success
+ *      FALSE  failure
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+RandomBytesPosix(const char *name,   // IN:
+                 unsigned int size,  // IN:
+                 void *buffer)       // OUT:
+{
+   int fd = open(name, O_RDONLY);
 
    if (fd == -1) {
-      Log("%s: Failed to open random device: %d\n", __FUNCTION__, errno);
+      Log("%s: Failed to open random device %s: %d\n", __FUNCTION__, name,
+          errno);
 
       return FALSE;
    }
 
    /* Although /dev/urandom does not block, it can return short reads. */
+
    while (size > 0) {
       ssize_t bytesRead = read(fd, buffer, size);
 
-      if (bytesRead == 0 || (bytesRead == -1 && errno != EINTR)) {
-         int error = errno;
+      if ((bytesRead == 0) || ((bytesRead == -1) && (errno != EINTR))) {
+         Log("%s: Short read: %d\n", __FUNCTION__, errno);
 
          close(fd);
-         Log("%s: Short read: %d\n", __FUNCTION__, error);
 
          return FALSE;
       }
+
       if (bytesRead > 0) {
          size -= bytesRead;
          buffer = ((uint8 *) buffer) + bytesRead; 
@@ -155,10 +138,76 @@ Random_Crypto(unsigned int size,  // IN:
 
       return FALSE;
    }
-#endif
 
    return TRUE;
 }
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Random_Crypto --
+ *
+ *      Generate 'size' bytes of cryptographically strong random bits in
+ *      'buffer'. Use this function when you need non-predictable random
+ *      bits, typically in security applications, where the bits are generated
+ *      external to the application.
+ *
+ *      DO NOT USE THIS FUNCTION UNLESS YOU HAVE AN ABSOLUTE, EXPLICIT
+ *      NEED FOR CRYPTOGRAPHICALLY VALID RANDOM NUMBERS. SEE BELOW.
+ *
+ *      THIS ROUTINE MAY BLOCK WAITING FOR SUFFICIENT ENTROPY.
+ *
+ * Results:
+ *      TRUE   success
+ *      FALSE  failure
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+Random_Crypto(unsigned int size,  // IN:
+              void *buffer)       // OUT:
+{
+#if defined(_WIN32)
+   return RandomBytesWin32(size, buffer);
+#else
+   /*
+    * We use /dev/urandom and not /dev/random because it is good enough and
+    * because it cannot block. --hpreg
+    */
+
+   if (vmx86_server) {
+      /*
+       * ESX: attempt to use the wonderful random device.
+       */
+
+      if (RandomBytesPosix(ESX_RANDOM_DEVICE, size, buffer)) {
+         return TRUE;
+      }
+   }
+
+   /*
+    * On ESX developer builds attempt to fall back to the generic random
+    * device, even if it is much slower. This has a nice side-effect -
+    * some things built for ESX will actually work in a Linux hosted
+    * environment.
+    */
+
+   if ((vmx86_server && vmx86_devel) || !vmx86_server) {
+      if (RandomBytesPosix(GENERIC_RANDOM_DEVICE, size, buffer)) {
+         return TRUE;
+      }
+   }
+
+   return FALSE;
+#endif
+}
+
 
 
 /*