Line data Source code
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
41 5 : BackendRandomShmemSize(void)
42 : {
43 5 : return 0;
44 : }
45 :
46 : void
47 5 : BackendRandomShmemInit(void)
48 : {
49 : /* do nothing */
50 5 : }
51 :
52 : bool
53 3 : pg_backend_random(char *dst, int len)
54 : {
55 : /* should not be called in postmaster */
56 3 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
57 :
58 3 : 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;
75 :
76 : Size
77 : BackendRandomShmemSize(void)
78 : {
79 : return sizeof(BackendRandomShmemStruct);
80 : }
81 :
82 : void
83 : BackendRandomShmemInit(void)
84 : {
85 : bool found;
86 :
87 : BackendRandomShmem = (BackendRandomShmemStruct *)
88 : ShmemInitStruct("Backend PRNG state",
89 : BackendRandomShmemSize(),
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 */
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 */
|