Skip to content

Commit 96fd76d

Browse files
committed
Fix and simplify check for whether we're running as Windows service.
If the process token contains SECURITY_SERVICE_RID, but it has been disabled by the SE_GROUP_USE_FOR_DENY_ONLY attribute, win32_is_service() would incorrectly report that we're running as a service. That situation arises, e.g. if postmaster is launched with a restricted security token, with the "Log in as Service" privilege explicitly removed. Replace the broken code with CheckProcessTokenMembership(), which does this correctly. Also replace similar code in win32_is_admin(), even though it got this right, for simplicity and consistency. Per bug #13755, reported by Breen Hagan. Back-patch to all supported versions. Patch by Takayuki Tsunakawa, reviewed by Michael Paquier. Discussion: https://www.postgresql.org/message-id/20151104062315.2745.67143%40wrigleys.postgresql.org
1 parent ee78ad5 commit 96fd76d

File tree

1 file changed

+38
-135
lines changed

1 file changed

+38
-135
lines changed

src/backend/port/win32/security.c

Lines changed: 38 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@
1414
#include "postgres.h"
1515

1616

17-
static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
18-
TOKEN_INFORMATION_CLASS class, char **InfoBuffer,
19-
char *errbuf, int errsize);
20-
2117
/*
2218
* Returns nonzero if the current user has administrative privileges,
2319
* or zero if not.
@@ -28,33 +24,11 @@ static BOOL pgwin32_get_dynamic_tokeninfo(HANDLE token,
2824
int
2925
pgwin32_is_admin(void)
3026
{
31-
HANDLE AccessToken;
32-
char *InfoBuffer = NULL;
33-
char errbuf[256];
34-
PTOKEN_GROUPS Groups;
3527
PSID AdministratorsSid;
3628
PSID PowerUsersSid;
3729
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
38-
UINT x;
39-
BOOL success;
40-
41-
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
42-
{
43-
write_stderr("could not open process token: error code %lu\n",
44-
GetLastError());
45-
exit(1);
46-
}
47-
48-
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups,
49-
&InfoBuffer, errbuf, sizeof(errbuf)))
50-
{
51-
write_stderr("%s", errbuf);
52-
exit(1);
53-
}
54-
55-
Groups = (PTOKEN_GROUPS) InfoBuffer;
56-
57-
CloseHandle(AccessToken);
30+
BOOL IsAdministrators;
31+
BOOL IsPowerUsers;
5832

5933
if (!AllocateAndInitializeSid(&NtAuthority, 2,
6034
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
@@ -74,32 +48,35 @@ pgwin32_is_admin(void)
7448
exit(1);
7549
}
7650

77-
success = FALSE;
78-
79-
for (x = 0; x < Groups->GroupCount; x++)
51+
if (!CheckTokenMembership(NULL, AdministratorsSid, &IsAdministrators) ||
52+
!CheckTokenMembership(NULL, PowerUsersSid, &IsPowerUsers))
8053
{
81-
if ((EqualSid(AdministratorsSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)) ||
82-
(EqualSid(PowerUsersSid, Groups->Groups[x].Sid) && (Groups->Groups[x].Attributes & SE_GROUP_ENABLED)))
83-
{
84-
success = TRUE;
85-
break;
86-
}
54+
write_stderr("could not check access token membership: error code %lu\n",
55+
GetLastError());
56+
exit(1);
8757
}
8858

89-
free(InfoBuffer);
9059
FreeSid(AdministratorsSid);
9160
FreeSid(PowerUsersSid);
92-
return success;
61+
62+
if (IsAdministrators || IsPowerUsers)
63+
return 1;
64+
else
65+
return 0;
9366
}
9467

9568
/*
9669
* We consider ourselves running as a service if one of the following is
9770
* true:
9871
*
99-
* 1) We are running as Local System (only used by services)
72+
* 1) We are running as LocalSystem (only used by services)
10073
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
10174
* process token by the SCM when starting a service)
10275
*
76+
* The check for LocalSystem is needed, because surprisingly, if a service
77+
* is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
78+
* process token.
79+
*
10380
* Return values:
10481
* 0 = Not service
10582
* 1 = Service
@@ -113,136 +90,62 @@ int
11390
pgwin32_is_service(void)
11491
{
11592
static int _is_service = -1;
116-
HANDLE AccessToken;
117-
char *InfoBuffer = NULL;
118-
char errbuf[256];
119-
PTOKEN_GROUPS Groups;
120-
PTOKEN_USER User;
93+
BOOL IsMember;
12194
PSID ServiceSid;
12295
PSID LocalSystemSid;
12396
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
124-
UINT x;
12597

12698
/* Only check the first time */
12799
if (_is_service != -1)
128100
return _is_service;
129101

130-
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &AccessToken))
131-
{
132-
fprintf(stderr, "could not open process token: error code %lu\n",
133-
GetLastError());
134-
return -1;
135-
}
136-
137-
/* First check for local system */
138-
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenUser, &InfoBuffer,
139-
errbuf, sizeof(errbuf)))
140-
{
141-
fprintf(stderr, "%s", errbuf);
142-
return -1;
143-
}
144-
145-
User = (PTOKEN_USER) InfoBuffer;
146-
102+
/* First check for LocalSystem */
147103
if (!AllocateAndInitializeSid(&NtAuthority, 1,
148104
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0,
149105
&LocalSystemSid))
150106
{
151107
fprintf(stderr, "could not get SID for local system account\n");
152-
CloseHandle(AccessToken);
153108
return -1;
154109
}
155110

156-
if (EqualSid(LocalSystemSid, User->User.Sid))
111+
if (!CheckTokenMembership(NULL, LocalSystemSid, &IsMember))
157112
{
113+
fprintf(stderr, "could not check access token membership: error code %lu\n",
114+
GetLastError());
158115
FreeSid(LocalSystemSid);
159-
free(InfoBuffer);
160-
CloseHandle(AccessToken);
161-
_is_service = 1;
162-
return _is_service;
116+
return -1;
163117
}
164-
165118
FreeSid(LocalSystemSid);
166-
free(InfoBuffer);
167119

168-
/* Now check for group SID */
169-
if (!pgwin32_get_dynamic_tokeninfo(AccessToken, TokenGroups, &InfoBuffer,
170-
errbuf, sizeof(errbuf)))
120+
if (IsMember)
171121
{
172-
fprintf(stderr, "%s", errbuf);
173-
return -1;
122+
_is_service = 1;
123+
return _is_service;
174124
}
175125

176-
Groups = (PTOKEN_GROUPS) InfoBuffer;
177-
126+
/* Check for service group membership */
178127
if (!AllocateAndInitializeSid(&NtAuthority, 1,
179128
SECURITY_SERVICE_RID, 0, 0, 0, 0, 0, 0, 0,
180129
&ServiceSid))
181130
{
182-
fprintf(stderr, "could not get SID for service group\n");
183-
free(InfoBuffer);
184-
CloseHandle(AccessToken);
131+
fprintf(stderr, "could not get SID for service group: error code %lu\n",
132+
GetLastError());
185133
return -1;
186134
}
187135

188-
_is_service = 0;
189-
for (x = 0; x < Groups->GroupCount; x++)
136+
if (!CheckTokenMembership(NULL, ServiceSid, &IsMember))
190137
{
191-
if (EqualSid(ServiceSid, Groups->Groups[x].Sid))
192-
{
193-
_is_service = 1;
194-
break;
195-
}
138+
fprintf(stderr, "could not check access token membership: error code %lu\n",
139+
GetLastError());
140+
FreeSid(ServiceSid);
141+
return -1;
196142
}
197-
198-
free(InfoBuffer);
199143
FreeSid(ServiceSid);
200144

201-
CloseHandle(AccessToken);
145+
if (IsMember)
146+
_is_service = 1;
147+
else
148+
_is_service = 0;
202149

203150
return _is_service;
204151
}
205-
206-
207-
/*
208-
* Call GetTokenInformation() on a token and return a dynamically sized
209-
* buffer with the information in it. This buffer must be free():d by
210-
* the calling function!
211-
*/
212-
static BOOL
213-
pgwin32_get_dynamic_tokeninfo(HANDLE token, TOKEN_INFORMATION_CLASS class,
214-
char **InfoBuffer, char *errbuf, int errsize)
215-
{
216-
DWORD InfoBufferSize;
217-
218-
if (GetTokenInformation(token, class, NULL, 0, &InfoBufferSize))
219-
{
220-
snprintf(errbuf, errsize, "could not get token information: got zero size\n");
221-
return FALSE;
222-
}
223-
224-
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
225-
{
226-
snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
227-
GetLastError());
228-
return FALSE;
229-
}
230-
231-
*InfoBuffer = malloc(InfoBufferSize);
232-
if (*InfoBuffer == NULL)
233-
{
234-
snprintf(errbuf, errsize, "could not allocate %d bytes for token information\n",
235-
(int) InfoBufferSize);
236-
return FALSE;
237-
}
238-
239-
if (!GetTokenInformation(token, class, *InfoBuffer,
240-
InfoBufferSize, &InfoBufferSize))
241-
{
242-
snprintf(errbuf, errsize, "could not get token information: error code %lu\n",
243-
GetLastError());
244-
return FALSE;
245-
}
246-
247-
return TRUE;
248-
}

0 commit comments

Comments
 (0)