[RTL]
[reactos.git] / reactos / sdk / lib / rtl / sid.c
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 */