87e70e41a0770db27cb8f93b24d0b6ce71520895
[reactos.git] / reactos / ntoskrnl / ob / security.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/security.c
6 * PURPOSE: Security manager
7 *
8 * PROGRAMERS: No programmer listed.
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS ***************************************************************/
18
19 /*
20 * @implemented
21 */
22 NTSTATUS STDCALL
23 ObAssignSecurity(IN PACCESS_STATE AccessState,
24 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
25 IN PVOID Object,
26 IN POBJECT_TYPE Type)
27 {
28 PSECURITY_DESCRIPTOR NewDescriptor;
29 NTSTATUS Status;
30
31 PAGED_CODE();
32
33 /* Build the new security descriptor */
34 Status = SeAssignSecurity(SecurityDescriptor,
35 AccessState->SecurityDescriptor,
36 &NewDescriptor,
37 (Type == ObDirectoryType),
38 &AccessState->SubjectSecurityContext,
39 &Type->TypeInfo.GenericMapping,
40 PagedPool);
41 if (!NT_SUCCESS(Status))
42 return Status;
43
44 if (Type->TypeInfo.SecurityProcedure != NULL)
45 {
46 /* Call the security method */
47 Status = Type->TypeInfo.SecurityProcedure(Object,
48 AssignSecurityDescriptor,
49 0,
50 NewDescriptor,
51 NULL);
52 }
53 else
54 {
55 /* Assign the security descriptor to the object header */
56 Status = ObpAddSecurityDescriptor(NewDescriptor,
57 &(BODY_TO_HEADER(Object)->SecurityDescriptor));
58 }
59
60 /* Release the new security descriptor */
61 SeDeassignSecurity(&NewDescriptor);
62
63 return Status;
64 }
65
66
67 /*
68 * @implemented
69 */
70 NTSTATUS STDCALL
71 ObGetObjectSecurity(IN PVOID Object,
72 OUT PSECURITY_DESCRIPTOR *SecurityDescriptor,
73 OUT PBOOLEAN MemoryAllocated)
74 {
75 POBJECT_HEADER Header;
76 ULONG Length;
77 NTSTATUS Status;
78
79 PAGED_CODE();
80
81 Header = BODY_TO_HEADER(Object);
82 if (Header->ObjectType == NULL)
83 return STATUS_UNSUCCESSFUL;
84
85 if (Header->ObjectType->TypeInfo.SecurityProcedure == NULL)
86 {
87 ObpReferenceCachedSecurityDescriptor(Header->SecurityDescriptor);
88 *SecurityDescriptor = Header->SecurityDescriptor;
89 *MemoryAllocated = FALSE;
90 return STATUS_SUCCESS;
91 }
92
93 /* Get the security descriptor size */
94 Length = 0;
95 Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object,
96 QuerySecurityDescriptor,
97 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
98 DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
99 NULL,
100 &Length);
101 if (Status != STATUS_BUFFER_TOO_SMALL)
102 return Status;
103
104 /* Allocate security descriptor */
105 *SecurityDescriptor = ExAllocatePool(NonPagedPool,
106 Length);
107 if (*SecurityDescriptor == NULL)
108 return STATUS_INSUFFICIENT_RESOURCES;
109
110 /* Query security descriptor */
111 Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object,
112 QuerySecurityDescriptor,
113 OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
114 DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION,
115 *SecurityDescriptor,
116 &Length);
117 if (!NT_SUCCESS(Status))
118 {
119 ExFreePool(*SecurityDescriptor);
120 return Status;
121 }
122
123 *MemoryAllocated = TRUE;
124
125 return STATUS_SUCCESS;
126 }
127
128
129 /*
130 * @implemented
131 */
132 VOID STDCALL
133 ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
134 IN BOOLEAN MemoryAllocated)
135 {
136 PAGED_CODE();
137
138 if (SecurityDescriptor == NULL)
139 return;
140
141 if (MemoryAllocated)
142 {
143 ExFreePool(SecurityDescriptor);
144 }
145 else
146 {
147 ObpDereferenceCachedSecurityDescriptor(SecurityDescriptor);
148 }
149 }
150
151
152 /*
153 * @implemented
154 */
155 NTSTATUS STDCALL
156 NtQuerySecurityObject(IN HANDLE Handle,
157 IN SECURITY_INFORMATION SecurityInformation,
158 OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
159 IN ULONG Length,
160 OUT PULONG ResultLength)
161 {
162 POBJECT_HEADER Header;
163 PVOID Object;
164 NTSTATUS Status;
165
166 PAGED_CODE();
167
168 DPRINT("NtQuerySecurityObject() called\n");
169
170 Status = ObReferenceObjectByHandle(Handle,
171 (SecurityInformation & SACL_SECURITY_INFORMATION) ? ACCESS_SYSTEM_SECURITY : 0,
172 NULL,
173 KeGetPreviousMode(),
174 &Object,
175 NULL);
176 if (!NT_SUCCESS(Status))
177 {
178 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
179 return Status;
180 }
181
182 Header = BODY_TO_HEADER(Object);
183 if (Header->ObjectType == NULL)
184 {
185 DPRINT1("Invalid object type\n");
186 ObDereferenceObject(Object);
187 return STATUS_UNSUCCESSFUL;
188 }
189
190 if (Header->ObjectType->TypeInfo.SecurityProcedure != NULL)
191 {
192 *ResultLength = Length;
193 Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object,
194 QuerySecurityDescriptor,
195 SecurityInformation,
196 SecurityDescriptor,
197 ResultLength);
198 }
199 else
200 {
201 *ResultLength = Length;
202 Status = SeQuerySecurityDescriptorInfo(&SecurityInformation,
203 SecurityDescriptor,
204 ResultLength,
205 &Header->SecurityDescriptor);
206 }
207
208 ObDereferenceObject(Object);
209
210 return Status;
211 }
212
213
214 /*
215 * @implemented
216 */
217 NTSTATUS STDCALL
218 NtSetSecurityObject(IN HANDLE Handle,
219 IN SECURITY_INFORMATION SecurityInformation,
220 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
221 {
222 PSECURITY_DESCRIPTOR ObjectSd;
223 PSECURITY_DESCRIPTOR NewSd;
224 POBJECT_HEADER Header;
225 PVOID Object;
226 PSID Owner = 0;
227 PSID Group = 0;
228 PACL Dacl = 0;
229 PACL Sacl = 0;
230 ULONG OwnerLength = 0;
231 ULONG GroupLength = 0;
232 ULONG DaclLength = 0;
233 ULONG SaclLength = 0;
234 ULONG Control = 0;
235 ULONG_PTR Current;
236 NTSTATUS Status;
237
238 PAGED_CODE();
239
240 DPRINT("NtSetSecurityObject() called\n");
241
242 Status = ObReferenceObjectByHandle(Handle,
243 (SecurityInformation & SACL_SECURITY_INFORMATION) ? ACCESS_SYSTEM_SECURITY : 0,
244 NULL,
245 KeGetPreviousMode(),
246 &Object,
247 NULL);
248 if (!NT_SUCCESS(Status))
249 {
250 DPRINT1("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
251 return Status;
252 }
253
254 Header = BODY_TO_HEADER(Object);
255 if (Header->ObjectType == NULL)
256 {
257 DPRINT1("Invalid object type\n");
258 ObDereferenceObject(Object);
259 return STATUS_UNSUCCESSFUL;
260 }
261
262 if (Header->ObjectType->TypeInfo.SecurityProcedure != NULL)
263 {
264 Status = Header->ObjectType->TypeInfo.SecurityProcedure(Object,
265 SetSecurityDescriptor,
266 SecurityInformation,
267 SecurityDescriptor,
268 NULL);
269 }
270 else
271 {
272 ObjectSd = Header->SecurityDescriptor;
273
274 /* Get owner and owner size */
275 if (SecurityInformation & OWNER_SECURITY_INFORMATION)
276 {
277 if (SecurityDescriptor->Owner != NULL)
278 {
279 if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
280 Owner = (PSID)((ULONG_PTR)SecurityDescriptor->Owner +
281 (ULONG_PTR)SecurityDescriptor);
282 else
283 Owner = (PSID)SecurityDescriptor->Owner;
284 OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
285 }
286 Control |= (SecurityDescriptor->Control & SE_OWNER_DEFAULTED);
287 }
288 else
289 {
290 if (ObjectSd->Owner != NULL)
291 {
292 Owner = (PSID)((ULONG_PTR)ObjectSd->Owner + (ULONG_PTR)ObjectSd);
293 OwnerLength = ROUND_UP(RtlLengthSid(Owner), 4);
294 }
295 Control |= (ObjectSd->Control & SE_OWNER_DEFAULTED);
296 }
297
298 /* Get group and group size */
299 if (SecurityInformation & GROUP_SECURITY_INFORMATION)
300 {
301 if (SecurityDescriptor->Group != NULL)
302 {
303 if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
304 Group = (PSID)((ULONG_PTR)SecurityDescriptor->Group +
305 (ULONG_PTR)SecurityDescriptor);
306 else
307 Group = (PSID)SecurityDescriptor->Group;
308 GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
309 }
310 Control |= (SecurityDescriptor->Control & SE_GROUP_DEFAULTED);
311 }
312 else
313 {
314 if (ObjectSd->Group != NULL)
315 {
316 Group = (PSID)((ULONG_PTR)ObjectSd->Group + (ULONG_PTR)ObjectSd);
317 GroupLength = ROUND_UP(RtlLengthSid(Group), 4);
318 }
319 Control |= (ObjectSd->Control & SE_GROUP_DEFAULTED);
320 }
321
322 /* Get DACL and DACL size */
323 if (SecurityInformation & DACL_SECURITY_INFORMATION)
324 {
325 if ((SecurityDescriptor->Control & SE_DACL_PRESENT) &&
326 (SecurityDescriptor->Dacl != NULL))
327 {
328 if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
329 Dacl = (PACL)((ULONG_PTR)SecurityDescriptor->Dacl +
330 (ULONG_PTR)SecurityDescriptor);
331 else
332 Dacl = (PACL)SecurityDescriptor->Dacl;
333
334 DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
335 }
336 Control |= (SecurityDescriptor->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
337 }
338 else
339 {
340 if ((ObjectSd->Control & SE_DACL_PRESENT) &&
341 (ObjectSd->Dacl != NULL))
342 {
343 Dacl = (PACL)((ULONG_PTR)ObjectSd->Dacl + (ULONG_PTR)ObjectSd);
344 DaclLength = ROUND_UP((ULONG)Dacl->AclSize, 4);
345 }
346 Control |= (ObjectSd->Control & (SE_DACL_DEFAULTED | SE_DACL_PRESENT));
347 }
348
349 /* Get SACL and SACL size */
350 if (SecurityInformation & SACL_SECURITY_INFORMATION)
351 {
352 if ((SecurityDescriptor->Control & SE_SACL_PRESENT) &&
353 (SecurityDescriptor->Sacl != NULL))
354 {
355 if( SecurityDescriptor->Control & SE_SELF_RELATIVE )
356 Sacl = (PACL)((ULONG_PTR)SecurityDescriptor->Sacl +
357 (ULONG_PTR)SecurityDescriptor);
358 else
359 Sacl = (PACL)SecurityDescriptor->Sacl;
360 SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
361 }
362 Control |= (SecurityDescriptor->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
363 }
364 else
365 {
366 if ((ObjectSd->Control & SE_SACL_PRESENT) &&
367 (ObjectSd->Sacl != NULL))
368 {
369 Sacl = (PACL)((ULONG_PTR)ObjectSd->Sacl + (ULONG_PTR)ObjectSd);
370 SaclLength = ROUND_UP((ULONG)Sacl->AclSize, 4);
371 }
372 Control |= (ObjectSd->Control & (SE_SACL_DEFAULTED | SE_SACL_PRESENT));
373 }
374
375 NewSd = ExAllocatePool(NonPagedPool,
376 sizeof(SECURITY_DESCRIPTOR) + OwnerLength + GroupLength +
377 DaclLength + SaclLength);
378 if (NewSd == NULL)
379 {
380 ObDereferenceObject(Object);
381 return STATUS_INSUFFICIENT_RESOURCES;
382 }
383
384 RtlCreateSecurityDescriptor(NewSd,
385 SECURITY_DESCRIPTOR_REVISION1);
386 /* We always build a self-relative descriptor */
387 NewSd->Control = Control | SE_SELF_RELATIVE;
388
389 Current = (ULONG_PTR)NewSd + sizeof(SECURITY_DESCRIPTOR);
390
391 if (OwnerLength != 0)
392 {
393 RtlCopyMemory((PVOID)Current,
394 Owner,
395 OwnerLength);
396 NewSd->Owner = (PSID)(Current - (ULONG_PTR)NewSd);
397 Current += OwnerLength;
398 }
399
400 if (GroupLength != 0)
401 {
402 RtlCopyMemory((PVOID)Current,
403 Group,
404 GroupLength);
405 NewSd->Group = (PSID)(Current - (ULONG_PTR)NewSd);
406 Current += GroupLength;
407 }
408
409 if (DaclLength != 0)
410 {
411 RtlCopyMemory((PVOID)Current,
412 Dacl,
413 DaclLength);
414 NewSd->Dacl = (PACL)(Current - (ULONG_PTR)NewSd);
415 Current += DaclLength;
416 }
417
418 if (SaclLength != 0)
419 {
420 RtlCopyMemory((PVOID)Current,
421 Sacl,
422 SaclLength);
423 NewSd->Sacl = (PACL)(Current - (ULONG_PTR)NewSd);
424 Current += SaclLength;
425 }
426
427 /* Add the new SD */
428 Status = ObpAddSecurityDescriptor(NewSd,
429 &Header->SecurityDescriptor);
430 if (NT_SUCCESS(Status))
431 {
432 /* Remove the old security descriptor */
433 ObpRemoveSecurityDescriptor(ObjectSd);
434 }
435 else
436 {
437 /* Restore the old security descriptor */
438 Header->SecurityDescriptor = ObjectSd;
439 }
440
441 ExFreePool(NewSd);
442 }
443
444 ObDereferenceObject(Object);
445
446 return Status;
447 }
448
449 /* EOF */