14
14
#include "postgres.h"
15
15
16
16
17
+ static BOOL pgwin32_get_dynamic_tokeninfo (HANDLE token ,
18
+ TOKEN_INFORMATION_CLASS class , char * * InfoBuffer ,
19
+ char * errbuf , int errsize );
20
+
17
21
/*
18
22
* Returns nonzero if the current user has administrative privileges,
19
23
* or zero if not.
24
28
int
25
29
pgwin32_is_admin (void )
26
30
{
31
+ HANDLE AccessToken ;
32
+ char * InfoBuffer = NULL ;
33
+ char errbuf [256 ];
34
+ PTOKEN_GROUPS Groups ;
27
35
PSID AdministratorsSid ;
28
36
PSID PowerUsersSid ;
29
37
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
30
- BOOL IsAdministrators ;
31
- BOOL IsPowerUsers ;
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 );
32
58
33
59
if (!AllocateAndInitializeSid (& NtAuthority , 2 ,
34
60
SECURITY_BUILTIN_DOMAIN_RID , DOMAIN_ALIAS_RID_ADMINS , 0 , 0 , 0 , 0 , 0 ,
@@ -48,35 +74,32 @@ pgwin32_is_admin(void)
48
74
exit (1 );
49
75
}
50
76
51
- if (!CheckTokenMembership (NULL , AdministratorsSid , & IsAdministrators ) ||
52
- !CheckTokenMembership (NULL , PowerUsersSid , & IsPowerUsers ))
77
+ success = FALSE;
78
+
79
+ for (x = 0 ; x < Groups -> GroupCount ; x ++ )
53
80
{
54
- write_stderr ("could not check access token membership: error code %lu\n" ,
55
- GetLastError ());
56
- exit (1 );
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
+ }
57
87
}
58
88
89
+ free (InfoBuffer );
59
90
FreeSid (AdministratorsSid );
60
91
FreeSid (PowerUsersSid );
61
-
62
- if (IsAdministrators || IsPowerUsers )
63
- return 1 ;
64
- else
65
- return 0 ;
92
+ return success ;
66
93
}
67
94
68
95
/*
69
96
* We consider ourselves running as a service if one of the following is
70
97
* true:
71
98
*
72
- * 1) We are running as LocalSystem (only used by services)
99
+ * 1) We are running as Local System (only used by services)
73
100
* 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
74
101
* process token by the SCM when starting a service)
75
102
*
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
- *
80
103
* Return values:
81
104
* 0 = Not service
82
105
* 1 = Service
@@ -90,62 +113,137 @@ int
90
113
pgwin32_is_service (void )
91
114
{
92
115
static int _is_service = -1 ;
93
- BOOL IsMember ;
116
+ HANDLE AccessToken ;
117
+ char * InfoBuffer = NULL ;
118
+ char errbuf [256 ];
119
+ PTOKEN_GROUPS Groups ;
120
+ PTOKEN_USER User ;
94
121
PSID ServiceSid ;
95
122
PSID LocalSystemSid ;
96
123
SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
124
+ UINT x ;
97
125
98
126
/* Only check the first time */
99
127
if (_is_service != -1 )
100
128
return _is_service ;
101
129
102
- /* First check for LocalSystem */
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
+
103
147
if (!AllocateAndInitializeSid (& NtAuthority , 1 ,
104
148
SECURITY_LOCAL_SYSTEM_RID , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
105
149
& LocalSystemSid ))
106
150
{
107
151
fprintf (stderr , "could not get SID for local system account\n" );
152
+ CloseHandle (AccessToken );
108
153
return -1 ;
109
154
}
110
155
111
- if (! CheckTokenMembership ( NULL , LocalSystemSid , & IsMember ))
156
+ if (EqualSid ( LocalSystemSid , User -> User . Sid ))
112
157
{
113
- fprintf (stderr , "could not check access token membership: error code %lu\n" ,
114
- GetLastError ());
115
158
FreeSid (LocalSystemSid );
116
- return -1 ;
159
+ free (InfoBuffer );
160
+ CloseHandle (AccessToken );
161
+ _is_service = 1 ;
162
+ return _is_service ;
117
163
}
164
+
118
165
FreeSid (LocalSystemSid );
166
+ free (InfoBuffer );
119
167
120
- if (IsMember )
168
+ /* Now check for group SID */
169
+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken , TokenGroups , & InfoBuffer ,
170
+ errbuf , sizeof (errbuf )))
121
171
{
122
- _is_service = 1 ;
123
- return _is_service ;
172
+ fprintf ( stderr , "%s" , errbuf ) ;
173
+ return -1 ;
124
174
}
125
175
126
- /* Check for service group membership */
176
+ Groups = (PTOKEN_GROUPS ) InfoBuffer ;
177
+
127
178
if (!AllocateAndInitializeSid (& NtAuthority , 1 ,
128
179
SECURITY_SERVICE_RID , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
129
180
& ServiceSid ))
130
181
{
131
- fprintf (stderr , "could not get SID for service group: error code %lu\n" ,
132
- GetLastError ());
182
+ fprintf (stderr , "could not get SID for service group\n" );
183
+ free (InfoBuffer );
184
+ CloseHandle (AccessToken );
133
185
return -1 ;
134
186
}
135
187
136
- if (!CheckTokenMembership (NULL , ServiceSid , & IsMember ))
188
+ _is_service = 0 ;
189
+ for (x = 0 ; x < Groups -> GroupCount ; x ++ )
137
190
{
138
- fprintf (stderr , "could not check access token membership: error code %lu\n" ,
139
- GetLastError ());
140
- FreeSid (ServiceSid );
141
- return -1 ;
191
+ if (EqualSid (ServiceSid , Groups -> Groups [x ].Sid ) &&
192
+ (Groups -> Groups [x ].Attributes & SE_GROUP_ENABLED ))
193
+ {
194
+ _is_service = 1 ;
195
+ break ;
196
+ }
142
197
}
198
+
199
+ free (InfoBuffer );
143
200
FreeSid (ServiceSid );
144
201
145
- if (IsMember )
146
- _is_service = 1 ;
147
- else
148
- _is_service = 0 ;
202
+ CloseHandle (AccessToken );
149
203
150
204
return _is_service ;
151
205
}
206
+
207
+
208
+ /*
209
+ * Call GetTokenInformation() on a token and return a dynamically sized
210
+ * buffer with the information in it. This buffer must be free():d by
211
+ * the calling function!
212
+ */
213
+ static BOOL
214
+ pgwin32_get_dynamic_tokeninfo (HANDLE token , TOKEN_INFORMATION_CLASS class ,
215
+ char * * InfoBuffer , char * errbuf , int errsize )
216
+ {
217
+ DWORD InfoBufferSize ;
218
+
219
+ if (GetTokenInformation (token , class , NULL , 0 , & InfoBufferSize ))
220
+ {
221
+ snprintf (errbuf , errsize , "could not get token information: got zero size\n" );
222
+ return FALSE;
223
+ }
224
+
225
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER )
226
+ {
227
+ snprintf (errbuf , errsize , "could not get token information: error code %lu\n" ,
228
+ GetLastError ());
229
+ return FALSE;
230
+ }
231
+
232
+ * InfoBuffer = malloc (InfoBufferSize );
233
+ if (* InfoBuffer == NULL )
234
+ {
235
+ snprintf (errbuf , errsize , "could not allocate %d bytes for token information\n" ,
236
+ (int ) InfoBufferSize );
237
+ return FALSE;
238
+ }
239
+
240
+ if (!GetTokenInformation (token , class , * InfoBuffer ,
241
+ InfoBufferSize , & InfoBufferSize ))
242
+ {
243
+ snprintf (errbuf , errsize , "could not get token information: error code %lu\n" ,
244
+ GetLastError ());
245
+ return FALSE;
246
+ }
247
+
248
+ return TRUE;
249
+ }
0 commit comments