159 lines
3.3 KiB
C
159 lines
3.3 KiB
C
|
/*-------------------------------------------------------------------------
|
||
|
*
|
||
|
* backend_random.c
|
||
|
* Backend random number generation routine.
|
||
|
*
|
||
|
* pg_backend_random() function fills a buffer with random bytes. Normally,
|
||
|
* it is just a thin wrapper around pg_strong_random(), but when compiled
|
||
|
* with --disable-strong-random, we provide a built-in implementation.
|
||
|
*
|
||
|
* This function is used for generating nonces in authentication, and for
|
||
|
* random salt generation in pgcrypto. The built-in implementation is not
|
||
|
* cryptographically strong, but if the user asked for it, we'll go ahead
|
||
|
* and use it anyway.
|
||
|
*
|
||
|
* The built-in implementation uses the standard erand48 algorithm, with
|
||
|
* a seed shared between all backends.
|
||
|
*
|
||
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||
|
*
|
||
|
*
|
||
|
* IDENTIFICATION
|
||
|
* src/backend/utils/misc/backend_random.c
|
||
|
*
|
||
|
*-------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
#include "postgres.h"
|
||
|
|
||
|
#include <sys/time.h>
|
||
|
|
||
|
#include "miscadmin.h"
|
||
|
#include "storage/lwlock.h"
|
||
|
#include "storage/shmem.h"
|
||
|
#include "utils/backend_random.h"
|
||
|
#include "utils/timestamp.h"
|
||
|
|
||
|
#ifdef HAVE_STRONG_RANDOM
|
||
|
|
||
|
Size
|
||
|
BackendRandomShmemSize(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
BackendRandomShmemInit(void)
|
||
|
{
|
||
|
/* do nothing */
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pg_backend_random(char *dst, int len)
|
||
|
{
|
||
|
/* should not be called in postmaster */
|
||
|
Assert (IsUnderPostmaster || !IsPostmasterEnvironment);
|
||
|
|
||
|
return pg_strong_random(dst, len);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
/*
|
||
|
* Seed for the PRNG, stored in shared memory.
|
||
|
*
|
||
|
* Protected by BackendRandomLock.
|
||
|
*/
|
||
|
typedef struct
|
||
|
{
|
||
|
bool initialized;
|
||
|
unsigned short seed[3];
|
||
|
} BackendRandomShmemStruct;
|
||
|
|
||
|
static BackendRandomShmemStruct *BackendRandomShmem;
|
||
|
|
||
|
Size
|
||
|
BackendRandomShmemSize(void)
|
||
|
{
|
||
|
return sizeof(BackendRandomShmemStruct);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
BackendRandomShmemInit(void)
|
||
|
{
|
||
|
bool found;
|
||
|
|
||
|
BackendRandomShmem = (BackendRandomShmemStruct *)
|
||
|
ShmemInitStruct("Backend PRNG state",
|
||
|
BackendRandomShmemSize(),
|
||
|
&found);
|
||
|
|
||
|
if (!IsUnderPostmaster)
|
||
|
{
|
||
|
Assert(!found);
|
||
|
|
||
|
BackendRandomShmem->initialized = false;
|
||
|
}
|
||
|
else
|
||
|
Assert(found);
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
pg_backend_random(char *dst, int len)
|
||
|
{
|
||
|
int i;
|
||
|
char *end = dst + len;
|
||
|
|
||
|
/* should not be called in postmaster */
|
||
|
Assert (IsUnderPostmaster || !IsPostmasterEnvironment);
|
||
|
|
||
|
LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE);
|
||
|
|
||
|
/*
|
||
|
* Seed the PRNG on the first use.
|
||
|
*/
|
||
|
if (!BackendRandomShmem->initialized)
|
||
|
{
|
||
|
struct timeval now;
|
||
|
|
||
|
gettimeofday(&now, NULL);
|
||
|
|
||
|
BackendRandomShmem->seed[0] = now.tv_sec;
|
||
|
BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec);
|
||
|
BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16);
|
||
|
|
||
|
/*
|
||
|
* Mix in the cancel key, generated by the postmaster. This adds
|
||
|
* what little entropy the postmaster had to the seed.
|
||
|
*/
|
||
|
BackendRandomShmem->seed[0] ^= (MyCancelKey);
|
||
|
BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16);
|
||
|
|
||
|
BackendRandomShmem->initialized = true;
|
||
|
}
|
||
|
|
||
|
for (i = 0; dst < end; i++)
|
||
|
{
|
||
|
uint32 r;
|
||
|
int j;
|
||
|
|
||
|
/*
|
||
|
* pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it.
|
||
|
*/
|
||
|
r = (uint32) pg_jrand48(BackendRandomShmem->seed);
|
||
|
|
||
|
for (j = 0; j < 4 && dst < end; j++)
|
||
|
{
|
||
|
*(dst++) = (char) (r & 0xFF);
|
||
|
r >>= 8;
|
||
|
}
|
||
|
}
|
||
|
LWLockRelease(BackendRandomLock);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif /* HAVE_STRONG_RANDOM */
|