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