PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
backend_random.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * backend_random.c
4  * Backend random number generation routine.
5  *
6  * pg_backend_random() function fills a buffer with random bytes. Normally,
7  * it is just a thin wrapper around pg_strong_random(), but when compiled
8  * with --disable-strong-random, we provide a built-in implementation.
9  *
10  * This function is used for generating nonces in authentication, and for
11  * random salt generation in pgcrypto. The built-in implementation is not
12  * cryptographically strong, but if the user asked for it, we'll go ahead
13  * and use it anyway.
14  *
15  * The built-in implementation uses the standard erand48 algorithm, with
16  * a seed shared between all backends.
17  *
18  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
19  * Portions Copyright (c) 1994, Regents of the University of California
20  *
21  *
22  * IDENTIFICATION
23  * src/backend/utils/misc/backend_random.c
24  *
25  *-------------------------------------------------------------------------
26  */
27 
28 #include "postgres.h"
29 
30 #include <sys/time.h>
31 
32 #include "miscadmin.h"
33 #include "storage/lwlock.h"
34 #include "storage/shmem.h"
35 #include "utils/backend_random.h"
36 #include "utils/timestamp.h"
37 
38 #ifdef HAVE_STRONG_RANDOM
39 
40 Size
42 {
43  return 0;
44 }
45 
46 void
48 {
49  /* do nothing */
50 }
51 
52 bool
53 pg_backend_random(char *dst, int len)
54 {
55  /* should not be called in postmaster */
57 
58  return pg_strong_random(dst, len);
59 }
60 
61 #else
62 
63 /*
64  * Seed for the PRNG, stored in shared memory.
65  *
66  * Protected by BackendRandomLock.
67  */
68 typedef struct
69 {
71  unsigned short seed[3];
73 
75 
76 Size
78 {
79  return sizeof(BackendRandomShmemStruct);
80 }
81 
82 void
84 {
85  bool found;
86 
87  BackendRandomShmem = (BackendRandomShmemStruct *)
88  ShmemInitStruct("Backend PRNG state",
90  &found);
91 
92  if (!IsUnderPostmaster)
93  {
94  Assert(!found);
95 
96  BackendRandomShmem->initialized = false;
97  }
98  else
99  Assert(found);
100 }
101 
102 bool
103 pg_backend_random(char *dst, int len)
104 {
105  int i;
106  char *end = dst + len;
107 
108  /* should not be called in postmaster */
110 
111  LWLockAcquire(BackendRandomLock, LW_EXCLUSIVE);
112 
113  /*
114  * Seed the PRNG on the first use.
115  */
116  if (!BackendRandomShmem->initialized)
117  {
118  struct timeval now;
119 
120  gettimeofday(&now, NULL);
121 
122  BackendRandomShmem->seed[0] = now.tv_sec;
123  BackendRandomShmem->seed[1] = (unsigned short) (now.tv_usec);
124  BackendRandomShmem->seed[2] = (unsigned short) (now.tv_usec >> 16);
125 
126  /*
127  * Mix in the cancel key, generated by the postmaster. This adds what
128  * little entropy the postmaster had to the seed.
129  */
130  BackendRandomShmem->seed[0] ^= (MyCancelKey);
131  BackendRandomShmem->seed[1] ^= (MyCancelKey >> 16);
132 
133  BackendRandomShmem->initialized = true;
134  }
135 
136  for (i = 0; dst < end; i++)
137  {
138  uint32 r;
139  int j;
140 
141  /*
142  * pg_jrand48 returns a 32-bit integer. Fill the next 4 bytes from it.
143  */
144  r = (uint32) pg_jrand48(BackendRandomShmem->seed);
145 
146  for (j = 0; j < 4 && dst < end; j++)
147  {
148  *(dst++) = (char) (r & 0xFF);
149  r >>= 8;
150  }
151  }
152  LWLockRelease(BackendRandomLock);
153 
154  return true;
155 }
156 
157 
158 #endif /* HAVE_STRONG_RANDOM */
static BackendRandomShmemStruct * BackendRandomShmem
bool IsPostmasterEnvironment
Definition: globals.c:100
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:105
Size BackendRandomShmemSize(void)
void BackendRandomShmemInit(void)
bool pg_strong_random(void *buf, size_t len)
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1721
int32 MyCancelKey
Definition: globals.c:42
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
bool pg_backend_random(char *dst, int len)
bool IsUnderPostmaster
Definition: globals.c:101
unsigned int uint32
Definition: c.h:258
unsigned short seed[3]
#define Assert(condition)
Definition: c.h:681
size_t Size
Definition: c.h:350
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1117
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:95
int i