summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-02-10 22:05:42 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-02-10 22:05:42 +0000
commitfc9c20eb72cb594fb016caef198a9edebe29195f (patch)
tree490288b2ae6eb2d41fc7d3b8dc9269f97e92b47f /src
parenta25cd81007e827684343a53a80e8bc90f585ca8e (diff)
Make it possible to run initdb from an admin account on Windows,
by giving up admin privileges (only works if newer than NT4). Magnus
Diffstat (limited to 'src')
-rw-r--r--src/bin/initdb/initdb.c139
1 files changed, 138 insertions, 1 deletions
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 9399a531d9b..4a85dfb24d5 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.107 2006/01/27 19:01:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.108 2006/02/10 22:05:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -95,6 +95,9 @@ static char *authmethod = "";
static bool debug = false;
static bool noclean = false;
static bool show_setting = false;
+#ifdef WIN32
+static bool restricted_exec = false;
+#endif
/* internal vars */
@@ -192,6 +195,9 @@ static int locale_date_order(const char *locale);
static bool chklocale(const char *locale);
static void setlocales(void);
static void usage(const char *progname);
+#ifdef WIN32
+static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo);
+#endif
/*
@@ -2239,6 +2245,91 @@ setlocales(void)
}
+#ifdef WIN32
+/* MingW headers are incomplete */
+typedef WINAPI BOOL (*__CreateRestrictedToken)(HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
+#define DISABLE_MAX_PRIVILEGE 0x1
+
+/*
+ * Create a restricted token and execute the specified process with it.
+ *
+ * Returns 0 on failure, non-zero on success, same as CreateProcess().
+ *
+ * On NT4, or any other system not containing the required functions, will
+ * NOT execute anything.
+ */
+static int
+CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo)
+{
+ BOOL b;
+ STARTUPINFO si;
+ HANDLE origToken;
+ HANDLE restrictedToken;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
+ SID_AND_ATTRIBUTES dropSids[2];
+ __CreateRestrictedToken _CreateRestrictedToken = NULL;
+ HANDLE Advapi32Handle;
+
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
+ if (Advapi32Handle != NULL)
+ {
+ _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
+ }
+
+ if (_CreateRestrictedToken == NULL)
+ {
+ fprintf(stderr,"WARNING: Unable to create restricted tokens on this platform\n");
+ if (Advapi32Handle != NULL)
+ FreeLibrary(Advapi32Handle);
+ return 0;
+ }
+
+ /* Open the current token to use as a base for the restricted one */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
+ {
+ fprintf(stderr, "Failed to open process token: %lu\n", GetLastError());
+ return 0;
+ }
+
+ /* Allocate list of SIDs to remove */
+ ZeroMemory(&dropSids, sizeof(dropSids));
+ if (!AllocateAndInitializeSid(&NtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,
+ 0, &dropSids[0].Sid) ||
+ !AllocateAndInitializeSid(&NtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0,0,0,0,0,
+ 0, &dropSids[1].Sid))
+ {
+ fprintf(stderr,"Failed to allocate SIDs: %lu\n", GetLastError());
+ return 0;
+ }
+
+ b = _CreateRestrictedToken(origToken,
+ DISABLE_MAX_PRIVILEGE,
+ sizeof(dropSids)/sizeof(dropSids[0]),
+ dropSids,
+ 0, NULL,
+ 0, NULL,
+ &restrictedToken);
+
+ FreeSid(dropSids[1].Sid);
+ FreeSid(dropSids[0].Sid);
+ CloseHandle(origToken);
+ FreeLibrary(Advapi32Handle);
+
+ if (!b)
+ {
+ fprintf(stderr,"Failed to create restricted token: %lu\n", GetLastError());
+ return 0;
+ }
+
+ return CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, processInfo);
+}
+#endif
+
/*
* print help text
*/
@@ -2295,6 +2386,9 @@ main(int argc, char *argv[])
{"auth", required_argument, NULL, 'A'},
{"pwprompt", no_argument, NULL, 'W'},
{"pwfile", required_argument, NULL, 9},
+#ifdef WIN32
+ {"restrictedexec", no_argument, NULL, 10},
+#endif
{"username", required_argument, NULL, 'U'},
{"help", no_argument, NULL, '?'},
{"version", no_argument, NULL, 'V'},
@@ -2403,6 +2497,11 @@ main(int argc, char *argv[])
case 9:
pwfilename = xstrdup(optarg);
break;
+#ifdef WIN32
+ case 10:
+ restricted_exec = true;
+ break;
+#endif
case 's':
show_setting = true;
break;
@@ -2497,6 +2596,44 @@ main(int argc, char *argv[])
pg_data_native = pg_data;
canonicalize_path(pg_data);
+#ifdef WIN32
+ /*
+ * Before we execute another program, make sure that we are running with a
+ * restricted token. If not, re-execute ourselves with one.
+ */
+ if (!restricted_exec)
+ {
+ PROCESS_INFORMATION pi;
+ char *cmdline;
+
+ ZeroMemory(&pi, sizeof(pi));
+
+ cmdline = pg_malloc(strlen(GetCommandLine()) + 19);
+ strcpy(cmdline, GetCommandLine());
+ strcat(cmdline, " --restrictedexec");
+
+ if (!CreateRestrictedProcess(cmdline, &pi))
+ {
+ fprintf(stderr,"Failed to re-exec with restricted token: %lu.\n", 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))
+ {
+ fprintf(stderr,"Failed to get exit code from subprocess: %lu\n", GetLastError());
+ exit(1);
+ }
+ exit(x);
+ }
+ }
+#endif
+
/*
* we have to set PGDATA for postgres rather than pass it on the command
* line to avoid dumb quoting problems on Windows, and we would especially