Search code examples
c#wpfwindowssecuritysid

Get current logged user SID with no-admin account


I am developing a C# app.

For the application to work, the user must launch the application with administrative rights.

So if a user with a no-admin account wants to launch the application, he must right click and choose "Run as another user" to authenticate with an administrator account. The problem is that once logged in with the administrator account, I can’t get the no-admin user’s SID back.

When I’m doing this:

WindowsIdentity.GetCurrent().User

Its returns the SID of the admin user with which the user has logged in. However, I want to recover the SID of the user who logged in with the administrator account.


Solution

  • I found the solution :)

    I use Cassia to find the user name :

    ITerminalServicesManager manager = new TerminalServicesManager();
    ITerminalServicesSession session = manager.CurrentSession;
    

    And select all users who match with session.UserName and session.DomainName :

    ManagementObjectSearcher mos = new ManagementObjectSearcher("select * from Win32_Account where Name='" + session.UserName + "' AND Domain='" + session.DomainName + "'");
    ManagementObjectCollection Users = mos.Get();
    

    And after found the %appData% with user SID :

    // Get first user
    ManagementObject[] arr = new ManagementObject[1];
    Users.CopyTo(arr, 0);
    ManagementObject User = arr[0];
    
    // Found the %appData%
    const string regValueLocalAppData = @"AppData";
    const string regKeyShellFolders = @"HKEY_USERS\$SID$\Software\Microsoft\Windows\" +
                                                      @"CurrentVersion\Explorer\Shell Folders";
    
    var localAppDataPath = Microsoft.Win32.Registry.GetValue(regKeyShellFolders.Replace("$SID$", User["SID"].ToString()), regValueLocalAppData, null) as string;
    
    // Check if %appData% is not empty// Le dossier %appData% existe
    if (!string.IsNullOrWhiteSpace(localAppDataPath))
    {
        PathToRoaming = localAppDataPath;
    }
    
    

    It is also possible to create the path and check if it exists :

    public string GetAppdataPath() {
        string PathToRoaming = "";
    
        ITerminalServicesManager manager = new TerminalServicesManager();
        ITerminalServicesSession session = manager.CurrentSession;
    
        // Get path to Users directory
        Guid UserProfilesGuid = new Guid("0762D272-C50A-4BB0-A382-697DCD729B80");
        IntPtr pPath;
        SHGetKnownFolderPath(UserProfilesGuid, 0, IntPtr.Zero, out pPath);
        string PathToUsers = System.Runtime.InteropServices.Marshal.PtrToStringUni(pPath);
        System.Runtime.InteropServices.Marshal.FreeCoTaskMem(pPath);
    
        // Build path
        string PathToRoamingDir = String.Format("{0}\\{1}\\AppData\\Roaming", PathToUsers, session.UserName);
    
       if (Directory.Exists(PathToRoamingDir))
       {
          PathToRoaming = PathToRoamingDir;
       }
    }
    
    [System.Runtime.InteropServices.DllImport("shell32.dll")]
    static extern int SHGetKnownFolderPath([System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPStruct)] Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr pszPath);