mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08:00
Revert "Replace PostmasterRandom() with a stronger way of generating randomness."
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.
This commit is contained in:
parent
7d3235ba42
commit
faae1c918e
@ -1,7 +1,7 @@
|
|||||||
# contrib/pgcrypto/Makefile
|
# contrib/pgcrypto/Makefile
|
||||||
|
|
||||||
INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
|
INT_SRCS = md5.c sha1.c sha2.c internal.c internal-sha2.c blf.c rijndael.c \
|
||||||
fortuna.c pgp-mpi-internal.c imath.c
|
fortuna.c random.c pgp-mpi-internal.c imath.c
|
||||||
INT_TESTS = sha2
|
INT_TESTS = sha2
|
||||||
|
|
||||||
OSSL_SRCS = openssl.c pgp-mpi-openssl.c
|
OSSL_SRCS = openssl.c pgp-mpi-openssl.c
|
||||||
|
@ -626,6 +626,8 @@ static time_t check_time = 0;
|
|||||||
static void
|
static void
|
||||||
system_reseed(void)
|
system_reseed(void)
|
||||||
{
|
{
|
||||||
|
uint8 buf[1024];
|
||||||
|
int n;
|
||||||
time_t t;
|
time_t t;
|
||||||
int skip = 1;
|
int skip = 1;
|
||||||
|
|
||||||
@ -640,34 +642,24 @@ system_reseed(void)
|
|||||||
else if (check_time == 0 ||
|
else if (check_time == 0 ||
|
||||||
(t - check_time) > SYSTEM_RESEED_CHECK_TIME)
|
(t - check_time) > SYSTEM_RESEED_CHECK_TIME)
|
||||||
{
|
{
|
||||||
uint8 buf;
|
|
||||||
|
|
||||||
check_time = t;
|
check_time = t;
|
||||||
|
|
||||||
/* roll dice */
|
/* roll dice */
|
||||||
px_get_random_bytes(&buf, 1);
|
px_get_random_bytes(buf, 1);
|
||||||
skip = (buf >= SYSTEM_RESEED_CHANCE);
|
skip = buf[0] >= SYSTEM_RESEED_CHANCE;
|
||||||
|
|
||||||
/* clear 1 byte */
|
|
||||||
px_memset(&buf, 0, sizeof(buf));
|
|
||||||
}
|
}
|
||||||
if (!skip)
|
/* clear 1 byte */
|
||||||
{
|
px_memset(buf, 0, sizeof(buf));
|
||||||
/*
|
|
||||||
* fortuna_add_entropy passes the input to SHA-256, so there's no
|
|
||||||
* point in giving it more than 256 bits of input to begin with.
|
|
||||||
*/
|
|
||||||
uint8 buf[32];
|
|
||||||
|
|
||||||
if (!pg_strong_random(buf, sizeof(buf)))
|
if (skip)
|
||||||
ereport(ERROR,
|
return;
|
||||||
(errcode(ERRCODE_INTERNAL_ERROR),
|
|
||||||
errmsg("could not acquire random data")));
|
|
||||||
fortuna_add_entropy(buf, sizeof(buf));
|
|
||||||
|
|
||||||
seed_time = t;
|
n = px_acquire_system_randomness(buf);
|
||||||
px_memset(buf, 0, sizeof(buf));
|
if (n > 0)
|
||||||
}
|
fortuna_add_entropy(buf, n);
|
||||||
|
|
||||||
|
seed_time = t;
|
||||||
|
px_memset(buf, 0, sizeof(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
247
contrib/pgcrypto/random.c
Normal file
247
contrib/pgcrypto/random.c
Normal file
@ -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;
|
||||||
|
}
|
@ -45,12 +45,6 @@ static void auth_failed(Port *port, int status, char *logdetail);
|
|||||||
static char *recv_password_packet(Port *port);
|
static char *recv_password_packet(Port *port);
|
||||||
static int recv_and_check_password_packet(Port *port, char **logdetail);
|
static int recv_and_check_password_packet(Port *port, char **logdetail);
|
||||||
|
|
||||||
/*----------------------------------------------------------------
|
|
||||||
* MD5 authentication
|
|
||||||
*----------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
static int CheckMD5Auth(Port *port, char **logdetail);
|
|
||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
* Ident authentication
|
* Ident authentication
|
||||||
@ -541,7 +535,9 @@ ClientAuthentication(Port *port)
|
|||||||
ereport(FATAL,
|
ereport(FATAL,
|
||||||
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
|
(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
|
||||||
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
|
errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled")));
|
||||||
status = CheckMD5Auth(port, &logdetail);
|
/* include the salt to use for computing the response */
|
||||||
|
sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4);
|
||||||
|
status = recv_and_check_password_packet(port, &logdetail);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case uaPassword:
|
case uaPassword:
|
||||||
@ -696,25 +692,10 @@ recv_password_packet(Port *port)
|
|||||||
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
||||||
* MD5 and password authentication
|
* MD5 authentication
|
||||||
*----------------------------------------------------------------
|
*----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
|
||||||
CheckMD5Auth(Port *port, char **logdetail)
|
|
||||||
{
|
|
||||||
/* include the salt to use for computing the response */
|
|
||||||
if (!pg_strong_random(port->md5Salt, sizeof(port->md5Salt)))
|
|
||||||
{
|
|
||||||
*logdetail = psprintf(_("Could not generate random salt"));
|
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAuthRequest(port, AUTH_REQ_MD5, port->md5Salt, 4);
|
|
||||||
return recv_and_check_password_packet(port, logdetail);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when we have sent an authorization request for a password.
|
* Called when we have sent an authorization request for a password.
|
||||||
* Get the response and check it.
|
* Get the response and check it.
|
||||||
|
@ -358,6 +358,14 @@ static volatile bool avlauncher_needs_signal = false;
|
|||||||
static volatile bool StartWorkerNeeded = true;
|
static volatile bool StartWorkerNeeded = true;
|
||||||
static volatile bool HaveCrashedWorker = false;
|
static volatile bool HaveCrashedWorker = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State for assigning random salts and cancel keys.
|
||||||
|
* Also, the global MyCancelKey passes the cancel key assigned to a given
|
||||||
|
* backend from the postmaster to that backend (via fork).
|
||||||
|
*/
|
||||||
|
static unsigned int random_seed = 0;
|
||||||
|
static struct timeval random_start_time;
|
||||||
|
|
||||||
#ifdef USE_BONJOUR
|
#ifdef USE_BONJOUR
|
||||||
static DNSServiceRef bonjour_sdref = NULL;
|
static DNSServiceRef bonjour_sdref = NULL;
|
||||||
#endif
|
#endif
|
||||||
@ -395,6 +403,8 @@ static void processCancelRequest(Port *port, void *pkt);
|
|||||||
static int initMasks(fd_set *rmask);
|
static int initMasks(fd_set *rmask);
|
||||||
static void report_fork_failure_to_client(Port *port, int errnum);
|
static void report_fork_failure_to_client(Port *port, int errnum);
|
||||||
static CAC_state canAcceptConnections(void);
|
static CAC_state canAcceptConnections(void);
|
||||||
|
static long PostmasterRandom(void);
|
||||||
|
static void RandomSalt(char *salt, int len);
|
||||||
static void signal_child(pid_t pid, int signal);
|
static void signal_child(pid_t pid, int signal);
|
||||||
static bool SignalSomeChildren(int signal, int targets);
|
static bool SignalSomeChildren(int signal, int targets);
|
||||||
static void TerminateChildren(int signal);
|
static void TerminateChildren(int signal);
|
||||||
@ -569,11 +579,9 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
* Initialize random(3) so we don't get the same values in every run.
|
* Initialize random(3) so we don't get the same values in every run.
|
||||||
*
|
*
|
||||||
* Note: the seed is pretty predictable from externally-visible facts such
|
* Note: the seed is pretty predictable from externally-visible facts such
|
||||||
* as postmaster start time, so don't use random() for security-critical
|
* as postmaster start time, so avoid using random() for security-critical
|
||||||
* random values (use pg_strong_random() instead). Backends select a
|
* random values during postmaster startup. At the time of first
|
||||||
* somewhat more random seed after forking, in BackendRun(), based on the
|
* connection, PostmasterRandom will select a hopefully-more-random seed.
|
||||||
* PID and session start timestamp, but that is still not suitable for
|
|
||||||
* security-critical values.
|
|
||||||
*/
|
*/
|
||||||
srandom((unsigned int) (MyProcPid ^ MyStartTime));
|
srandom((unsigned int) (MyProcPid ^ MyStartTime));
|
||||||
|
|
||||||
@ -1284,6 +1292,8 @@ PostmasterMain(int argc, char *argv[])
|
|||||||
* Remember postmaster startup time
|
* Remember postmaster startup time
|
||||||
*/
|
*/
|
||||||
PgStartTime = GetCurrentTimestamp();
|
PgStartTime = GetCurrentTimestamp();
|
||||||
|
/* PostmasterRandom wants its own copy */
|
||||||
|
gettimeofday(&random_start_time, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're ready to rock and roll...
|
* We're ready to rock and roll...
|
||||||
@ -2333,6 +2343,15 @@ ConnCreate(int serverFd)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Precompute password salt values to use for this connection. It's
|
||||||
|
* slightly annoying to do this long in advance of knowing whether we'll
|
||||||
|
* need 'em or not, but we must do the random() calls before we fork, not
|
||||||
|
* after. Else the postmaster's random sequence won't get advanced, and
|
||||||
|
* all backends would end up using the same salt...
|
||||||
|
*/
|
||||||
|
RandomSalt(port->md5Salt, sizeof(port->md5Salt));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate GSSAPI specific state struct
|
* Allocate GSSAPI specific state struct
|
||||||
*/
|
*/
|
||||||
@ -3885,12 +3904,7 @@ BackendStartup(Port *port)
|
|||||||
* backend will have its own copy in the forked-off process' value of
|
* backend will have its own copy in the forked-off process' value of
|
||||||
* MyCancelKey, so that it can transmit the key to the frontend.
|
* MyCancelKey, so that it can transmit the key to the frontend.
|
||||||
*/
|
*/
|
||||||
if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
|
MyCancelKey = PostmasterRandom();
|
||||||
{
|
|
||||||
ereport(LOG,
|
|
||||||
(errmsg("could not generate random query cancel key")));
|
|
||||||
return STATUS_ERROR;
|
|
||||||
}
|
|
||||||
bn->cancel_key = MyCancelKey;
|
bn->cancel_key = MyCancelKey;
|
||||||
|
|
||||||
/* Pass down canAcceptConnections state */
|
/* Pass down canAcceptConnections state */
|
||||||
@ -4198,6 +4212,13 @@ BackendRun(Port *port)
|
|||||||
int usecs;
|
int usecs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't want backend to be able to see the postmaster random number
|
||||||
|
* generator state. We have to clobber the static random_seed *and* start
|
||||||
|
* a new random sequence in the random() library function.
|
||||||
|
*/
|
||||||
|
random_seed = 0;
|
||||||
|
random_start_time.tv_usec = 0;
|
||||||
/* slightly hacky way to convert timestamptz into integers */
|
/* slightly hacky way to convert timestamptz into integers */
|
||||||
TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
|
TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
|
||||||
srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
|
srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs));
|
||||||
@ -5045,6 +5066,66 @@ StartupPacketTimeoutHandler(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RandomSalt
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
RandomSalt(char *salt, int len)
|
||||||
|
{
|
||||||
|
long rand;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We use % 255, sacrificing one possible byte value, so as to ensure that
|
||||||
|
* all bits of the random() value participate in the result. While at it,
|
||||||
|
* add one to avoid generating any null bytes.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
rand = PostmasterRandom();
|
||||||
|
salt[i] = (rand % 255) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PostmasterRandom
|
||||||
|
*
|
||||||
|
* Caution: use this only for values needed during connection-request
|
||||||
|
* processing. Otherwise, the intended property of having an unpredictable
|
||||||
|
* delay between random_start_time and random_stop_time will be broken.
|
||||||
|
*/
|
||||||
|
static long
|
||||||
|
PostmasterRandom(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Select a random seed at the time of first receiving a request.
|
||||||
|
*/
|
||||||
|
if (random_seed == 0)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
struct timeval random_stop_time;
|
||||||
|
|
||||||
|
gettimeofday(&random_stop_time, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are not sure how much precision is in tv_usec, so we swap
|
||||||
|
* the high and low 16 bits of 'random_stop_time' and XOR them
|
||||||
|
* with 'random_start_time'. On the off chance that the result is
|
||||||
|
* 0, we loop until it isn't.
|
||||||
|
*/
|
||||||
|
random_seed = random_start_time.tv_usec ^
|
||||||
|
((random_stop_time.tv_usec << 16) |
|
||||||
|
((random_stop_time.tv_usec >> 16) & 0xffff));
|
||||||
|
}
|
||||||
|
while (random_seed == 0);
|
||||||
|
|
||||||
|
srandom(random_seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return random();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Count up number of child processes of specified types (dead_end chidren
|
* Count up number of child processes of specified types (dead_end chidren
|
||||||
* are always excluded).
|
* are always excluded).
|
||||||
@ -5222,37 +5303,31 @@ StartAutovacuumWorker(void)
|
|||||||
* we'd better have something random in the field to prevent
|
* we'd better have something random in the field to prevent
|
||||||
* unfriendly people from sending cancels to them.
|
* unfriendly people from sending cancels to them.
|
||||||
*/
|
*/
|
||||||
if (pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
|
MyCancelKey = PostmasterRandom();
|
||||||
|
bn->cancel_key = MyCancelKey;
|
||||||
|
|
||||||
|
/* Autovac workers are not dead_end and need a child slot */
|
||||||
|
bn->dead_end = false;
|
||||||
|
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
||||||
|
bn->bgworker_notify = false;
|
||||||
|
|
||||||
|
bn->pid = StartAutoVacWorker();
|
||||||
|
if (bn->pid > 0)
|
||||||
{
|
{
|
||||||
bn->cancel_key = MyCancelKey;
|
bn->bkend_type = BACKEND_TYPE_AUTOVAC;
|
||||||
|
dlist_push_head(&BackendList, &bn->elem);
|
||||||
/* Autovac workers are not dead_end and need a child slot */
|
|
||||||
bn->dead_end = false;
|
|
||||||
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
|
||||||
bn->bgworker_notify = false;
|
|
||||||
|
|
||||||
bn->pid = StartAutoVacWorker();
|
|
||||||
if (bn->pid > 0)
|
|
||||||
{
|
|
||||||
bn->bkend_type = BACKEND_TYPE_AUTOVAC;
|
|
||||||
dlist_push_head(&BackendList, &bn->elem);
|
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
ShmemBackendArrayAdd(bn);
|
ShmemBackendArrayAdd(bn);
|
||||||
#endif
|
#endif
|
||||||
/* all OK */
|
/* all OK */
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fork failed, fall through to report -- actual error message
|
|
||||||
* was logged by StartAutoVacWorker
|
|
||||||
*/
|
|
||||||
(void) ReleasePostmasterChildSlot(bn->child_slot);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
ereport(LOG,
|
|
||||||
(errmsg("could not generate random query cancel key")));
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fork failed, fall through to report -- actual error message was
|
||||||
|
* logged by StartAutoVacWorker
|
||||||
|
*/
|
||||||
|
(void) ReleasePostmasterChildSlot(bn->child_slot);
|
||||||
free(bn);
|
free(bn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -5540,11 +5615,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw)
|
|||||||
* have something random in the field to prevent unfriendly people from
|
* have something random in the field to prevent unfriendly people from
|
||||||
* sending cancels to them.
|
* sending cancels to them.
|
||||||
*/
|
*/
|
||||||
if (!pg_strong_random(&MyCancelKey, sizeof(MyCancelKey)))
|
MyCancelKey = PostmasterRandom();
|
||||||
{
|
|
||||||
rw->rw_crashed_at = GetCurrentTimestamp();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bn->cancel_key = MyCancelKey;
|
bn->cancel_key = MyCancelKey;
|
||||||
|
|
||||||
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();
|
||||||
|
@ -454,9 +454,6 @@ extern int pg_codepage_to_encoding(UINT cp);
|
|||||||
extern char *inet_net_ntop(int af, const void *src, int bits,
|
extern char *inet_net_ntop(int af, const void *src, int bits,
|
||||||
char *dst, size_t size);
|
char *dst, size_t size);
|
||||||
|
|
||||||
/* port/pg_strong_random.c */
|
|
||||||
extern bool pg_strong_random(void *buf, size_t len);
|
|
||||||
|
|
||||||
/* port/pgcheckdir.c */
|
/* port/pgcheckdir.c */
|
||||||
extern int pg_check_dir(const char *dir);
|
extern int pg_check_dir(const char *dir);
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ LIBS += $(PTHREAD_LIBS)
|
|||||||
|
|
||||||
OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
|
OBJS = $(LIBOBJS) $(PG_CRC32C_OBJS) chklocale.o erand48.o inet_net_ntop.o \
|
||||||
noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
|
noblock.o path.o pgcheckdir.o pgmkdirp.o pgsleep.o \
|
||||||
pg_strong_random.o pgstrcasecmp.o pqsignal.o \
|
pgstrcasecmp.o pqsignal.o \
|
||||||
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
|
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
|
||||||
|
|
||||||
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
|
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
|
||||||
|
@ -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;
|
|
||||||
}
|
|
@ -92,7 +92,7 @@ sub mkvcbuild
|
|||||||
srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
|
srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
|
||||||
erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
|
erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
|
||||||
pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
|
pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
|
||||||
mkdtemp.c pg_strong_random.c qsort.c qsort_arg.c quotes.c system.c
|
mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
|
||||||
sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
|
sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
|
||||||
win32env.c win32error.c win32security.c win32setlocale.c);
|
win32env.c win32error.c win32security.c win32setlocale.c);
|
||||||
|
|
||||||
@ -425,8 +425,8 @@ sub mkvcbuild
|
|||||||
'sha1.c', 'sha2.c',
|
'sha1.c', 'sha2.c',
|
||||||
'internal.c', 'internal-sha2.c',
|
'internal.c', 'internal-sha2.c',
|
||||||
'blf.c', 'rijndael.c',
|
'blf.c', 'rijndael.c',
|
||||||
'fortuna.c', 'pgp-mpi-internal.c',
|
'fortuna.c', 'random.c',
|
||||||
'imath.c');
|
'pgp-mpi-internal.c', 'imath.c');
|
||||||
}
|
}
|
||||||
$pgcrypto->AddReference($postgres);
|
$pgcrypto->AddReference($postgres);
|
||||||
$pgcrypto->AddLibrary('ws2_32.lib');
|
$pgcrypto->AddLibrary('ws2_32.lib');
|
||||||
|
Loading…
Reference in New Issue
Block a user