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