diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/initdb/initdb.c | 23 | ||||
-rw-r--r-- | src/bin/pg_ctl/pg_ctl.c | 4 | ||||
-rw-r--r-- | src/include/port.h | 8 | ||||
-rw-r--r-- | src/port/exec.c | 219 |
4 files changed, 249 insertions, 5 deletions
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index ce5439a1dd1..831eed319f0 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.125 2006/10/04 18:58:08 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.125.2.1 2008/02/29 15:31:37 mha Exp $ * *------------------------------------------------------------------------- */ @@ -2324,7 +2324,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 ae8e3747e11..9b65a09382c 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-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.74.2.2 2008/02/20 22:18:28 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.74.2.3 2008/02/29 15:31:37 mha Exp $ * *------------------------------------------------------------------------- */ @@ -1424,6 +1424,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 9481c66961c..c9d3e48f0e8 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/port.h,v 1.106.2.2 2007/11/29 16:44:26 mha Exp $ + * $PostgreSQL: pgsql/src/include/port.h,v 1.106.2.3 2008/02/29 15:31:37 mha Exp $ * *------------------------------------------------------------------------- */ @@ -74,6 +74,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 642bd5fdc9e..1fc0dffaa13 100644 --- a/src/port/exec.c +++ b/src/port/exec.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/port/exec.c,v 1.43 2006/09/11 20:10:30 tgl Exp $ + * $PostgreSQL: pgsql/src/port/exec.c,v 1.43.2.1 2008/02/29 15:31:37 mha Exp $ * *------------------------------------------------------------------------- */ @@ -54,6 +54,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 @@ -642,3 +645,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 |