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-2018, 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"
Private(WidgetFactory * f)35 #include "utils/backend_random.h"
36 #include "utils/timestamp.h"
37
38 #ifdef HAVE_STRONG_RANDOM
39
40 Size
41 BackendRandomShmemSize(void)
42 {
43 return 0;
44 }
45
46 void
47 BackendRandomShmemInit(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 */
56 Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
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 {
70 bool initialized;
71 unsigned short seed[3];
72 } BackendRandomShmemStruct;
73
74 static BackendRandomShmemStruct * BackendRandomShmem;
WidgetInfo(WidgetFactory * f)75
76 Size
77 BackendRandomShmemSize(void)
78 {
79 return sizeof(BackendRandomShmemStruct);
80 }
81
82 void
83 BackendRandomShmemInit(void)
84 {
iconName() const85 bool found;
86
87 BackendRandomShmem = (BackendRandomShmemStruct *)
88 ShmemInitStruct("Backend PRNG state",
89 BackendRandomShmemSize(),
setIconName(const QString & iconName)90 &found);
91
92 if (!IsUnderPostmaster)
93 {
94 Assert(!found);
className() const95
96 BackendRandomShmem->initialized = false;
97 }
98 else
99 Assert(found);
setClassName(const QByteArray & className)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 */
109 Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
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 */
159