aboutsummaryrefslogtreecommitdiff
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)
downloadpostgresql-fc9c20eb72cb594fb016caef198a9edebe29195f.tar.gz
postgresql-fc9c20eb72cb594fb016caef198a9edebe29195f.zip
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