diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index f3eb38b2dc42083e97fdab3170e3609d9dd60246..41db8a8b02964628ddce3dbd7d7c9ac8e8b72bcb 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * Portions taken from FreeBSD.
  *
- * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.153 2008/02/20 22:46:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.154 2008/02/29 15:31:33 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2329,7 +2329,26 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION * processInfo)
 		return 0;
 	}
 
-	return CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, processInfo);
+	if (!CreateProcessAsUser(restrictedToken,
+						NULL,
+						cmd,
+						NULL,
+						NULL,
+						TRUE,
+						CREATE_SUSPENDED,
+						NULL,
+						NULL,
+						&si,
+						processInfo))
+
+	{
+		fprintf(stderr, "CreateProcessAsUser failed: %lu\n", GetLastError());
+		return 0;
+	}
+
+	AddUserToDacl(processInfo->hProcess);
+
+	return ResumeThread(processInfo->hThread);
 }
 #endif
 
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index bd969169298a4c2826c82230ac6e08f886ee2fca..9e0e16ca6b1b04a7421b515faf095c5b981db98c 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -4,7 +4,7 @@
  *
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.94 2008/02/20 22:46:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.95 2008/02/29 15:31:33 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1469,6 +1469,8 @@ CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION * processInfo)
 		}
 	}
 
+    AddUserToDacl(processInfo->hProcess);
+    
 	CloseHandle(restrictedToken);
 
 	ResumeThread(processInfo->hThread);
diff --git a/src/include/port.h b/src/include/port.h
index f2907f4b348330db0b95121a701559f217f6518a..38c6c5f68691a1d91a99fd35f4ebd1b6c9ac0870 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/port.h,v 1.117 2008/02/18 14:51:48 petere Exp $
+ * $PostgreSQL: pgsql/src/include/port.h,v 1.118 2008/02/29 15:31:33 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,6 +79,12 @@ extern int	find_my_exec(const char *argv0, char *retpath);
 extern int find_other_exec(const char *argv0, const char *target,
 				const char *versionstr, char *retpath);
 
+/* Windows security token manipulation (in exec.c) */
+#ifdef WIN32
+extern BOOL AddUserToDacl(HANDLE hProcess);
+#endif
+
+
 #if defined(WIN32) || defined(__CYGWIN__)
 #define EXE ".exe"
 #else
diff --git a/src/port/exec.c b/src/port/exec.c
index 38a725a28af41ca94fe5669e07e2081dda4b995a..e9a60d67fcc6efde7b34d6e5dbee41f771c94fe8 100644
--- a/src/port/exec.c
+++ b/src/port/exec.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/port/exec.c,v 1.57 2008/01/01 19:46:00 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/port/exec.c,v 1.58 2008/02/29 15:31:33 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,6 +55,9 @@ static int	validate_exec(const char *path);
 static int	resolve_symlinks(char *path);
 static char *pipe_read_line(char *cmd, char *line, int maxsize);
 
+#ifdef WIN32
+static BOOL GetUserSid(PSID * ppSidUser, HANDLE hToken);
+#endif
 
 /*
  * validate_exec -- validate "path" as an executable file
@@ -657,3 +660,217 @@ set_pglocale_pgservice(const char *argv0, const char *app)
 		putenv(strdup(env_path));
 	}
 }
+
+#ifdef WIN32
+
+/*
+ * AddUserToDacl(HANDLE hProcess)
+ *
+ * This function adds the current user account to the default DACL
+ * which gets attached to the restricted token used when we create
+ * a restricted process.
+ *
+ * This is required because of some security changes in Windows
+ * that appeared in patches to XP/2K3 and in Vista/2008.
+ *
+ * On these machines, the Administrator account is not included in
+ * the default DACL - you just get Administrators + System. For
+ * regular users you get User + System. Because we strip Administrators
+ * when we create the restricted token, we are left with only System
+ * in the DACL which leads to access denied errors for later CreatePipe()
+ * and CreateProcess() calls when running as Administrator.
+ *
+ * This function fixes this problem by modifying the DACL of the
+ * specified process and explicitly re-adding the current user account.
+ * This is still secure because the Administrator account inherits it's
+ * privileges from the Administrators group - it doesn't have any of
+ * it's own.
+ */
+BOOL
+AddUserToDacl(HANDLE hProcess)
+{
+	int			i;
+	ACL_SIZE_INFORMATION asi;
+	ACCESS_ALLOWED_ACE *pace;
+	DWORD		dwNewAclSize;
+	DWORD		dwSize = 0;
+	DWORD		dwTokenInfoLength = 0;
+	DWORD		dwResult = 0;
+	HANDLE		hToken = NULL;
+	PACL		pacl = NULL;
+	PSID		psidUser = NULL;
+	TOKEN_DEFAULT_DACL tddNew;
+	TOKEN_DEFAULT_DACL *ptdd = NULL;
+	TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl;
+	BOOL		ret = FALSE;
+
+	/* Get the token for the process */
+	if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hToken))
+	{
+		log_error("could not open process token: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	/* Figure out the buffer size for the DACL info */
+	if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize))
+	{
+		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+		{
+			ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
+			if (ptdd == NULL)
+			{
+				log_error("could not allocate %i bytes of memory", dwSize);
+				goto cleanup;
+			}
+
+			if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize))
+			{
+				log_error("could not get token information: %ui", GetLastError());
+				goto cleanup;
+			}
+		}
+		else
+		{
+			log_error("could not get token information buffer size: %ui", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Get the ACL info */
+	if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) & asi,
+						   (DWORD) sizeof(ACL_SIZE_INFORMATION),
+						   AclSizeInformation))
+	{
+		log_error("could not get ACL information: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	/* Get the SID for the current user. We need to add this to the ACL. */
+	if (!GetUserSid(&psidUser, hToken))
+	{
+		log_error("could not get user SID: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	/* Figure out the size of the new ACL */
+	dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidUser) - sizeof(DWORD);
+
+	/* Allocate the ACL buffer & initialize it */
+	pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
+	if (pacl == NULL)
+	{
+		log_error("could not allocate %i bytes of memory", dwNewAclSize);
+		goto cleanup;
+	}
+
+	if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
+	{
+		log_error("could not initialize ACL: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	/* Loop through the existing ACEs, and build the new ACL */
+	for (i = 0; i < (int) asi.AceCount; i++)
+	{
+		if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) & pace))
+		{
+			log_error("could not get ACE: %ui", GetLastError());
+			goto cleanup;
+		}
+
+		if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize))
+		{
+			log_error("could not add ACE: %ui", GetLastError());
+			goto cleanup;
+		}
+	}
+
+	/* Add the new ACE for the current user */
+	if (!AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psidUser))
+	{
+		log_error("could not add access allowed ACE: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	/* Set the new DACL in the token */
+	tddNew.DefaultDacl = pacl;
+
+	if (!SetTokenInformation(hToken, tic, (LPVOID) & tddNew, dwNewAclSize))
+	{
+		log_error("could not set token information: %ui", GetLastError());
+		goto cleanup;
+	}
+
+	ret = TRUE;
+
+cleanup:
+	if (psidUser)
+		FreeSid(psidUser);
+
+	if (pacl)
+		LocalFree((HLOCAL) pacl);
+
+	if (ptdd)
+		LocalFree((HLOCAL) ptdd);
+
+	if (hToken)
+		CloseHandle(hToken);
+
+	return ret;
+}
+
+/*
+ * GetUserSid*PSID *ppSidUser, HANDLE hToken)
+ *
+ * Get the SID for the current user
+ */
+static BOOL
+GetUserSid(PSID * ppSidUser, HANDLE hToken)
+{
+	DWORD		dwLength;
+	DWORD		cbName = 250;
+	DWORD		cbDomainName = 250;
+	PTOKEN_USER pTokenUser = NULL;
+
+
+	if (!GetTokenInformation(hToken,
+							 TokenUser,
+							 pTokenUser,
+							 0,
+							 &dwLength))
+	{
+		if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+		{
+			pTokenUser = (PTOKEN_USER) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
+
+			if (pTokenUser == NULL)
+			{
+				log_error("could not allocate %ui bytes of memory", dwLength);
+				return FALSE;
+			}
+		}
+		else
+		{
+			log_error("could not get token information buffer size: %ui", GetLastError());
+			return FALSE;
+		}
+	}
+
+	if (!GetTokenInformation(hToken,
+							 TokenUser,
+							 pTokenUser,
+							 dwLength,
+							 &dwLength))
+	{
+		HeapFree(GetProcessHeap(), 0, pTokenUser);
+		pTokenUser = NULL;
+
+		log_error("could not get token information: %ui", GetLastError());
+		return FALSE;
+	}
+
+	*ppSidUser = pTokenUser->User.Sid;
+	return TRUE;
+}
+
+#endif