1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * PURPOSE: Security manager 5 * FILE: lib/rtl/sid.c 6 * PROGRAMER: David Welch <welch@cwcom.net> 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <rtl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define TAG_SID 'diSp' 16 17 /* FUNCTIONS ***************************************************************/ 18 19 BOOLEAN 20 NTAPI 21 RtlValidSid(IN PSID Sid_) 22 { 23 PISID Sid = Sid_; 24 PAGED_CODE_RTL(); 25 26 /* Use SEH in case any pointer is invalid */ 27 _SEH2_TRY 28 { 29 /* Validate the revision and subauthority count */ 30 if ((Sid) && 31 (((Sid->Revision & 0xF) != SID_REVISION) || 32 (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES))) 33 { 34 /* It's not, fail */ 35 _SEH2_YIELD(return FALSE); 36 } 37 } 38 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 39 { 40 /* Access violation, SID is not valid */ 41 _SEH2_YIELD(return FALSE); 42 } 43 _SEH2_END; 44 45 /* All good */ 46 return TRUE; 47 } 48 49 /* 50 * @implemented 51 */ 52 ULONG 53 NTAPI 54 RtlLengthRequiredSid(IN ULONG SubAuthorityCount) 55 { 56 PAGED_CODE_RTL(); 57 58 /* Return the required length */ 59 return (ULONG)FIELD_OFFSET(SID, 60 SubAuthority[SubAuthorityCount]); 61 } 62 63 /* 64 * @implemented 65 */ 66 NTSTATUS 67 NTAPI 68 RtlInitializeSid(IN PSID Sid_, 69 IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, 70 IN UCHAR SubAuthorityCount) 71 { 72 PISID Sid = Sid_; 73 PAGED_CODE_RTL(); 74 75 /* Fill out the header */ 76 Sid->Revision = SID_REVISION; 77 Sid->SubAuthorityCount = SubAuthorityCount; 78 Sid->IdentifierAuthority = *IdentifierAuthority; 79 80 /* All good */ 81 return STATUS_SUCCESS; 82 } 83 84 /* 85 * @implemented 86 */ 87 PULONG 88 NTAPI 89 RtlSubAuthoritySid(IN PSID Sid_, 90 IN ULONG SubAuthority) 91 { 92 PISID Sid = Sid_; 93 PAGED_CODE_RTL(); 94 95 /* Return the offset */ 96 return (PULONG)&Sid->SubAuthority[SubAuthority]; 97 } 98 99 /* 100 * @implemented 101 */ 102 PUCHAR 103 NTAPI 104 RtlSubAuthorityCountSid(IN PSID Sid_) 105 { 106 PISID Sid = Sid_; 107 PAGED_CODE_RTL(); 108 109 /* Return the offset to the count */ 110 return &Sid->SubAuthorityCount; 111 } 112 113 /* 114 * @implemented 115 */ 116 PSID_IDENTIFIER_AUTHORITY 117 NTAPI 118 RtlIdentifierAuthoritySid(IN PSID Sid_) 119 { 120 PISID Sid = Sid_; 121 PAGED_CODE_RTL(); 122 123 /* Return the offset to the identifier authority */ 124 return &Sid->IdentifierAuthority; 125 } 126 127 /* 128 * @implemented 129 */ 130 BOOLEAN 131 NTAPI 132 RtlEqualSid(IN PSID Sid1_, 133 IN PSID Sid2_) 134 { 135 PISID Sid1 = Sid1_, Sid2 = Sid2_; 136 PAGED_CODE_RTL(); 137 138 /* Quick compare of the revision and the count */ 139 if (*(PUSHORT)&Sid1->Revision != *(PUSHORT)&Sid2->Revision) return FALSE; 140 141 /* Get the length and compare it the long way */ 142 return RtlEqualMemory(Sid1, Sid2, RtlLengthSid(Sid1)); 143 } 144 145 /* 146 * @implemented 147 */ 148 ULONG 149 NTAPI 150 RtlLengthSid(IN PSID Sid_) 151 { 152 PISID Sid = Sid_; 153 PAGED_CODE_RTL(); 154 155 /* The offset to the last index + 1 (since it's a count) is the length */ 156 return (ULONG)FIELD_OFFSET(SID, 157 SubAuthority[Sid->SubAuthorityCount]); 158 } 159 160 /* 161 * @implemented 162 */ 163 NTSTATUS 164 NTAPI 165 RtlCopySid(IN ULONG BufferLength, 166 IN PSID Dest, 167 IN PSID Src) 168 { 169 ULONG SidLength; 170 PAGED_CODE_RTL(); 171 172 /* Make sure the buffer is large enough*/ 173 SidLength = RtlLengthSid(Src); 174 if (SidLength > BufferLength) return STATUS_BUFFER_TOO_SMALL; 175 176 /* And then copy the SID */ 177 RtlMoveMemory(Dest, Src, SidLength); 178 return STATUS_SUCCESS; 179 } 180 181 /* 182 * @implemented 183 */ 184 PVOID 185 NTAPI 186 RtlFreeSid(IN PSID Sid) 187 { 188 PAGED_CODE_RTL(); 189 190 /* Free the SID and always return NULL */ 191 RtlpFreeMemory(Sid, TAG_SID); 192 return NULL; 193 } 194 195 /* 196 * @implemented 197 */ 198 BOOLEAN 199 NTAPI 200 RtlEqualPrefixSid(IN PSID Sid1_, 201 IN PSID Sid2_) 202 { 203 PISID Sid1 = Sid1_, Sid2 = Sid2_; 204 ULONG i; 205 PAGED_CODE_RTL(); 206 207 /* Revisions have to match */ 208 if (Sid1->Revision != Sid2->Revision) return FALSE; 209 210 /* The identifier authorities have to match */ 211 if ((Sid1->IdentifierAuthority.Value[0] == Sid2->IdentifierAuthority.Value[0]) && 212 (Sid1->IdentifierAuthority.Value[1] == Sid2->IdentifierAuthority.Value[1]) && 213 (Sid1->IdentifierAuthority.Value[2] == Sid2->IdentifierAuthority.Value[2]) && 214 (Sid1->IdentifierAuthority.Value[3] == Sid2->IdentifierAuthority.Value[3]) && 215 (Sid1->IdentifierAuthority.Value[4] == Sid2->IdentifierAuthority.Value[4]) && 216 (Sid1->IdentifierAuthority.Value[5] == Sid2->IdentifierAuthority.Value[5])) 217 { 218 /* The subauthority counts have to match */ 219 if (Sid1->SubAuthorityCount == Sid2->SubAuthorityCount) 220 { 221 /* If there aren't any in SID1, means none in SID2 either, so equal */ 222 if (!Sid1->SubAuthorityCount) return TRUE; 223 224 /* Now compare all the subauthority values BUT the last one */ 225 for (i = 0; (i + 1) < Sid1->SubAuthorityCount; i++) 226 { 227 /* Does any mismatch? */ 228 if (Sid1->SubAuthority[i] != Sid2->SubAuthority[i]) 229 { 230 /* Prefix doesn't match, fail */ 231 return FALSE; 232 } 233 } 234 235 /* Everything that should matches, does, return success */ 236 return TRUE; 237 } 238 } 239 240 /* Identifiers don't match, fail */ 241 return FALSE; 242 } 243 244 /* 245 * @implemented 246 */ 247 NTSTATUS 248 NTAPI 249 RtlCopySidAndAttributesArray(IN ULONG Count, 250 IN PSID_AND_ATTRIBUTES Src, 251 IN ULONG SidAreaSize, 252 IN PSID_AND_ATTRIBUTES Dest, 253 IN PSID SidArea, 254 OUT PSID* RemainingSidArea, 255 OUT PULONG RemainingSidAreaSize) 256 { 257 ULONG SidLength, i; 258 PAGED_CODE_RTL(); 259 260 /* Loop all the attributes */ 261 for (i = 0; i < Count; i++) 262 { 263 /* Make sure this SID can fit in the buffer */ 264 SidLength = RtlLengthSid(Src[i].Sid); 265 if (SidLength > SidAreaSize) return STATUS_BUFFER_TOO_SMALL; 266 267 /* Consume remaining buffer space for this SID */ 268 SidAreaSize -= SidLength; 269 270 /* Copy the SID and attributes */ 271 Dest[i].Sid = SidArea; 272 Dest[i].Attributes = Src[i].Attributes; 273 RtlCopySid(SidLength, SidArea, Src[i].Sid); 274 275 /* Push the buffer area where the SID will reset */ 276 SidArea = (PSID)((ULONG_PTR)SidArea + SidLength); 277 } 278 279 /* Return how much space is left, and where the buffer is at now */ 280 *RemainingSidArea = SidArea; 281 *RemainingSidAreaSize = SidAreaSize; 282 return STATUS_SUCCESS; 283 } 284 285 /* 286 * @implemented 287 */ 288 NTSTATUS 289 NTAPI 290 RtlAllocateAndInitializeSid(IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, 291 IN UCHAR SubAuthorityCount, 292 IN ULONG SubAuthority0, 293 IN ULONG SubAuthority1, 294 IN ULONG SubAuthority2, 295 IN ULONG SubAuthority3, 296 IN ULONG SubAuthority4, 297 IN ULONG SubAuthority5, 298 IN ULONG SubAuthority6, 299 IN ULONG SubAuthority7, 300 OUT PSID *Sid) 301 { 302 PISID pSid; 303 PAGED_CODE_RTL(); 304 305 /* SIDs can only have up to 8 subauthorities */ 306 if (SubAuthorityCount > 8) return STATUS_INVALID_SID; 307 308 /* Allocate memory to hold the SID */ 309 pSid = RtlpAllocateMemory(RtlLengthRequiredSid(SubAuthorityCount), TAG_SID); 310 if (!pSid) return STATUS_NO_MEMORY; 311 312 /* Fill out the header */ 313 pSid->Revision = SID_REVISION; 314 pSid->SubAuthorityCount = SubAuthorityCount; 315 pSid->IdentifierAuthority = *IdentifierAuthority; 316 317 /* Iteraratively drop into each successive lower count */ 318 switch (SubAuthorityCount) 319 { 320 /* And copy the needed subahority */ 321 case 8: pSid->SubAuthority[7] = SubAuthority7; 322 case 7: pSid->SubAuthority[6] = SubAuthority6; 323 case 6: pSid->SubAuthority[5] = SubAuthority5; 324 case 5: pSid->SubAuthority[4] = SubAuthority4; 325 case 4: pSid->SubAuthority[3] = SubAuthority3; 326 case 3: pSid->SubAuthority[2] = SubAuthority2; 327 case 2: pSid->SubAuthority[1] = SubAuthority1; 328 case 1: pSid->SubAuthority[0] = SubAuthority0; 329 default: break; 330 } 331 332 /* Return the allocated SID */ 333 *Sid = pSid; 334 return STATUS_SUCCESS; 335 } 336 337 /* 338 * @implemented 339 */ 340 NTSTATUS 341 NTAPI 342 RtlConvertSidToUnicodeString(IN PUNICODE_STRING String, 343 IN PSID Sid_, 344 IN BOOLEAN AllocateBuffer) 345 { 346 WCHAR Buffer[256]; 347 PWSTR wcs; 348 SIZE_T Length; 349 ULONG i; 350 PISID Sid = Sid_; 351 PAGED_CODE_RTL(); 352 353 if (!RtlValidSid(Sid)) return STATUS_INVALID_SID; 354 355 wcs = Buffer; 356 wcs += swprintf(wcs, L"S-1-"); 357 358 if ((Sid->IdentifierAuthority.Value[0] == 0) && 359 (Sid->IdentifierAuthority.Value[1] == 0)) 360 { 361 wcs += swprintf(wcs, 362 L"%lu", 363 (ULONG)Sid->IdentifierAuthority.Value[2] << 24 | 364 (ULONG)Sid->IdentifierAuthority.Value[3] << 16 | 365 (ULONG)Sid->IdentifierAuthority.Value[4] << 8 | 366 (ULONG)Sid->IdentifierAuthority.Value[5]); 367 } 368 else 369 { 370 wcs += swprintf(wcs, 371 L"0x%02hx%02hx%02hx%02hx%02hx%02hx", 372 Sid->IdentifierAuthority.Value[0], 373 Sid->IdentifierAuthority.Value[1], 374 Sid->IdentifierAuthority.Value[2], 375 Sid->IdentifierAuthority.Value[3], 376 Sid->IdentifierAuthority.Value[4], 377 Sid->IdentifierAuthority.Value[5]); 378 } 379 380 for (i = 0; i < Sid->SubAuthorityCount; i++) 381 { 382 wcs += swprintf(wcs, L"-%u", Sid->SubAuthority[i]); 383 } 384 385 if (AllocateBuffer) 386 { 387 if (!RtlCreateUnicodeString(String, Buffer)) return STATUS_NO_MEMORY; 388 } 389 else 390 { 391 Length = (wcs - Buffer) * sizeof(WCHAR); 392 393 if (Length > String->MaximumLength) return STATUS_BUFFER_TOO_SMALL; 394 395 String->Length = (USHORT)Length; 396 RtlCopyMemory(String->Buffer, Buffer, Length); 397 398 if (Length < String->MaximumLength) 399 { 400 String->Buffer[Length / sizeof(WCHAR)] = UNICODE_NULL; 401 } 402 } 403 404 return STATUS_SUCCESS; 405 } 406 407 /* EOF */ 408