From 539f4ea99bd7040045b83d58fe279a5db7dd213d Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 15 Mar 2017 22:06:12 +0900
Subject: [PATCH 2/4] Refactor frontend-side random number generation

pg_frontend_random() is moved into its own file in src/common/ to
give other portions of the code the ability to generate random numbers.
This will be used for the SCRAM verifier generation from clients.
---
 src/common/Makefile                  |  3 +-
 src/common/frontend_random.c         | 86 ++++++++++++++++++++++++++++++++++++
 src/include/common/frontend_random.h | 17 +++++++
 src/interfaces/libpq/.gitignore      |  1 +
 src/interfaces/libpq/Makefile        |  4 +-
 src/interfaces/libpq/fe-auth-scram.c | 59 +------------------------
 src/tools/msvc/Mkvcbuild.pm          |  2 +-
 7 files changed, 110 insertions(+), 62 deletions(-)
 create mode 100644 src/common/frontend_random.c
 create mode 100644 src/include/common/frontend_random.h

diff --git a/src/common/Makefile b/src/common/Makefile
index 971ddd5ea7..b516ec43f1 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -50,7 +50,8 @@ else
 OBJS_COMMON += sha2.o
 endif
 
-OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_utils.o restricted_token.o
+OBJS_FRONTEND = $(OBJS_COMMON) fe_memutils.o file_utils.o frontend_random.c \
+	restricted_token.o
 
 OBJS_SRV = $(OBJS_COMMON:%.o=%_srv.o)
 
diff --git a/src/common/frontend_random.c b/src/common/frontend_random.c
new file mode 100644
index 0000000000..7ecc7d5fdf
--- /dev/null
+++ b/src/common/frontend_random.c
@@ -0,0 +1,86 @@
+/*-------------------------------------------------------------------------
+ *
+ * frontend_random.c
+ *	  Frontend random number generation routine.
+ *
+ * pg_frontend_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, there is a built-in implementation.
+ *
+ * The built-in implementation uses the standard erand48 algorithm, with
+ * a seed calculated using the process ID and a timestamp.
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/common/frontend_random.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#error "This file is not expected to be compiled for backend code"
+#endif
+
+#include "postgres_fe.h"
+#include "common/frontend_random.h"
+
+/* These are needed for getpid(), in the fallback implementation */
+#ifndef HAVE_STRONG_RANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+/*
+ * Random number generator.
+ */
+bool
+pg_frontend_random(char *dst, int len)
+{
+#ifdef HAVE_STRONG_RANDOM
+	return pg_strong_random(dst, len);
+#else
+	int			i;
+	char	   *end = dst + len;
+
+	static unsigned short seed[3];
+	static int	mypid = 0;
+
+	pglock_thread();
+
+	if (mypid != getpid())
+	{
+		struct timeval now;
+
+		gettimeofday(&now, NULL);
+
+		seed[0] = now.tv_sec ^ getpid();
+		seed[1] = (unsigned short) (now.tv_usec);
+		seed[2] = (unsigned short) (now.tv_usec >> 16);
+	}
+
+	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(seed);
+
+		for (j = 0; j < 4 && dst < end; j++)
+		{
+			*(dst++) = (char) (r & 0xFF);
+			r >>= 8;
+		}
+	}
+
+	pgunlock_thread();
+
+	return true;
+#endif
+}
diff --git a/src/include/common/frontend_random.h b/src/include/common/frontend_random.h
new file mode 100644
index 0000000000..600c55ace9
--- /dev/null
+++ b/src/include/common/frontend_random.h
@@ -0,0 +1,17 @@
+/*-------------------------------------------------------------------------
+ *
+ * frontend_random.h
+ *		Declarations for frontend random number generation
+ *
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
+ *
+ *	  src/include/common/frontend_random.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FRONTEND_RANDOM_H
+#define FRONTEND_RANDOM_H
+
+extern bool pg_frontend_random(char *dst, int len);
+
+#endif   /* FRONTEND_RANDOM_H */
diff --git a/src/interfaces/libpq/.gitignore b/src/interfaces/libpq/.gitignore
index 2224ada731..f84bc35706 100644
--- a/src/interfaces/libpq/.gitignore
+++ b/src/interfaces/libpq/.gitignore
@@ -2,6 +2,7 @@
 /base64.c
 /chklocale.c
 /crypt.c
+/frontend_random.c
 /getaddrinfo.c
 /getpeereid.c
 /inet_aton.c
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 792232db49..757a702a37 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -49,7 +49,7 @@ endif
 # src/backend/utils/mb
 OBJS += encnames.o wchar.o
 # src/common
-OBJS += base64.o ip.o md5.o scram-common.o
+OBJS += base64.o frontend_random.o ip.o md5.o scram-common.o
 
 ifeq ($(with_openssl),yes)
 OBJS += fe-secure-openssl.o sha2_openssl.o
@@ -111,7 +111,7 @@ ip.c md5.c: % : $(top_srcdir)/src/common/%
 encnames.c wchar.c: % : $(backend_src)/utils/mb/%
 	rm -f $@ && $(LN_S) $< .
 
-base64.c scram-common.c sha2.c sha2_openssl.c: % : $(top_srcdir)/src/common/%
+base64.c frontend_random.c scram-common.c sha2.c sha2_openssl.c: % : $(top_srcdir)/src/common/%
 	rm -f $@ && $(LN_S) $< .
 
 
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index a7bb30a141..6390ccf30d 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -15,14 +15,10 @@
 #include "postgres_fe.h"
 
 #include "common/base64.h"
+#include "common/frontend_random.h"
 #include "common/scram-common.h"
 #include "fe-auth.h"
 
-/* These are needed for getpid(), in the fallback implementation */
-#ifndef HAVE_STRONG_RANDOM
-#include <sys/types.h>
-#include <unistd.h>
-#endif
 
 /*
  * Status of exchange messages used for SCRAM authentication via the
@@ -73,7 +69,6 @@ static bool verify_server_proof(fe_scram_state *state);
 static void calculate_client_proof(fe_scram_state *state,
 					   const char *client_final_message_without_proof,
 					   uint8 *result);
-static bool pg_frontend_random(char *dst, int len);
 
 /*
  * Initialize SCRAM exchange status.
@@ -586,55 +581,3 @@ verify_server_proof(fe_scram_state *state)
 
 	return true;
 }
-
-/*
- * Random number generator.
- */
-static bool
-pg_frontend_random(char *dst, int len)
-{
-#ifdef HAVE_STRONG_RANDOM
-	return pg_strong_random(dst, len);
-#else
-	int			i;
-	char	   *end = dst + len;
-
-	static unsigned short seed[3];
-	static int	mypid = 0;
-
-	pglock_thread();
-
-	if (mypid != getpid())
-	{
-		struct timeval now;
-
-		gettimeofday(&now, NULL);
-
-		seed[0] = now.tv_sec ^ getpid();
-		seed[1] = (unsigned short) (now.tv_usec);
-		seed[2] = (unsigned short) (now.tv_usec >> 16);
-	}
-
-	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(seed);
-
-		for (j = 0; j < 4 && dst < end; j++)
-		{
-			*(dst++) = (char) (r & 0xFF);
-			r >>= 8;
-		}
-	}
-
-	pgunlock_thread();
-
-	return true;
-#endif
-}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 12f73f344c..615c769483 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -125,7 +125,7 @@ sub mkvcbuild
 
 	our @pgcommonfrontendfiles = (
 		@pgcommonallfiles, qw(fe_memutils.c file_utils.c
-		  restricted_token.c));
+		  frontend_random.c restricted_token.c));
 
 	our @pgcommonbkndfiles = @pgcommonallfiles;
 
-- 
2.12.0

