Index: src/bin/initdb/initdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/initdb/initdb.c,v
retrieving revision 1.153
diff -c -r1.153 initdb.c
*** src/bin/initdb/initdb.c	20 Feb 2008 22:46:24 -0000	1.153
--- src/bin/initdb/initdb.c	21 Feb 2008 13:44:07 -0000
***************
*** 2329,2335 ****
  		return 0;
  	}
  
! 	return CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, processInfo);
  }
  #endif
  
--- 2329,2354 ----
  		return 0;
  	}
  
! 	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
  
Index: src/bin/pg_ctl/pg_ctl.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_ctl/pg_ctl.c,v
retrieving revision 1.94
diff -c -r1.94 pg_ctl.c
*** src/bin/pg_ctl/pg_ctl.c	20 Feb 2008 22:46:24 -0000	1.94
--- src/bin/pg_ctl/pg_ctl.c	21 Feb 2008 13:13:05 -0000
***************
*** 1469,1474 ****
--- 1469,1476 ----
  		}
  	}
  
+     AddUserToDacl(processInfo->hProcess);
+     
  	CloseHandle(restrictedToken);
  
  	ResumeThread(processInfo->hThread);
Index: src/include/port.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/port.h,v
retrieving revision 1.117
diff -c -r1.117 port.h
*** src/include/port.h	18 Feb 2008 14:51:48 -0000	1.117
--- src/include/port.h	21 Feb 2008 13:43:37 -0000
***************
*** 79,84 ****
--- 79,90 ----
  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
Index: src/port/exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/port/exec.c,v
retrieving revision 1.57
diff -c -r1.57 exec.c
*** src/port/exec.c	1 Jan 2008 19:46:00 -0000	1.57
--- src/port/exec.c	21 Feb 2008 13:44:07 -0000
***************
*** 55,60 ****
--- 55,64 ----
  static int	resolve_symlinks(char *path);
  static char *pipe_read_line(char *cmd, char *line, int maxsize);
  
+ #ifdef WIN32
+ static void AddUserToDaclCleanup(PSID psidUser, PACL pacl, TOKEN_DEFAULT_DACL *ptdd, HANDLE hToken);
+ static BOOL GetUserSid(PSID *ppSidUser, HANDLE hToken);
+ #endif
  
  /*
   * validate_exec -- validate "path" as an executable file
***************
*** 657,659 ****
--- 661,877 ----
  		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 on Windows machines running some of Microsoft's 
+  * latest security patches on XP/2K3, and on Vista/Longhorn boxes.
+  * 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;
+ 
+     /* Get the token for the process. */
+     if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hToken))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     /* 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)
+ 				{
+ 					AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 					return FALSE;
+ 				}
+ 
+             if (!GetTokenInformation(hToken, tic, (LPVOID)ptdd, dwSize, &dwSize))
+ 			{
+ 				AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 				return FALSE;
+ 			}	
+         }
+         else
+ 		{
+ 			AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 			return FALSE;
+ 		}
+     }
+ 
+     /* Get the ACL info */
+     if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID)&asi, 
+    						   (DWORD)sizeof(ACL_SIZE_INFORMATION),
+                            AclSizeInformation))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     /* Get the SID for the current user. We need to add this to the ACL. */
+     if (!GetUserSid(&psidUser, hToken))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     /* figure out the size of the new ACL */
+     dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psidUser) - sizeof(DWORD);
+ 
+     /* Allocate the ACL buffer & initialise it */
+     pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
+     if (pacl == NULL)
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     /* 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))
+ 		{
+ 			AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 			return FALSE;
+ 		}
+ 
+         if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER)pace)->AceSize))
+ 		{
+ 			AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 			return FALSE;
+ 		}
+     }
+ 
+     /* Add the new ACE for the current user */
+     if (!AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psidUser))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     /* Set the new DACL in the token */
+     tddNew.DefaultDacl = pacl;
+ 
+     if (!SetTokenInformation(hToken, tic, (LPVOID)&tddNew, dwNewAclSize))
+ 	{
+ 		AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 		return FALSE;
+ 	}
+ 
+     AddUserToDaclCleanup(psidUser, pacl, ptdd, hToken);
+ 
+     return TRUE;
+ }
+ 
+ /*
+  * AddUserToDaclCleanup()
+  *
+  * Helper function for AddUserToDacl() - cleans up resources
+  */
+ static void
+ AddUserToDaclCleanup(PSID psidUser, PACL pacl, TOKEN_DEFAULT_DACL *ptdd, HANDLE hToken)
+ {
+     /* Cleanup */
+     if (psidUser)
+         FreeSid(psidUser);
+ 
+     if (pacl)
+         LocalFree((HLOCAL)pacl);
+ 
+     if (ptdd)
+         LocalFree((HLOCAL)ptdd);
+ 
+     if (hToken)
+         CloseHandle(hToken);
+ }
+ 
+ /*
+  * 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)
+                 return FALSE;
+         }
+         else
+             return FALSE;
+     }
+ 
+     if( !GetTokenInformation(hToken,
+                              TokenUser,
+                              pTokenUser,
+                              dwLength,
+                              &dwLength))
+     {
+         HeapFree( GetProcessHeap(), 0, pTokenUser );
+         pTokenUser = NULL;
+ 
+         return FALSE;
+     }
+ 
+     *ppSidUser = pTokenUser->User.Sid;
+     return TRUE;
+ }
+ 
+ #endif
\ No newline at end of file
