xref: /reactos/sdk/lib/rtl/sid.c (revision 5fa4fd7b)
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
RtlValidSid(IN PSID Sid_)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
RtlLengthRequiredSid(IN ULONG SubAuthorityCount)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
RtlInitializeSid(IN PSID Sid_,IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,IN UCHAR SubAuthorityCount)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
RtlSubAuthoritySid(IN PSID Sid_,IN ULONG SubAuthority)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
RtlSubAuthorityCountSid(IN PSID Sid_)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
RtlIdentifierAuthoritySid(IN PSID Sid_)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
RtlEqualSid(IN PSID Sid1_,IN PSID Sid2_)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
RtlLengthSid(IN PSID Sid_)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
RtlCopySid(IN ULONG BufferLength,IN PSID Dest,IN PSID Src)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
RtlFreeSid(IN PSID Sid)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
RtlEqualPrefixSid(IN PSID Sid1_,IN PSID Sid2_)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
RtlCopySidAndAttributesArray(IN ULONG Count,IN PSID_AND_ATTRIBUTES Src,IN ULONG SidAreaSize,IN PSID_AND_ATTRIBUTES Dest,IN PSID SidArea,OUT PSID * RemainingSidArea,OUT PULONG RemainingSidAreaSize)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
RtlAllocateAndInitializeSid(IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,IN UCHAR SubAuthorityCount,IN ULONG SubAuthority0,IN ULONG SubAuthority1,IN ULONG SubAuthority2,IN ULONG SubAuthority3,IN ULONG SubAuthority4,IN ULONG SubAuthority5,IN ULONG SubAuthority6,IN ULONG SubAuthority7,OUT PSID * Sid)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
RtlConvertSidToUnicodeString(IN PUNICODE_STRING String,IN PSID Sid_,IN BOOLEAN AllocateBuffer)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 /*
408  * @unimplemented
409  */
410 NTSTATUS
411 NTAPI
RtlCreateServiceSid(_In_ PUNICODE_STRING ServiceName,_Out_writes_bytes_opt_ (* ServiceSidLength)PSID ServiceSid,_Inout_ PULONG ServiceSidLength)412 RtlCreateServiceSid(
413     _In_ PUNICODE_STRING ServiceName,
414     _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,
415     _Inout_ PULONG ServiceSidLength)
416 {
417     UNIMPLEMENTED;
418     return STATUS_NOT_IMPLEMENTED;
419 }
420 
421 /* EOF */
422