use the captured link target string length in NtCreateSymbolicLinkObject. Spotted...
[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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, ObInitSymbolicLinkImplementation)
19 #endif
20
21
22 /* GLOBALS ******************************************************************/
23
24 POBJECT_TYPE ObSymbolicLinkType = NULL;
25
26 static GENERIC_MAPPING ObpSymbolicLinkMapping = {
27 STANDARD_RIGHTS_READ|SYMBOLIC_LINK_QUERY,
28 STANDARD_RIGHTS_WRITE,
29 STANDARD_RIGHTS_EXECUTE|SYMBOLIC_LINK_QUERY,
30 SYMBOLIC_LINK_ALL_ACCESS};
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 NTAPI
139 ObInitSymbolicLinkImplementation (VOID)
140 {
141 UNICODE_STRING Name;
142 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
143
144 DPRINT("Creating SymLink Object Type\n");
145
146 /* Initialize the Directory type */
147 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
148 RtlInitUnicodeString(&Name, L"SymbolicLink");
149 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
150 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(SYMLINK_OBJECT);
151 ObjectTypeInitializer.GenericMapping = ObpSymbolicLinkMapping;
152 ObjectTypeInitializer.PoolType = NonPagedPool;
153 ObjectTypeInitializer.ValidAccessMask = SYMBOLIC_LINK_ALL_ACCESS;
154 ObjectTypeInitializer.UseDefaultObject = TRUE;
155 ObjectTypeInitializer.ParseProcedure = ObpParseSymbolicLink;
156 ObjectTypeInitializer.DeleteProcedure = ObpDeleteSymbolicLink;
157 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ObSymbolicLinkType);
158 }
159
160
161 /**********************************************************************
162 * NAME EXPORTED
163 * NtCreateSymbolicLinkObject
164 *
165 * DESCRIPTION
166 *
167 * ARGUMENTS
168 *
169 * RETURN VALUE
170 *
171 * REVISIONS
172 *
173 */
174 NTSTATUS STDCALL
175 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle,
176 IN ACCESS_MASK DesiredAccess,
177 IN POBJECT_ATTRIBUTES ObjectAttributes,
178 IN PUNICODE_STRING LinkTarget)
179 {
180 HANDLE hLink;
181 PSYMLINK_OBJECT SymbolicLink;
182 UNICODE_STRING CapturedLinkTarget;
183 KPROCESSOR_MODE PreviousMode;
184 NTSTATUS Status = STATUS_SUCCESS;
185
186 PAGED_CODE();
187
188 PreviousMode = ExGetPreviousMode();
189
190 if(PreviousMode != KernelMode)
191 {
192 _SEH_TRY
193 {
194 ProbeForWriteHandle(LinkHandle);
195 }
196 _SEH_HANDLE
197 {
198 Status = _SEH_GetExceptionCode();
199 }
200 _SEH_END;
201
202 if(!NT_SUCCESS(Status))
203 {
204 return Status;
205 }
206 }
207
208 Status = ProbeAndCaptureUnicodeString(&CapturedLinkTarget,
209 PreviousMode,
210 LinkTarget);
211 if(!NT_SUCCESS(Status))
212 {
213 DPRINT1("NtCreateSymbolicLinkObject: Capturing the target link failed!\n");
214 return Status;
215 }
216
217 DPRINT("NtCreateSymbolicLinkObject(LinkHandle %p, DesiredAccess %ul, ObjectAttributes %p, LinkTarget %wZ)\n",
218 LinkHandle,
219 DesiredAccess,
220 ObjectAttributes,
221 &CapturedLinkTarget);
222
223 Status = ObCreateObject(ExGetPreviousMode(),
224 ObSymbolicLinkType,
225 ObjectAttributes,
226 PreviousMode,
227 NULL,
228 sizeof(SYMLINK_OBJECT),
229 0,
230 0,
231 (PVOID*)&SymbolicLink);
232 if (NT_SUCCESS(Status))
233 {
234 SymbolicLink->TargetName.Length = 0;
235 SymbolicLink->TargetName.MaximumLength =
236 CapturedLinkTarget.Length + sizeof(WCHAR);
237 SymbolicLink->TargetName.Buffer =
238 ExAllocatePoolWithTag(NonPagedPool,
239 SymbolicLink->TargetName.MaximumLength,
240 TAG_SYMLINK_TARGET);
241 RtlCopyUnicodeString(&SymbolicLink->TargetName,
242 &CapturedLinkTarget);
243
244 DPRINT("DeviceName %S\n", SymbolicLink->TargetName.Buffer);
245
246 ZwQuerySystemTime (&SymbolicLink->CreateTime);
247
248 Status = ObInsertObject ((PVOID)SymbolicLink,
249 NULL,
250 DesiredAccess,
251 0,
252 NULL,
253 &hLink);
254 if (NT_SUCCESS(Status))
255 {
256 _SEH_TRY
257 {
258 *LinkHandle = hLink;
259 }
260 _SEH_HANDLE
261 {
262 Status = _SEH_GetExceptionCode();
263 }
264 _SEH_END;
265 }
266 ObDereferenceObject(SymbolicLink);
267 }
268
269 ReleaseCapturedUnicodeString(&CapturedLinkTarget,
270 PreviousMode);
271
272 return Status;
273 }
274
275
276 /**********************************************************************
277 * NAME EXPORTED
278 * NtOpenSymbolicLinkObject
279 *
280 * DESCRIPTION
281 *
282 * ARGUMENTS
283 *
284 * RETURN VALUE
285 *
286 * REVISIONS
287 *
288 */
289 NTSTATUS STDCALL
290 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle,
291 IN ACCESS_MASK DesiredAccess,
292 IN POBJECT_ATTRIBUTES ObjectAttributes)
293 {
294 HANDLE hLink;
295 KPROCESSOR_MODE PreviousMode;
296 NTSTATUS Status = STATUS_SUCCESS;
297
298 PAGED_CODE();
299
300 PreviousMode = ExGetPreviousMode();
301
302 if(PreviousMode != KernelMode)
303 {
304 _SEH_TRY
305 {
306 ProbeForWriteHandle(LinkHandle);
307 }
308 _SEH_HANDLE
309 {
310 Status = _SEH_GetExceptionCode();
311 }
312 _SEH_END;
313
314 if(!NT_SUCCESS(Status))
315 {
316 return Status;
317 }
318 }
319
320 DPRINT("NtOpenSymbolicLinkObject (Name %wZ)\n",
321 ObjectAttributes->ObjectName);
322
323 Status = ObOpenObjectByName(ObjectAttributes,
324 ObSymbolicLinkType,
325 NULL,
326 PreviousMode,
327 DesiredAccess,
328 NULL,
329 &hLink);
330 if(NT_SUCCESS(Status))
331 {
332 _SEH_TRY
333 {
334 *LinkHandle = hLink;
335 }
336 _SEH_HANDLE
337 {
338 Status = _SEH_GetExceptionCode();
339 }
340 _SEH_END;
341 }
342
343 return Status;
344 }
345
346
347 /**********************************************************************
348 * NAME EXPORTED
349 * NtQuerySymbolicLinkObject
350 *
351 * DESCRIPTION
352 *
353 * ARGUMENTS
354 *
355 * RETURN VALUE
356 *
357 * REVISIONS
358 *
359 */
360 NTSTATUS STDCALL
361 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle,
362 OUT PUNICODE_STRING LinkTarget,
363 OUT PULONG ResultLength OPTIONAL)
364 {
365 UNICODE_STRING SafeLinkTarget;
366 PSYMLINK_OBJECT SymlinkObject;
367 KPROCESSOR_MODE PreviousMode;
368 NTSTATUS Status = STATUS_SUCCESS;
369
370 PAGED_CODE();
371
372 PreviousMode = ExGetPreviousMode();
373
374 if(PreviousMode != KernelMode)
375 {
376 _SEH_TRY
377 {
378 /* probe the unicode string and buffers supplied */
379 ProbeForWrite(LinkTarget,
380 sizeof(UNICODE_STRING),
381 sizeof(ULONG));
382 SafeLinkTarget = *LinkTarget;
383 ProbeForWrite(SafeLinkTarget.Buffer,
384 SafeLinkTarget.MaximumLength,
385 sizeof(WCHAR));
386
387 if(ResultLength != NULL)
388 {
389 ProbeForWriteUlong(ResultLength);
390 }
391 }
392 _SEH_HANDLE
393 {
394 Status = _SEH_GetExceptionCode();
395 }
396 _SEH_END;
397
398 if(!NT_SUCCESS(Status))
399 {
400 return Status;
401 }
402 }
403 else
404 {
405 SafeLinkTarget = *LinkTarget;
406 }
407
408 Status = ObReferenceObjectByHandle(LinkHandle,
409 SYMBOLIC_LINK_QUERY,
410 ObSymbolicLinkType,
411 PreviousMode,
412 (PVOID *)&SymlinkObject,
413 NULL);
414 if (NT_SUCCESS(Status))
415 {
416 ULONG LengthRequired = SymlinkObject->TargetName.Length + sizeof(WCHAR);
417
418 _SEH_TRY
419 {
420 if(SafeLinkTarget.MaximumLength >= LengthRequired)
421 {
422 /* don't pass TargetLink to RtlCopyUnicodeString here because the caller
423 might have modified the structure which could lead to a copy into
424 kernel memory! */
425 RtlCopyUnicodeString(&SafeLinkTarget,
426 &SymlinkObject->TargetName);
427 SafeLinkTarget.Buffer[SafeLinkTarget.Length / sizeof(WCHAR)] = L'\0';
428 /* copy back the new UNICODE_STRING structure */
429 *LinkTarget = SafeLinkTarget;
430 }
431 else
432 {
433 Status = STATUS_BUFFER_TOO_SMALL;
434 }
435
436 if(ResultLength != NULL)
437 {
438 *ResultLength = LengthRequired;
439 }
440 }
441 _SEH_HANDLE
442 {
443 Status = _SEH_GetExceptionCode();
444 }
445 _SEH_END;
446
447 ObDereferenceObject(SymlinkObject);
448 }
449
450 return Status;
451 }
452
453 /* EOF */