rsaenh: Cast-qual warning fix.
[wine] / dlls / ntdll / om.c
1 /*
2  *      Object management functions
3  *
4  * Copyright 1999, 2000 Juergen Schmied
5  * Copyright 2005 Vitaliy Margolen
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_IO_H
28 # include <io.h>
29 #endif
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #include "ntstatus.h"
35 #define WIN32_NO_STATUS
36 #include "wine/debug.h"
37 #include "windef.h"
38 #include "winternl.h"
39 #include "ntdll_misc.h"
40 #include "wine/server.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
43
44
45 /*
46  *      Generic object functions
47  */
48
49 /******************************************************************************
50  * NtQueryObject [NTDLL.@]
51  * ZwQueryObject [NTDLL.@]
52  */
53 NTSTATUS WINAPI NtQueryObject(IN HANDLE handle,
54                               IN OBJECT_INFORMATION_CLASS info_class,
55                               OUT PVOID ptr, IN ULONG len, OUT PULONG used_len)
56 {
57     NTSTATUS status;
58
59     TRACE("(%p,0x%08x,%p,0x%08x,%p): stub\n",
60           handle, info_class, ptr, len, used_len);
61
62     if (used_len) *used_len = 0;
63
64     switch (info_class)
65     {
66     case ObjectDataInformation:
67         {
68             OBJECT_DATA_INFORMATION* p = (OBJECT_DATA_INFORMATION*)ptr;
69
70             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
71
72             SERVER_START_REQ( set_handle_info )
73             {
74                 req->handle = handle;
75                 req->flags  = 0;
76                 req->mask   = 0;
77                 status = wine_server_call( req );
78                 if (status == STATUS_SUCCESS)
79                 {
80                     p->InheritHandle = (reply->old_flags & HANDLE_FLAG_INHERIT) ? TRUE : FALSE;
81                     p->ProtectFromClose = (reply->old_flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ? TRUE : FALSE;
82                     if (used_len) *used_len = sizeof(*p);
83                 }
84             }
85             SERVER_END_REQ;
86         }
87         break;
88     default:
89         FIXME("Unsupported information class %u\n", info_class);
90         status = STATUS_NOT_IMPLEMENTED;
91         break;
92     }
93     return status;
94 }
95
96 /******************************************************************
97  *              NtSetInformationObject [NTDLL.@]
98  *              ZwSetInformationObject [NTDLL.@]
99  *
100  */
101 NTSTATUS WINAPI NtSetInformationObject(IN HANDLE handle,
102                                        IN OBJECT_INFORMATION_CLASS info_class,
103                                        IN PVOID ptr, IN ULONG len)
104 {
105     NTSTATUS status;
106
107     TRACE("(%p,0x%08x,%p,0x%08x): stub\n",
108           handle, info_class, ptr, len);
109
110     switch (info_class)
111     {
112     case ObjectDataInformation:
113         {
114             OBJECT_DATA_INFORMATION* p = (OBJECT_DATA_INFORMATION*)ptr;
115
116             if (len < sizeof(*p)) return STATUS_INVALID_BUFFER_SIZE;
117
118             SERVER_START_REQ( set_handle_info )
119             {
120                 req->handle = handle;
121                 req->flags  = 0;
122                 req->mask   = HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE;
123                 if (p->InheritHandle)    req->flags |= HANDLE_FLAG_INHERIT;
124                 if (p->ProtectFromClose) req->flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
125                 status = wine_server_call( req );
126             }
127             SERVER_END_REQ;
128         }
129         break;
130     default:
131         FIXME("Unsupported information class %u\n", info_class);
132         status = STATUS_NOT_IMPLEMENTED;
133         break;
134     }
135     return status;
136 }
137
138 /******************************************************************************
139  *  NtQuerySecurityObject       [NTDLL.@]
140  *
141  * An ntdll analogue to GetKernelObjectSecurity().
142  *
143  * NOTES
144  *  only the lowest 4 bit of SecurityObjectInformationClass are used
145  *  0x7-0xf returns STATUS_ACCESS_DENIED (even running with system privileges)
146  *
147  * FIXME
148  *  We are constructing a fake sid (Administrators:Full, System:Full, Everyone:Read)
149  */
150 NTSTATUS WINAPI
151 NtQuerySecurityObject(
152         IN HANDLE Object,
153         IN SECURITY_INFORMATION RequestedInformation,
154         OUT PSECURITY_DESCRIPTOR pSecurityDesriptor,
155         IN ULONG Length,
156         OUT PULONG ResultLength)
157 {
158         static SID_IDENTIFIER_AUTHORITY localSidAuthority = {SECURITY_NT_AUTHORITY};
159         static SID_IDENTIFIER_AUTHORITY worldSidAuthority = {SECURITY_WORLD_SID_AUTHORITY};
160         BYTE Buffer[256];
161         PISECURITY_DESCRIPTOR_RELATIVE psd = (PISECURITY_DESCRIPTOR_RELATIVE)Buffer;
162         UINT BufferIndex = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
163
164         FIXME("(%p,0x%08x,%p,0x%08x,%p) stub!\n",
165         Object, RequestedInformation, pSecurityDesriptor, Length, ResultLength);
166
167         RequestedInformation &= 0x0000000f;
168
169         if (RequestedInformation & SACL_SECURITY_INFORMATION) return STATUS_ACCESS_DENIED;
170
171         ZeroMemory(Buffer, 256);
172         RtlCreateSecurityDescriptor((PSECURITY_DESCRIPTOR)psd, SECURITY_DESCRIPTOR_REVISION);
173         psd->Control = SE_SELF_RELATIVE |
174           ((RequestedInformation & DACL_SECURITY_INFORMATION) ? SE_DACL_PRESENT:0);
175
176         /* owner: administrator S-1-5-20-220*/
177         if (OWNER_SECURITY_INFORMATION & RequestedInformation)
178         {
179           SID* psid = (SID*)&(Buffer[BufferIndex]);
180
181           psd->Owner = BufferIndex;
182           BufferIndex += RtlLengthRequiredSid(2);
183
184           psid->Revision = SID_REVISION;
185           psid->SubAuthorityCount = 2;
186           psid->IdentifierAuthority = localSidAuthority;
187           psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
188           psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
189         }
190
191         /* group: built in domain S-1-5-12 */
192         if (GROUP_SECURITY_INFORMATION & RequestedInformation)
193         {
194           SID* psid = (SID*) &(Buffer[BufferIndex]);
195
196           psd->Group = BufferIndex;
197           BufferIndex += RtlLengthRequiredSid(1);
198
199           psid->Revision = SID_REVISION;
200           psid->SubAuthorityCount = 1;
201           psid->IdentifierAuthority = localSidAuthority;
202           psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
203         }
204
205         /* discretionary ACL */
206         if (DACL_SECURITY_INFORMATION & RequestedInformation)
207         {
208           /* acl header */
209           PACL pacl = (PACL)&(Buffer[BufferIndex]);
210           PACCESS_ALLOWED_ACE pace;
211           SID* psid;
212
213           psd->Dacl = BufferIndex;
214
215           pacl->AclRevision = MIN_ACL_REVISION;
216           pacl->AceCount = 3;
217           pacl->AclSize = BufferIndex; /* storing the start index temporary */
218
219           BufferIndex += sizeof(ACL);
220
221           /* ACE System - full access */
222           pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
223           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
224
225           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
226           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
227           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
228           pace->Mask = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER  | 0x3f;
229           pace->SidStart = BufferIndex;
230
231           /* SID S-1-5-12 (System) */
232           psid = (SID*)&(Buffer[BufferIndex]);
233
234           BufferIndex += RtlLengthRequiredSid(1);
235
236           psid->Revision = SID_REVISION;
237           psid->SubAuthorityCount = 1;
238           psid->IdentifierAuthority = localSidAuthority;
239           psid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
240
241           /* ACE Administrators - full access*/
242           pace = (PACCESS_ALLOWED_ACE) &(Buffer[BufferIndex]);
243           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
244
245           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
246           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
247           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(2);
248           pace->Mask = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER  | 0x3f;
249           pace->SidStart = BufferIndex;
250
251           /* S-1-5-12 (Administrators) */
252           psid = (SID*)&(Buffer[BufferIndex]);
253
254           BufferIndex += RtlLengthRequiredSid(2);
255
256           psid->Revision = SID_REVISION;
257           psid->SubAuthorityCount = 2;
258           psid->IdentifierAuthority = localSidAuthority;
259           psid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID;
260           psid->SubAuthority[1] = DOMAIN_ALIAS_RID_ADMINS;
261
262           /* ACE Everyone - read access */
263           pace = (PACCESS_ALLOWED_ACE)&(Buffer[BufferIndex]);
264           BufferIndex += sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD);
265
266           pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
267           pace->Header.AceFlags = CONTAINER_INHERIT_ACE;
268           pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + RtlLengthRequiredSid(1);
269           pace->Mask = READ_CONTROL| 0x19;
270           pace->SidStart = BufferIndex;
271
272           /* SID S-1-1-0 (Everyone) */
273           psid = (SID*)&(Buffer[BufferIndex]);
274
275           BufferIndex += RtlLengthRequiredSid(1);
276
277           psid->Revision = SID_REVISION;
278           psid->SubAuthorityCount = 1;
279           psid->IdentifierAuthority = worldSidAuthority;
280           psid->SubAuthority[0] = 0;
281
282           /* calculate used bytes */
283           pacl->AclSize = BufferIndex - pacl->AclSize;
284         }
285         *ResultLength = BufferIndex;
286         TRACE("len=%u\n", *ResultLength);
287         if (Length < *ResultLength) return STATUS_BUFFER_TOO_SMALL;
288         memcpy(pSecurityDesriptor, Buffer, *ResultLength);
289
290         return STATUS_SUCCESS;
291 }
292
293
294 /******************************************************************************
295  *  NtDuplicateObject           [NTDLL.@]
296  *  ZwDuplicateObject           [NTDLL.@]
297  */
298 NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source,
299                                    HANDLE dest_process, PHANDLE dest,
300                                    ACCESS_MASK access, ULONG attributes, ULONG options )
301 {
302     NTSTATUS ret;
303     SERVER_START_REQ( dup_handle )
304     {
305         req->src_process = source_process;
306         req->src_handle  = source;
307         req->dst_process = dest_process;
308         req->access      = access;
309         req->attributes  = attributes;
310         req->options     = options;
311
312         if (!(ret = wine_server_call( req )))
313         {
314             if (dest) *dest = reply->handle;
315             if (reply->closed)
316                 server_remove_fd_from_cache( source );
317             else if (options & DUPLICATE_CLOSE_SOURCE)
318                 WARN( "failed to close handle %p in process %p\n", source, source_process );
319         }
320     }
321     SERVER_END_REQ;
322     return ret;
323 }
324
325 /**************************************************************************
326  *                 NtClose                              [NTDLL.@]
327  *
328  * Close a handle reference to an object.
329  * 
330  * PARAMS
331  *  Handle [I] handle to close
332  *
333  * RETURNS
334  *  Success: ERROR_SUCCESS.
335  *  Failure: An NTSTATUS error code.
336  */
337 NTSTATUS WINAPI NtClose( HANDLE Handle )
338 {
339     NTSTATUS ret;
340     SERVER_START_REQ( close_handle )
341     {
342         req->handle = Handle;
343         ret = wine_server_call( req );
344         if (!ret) server_remove_fd_from_cache( Handle );
345     }
346     SERVER_END_REQ;
347     return ret;
348 }
349
350 /*
351  *      Directory functions
352  */
353
354 /**************************************************************************
355  * NtOpenDirectoryObject [NTDLL.@]
356  * ZwOpenDirectoryObject [NTDLL.@]
357  *
358  * Open a namespace directory object.
359  * 
360  * PARAMS
361  *  DirectoryHandle  [O] Destination for the new directory handle
362  *  DesiredAccess    [I] Desired access to the directory
363  *  ObjectAttributes [I] Structure describing the directory
364  *
365  * RETURNS
366  *  Success: ERROR_SUCCESS.
367  *  Failure: An NTSTATUS error code.
368  */
369 NTSTATUS WINAPI NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
370                                       POBJECT_ATTRIBUTES ObjectAttributes)
371 {
372     NTSTATUS ret;
373     TRACE("(%p,0x%08x)\n", DirectoryHandle, DesiredAccess);
374     dump_ObjectAttributes(ObjectAttributes);
375
376     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
377     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
378     /* Have to test it here because server won't know difference between
379      * ObjectName == NULL and ObjectName == "" */
380     if (!ObjectAttributes->ObjectName)
381     {
382         if (ObjectAttributes->RootDirectory)
383             return STATUS_OBJECT_NAME_INVALID;
384         else
385             return STATUS_OBJECT_PATH_SYNTAX_BAD;
386     }
387
388     SERVER_START_REQ(open_directory)
389     {
390         req->access = DesiredAccess;
391         req->attributes = ObjectAttributes->Attributes;
392         req->rootdir = ObjectAttributes->RootDirectory;
393         if (ObjectAttributes->ObjectName)
394             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
395                                  ObjectAttributes->ObjectName->Length);
396         ret = wine_server_call( req );
397         *DirectoryHandle = reply->handle;
398     }
399     SERVER_END_REQ;
400     return ret;
401 }
402
403 /******************************************************************************
404  *  NtCreateDirectoryObject     [NTDLL.@]
405  *  ZwCreateDirectoryObject     [NTDLL.@]
406  *
407  * Create a namespace directory object.
408  * 
409  * PARAMS
410  *  DirectoryHandle  [O] Destination for the new directory handle
411  *  DesiredAccess    [I] Desired access to the directory
412  *  ObjectAttributes [I] Structure describing the directory
413  *
414  * RETURNS
415  *  Success: ERROR_SUCCESS.
416  *  Failure: An NTSTATUS error code.
417  */
418 NTSTATUS WINAPI NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess,
419                                         POBJECT_ATTRIBUTES ObjectAttributes)
420 {
421     NTSTATUS ret;
422     TRACE("(%p,0x%08x)\n", DirectoryHandle, DesiredAccess);
423     dump_ObjectAttributes(ObjectAttributes);
424
425     if (!DirectoryHandle) return STATUS_ACCESS_VIOLATION;
426
427     SERVER_START_REQ(create_directory)
428     {
429         req->access = DesiredAccess;
430         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
431         req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0;
432         if (ObjectAttributes && ObjectAttributes->ObjectName)
433             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
434                                  ObjectAttributes->ObjectName->Length);
435         ret = wine_server_call( req );
436         *DirectoryHandle = reply->handle;
437     }
438     SERVER_END_REQ;
439     return ret;
440 }
441
442 /******************************************************************************
443  * NtQueryDirectoryObject [NTDLL.@]
444  * ZwQueryDirectoryObject [NTDLL.@]
445  *
446  * Read information from a namespace directory.
447  * 
448  * PARAMS
449  *  DirectoryHandle   [I]   Handle to a directory object
450  *  Buffer            [O]   Buffer to hold the read data
451  *  BufferLength      [I]   Size of the buffer in bytes
452  *  ReturnSingleEntry [I]   If TRUE, return a single entry, if FALSE, return as many as fit in the buffer
453  *  RestartScan       [I]   If TRUE, start scanning from the start, if FALSE, scan from Context
454  *  Context           [I/O] Indicates what point of the directory the scan is at
455  *  ReturnLength      [O]   Caller supplied storage for the number of bytes written (or NULL)
456  *
457  * RETURNS
458  *  Success: ERROR_SUCCESS.
459  *  Failure: An NTSTATUS error code.
460  */
461 NTSTATUS WINAPI NtQueryDirectoryObject(IN HANDLE DirectoryHandle, OUT PDIRECTORY_BASIC_INFORMATION Buffer,
462                                        IN ULONG BufferLength, IN BOOLEAN ReturnSingleEntry, IN BOOLEAN RestartScan,
463                                        IN OUT PULONG Context, OUT PULONG ReturnLength OPTIONAL)
464 {
465     FIXME("(%p,%p,0x%08x,0x%08x,0x%08x,%p,%p), stub\n", DirectoryHandle, Buffer, BufferLength, ReturnSingleEntry,
466           RestartScan, Context, ReturnLength);
467
468     return STATUS_NOT_IMPLEMENTED;
469 }
470
471 /*
472  *      Link objects
473  */
474
475 /******************************************************************************
476  *  NtOpenSymbolicLinkObject    [NTDLL.@]
477  *  ZwOpenSymbolicLinkObject    [NTDLL.@]
478  *
479  * Open a namespace symbolic link object.
480  * 
481  * PARAMS
482  *  LinkHandle       [O] Destination for the new symbolic link handle
483  *  DesiredAccess    [I] Desired access to the symbolic link
484  *  ObjectAttributes [I] Structure describing the symbolic link
485  *
486  * RETURNS
487  *  Success: ERROR_SUCCESS.
488  *  Failure: An NTSTATUS error code.
489  */
490 NTSTATUS WINAPI NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, IN ACCESS_MASK DesiredAccess,
491                                          IN POBJECT_ATTRIBUTES ObjectAttributes)
492 {
493     NTSTATUS ret;
494     TRACE("(%p,0x%08x,%p)\n",LinkHandle, DesiredAccess, ObjectAttributes);
495     dump_ObjectAttributes(ObjectAttributes);
496
497     if (!LinkHandle) return STATUS_ACCESS_VIOLATION;
498     if (!ObjectAttributes) return STATUS_INVALID_PARAMETER;
499     /* Have to test it here because server won't know difference between
500      * ObjectName == NULL and ObjectName == "" */
501     if (!ObjectAttributes->ObjectName)
502     {
503         if (ObjectAttributes->RootDirectory)
504             return STATUS_OBJECT_NAME_INVALID;
505         else
506             return STATUS_OBJECT_PATH_SYNTAX_BAD;
507     }
508
509     SERVER_START_REQ(open_symlink)
510     {
511         req->access = DesiredAccess;
512         req->attributes = ObjectAttributes->Attributes;
513         req->rootdir = ObjectAttributes->RootDirectory;
514         if (ObjectAttributes->ObjectName)
515             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
516                                  ObjectAttributes->ObjectName->Length);
517         ret = wine_server_call( req );
518         *LinkHandle = reply->handle;
519     }
520     SERVER_END_REQ;
521     return ret;
522 }
523
524 /******************************************************************************
525  *  NtCreateSymbolicLinkObject  [NTDLL.@]
526  *  ZwCreateSymbolicLinkObject  [NTDLL.@]
527  *
528  * Open a namespace symbolic link object.
529  * 
530  * PARAMS
531  *  SymbolicLinkHandle [O] Destination for the new symbolic link handle
532  *  DesiredAccess      [I] Desired access to the symbolic link
533  *  ObjectAttributes   [I] Structure describing the symbolic link
534  *  TargetName         [I] Name of the target symbolic link points to
535  *
536  * RETURNS
537  *  Success: ERROR_SUCCESS.
538  *  Failure: An NTSTATUS error code.
539  */
540 NTSTATUS WINAPI NtCreateSymbolicLinkObject(OUT PHANDLE SymbolicLinkHandle,IN ACCESS_MASK DesiredAccess,
541                                            IN POBJECT_ATTRIBUTES ObjectAttributes,
542                                            IN PUNICODE_STRING TargetName)
543 {
544     NTSTATUS ret;
545     TRACE("(%p,0x%08x,%p, -> %s)\n", SymbolicLinkHandle, DesiredAccess, ObjectAttributes,
546                                       debugstr_us(TargetName));
547     dump_ObjectAttributes(ObjectAttributes);
548
549     if (!SymbolicLinkHandle || !TargetName) return STATUS_ACCESS_VIOLATION;
550     if (!TargetName->Buffer) return STATUS_INVALID_PARAMETER;
551
552     SERVER_START_REQ(create_symlink)
553     {
554         req->access = DesiredAccess;
555         req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
556         req->rootdir = ObjectAttributes ? ObjectAttributes->RootDirectory : 0;
557         if (ObjectAttributes->ObjectName)
558         {
559             req->name_len = ObjectAttributes->ObjectName->Length;
560             wine_server_add_data(req, ObjectAttributes->ObjectName->Buffer,
561                                  ObjectAttributes->ObjectName->Length);
562         }
563         else
564             req->name_len = 0;
565         wine_server_add_data(req, TargetName->Buffer, TargetName->Length);
566         ret = wine_server_call( req );
567         *SymbolicLinkHandle = reply->handle;
568     }
569     SERVER_END_REQ;
570     return ret;
571 }
572
573 /******************************************************************************
574  *  NtQuerySymbolicLinkObject   [NTDLL.@]
575  *  ZwQuerySymbolicLinkObject   [NTDLL.@]
576  *
577  * Query a namespace symbolic link object target name.
578  * 
579  * PARAMS
580  *  LinkHandle     [I] Handle to a symbolic link object
581  *  LinkTarget     [O] Destination for the symbolic link target
582  *  ReturnedLength [O] Size of returned data
583  *
584  * RETURNS
585  *  Success: ERROR_SUCCESS.
586  *  Failure: An NTSTATUS error code.
587  */
588 NTSTATUS WINAPI NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, IN OUT PUNICODE_STRING LinkTarget,
589                                           OUT PULONG ReturnedLength OPTIONAL)
590 {
591     NTSTATUS ret;
592     TRACE("(%p,%p,%p)\n", LinkHandle, LinkTarget, ReturnedLength);
593
594     if (!LinkTarget) return STATUS_ACCESS_VIOLATION;
595
596     SERVER_START_REQ(query_symlink)
597     {
598         req->handle = LinkHandle;
599         wine_server_set_reply( req, LinkTarget->Buffer, LinkTarget->MaximumLength );
600         if (!(ret = wine_server_call( req )))
601         {
602             LinkTarget->Length = wine_server_reply_size(reply);
603             if (ReturnedLength) *ReturnedLength = LinkTarget->Length;
604         }
605     }
606     SERVER_END_REQ;
607     return ret;
608 }
609
610 /******************************************************************************
611  *  NtAllocateUuids   [NTDLL.@]
612  */
613 NTSTATUS WINAPI NtAllocateUuids(
614         PULARGE_INTEGER Time,
615         PULONG Range,
616         PULONG Sequence)
617 {
618         FIXME("(%p,%p,%p), stub.\n", Time, Range, Sequence);
619         return 0;
620 }