C#, Cassia terminal server query and Impersonation

409 Views Asked by At

I have a function using the Cassia library in my forms app that returns all the users logged in via rdp to session hosts and some details about their session (and then adds it to a datagridview).

It works fine, as long as you are in the domain.

However I want to run this function outside of the domain. Impersonation seemed to be the way to go but I'm having issues with it, I either get 'bad username or password' (when I am 100% sure they are correct), or I get an 'Access is denied' error which comes from the cassia function. Which means that the impersonation didn't throw an error, but it also didn't work.

I've seen some places mention that the registry code AllowRemoteRPC has to be set to 1 on the machine you are connecting to, which is already the case.

Code (largely copied from other places):

string serverAddr = "server.com";
string userName = "domainUser"
string uPw = "1234"

IntPtr token;
if (!NativeMethods.LogonUser(userName, serverAddr, uPw, NativeMethods.LogonType.NewCredentials, NativeMethods.LogonProvider.WinNT50, out token))
{
   throw new Win32Exception();
}
try
{
   IntPtr tokenDuplicate;

    if (!NativeMethods.DuplicateToken(token, NativeMethods.SecurityImpersonationLevel.Impersonation, out tokenDuplicate))
    {
        throw new Win32Exception();
    }

    try
    {
         using (WindowsImpersonationContext impersonationContext = new WindowsIdentity(tokenDuplicate).Impersonate())
         {
             #Do stuff here querying the terminal servers
              ITerminalServicesManager manager = new TerminalServicesManager();
                    
              IList<ITerminalServer> svs = manager.GetServers("DOMAIN"); 

              int rowCnt = 0;

              foreach (ITerminalServer server in svs)
              {

                  server.Open();
                  string svr = default(string);
                  string cName = default(string);
                  string state = default(string);
                  string uName = default(string);

                  foreach (ITerminalServicesSession session in server.GetSessions())
                  {
                      NTAccount account = session.UserAccount;
                      uName = session.UserName;
                      svr = session.Server.ServerName;
                      cName = session.ClientName;
                      state = session.ConnectionState.ToString();

                      if (account != null)
                      {
                          userGrid1.Rows.Add();
                          userGrid1.Rows[rowCnt].Cells[0].Value = uName;
                          userGrid1.Rows[rowCnt].Cells[1].Value = svr;
                          userGrid1.Rows[rowCnt].Cells[2].Value = cName;
                          userGrid1.Rows[rowCnt].Cells[3].Value = state;

                          rowCnt++;
                      }

                 }

             }   

             impersonationContext.Undo();
         }
     }
     finally
     {
          if (tokenDuplicate != IntPtr.Zero)
          {
               NativeMethods.CloseHandle(tokenDuplicate);
          }
     }
  }
  finally
  {
       if (token != IntPtr.Zero)
       {
          NativeMethods.CloseHandle(token);
       }
 }
        
}

#the above is all inside a function, NativeMethods class copied below for clarity;

    internal static class NativeMethods
    {
        internal enum LogonType : int
        {
            Interactive = 2,
            Network = 3,
            Batch = 4,
            Service = 5,
            Unlock = 7,
            NetworkCleartext = 8,
            NewCredentials = 9
        }

        internal enum LogonProvider : int
        {
            Default = 0,
            WinNT35 = 1,
            WinNT40 = 2,
            WinNT50 = 3
        }

        internal enum SecurityImpersonationLevel : int
        {

            Anonymous = 0,
            Identification = 1,
            Impersonation = 2,
            Delegation = 3
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool LogonUser(
            string userName,
            string domain,
            string password,
            LogonType logonType,
            LogonProvider logonProvider,
            out IntPtr token);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool DuplicateToken(
            IntPtr existingTokenHandle,
            SecurityImpersonationLevel securityImpersonationLevel,
            out IntPtr duplicateTokenHandle);

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CloseHandle(IntPtr handle);
    }

Impersonation is very new to me, so it's possible I have a fundamental misunderstanding going on, or maybe its just a syntax issue. I don't know. Any help would be appreciated

0

There are 0 best solutions below