[BASESRV]
[reactos.git] / subsystems / win / basesrv / server.c
index f5d0e92..9b6ac02 100644 (file)
-/* $Id$
- *
- * server.c - ReactOS/Win32 base enviroment subsystem server
- *
- * ReactOS Operating System
- *
- * --------------------------------------------------------------------
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * --------------------------------------------------------------------
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS/Win32 base enviroment subsystem server
+ * FILE:            subsystems/win/basesrv/server.c
+ * PURPOSE:         Initialization
+ * PROGRAMMERS:     Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  */
+
 #include "basesrv.h"
 
 #define NDEBUG
 #include <debug.h>
 
-/*=====================================================================
- *     PUBLIC API
- *===================================================================*/
 
-NTSTATUS WINAPI BaseSetProcessCreateNotify (BASE_PROCESS_CREATE_NOTIFY_ROUTINE ProcessCreateNotifyProc)
+// extern NTSTATUS CallProcessCreated(PCSR_PROCESS, PCSR_PROCESS); // TODO: Import it from csrsrv/init.c
+// Remove it and correct csrsrv instead...
+#if 0
+NTSTATUS
+CallProcessCreated(IN PCSR_PROCESS SourceProcessData,
+                   IN PCSR_PROCESS TargetProcessData)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG i;
+    PCSR_SERVER_DLL ServerDll;
+
+    DPRINT("CSR: %s called\n", __FUNCTION__);
+
+    /* Notify the Server DLLs */
+    for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
+    {
+        /* Get the current Server DLL */
+        ServerDll = CsrLoadedServerDll[i];
+
+        /* Make sure it's valid and that it has callback */
+        if ((ServerDll) && (ServerDll->NewProcessCallback))
+        {
+            Status = ServerDll->NewProcessCallback(SourceProcessData, TargetProcessData);
+        }
+    }
+
+    return Status;
+}
+#endif
+
+CSR_API(BaseSrvCreateProcess)
+{
+    NTSTATUS Status;
+    PBASE_CREATE_PROCESS CreateProcessRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CreateProcessRequest;
+    HANDLE ProcessHandle, ThreadHandle;
+    PCSR_THREAD CsrThread;
+    PCSR_PROCESS Process; // , NewProcess;
+    ULONG /* Flags, */ VdmPower = 0, DebugFlags = 0;
+
+    /* Get the current client thread */
+    CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread != NULL);
+
+    Process = CsrThread->Process;
+
+    /* Extract the flags out of the process handle */
+    // Flags = (ULONG_PTR)CreateProcessRequest->ProcessHandle & 3;
+    CreateProcessRequest->ProcessHandle = (HANDLE)((ULONG_PTR)CreateProcessRequest->ProcessHandle & ~3);
+
+    /* Duplicate the process handle */
+    Status = NtDuplicateObject(Process->ProcessHandle,
+                               CreateProcessRequest->ProcessHandle,
+                               NtCurrentProcess(),
+                               &ProcessHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to duplicate process handle\n");
+        return Status;
+    }
+
+    /* Duplicate the thread handle */
+    Status = NtDuplicateObject(Process->ProcessHandle,
+                               CreateProcessRequest->ThreadHandle,
+                               NtCurrentProcess(),
+                               &ThreadHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to duplicate process handle\n");
+        NtClose(ProcessHandle);
+        return Status;
+    }
+
+    /* See if this is a VDM process */
+    if (VdmPower)
+    {
+        /* Request VDM powers */
+        Status = NtSetInformationProcess(ProcessHandle,
+                                         ProcessWx86Information,
+                                         &VdmPower,
+                                         sizeof(VdmPower));
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("Failed to get VDM powers\n");
+            NtClose(ProcessHandle);
+            NtClose(ThreadHandle);
+            return Status;
+        }
+    }
+
+    /* Convert some flags. FIXME: More need conversion */
+    if (CreateProcessRequest->CreationFlags & CREATE_NEW_PROCESS_GROUP)
+    {
+        DebugFlags |= CsrProcessCreateNewGroup;
+    }
+
+    /* FIXME: SxS Stuff */
+
+    /* Call CSRSRV to create the CSR_PROCESS structure and the first CSR_THREAD */
+    Status = CsrCreateProcess(ProcessHandle,
+                              ThreadHandle,
+                              &CreateProcessRequest->ClientId,
+                              Process->NtSession,
+                              DebugFlags,
+                              NULL);
+    if (Status == STATUS_THREAD_IS_TERMINATING)
+    {
+        DPRINT1("Thread already dead\n");
+        return Status;
+    }
+
+    /* Check for other failures */
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to create process/thread structures: %lx\n", Status);
+        return Status;
+    }
+
+    /* FIXME: Should notify user32 */
+
+    /* FIXME: VDM vodoo */
+
+    /* ReactOS Compatibility */
+#if 0
+    Status = CsrLockProcessByClientId(CreateProcessRequest->ClientId.UniqueProcess, &NewProcess);
+    ASSERT(Status == STATUS_SUCCESS);
+    if (!(CreateProcessRequest->CreationFlags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
+    {
+        NewProcess->ParentConsole = Process->Console;
+        NewProcess->bInheritHandles = CreateProcessRequest->bInheritHandles;
+    }
+    RtlInitializeCriticalSection(&NewProcess->HandleTableLock);
+    CallProcessCreated(Process, NewProcess);
+    CsrUnlockProcess(NewProcess);
+#endif
+
+    /* Return the result of this operation */
+    return Status;
+}
+
+CSR_API(BaseSrvCreateThread)
+{
+    NTSTATUS Status;
+    PBASE_CREATE_THREAD CreateThreadRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.CreateThreadRequest;
+    PCSR_THREAD CurrentThread;
+    HANDLE ThreadHandle;
+    PCSR_PROCESS CsrProcess;
+
+    /* Get the current CSR thread */
+    CurrentThread = CsrGetClientThread();
+    if (!CurrentThread)
+    {
+        DPRINT1("Server Thread TID: [%lx.%lx]\n",
+        CreateThreadRequest->ClientId.UniqueProcess,
+        CreateThreadRequest->ClientId.UniqueThread);
+        return STATUS_SUCCESS; // server-to-server
+    }
+
+    /* Get the CSR Process for this request */
+    CsrProcess = CurrentThread->Process;
+    if (CsrProcess->ClientId.UniqueProcess !=
+        CreateThreadRequest->ClientId.UniqueProcess)
+    {
+        /* This is a remote thread request -- is it within the server itself? */
+        if (CreateThreadRequest->ClientId.UniqueProcess == NtCurrentTeb()->ClientId.UniqueProcess)
+        {
+            /* Accept this without any further work */
+            return STATUS_SUCCESS;
+        }
+
+        /* Get the real CSR Process for the remote thread's process */
+        Status = CsrLockProcessByClientId(CreateThreadRequest->ClientId.UniqueProcess,
+                                          &CsrProcess);
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Duplicate the thread handle so we can own it */
+    Status = NtDuplicateObject(CurrentThread->Process->ProcessHandle,
+                               CreateThreadRequest->ThreadHandle,
+                               NtCurrentProcess(),
+                               &ThreadHandle,
+                               0,
+                               0,
+                               DUPLICATE_SAME_ACCESS);
+    if (NT_SUCCESS(Status))
+    {
+        /* Call CSRSRV to tell it about the new thread */
+        Status = CsrCreateThread(CsrProcess,
+                                 ThreadHandle,
+                                 &CreateThreadRequest->ClientId);
+    }
+
+    /* Unlock the process and return */
+    if (CsrProcess != CurrentThread->Process) CsrUnlockProcess(CsrProcess);
+    return Status;
+}
+
+CSR_API(BaseSrvGetTempFile)
+{
+    static UINT CsrGetTempFileUnique = 0;
+    PBASE_GET_TEMP_FILE GetTempFile = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetTempFile;
+
+    /* Return 16-bits ID */
+    GetTempFile->UniqueID = (++CsrGetTempFileUnique & 0xFFFF);
+
+    DPRINT("Returning: %u\n", GetTempFile->UniqueID);
+
+    return STATUS_SUCCESS;
+}
+
+CSR_API(BaseSrvExitProcess)
+{
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread != NULL);
+
+    /* Set magic flag so we don't reply this message back */
+    ApiMessage->ApiNumber = 0xBABE;
+
+    /* Remove the CSR_THREADs and CSR_PROCESS */
+    return CsrDestroyProcess(&CsrThread->ClientId,
+                             (NTSTATUS)((PBASE_API_MESSAGE)ApiMessage)->Data.ExitProcessRequest.uExitCode);
+}
+
+CSR_API(BaseSrvGetProcessShutdownParam)
+{
+    PBASE_GET_PROCESS_SHUTDOWN_PARAMS GetShutdownParametersRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.GetShutdownParametersRequest;
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread);
+
+    GetShutdownParametersRequest->Level = CsrThread->Process->ShutdownLevel;
+    GetShutdownParametersRequest->Flags = CsrThread->Process->ShutdownFlags;
+
+    return STATUS_SUCCESS;
+}
+
+CSR_API(BaseSrvSetProcessShutdownParam)
+{
+    PBASE_SET_PROCESS_SHUTDOWN_PARAMS SetShutdownParametersRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.SetShutdownParametersRequest;
+    PCSR_THREAD CsrThread = CsrGetClientThread();
+    ASSERT(CsrThread);
+
+    CsrThread->Process->ShutdownLevel = SetShutdownParametersRequest->Level;
+    CsrThread->Process->ShutdownFlags = SetShutdownParametersRequest->Flags;
+
+    return STATUS_SUCCESS;
+}
+
+
+/***
+ *** Sound sentry
+ ***/
+
+typedef BOOL (WINAPI *PUSER_SOUND_SENTRY)(VOID);
+BOOL NTAPI FirstSoundSentry(VOID);
+
+PUSER_SOUND_SENTRY _UserSoundSentry = FirstSoundSentry;
+
+BOOL
+NTAPI
+FailSoundSentry(VOID)
+{
+    /* In case the function can't be found/is unimplemented */
+    return FALSE;
+}
+
+BOOL
+NTAPI
+FirstSoundSentry(VOID)
+{
+    UNICODE_STRING DllString = RTL_CONSTANT_STRING(L"winsrv");
+    STRING FuncString = RTL_CONSTANT_STRING("_UserSoundSentry");
+    HANDLE DllHandle;
+    NTSTATUS Status;
+    PUSER_SOUND_SENTRY NewSoundSentry = FailSoundSentry;
+
+    /* Load winsrv manually */
+    Status = LdrGetDllHandle(NULL, NULL, &DllString, &DllHandle);
+    if (NT_SUCCESS(Status))
+    {
+        /* If it was found, get SoundSentry export */
+        Status = LdrGetProcedureAddress(DllHandle,
+                                        &FuncString,
+                                        0,
+                                        (PVOID*)&NewSoundSentry);
+    }
+    
+    /* Set it as the callback for the future, and call it */
+    _UserSoundSentry = NewSoundSentry;
+    return _UserSoundSentry();
+}
+
+CSR_API(BaseSrvSoundSentryNotification)
+{
+    /* Call the API and see if it succeeds */
+    return _UserSoundSentry() ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+}
+
+
+/***
+ *** Dos Devices (C) Pierre Schweitzer (pierre.schweitzer@reactos.org)
+ ***/
+
+typedef struct tagBASE_DOS_DEVICE_HISTORY_ENTRY
+{
+    UNICODE_STRING Device;
+    UNICODE_STRING Target;
+    LIST_ENTRY Entry;
+} BASE_DOS_DEVICE_HISTORY_ENTRY, *PBASE_DOS_DEVICE_HISTORY_ENTRY;
+
+LIST_ENTRY DosDeviceHistory;
+RTL_CRITICAL_SECTION BaseDefineDosDeviceCritSec;
+
+VOID BaseCleanupDefineDosDevice(VOID)
+{
+    PLIST_ENTRY Entry, ListHead;
+    PBASE_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
+
+    (void) RtlDeleteCriticalSection(&BaseDefineDosDeviceCritSec);
+
+    ListHead = &DosDeviceHistory;
+    Entry = ListHead->Flink;
+    while (Entry != ListHead)
+    {
+        HistoryEntry = (PBASE_DOS_DEVICE_HISTORY_ENTRY)
+            CONTAINING_RECORD(Entry,
+                              BASE_DOS_DEVICE_HISTORY_ENTRY,
+                              Entry);
+        Entry = Entry->Flink;
+
+        if (HistoryEntry)
+        {
+            if (HistoryEntry->Target.Buffer)
+                (void) RtlFreeHeap(BaseSrvHeap,
+                                   0,
+                                   HistoryEntry->Target.Buffer);
+            if (HistoryEntry->Device.Buffer)
+                (void) RtlFreeHeap(BaseSrvHeap,
+                                   0,
+                                   HistoryEntry->Device.Buffer);
+            (void) RtlFreeHeap(BaseSrvHeap,
+                               0,
+                               HistoryEntry);
+        }
+    }
+}
+
+CSR_API(BaseSrvDefineDosDevice)
 {
-       NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &((PBASE_API_MESSAGE)ApiMessage)->Data.DefineDosDeviceRequest;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    HANDLE LinkHandle = NULL;
+    UNICODE_STRING DeviceName = {0};
+    UNICODE_STRING RequestDeviceName = {0};
+    UNICODE_STRING LinkTarget = {0};
+    PUNICODE_STRING RequestLinkTarget;
+    ULONG Length;
+    SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY};
+    SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
+    PSECURITY_DESCRIPTOR SecurityDescriptor;
+    PACL Dacl;
+    PSID AdminSid;
+    PSID SystemSid;
+    PSID WorldSid;
+    ULONG SidLength;
+    PBASE_DOS_DEVICE_HISTORY_ENTRY HistoryEntry;
+    PLIST_ENTRY Entry;
+    PLIST_ENTRY ListHead;
+    BOOLEAN Matched, AddHistory;
+    DWORD dwFlags;
+    PWSTR lpBuffer;
+
+    DPRINT("CsrDefineDosDevice entered, Flags:%d, DeviceName:%wZ, TargetName:%wZ\n",
+           DefineDosDeviceRequest->dwFlags,
+           &DefineDosDeviceRequest->DeviceName,
+           &DefineDosDeviceRequest->TargetName);
+
+    Matched = AddHistory = FALSE;
+    HistoryEntry = NULL;
+    AdminSid = SystemSid = WorldSid = NULL;
+    SecurityDescriptor = NULL;
+    ListHead = &DosDeviceHistory;
+    dwFlags = DefineDosDeviceRequest->dwFlags;
+
+    /* Validate the flags */
+    if ( (dwFlags & 0xFFFFFFF0) ||
+        ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) &&
+            ! (dwFlags & DDD_REMOVE_DEFINITION)) )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = RtlEnterCriticalSection(&BaseDefineDosDeviceCritSec);
+    if (! NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlEnterCriticalSection() failed (Status %lx)\n",
+                Status);
+        return Status;
+    }
+
+    _SEH2_TRY
+    {
+        Status =
+            RtlUpcaseUnicodeString(&RequestDeviceName,
+                                   &DefineDosDeviceRequest->DeviceName,
+                                   TRUE);
+        if (! NT_SUCCESS(Status))
+            _SEH2_LEAVE;
+
+        RequestLinkTarget = &DefineDosDeviceRequest->TargetName;
+        lpBuffer = (PWSTR) RtlAllocateHeap(BaseSrvHeap,
+                                           HEAP_ZERO_MEMORY,
+                                           RequestDeviceName.MaximumLength + 5 * sizeof(WCHAR));
+        if (! lpBuffer)
+        {
+            DPRINT1("Failed to allocate memory\n");
+            Status = STATUS_NO_MEMORY;
+            _SEH2_LEAVE;
+        }
+
+        swprintf(lpBuffer,
+                 L"\\??\\%wZ",
+                 &RequestDeviceName);
+        RtlInitUnicodeString(&DeviceName,
+                             lpBuffer);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &DeviceName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   NULL,
+                                   NULL);
+        Status = NtOpenSymbolicLinkObject(&LinkHandle,
+                                          DELETE | 0x1,
+                                          &ObjectAttributes);
+        if (NT_SUCCESS(Status))
+        {
+            Status = NtQuerySymbolicLinkObject(LinkHandle,
+                                               &LinkTarget,
+                                               &Length);
+            if (! NT_SUCCESS(Status) &&
+                Status == STATUS_BUFFER_TOO_SMALL)
+            {
+                LinkTarget.Length = 0;
+                LinkTarget.MaximumLength = Length;
+                LinkTarget.Buffer = (PWSTR)
+                    RtlAllocateHeap(BaseSrvHeap,
+                                    HEAP_ZERO_MEMORY,
+                                    Length);
+                if (! LinkTarget.Buffer)
+                {
+                    DPRINT1("Failed to allocate memory\n");
+                    Status = STATUS_NO_MEMORY;
+                    _SEH2_LEAVE;
+                }
+
+                Status = NtQuerySymbolicLinkObject(LinkHandle,
+                                                   &LinkTarget,
+                                                   &Length);
+            }
+
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("NtQuerySymbolicLinkObject(%wZ) failed (Status %lx)\n",
+                     &DeviceName, Status);
+                _SEH2_LEAVE;
+            }
+
+            if ((dwFlags & DDD_REMOVE_DEFINITION))
+            {
+                /* If no target name specified we remove the current symlink target */
+                if (RequestLinkTarget->Length == 0)
+                    Matched = TRUE;
+                else
+                {
+                    if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
+                        Matched = ! RtlCompareUnicodeString(RequestLinkTarget,
+                                                            &LinkTarget,
+                                                            TRUE);
+                    else
+                        Matched = RtlPrefixUnicodeString(RequestLinkTarget,
+                                                         &LinkTarget,
+                                                         TRUE);
+                }
+
+                if (Matched && IsListEmpty(ListHead))
+                {
+                    /* Current symlink target macthed and there is nothing to revert to */
+                    RequestLinkTarget = NULL;
+                }
+                else if (Matched && ! IsListEmpty(ListHead))
+                {
+                    /* Fetch the first history entry we come across for the device name */
+                    /* This will become the current symlink target for the device name */
+                    Matched = FALSE;
+                    Entry = ListHead->Flink;
+                    while (Entry != ListHead)
+                    {
+                        HistoryEntry = (PBASE_DOS_DEVICE_HISTORY_ENTRY)
+                            CONTAINING_RECORD(Entry,
+                                              BASE_DOS_DEVICE_HISTORY_ENTRY,
+                                              Entry);
+                        Matched =
+                            ! RtlCompareUnicodeString(&RequestDeviceName,
+                                                      &HistoryEntry->Device,
+                                                      FALSE);
+                        if (Matched)
+                        {
+                            RemoveEntryList(&HistoryEntry->Entry);
+                            RequestLinkTarget = &HistoryEntry->Target;
+                            break;
+                        }
+                        Entry = Entry->Flink;
+                        HistoryEntry = NULL;
+                    }
 
-       DPRINT("BASESRV: %s(%08lx) called\n", __FUNCTION__, ProcessCreateNotifyProc);
-       return Status;
+                    /* Nothing to revert to so delete the symlink */
+                    if (! Matched)
+                        RequestLinkTarget = NULL;
+                }
+                else if (! Matched)
+                {
+                    /* Locate a previous symlink target as we did not get a hit earlier */
+                    /* If we find one we need to remove it */
+                    Entry = ListHead->Flink;
+                    while (Entry != ListHead)
+                    {
+                        HistoryEntry = (PBASE_DOS_DEVICE_HISTORY_ENTRY)
+                            CONTAINING_RECORD(Entry,
+                                              BASE_DOS_DEVICE_HISTORY_ENTRY,
+                                              Entry);
+                        Matched =
+                            ! RtlCompareUnicodeString(&RequestDeviceName,
+                                                      &HistoryEntry->Device,
+                                                      FALSE);
+                        if (! Matched)
+                        {
+                            HistoryEntry = NULL;
+                            Entry = Entry->Flink;
+                            continue;
+                        }
+
+                        Matched = FALSE;
+                        if (dwFlags & DDD_EXACT_MATCH_ON_REMOVE)
+                        {
+                            if (! RtlCompareUnicodeString(RequestLinkTarget,
+                                                          &HistoryEntry->Target,
+                                                          TRUE))
+                            {
+                                Matched = TRUE;
+                            }
+                        }
+                        else if (RtlPrefixUnicodeString(RequestLinkTarget,
+                                                        &HistoryEntry->Target,
+                                                        TRUE))
+                        {
+                            Matched = TRUE;
+                        }
+
+                        if (Matched)
+                        {
+                            RemoveEntryList(&HistoryEntry->Entry);
+                            break;
+                        }
+                        Entry = Entry->Flink;
+                        HistoryEntry = NULL;
+                    }
+
+                    /* Leave existing symlink as is */
+                    if (! Matched)
+                        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+                    else
+                        Status = STATUS_SUCCESS;
+                    _SEH2_LEAVE;
+                }
+            }
+            else
+            {
+                AddHistory = TRUE;
+            }
+
+            Status = NtMakeTemporaryObject(LinkHandle);
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("NtMakeTemporaryObject(%wZ) failed (Status %lx)\n",
+                     &DeviceName, Status);
+                _SEH2_LEAVE;
+            }
+
+            Status = NtClose(LinkHandle);
+            LinkHandle = NULL;
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("NtClose(%wZ) failed (Status %lx)\n",
+                     &DeviceName, Status);
+                _SEH2_LEAVE;
+            }
+        }
+
+        /* Don't create symlink if we don't have a target */
+        if (! RequestLinkTarget || RequestLinkTarget->Length == 0)
+            _SEH2_LEAVE;
+
+        if (AddHistory)
+        {
+            HistoryEntry = (PBASE_DOS_DEVICE_HISTORY_ENTRY)
+                RtlAllocateHeap(BaseSrvHeap,
+                                HEAP_ZERO_MEMORY,
+                                sizeof(BASE_DOS_DEVICE_HISTORY_ENTRY));
+            if (! HistoryEntry)
+            {
+                DPRINT1("Failed to allocate memory\n");
+                Status = STATUS_NO_MEMORY;
+                _SEH2_LEAVE;
+            }
+
+            HistoryEntry->Target.Buffer =
+                RtlAllocateHeap(BaseSrvHeap,
+                                HEAP_ZERO_MEMORY,
+                                LinkTarget.Length);
+            if (! HistoryEntry->Target.Buffer)
+            {
+                DPRINT1("Failed to allocate memory\n");
+                Status = STATUS_NO_MEMORY;
+                _SEH2_LEAVE;
+            }
+            HistoryEntry->Target.Length =
+                HistoryEntry->Target.MaximumLength =
+                    LinkTarget.Length;
+            RtlCopyUnicodeString(&HistoryEntry->Target,
+                                 &LinkTarget);
+
+            HistoryEntry->Device.Buffer =
+                RtlAllocateHeap(BaseSrvHeap,
+                                HEAP_ZERO_MEMORY,
+                                RequestDeviceName.Length);
+            if (! HistoryEntry->Device.Buffer)
+            {
+                DPRINT1("Failed to allocate memory\n");
+                Status = STATUS_NO_MEMORY;
+                _SEH2_LEAVE;
+            }
+            HistoryEntry->Device.Length =
+                HistoryEntry->Device.MaximumLength =
+                    RequestDeviceName.Length;
+            RtlCopyUnicodeString(&HistoryEntry->Device,
+                                 &RequestDeviceName);
+
+            /* Remember previous symlink target for this device */
+            InsertHeadList(ListHead,
+                           &HistoryEntry->Entry);
+            HistoryEntry = NULL;
+        }
+
+        RtlAllocateAndInitializeSid(&WorldAuthority,
+                                    1,
+                                    SECURITY_WORLD_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    &WorldSid);
+
+        RtlAllocateAndInitializeSid(&SystemAuthority,
+                                    1,
+                                    SECURITY_LOCAL_SYSTEM_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    &SystemSid);
+
+        RtlAllocateAndInitializeSid(&SystemAuthority,
+                                    2,
+                                    SECURITY_BUILTIN_DOMAIN_RID,
+                                    DOMAIN_ALIAS_RID_ADMINS,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    SECURITY_NULL_RID,
+                                    &AdminSid);
+
+        SidLength = RtlLengthSid(SystemSid) +
+            RtlLengthSid(AdminSid) +
+            RtlLengthSid(WorldSid);
+        Length = sizeof(ACL) + SidLength + 3 * sizeof(ACCESS_ALLOWED_ACE);
+
+        SecurityDescriptor = RtlAllocateHeap(BaseSrvHeap,
+                                             0,
+                                             SECURITY_DESCRIPTOR_MIN_LENGTH + Length);
+        if (! SecurityDescriptor)
+        {
+            DPRINT1("Failed to allocate memory\n");
+            Status = STATUS_NO_MEMORY;
+            _SEH2_LEAVE;
+        }
+
+        Dacl = (PACL)((ULONG_PTR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
+        Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
+                                             SECURITY_DESCRIPTOR_REVISION);
+        if (! NT_SUCCESS(Status))
+        {
+            DPRINT1("RtlCreateSecurityDescriptor() failed (Status %lx)\n",
+                 Status);
+            _SEH2_LEAVE;
+        }
+
+        Status = RtlCreateAcl(Dacl,
+                              Length,
+                              ACL_REVISION);
+        if (! NT_SUCCESS(Status))
+        {
+            DPRINT1("RtlCreateAcl() failed (Status %lx)\n",
+                 Status);
+            _SEH2_LEAVE;
+        }
+
+        (void) RtlAddAccessAllowedAce(Dacl,
+                                      ACL_REVISION,
+                                      GENERIC_ALL,
+                                      SystemSid);
+        (void) RtlAddAccessAllowedAce(Dacl,
+                                      ACL_REVISION,
+                                      GENERIC_ALL,
+                                      AdminSid);
+        (void) RtlAddAccessAllowedAce(Dacl,
+                                      ACL_REVISION,
+                                      STANDARD_RIGHTS_READ,
+                                      WorldSid);
+
+        Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
+                                              TRUE,
+                                              Dacl,
+                                              FALSE);
+        if (! NT_SUCCESS(Status))
+        {
+            DPRINT1("RtlSetDaclSecurityDescriptor() failed (Status %lx)\n",
+                 Status);
+            _SEH2_LEAVE;
+        }
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &DeviceName,
+                                   OBJ_CASE_INSENSITIVE,
+                                   NULL,
+                                   SecurityDescriptor);
+        Status = NtCreateSymbolicLinkObject(&LinkHandle,
+                                            SYMBOLIC_LINK_ALL_ACCESS,
+                                            &ObjectAttributes,
+                                            RequestLinkTarget);
+        if (NT_SUCCESS(Status))
+        {
+            Status = NtMakePermanentObject(LinkHandle);
+            if (! NT_SUCCESS(Status))
+            {
+                DPRINT1("NtMakePermanentObject(%wZ) failed (Status %lx)\n",
+                     &DeviceName, Status);
+            }
+        }
+        else
+        {
+            DPRINT1("NtCreateSymbolicLinkObject(%wZ) failed (Status %lx)\n",
+                 &DeviceName, Status);
+        }
+    }
+    _SEH2_FINALLY
+    {
+        (void) RtlLeaveCriticalSection(&BaseDefineDosDeviceCritSec);
+        if (DeviceName.Buffer)
+            (void) RtlFreeHeap(BaseSrvHeap,
+                               0,
+                               DeviceName.Buffer);
+        if (LinkTarget.Buffer)
+            (void) RtlFreeHeap(BaseSrvHeap,
+                               0,
+                               LinkTarget.Buffer);
+        if (SecurityDescriptor)
+            (void) RtlFreeHeap(BaseSrvHeap,
+                               0,
+                               SecurityDescriptor);
+        if (LinkHandle)
+            (void) NtClose(LinkHandle);
+        if (SystemSid)
+            (void) RtlFreeSid(SystemSid);
+        if (AdminSid)
+            (void) RtlFreeSid(AdminSid);
+        if (WorldSid)
+            (void) RtlFreeSid(WorldSid);
+        RtlFreeUnicodeString(&RequestDeviceName);
+        if (HistoryEntry)
+        {
+            if (HistoryEntry->Target.Buffer)
+                (void) RtlFreeHeap(BaseSrvHeap,
+                                   0,
+                                   HistoryEntry->Target.Buffer);
+            if (HistoryEntry->Device.Buffer)
+                (void) RtlFreeHeap(BaseSrvHeap,
+                                   0,
+                                   HistoryEntry->Device.Buffer);
+            (void) RtlFreeHeap(BaseSrvHeap,
+                               0,
+                               HistoryEntry);
+        }
+    }
+    _SEH2_END
+
+    DPRINT("CsrDefineDosDevice Exit, Statux: 0x%x\n", Status);
+    return Status;
+}
+
+
+
+
+
+
+/* PUBLIC API *****************************************************************/
+
+NTSTATUS NTAPI BaseSetProcessCreateNotify(IN BASE_PROCESS_CREATE_NOTIFY_ROUTINE ProcessCreateNotifyProc)
+{
+    DPRINT("BASESRV: %s(%08lx) called\n", __FUNCTION__, ProcessCreateNotifyProc);
+    return STATUS_NOT_IMPLEMENTED;
 }
 
 /* EOF */