[NTOS:IO] Implement IopAcquireFileObjectLock and use it to fix IopLockFileObject
[reactos.git] / ntoskrnl / ob / obinit.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obinit.c
5 * PURPOSE: Handles Object Manager Initialization and Shutdown
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Thomas Weidenmueller (w3seek@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 GENERIC_MAPPING ObpTypeMapping =
20 {
21 STANDARD_RIGHTS_READ,
22 STANDARD_RIGHTS_WRITE,
23 STANDARD_RIGHTS_EXECUTE,
24 0x000F0001
25 };
26
27 GENERIC_MAPPING ObpDirectoryMapping =
28 {
29 STANDARD_RIGHTS_READ | DIRECTORY_QUERY |
30 DIRECTORY_TRAVERSE,
31 STANDARD_RIGHTS_WRITE | DIRECTORY_CREATE_SUBDIRECTORY |
32 DIRECTORY_CREATE_OBJECT,
33 STANDARD_RIGHTS_EXECUTE | DIRECTORY_QUERY |
34 DIRECTORY_TRAVERSE,
35 DIRECTORY_ALL_ACCESS
36 };
37
38 GENERIC_MAPPING ObpSymbolicLinkMapping =
39 {
40 STANDARD_RIGHTS_READ | SYMBOLIC_LINK_QUERY,
41 STANDARD_RIGHTS_WRITE,
42 STANDARD_RIGHTS_EXECUTE | SYMBOLIC_LINK_QUERY,
43 SYMBOLIC_LINK_ALL_ACCESS
44 };
45
46 PDEVICE_MAP ObSystemDeviceMap = NULL;
47 ULONG ObpTraceLevel = 0;
48
49 VOID
50 NTAPI
51 PsInitializeQuotaSystem(VOID);
52
53 ULONG ObpInitializationPhase;
54
55 /* PRIVATE FUNCTIONS *********************************************************/
56
57 static
58 NTSTATUS
59 NTAPI
60 INIT_FUNCTION
61 ObpCreateKernelObjectsSD(OUT PSECURITY_DESCRIPTOR *SecurityDescriptor)
62 {
63 PSECURITY_DESCRIPTOR Sd = NULL;
64 PACL Dacl;
65 ULONG AclSize, SdSize;
66 NTSTATUS Status;
67
68 AclSize = sizeof(ACL) +
69 sizeof(ACE) + RtlLengthSid(SeWorldSid) +
70 sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid) +
71 sizeof(ACE) + RtlLengthSid(SeLocalSystemSid);
72
73 SdSize = sizeof(SECURITY_DESCRIPTOR) + AclSize;
74
75 /* Allocate the SD and ACL */
76 Sd = ExAllocatePoolWithTag(PagedPool, SdSize, TAG_SD);
77 if (Sd == NULL)
78 {
79 return STATUS_INSUFFICIENT_RESOURCES;
80 }
81
82 /* Initialize the SD */
83 Status = RtlCreateSecurityDescriptor(Sd,
84 SECURITY_DESCRIPTOR_REVISION);
85 if (!NT_SUCCESS(Status))
86 goto done;
87
88 Dacl = (PACL)((INT_PTR)Sd + sizeof(SECURITY_DESCRIPTOR));
89
90 /* Initialize the DACL */
91 RtlCreateAcl(Dacl, AclSize, ACL_REVISION);
92
93 /* Add the ACEs */
94 RtlAddAccessAllowedAce(Dacl,
95 ACL_REVISION,
96 GENERIC_READ,
97 SeWorldSid);
98
99 RtlAddAccessAllowedAce(Dacl,
100 ACL_REVISION,
101 GENERIC_ALL,
102 SeAliasAdminsSid);
103
104 RtlAddAccessAllowedAce(Dacl,
105 ACL_REVISION,
106 GENERIC_ALL,
107 SeLocalSystemSid);
108
109 /* Attach the DACL to the SD */
110 Status = RtlSetDaclSecurityDescriptor(Sd,
111 TRUE,
112 Dacl,
113 FALSE);
114 if (!NT_SUCCESS(Status))
115 goto done;
116
117 *SecurityDescriptor = Sd;
118
119 done:
120 if (!NT_SUCCESS(Status))
121 {
122 if (Sd != NULL)
123 ExFreePoolWithTag(Sd, TAG_SD);
124 }
125
126 return Status;
127 }
128
129 BOOLEAN
130 INIT_FUNCTION
131 NTAPI
132 ObInit2(VOID)
133 {
134 CCHAR i;
135 PKPRCB Prcb;
136 PGENERAL_LOOKASIDE CurrentList = NULL;
137
138 /* Now allocate the per-processor lists */
139 for (i = 0; i < KeNumberProcessors; i++)
140 {
141 /* Get the PRCB for this CPU */
142 Prcb = KiProcessorBlock[(int)i];
143
144 /* Set the OBJECT_CREATE_INFORMATION List */
145 Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList;
146 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
147 sizeof(GENERAL_LOOKASIDE),
148 'ICbO');
149 if (CurrentList)
150 {
151 /* Initialize it */
152 ExInitializeSystemLookasideList(CurrentList,
153 NonPagedPool,
154 sizeof(OBJECT_CREATE_INFORMATION),
155 'ICbO',
156 32,
157 &ExSystemLookasideListHead);
158 }
159 else
160 {
161 /* No list, use the static buffer */
162 CurrentList = &ObpCreateInfoLookasideList;
163 }
164
165 /* Link it */
166 Prcb->PPLookasideList[LookasideCreateInfoList].P = CurrentList;
167
168 /* Set the captured UNICODE_STRING Object Name List */
169 Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList;
170 CurrentList = ExAllocatePoolWithTag(NonPagedPool,
171 sizeof(GENERAL_LOOKASIDE),
172 'MNbO');
173 if (CurrentList)
174 {
175 /* Initialize it */
176 ExInitializeSystemLookasideList(CurrentList,
177 PagedPool,
178 248,
179 'MNbO',
180 16,
181 &ExSystemLookasideListHead);
182 }
183 else
184 {
185 /* No list, use the static buffer */
186 CurrentList = &ObpNameBufferLookasideList;
187 }
188
189 /* Link it */
190 Prcb->PPLookasideList[LookasideNameBufferList].P = CurrentList;
191 }
192
193 return TRUE;
194 }
195
196 BOOLEAN
197 INIT_FUNCTION
198 NTAPI
199 ObInitSystem(VOID)
200 {
201 OBJECT_ATTRIBUTES ObjectAttributes;
202 UNICODE_STRING Name;
203 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
204 OBP_LOOKUP_CONTEXT Context;
205 HANDLE Handle;
206 PKPRCB Prcb = KeGetCurrentPrcb();
207 PLIST_ENTRY ListHead, NextEntry;
208 POBJECT_HEADER Header;
209 POBJECT_HEADER_CREATOR_INFO CreatorInfo;
210 POBJECT_HEADER_NAME_INFO NameInfo;
211 PSECURITY_DESCRIPTOR KernelObjectsSD = NULL;
212 NTSTATUS Status;
213
214 /* Check if this is actually Phase 1 initialization */
215 if (ObpInitializationPhase != 0) goto ObPostPhase0;
216
217 /* Initialize the OBJECT_CREATE_INFORMATION List */
218 ExInitializeSystemLookasideList(&ObpCreateInfoLookasideList,
219 NonPagedPool,
220 sizeof(OBJECT_CREATE_INFORMATION),
221 'ICbO',
222 32,
223 &ExSystemLookasideListHead);
224
225 /* Set the captured UNICODE_STRING Object Name List */
226 ExInitializeSystemLookasideList(&ObpNameBufferLookasideList,
227 PagedPool,
228 248,
229 'MNbO',
230 16,
231 &ExSystemLookasideListHead);
232
233 /* Temporarily setup both pointers to the shared list */
234 Prcb->PPLookasideList[LookasideCreateInfoList].L = &ObpCreateInfoLookasideList;
235 Prcb->PPLookasideList[LookasideCreateInfoList].P = &ObpCreateInfoLookasideList;
236 Prcb->PPLookasideList[LookasideNameBufferList].L = &ObpNameBufferLookasideList;
237 Prcb->PPLookasideList[LookasideNameBufferList].P = &ObpNameBufferLookasideList;
238
239 /* Initialize the security descriptor cache */
240 ObpInitSdCache();
241
242 /* Initialize the Default Event */
243 KeInitializeEvent(&ObpDefaultObject, NotificationEvent, TRUE);
244
245 /* Initialize the Dos Device Map mutex */
246 KeInitializeGuardedMutex(&ObpDeviceMapLock);
247
248 /* Setup default access for the system process */
249 PsGetCurrentProcess()->GrantedAccess = PROCESS_ALL_ACCESS;
250 PsGetCurrentThread()->GrantedAccess = THREAD_ALL_ACCESS;
251
252 /* Setup the Object Reaper */
253 ExInitializeWorkItem(&ObpReaperWorkItem, ObpReapObject, NULL);
254
255 /* Initialize default Quota block */
256 PsInitializeQuotaSystem();
257
258 /* Create kernel handle table */
259 PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable(NULL);
260 ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable;
261
262 /* Create the Type Type */
263 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
264 RtlInitUnicodeString(&Name, L"Type");
265 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
266 ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
267 ObjectTypeInitializer.UseDefaultObject = TRUE;
268 ObjectTypeInitializer.MaintainTypeList = TRUE;
269 ObjectTypeInitializer.PoolType = NonPagedPool;
270 ObjectTypeInitializer.GenericMapping = ObpTypeMapping;
271 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_TYPE);
272 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
273 ObjectTypeInitializer.DeleteProcedure = ObpDeleteObjectType;
274 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObpTypeObjectType);
275
276 /* Create the Directory Type */
277 RtlInitUnicodeString(&Name, L"Directory");
278 ObjectTypeInitializer.PoolType = PagedPool;
279 ObjectTypeInitializer.ValidAccessMask = DIRECTORY_ALL_ACCESS;
280 ObjectTypeInitializer.CaseInsensitive = TRUE;
281 ObjectTypeInitializer.MaintainTypeList = FALSE;
282 ObjectTypeInitializer.GenericMapping = ObpDirectoryMapping;
283 ObjectTypeInitializer.DeleteProcedure = NULL;
284 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_DIRECTORY);
285 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObpDirectoryObjectType);
286 ObpDirectoryObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;
287
288 /* Create 'symbolic link' object type */
289 RtlInitUnicodeString(&Name, L"SymbolicLink");
290 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(OBJECT_SYMBOLIC_LINK);
291 ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
292 ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
293 ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
294 ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
295 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ObpSymbolicLinkObjectType);
296 ObpSymbolicLinkObjectType->TypeInfo.ValidAccessMask &= ~SYNCHRONIZE;
297
298 /* Phase 0 initialization complete */
299 ObpInitializationPhase++;
300 return TRUE;
301
302 ObPostPhase0:
303
304 /* Re-initialize lookaside lists */
305 ObInit2();
306
307 /* Initialize Object Types directory attributes */
308 RtlInitUnicodeString(&Name, L"\\");
309 InitializeObjectAttributes(&ObjectAttributes,
310 &Name,
311 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
312 NULL,
313 SePublicDefaultUnrestrictedSd);
314
315 /* Create the directory */
316 Status = NtCreateDirectoryObject(&Handle,
317 DIRECTORY_ALL_ACCESS,
318 &ObjectAttributes);
319 if (!NT_SUCCESS(Status)) return FALSE;
320
321 /* Get a handle to it */
322 Status = ObReferenceObjectByHandle(Handle,
323 0,
324 ObpDirectoryObjectType,
325 KernelMode,
326 (PVOID*)&ObpRootDirectoryObject,
327 NULL);
328 if (!NT_SUCCESS(Status)) return FALSE;
329
330 /* Close the extra handle */
331 Status = NtClose(Handle);
332 if (!NT_SUCCESS(Status)) return FALSE;
333
334 /* Create a custom security descriptor for the KernelObjects directory */
335 Status = ObpCreateKernelObjectsSD(&KernelObjectsSD);
336 if (!NT_SUCCESS(Status))
337 return FALSE;
338
339 /* Initialize the KernelObjects directory attributes */
340 RtlInitUnicodeString(&Name, L"\\KernelObjects");
341 InitializeObjectAttributes(&ObjectAttributes,
342 &Name,
343 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
344 NULL,
345 KernelObjectsSD);
346
347 /* Create the directory */
348 Status = NtCreateDirectoryObject(&Handle,
349 DIRECTORY_ALL_ACCESS,
350 &ObjectAttributes);
351 ExFreePoolWithTag(KernelObjectsSD, TAG_SD);
352 if (!NT_SUCCESS(Status)) return FALSE;
353
354 /* Close the extra handle */
355 Status = NtClose(Handle);
356 if (!NT_SUCCESS(Status)) return FALSE;
357
358 /* Initialize ObjectTypes directory attributes */
359 RtlInitUnicodeString(&Name, L"\\ObjectTypes");
360 InitializeObjectAttributes(&ObjectAttributes,
361 &Name,
362 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
363 NULL,
364 NULL);
365
366 /* Create the directory */
367 Status = NtCreateDirectoryObject(&Handle,
368 DIRECTORY_ALL_ACCESS,
369 &ObjectAttributes);
370 if (!NT_SUCCESS(Status)) return FALSE;
371
372 /* Get a handle to it */
373 Status = ObReferenceObjectByHandle(Handle,
374 0,
375 ObpDirectoryObjectType,
376 KernelMode,
377 (PVOID*)&ObpTypeDirectoryObject,
378 NULL);
379 if (!NT_SUCCESS(Status)) return FALSE;
380
381 /* Close the extra handle */
382 Status = NtClose(Handle);
383 if (!NT_SUCCESS(Status)) return FALSE;
384
385 /* Initialize lookup context */
386 ObpInitializeLookupContext(&Context);
387
388 /* Lock it */
389 ObpAcquireDirectoryLockExclusive(ObpTypeDirectoryObject, &Context);
390
391 /* Loop the object types */
392 ListHead = &ObpTypeObjectType->TypeList;
393 NextEntry = ListHead->Flink;
394 while (ListHead != NextEntry)
395 {
396 /* Get the creator info from the list */
397 CreatorInfo = CONTAINING_RECORD(NextEntry,
398 OBJECT_HEADER_CREATOR_INFO,
399 TypeList);
400
401 /* Recover the header and the name header from the creator info */
402 Header = (POBJECT_HEADER)(CreatorInfo + 1);
403 NameInfo = OBJECT_HEADER_TO_NAME_INFO(Header);
404
405 /* Make sure we have a name, and aren't inserted yet */
406 if ((NameInfo) && !(NameInfo->Directory))
407 {
408 /* Do the initial lookup to setup the context */
409 if (!ObpLookupEntryDirectory(ObpTypeDirectoryObject,
410 &NameInfo->Name,
411 OBJ_CASE_INSENSITIVE,
412 FALSE,
413 &Context))
414 {
415 /* Insert this object type */
416 ObpInsertEntryDirectory(ObpTypeDirectoryObject,
417 &Context,
418 Header);
419 }
420 }
421
422 /* Move to the next entry */
423 NextEntry = NextEntry->Flink;
424 }
425
426 /* Cleanup after lookup */
427 ObpReleaseLookupContext(&Context);
428
429 /* Initialize DOS Devices Directory and related Symbolic Links */
430 Status = ObpCreateDosDevicesDirectory();
431 if (!NT_SUCCESS(Status)) return FALSE;
432 return TRUE;
433 }
434
435 /* EOF */