1818#endif
1919
2020
21+ static BOOL pgwin32_get_dynamic_tokeninfo (HANDLE token ,
22+ TOKEN_INFORMATION_CLASS class ,
23+ char * * InfoBuffer , char * errbuf , int errsize );
24+
25+
2126/*
2227 * Utility wrapper for frontend and backend when reporting an error
2328 * message.
@@ -48,11 +53,33 @@ log_error(const char *fmt,...)
4853int
4954pgwin32_is_admin (void )
5055{
56+ HANDLE AccessToken ;
57+ char * InfoBuffer = NULL ;
58+ char errbuf [256 ];
59+ PTOKEN_GROUPS Groups ;
5160 PSID AdministratorsSid ;
5261 PSID PowerUsersSid ;
5362 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
54- BOOL IsAdministrators ;
55- BOOL IsPowerUsers ;
63+ UINT x ;
64+ BOOL success ;
65+
66+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ , & AccessToken ))
67+ {
68+ log_error (_ ("could not open process token: error code %lu\n" ),
69+ GetLastError ());
70+ exit (1 );
71+ }
72+
73+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken , TokenGroups ,
74+ & InfoBuffer , errbuf , sizeof (errbuf )))
75+ {
76+ log_error ("%s" , errbuf );
77+ exit (1 );
78+ }
79+
80+ Groups = (PTOKEN_GROUPS ) InfoBuffer ;
81+
82+ CloseHandle (AccessToken );
5683
5784 if (!AllocateAndInitializeSid (& NtAuthority , 2 ,
5885 SECURITY_BUILTIN_DOMAIN_RID ,
@@ -74,35 +101,34 @@ pgwin32_is_admin(void)
74101 exit (1 );
75102 }
76103
77- if (!CheckTokenMembership (NULL , AdministratorsSid , & IsAdministrators ) ||
78- !CheckTokenMembership (NULL , PowerUsersSid , & IsPowerUsers ))
104+ success = FALSE;
105+
106+ for (x = 0 ; x < Groups -> GroupCount ; x ++ )
79107 {
80- log_error (_ ("could not check access token membership: error code %lu\n" ),
81- GetLastError ());
82- exit (1 );
108+ if ((EqualSid (AdministratorsSid , Groups -> Groups [x ].Sid ) &&
109+ (Groups -> Groups [x ].Attributes & SE_GROUP_ENABLED )) ||
110+ (EqualSid (PowerUsersSid , Groups -> Groups [x ].Sid ) &&
111+ (Groups -> Groups [x ].Attributes & SE_GROUP_ENABLED )))
112+ {
113+ success = TRUE;
114+ break ;
115+ }
83116 }
84117
118+ free (InfoBuffer );
85119 FreeSid (AdministratorsSid );
86120 FreeSid (PowerUsersSid );
87-
88- if (IsAdministrators || IsPowerUsers )
89- return 1 ;
90- else
91- return 0 ;
121+ return success ;
92122}
93123
94124/*
95125 * We consider ourselves running as a service if one of the following is
96126 * true:
97127 *
98- * 1) We are running as LocalSystem (only used by services)
128+ * 1) We are running as Local System (only used by services)
99129 * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
100130 * process token by the SCM when starting a service)
101131 *
102- * The check for LocalSystem is needed, because surprisingly, if a service
103- * is running as LocalSystem, it does not have SECURITY_SERVICE_RID in its
104- * process token.
105- *
106132 * Return values:
107133 * 0 = Not service
108134 * 1 = Service
@@ -117,62 +143,141 @@ int
117143pgwin32_is_service (void )
118144{
119145 static int _is_service = -1 ;
120- BOOL IsMember ;
146+ HANDLE AccessToken ;
147+ char * InfoBuffer = NULL ;
148+ char errbuf [256 ];
149+ PTOKEN_GROUPS Groups ;
150+ PTOKEN_USER User ;
121151 PSID ServiceSid ;
122152 PSID LocalSystemSid ;
123153 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
154+ UINT x ;
124155
125156 /* Only check the first time */
126157 if (_is_service != -1 )
127158 return _is_service ;
128159
129- /* First check for LocalSystem */
160+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ , & AccessToken ))
161+ {
162+ fprintf (stderr , "could not open process token: error code %lu\n" ,
163+ GetLastError ());
164+ return -1 ;
165+ }
166+
167+ /* First check for local system */
168+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken , TokenUser , & InfoBuffer ,
169+ errbuf , sizeof (errbuf )))
170+ {
171+ fprintf (stderr , "%s" , errbuf );
172+ return -1 ;
173+ }
174+
175+ User = (PTOKEN_USER ) InfoBuffer ;
176+
130177 if (!AllocateAndInitializeSid (& NtAuthority , 1 ,
131178 SECURITY_LOCAL_SYSTEM_RID , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
132179 & LocalSystemSid ))
133180 {
134181 fprintf (stderr , "could not get SID for local system account\n" );
182+ CloseHandle (AccessToken );
135183 return -1 ;
136184 }
137185
138- if (! CheckTokenMembership ( NULL , LocalSystemSid , & IsMember ))
186+ if (EqualSid ( LocalSystemSid , User -> User . Sid ))
139187 {
140- fprintf (stderr , "could not check access token membership: error code %lu\n" ,
141- GetLastError ());
142188 FreeSid (LocalSystemSid );
143- return -1 ;
189+ free (InfoBuffer );
190+ CloseHandle (AccessToken );
191+ _is_service = 1 ;
192+ return _is_service ;
144193 }
194+
145195 FreeSid (LocalSystemSid );
196+ free (InfoBuffer );
146197
147- if (IsMember )
198+ /* Now check for group SID */
199+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken , TokenGroups , & InfoBuffer ,
200+ errbuf , sizeof (errbuf )))
148201 {
149- _is_service = 1 ;
150- return _is_service ;
202+ fprintf ( stderr , "%s" , errbuf ) ;
203+ return -1 ;
151204 }
152205
153- /* Check for service group membership */
206+ Groups = (PTOKEN_GROUPS ) InfoBuffer ;
207+
154208 if (!AllocateAndInitializeSid (& NtAuthority , 1 ,
155209 SECURITY_SERVICE_RID , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
156210 & ServiceSid ))
157211 {
158- fprintf (stderr , "could not get SID for service group: error code %lu\n" ,
159- GetLastError ());
212+ fprintf (stderr , "could not get SID for service group\n" );
213+ free (InfoBuffer );
214+ CloseHandle (AccessToken );
160215 return -1 ;
161216 }
162217
163- if (!CheckTokenMembership (NULL , ServiceSid , & IsMember ))
218+ _is_service = 0 ;
219+ for (x = 0 ; x < Groups -> GroupCount ; x ++ )
164220 {
165- fprintf (stderr , "could not check access token membership: error code %lu\n" ,
166- GetLastError ());
167- FreeSid (ServiceSid );
168- return -1 ;
221+ if (EqualSid (ServiceSid , Groups -> Groups [x ].Sid ) &&
222+ (Groups -> Groups [x ].Attributes & SE_GROUP_ENABLED ))
223+ {
224+ _is_service = 1 ;
225+ break ;
226+ }
169227 }
228+
229+ free (InfoBuffer );
170230 FreeSid (ServiceSid );
171231
172- if (IsMember )
173- _is_service = 1 ;
174- else
175- _is_service = 0 ;
232+ CloseHandle (AccessToken );
176233
177234 return _is_service ;
178235}
236+
237+
238+ /*
239+ * Call GetTokenInformation() on a token and return a dynamically sized
240+ * buffer with the information in it. This buffer must be free():d by
241+ * the calling function!
242+ */
243+ static BOOL
244+ pgwin32_get_dynamic_tokeninfo (HANDLE token , TOKEN_INFORMATION_CLASS class ,
245+ char * * InfoBuffer , char * errbuf , int errsize )
246+ {
247+ DWORD InfoBufferSize ;
248+
249+ if (GetTokenInformation (token , class , NULL , 0 , & InfoBufferSize ))
250+ {
251+ snprintf (errbuf , errsize ,
252+ "could not get token information buffer size: got zero size\n" );
253+ return FALSE;
254+ }
255+
256+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER )
257+ {
258+ snprintf (errbuf , errsize ,
259+ "could not get token information buffer size: error code %lu\n" ,
260+ GetLastError ());
261+ return FALSE;
262+ }
263+
264+ * InfoBuffer = malloc (InfoBufferSize );
265+ if (* InfoBuffer == NULL )
266+ {
267+ snprintf (errbuf , errsize ,
268+ "could not allocate %d bytes for token information\n" ,
269+ (int ) InfoBufferSize );
270+ return FALSE;
271+ }
272+
273+ if (!GetTokenInformation (token , class , * InfoBuffer ,
274+ InfoBufferSize , & InfoBufferSize ))
275+ {
276+ snprintf (errbuf , errsize ,
277+ "could not get token information: error code %lu\n" ,
278+ GetLastError ());
279+ return FALSE;
280+ }
281+
282+ return TRUE;
283+ }
0 commit comments