Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do DOS devices defined in an impersonated session not appear in Explorer

I have a Windows service running under the Local System account that creates DOS devices using the DefineDosDevice function. The service is running on a W2K8 Remote Desktop Server. If the devices are created using the service's credentials, they are created in the GLOBAL device namespace and therefore visible to all users. I need the devices visible only to a particular interaction session.

I accomplish this by impersonating the user in whose session I want the drives to appear. This is fairly straightforward, provided the session id is available. Here's a simple test application I wrote to illustrate the problem:

int _tmain(int argc, _TCHAR* argv[])
{
BOOL result = TRUE;

if(argc > 3 && !wcscmp(argv[2], L"/i"))
{
    HANDLE hToken = 0;
    DWORD dwSessionId = _wtoi(argv[3]);
    result = WTSQueryUserToken(dwSessionId, &hToken);
    if(result) result = ImpersonateLoggedOnUser(hToken);
}
if(result)
{
    LPTSTR drive = argv[1];
    DefineDosDevice(DDD_REMOVE_DEFINITION, drive, NULL);
    result = DefineDosDevice(0, drive, L"C:\\test");
}

if(!result)
{
    printf("Error: %d\n", GetLastError());
}
return 0;
}

To test this code, I created a service that launches a command shell under the LocalSystem account:

sc create test_svc binpath= "cmd /K start" type= own type= interact

This service fails to start, but before it fails, it spawns a command shell running under the LocalSystem account.

From the LocalSystem cmd.exe, I run:

MySubst.exe x: /i 2

which invokes ImpersonateLoggedOnUser(), then calls DefineDosDevice()

From cmd.exe running in the user's session, I run:

MySubst.exe y:

Which calls DefineDosDevice without invoking ImpersonateLoggedOnUser().

This works. From cmd.exe I can access the two drives X: and Y:. I can launch notepad.exe from the start menu, and see the X: and Y: drives. Furthermore, if I create a new terminal services session with a different user, I do not see the X: or Y:.

However, Explorer only shows the Y: drive under "all computers". Y: is the drive that was created by running my test application from cmd.exe running within the target session, i.e. impersonation was not done. If I restart explorer.exe from Task Manager, both the X: and Y: drives show up.

I also used WinObj.exe from SysInternals to examine the defined Win NT devices. What I see is:

- Sessions
    - 0
        - DosDevices
            00000000-000057607

(57607 is the ID of the login session associated with the session that I'm impersonating)

The contents of "00000000-000057607" are:

Global    SymbolicLink    \Global??
X:        SymbolicLink    \\??\C:\test
Y:        SymbolicLink    \\??\C:\test

According the WinObj, the two dos Devices are identical. They belong to the same session and logon session. They are symlinks to the same NT object.

How can it be that one of them appears in Explorer and the other doesn't.

like image 707
FishesCycle Avatar asked Oct 06 '22 01:10

FishesCycle


1 Answers

@arx and @HarryJohnston were on the money. If I broadcast a WM_DEVICECHANGE message from a thread in the same session as explorer, the new drive appears in My Computer. Here's the code:

DWORD recipients = BSM_ALLDESKTOPS | BSM_APPLICATIONS;

DEV_BROADCAST_VOLUME msg;
ZeroMemory(&msg, sizeof(msg));
msg.dbcv_size = sizeof(msg);
msg.dbcv_devicetype = DBT_DEVTYP_VOLUME;
msg.dbcv_unitmask = 1 << ('X' - 'A');

long success = BroadcastSystemMessage(0, &recipients, WM_DEVICECHANGE, DBT_DEVICEARRIVAL, (LPARAM)&msg);
like image 144
FishesCycle Avatar answered Oct 13 '22 10:10

FishesCycle