user8507966
user8507966

Reputation: 1

Unable to get the associated network UNC of a mapped drive C/C++

Have written a DLL that attempts to convert a mapped drive to its equivalent network UNC. But it fails when DLL is called by setup program running as an elevated process. As a potential fix I modified the example source offered by @RbMn from an answer to the following question: How to correctly detect Network drive when running with elevated privileges

The call to GetLogicalDrives worked just like it was stated it would. However when it makes a call to WNetGetConnection with a mapped drive letter the error returned is 1222 (ERROR_NO_NETWORK) thus not giving the associated UNC. I believe the problem stems from how I go about impersonating a logon. Since my knowledge of UAC matters is very limited, I am not certain what I have to alter about impersonating a logon in order to correctly get the information I need.

Any help is greatly appreciated.

Below is the actual code:

BOOL ConvertToMappedFolder(LPSTR pUncPath, LPSTR pMappedDrive)
{
   BOOL bRet = 0; 

if (1) 
{
  HANDLE hToken = NULL;
  ULONG rcb = 0;
  TOKEN_ELEVATION_TYPE tet = 0;
  TOKEN_LINKED_TOKEN tlt = { 0 };
  ULONG err = BOOL_TO_ERR(OpenProcessToken(GetCurrentProcess() /* NtCurrentProcess() */, TOKEN_QUERY, &hToken));

if (err == NOERROR)
{
  err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb));

  if (err == NOERROR)
  {
   if (tet == TokenElevationTypeFull)
   {
     err = BOOL_TO_ERR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb));

    if (err == NOERROR)
    {
      if (NOERROR == (err = BOOL_TO_ERR(SetThreadToken(0, tlt.LinkedToken))))
      {
         bRet = ConvertToMappedFolderEx(pUncPath, pMappedDrive); 
         SetThreadToken(0, 0);
      }

      CloseHandle(tlt.LinkedToken);
    }
  }
}
}
}

BOOL ConvertToMappedFolderEx(LPSTR pUncPath, LPSTR pMappedDrive)
{
int  nPos  = 0;
UINT nType = 0; 
char strDrive[MAX_PATH+1] = "?:\\"; 
DWORD dwDriveList = GetLogicalDrives();
BOOL bRet = FALSE; 

(*pMappedDrive) = 0; 

// Check each drive letter determining if it is a mapped drive...
while (dwDriveList) 
{
if (dwDriveList & 1) 
{
strDrive[0] = 0x41 + nPos;

nType = GetDriveType(strDrive);

// If drive unknown do not attempt to determine if its UNC matches up...
if (DRIVE_UNKNOWN != nType) 
{
char  szDeviceName[MAX_PATH+1] = ""; 
char  szDriveLetter[4] = " :"; 
DWORD dwResult = 0;
DWORD cchBuff  = MAX_PATH; 

szDriveLetter[0] = strDrive[0]; 
dwResult = WNetGetConnection(szDriveLetter, (LPSTR) szDeviceName, &cchBuff); 


if (NO_ERROR == dwResult) 
{ 
LPSTR pPath = _stristr(pUncPath, szDeviceName); 

if (NULL != pPath)
{
strcpy(pMappedDrive, szDriveLetter); 
strcat(pMappedDrive, (pUncPath + strlen(szDeviceName))); 

bRet = TRUE; 
break; 
}
}
}
}

dwDriveList >>= 1;
nPos++;
}

return (bRet); 
}

Upvotes: 0

Views: 618

Answers (1)

RbMm
RbMm

Reputation: 33706

connection made using Microsoft LAN Manager is per logon session. more exactly it associated with a logon session LUID. this is stored in token and can be read from TOKEN_STATISTICS.AuthenticationId. so result for any network drive functions depend from your current token - thread (if you impersonate) or process. use different tokens - can give different results. the elevated and not elevated processes always run in different logon sessions (have different AuthenticationId in process token).

so no sense speak about network drives in windows. need speak about network drives in logon session. and different logon session have different set of network drives. we can do next - enumerate all currently running processes, for every process open it token and query AuthenticationId - then we can once impersonate and query for every new AuthenticationId or say we can query AuthenticationId for not elevated token, linked to our elevated, and then try found process with exactly this token, impersonate it, and query with this token.

code example:

void CheckDrives()
{
    LONG dwDriveList = GetLogicalDrives();

    WCHAR Drive[] = L"Z:";

    ULONG n = 1 + 'Z' - 'A';

    do 
    {
        if (_bittest(&dwDriveList, --n))
        {
            if (DRIVE_REMOTE == GetDriveTypeW(Drive))
            {
                PUSE_INFO_0 pui;

                if (NET_API_STATUS err = NetUseGetInfo(0, Drive, 0, (BYTE**)&pui))
                {
                    DbgPrint("%S error=%u\n", Drive, err);
                }
                else
                {
                    DbgPrint("%S -> %S\n", pui->ui0_local, pui->ui0_remote);
                    NetApiBufferFree(pui);
                }
            }
        }

        --*Drive;

    } while (n);
}

BOOL ImpersonateNotElevated(LUID AuthenticationId)
{
    BOOL fOk = FALSE;

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32W pe = { sizeof(pe) };

        ULONG rcb;

        BOOL fFound = FALSE;

        if (Process32First(hSnapshot, &pe))
        {
            do 
            {
                if (HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID))
                {
                    HANDLE hToken, hNewToken;                   

                    if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
                    {
                        TOKEN_STATISTICS ts;

                        if (GetTokenInformation(hToken, TokenStatistics, &ts, sizeof(ts), &rcb))
                        {
                            if (ts.AuthenticationId.LowPart == AuthenticationId.LowPart && ts.AuthenticationId.HighPart == AuthenticationId.HighPart)
                            {
                                fFound = TRUE;

                                if (DuplicateToken(hToken, SecurityImpersonation, &hNewToken))
                                {
                                    fOk = SetThreadToken(0, hNewToken);

                                    CloseHandle(hNewToken);
                                }
                            }
                        }
                        CloseHandle(hToken);
                    }

                    CloseHandle(hProcess);
                }

            } while (!fFound && Process32Next(hSnapshot, &pe));
        }

        CloseHandle(hSnapshot);
    }

    return fOk;
}

void CheckDrivesNotElevated()
{
    HANDLE hToken;

    if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        union {
            TOKEN_ELEVATION_TYPE tet;
            TOKEN_LINKED_TOKEN tlt;
        };

        ULONG rcb;

        if (GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &rcb))
        {
            if (tet == TokenElevationTypeFull)
            {
                if (GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &rcb))
                {
                    TOKEN_STATISTICS ts;

                    BOOL fOk = GetTokenInformation(tlt.LinkedToken, ::TokenStatistics, &ts, sizeof(ts), &rcb);

                    CloseHandle(tlt.LinkedToken);

                    if (fOk)
                    {
                        if (ImpersonateNotElevated(ts.AuthenticationId))
                        {
                            CheckDrives();
                            SetThreadToken(0, 0);
                        }
                    }
                }
            }
            else
            {
                CheckDrives();
            }
        }
        CloseHandle(hToken);
    }
}

Upvotes: 1

Related Questions