mirror of https://github.com/postgres/postgres
This reverts commit 9e083fd468. That was a
few bricks shy of a load:
* Query cancel stopped working
* Buildfarm member pademelon stopped working, because the box doesn't have
/dev/urandom nor /dev/random.
This clearly needs some more discussion, and a quite different patch, so
revert for now.
pull/17/head
parent
7d3235ba42
commit
faae1c918e
@ -0,0 +1,247 @@ |
||||
/*
|
||||
* random.c |
||||
* Acquire randomness from system. For seeding RNG. |
||||
* |
||||
* Copyright (c) 2001 Marko Kreen |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
* contrib/pgcrypto/random.c |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#include "px.h" |
||||
#include "utils/memdebug.h" |
||||
|
||||
/* how many bytes to ask from system random provider */ |
||||
#define RND_BYTES 32 |
||||
|
||||
/*
|
||||
* Try to read from /dev/urandom or /dev/random on these OS'es. |
||||
* |
||||
* The list can be pretty liberal, as the device not existing |
||||
* is expected event. |
||||
*/ |
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ |
||||
|| defined(__NetBSD__) || defined(__DragonFly__) \
|
||||
|| defined(__darwin__) || defined(__SOLARIS__) \
|
||||
|| defined(__hpux) || defined(__HPUX__) \
|
||||
|| defined(__CYGWIN__) || defined(_AIX) |
||||
|
||||
#define TRY_DEV_RANDOM |
||||
|
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
static int |
||||
safe_read(int fd, void *buf, size_t count) |
||||
{ |
||||
int done = 0; |
||||
char *p = buf; |
||||
int res; |
||||
|
||||
while (count) |
||||
{ |
||||
res = read(fd, p, count); |
||||
if (res <= 0) |
||||
{ |
||||
if (errno == EINTR) |
||||
continue; |
||||
return PXE_DEV_READ_ERROR; |
||||
} |
||||
p += res; |
||||
done += res; |
||||
count -= res; |
||||
} |
||||
return done; |
||||
} |
||||
|
||||
static uint8 * |
||||
try_dev_random(uint8 *dst) |
||||
{ |
||||
int fd; |
||||
int res; |
||||
|
||||
fd = open("/dev/urandom", O_RDONLY, 0); |
||||
if (fd == -1) |
||||
{ |
||||
fd = open("/dev/random", O_RDONLY, 0); |
||||
if (fd == -1) |
||||
return dst; |
||||
} |
||||
res = safe_read(fd, dst, RND_BYTES); |
||||
close(fd); |
||||
if (res > 0) |
||||
dst += res; |
||||
return dst; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* Try to find randomness on Windows |
||||
*/ |
||||
#ifdef WIN32 |
||||
|
||||
#define TRY_WIN32_GENRAND |
||||
#define TRY_WIN32_PERFC |
||||
|
||||
#include <windows.h> |
||||
#include <wincrypt.h> |
||||
|
||||
/*
|
||||
* this function is from libtomcrypt |
||||
* |
||||
* try to use Microsoft crypto API |
||||
*/ |
||||
static uint8 * |
||||
try_win32_genrand(uint8 *dst) |
||||
{ |
||||
int res; |
||||
HCRYPTPROV h = 0; |
||||
|
||||
res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, |
||||
(CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)); |
||||
if (!res) |
||||
res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL, |
||||
CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET); |
||||
if (!res) |
||||
return dst; |
||||
|
||||
res = CryptGenRandom(h, RND_BYTES, dst); |
||||
if (res == TRUE) |
||||
dst += RND_BYTES; |
||||
|
||||
CryptReleaseContext(h, 0); |
||||
return dst; |
||||
} |
||||
|
||||
static uint8 * |
||||
try_win32_perfc(uint8 *dst) |
||||
{ |
||||
int res; |
||||
LARGE_INTEGER time; |
||||
|
||||
res = QueryPerformanceCounter(&time); |
||||
if (!res) |
||||
return dst; |
||||
|
||||
memcpy(dst, &time, sizeof(time)); |
||||
return dst + sizeof(time); |
||||
} |
||||
#endif /* WIN32 */ |
||||
|
||||
|
||||
/*
|
||||
* If we are not on Windows, then hopefully we are |
||||
* on a unix-like system. Use the usual suspects |
||||
* for randomness. |
||||
*/ |
||||
#ifndef WIN32 |
||||
|
||||
#define TRY_UNIXSTD |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/time.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
/*
|
||||
* Everything here is predictible, only needs some patience. |
||||
* |
||||
* But there is a chance that the system-specific functions |
||||
* did not work. So keep faith and try to slow the attacker down. |
||||
*/ |
||||
static uint8 * |
||||
try_unix_std(uint8 *dst) |
||||
{ |
||||
pid_t pid; |
||||
int x; |
||||
PX_MD *md; |
||||
struct timeval tv; |
||||
int res; |
||||
|
||||
/* process id */ |
||||
pid = getpid(); |
||||
memcpy(dst, (uint8 *) &pid, sizeof(pid)); |
||||
dst += sizeof(pid); |
||||
|
||||
/* time */ |
||||
gettimeofday(&tv, NULL); |
||||
memcpy(dst, (uint8 *) &tv, sizeof(tv)); |
||||
dst += sizeof(tv); |
||||
|
||||
/* pointless, but should not hurt */ |
||||
x = random(); |
||||
memcpy(dst, (uint8 *) &x, sizeof(x)); |
||||
dst += sizeof(x); |
||||
|
||||
/* hash of uninitialized stack and heap allocations */ |
||||
res = px_find_digest("sha1", &md); |
||||
if (res >= 0) |
||||
{ |
||||
uint8 *ptr; |
||||
uint8 stack[8192]; |
||||
int alloc = 32 * 1024; |
||||
|
||||
VALGRIND_MAKE_MEM_DEFINED(stack, sizeof(stack)); |
||||
px_md_update(md, stack, sizeof(stack)); |
||||
ptr = px_alloc(alloc); |
||||
VALGRIND_MAKE_MEM_DEFINED(ptr, alloc); |
||||
px_md_update(md, ptr, alloc); |
||||
px_free(ptr); |
||||
|
||||
px_md_finish(md, dst); |
||||
px_md_free(md); |
||||
|
||||
dst += 20; |
||||
} |
||||
|
||||
return dst; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* try to extract some randomness for initial seeding |
||||
* |
||||
* dst should have room for 1024 bytes. |
||||
*/ |
||||
unsigned |
||||
px_acquire_system_randomness(uint8 *dst) |
||||
{ |
||||
uint8 *p = dst; |
||||
|
||||
#ifdef TRY_DEV_RANDOM |
||||
p = try_dev_random(p); |
||||
#endif |
||||
#ifdef TRY_WIN32_GENRAND |
||||
p = try_win32_genrand(p); |
||||
#endif |
||||
#ifdef TRY_WIN32_PERFC |
||||
p = try_win32_perfc(p); |
||||
#endif |
||||
#ifdef TRY_UNIXSTD |
||||
p = try_unix_std(p); |
||||
#endif |
||||
return p - dst; |
||||
} |
||||
@ -1,148 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_strong_random.c |
||||
* pg_strong_random() function to return a strong random number |
||||
* |
||||
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/port/pg_strong_random.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef FRONTEND |
||||
#include "postgres.h" |
||||
#else |
||||
#include "postgres_fe.h" |
||||
#endif |
||||
|
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
#ifdef USE_SSL |
||||
#include <openssl/rand.h> |
||||
#endif |
||||
#ifdef WIN32 |
||||
#include <Wincrypt.h> |
||||
#endif |
||||
|
||||
static bool random_from_file(char *filename, void *buf, size_t len); |
||||
|
||||
#ifdef WIN32 |
||||
/*
|
||||
* Cache a global crypto provider that only gets freed when the process |
||||
* exits, in case we need random numbers more than once. |
||||
*/ |
||||
static HCRYPTPROV hProvider = 0; |
||||
#endif |
||||
|
||||
/*
|
||||
* Read (random) bytes from a file. |
||||
*/ |
||||
static bool |
||||
random_from_file(char *filename, void *buf, size_t len) |
||||
{ |
||||
int f; |
||||
char *p = buf; |
||||
ssize_t res; |
||||
|
||||
f = open(filename, O_RDONLY, 0); |
||||
if (f == -1) |
||||
return false; |
||||
|
||||
while (len) |
||||
{ |
||||
res = read(f, p, len); |
||||
if (res <= 0) |
||||
{ |
||||
if (errno == EINTR) |
||||
continue; /* interrupted by signal, just retry */ |
||||
|
||||
close(f); |
||||
return false; |
||||
} |
||||
|
||||
p += res; |
||||
len -= res; |
||||
} |
||||
|
||||
close(f); |
||||
return true; |
||||
} |
||||
|
||||
/*
|
||||
* pg_strong_random |
||||
* |
||||
* Generate requested number of random bytes. The bytes are |
||||
* cryptographically strong random, suitable for use e.g. in key |
||||
* generation. |
||||
* |
||||
* The bytes can be acquired from a number of sources, depending |
||||
* on what's available. We try the following, in this order: |
||||
* |
||||
* 1. OpenSSL's RAND_bytes() |
||||
* 2. Windows' CryptGenRandom() function |
||||
* 3. /dev/urandom |
||||
* 4. /dev/random |
||||
* |
||||
* Returns true on success, and false if none of the sources |
||||
* were available. NB: It is important to check the return value! |
||||
* Proceeding with key generation when no random data was available |
||||
* would lead to predictable keys and security issues. |
||||
*/ |
||||
bool |
||||
pg_strong_random(void *buf, size_t len) |
||||
{ |
||||
#ifdef USE_SSL |
||||
|
||||
/*
|
||||
* When built with OpenSSL, first try the random generation function from |
||||
* there. |
||||
*/ |
||||
if (RAND_bytes(buf, len) == 1) |
||||
return true; |
||||
#endif |
||||
|
||||
#ifdef WIN32 |
||||
|
||||
/*
|
||||
* Windows has CryptoAPI for strong cryptographic numbers. |
||||
*/ |
||||
if (hProvider == 0) |
||||
{ |
||||
if (!CryptAcquireContext(&hProvider, |
||||
NULL, |
||||
MS_DEF_PROV, |
||||
PROV_RSA_FULL, |
||||
CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) |
||||
{ |
||||
/*
|
||||
* On failure, set back to 0 in case the value was for some reason |
||||
* modified. |
||||
*/ |
||||
hProvider = 0; |
||||
} |
||||
} |
||||
|
||||
/* Re-check in case we just retrieved the provider */ |
||||
if (hProvider != 0) |
||||
{ |
||||
if (CryptGenRandom(hProvider, len, buf)) |
||||
return true; |
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* If there is no OpenSSL and no CryptoAPI (or they didn't work), then |
||||
* fall back on reading /dev/urandom or even /dev/random. |
||||
*/ |
||||
if (random_from_file("/dev/urandom", buf, len)) |
||||
return true; |
||||
if (random_from_file("/dev/random", buf, len)) |
||||
return true; |
||||
|
||||
/* None of the sources were available. */ |
||||
return false; |
||||
} |
||||
Loading…
Reference in new issue