xref: /reactos/dll/win32/advapi32/token/token.c (revision 50cf16b3)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS system libraries
4  * FILE:            lib/advapi32/token/token.c
5  * PURPOSE:         Token functions
6  * PROGRAMMER:      Ariadne (ariadne@xs4all.nl)
7  * UPDATE HISTORY:
8  *                  Created 01/11/98
9  */
10 
11 #include <advapi32.h>
12 
13 #include <ndk/setypes.h>
14 
15 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
16 
17 /*
18  * @implemented
19  */
20 BOOL WINAPI
21 CheckTokenMembership(IN HANDLE ExistingTokenHandle,
22                      IN PSID SidToCheck,
23                      OUT PBOOL IsMember)
24 {
25     PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
26     ACCESS_MASK GrantedAccess;
27     struct
28     {
29         PRIVILEGE_SET PrivilegeSet;
30         LUID_AND_ATTRIBUTES Privileges[4];
31     } PrivBuffer;
32     ULONG PrivBufferSize = sizeof(PrivBuffer);
33     GENERIC_MAPPING GenericMapping =
34     {
35         STANDARD_RIGHTS_READ,
36         STANDARD_RIGHTS_WRITE,
37         STANDARD_RIGHTS_EXECUTE,
38         STANDARD_RIGHTS_ALL
39     };
40     PACL Dacl;
41     ULONG SidLen;
42     HANDLE hToken = NULL;
43     NTSTATUS Status, AccessStatus;
44 
45     /* doesn't return gracefully if IsMember is NULL! */
46     *IsMember = FALSE;
47 
48     SidLen = RtlLengthSid(SidToCheck);
49 
50     if (ExistingTokenHandle == NULL)
51     {
52         Status = NtOpenThreadToken(NtCurrentThread(),
53                                    TOKEN_QUERY,
54                                    FALSE,
55                                    &hToken);
56 
57         if (Status == STATUS_NO_TOKEN)
58         {
59             /* we're not impersonating, open the primary token */
60             Status = NtOpenProcessToken(NtCurrentProcess(),
61                                         TOKEN_QUERY | TOKEN_DUPLICATE,
62                                         &hToken);
63             if (NT_SUCCESS(Status))
64             {
65                 HANDLE hNewToken = FALSE;
66                 BOOL DupRet;
67 
68                 /* duplicate the primary token to create an impersonation token */
69                 DupRet = DuplicateTokenEx(hToken,
70                                           TOKEN_QUERY | TOKEN_IMPERSONATE,
71                                           NULL,
72                                           SecurityImpersonation,
73                                           TokenImpersonation,
74                                           &hNewToken);
75 
76                 NtClose(hToken);
77 
78                 if (!DupRet)
79                 {
80                     WARN("Failed to duplicate the primary token!\n");
81                     return FALSE;
82                 }
83 
84                 hToken = hNewToken;
85             }
86         }
87 
88         if (!NT_SUCCESS(Status))
89         {
90             goto Cleanup;
91         }
92     }
93     else
94     {
95         hToken = ExistingTokenHandle;
96     }
97 
98     /* create a security descriptor */
99     SecurityDescriptor = RtlAllocateHeap(RtlGetProcessHeap(),
100                                          0,
101                                          sizeof(SECURITY_DESCRIPTOR) +
102                                              sizeof(ACL) + SidLen +
103                                              sizeof(ACCESS_ALLOWED_ACE));
104     if (SecurityDescriptor == NULL)
105     {
106         Status = STATUS_INSUFFICIENT_RESOURCES;
107         goto Cleanup;
108     }
109 
110     Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
111                                          SECURITY_DESCRIPTOR_REVISION);
112     if (!NT_SUCCESS(Status))
113     {
114         goto Cleanup;
115     }
116 
117     /* set the owner and group */
118     Status = RtlSetOwnerSecurityDescriptor(SecurityDescriptor,
119                                            SidToCheck,
120                                            FALSE);
121     if (!NT_SUCCESS(Status))
122     {
123         goto Cleanup;
124     }
125 
126     Status = RtlSetGroupSecurityDescriptor(SecurityDescriptor,
127                                            SidToCheck,
128                                            FALSE);
129     if (!NT_SUCCESS(Status))
130     {
131         goto Cleanup;
132     }
133 
134     /* create the DACL */
135     Dacl = (PACL)(SecurityDescriptor + 1);
136     Status = RtlCreateAcl(Dacl,
137                           sizeof(ACL) + SidLen + sizeof(ACCESS_ALLOWED_ACE),
138                           ACL_REVISION);
139     if (!NT_SUCCESS(Status))
140     {
141         goto Cleanup;
142     }
143 
144     Status = RtlAddAccessAllowedAce(Dacl,
145                                     ACL_REVISION,
146                                     0x1,
147                                     SidToCheck);
148     if (!NT_SUCCESS(Status))
149     {
150         goto Cleanup;
151     }
152 
153     /* assign the DACL to the security descriptor */
154     Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
155                                           TRUE,
156                                           Dacl,
157                                           FALSE);
158     if (!NT_SUCCESS(Status))
159     {
160         goto Cleanup;
161     }
162 
163     /* it's time to perform the access check. Just use _some_ desired access right
164        (same as for the ACE) and see if we're getting it granted. This indicates
165        our SID is a member of the token. We however can't use a generic access
166        right as those aren't mapped and return an error (STATUS_GENERIC_NOT_MAPPED). */
167     Status = NtAccessCheck(SecurityDescriptor,
168                            hToken,
169                            0x1,
170                            &GenericMapping,
171                            &PrivBuffer.PrivilegeSet,
172                            &PrivBufferSize,
173                            &GrantedAccess,
174                            &AccessStatus);
175     if (NT_SUCCESS(Status) && NT_SUCCESS(AccessStatus) && (GrantedAccess == 0x1))
176     {
177         *IsMember = TRUE;
178     }
179 
180 Cleanup:
181     if (hToken != NULL && hToken != ExistingTokenHandle)
182     {
183         NtClose(hToken);
184     }
185 
186     if (SecurityDescriptor != NULL)
187     {
188         RtlFreeHeap(RtlGetProcessHeap(),
189                     0,
190                     SecurityDescriptor);
191     }
192 
193     if (!NT_SUCCESS(Status))
194     {
195         SetLastError(RtlNtStatusToDosError(Status));
196         return FALSE;
197     }
198 
199     return TRUE;
200 }
201 
202 
203 /*
204  * @implemented
205  */
206 BOOL WINAPI
207 IsTokenRestricted(HANDLE TokenHandle)
208 {
209     ULONG RetLength;
210     PTOKEN_GROUPS lpGroups;
211     NTSTATUS Status;
212     BOOL Ret = FALSE;
213 
214     /* determine the required buffer size and allocate enough memory to read the
215        list of restricted SIDs */
216     Status = NtQueryInformationToken(TokenHandle,
217                                      TokenRestrictedSids,
218                                      NULL,
219                                      0,
220                                      &RetLength);
221     if (Status != STATUS_BUFFER_TOO_SMALL)
222     {
223         SetLastError(RtlNtStatusToDosError(Status));
224         return FALSE;
225     }
226 
227 AllocAndReadRestrictedSids:
228     lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
229                                         0,
230                                         RetLength);
231     if (lpGroups == NULL)
232     {
233         SetLastError(ERROR_OUTOFMEMORY);
234         return FALSE;
235     }
236 
237     /* actually read the list of the restricted SIDs */
238     Status = NtQueryInformationToken(TokenHandle,
239                                      TokenRestrictedSids,
240                                      lpGroups,
241                                      RetLength,
242                                      &RetLength);
243     if (NT_SUCCESS(Status))
244     {
245         Ret = (lpGroups->GroupCount != 0);
246     }
247     else if (Status == STATUS_BUFFER_TOO_SMALL)
248     {
249         /* looks like the token was modified in the meanwhile, let's just try again */
250         HeapFree(GetProcessHeap(),
251                  0,
252                  lpGroups);
253 
254         goto AllocAndReadRestrictedSids;
255     }
256     else
257     {
258         SetLastError(RtlNtStatusToDosError(Status));
259     }
260 
261     /* free allocated memory */
262     HeapFree(GetProcessHeap(),
263              0,
264              lpGroups);
265 
266     return Ret;
267 }
268 
269 /*
270  * @unimplemented
271  */
272 PSID
273 WINAPI
274 GetSiteSidFromToken(IN HANDLE TokenHandle)
275 {
276     PTOKEN_GROUPS RestrictedSids;
277     ULONG RetLen;
278     UINT i;
279     NTSTATUS Status;
280     PSID PSiteSid = NULL;
281     SID_IDENTIFIER_AUTHORITY InternetSiteAuthority = {SECURITY_INTERNETSITE_AUTHORITY};
282 
283     Status = NtQueryInformationToken(TokenHandle,
284                                      TokenRestrictedSids,
285                                      NULL,
286                                      0,
287                                      &RetLen);
288     if (Status != STATUS_BUFFER_TOO_SMALL)
289     {
290         SetLastError(RtlNtStatusToDosError(Status));
291         return NULL;
292     }
293 
294     RestrictedSids = (PTOKEN_GROUPS)RtlAllocateHeap(RtlGetProcessHeap(),
295                                                     0,
296                                                     RetLen);
297     if (RestrictedSids == NULL)
298     {
299         SetLastError(ERROR_OUTOFMEMORY);
300         return NULL;
301     }
302 
303     Status = NtQueryInformationToken(TokenHandle,
304                                      TokenRestrictedSids,
305                                      RestrictedSids,
306                                      RetLen,
307                                      &RetLen);
308     if (NT_SUCCESS(Status))
309     {
310         for (i = 0; i < RestrictedSids->GroupCount; i++)
311         {
312             SID* RSSid = RestrictedSids->Groups[i].Sid;
313 
314             if (RtlCompareMemory(&(RSSid->IdentifierAuthority),
315                                  &InternetSiteAuthority,
316                                  sizeof(SID_IDENTIFIER_AUTHORITY)) ==
317                                  sizeof(SID_IDENTIFIER_AUTHORITY))
318             {
319                 PSiteSid = RtlAllocateHeap(RtlGetProcessHeap(),
320                                            0,
321                                            RtlLengthSid((RestrictedSids->
322                                                          Groups[i]).Sid));
323                 if (PSiteSid == NULL)
324                 {
325                     SetLastError(ERROR_OUTOFMEMORY);
326                 }
327                 else
328                 {
329                     RtlCopySid(RtlLengthSid(RestrictedSids->Groups[i].Sid),
330                                PSiteSid,
331                                RestrictedSids->Groups[i].Sid);
332                 }
333 
334                 break;
335             }
336         }
337     }
338     else
339     {
340         SetLastError(RtlNtStatusToDosError(Status));
341     }
342 
343     RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedSids);
344     return PSiteSid;
345 }
346