makecheck-secure-v3.patch

text/plain

Filename: makecheck-secure-v3.patch
Type: text/plain
Part: 0
Message: Securing "make check" (CVE-2014-0067)

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v3
File+
contrib/dblink/expected/dblink.out 4 5
contrib/dblink/sql/dblink.sql 4 5
contrib/pg_upgrade/test.sh 35 2
doc/src/sgml/ref/allfiles.sgml 1 0
doc/src/sgml/reference.sgml 1 0
doc/src/sgml/ref/initdb.sgml 2 0
doc/src/sgml/ref/pg_genpassword.sgml 82 0
doc/src/sgml/regress.sgml 12 20
src/backend/utils/adt/encode.c 1 88
src/bin/Makefile 2 2
src/bin/pg_genpassword/.gitignore 1 0
src/bin/pg_genpassword/Makefile 36 0
src/bin/pg_genpassword/nls.mk 4 0
src/bin/pg_genpassword/pg_genpassword.c 87 0
src/include/port.h 8 0
src/interfaces/ecpg/test/connect/test5.pgc 10 8
src/interfaces/ecpg/test/expected/connect-test5.c 44 38
src/interfaces/ecpg/test/expected/connect-test5.stderr 13 5
src/port/Makefile 2 2
src/port/pgencode.c 120 0
src/port/pgrand.c 119 0
src/test/regress/pg_regress.c 117 2
src/tools/msvc/Mkvcbuild.pm 4 1
src/tools/msvc/vcregress.pl 30 2
diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out
index f237c43..36fdf73 100644
--- a/contrib/dblink/expected/dblink.out
+++ b/contrib/dblink/expected/dblink.out
@@ -782,18 +782,17 @@ SELECT dblink_disconnect('dtest1');
 (1 row)
 
 -- test foreign data wrapper functionality
-CREATE USER dblink_regression_test;
+CREATE ROLE dblink_regression_test;
 CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw
   OPTIONS (dbname 'contrib_regression');
 CREATE USER MAPPING FOR public SERVER fdtest
   OPTIONS (server 'localhost');  -- fail, can't specify server here
 ERROR:  invalid option "server"
 HINT:  Valid options in this context are: user, password
-CREATE USER MAPPING FOR public SERVER fdtest;
+CREATE USER MAPPING FOR public SERVER fdtest OPTIONS (user :'USER');
 GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
 GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
-\set ORIGINAL_USER :USER
-\c - dblink_regression_test
+SET SESSION AUTHORIZATION dblink_regression_test;
 -- should fail
 SELECT dblink_connect('myconn', 'fdtest');
 ERROR:  password is required
@@ -821,7 +820,7 @@ SELECT * FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[])
  10 | k | {a10,b10,c10}
 (11 rows)
 
-\c - :ORIGINAL_USER
+\c - -
 REVOKE USAGE ON FOREIGN SERVER fdtest FROM dblink_regression_test;
 REVOKE EXECUTE ON FUNCTION dblink_connect_u(text, text) FROM dblink_regression_test;
 DROP USER dblink_regression_test;
diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql
index 2a10760..30396ed 100644
--- a/contrib/dblink/sql/dblink.sql
+++ b/contrib/dblink/sql/dblink.sql
@@ -359,25 +359,24 @@ SELECT dblink_error_message('dtest1');
 SELECT dblink_disconnect('dtest1');
 
 -- test foreign data wrapper functionality
-CREATE USER dblink_regression_test;
+CREATE ROLE dblink_regression_test;
 CREATE SERVER fdtest FOREIGN DATA WRAPPER dblink_fdw
   OPTIONS (dbname 'contrib_regression');
 CREATE USER MAPPING FOR public SERVER fdtest
   OPTIONS (server 'localhost');  -- fail, can't specify server here
-CREATE USER MAPPING FOR public SERVER fdtest;
+CREATE USER MAPPING FOR public SERVER fdtest OPTIONS (user :'USER');
 
 GRANT USAGE ON FOREIGN SERVER fdtest TO dblink_regression_test;
 GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO dblink_regression_test;
 
-\set ORIGINAL_USER :USER
-\c - dblink_regression_test
+SET SESSION AUTHORIZATION dblink_regression_test;
 -- should fail
 SELECT dblink_connect('myconn', 'fdtest');
 -- should succeed
 SELECT dblink_connect_u('myconn', 'fdtest');
 SELECT * FROM dblink('myconn','SELECT * FROM foo') AS t(a int, b text, c text[]);
 
-\c - :ORIGINAL_USER
+\c - -
 REVOKE USAGE ON FOREIGN SERVER fdtest FROM dblink_regression_test;
 REVOKE EXECUTE ON FUNCTION dblink_connect_u(text, text) FROM dblink_regression_test;
 DROP USER dblink_regression_test;
diff --git a/contrib/pg_upgrade/test.sh b/contrib/pg_upgrade/test.sh
index 1ef80ed..87cf01c 100644
--- a/contrib/pg_upgrade/test.sh
+++ b/contrib/pg_upgrade/test.sh
@@ -111,10 +111,43 @@ done
 EXTRA_REGRESS_OPTS="$EXTRA_REGRESS_OPTS --port=$PGPORT"
 export EXTRA_REGRESS_OPTS
 
+# Use md5 authentication; take the bootstrap superuser password from a
+# user-specified file, or generate a password.  Prepare password files
+# suitable for initdb and libpq.  A strong password prevents hostile local
+# users from connecting to the test server and using superuser-only features
+# to hijack the OS user account.
+pwdir=$temp_root/passwords
+server_pwfile=${PGTESTPWFILE-$pwdir/superuser_password}
+PGPASSFILE=$pwdir/pgpass
+export PGPASSFILE
+(
+	# Most of these commands rarely fail, but be paranoid.
+	set -e
+
+	# Since we can't readily use O_EXCL, create a directory accessible to the
+	# owner alone and store the files there.
+	umask 077
+	rm -rf "$pwdir"
+	mkdir "$pwdir"
+
+	if [ -n "${PGTESTPWFILE+set}" ] || pg_genpassword >"$server_pwfile"; then
+		:
+	else
+		cat >&2 <<EOF
+Failed to generate a strong password for the test superuser.  Set the
+PGTESTPWFILE environment variable to the absolute path of a file containing a
+strong password, which need not and should not match one you use elsewhere.
+EOF
+		exit 1
+	fi
+
+	{ printf '*:*:*:*:'; cat "$server_pwfile"; } >"$PGPASSFILE"
+) || exit
+
 # enable echo so the user can see what is being executed
 set -x
 
-$oldbindir/initdb -N
+$oldbindir/initdb -N --auth=md5 --pwfile="$server_pwfile"
 $oldbindir/pg_ctl start -l "$logdir/postmaster1.log" -o "$POSTMASTER_OPTS" -w
 if "$MAKE" -C "$oldsrc" installcheck; then
 	pg_dumpall -f "$temp_root"/dump1.sql || pg_dumpall1_status=$?
@@ -154,7 +187,7 @@ fi
 
 PGDATA=$BASE_PGDATA
 
-initdb -N
+initdb -N --auth=md5 --pwfile="$server_pwfile"
 
 pg_upgrade $PG_UPGRADE_OPTS -d "${PGDATA}.old" -D "${PGDATA}" -b "$oldbindir" -B "$bindir" -p "$PGPORT" -P "$PGPORT"
 
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index ce7a5e3..5a6ad33 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -181,6 +181,7 @@ Complete list of usable sgml source files in this directory.
 <!ENTITY pgCtl              SYSTEM "pg_ctl-ref.sgml">
 <!ENTITY pgDump             SYSTEM "pg_dump.sgml">
 <!ENTITY pgDumpall          SYSTEM "pg_dumpall.sgml">
+<!ENTITY pgGenpassword      SYSTEM "pg_genpassword.sgml">
 <!ENTITY pgIsready          SYSTEM "pg_isready.sgml">
 <!ENTITY pgReceivexlog      SYSTEM "pg_receivexlog.sgml">
 <!ENTITY pgResetxlog        SYSTEM "pg_resetxlog.sgml">
diff --git a/doc/src/sgml/ref/initdb.sgml b/doc/src/sgml/ref/initdb.sgml
index 228edf7..72ef536 100644
--- a/doc/src/sgml/ref/initdb.sgml
+++ b/doc/src/sgml/ref/initdb.sgml
@@ -254,6 +254,8 @@ PostgreSQL documentation
        <para>
         Makes <command>initdb</command> read the database superuser's password
         from a file.  The first line of the file is taken as the password.
+        <xref linkend="app-pggenpassword"> is available for generating strong
+        passwords.
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/ref/pg_genpassword.sgml b/doc/src/sgml/ref/pg_genpassword.sgml
new file mode 100644
index 0000000..d19b9f1
--- /dev/null
+++ b/doc/src/sgml/ref/pg_genpassword.sgml
@@ -0,0 +1,82 @@
+<!--
+doc/src/sgml/ref/pg_genpassword.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="APP-PGGENPASSWORD">
+ <refmeta>
+  <refentrytitle>pg_genpassword</refentrytitle>
+  <manvolnum>1</manvolnum>
+  <refmiscinfo>Application</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+  <refname>pg_genpassword</refname>
+  <refpurpose>generate a strong user password</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="app-pggenpassword">
+  <primary>pg_genpassword</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+  <cmdsynopsis>
+   <command>pg_genpassword</command>
+   <arg choice="opt"><replaceable class="parameter">option</replaceable></arg>
+  </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-APP-PGGENPASSWORD-1">
+  <title>
+   Description
+  </title>
+  <para>
+   <command>pg_genpassword</> generates a password from system-provided
+   entropy and prints it to standard output.  The password is not conducive to
+   human memorization.  It suits machine use, particularly automated test
+   suites.  <command>pg_genpassword</> exits with status 2 if it fails due to
+   the absence of any supported entropy source.  For any other failure cause,
+   it exits with status 1.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Options</title>
+
+   <para>
+    <variablelist>
+     <varlistentry>
+       <term><option>-V</></term>
+       <term><option>--version</></term>
+       <listitem>
+       <para>
+       Print the <application>pg_genpassword</application> version and exit.
+       </para>
+       </listitem>
+     </varlistentry>
+
+     <varlistentry>
+       <term><option>-?</></term>
+       <term><option>--help</></term>
+       <listitem>
+       <para>
+       Show help about <application>pg_genpassword</application> command line
+       arguments, and exit.
+       </para>
+       </listitem>
+     </varlistentry>
+
+    </variablelist>
+   </para>
+
+ </refsect1>
+
+ <refsect1>
+  <title>See Also</title>
+
+  <simplelist type="inline">
+   <member><xref linkend="app-initdb"></member>
+  </simplelist>
+ </refsect1>
+
+</refentry>
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index 87e8e9e..a1dcae2 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -252,6 +252,7 @@
   </partintro>
 
    &initdb;
+   &pgGenpassword;
    &pgControldata;
    &pgCtl;
    &pgResetxlog;
diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml
index 16b3621..3db8cf8 100644
--- a/doc/src/sgml/regress.sgml
+++ b/doc/src/sgml/regress.sgml
@@ -56,26 +56,6 @@ make check
    <quote>failure</> represents a serious problem.
   </para>
 
-  <warning>
-   <para>
-    This test method starts a temporary server, which is configured to accept
-    any connection originating on the local machine.  Any local user can gain
-    database superuser privileges when connecting to this server, and could
-    in principle exploit all privileges of the operating-system user running
-    the tests.  Therefore, it is not recommended that you use <literal>make
-    check</> on machines shared with untrusted users.  Instead, run the tests
-    after completing the installation, as described in the next section.
-   </para>
-
-   <para>
-    On Unix-like machines, this danger can be avoided if the temporary
-    server's socket file is made inaccessible to other users, for example
-    by running the tests in a protected chroot.  On Windows, the temporary
-    server opens a locally-accessible TCP socket, so filesystem protections
-    cannot help.
-   </para>
-  </warning>
-
    <para>
     Because this test method runs a temporary server, it will not work
     if you did the build as the root user, since the server will not start as
@@ -111,6 +91,18 @@ make MAX_CONNECTIONS=10 check
 </screen>
     runs no more than ten tests concurrently.
    </para>
+
+   <para>
+    To protect your operating system user account, the test driver generates a
+    strong password for the bootstrap superuser account of the temporary
+    database cluster.  If your platform lacks a recognized source of
+    high-entropy bytes, such as <filename>/dev/urandom</>, <literal>make
+    check</> will fail at that step.  To work around this problem, store a
+    strong password alone in a text file and set the <envar>PGTESTPWFILE</>
+    environment variable to the location of that file.  This variable can also
+    be used on systems having a recognized entropy source to avoid draining
+    the system entropy pool for password generation.
+   </para>
   </sect2>
 
   <sect2>
diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c
index 46993ba..adcd8f3 100644
--- a/src/backend/utils/adt/encode.c
+++ b/src/backend/utils/adt/encode.c
@@ -106,96 +106,9 @@ binary_decode(PG_FUNCTION_ARGS)
 
 
 /*
- * HEX
+ * HEX from src/port/pgencode.c
  */
 
-static const char hextbl[] = "0123456789abcdef";
-
-static const int8 hexlookup[128] = {
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-
-unsigned
-hex_encode(const char *src, unsigned len, char *dst)
-{
-	const char *end = src + len;
-
-	while (src < end)
-	{
-		*dst++ = hextbl[(*src >> 4) & 0xF];
-		*dst++ = hextbl[*src & 0xF];
-		src++;
-	}
-	return len * 2;
-}
-
-static inline char
-get_hex(char c)
-{
-	int			res = -1;
-
-	if (c > 0 && c < 127)
-		res = hexlookup[(unsigned char) c];
-
-	if (res < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("invalid hexadecimal digit: \"%c\"", c)));
-
-	return (char) res;
-}
-
-unsigned
-hex_decode(const char *src, unsigned len, char *dst)
-{
-	const char *s,
-			   *srcend;
-	char		v1,
-				v2,
-			   *p;
-
-	srcend = src + len;
-	s = src;
-	p = dst;
-	while (s < srcend)
-	{
-		if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
-		{
-			s++;
-			continue;
-		}
-		v1 = get_hex(*s++) << 4;
-		if (s >= srcend)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				  errmsg("invalid hexadecimal data: odd number of digits")));
-
-		v2 = get_hex(*s++);
-		*p++ = v1 | v2;
-	}
-
-	return p - dst;
-}
-
-static unsigned
-hex_enc_len(const char *src, unsigned srclen)
-{
-	return srclen << 1;
-}
-
-static unsigned
-hex_dec_len(const char *src, unsigned srclen)
-{
-	return srclen >> 1;
-}
-
 /*
  * BASE64
  */
diff --git a/src/bin/Makefile b/src/bin/Makefile
index f03cc42..cf4358d 100644
--- a/src/bin/Makefile
+++ b/src/bin/Makefile
@@ -13,8 +13,8 @@ subdir = src/bin
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS = initdb pg_ctl pg_dump \
-	psql scripts pg_config pg_controldata pg_resetxlog pg_basebackup
+SUBDIRS = initdb pg_ctl pg_dump psql scripts pg_config pg_controldata \
+	pg_resetxlog pg_basebackup pg_genpassword
 
 ifeq ($(PORTNAME), win32)
 SUBDIRS += pgevent
diff --git a/src/bin/pg_genpassword/.gitignore b/src/bin/pg_genpassword/.gitignore
new file mode 100644
index 0000000..a310f5b
--- /dev/null
+++ b/src/bin/pg_genpassword/.gitignore
@@ -0,0 +1 @@
+/pg_genpassword
diff --git a/src/bin/pg_genpassword/Makefile b/src/bin/pg_genpassword/Makefile
new file mode 100644
index 0000000..fd6c57d
--- /dev/null
+++ b/src/bin/pg_genpassword/Makefile
@@ -0,0 +1,36 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/bin/pg_genpassword
+#
+# Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/bin/pg_genpassword/Makefile
+#
+#-------------------------------------------------------------------------
+
+PGFILEDESC = "pg_genpassword - generate a strong user password"
+PGAPPICON=win32
+
+subdir = src/bin/pg_genpassword
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS= pg_genpassword.o $(WIN32RES)
+
+all: pg_genpassword
+
+pg_genpassword: $(OBJS) | submake-libpgport
+	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+
+install: all installdirs
+	$(INSTALL_PROGRAM) pg_genpassword$(X) '$(DESTDIR)$(bindir)/pg_genpassword$(X)'
+
+installdirs:
+	$(MKDIR_P) '$(DESTDIR)$(bindir)'
+
+uninstall:
+	rm -f '$(DESTDIR)$(bindir)/pg_genpassword$(X)'
+
+clean distclean maintainer-clean:
+	rm -f pg_genpassword$(X) $(OBJS)
diff --git a/src/bin/pg_genpassword/nls.mk b/src/bin/pg_genpassword/nls.mk
new file mode 100644
index 0000000..64981eb
--- /dev/null
+++ b/src/bin/pg_genpassword/nls.mk
@@ -0,0 +1,4 @@
+# src/bin/pg_genpassword/nls.mk
+CATALOG_NAME     = pg_genpassword
+AVAIL_LANGUAGES  =
+GETTEXT_FILES    = pg_genpassword.c ../../port/exec.c
diff --git a/src/bin/pg_genpassword/pg_genpassword.c b/src/bin/pg_genpassword/pg_genpassword.c
new file mode 100644
index 0000000..a1ee5f9
--- /dev/null
+++ b/src/bin/pg_genpassword/pg_genpassword.c
@@ -0,0 +1,87 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_genpassword.c - generate a strong user password
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		  src/bin/pg_genpassword/pg_genpassword.c
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+
+const char *progname;
+
+static void
+usage(void)
+{
+	printf(_("%s generates a strong user password.\n\n"),
+		   progname);
+	printf(_("Usage:\n"));
+	printf(_("  %s [OPTION]...\n"), progname);
+	printf(_("\nOptions:\n"));
+	printf(_("  -V, --version          output version information, then exit\n"));
+	printf(_("  -?, --help             show this help, then exit\n"));
+	printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
+}
+
+int
+main(int argc, char **argv)
+{
+	char		entropy[16];
+	unsigned	hex_len;
+	char	   *password;
+
+	progname = get_progname(argv[0]);
+	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_genpassword"));
+
+	if (argc > 1)
+	{
+		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
+		{
+			usage();
+			exit(0);
+		}
+		else if (strcmp(argv[1], "-V") == 0
+				 || strcmp(argv[1], "--version") == 0)
+		{
+			puts("pg_genpassword (PostgreSQL) " PG_VERSION);
+			exit(0);
+		}
+		else
+		{
+			fprintf(stderr,
+				_("%s: too many command-line arguments (first is \"%s\")\n"),
+					progname, argv[1]);
+			fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+					progname);
+			exit(1);
+		}
+	}
+
+
+	/*
+	 * Generate a sequence of 16 secure random bytes, hex-encode them, and
+	 * print the result.
+	 */
+	if (!secure_rand_bytes((unsigned char *) entropy, sizeof(entropy)))
+	{
+		fprintf(stderr, _("%s: could not gather system entropy\n"), progname);
+		exit(2);
+	}
+
+	hex_len = hex_enc_len(entropy, sizeof(entropy));
+	password = malloc(hex_len + 1);
+	if (password == NULL)
+	{
+		fprintf(stderr, _("%s: out of memory\n"), progname);
+		exit(1);
+	}
+	hex_encode(entropy, sizeof(entropy), password);
+	password[hex_len] = '\0';
+
+	puts(password);
+
+	return 0;
+}
diff --git a/src/include/port.h b/src/include/port.h
index aeb7754..f5662c1 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -373,6 +373,8 @@ extern double pg_erand48(unsigned short xseed[3]);
 extern long pg_lrand48(void);
 extern void pg_srand48(long seed);
 
+extern bool secure_rand_bytes(unsigned char *buf, int count);
+
 #ifndef HAVE_FLS
 extern int	fls(int mask);
 #endif
@@ -462,6 +464,12 @@ extern int	pg_check_dir(const char *dir);
 /* port/pgmkdirp.c */
 extern int	pg_mkdir_p(char *path, int omode);
 
+/* port/pgencode.c */
+extern unsigned hex_encode(const char *src, unsigned len, char *dst);
+extern unsigned hex_decode(const char *src, unsigned len, char *dst);
+extern unsigned hex_enc_len(const char *src, unsigned srclen);
+extern unsigned hex_dec_len(const char *src, unsigned srclen);
+
 /* port/pqsignal.c */
 typedef void (*pqsigfunc) (int signo);
 extern pqsigfunc pqsignal(int signo, pqsigfunc func);
diff --git a/src/interfaces/ecpg/test/connect/test5.pgc b/src/interfaces/ecpg/test/connect/test5.pgc
index d3efecb..5ba59eb 100644
--- a/src/interfaces/ecpg/test/connect/test5.pgc
+++ b/src/interfaces/ecpg/test/connect/test5.pgc
@@ -21,7 +21,9 @@ exec sql end declare section;
 	ECPGdebug(1, stderr);
 
 	exec sql connect to connectdb as main;
+	exec sql alter user connectdb ENCRYPTED PASSWORD 'insecure';
 	exec sql alter user connectuser ENCRYPTED PASSWORD 'connectpw';
+	exec sql commit;
 	exec sql disconnect;  /* <-- "main" not specified */
 
 	strcpy(db, "connectdb");
@@ -38,28 +40,28 @@ exec sql end declare section;
 	exec sql connect to 'connectdb' as main;
 	exec sql disconnect main;
 
-	exec sql connect to as main user connectdb;
+	exec sql connect to as main user connectdb/insecure;
 	exec sql disconnect main;
 
-	exec sql connect to connectdb as main user connectuser/connectdb;
+	exec sql connect to connectdb as main user connectuser/connectpw;
 	exec sql disconnect main;
 
-	exec sql connect to unix:postgresql://localhost/connectdb as main user connectuser;
+	exec sql connect to unix:postgresql://localhost/connectdb as main user connectuser/connectpw;
 	exec sql disconnect main;
 
-	exec sql connect to "unix:postgresql://localhost/connectdb" as main user connectuser;
+	exec sql connect to "unix:postgresql://localhost/connectdb" as main user connectuser/connectpw;
 	exec sql disconnect main;
 
-	exec sql connect to 'unix:postgresql://localhost/connectdb' as main user :user;
+	exec sql connect to 'unix:postgresql://localhost/connectdb' as main user :user USING "connectpw";
 	exec sql disconnect main;
 
-	exec sql connect to unix:postgresql://localhost/connectdb?connect_timeout=14&client_encoding=latin1 as main user connectuser;
+	exec sql connect to unix:postgresql://localhost/connectdb?connect_timeout=14&client_encoding=latin1 as main user connectuser/connectpw;
 	exec sql disconnect main;
 
-	exec sql connect to "unix:postgresql://200.46.204.71/connectdb" as main user connectuser;
+	exec sql connect to "unix:postgresql://200.46.204.71/connectdb" as main user connectuser/connectpw;
 	exec sql disconnect main;
 
-	exec sql connect to unix:postgresql://localhost/ as main user connectdb;
+	exec sql connect to unix:postgresql://localhost/ as main user connectdb IDENTIFIED BY insecure;
 	exec sql disconnect main;
 
 	/* connect twice */
diff --git a/src/interfaces/ecpg/test/expected/connect-test5.c b/src/interfaces/ecpg/test/expected/connect-test5.c
index a8f79f9..79decd3 100644
--- a/src/interfaces/ecpg/test/expected/connect-test5.c
+++ b/src/interfaces/ecpg/test/expected/connect-test5.c
@@ -43,113 +43,119 @@ main(void)
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
 #line 23 "test5.pgc"
 
-	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "alter user connectuser encrypted password 'connectpw'", ECPGt_EOIT, ECPGt_EORT);}
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "alter user connectdb encrypted password 'insecure'", ECPGt_EOIT, ECPGt_EORT);}
 #line 24 "test5.pgc"
 
-	{ ECPGdisconnect(__LINE__, "CURRENT");}
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "alter user connectuser encrypted password 'connectpw'", ECPGt_EOIT, ECPGt_EORT);}
 #line 25 "test5.pgc"
+
+	{ ECPGtrans(__LINE__, NULL, "commit");}
+#line 26 "test5.pgc"
+
+	{ ECPGdisconnect(__LINE__, "CURRENT");}
+#line 27 "test5.pgc"
   /* <-- "main" not specified */
 
 	strcpy(db, "connectdb");
 	strcpy(id, "main");
 	{ ECPGconnect(__LINE__, 0, db , NULL, NULL , id, 0); }
-#line 29 "test5.pgc"
+#line 31 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, id);}
-#line 30 "test5.pgc"
+#line 32 "test5.pgc"
 
 
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
-#line 32 "test5.pgc"
+#line 34 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 33 "test5.pgc"
+#line 35 "test5.pgc"
 
 
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
-#line 35 "test5.pgc"
+#line 37 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 36 "test5.pgc"
+#line 38 "test5.pgc"
 
 
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
-#line 38 "test5.pgc"
+#line 40 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 39 "test5.pgc"
+#line 41 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "" , "connectdb" , NULL , "main", 0); }
-#line 41 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "" , "connectdb" , "insecure" , "main", 0); }
+#line 43 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 42 "test5.pgc"
+#line 44 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "connectdb" , "connectuser" , "connectdb" , "main", 0); }
-#line 44 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "connectdb" , "connectuser" , "connectpw" , "main", 0); }
+#line 46 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 45 "test5.pgc"
+#line 47 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , "connectuser" , NULL , "main", 0); }
-#line 47 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , "connectuser" , "connectpw" , "main", 0); }
+#line 49 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 48 "test5.pgc"
+#line 50 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , "connectuser" , NULL , "main", 0); }
-#line 50 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , "connectuser" , "connectpw" , "main", 0); }
+#line 52 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 51 "test5.pgc"
+#line 53 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , user , NULL , "main", 0); }
-#line 53 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb" , user , "connectpw" , "main", 0); }
+#line 55 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 54 "test5.pgc"
+#line 56 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb?connect_timeout=14 & client_encoding=latin1" , "connectuser" , NULL , "main", 0); }
-#line 56 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/connectdb?connect_timeout=14 & client_encoding=latin1" , "connectuser" , "connectpw" , "main", 0); }
+#line 58 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 57 "test5.pgc"
+#line 59 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://200.46.204.71/connectdb" , "connectuser" , NULL , "main", 0); }
-#line 59 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://200.46.204.71/connectdb" , "connectuser" , "connectpw" , "main", 0); }
+#line 61 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 60 "test5.pgc"
+#line 62 "test5.pgc"
 
 
-	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/" , "connectdb" , NULL , "main", 0); }
-#line 62 "test5.pgc"
+	{ ECPGconnect(__LINE__, 0, "unix:postgresql://localhost/" , "connectdb" , "insecure" , "main", 0); }
+#line 64 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 63 "test5.pgc"
+#line 65 "test5.pgc"
 
 
 	/* connect twice */
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
-#line 66 "test5.pgc"
+#line 68 "test5.pgc"
 
 	{ ECPGconnect(__LINE__, 0, "connectdb" , NULL, NULL , "main", 0); }
-#line 67 "test5.pgc"
+#line 69 "test5.pgc"
 
 	{ ECPGdisconnect(__LINE__, "main");}
-#line 68 "test5.pgc"
+#line 70 "test5.pgc"
 
 
 	/* not connected */
 	{ ECPGdisconnect(__LINE__, "nonexistant");}
-#line 71 "test5.pgc"
+#line 73 "test5.pgc"
 
 
 	return (0);
diff --git a/src/interfaces/ecpg/test/expected/connect-test5.stderr b/src/interfaces/ecpg/test/expected/connect-test5.stderr
index 9c8dbf2..c856960 100644
--- a/src/interfaces/ecpg/test/expected/connect-test5.stderr
+++ b/src/interfaces/ecpg/test/expected/connect-test5.stderr
@@ -2,12 +2,20 @@
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database connectdb on <DEFAULT> port <DEFAULT>  
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ecpg_execute on line 24: query: alter user connectuser encrypted password 'connectpw'; with 0 parameter(s) on connection main
+[NO_PID]: ecpg_execute on line 24: query: alter user connectdb encrypted password 'insecure'; with 0 parameter(s) on connection main
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_execute on line 24: using PQexec
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_process_output on line 24: OK: ALTER ROLE
 [NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: query: alter user connectuser encrypted password 'connectpw'; with 0 parameter(s) on connection main
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 25: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 25: OK: ALTER ROLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGtrans on line 26: action "commit"; connection "main"
+[NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection main closed
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ECPGconnect: opening database connectdb on <DEFAULT> port <DEFAULT>  
@@ -50,11 +58,11 @@
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection main closed
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: ECPGconnect: non-localhost access via sockets on line 59
+[NO_PID]: ECPGconnect: non-localhost access via sockets on line 61
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: raising sqlcode -402 on line 59: could not connect to database "connectdb" on line 59
+[NO_PID]: raising sqlcode -402 on line 61: could not connect to database "connectdb" on line 61
 [NO_PID]: sqlca: code: -402, state: 08001
-[NO_PID]: raising sqlcode -220 on line 60: connection "main" does not exist on line 60
+[NO_PID]: raising sqlcode -220 on line 62: connection "main" does not exist on line 62
 [NO_PID]: sqlca: code: -220, state: 08003
 [NO_PID]: ECPGconnect: opening database <DEFAULT> on <DEFAULT> port <DEFAULT>  for user connectdb
 [NO_PID]: sqlca: code: 0, state: 00000
@@ -66,5 +74,5 @@
 [NO_PID]: sqlca: code: 0, state: 00000
 [NO_PID]: ecpg_finish: connection main closed
 [NO_PID]: sqlca: code: 0, state: 00000
-[NO_PID]: raising sqlcode -220 on line 71: connection "nonexistant" does not exist on line 71
+[NO_PID]: raising sqlcode -220 on line 73: connection "nonexistant" does not exist on line 73
 [NO_PID]: sqlca: code: -220, state: 08003
diff --git a/src/port/Makefile b/src/port/Makefile
index 1be4ff5..2a356ec 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -31,8 +31,8 @@ override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
 LIBS += $(PTHREAD_LIBS)
 
 OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o fls.o inet_net_ntop.o \
-	noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
-	pgstrcasecmp.o pqsignal.o \
+	noblock.o path.o pgcheckdir.o pg_crc.o pgencode.o pgmkdirp.o \
+	pgrand.o pgsleep.o pgstrcasecmp.o pqsignal.o \
 	qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
 
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
diff --git a/src/port/pgencode.c b/src/port/pgencode.c
new file mode 100644
index 0000000..313af7c
--- /dev/null
+++ b/src/port/pgencode.c
@@ -0,0 +1,120 @@
+/*-------------------------------------------------------------------------
+ *
+ * pgencode.c
+ *	  Data encode/decode algorithms used in both frontend and backend code
+ *
+ * Copyright (c) 2001-2014, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *	  src/port/pgencode.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+/*
+ * On success, decode functions return the number of bytes written.  In the
+ * backend, they raise errors using ereport(ERROR).  In frontend programs,
+ * they instead return -1.	Other functions defined in this file never fail.
+ */
+#ifdef FRONTEND
+#define ereport(elevel, rest) return -1
+#endif
+
+
+/*
+ * HEX
+ */
+
+static const char hextbl[] = "0123456789abcdef";
+
+static const int8 hexlookup[128] = {
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+
+unsigned
+hex_encode(const char *src, unsigned len, char *dst)
+{
+	const char *end = src + len;
+
+	while (src < end)
+	{
+		*dst++ = hextbl[(*src >> 4) & 0xF];
+		*dst++ = hextbl[*src & 0xF];
+		src++;
+	}
+	return len * 2;
+}
+
+static inline char
+get_hex(char c)
+{
+	int			res = -1;
+
+	if (c > 0 && c < 127)
+		res = hexlookup[(unsigned char) c];
+
+	if (res < 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid hexadecimal digit: \"%c\"", c)));
+
+	return (char) res;
+}
+
+unsigned
+hex_decode(const char *src, unsigned len, char *dst)
+{
+	const char *s,
+			   *srcend;
+	char		v1,
+				v2,
+			   *p;
+
+	srcend = src + len;
+	s = src;
+	p = dst;
+	while (s < srcend)
+	{
+		if (*s == ' ' || *s == '\n' || *s == '\t' || *s == '\r')
+		{
+			s++;
+			continue;
+		}
+		v1 = get_hex(*s++) << 4;
+		if (s >= srcend)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				  errmsg("invalid hexadecimal data: odd number of digits")));
+
+		v2 = get_hex(*s++);
+		*p++ = v1 | v2;
+	}
+
+	return p - dst;
+}
+
+unsigned
+hex_enc_len(const char *src, unsigned srclen)
+{
+	return srclen << 1;
+}
+
+unsigned
+hex_dec_len(const char *src, unsigned srclen)
+{
+	return srclen >> 1;
+}
diff --git a/src/port/pgrand.c b/src/port/pgrand.c
new file mode 100644
index 0000000..604f6d2
--- /dev/null
+++ b/src/port/pgrand.c
@@ -0,0 +1,119 @@
+/*
+ * pgrand.c
+ *		Cryptographically secure pseudo-random numbers
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Copyright (c) 2001 Marko Kreen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *	  notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *	  notice, this list of conditions and the following disclaimer in the
+ *	  documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * src/port/pgrand.c
+ */
+
+#include "c.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef USE_SSL
+#include <openssl/rand.h>
+#endif
+
+#if !defined(USE_SSL) && !defined(WIN32)
+/* Wrapper for read(2) that never returns short. */
+static int
+safe_read(int fd, void *buf, size_t count)
+{
+	int			done = 0;
+	char	   *p = buf;
+	int			res;
+
+	while (count)
+	{
+		res = read(fd, p, count);
+		if (res <= 0)
+		{
+			if (errno == EINTR)
+				continue;
+			return res;
+		}
+		p += res;
+		done += res;
+		count -= res;
+	}
+	return done;
+}
+#endif
+
+/*
+ * secure_rand_bytes: retrieve an arbitrary quantity of random bytes
+ *
+ * Current callers need no more than 16 bytes per process, so seeding a PRNG
+ * costs as much as simply using the OS entropy directly.  When available, use
+ * the OpenSSL PRNG; if for no other reason, it supports a wider range of
+ * entropy sources.  In the absence of OpenSSL, retrieve bytes directly from
+ * an OS source.  If we ever add a high-volume caller, consider importing
+ * pgcrypto's PRNG for use in non-SSL builds.
+ *
+ * We never fall back to emitting low-entropy sequences.  Callers should do so
+ * where acceptable.
+ */
+bool
+secure_rand_bytes(unsigned char *buf, int count)
+{
+#if defined(USE_SSL)
+	return RAND_bytes(buf, count) == 1;
+#elif defined(WIN32)
+	int			res;
+	HCRYPTPROV	h = 0;
+
+	res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+							  (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
+	if (!res)
+		res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+			   CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET);
+	if (!res)
+		return false;
+
+	res = CryptGenRandom(h, count, buf);
+	if (!res)
+		return false;
+
+	CryptReleaseContext(h, 0);
+	return true;
+#else
+	int			fd;
+	int			res;
+
+	fd = open("/dev/urandom", O_RDONLY, 0);
+	if (fd == -1)
+	{
+		fd = open("/dev/random", O_RDONLY, 0);
+		if (fd == -1)
+			return false;
+	}
+	res = safe_read(fd, buf, count);
+	close(fd);
+	return res == count;
+#endif
+}
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 3a49244..4724b43 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -19,6 +19,7 @@
 #include "pg_regress.h"
 
 #include <ctype.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <signal.h>
@@ -92,6 +93,7 @@ static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
 static _stringlist *extra_tests = NULL;
 static char *temp_install = NULL;
+static char *server_pwfile = NULL;
 static char *temp_config = NULL;
 static char *top_builddir = NULL;
 static bool nolocale = false;
@@ -682,6 +684,114 @@ add_to_path(const char *pathname, char separator, const char *addval)
 }
 
 /*
+ * Take the bootstrap superuser password from a user-specified file, or
+ * generate a password.  Prepare password files suitable for initdb and libpq.
+ * A strong password prevents hostile local users from connecting to the test
+ * server and using superuser-only features to hijack the OS user account.
+ *
+ * The ability to specify a password is mostly for the benefit of systems
+ * lacking the infrastructure for us to generate one.  Folks could do so for
+ * other reasons, such as to relieve pressure on system entropy.
+ */
+static void
+initialize_password(void)
+{
+	char		file_buf[MAXPGPATH * 2],
+				password_buf[MAXPGPATH],
+				pgpass_buf[MAXPGPATH + 32];
+	int			fd;
+	int			len_pgpass;
+
+	server_pwfile = getenv("PGTESTPWFILE");
+	if (server_pwfile != NULL)
+	{
+		int			len;
+
+		/* Read the password so we can create a PGPASSFILE. */
+		fd = open(server_pwfile, O_RDONLY);
+		if (fd < 0
+			|| (len = read(fd, password_buf, sizeof(password_buf))) < 1
+			|| close(fd) != 0)
+		{
+			fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
+					progname, server_pwfile, strerror(errno));
+			exit(2);
+		}
+
+		if (len >= sizeof(password_buf))
+		{
+			fprintf(stderr,
+					_("%s: password file \"%s\" must be shorter than %u bytes\n"),
+					progname, server_pwfile, (unsigned) sizeof(password_buf));
+			exit(2);
+		}
+
+		password_buf[len] = '\0';
+	}
+	else
+	{
+		FILE	   *child;
+		int			len;
+
+		/* Generate a password. */
+		snprintf(file_buf, sizeof(file_buf),
+				 SYSTEMQUOTE "\"%s/pg_genpassword\"" SYSTEMQUOTE, bindir);
+		child = popen(file_buf, "r");
+
+		if (child == NULL
+			|| fgets(password_buf, sizeof(password_buf), child) == NULL
+			|| (len = strlen(password_buf)) < 32
+			|| pclose(child) != 0)
+		{
+			fputs(_("Failed to generate a strong password for the test superuser.  Set the\n"
+					"PGTESTPWFILE environment variable to the absolute path of a file containing a\n"
+					"strong password, which need not and should not match one you use elsewhere.\n"),
+				  stderr);
+			exit(2);
+		}
+
+		/* Write the file for "initdb --pwfile=..." */
+		snprintf(file_buf, sizeof(file_buf),
+				 "%s/superuser_password", temp_install);
+		server_pwfile = strdup(file_buf);
+
+		/* XXX should we worry about configurations that ignore O_EXCL? */
+		fd = open(server_pwfile, O_WRONLY | O_CREAT | O_EXCL,
+				  S_IRUSR | S_IWUSR);
+		if (fd < 0
+			|| write(fd, password_buf, len) != len
+			|| close(fd) != 0)
+		{
+			fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
+					progname, server_pwfile, strerror(errno));
+			exit(2);
+		}
+	}
+
+	/*
+	 * Write the PGPASSFILE.  We don't escape backslashes or colons, so
+	 * user-supplied passwords bearing those characters will not work.
+	 * Hackers can cope with that.
+	 */
+	snprintf(file_buf, sizeof(file_buf), "%s/pgpass", temp_install);
+	doputenv("PGPASSFILE", file_buf);
+
+	len_pgpass = snprintf(pgpass_buf, sizeof(pgpass_buf),
+						  "*:*:*:*:%s", password_buf);
+	Assert(len_pgpass < sizeof(pgpass_buf));
+
+	fd = open(file_buf, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+	if (fd < 0
+		|| write(fd, pgpass_buf, len_pgpass) != len_pgpass
+		|| close(fd) != 0)
+	{
+		fprintf(stderr, _("%s: could not write file \"%s\": %s\n"),
+				progname, file_buf, strerror(errno));
+		exit(2);
+	}
+}
+
+/*
  * Prepare environment variables for running regression tests
  */
 static void
@@ -2152,11 +2262,16 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 			}
 		}
 
+		/* generate a password for the bootstrap superuser */
+		initialize_password();
+
 		/* initdb */
 		header(_("initializing database system"));
 		snprintf(buf, sizeof(buf),
-				 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
-				 bindir, temp_install, datadir,
+				 SYSTEMQUOTE "\"%s/initdb\" -D \"%s/data\" -L \"%s\" "
+				 "--auth=md5 --pwfile=\"%s\" --noclean --nosync%s%s "
+				 "> \"%s/log/initdb.log\" 2>&1" SYSTEMQUOTE,
+				 bindir, temp_install, datadir, server_pwfile,
 				 debug ? " --debug" : "",
 				 nolocale ? " --no-locale" : "",
 				 outputdir);
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 308a4b4..36369e2 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -68,7 +68,8 @@ sub mkvcbuild
 	  chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c
 	  srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
 	  erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
-	  pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
+	  pgcheckdir.c pg_crc.c pgencode.c pgmkdirp.c
+	  pgrand.c pgsleep.c pgstrcasecmp.c pqsignal.c
 	  qsort.c qsort_arg.c quotes.c
 	  sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c
 	  win32env.c win32error.c win32setlocale.c);
@@ -375,6 +376,8 @@ sub mkvcbuild
 	$pgreceivexlog->AddFile('src\bin\pg_basebackup\pg_receivexlog.c');
 	$pgreceivexlog->AddLibrary('ws2_32.lib');
 
+	my $pggenpassword = AddSimpleFrontend('pg_genpassword');
+
 	my $pgconfig = AddSimpleFrontend('pg_config');
 
 	my $pgcontrol = AddSimpleFrontend('pg_controldata');
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index 447b4a1..8a6b9e9 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -7,7 +7,9 @@ use strict;
 our $config;
 
 use Cwd;
+use Fcntl qw(:DEFAULT :mode);
 use File::Copy;
+use IO::File;
 
 use Install qw(Install);
 
@@ -236,6 +238,21 @@ sub contribcheck
 	exit $mstat if $mstat;
 }
 
+# Write the given content to a given file, creating the file as accessible to
+# its owner alone.  Die on any error.
+sub write_sensitive_file
+{
+	my ($file, $content) = @_;
+
+	my $fh =
+	  IO::File->new($file, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)
+	  || die qq{Could not open file "$file" for writing: $!};
+	$fh->print($content)
+	  || die qq{Could not write to file "$file": $!};
+	$fh->close
+	  || die qq{Could not close file "$file": $!};
+}
+
 sub upgradecheck
 {
 	my $status;
@@ -259,12 +276,23 @@ sub upgradecheck
 	my ($bindir, $libdir, $oldsrc, $newsrc) =
 	  ("$tmp_install/bin", "$tmp_install/lib", $topdir, $topdir);
 	$ENV{PATH} = "$bindir;$ENV{PATH}";
+
+	# Generate a password for the bootstrap superuser.  Since pg_genpassword
+	# is expected to work on all supported Windows configurations, don't
+	# bother supporting the PGTESTPWFILE override.
+	my $pwfile = "$tmp_root/superuser_password";
+	$ENV{PGPASSFILE} = "$tmp_root/pgpass";
+	my $password = `pg_genpassword`;
+	die "Failed to generate strong password" if $? || length $password < 32;
+	write_sensitive_file($pwfile, $password);
+	write_sensitive_file($ENV{PGPASSFILE}, "*:*:*:*:$password");
+
 	my $data = "$tmp_root/data";
 	$ENV{PGDATA} = "$data.old";
 	my $logdir = "$topdir/contrib/pg_upgrade/log";
 	(mkdir $logdir || die $!) unless -d $logdir;
 	print "\nRunning initdb on old cluster\n\n";
-	system("initdb") == 0 or exit 1;
+	system('initdb', '--auth=md5', "--pwfile=$pwfile") == 0 or exit 1;
 	print "\nStarting old cluster\n\n";
 	system("pg_ctl start -l $logdir/postmaster1.log -w") == 0 or exit 1;
 	print "\nSetting up data for upgrading\n\n";
@@ -278,7 +306,7 @@ sub upgradecheck
 	system("pg_ctl -m fast stop") == 0 or exit 1;
 	$ENV{PGDATA} = "$data";
 	print "\nSetting up new cluster\n\n";
-	system("initdb") == 0 or exit 1;
+	system('initdb', '--auth=md5', "--pwfile=$pwfile") == 0 or exit 1;
 	print "\nRunning pg_upgrade\n\n";
 	system("pg_upgrade -d $data.old -D $data -b $bindir -B $bindir") == 0
 	  or exit 1;