| /*------------------------------------------------------------------------- |
| * |
| * security.c |
| * Microsoft Windows Win32 Security Support Functions |
| * |
| * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group |
| * |
| * IDENTIFICATION |
| * $PostgreSQL: pgsql/src/backend/port/win32/security.c,v 1.14 2009/01/01 17:23:46 momjian Exp $ |
| * |
| *------------------------------------------------------------------------- |
| */ |
| |
| #include "postgres.h" |
| |
| |
| static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token, |
| TOKEN_INFORMATION_CLASS class, char **InfoBuffer, |
| char *errbuf, int errsize); |
| |
| /* |
| * Returns nonzero if the current user has administrative privileges, |
| * or zero if not. |
| * |
| * Note: this cannot use ereport() because it's called too early during |
| * startup. |
| */ |
| 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 %d\n", |
| (int) GetLastError()); |
| exit(1); |
| } |
| |
| if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, |
| &InfoBuffer, errbuf, sizeof(errbuf))) |
| { |
| write_stderr(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 %d\n", |
| (int) 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 %d\n", |
| (int) 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; |
| } |
| |
| /* |
| * We consider ourselves running as a service if one of the following is |
| * true: |
| * |
| * 1) We are running as Local System (only used by services) |
| * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the |
| * process token by the SCM when starting a service) |
| * |
| * Return values: |
| * 0 = Not service |
| * 1 = Service |
| * -1 = Error |
| * |
| * Note: we can't report errors via either ereport (we're called too early) |
| * or write_stderr (because that calls this). We are therefore reduced to |
| * writing directly on stderr, which sucks, but we have few alternatives. |
| */ |
| int |
| pgwin32_is_service(void) |
| { |
| static int _is_service = -1; |
| HANDLE AccessToken; |
| char *InfoBuffer = NULL; |
| char errbuf[256]; |
| PTOKEN_GROUPS Groups; |
| PTOKEN_USER User; |
| PSID ServiceSid; |
| PSID LocalSystemSid; |
| SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; |
| UINT x; |
| |
| /* Only check the first time */ |
| if (_is_service != -1) |
| return _is_service; |
| |
| if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken)) |
| { |
| fprintf(stderr, "could not open process token: error code %d\n", |
| (int) GetLastError()); |
| return -1; |
| } |
| |
| /* First check for local system */ |
| if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer, |
| errbuf, sizeof(errbuf))) |
| { |
| fprintf(stderr, errbuf); |
| return -1; |
| } |
| |
| User = (PTOKEN_USER) InfoBuffer; |
| |
| if (!AllocateAndInitializeSid(&NtAuthority, 1, |
| SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, |
| &LocalSystemSid)) |
| { |
| fprintf(stderr, "could not get SID for local system account\n"); |
| CloseHandle(AccessToken); |
| return -1; |
| } |
| |
| if (EqualSid(LocalSystemSid, User->User.Sid)) |
| { |
| FreeSid(LocalSystemSid); |
| free(InfoBuffer); |
| CloseHandle(AccessToken); |
| _is_service = 1; |
| return _is_service; |
| } |
| |
| FreeSid(LocalSystemSid); |
| free(InfoBuffer); |
| |
| /* Now check for group SID */ |
| if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer, |
| errbuf, sizeof(errbuf))) |
| { |
| fprintf(stderr, errbuf); |
| return -1; |
| } |
| |
| Groups = (PTOKEN_GROUPS) InfoBuffer; |
| |
| if (!AllocateAndInitializeSid(&NtAuthority, 1, |
| SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, |
| &ServiceSid)) |
| { |
| fprintf(stderr, "could not get SID for service group\n"); |
| free(InfoBuffer); |
| CloseHandle(AccessToken); |
| return -1; |
| } |
| |
| _is_service = 0; |
| for (x = 0; x < Groups->GroupCount; x++) |
| { |
| if (EqualSid(ServiceSid, Groups->Groups[x].Sid)) |
| { |
| _is_service = 1; |
| break; |
| } |
| } |
| |
| free(InfoBuffer); |
| FreeSid(ServiceSid); |
| |
| CloseHandle(AccessToken); |
| |
| return _is_service; |
| } |
| |
| |
| /* |
| * 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 %d\n", |
| (int) 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 %d\n", |
| (int) GetLastError()); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |