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+
1721/*
1822 * Returns nonzero if the current user has administrative privileges,
1923 * or zero if not.
2428int
2529pgwin32_is_admin (void )
2630{
31+ HANDLE AccessToken ;
32+ char * InfoBuffer = NULL ;
33+ char errbuf [256 ];
34+ PTOKEN_GROUPS Groups ;
2735PSID AdministratorsSid ;
2836PSID PowerUsersSid ;
2937SID_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 );
3258
3359if (!AllocateAndInitializeSid (& NtAuthority ,2 ,
3460SECURITY_BUILTIN_DOMAIN_RID ,DOMAIN_ALIAS_RID_ADMINS ,0 ,0 ,0 ,0 ,0 ,
@@ -48,35 +74,32 @@ pgwin32_is_admin(void)
4874exit (1 );
4975}
5076
51- if (!CheckTokenMembership (NULL ,AdministratorsSid ,& IsAdministrators )||
52- !CheckTokenMembership (NULL ,PowerUsersSid ,& IsPowerUsers ))
77+ success = FALSE;
78+
79+ for (x = 0 ;x < Groups -> GroupCount ;x ++ )
5380{
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+ }
5787}
5888
89+ free (InfoBuffer );
5990FreeSid (AdministratorsSid );
6091FreeSid (PowerUsersSid );
61-
62- if (IsAdministrators || IsPowerUsers )
63- return 1 ;
64- else
65- return 0 ;
92+ return success ;
6693}
6794
6895/*
6996 * We consider ourselves running as a service if one of the following is
7097 * true:
7198 *
72- * 1) We are running asLocalSystem (only used by services)
99+ * 1) We are running asLocal System (only used by services)
73100 * 2) Our token contains SECURITY_SERVICE_RID (automatically added to the
74101 * process token by the SCM when starting a service)
75102 *
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- *
80103 * Return values:
81104 * 0 = Not service
82105 * 1 = Service
@@ -90,62 +113,137 @@ int
90113pgwin32_is_service (void )
91114{
92115static 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 ;
94121PSID ServiceSid ;
95122PSID LocalSystemSid ;
96123SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY };
124+ UINT x ;
97125
98126/* Only check the first time */
99127if (_is_service != -1 )
100128return _is_service ;
101129
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+
103147if (!AllocateAndInitializeSid (& NtAuthority ,1 ,
104148SECURITY_LOCAL_SYSTEM_RID ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
105149& LocalSystemSid ))
106150{
107151fprintf (stderr ,"could not get SID for local system account\n" );
152+ CloseHandle (AccessToken );
108153return -1 ;
109154}
110155
111- if (! CheckTokenMembership ( NULL , LocalSystemSid ,& IsMember ))
156+ if (EqualSid ( LocalSystemSid ,User -> User . Sid ))
112157{
113- fprintf (stderr ,"could not check access token membership: error code %lu\n" ,
114- GetLastError ());
115158FreeSid (LocalSystemSid );
116- return -1 ;
159+ free (InfoBuffer );
160+ CloseHandle (AccessToken );
161+ _is_service = 1 ;
162+ return _is_service ;
117163}
164+
118165FreeSid (LocalSystemSid );
166+ free (InfoBuffer );
119167
120- if (IsMember )
168+ /* Now check for group SID */
169+ if (!pgwin32_get_dynamic_tokeninfo (AccessToken ,TokenGroups ,& InfoBuffer ,
170+ errbuf ,sizeof (errbuf )))
121171{
122- _is_service = 1 ;
123- return _is_service ;
172+ fprintf ( stderr , "%s" , errbuf ) ;
173+ return -1 ;
124174}
125175
126- /* Check for service group membership */
176+ Groups = (PTOKEN_GROUPS )InfoBuffer ;
177+
127178if (!AllocateAndInitializeSid (& NtAuthority ,1 ,
128179SECURITY_SERVICE_RID ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
129180& ServiceSid ))
130181{
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 );
133185return -1 ;
134186}
135187
136- if (!CheckTokenMembership (NULL ,ServiceSid ,& IsMember ))
188+ _is_service = 0 ;
189+ for (x = 0 ;x < Groups -> GroupCount ;x ++ )
137190{
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+ }
142197}
198+
199+ free (InfoBuffer );
143200FreeSid (ServiceSid );
144201
145- if (IsMember )
146- _is_service = 1 ;
147- else
148- _is_service = 0 ;
202+ CloseHandle (AccessToken );
149203
150204return _is_service ;
151205}
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+ }