1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Revert Windows service check refactoring, and replace with a different fix.

This reverts commit 38bdba54a6, "Fix and
simplify check for whether we're running as Windows service". It turns out
that older versions of MinGW - like that on buildfarm member narwhal - do
not support the CheckTokenMembership() function. This replaces the
refactoring with a much smaller fix, to add a check for SE_GROUP_ENABLED to
pgwin32_is_service().

Only apply to back-branches, and keep the refactoring in HEAD. It's
unlikely that anyone is still really using such an old version of MinGW -
aside from narwhal - but let's not change the minimum requirements in
minor releases.

Discussion: https://www.postgresql.org/message-id/16609.1489773427@sss.pgh.pa.us
Patch: https://www.postgresql.org/message-id/CAB7nPqSvfu%3DKpJ%3DNX%2BYAHmgAmQdzA7N5h31BjzXeMgczhGCC%2BQ%40mail.gmail.com
This commit is contained in:
Heikki Linnakangas
2017-03-24 12:39:01 +02:00
parent 5fdc70826f
commit e0e1ef46d8

View File

@ -14,6 +14,10 @@
#include "postgres.h" #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, * Returns nonzero if the current user has administrative privileges,
* or zero if not. * or zero if not.
@ -24,11 +28,33 @@
int int
pgwin32_is_admin(void) pgwin32_is_admin(void)
{ {
HANDLE AccessToken;
char *InfoBuffer = NULL;
char errbuf[256];
PTOKEN_GROUPS Groups;
PSID AdministratorsSid; PSID AdministratorsSid;
PSID PowerUsersSid; PSID PowerUsersSid;
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
BOOL IsAdministrators; UINT x;
BOOL IsPowerUsers; BOOL success;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
{
write_stderr("could not open process token: error code %lu\n",
GetLastError());
exit(1);
}
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
&InfoBuffer, errbuf, sizeof(errbuf)))
{
write_stderr("%s", errbuf);
exit(1);
}
Groups = (PTOKEN_GROUPS) InfoBuffer;
CloseHandle(AccessToken);
if (!AllocateAndInitializeSid(&NtAuthority, 2, if (!AllocateAndInitializeSid(&NtAuthority, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
@ -48,35 +74,32 @@ pgwin32_is_admin(void)
exit(1); exit(1);
} }
if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) || success = FALSE;
!CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
for (x = 0; x < Groups->GroupCount; x++)
{ {
write_stderr("could not check access token membership: error code %lu\n", if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
GetLastError()); (EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
exit(1); {
success = TRUE;
break;
}
} }
free(InfoBuffer);
FreeSid(AdministratorsSid); FreeSid(AdministratorsSid);
FreeSid(PowerUsersSid); FreeSid(PowerUsersSid);
return success;
if (IsAdministrators || IsPowerUsers)
return 1;
else
return 0;
} }
/* /*
* We consider ourselves running as a service if one of the following is * We consider ourselves running as a service if one of the following is
* true: * true:
* *
* 1) We are running as LocalSystem (only used by services) * 1) We are running as Local System (only used by services)
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
* process token by the SCM when starting a service) * process token by the SCM when starting a service)
* *
* The check for LocalSystem is needed, because surprisingly, if a service
* is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
* process token.
*
* Return values: * Return values:
* 0 = Not service * 0 = Not service
* 1 = Service * 1 = Service
@ -90,62 +113,137 @@ int
pgwin32_is_service(void) pgwin32_is_service(void)
{ {
static int _is_service = -1; static int _is_service = -1;
BOOL IsMember; HANDLE AccessToken;
char *InfoBuffer = NULL;
char errbuf[256];
PTOKEN_GROUPS Groups;
PTOKEN_USER User;
PSID ServiceSid; PSID ServiceSid;
PSID LocalSystemSid; PSID LocalSystemSid;
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
UINT x;
/* Only check the first time */ /* Only check the first time */
if (_is_service != -1) if (_is_service != -1)
return _is_service; return _is_service;
/* First check for LocalSystem */ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
{
fprintf(stderr, "could not open process token: error code %lu\n",
GetLastError());
return -1;
}
/* First check for local system */
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
errbuf, sizeof(errbuf)))
{
fprintf(stderr, "%s", errbuf);
return -1;
}
User = (PTOKEN_USER) InfoBuffer;
if (!AllocateAndInitializeSid(&NtAuthority, 1, if (!AllocateAndInitializeSid(&NtAuthority, 1,
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
&LocalSystemSid)) &LocalSystemSid))
{ {
fprintf(stderr, "could not get SID for local system account\n"); fprintf(stderr, "could not get SID for local system account\n");
CloseHandle(AccessToken);
return -1; return -1;
} }
if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember)) if (EqualSid(LocalSystemSid, User->User.Sid))
{ {
fprintf(stderr, "could not check access token membership: error code %lu\n",
GetLastError());
FreeSid(LocalSystemSid); FreeSid(LocalSystemSid);
return -1; free(InfoBuffer);
} CloseHandle(AccessToken);
FreeSid(LocalSystemSid);
if (IsMember)
{
_is_service = 1; _is_service = 1;
return _is_service; return _is_service;
} }
/* Check for service group membership */ FreeSid(LocalSystemSid);
free(InfoBuffer);
/* Now check for group SID */
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
errbuf, sizeof(errbuf)))
{
fprintf(stderr, "%s", errbuf);
return -1;
}
Groups = (PTOKEN_GROUPS) InfoBuffer;
if (!AllocateAndInitializeSid(&NtAuthority, 1, if (!AllocateAndInitializeSid(&NtAuthority, 1,
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0, SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
&ServiceSid)) &ServiceSid))
{ {
fprintf(stderr, "could not get SID for service group: error code %lu\n", fprintf(stderr, "could not get SID for service group\n");
GetLastError()); free(InfoBuffer);
CloseHandle(AccessToken);
return -1; return -1;
} }
if (!CheckTokenMembership(NULL, ServiceSid, &IsMember)) _is_service = 0;
for (x = 0; x < Groups->GroupCount; x++)
{ {
fprintf(stderr, "could not check access token membership: error code %lu\n", if (EqualSid(ServiceSid, Groups->Groups[x].Sid) &&
GetLastError()); (Groups->Groups[x].Attributes & SE_GROUP_ENABLED))
FreeSid(ServiceSid); {
return -1; _is_service = 1;
break;
}
} }
free(InfoBuffer);
FreeSid(ServiceSid); FreeSid(ServiceSid);
if (IsMember) CloseHandle(AccessToken);
_is_service = 1;
else
_is_service = 0;
return _is_service; 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 %lu\n",
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 %lu\n",
GetLastError());
return FALSE;
}
return TRUE;
}