Merge 15268:15329 from trunk
[reactos.git] / reactos / ntoskrnl / ob / symlink.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ob/symlink.c
6 * PURPOSE: Implements symbolic links
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17
18 /* GLOBALS ******************************************************************/
19
20 POBJECT_TYPE ObSymbolicLinkType = NULL;
21
22 static GENERIC_MAPPING ObpSymbolicLinkMapping = {
23 STANDARD_RIGHTS_READ|SYMBOLIC_LINK_QUERY,
24 STANDARD_RIGHTS_WRITE,
25 STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY,
26 SYMBOLIC_LINK_ALL_ACCESS};
27
28 #define TAG_SYMLINK_TTARGET TAG('S', 'Y', 'T', 'T')
29 #define TAG_SYMLINK_TARGET TAG('S', 'Y', 'M', 'T')
30
31
32 /* FUNCTIONS ****************************************************************/
33
34 /**********************************************************************
35 * NAME INTERNAL
36 * ObpDeleteSymbolicLink
37 *
38 * DESCRIPTION
39 *
40 * ARGUMENTS
41 *
42 * RETURNN VALUE
43 * Status.
44 *
45 * REVISIONS
46 */
47 VOID STDCALL
48 ObpDeleteSymbolicLink(PVOID ObjectBody)
49 {
50 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT)ObjectBody;
51
52 ExFreePool(SymlinkObject->TargetName.Buffer);
53 }
54
55
56 /**********************************************************************
57 * NAME INTERNAL
58 * ObpParseSymbolicLink
59 *
60 * DESCRIPTION
61 *
62 * ARGUMENTS
63 *
64 * RETURN VALUE
65 *
66 * REVISIONS
67 */
68 NTSTATUS STDCALL
69 ObpParseSymbolicLink(PVOID Object,
70 PVOID * NextObject,
71 PUNICODE_STRING FullPath,
72 PWSTR * RemainingPath,
73 ULONG Attributes)
74 {
75 PSYMLINK_OBJECT SymlinkObject = (PSYMLINK_OBJECT) Object;
76 UNICODE_STRING TargetPath;
77
78 DPRINT("ObpParseSymbolicLink (RemainingPath %S)\n", *RemainingPath);
79
80 /*
81 * Stop parsing if the entire path has been parsed and
82 * the desired object is a symbolic link object.
83 */
84 if (((*RemainingPath == NULL) || (**RemainingPath == 0)) &&
85 (Attributes & OBJ_OPENLINK))
86 {
87 DPRINT("Parsing stopped!\n");
88 *NextObject = NULL;
89 return(STATUS_SUCCESS);
90 }
91
92 /* build the expanded path */
93 TargetPath.MaximumLength = SymlinkObject->TargetName.Length + sizeof(WCHAR);
94 if (RemainingPath && *RemainingPath)
95 {
96 TargetPath.MaximumLength += (wcslen(*RemainingPath) * sizeof(WCHAR));
97 }
98 TargetPath.Length = TargetPath.MaximumLength - sizeof(WCHAR);
99 TargetPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
100 TargetPath.MaximumLength,
101 TAG_SYMLINK_TTARGET);
102 wcscpy(TargetPath.Buffer, SymlinkObject->TargetName.Buffer);
103 if (RemainingPath && *RemainingPath)
104 {
105 wcscat(TargetPath.Buffer, *RemainingPath);
106 }
107
108 /* transfer target path buffer into FullPath */
109 ExFreePool(FullPath->Buffer);
110 FullPath->Length = TargetPath.Length;
111 FullPath->MaximumLength = TargetPath.MaximumLength;
112 FullPath->Buffer = TargetPath.Buffer;
113
114 /* reinitialize RemainingPath for reparsing */
115 *RemainingPath = FullPath->Buffer;
116
117 *NextObject = NULL;
118 return STATUS_REPARSE;
119 }
120
121
122 /**********************************************************************
123 * NAME INTERNAL
124 * ObInitSymbolicLinkImplementation
125 *
126 * DESCRIPTION
127 *
128 * ARGUMENTS
129 * None.
130 *
131 * RETURNN VALUE
132 * None.
133 *
134 * REVISIONS
135 */
136 VOID
137 INIT_FUNCTION
138 ObInitSymbolicLinkImplementation (VOID)
139 {
140 UNICODE_STRING Name;
141 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
142
143 DPRINT1("Creating SymLink Object Type\n");
144
145 /* Initialize the Directory type */
146 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
147 RtlInitUnicodeString(&Name, L"SymbolicLink");
148 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
149 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT);
150 ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
151 ObjectTypeInitializer.PoolType = NonPagedPool;
152 ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
153 ObjectTypeInitializer.UseDefaultObject = TRUE;
154 ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
155 ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
156 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObSymbolicLinkType);
157 }
158
159
160 /**********************************************************************
161 * NAME EXPORTED
162 * NtCreateSymbolicLinkObject
163 *
164 * DESCRIPTION
165 *
166 * ARGUMENTS
167 *
168 * RETURN VALUE
169 *
170 * REVISIONS
171 *
172 */
173 NTSTATUS STDCALL
174 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
175 IN ACCESS_MASK DesiredAccess,
176 IN POBJECT_ATTRIBUTES ObjectAttributes,
177 IN PUNICODE_STRING LinkTarget)
178 {
179 HANDLE hLink;
180 PSYMLINK_OBJECT SymbolicLink;
181 UNICODE_STRING CapturedLinkTarget;
182 KPROCESSOR_MODE PreviousMode;
183 NTSTATUS Status = STATUS_SUCCESS;
184
185 PAGED_CODE();
186
187 PreviousMode = ExGetPreviousMode();
188
189 if(PreviousMode != KernelMode)
190 {
191 _SEH_TRY
192 {
193 ProbeForWrite(LinkHandle,
194 sizeof(HANDLE),
195 sizeof(ULONG));
196 }
197 _SEH_HANDLE
198 {
199 Status = _SEH_GetExceptionCode();
200 }
201 _SEH_END;
202
203 if(!NT_SUCCESS(Status))
204 {
205 return Status;
206 }
207 }
208
209 Status = RtlCaptureUnicodeString(&CapturedLinkTarget,
210 PreviousMode,
211 PagedPool,
212 FALSE,
213 LinkTarget);
214 if(!NT_SUCCESS(Status))
215 {
216 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
217 return Status;
218 }
219
220 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
221 LinkHandle,
222 DesiredAccess,
223 ObjectAttributes,
224 &CapturedLinkTarget);
225
226 Status = ObCreateObject(ExGetPreviousMode(),
227 ObSymbolicLinkType,
228 ObjectAttributes,
229 PreviousMode,
230 NULL,
231 sizeof(SYMLINK_OBJECT),
232 0,
233 0,
234 (PVOID*)&SymbolicLink);
235 if (NT_SUCCESS(Status))
236 {
237 SymbolicLink->TargetName.Length = 0;
238 SymbolicLink->TargetName.MaximumLength =
239 ((wcslen(LinkTarget->Buffer) + 1) * sizeof(WCHAR));
240 SymbolicLink->TargetName.Buffer =
241 ExAllocatePoolWithTag(NonPagedPool,
242 SymbolicLink->TargetName.MaximumLength,
243 TAG_SYMLINK_TARGET);
244 RtlCopyUnicodeString(&SymbolicLink->TargetName,
245 &CapturedLinkTarget);
246
247 DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
248
249 ZwQuerySystemTime (&SymbolicLink->CreateTime);
250
251 Status = ObInsertObject ((PVOID)SymbolicLink,
252 NULL,
253 DesiredAccess,
254 0,
255 NULL,
256 &hLink);
257 if (NT_SUCCESS(Status))
258 {
259 _SEH_TRY
260 {
261 *LinkHandle = hLink;
262 }
263 _SEH_HANDLE
264 {
265 Status = _SEH_GetExceptionCode();
266 }
267 _SEH_END;
268 }
269 ObDereferenceObject(SymbolicLink);
270 }
271
272 RtlReleaseCapturedUnicodeString(&CapturedLinkTarget,
273 PreviousMode,
274 FALSE);
275
276 return Status;
277 }
278
279
280 /**********************************************************************
281 * NAME EXPORTED
282 * NtOpenSymbolicLinkObject
283 *
284 * DESCRIPTION
285 *
286 * ARGUMENTS
287 *
288 * RETURN VALUE
289 *
290 * REVISIONS
291 *
292 */
293 NTSTATUS STDCALL
294 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
295 IN ACCESS_MASK DesiredAccess,
296 IN POBJECT_ATTRIBUTES ObjectAttributes)
297 {
298 HANDLE hLink;
299 KPROCESSOR_MODE PreviousMode;
300 NTSTATUS Status = STATUS_SUCCESS;
301
302 PAGED_CODE();
303
304 PreviousMode = ExGetPreviousMode();
305
306 if(PreviousMode != KernelMode)
307 {
308 _SEH_TRY
309 {
310 ProbeForWrite(LinkHandle,
311 sizeof(HANDLE),
312 sizeof(ULONG));
313 }
314 _SEH_HANDLE
315 {
316 Status = _SEH_GetExceptionCode();
317 }
318 _SEH_END;
319
320 if(!NT_SUCCESS(Status))
321 {
322 return Status;
323 }
324 }
325
326 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
327 ObjectAttributes->ObjectName);
328
329 Status = ObOpenObjectByName(ObjectAttributes,
330 ObSymbolicLinkType,
331 NULL,
332 PreviousMode,
333 DesiredAccess,
334 NULL,
335 &hLink);
336 if(NT_SUCCESS(Status))
337 {
338 _SEH_TRY
339 {
340 *LinkHandle = hLink;
341 }
342 _SEH_HANDLE
343 {
344 Status = _SEH_GetExceptionCode();
345 }
346 _SEH_END;
347 }
348
349 return Status;
350 }
351
352
353 /**********************************************************************
354 * NAME EXPORTED
355 * NtQuerySymbolicLinkObject
356 *
357 * DESCRIPTION
358 *
359 * ARGUMENTS
360 *
361 * RETURN VALUE
362 *
363 * REVISIONS
364 *
365 */
366 NTSTATUS STDCALL
367 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
368 OUT PUNICODE_STRING LinkTarget,
369 OUT PULONG ResultLength OPTIONAL)
370 {
371 UNICODE_STRING SafeLinkTarget;
372 PSYMLINK_OBJECT SymlinkObject;
373 KPROCESSOR_MODE PreviousMode;
374 NTSTATUS Status = STATUS_SUCCESS;
375
376 PAGED_CODE();
377
378 PreviousMode = ExGetPreviousMode();
379
380 if(PreviousMode != KernelMode)
381 {
382 _SEH_TRY
383 {
384 /* probe the unicode string and buffers supplied */
385 ProbeForWrite(LinkTarget,
386 sizeof(UNICODE_STRING),
387 sizeof(ULONG));
388 SafeLinkTarget = *LinkTarget;
389 ProbeForWrite(SafeLinkTarget.Buffer,
390 SafeLinkTarget.MaximumLength,
391 sizeof(WCHAR));
392
393 if(ResultLength != NULL)
394 {
395 ProbeForWrite(ResultLength,
396 sizeof(ULONG),
397 sizeof(ULONG));
398 }
399 }
400 _SEH_HANDLE
401 {
402 Status = _SEH_GetExceptionCode();
403 }
404 _SEH_END;
405
406 if(!NT_SUCCESS(Status))
407 {
408 return Status;
409 }
410 }
411 else
412 {
413 SafeLinkTarget = *LinkTarget;
414 }
415
416 Status = ObReferenceObjectByHandle(LinkHandle,
417 SYMBOLIC_LINK_QUERY,
418 ObSymbolicLinkType,
419 PreviousMode,
420 (PVOID *)&SymlinkObject,
421 NULL);
422 if (NT_SUCCESS(Status))
423 {
424 ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR);
425
426 _SEH_TRY
427 {
428 if(SafeLinkTarget.MaximumLength >= LengthRequired)
429 {
430 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
431 might have modified the structure which could lead to a copy into
432 kernel memory! */
433 RtlCopyUnicodeString(&SafeLinkTarget,
434 &SymlinkObject->TargetName);
435 SafeLinkTarget.Buffer[SafeLinkTarget.Length / sizeof(WCHAR)] = L'\0';
436 /* copy back the new UNICODE_STRING structure */
437 *LinkTarget = SafeLinkTarget;
438 }
439 else
440 {
441 Status = STATUS_BUFFER_TOO_SMALL;
442 }
443
444 if(ResultLength != NULL)
445 {
446 *ResultLength = LengthRequired;
447 }
448 }
449 _SEH_HANDLE
450 {
451 Status = _SEH_GetExceptionCode();
452 }
453 _SEH_END;
454
455 ObDereferenceObject(SymlinkObject);
456 }
457
458 return Status;
459 }
460
461 /* EOF */