From: VMware, Inc <> Date: Mon, 21 Nov 2011 23:56:39 +0000 (-0800) Subject: lib/misc: clean up random.c X-Git-Tag: 2011.11.20-535097~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2ebd3fe5ab7e2d27d5d222af13d8f0a9e5ebb861;p=thirdparty%2Fopen-vm-tools.git lib/misc: clean up random.c Make things cleaner. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/lib/misc/random.c b/open-vm-tools/lib/misc/random.c index 5b7aa92c1..ce8062051 100644 --- a/open-vm-tools/lib/misc/random.c +++ b/open-vm-tools/lib/misc/random.c @@ -32,46 +32,41 @@ # include # include # include + +# 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 +} + /*