* Sync up to trunk head (r64995).
[reactos.git] / dll / win32 / advapi32 / token / token.c
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 }