From 78068e010bac158bea0e5550e7b2bd3e08dec137 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 7 Apr 2017 10:24:44 +0900
Subject: [PATCH 2/4] Refactor frontend-side random number generation

pg_frontend_random() is moved into its own file in libpq/ to give other
portions of the libpq code the ability to generate random numbers. This
will be used for the SCRAM verifier generation from clients.
---
 src/interfaces/libpq/Makefile        |  2 +-
 src/interfaces/libpq/fe-auth-scram.c | 53 -----------------------
 src/interfaces/libpq/libpq-int.h     |  1 +
 src/interfaces/libpq/libpq-random.c  | 84 ++++++++++++++++++++++++++++++++++++
 src/interfaces/libpq/libpq-random.h  | 17 ++++++++
 src/tools/msvc/Install.pm            |  2 +-
 6 files changed, 104 insertions(+), 55 deletions(-)
 create mode 100644 src/interfaces/libpq/libpq-random.c
 create mode 100644 src/interfaces/libpq/libpq-random.h

diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 87f22d242f..eb6777ef2b 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -33,7 +33,7 @@ LIBS := $(LIBS:-lpgport=)
 # OBJS from this file.
 OBJS=	fe-auth.o fe-auth-scram.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
 	fe-protocol2.o fe-protocol3.o pqexpbuffer.o fe-secure.o \
-	libpq-events.o
+	libpq-events.o libpq-random.o
 # libpgport C files we always use
 OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
 	thread.o
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index c56e91e0e0..b453c6cc21 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -74,7 +74,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.
@@ -609,55 +608,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/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 34d049262f..65aa51cfc1 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -22,6 +22,7 @@
 
 /* We assume libpq-fe.h has already been included. */
 #include "libpq-events.h"
+#include "libpq-random.h"
 
 #include <time.h>
 #ifndef WIN32
diff --git a/src/interfaces/libpq/libpq-random.c b/src/interfaces/libpq/libpq-random.c
new file mode 100644
index 0000000000..5e788dc821
--- /dev/null
+++ b/src/interfaces/libpq/libpq-random.c
@@ -0,0 +1,84 @@
+/*-------------------------------------------------------------------------
+ *
+ * libpq-random.c
+ *	  Frontend random number generation routine for libpq.
+ *
+ * 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/interfaces/libpq/libpq-random.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+#include "libpq-fe.h"
+#include "libpq-int.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/interfaces/libpq/libpq-random.h b/src/interfaces/libpq/libpq-random.h
new file mode 100644
index 0000000000..054998b8d9
--- /dev/null
+++ b/src/interfaces/libpq/libpq-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/interfaces/libpq/libpq-random.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef LIBPQ_RANDOM_H
+#define LIBPQ_RANDOM_H
+
+extern bool pg_frontend_random(char *dst, int len);
+
+#endif   /* LIBPQ_RANDOM_H */
diff --git a/src/tools/msvc/Install.pm b/src/tools/msvc/Install.pm
index 35ad5b8a44..4acd6592ad 100644
--- a/src/tools/msvc/Install.pm
+++ b/src/tools/msvc/Install.pm
@@ -601,7 +601,7 @@ sub CopyIncludeFiles
 	CopyFiles(
 		'Libpq internal headers',
 		$target . '/include/internal/',
-		'src/interfaces/libpq/', 'libpq-int.h', 'pqexpbuffer.h');
+		'src/interfaces/libpq/', 'libpq-int.h', 'libpq-random.h', 'pqexpbuffer.h');
 
 	CopyFiles(
 		'Internal headers',
-- 
2.12.2

