defect_pg_ctl_admin_win32.patch

text/plain

Filename: defect_pg_ctl_admin_win32.patch
Type: text/plain
Part: 0
Message: Re: 9.2RC1 wraps this Thursday ...

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
File+
src/bin/pg_ctl/pg_ctl.c 156 0
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index af8d8b2..ff5d373 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -258,6 +258,121 @@ xstrdup(const char *s)
 }
 
 /*
+ * Call GetTokenInformation() on a token and return a dynamically sized
+ * buffer with the information in it. This buffer must be free():d by
+ * the calling function!
+ */
+static BOOL
+pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
+							  char **InfoBuffer, char *errbuf, int errsize)
+{
+	DWORD		InfoBufferSize;
+
+	if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
+	{
+		snprintf(errbuf, errsize, "could not get token information: got zero size\n");
+		return FALSE;
+	}
+
+	if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+	{
+		snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
+				 GetLastError());
+		return FALSE;
+	}
+
+	*InfoBuffer = malloc(InfoBufferSize);
+	if (*InfoBuffer == NULL)
+	{
+		snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
+				 (int) InfoBufferSize);
+		return FALSE;
+	}
+
+	if (!GetTokenInformation(token, class, *InfoBuffer,
+							 InfoBufferSize, &InfoBufferSize))
+	{
+		snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
+				 GetLastError());
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+/*
+ * Returns nonzero if the current user has administrative privileges,
+ * or zero if not.
+ */
+static int
+pgwin32_is_admin(void)
+{
+	HANDLE		AccessToken;
+	char	   *InfoBuffer = NULL;
+	char		errbuf[256];
+	PTOKEN_GROUPS Groups;
+	PSID		AdministratorsSid;
+	PSID		PowerUsersSid;
+	SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+	UINT		x;
+	BOOL		success;
+
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
+	{
+		write_stderr("could not open process token: error code %lu\n",
+					 GetLastError());
+		exit(1);
+	}
+
+	if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
+									   &InfoBuffer, errbuf, sizeof(errbuf)))
+	{
+		write_stderr("%s", errbuf);
+		exit(1);
+	}
+
+	Groups = (PTOKEN_GROUPS) InfoBuffer;
+
+	CloseHandle(AccessToken);
+
+	if (!AllocateAndInitializeSid(&NtAuthority, 2,
+		 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
+								  0, &AdministratorsSid))
+	{
+		write_stderr("could not get SID for Administrators group: error code %lu\n",
+					 GetLastError());
+		exit(1);
+	}
+
+	if (!AllocateAndInitializeSid(&NtAuthority, 2,
+	SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
+								  0, &PowerUsersSid))
+	{
+		write_stderr("could not get SID for PowerUsers group: error code %lu\n",
+					 GetLastError());
+		exit(1);
+	}
+
+	success = FALSE;
+
+	for (x = 0; x < Groups->GroupCount; x++)
+	{
+		if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
+			(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
+		{
+			success = TRUE;
+			break;
+		}
+	}
+
+	free(InfoBuffer);
+	FreeSid(AdministratorsSid);
+	FreeSid(PowerUsersSid);
+	return success;
+}
+
+/*
  * Given an already-localized string, print it to stdout unless the
  * user has specified that no messages should be printed.
  */
@@ -2015,6 +2130,47 @@ main(int argc, char **argv)
 					 progname);
 		exit(1);
 	}
+#else
+
+	/*
+	 * Before we execute another program, make sure that we are running with a
+	 * restricted token. If not, re-execute ourselves with one.
+	 */
+	if (pgwin32_is_admin())
+	{
+		PROCESS_INFORMATION pi;
+		char	   *cmdline;
+
+		ZeroMemory(&pi, sizeof(pi));
+
+		cmdline = xstrdup(GetCommandLine());
+
+		putenv("PG_RESTRICT_EXEC=1");
+
+		if (!CreateRestrictedProcess(cmdline, &pi, false))
+		{
+			write_stderr(_("%s: could not re-execute with restricted token: error code %lu\n"), progname, GetLastError());
+		}
+		else
+		{
+			/*
+			 * Successfully re-execed. Now wait for child process to capture
+			 * exitcode.
+			 */
+			DWORD		x;
+
+			CloseHandle(pi.hThread);
+			WaitForSingleObject(pi.hProcess, INFINITE);
+
+			if (!GetExitCodeProcess(pi.hProcess, &x))
+			{
+				write_stderr(_("%s: could not get exit code from subprocess: error code %lu\n"), progname, GetLastError());
+				exit(1);
+			}
+
+			exit(x);
+		}
+	}
 #endif
 
 	/*