Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 76071)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 76072)
@@ -300,32 +300,30 @@
 #
 if defined(VBOX_WITH_SDS) && "$(KBUILD_TARGET)" == "win"
- PROGRAMS += VBoxSDS
- VBoxSDS_TEMPLATE = VBOXMAINEXE
- VBoxSDS_DEFS.win += VBOX_COM_OUTOFPROC_MODULE
+PROGRAMS.win += VBoxSDS
+VBoxSDS_TEMPLATE = VBOXMAINEXE
+VBoxSDS_DEFS += VBOX_COM_OUTOFPROC_MODULE
  if "$(KBUILD_TYPE)" == "debug" && "$(USERNAME)" == "bird"
-VBoxSDS_DEFS.win += _WIN32_WINNT=0x0610 # ClientPID query requires vista+
+VBoxSDS_DEFS += _WIN32_WINNT=0x0610 # ClientPID query requires vista+
  else
-VBoxSDS_DEFS.win += _WIN32_WINNT=0x0510
- endif
- VBoxSDS_INCS = \
- 	include \
- 	$(VBoxSDS_0_OUTDIR)
- VBoxSDS_INCS.win = \
- 	$(VBoxCOM_0_OUTDIR)
- VBoxSDS_INTERMEDIATES = \
- 	$(VBOX_MAIN_PREREQS)
- VBoxSDS_SOURCES = \
- 	src-global/VirtualBoxSDSImpl.cpp
- VBoxSDS_SOURCES.win = \
- 	src-global/win/VBoxSDS.cpp \
- 	src-global/win/VBoxSDS.rc
- $(call KB_FN_DO_PASS0_ON_TARGET,VBoxSDS) # Sets VBoxSDS_0_OUTDIR
-
- src-global/win/VBoxSDS.rc_INCS  = $(VBoxSDS_0_OUTDIR)
- src-global/win/VBoxSDS.rc_DEPS  = $(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc #$(VBoxSDS_0_OUTDIR)/VBoxSDS.rgs
- src-global/win/VBoxSDS.rc_CLEAN = $(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc #$(VBoxSDS_0_OUTDIR)/VBoxSDS.rgs
-
- $(call KB_FN_AUTO_CMD_DEPS,$(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc)
- $(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc: $(VBOX_WINDOWS_ICON_FILE) | $$(dir $$@)
+VBoxSDS_DEFS += _WIN32_WINNT=0x0510
+ endif
+VBoxSDS_INCS  = \
+	include \
+	$(VBoxSDS_0_OUTDIR) \
+	$(VBoxCOM_0_OUTDIR)
+VBoxSDS_INTERMEDIATES = \
+	$(VBOX_MAIN_PREREQS)
+VBoxSDS_SOURCES = \
+	src-global/win/VBoxSDS.cpp \
+	src-global/win/VirtualBoxSDSImpl.cpp \
+	src-global/win/VBoxSDS.rc
+$(call KB_FN_DO_PASS0_ON_TARGET,VBoxSDS) # Sets VBoxSDS_0_OUTDIR
+
+src-global/win/VBoxSDS.rc_INCS  = $(VBoxSDS_0_OUTDIR)
+src-global/win/VBoxSDS.rc_DEPS  = $(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc #$(VBoxSDS_0_OUTDIR)/VBoxSDS.rgs
+src-global/win/VBoxSDS.rc_CLEAN = $(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc #$(VBoxSDS_0_OUTDIR)/VBoxSDS.rgs
+
+$(call KB_FN_AUTO_CMD_DEPS,$(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc)
+$(VBoxSDS_0_OUTDIR)/VBoxSDS-icon.rc: $(VBOX_WINDOWS_ICON_FILE) | $$(dir $$@)
 	$(call KB_FN_AUTO_CMD_DEPS_COMMANDS)
 	$(APPEND) -t $@ '1 ICON DISCARDABLE "$(subst /,\\,$(VBOX_WINDOWS_ICON_FILE))"'
Index: unk/src/VBox/Main/src-global/VirtualBoxSDSImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-global/VirtualBoxSDSImpl.cpp	(revision 76071)
+++ 	(revision )
@@ -1,469 +1,0 @@
-/* $Id$ */
-/** @file
- * VBox Global COM Class implementation.
- */
-
-/*
- * Copyright (C) 2015-2018 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#include <VBox/com/VirtualBox.h>
-#include "VirtualBoxSDSImpl.h"
-
-#include "AutoCaller.h"
-#include "Logging.h"
-
-#include <VBox/err.h>
-#include <iprt/asm.h>
-#include <iprt/critsect.h>
-
-#include <rpcasync.h>
-#include <rpcdcep.h>
-#include <sddl.h>
-#include <lmcons.h> /* UNLEN */
-
-
-/**
- * Per user data.
- *
- * @note We never delete instances of this class, except in case of an insertion
- *       race.  This allows us to separate the map lock from the user data lock
- *       and avoid DoS issues.
- */
-class VBoxSDSPerUserData
-{
-public:
-    /** The SID (secure identifier) for the user.  This is the key. */
-    com::Utf8Str                    m_strUserSid;
-    /** The user name (if we could get it). */
-    com::Utf8Str                    m_strUsername;
-    /** The VBoxSVC chosen to instantiate CLSID_VirtualBox.
-     * This is NULL if not set. */
-    ComPtr<IVBoxSVCRegistration>    m_ptrTheChosenOne;
-private:
-    /** Reference count to make destruction safe wrt hung callers.
-     * (References are retain while holding the map lock in some form, but
-     * released while holding no locks.) */
-    uint32_t volatile               m_cRefs;
-    /** Critical section protecting everything here. */
-    RTCRITSECT                      m_Lock;
-
-public:
-    VBoxSDSPerUserData(com::Utf8Str const &a_rStrUserSid, com::Utf8Str const &a_rStrUsername)
-        : m_strUserSid(a_rStrUserSid), m_strUsername(a_rStrUsername), m_cRefs(1)
-    {
-        RTCritSectInit(&m_Lock);
-    }
-
-    ~VBoxSDSPerUserData()
-    {
-        RTCritSectDelete(&m_Lock);
-    }
-
-    uint32_t i_retain()
-    {
-        uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
-        Assert(cRefs > 1);
-        return cRefs;
-    }
-
-    uint32_t i_release()
-    {
-        uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
-        Assert(cRefs < _1K);
-        if (cRefs == 0)
-            delete this;
-        return cRefs;
-    }
-
-    void i_lock()
-    {
-        RTCritSectEnter(&m_Lock);
-    }
-
-    void i_unlock()
-    {
-        RTCritSectLeave(&m_Lock);
-    }
-};
-
-
-
-
-// constructor / destructor
-/////////////////////////////////////////////////////////////////////////////
-
-DEFINE_EMPTY_CTOR_DTOR(VirtualBoxSDS)
-
-HRESULT VirtualBoxSDS::FinalConstruct()
-{
-    LogRelFlowThisFuncEnter();
-
-    int vrc = RTCritSectRwInit(&m_MapCritSect);
-    AssertLogRelRCReturn(vrc, E_FAIL);
-
-    LogRelFlowThisFuncLeave();
-    return S_OK;
-}
-
-
-void VirtualBoxSDS::FinalRelease()
-{
-    LogRelFlowThisFuncEnter();
-
-    RTCritSectRwDelete(&m_MapCritSect);
-
-    for (UserDataMap_T::iterator it = m_UserDataMap.begin(); it != m_UserDataMap.end(); ++it)
-    {
-        VBoxSDSPerUserData *pUserData = it->second;
-        if (pUserData)
-        {
-            it->second = NULL;
-            pUserData->i_release();
-        }
-    }
-
-    LogRelFlowThisFuncLeave();
-}
-
-
-
-// IVirtualBoxSDS methods
-/////////////////////////////////////////////////////////////////////////////
-
-
-/* SDS plan B interfaces: */
-STDMETHODIMP VirtualBoxSDS::RegisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid, IUnknown **aExistingVirtualBox)
-{
-    LogRel(("VirtualBoxSDS::registerVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid));
-#ifdef DEBUG_bird
-    RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL};
-    RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs);
-    LogRel(("RpcServerInqCallAttributesW -> %#x ClientPID=%#x IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid\n",
-            rcRpc, CallAttribs.ClientPID, CallAttribs.IsClientLocal, CallAttribs.ProtocolSequence, CallAttribs.CallStatus,
-            CallAttribs.CallType, CallAttribs.OpNum, &CallAttribs.InterfaceUuid));
-#endif
-
-    HRESULT hrc;
-    if (   RT_VALID_PTR(aVBoxSVC)
-        && RT_VALID_PTR(aExistingVirtualBox))
-    {
-        *aExistingVirtualBox = NULL;
-
-        /* Get the client user SID and name. */
-        com::Utf8Str strSid;
-        com::Utf8Str strUsername;
-        if (i_getClientUserSid(&strSid, &strUsername))
-        {
-            VBoxSDSPerUserData *pUserData = i_lookupOrCreatePerUserData(strSid, strUsername);
-            if (pUserData)
-            {
-                /*
-                 * If there already is a chosen one, ask it for a IVirtualBox instance
-                 * to return to the caller.  Should it be dead or unresponsive, the caller
-                 * takes its place.
-                 */
-                if (pUserData->m_ptrTheChosenOne.isNotNull())
-                {
-                    try
-                    {
-                        hrc = pUserData->m_ptrTheChosenOne->GetVirtualBox(aExistingVirtualBox);
-                    }
-                    catch (...)
-                    {
-                        LogRel(("VirtualBoxSDS::registerVBoxSVC: unexpected exception calling GetVirtualBox.\n"));
-                        hrc = E_FAIL;
-                    }
-                    if (FAILED_DEAD_INTERFACE(hrc))
-                    {
-                        LogRel(("VirtualBoxSDS::registerVBoxSVC: Seems VBoxSVC instance died.  Dropping it and letting caller take over. (hrc=%Rhrc)\n", hrc));
-                        pUserData->m_ptrTheChosenOne.setNull();
-                    }
-                }
-                else
-                    hrc = S_OK;
-
-                /*
-                 * Is the caller the chosen one?
-                 */
-                if (pUserData->m_ptrTheChosenOne.isNull())
-                {
-                    LogRel(("VirtualBoxSDS::registerVBoxSVC: Making aPid=%u (%#x) the chosen one for user %s (%s)!\n",
-                            aPid, aPid, pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str()));
-                    pUserData->m_ptrTheChosenOne = aVBoxSVC;
-                }
-
-                pUserData->i_unlock();
-                pUserData->i_release();
-            }
-            else
-                hrc = E_OUTOFMEMORY;
-        }
-        else
-            hrc = E_FAIL;
-    }
-    else
-        hrc = E_INVALIDARG;
-    LogRel2(("VirtualBoxSDS::registerVBoxSVC: returns %Rhrc aExistingVirtualBox=%p\n", hrc, (IUnknown *)aExistingVirtualBox));
-    return hrc;
-}
-
-
-STDMETHODIMP VirtualBoxSDS::DeregisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid)
-{
-    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid));
-    HRESULT hrc;
-    if (RT_VALID_PTR(aVBoxSVC))
-    {
-        /* Get the client user SID and name. */
-        com::Utf8Str strSid;
-        com::Utf8Str strUsername;
-        if (i_getClientUserSid(&strSid, &strUsername))
-        {
-            VBoxSDSPerUserData *pUserData = i_lookupPerUserData(strSid);
-            if (pUserData)
-            {
-                if (aVBoxSVC == (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne)
-                {
-                    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: It's the chosen one for %s (%s)!\n",
-                            pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str()));
-                    pUserData->m_ptrTheChosenOne.setNull();
-                }
-                else
-                    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: not the choosen one (%p != %p)\n",
-                            (IVBoxSVCRegistration *)aVBoxSVC, (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne));
-                pUserData->i_unlock();
-                pUserData->i_release();
-
-                hrc = S_OK;
-            }
-            else
-            {
-                LogRel(("VirtualBoxSDS::deregisterVBoxSVC: Found no user data for %s (%s) (pid %u)\n",
-                        strSid.c_str(), strUsername.c_str(), aPid));
-                hrc = S_OK;
-            }
-        }
-        else
-            hrc = E_FAIL;
-    }
-    else
-        hrc = E_INVALIDARG;
-    LogRel2(("VirtualBoxSDS::deregisterVBoxSVC: returns %Rhrc\n", hrc));
-    return hrc;
-}
-
-
-/*********************************************************************************************************************************
-*   Internal Methods                                                                                                             *
-*********************************************************************************************************************************/
-
-/*static*/ bool VirtualBoxSDS::i_getClientUserSid(com::Utf8Str *a_pStrSid, com::Utf8Str *a_pStrUsername)
-{
-    bool fRet = false;
-    a_pStrSid->setNull();
-    a_pStrUsername->setNull();
-
-    CoInitializeEx(NULL, COINIT_MULTITHREADED); // is this necessary?
-    HRESULT hrc = CoImpersonateClient();
-    if (SUCCEEDED(hrc))
-    {
-        HANDLE hToken = INVALID_HANDLE_VALUE;
-        if (::OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE /*OpenAsSelf*/, &hToken))
-        {
-            CoRevertToSelf();
-
-            union
-            {
-                TOKEN_USER  TokenUser;
-                uint8_t     abPadding[SECURITY_MAX_SID_SIZE + 256];
-                WCHAR       wszUsername[UNLEN + 1];
-            } uBuf;
-            RT_ZERO(uBuf);
-            DWORD cbActual = 0;
-            if (::GetTokenInformation(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbActual))
-            {
-                WCHAR *pwszString;
-                if (ConvertSidToStringSidW(uBuf.TokenUser.User.Sid, &pwszString))
-                {
-                    try
-                    {
-                        *a_pStrSid = pwszString;
-                        a_pStrSid->toUpper(); /* (just to be on the safe side) */
-                        fRet = true;
-                    }
-                    catch (std::bad_alloc &)
-                    {
-                        LogRel(("VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rstrSid.\n"));
-                    }
-                    LocalFree((HLOCAL)pwszString);
-
-                    /*
-                     * Get the username too.  We don't care if this step fails.
-                     */
-                    if (fRet)
-                    {
-                        WCHAR           wszUsername[UNLEN * 2 + 1];
-                        DWORD           cwcUsername = RT_ELEMENTS(wszUsername);
-                        WCHAR           wszDomain[UNLEN * 2 + 1];
-                        DWORD           cwcDomain = RT_ELEMENTS(wszDomain);
-                        SID_NAME_USE    enmNameUse;
-                        if (LookupAccountSidW(NULL, uBuf.TokenUser.User.Sid, wszUsername, &cwcUsername,
-                                              wszDomain, &cwcDomain, &enmNameUse))
-                        {
-                            wszUsername[RT_ELEMENTS(wszUsername) - 1] = '\0';
-                            wszDomain[RT_ELEMENTS(wszDomain) - 1] = '\0';
-                            try
-                            {
-                                *a_pStrUsername = wszDomain;
-                                a_pStrUsername->append('/');
-                                a_pStrUsername->append(Utf8Str(wszUsername));
-                            }
-                            catch (std::bad_alloc &)
-                            {
-                                LogRel(("VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rStrUsername.\n"));
-                                a_pStrUsername->setNull();
-                            }
-                        }
-                        else
-                            LogRel(("VirtualBoxSDS::i_GetClientUserSID: LookupAccountSidW failed: %u/%x (cwcUsername=%u, cwcDomain=%u)\n",
-                                   GetLastError(), cwcUsername, cwcDomain));
-                    }
-                }
-                else
-                    LogRel(("VirtualBoxSDS::i_GetClientUserSID: ConvertSidToStringSidW failed: %u\n", GetLastError()));
-            }
-            else
-                LogRel(("VirtualBoxSDS::i_GetClientUserSID: GetTokenInformation/TokenUser failed: %u\n", GetLastError()));
-            CloseHandle(hToken);
-        }
-        else
-        {
-            CoRevertToSelf();
-            LogRel(("VirtualBoxSDS::i_GetClientUserSID: OpenThreadToken failed: %u\n", GetLastError()));
-        }
-    }
-    else
-        LogRel(("VirtualBoxSDS::i_GetClientUserSID: CoImpersonateClient failed: %Rhrc\n", hrc));
-    CoUninitialize();
-    return fRet;
-}
-
-
-/**
- * Looks up the given user.
- *
- * @returns Pointer to the LOCKED and RETAINED per user data.
- *          NULL if not found.
- * @param   a_rStrUserSid   The user SID.
- */
-VBoxSDSPerUserData *VirtualBoxSDS::i_lookupPerUserData(com::Utf8Str const &a_rStrUserSid)
-{
-    int vrc = RTCritSectRwEnterShared(&m_MapCritSect);
-    if (RT_SUCCESS(vrc))
-    {
-
-        UserDataMap_T::iterator it = m_UserDataMap.find(a_rStrUserSid);
-        if (it != m_UserDataMap.end())
-        {
-            VBoxSDSPerUserData *pUserData = it->second;
-            pUserData->i_retain();
-
-            RTCritSectRwLeaveShared(&m_MapCritSect);
-
-            pUserData->i_lock();
-            return pUserData;
-        }
-
-        RTCritSectRwLeaveShared(&m_MapCritSect);
-    }
-    return NULL;
-}
-
-
-/**
- * Looks up the given user, creating it if not found
- *
- * @returns Pointer to the LOCKED and RETAINED per user data.
- *          NULL on allocation error.
- * @param   a_rStrUserSid   The user SID.
- * @param   a_rStrUsername  The user name if available.
- */
-VBoxSDSPerUserData *VirtualBoxSDS::i_lookupOrCreatePerUserData(com::Utf8Str const &a_rStrUserSid,
-                                                               com::Utf8Str const &a_rStrUsername)
-{
-    /*
-     * Try do a simple lookup first.
-     */
-    VBoxSDSPerUserData *pUserData = i_lookupPerUserData(a_rStrUserSid);
-    if (!pUserData)
-    {
-        /*
-         * SID is not in map, create a new one.
-         */
-        try
-        {
-            pUserData = new VBoxSDSPerUserData(a_rStrUserSid, a_rStrUsername);
-        }
-        catch (std::bad_alloc &)
-        {
-            pUserData = NULL;
-        }
-        if (pUserData)
-        {
-            /*
-             * Insert it.  We must check if someone raced us here.
-             */
-            VBoxSDSPerUserData *pUserDataFree = pUserData;
-            pUserData->i_lock();
-
-            int vrc = RTCritSectRwEnterExcl(&m_MapCritSect);
-            if (RT_SUCCESS(vrc))
-            {
-
-                UserDataMap_T::iterator it = m_UserDataMap.find(a_rStrUserSid);
-                if (it == m_UserDataMap.end())
-                {
-                    try
-                    {
-                        m_UserDataMap[a_rStrUserSid] = pUserData;
-                        pUserData->i_retain();
-                    }
-                    catch (std::bad_alloc &)
-                    {
-                        pUserData = NULL;
-                    }
-                }
-                else
-                    pUserData = NULL;
-
-                RTCritSectRwLeaveExcl(&m_MapCritSect);
-
-                if (pUserData)
-                    LogRel(("VirtualBoxSDS::i_lookupOrCreatePerUserData: Created new entry for %s (%s)\n",
-                            pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str() ));
-                else
-                {
-                    pUserDataFree->i_unlock();
-                    delete pUserDataFree;
-                }
-            }
-        }
-    }
-
-    return pUserData;
-}
-
-/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Index: /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp	(revision 76072)
+++ /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp	(revision 76072)
@@ -0,0 +1,469 @@
+/* $Id$ */
+/** @file
+ * VBox Global COM Class implementation.
+ */
+
+/*
+ * Copyright (C) 2015-2018 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <VBox/com/VirtualBox.h>
+#include "VirtualBoxSDSImpl.h"
+
+#include "AutoCaller.h"
+#include "Logging.h"
+
+#include <VBox/err.h>
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
+
+#include <rpcasync.h>
+#include <rpcdcep.h>
+#include <sddl.h>
+#include <lmcons.h> /* UNLEN */
+
+
+/**
+ * Per user data.
+ *
+ * @note We never delete instances of this class, except in case of an insertion
+ *       race.  This allows us to separate the map lock from the user data lock
+ *       and avoid DoS issues.
+ */
+class VBoxSDSPerUserData
+{
+public:
+    /** The SID (secure identifier) for the user.  This is the key. */
+    com::Utf8Str                    m_strUserSid;
+    /** The user name (if we could get it). */
+    com::Utf8Str                    m_strUsername;
+    /** The VBoxSVC chosen to instantiate CLSID_VirtualBox.
+     * This is NULL if not set. */
+    ComPtr<IVBoxSVCRegistration>    m_ptrTheChosenOne;
+private:
+    /** Reference count to make destruction safe wrt hung callers.
+     * (References are retain while holding the map lock in some form, but
+     * released while holding no locks.) */
+    uint32_t volatile               m_cRefs;
+    /** Critical section protecting everything here. */
+    RTCRITSECT                      m_Lock;
+
+public:
+    VBoxSDSPerUserData(com::Utf8Str const &a_rStrUserSid, com::Utf8Str const &a_rStrUsername)
+        : m_strUserSid(a_rStrUserSid), m_strUsername(a_rStrUsername), m_cRefs(1)
+    {
+        RTCritSectInit(&m_Lock);
+    }
+
+    ~VBoxSDSPerUserData()
+    {
+        RTCritSectDelete(&m_Lock);
+    }
+
+    uint32_t i_retain()
+    {
+        uint32_t cRefs = ASMAtomicIncU32(&m_cRefs);
+        Assert(cRefs > 1);
+        return cRefs;
+    }
+
+    uint32_t i_release()
+    {
+        uint32_t cRefs = ASMAtomicDecU32(&m_cRefs);
+        Assert(cRefs < _1K);
+        if (cRefs == 0)
+            delete this;
+        return cRefs;
+    }
+
+    void i_lock()
+    {
+        RTCritSectEnter(&m_Lock);
+    }
+
+    void i_unlock()
+    {
+        RTCritSectLeave(&m_Lock);
+    }
+};
+
+
+
+
+// constructor / destructor
+/////////////////////////////////////////////////////////////////////////////
+
+DEFINE_EMPTY_CTOR_DTOR(VirtualBoxSDS)
+
+HRESULT VirtualBoxSDS::FinalConstruct()
+{
+    LogRelFlowThisFuncEnter();
+
+    int vrc = RTCritSectRwInit(&m_MapCritSect);
+    AssertLogRelRCReturn(vrc, E_FAIL);
+
+    LogRelFlowThisFuncLeave();
+    return S_OK;
+}
+
+
+void VirtualBoxSDS::FinalRelease()
+{
+    LogRelFlowThisFuncEnter();
+
+    RTCritSectRwDelete(&m_MapCritSect);
+
+    for (UserDataMap_T::iterator it = m_UserDataMap.begin(); it != m_UserDataMap.end(); ++it)
+    {
+        VBoxSDSPerUserData *pUserData = it->second;
+        if (pUserData)
+        {
+            it->second = NULL;
+            pUserData->i_release();
+        }
+    }
+
+    LogRelFlowThisFuncLeave();
+}
+
+
+
+// IVirtualBoxSDS methods
+/////////////////////////////////////////////////////////////////////////////
+
+
+/* SDS plan B interfaces: */
+STDMETHODIMP VirtualBoxSDS::RegisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid, IUnknown **aExistingVirtualBox)
+{
+    LogRel(("VirtualBoxSDS::registerVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid));
+#ifdef DEBUG_bird
+    RPC_CALL_ATTRIBUTES_V2_W CallAttribs = { RPC_CALL_ATTRIBUTES_VERSION, RPC_QUERY_CLIENT_PID | RPC_QUERY_IS_CLIENT_LOCAL};
+    RPC_STATUS rcRpc = RpcServerInqCallAttributesW(NULL, &CallAttribs);
+    LogRel(("RpcServerInqCallAttributesW -> %#x ClientPID=%#x IsClientLocal=%d ProtocolSequence=%#x CallStatus=%#x CallType=%#x OpNum=%#x InterfaceUuid=%RTuuid\n",
+            rcRpc, CallAttribs.ClientPID, CallAttribs.IsClientLocal, CallAttribs.ProtocolSequence, CallAttribs.CallStatus,
+            CallAttribs.CallType, CallAttribs.OpNum, &CallAttribs.InterfaceUuid));
+#endif
+
+    HRESULT hrc;
+    if (   RT_VALID_PTR(aVBoxSVC)
+        && RT_VALID_PTR(aExistingVirtualBox))
+    {
+        *aExistingVirtualBox = NULL;
+
+        /* Get the client user SID and name. */
+        com::Utf8Str strSid;
+        com::Utf8Str strUsername;
+        if (i_getClientUserSid(&strSid, &strUsername))
+        {
+            VBoxSDSPerUserData *pUserData = i_lookupOrCreatePerUserData(strSid, strUsername);
+            if (pUserData)
+            {
+                /*
+                 * If there already is a chosen one, ask it for a IVirtualBox instance
+                 * to return to the caller.  Should it be dead or unresponsive, the caller
+                 * takes its place.
+                 */
+                if (pUserData->m_ptrTheChosenOne.isNotNull())
+                {
+                    try
+                    {
+                        hrc = pUserData->m_ptrTheChosenOne->GetVirtualBox(aExistingVirtualBox);
+                    }
+                    catch (...)
+                    {
+                        LogRel(("VirtualBoxSDS::registerVBoxSVC: unexpected exception calling GetVirtualBox.\n"));
+                        hrc = E_FAIL;
+                    }
+                    if (FAILED_DEAD_INTERFACE(hrc))
+                    {
+                        LogRel(("VirtualBoxSDS::registerVBoxSVC: Seems VBoxSVC instance died.  Dropping it and letting caller take over. (hrc=%Rhrc)\n", hrc));
+                        pUserData->m_ptrTheChosenOne.setNull();
+                    }
+                }
+                else
+                    hrc = S_OK;
+
+                /*
+                 * Is the caller the chosen one?
+                 */
+                if (pUserData->m_ptrTheChosenOne.isNull())
+                {
+                    LogRel(("VirtualBoxSDS::registerVBoxSVC: Making aPid=%u (%#x) the chosen one for user %s (%s)!\n",
+                            aPid, aPid, pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str()));
+                    pUserData->m_ptrTheChosenOne = aVBoxSVC;
+                }
+
+                pUserData->i_unlock();
+                pUserData->i_release();
+            }
+            else
+                hrc = E_OUTOFMEMORY;
+        }
+        else
+            hrc = E_FAIL;
+    }
+    else
+        hrc = E_INVALIDARG;
+    LogRel2(("VirtualBoxSDS::registerVBoxSVC: returns %Rhrc aExistingVirtualBox=%p\n", hrc, (IUnknown *)aExistingVirtualBox));
+    return hrc;
+}
+
+
+STDMETHODIMP VirtualBoxSDS::DeregisterVBoxSVC(IVBoxSVCRegistration *aVBoxSVC, LONG aPid)
+{
+    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: aVBoxSVC=%p aPid=%u (%#x)\n", (IVBoxSVCRegistration *)aVBoxSVC, aPid, aPid));
+    HRESULT hrc;
+    if (RT_VALID_PTR(aVBoxSVC))
+    {
+        /* Get the client user SID and name. */
+        com::Utf8Str strSid;
+        com::Utf8Str strUsername;
+        if (i_getClientUserSid(&strSid, &strUsername))
+        {
+            VBoxSDSPerUserData *pUserData = i_lookupPerUserData(strSid);
+            if (pUserData)
+            {
+                if (aVBoxSVC == (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne)
+                {
+                    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: It's the chosen one for %s (%s)!\n",
+                            pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str()));
+                    pUserData->m_ptrTheChosenOne.setNull();
+                }
+                else
+                    LogRel(("VirtualBoxSDS::deregisterVBoxSVC: not the choosen one (%p != %p)\n",
+                            (IVBoxSVCRegistration *)aVBoxSVC, (IVBoxSVCRegistration *)pUserData->m_ptrTheChosenOne));
+                pUserData->i_unlock();
+                pUserData->i_release();
+
+                hrc = S_OK;
+            }
+            else
+            {
+                LogRel(("VirtualBoxSDS::deregisterVBoxSVC: Found no user data for %s (%s) (pid %u)\n",
+                        strSid.c_str(), strUsername.c_str(), aPid));
+                hrc = S_OK;
+            }
+        }
+        else
+            hrc = E_FAIL;
+    }
+    else
+        hrc = E_INVALIDARG;
+    LogRel2(("VirtualBoxSDS::deregisterVBoxSVC: returns %Rhrc\n", hrc));
+    return hrc;
+}
+
+
+/*********************************************************************************************************************************
+*   Internal Methods                                                                                                             *
+*********************************************************************************************************************************/
+
+/*static*/ bool VirtualBoxSDS::i_getClientUserSid(com::Utf8Str *a_pStrSid, com::Utf8Str *a_pStrUsername)
+{
+    bool fRet = false;
+    a_pStrSid->setNull();
+    a_pStrUsername->setNull();
+
+    CoInitializeEx(NULL, COINIT_MULTITHREADED); // is this necessary?
+    HRESULT hrc = CoImpersonateClient();
+    if (SUCCEEDED(hrc))
+    {
+        HANDLE hToken = INVALID_HANDLE_VALUE;
+        if (::OpenThreadToken(GetCurrentThread(), TOKEN_READ, TRUE /*OpenAsSelf*/, &hToken))
+        {
+            CoRevertToSelf();
+
+            union
+            {
+                TOKEN_USER  TokenUser;
+                uint8_t     abPadding[SECURITY_MAX_SID_SIZE + 256];
+                WCHAR       wszUsername[UNLEN + 1];
+            } uBuf;
+            RT_ZERO(uBuf);
+            DWORD cbActual = 0;
+            if (::GetTokenInformation(hToken, TokenUser, &uBuf, sizeof(uBuf), &cbActual))
+            {
+                WCHAR *pwszString;
+                if (ConvertSidToStringSidW(uBuf.TokenUser.User.Sid, &pwszString))
+                {
+                    try
+                    {
+                        *a_pStrSid = pwszString;
+                        a_pStrSid->toUpper(); /* (just to be on the safe side) */
+                        fRet = true;
+                    }
+                    catch (std::bad_alloc &)
+                    {
+                        LogRel(("VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rstrSid.\n"));
+                    }
+                    LocalFree((HLOCAL)pwszString);
+
+                    /*
+                     * Get the username too.  We don't care if this step fails.
+                     */
+                    if (fRet)
+                    {
+                        WCHAR           wszUsername[UNLEN * 2 + 1];
+                        DWORD           cwcUsername = RT_ELEMENTS(wszUsername);
+                        WCHAR           wszDomain[UNLEN * 2 + 1];
+                        DWORD           cwcDomain = RT_ELEMENTS(wszDomain);
+                        SID_NAME_USE    enmNameUse;
+                        if (LookupAccountSidW(NULL, uBuf.TokenUser.User.Sid, wszUsername, &cwcUsername,
+                                              wszDomain, &cwcDomain, &enmNameUse))
+                        {
+                            wszUsername[RT_ELEMENTS(wszUsername) - 1] = '\0';
+                            wszDomain[RT_ELEMENTS(wszDomain) - 1] = '\0';
+                            try
+                            {
+                                *a_pStrUsername = wszDomain;
+                                a_pStrUsername->append('/');
+                                a_pStrUsername->append(Utf8Str(wszUsername));
+                            }
+                            catch (std::bad_alloc &)
+                            {
+                                LogRel(("VirtualBoxSDS::i_GetClientUserSID: std::bad_alloc setting rStrUsername.\n"));
+                                a_pStrUsername->setNull();
+                            }
+                        }
+                        else
+                            LogRel(("VirtualBoxSDS::i_GetClientUserSID: LookupAccountSidW failed: %u/%x (cwcUsername=%u, cwcDomain=%u)\n",
+                                   GetLastError(), cwcUsername, cwcDomain));
+                    }
+                }
+                else
+                    LogRel(("VirtualBoxSDS::i_GetClientUserSID: ConvertSidToStringSidW failed: %u\n", GetLastError()));
+            }
+            else
+                LogRel(("VirtualBoxSDS::i_GetClientUserSID: GetTokenInformation/TokenUser failed: %u\n", GetLastError()));
+            CloseHandle(hToken);
+        }
+        else
+        {
+            CoRevertToSelf();
+            LogRel(("VirtualBoxSDS::i_GetClientUserSID: OpenThreadToken failed: %u\n", GetLastError()));
+        }
+    }
+    else
+        LogRel(("VirtualBoxSDS::i_GetClientUserSID: CoImpersonateClient failed: %Rhrc\n", hrc));
+    CoUninitialize();
+    return fRet;
+}
+
+
+/**
+ * Looks up the given user.
+ *
+ * @returns Pointer to the LOCKED and RETAINED per user data.
+ *          NULL if not found.
+ * @param   a_rStrUserSid   The user SID.
+ */
+VBoxSDSPerUserData *VirtualBoxSDS::i_lookupPerUserData(com::Utf8Str const &a_rStrUserSid)
+{
+    int vrc = RTCritSectRwEnterShared(&m_MapCritSect);
+    if (RT_SUCCESS(vrc))
+    {
+
+        UserDataMap_T::iterator it = m_UserDataMap.find(a_rStrUserSid);
+        if (it != m_UserDataMap.end())
+        {
+            VBoxSDSPerUserData *pUserData = it->second;
+            pUserData->i_retain();
+
+            RTCritSectRwLeaveShared(&m_MapCritSect);
+
+            pUserData->i_lock();
+            return pUserData;
+        }
+
+        RTCritSectRwLeaveShared(&m_MapCritSect);
+    }
+    return NULL;
+}
+
+
+/**
+ * Looks up the given user, creating it if not found
+ *
+ * @returns Pointer to the LOCKED and RETAINED per user data.
+ *          NULL on allocation error.
+ * @param   a_rStrUserSid   The user SID.
+ * @param   a_rStrUsername  The user name if available.
+ */
+VBoxSDSPerUserData *VirtualBoxSDS::i_lookupOrCreatePerUserData(com::Utf8Str const &a_rStrUserSid,
+                                                               com::Utf8Str const &a_rStrUsername)
+{
+    /*
+     * Try do a simple lookup first.
+     */
+    VBoxSDSPerUserData *pUserData = i_lookupPerUserData(a_rStrUserSid);
+    if (!pUserData)
+    {
+        /*
+         * SID is not in map, create a new one.
+         */
+        try
+        {
+            pUserData = new VBoxSDSPerUserData(a_rStrUserSid, a_rStrUsername);
+        }
+        catch (std::bad_alloc &)
+        {
+            pUserData = NULL;
+        }
+        if (pUserData)
+        {
+            /*
+             * Insert it.  We must check if someone raced us here.
+             */
+            VBoxSDSPerUserData *pUserDataFree = pUserData;
+            pUserData->i_lock();
+
+            int vrc = RTCritSectRwEnterExcl(&m_MapCritSect);
+            if (RT_SUCCESS(vrc))
+            {
+
+                UserDataMap_T::iterator it = m_UserDataMap.find(a_rStrUserSid);
+                if (it == m_UserDataMap.end())
+                {
+                    try
+                    {
+                        m_UserDataMap[a_rStrUserSid] = pUserData;
+                        pUserData->i_retain();
+                    }
+                    catch (std::bad_alloc &)
+                    {
+                        pUserData = NULL;
+                    }
+                }
+                else
+                    pUserData = NULL;
+
+                RTCritSectRwLeaveExcl(&m_MapCritSect);
+
+                if (pUserData)
+                    LogRel(("VirtualBoxSDS::i_lookupOrCreatePerUserData: Created new entry for %s (%s)\n",
+                            pUserData->m_strUserSid.c_str(), pUserData->m_strUsername.c_str() ));
+                else
+                {
+                    pUserDataFree->i_unlock();
+                    delete pUserDataFree;
+                }
+            }
+        }
+    }
+
+    return pUserData;
+}
+
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
