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