2015-05-08 30 views
6

Ho difficoltà a trovare un caso d'uso molto specifico per funzionare. L'applicazione in questione ha due componenti: un servizio Windows, che deve essere eseguito in un contesto privilegiato all'esterno del desktop (ovvero per accettare le connessioni mentre un utente è connesso o meno) e un'app Winforms client. Il servizio accetta le connessioni websocket e, se la richiesta di connessione dovesse riuscire, si suppone che l'utente effettui il login interattivo (nel desktop) e genera un processo come tale utente con accesso desktop. Ho usato i seguenti link e, sebbene siano in grado di impersonare un utente, in realtà non registrano l'utente sul desktop, cioè se guardo il sistema usando VNC o se lo provo sul mio sistema locale, il l'utente non viene loggato. Il processo, tuttavia, viene generato come utente, ma ovviamente non con l'accesso desktop.Servizio di amministrazione: registra l'utente nel desktop, genera un processo che può interagire con il desktop

Qualcuno ha un esempio di codice che registrerà un utente nel desktop?

I collegamenti e il codice che ho provato:

Using Process.Start() to start a process as a different user from within a Windows Service

How to use LogonUser properly to impersonate domain user from workgroup client pubblico

Launch a process under another user's credentials

https://social.msdn.microsoft.com/Forums/vstudio/en-US/9fb068b0-507b-4b6b-879a-b0fbe492ba92/c-start-program-with-different-user-credentials

Il codice attuale è:

using Cassia; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics; 
using System.DirectoryServices; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Permissions; 
using System.Security.Principal; 
using System.ServiceProcess; 

namespace program 
{ 
    public partial class service 
    { 
     #region Interop 

     [StructLayout(LayoutKind.Sequential)] 
     public struct LUID 
     { 
      public UInt32 LowPart; 
      public Int32 HighPart; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct LUID_AND_ATTRIBUTES 
     { 
      public LUID Luid; 
      public UInt32 Attributes; 
     } 

     public struct TOKEN_PRIVILEGES 
     { 
      public UInt32 PrivilegeCount; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
      public LUID_AND_ATTRIBUTES[] Privileges; 
     } 

     enum TOKEN_INFORMATION_CLASS 
     { 
      TokenUser = 1, 
      TokenGroups, 
      TokenPrivileges, 
      TokenOwner, 
      TokenPrimaryGroup, 
      TokenDefaultDacl, 
      TokenSource, 
      TokenType, 
      TokenImpersonationLevel, 
      TokenStatistics, 
      TokenRestrictedSids, 
      TokenSessionId, 
      TokenGroupsAndPrivileges, 
      TokenSessionReference, 
      TokenSandBoxInert, 
      TokenAuditPolicy, 
      TokenOrigin, 
      TokenElevationType, 
      TokenLinkedToken, 
      TokenElevation, 
      TokenHasRestrictions, 
      TokenAccessInformation, 
      TokenVirtualizationAllowed, 
      TokenVirtualizationEnabled, 
      TokenIntegrityLevel, 
      TokenUIAccess, 
      TokenMandatoryPolicy, 
      TokenLogonSid, 
      MaxTokenInfoClass 
     } 

     [Flags] 
     enum CreationFlags : uint 
     { 
      CREATE_BREAKAWAY_FROM_JOB = 0x01000000, 
      CREATE_DEFAULT_ERROR_MODE = 0x04000000, 
      CREATE_NEW_CONSOLE = 0x00000010, 
      CREATE_NEW_PROCESS_GROUP = 0x00000200, 
      CREATE_NO_WINDOW = 0x08000000, 
      CREATE_PROTECTED_PROCESS = 0x00040000, 
      CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, 
      CREATE_SEPARATE_WOW_VDM = 0x00001000, 
      CREATE_SUSPENDED = 0x00000004, 
      CREATE_UNICODE_ENVIRONMENT = 0x00000400, 
      DEBUG_ONLY_THIS_PROCESS = 0x00000002, 
      DEBUG_PROCESS = 0x00000001, 
      DETACHED_PROCESS = 0x00000008, 
      EXTENDED_STARTUPINFO_PRESENT = 0x00080000 
     } 

     public enum TOKEN_TYPE 
     { 
      TokenPrimary = 1, 
      TokenImpersonation 
     } 

     public enum SECURITY_IMPERSONATION_LEVEL 
     { 
      SecurityAnonymous, 
      SecurityIdentification, 
      SecurityImpersonation, 
      SecurityDelegation 
     } 

     [Flags] 
     enum LogonFlags 
     { 
      LOGON_NETCREDENTIALS_ONLY = 2, 
      LOGON_WITH_PROFILE = 1 
     } 

     enum LOGON_TYPE 
     { 
      LOGON32_LOGON_INTERACTIVE = 2, 
      LOGON32_LOGON_NETWORK, 
      LOGON32_LOGON_BATCH, 
      LOGON32_LOGON_SERVICE, 
      LOGON32_LOGON_UNLOCK = 7, 
      LOGON32_LOGON_NETWORK_CLEARTEXT, 
      LOGON32_LOGON_NEW_CREDENTIALS 
     } 

     enum LOGON_PROVIDER 
     { 
      LOGON32_PROVIDER_DEFAULT, 
      LOGON32_PROVIDER_WINNT35, 
      LOGON32_PROVIDER_WINNT40, 
      LOGON32_PROVIDER_WINNT50 
     } 

     struct SECURITY_ATTRIBUTES 
     { 
      public uint Length; 
      public IntPtr SecurityDescriptor; 
      public bool InheritHandle; 
     } 

     [Flags] 
     enum SECURITY_INFORMATION : uint 
     { 
      OWNER_SECURITY_INFORMATION = 0x00000001, 
      GROUP_SECURITY_INFORMATION = 0x00000002, 
      DACL_SECURITY_INFORMATION = 0x00000004, 
      SACL_SECURITY_INFORMATION = 0x00000008, 
      UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000, 
      UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000, 
      PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000, 
      PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 
     } 

     [StructLayoutAttribute(LayoutKind.Sequential)] 
     struct SECURITY_DESCRIPTOR 
     { 
      public byte revision; 
      public byte size; 
      public short control; // public SECURITY_DESCRIPTOR_CONTROL control; 
      public IntPtr owner; 
      public IntPtr group; 
      public IntPtr sacl; 
      public IntPtr dacl; 
     } 

     struct STARTUPINFO 
     { 
      public uint cb; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string Reserved; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string Desktop; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public string Title; 
      public uint X; 
      public uint Y; 
      public uint XSize; 
      public uint YSize; 
      public uint XCountChars; 
      public uint YCountChars; 
      public uint FillAttribute; 
      public uint Flags; 
      public ushort ShowWindow; 
      public ushort Reserverd2; 
      public byte bReserverd2; 
      public IntPtr StdInput; 
      public IntPtr StdOutput; 
      public IntPtr StdError; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     struct PROCESS_INFORMATION 
     { 
      public IntPtr Process; 
      public IntPtr Thread; 
      public uint ProcessId; 
      public uint ThreadId; 
     } 

     [DllImport("advapi32.dll", SetLastError = true)] 
     static extern bool InitializeSecurityDescriptor(IntPtr pSecurityDescriptor, uint dwRevision); 
     const uint SECURITY_DESCRIPTOR_REVISION = 1; 

     [DllImport("advapi32.dll", SetLastError = true)] 
     static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     extern static bool DuplicateTokenEx(
      IntPtr hExistingToken, 
      uint dwDesiredAccess, 
      ref SECURITY_ATTRIBUTES lpTokenAttributes, 
      SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 
      TOKEN_TYPE TokenType, 
      out IntPtr phNewToken); 

     [DllImport("advapi32.dll", SetLastError = true)] 
     public static extern bool LogonUser(
      string lpszUsername, 
      string lpszDomain, 
      string lpszPassword, 
      int dwLogonType, 
      int dwLogonProvider, 
      out IntPtr phToken 
      ); 

     [DllImport("advapi32.dll", SetLastError = true)] 
     static extern bool GetTokenInformation(
      IntPtr TokenHandle, 
      TOKEN_INFORMATION_CLASS TokenInformationClass, 
      IntPtr TokenInformation, 
      int TokenInformationLength, 
      out int ReturnLength 
      ); 

     [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
     static extern bool CreateProcessAsUser(
      IntPtr Token, 
      [MarshalAs(UnmanagedType.LPTStr)] string ApplicationName, 
      [MarshalAs(UnmanagedType.LPTStr)] string CommandLine, 
      ref SECURITY_ATTRIBUTES ProcessAttributes, 
      ref SECURITY_ATTRIBUTES ThreadAttributes, 
      bool InheritHandles, 
      uint CreationFlags, 
      IntPtr Environment, 
      [MarshalAs(UnmanagedType.LPTStr)] string CurrentDirectory, 
      ref STARTUPINFO StartupInfo, 
      out PROCESS_INFORMATION ProcessInformation); 

     [DllImport("Kernel32.dll")] 
     extern static int CloseHandle(IntPtr handle); 

     [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 
     internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen); 

     [DllImport("advapi32.dll", SetLastError = true)] 
     internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); 

     [StructLayout(LayoutKind.Sequential, Pack = 1)] 
     internal struct TokPriv1Luid 
     { 
      public int Count; 
      public long Luid; 
      public int Attr; 
     } 

     internal const int SE_PRIVILEGE_ENABLED = 0x00000002; 
     internal const int TOKEN_QUERY = 0x00000008; 
     internal const int TOKEN_DUPLICATE = 0x0002; 
     internal const int TOKEN_ASSIGN_PRIMARY = 0x0001; 

     #endregion 

     public static bool LoginUser(string domain, string username, string password, string program, string workingDir) 
     { 
      IntPtr token = IntPtr.Zero; 
      IntPtr primaryToken = IntPtr.Zero; 

      try 
      { 
       bool result = LogonUser(username, domain, password, (int)LOGON_TYPE.LOGON32_LOGON_NETWORK, (int)LOGON_PROVIDER.LOGON32_PROVIDER_DEFAULT, out token); 
       if (!result) 
       { 
        int winError = Marshal.GetLastWin32Error(); 
        Console.WriteLine("LoginUser unable to login user " + username + ", error: " + winError); 
        return false; 
       } 

       SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES(); 
       SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR(); 
       IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(sd)); 
       Marshal.StructureToPtr(sd, ptr, false); 
       InitializeSecurityDescriptor(ptr, SECURITY_DESCRIPTOR_REVISION); 
       sd = (SECURITY_DESCRIPTOR)Marshal.PtrToStructure(ptr, typeof(SECURITY_DESCRIPTOR)); 

       result = SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false); 
       if (!result) 
       { 
        int winError = Marshal.GetLastWin32Error(); 
       } 

       primaryToken = new IntPtr(); 
       result = DuplicateTokenEx(token, 0, ref processAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken); 
       if (!result) 
       { 
        int winError = Marshal.GetLastWin32Error(); 
       } 

       processAttributes.SecurityDescriptor = ptr; 
       processAttributes.Length = (uint)Marshal.SizeOf(sd); 
       processAttributes.InheritHandle = true; 

       SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES(); 
       threadAttributes.SecurityDescriptor = IntPtr.Zero; 
       threadAttributes.Length = 0; 
       threadAttributes.InheritHandle = false; 

       bool inheritHandles = true; 
       IntPtr environment = IntPtr.Zero; 

       STARTUPINFO startupInfo = new STARTUPINFO(); 
       startupInfo.Desktop = ""; 

       PROCESS_INFORMATION processInformation; 

       result = CreateProcessAsUser(
        primaryToken, 
        program, 
        program, 
        ref processAttributes, 
        ref threadAttributes, 
        inheritHandles, 
        16, 
        environment, 
        workingDir, 
        ref startupInfo, 
        out processInformation); 

       if (!result) 
       { 
        int winError = Marshal.GetLastWin32Error(); 
        Console.WriteLine("LoginUser unable to create process as user " + username + ", error: " + winError); 
        return false; 
       } 

       return true; 
      } 
      catch (Exception e) 
      { 
       Console.WriteLine("LoginUser exception encountered: " + e.Message()); 
       return false; 
      } 
      finally 
      { 
       if (token != IntPtr.Zero) 
       { 
        int x = CloseHandle(token); 
        if (x == 0) 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        x = CloseHandle(primaryToken); 
        if (x == 0) 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
     } 

     public static SecureString securePassword(string password) 
     { 
      if (string_null(password)) return null; 
      SecureString secure = new SecureString(); 
      foreach (char c in password) 
      { 
       secure.AppendChar(c); 
      } 
      return secure; 
     } 
    } 
} 

e il mio obiettivo è quello di essere in grado di chiamare semplicemente come:

if (!LoginUser("machinename", "username", "password", "c:\\path\\to\\program.exe", "c:\\path\\to")) 
{ 
    // error 
} 
else 
{ 
    // success, user is logged into desktop and app is launch 
    // as user with desktop access 
} 

risposta

3

Ho avuto lo stesso scenario di prima e le cose si complicano così ho usato PSEXEC in combinazione con Process.Start

proprio utilizzando PSEXEC come che cosa è indicato sul loro campione tutto quello che dovete fare è qualcosa di simile

Copiare o installare l'eseguibile tramite cod e o manualmente (es. program.exe) al sistema remoto ed eseguire in modo interattivo, in esecuzione con l'account Danny Glover:

psexec \\workstation64 -c program.exe -u YourUser -p YourPa55w0rd 

Ora sapete i parametri è possibile utilizzare Process.Start per eseguirlo. così sarà simile a questa

using System.Diagnostics; 
... 
Process process = new Process(); 
process.StartInfo.FileName = "program.exe"; 
process.StartInfo.Arguments = "\\workstation64 -c program.exe -u YourUser -p YourPa55w0rd"; 
process.Start(); 
process.WaitForExit(); 

Tra l'altro si può imparare di più e scaricare PSEXEC qui http://ss64.com/nt/psexec.html

+0

Hi Raymund, questo in realtà registrerà l'utente YourUser nel desktop e avvierà l'app? – joelc

+1

Non funziona fisicamente ma eseguirà l'applicazione sul desktop/workstation a cui si riferisce come utente indicato. L'ho usato molto specialmente sul nostro scenario in cui avevamo server in oltre 200 negozi dove abbiamo bisogno di distribuire un eseguibile ed eseguirlo come un certo utente – Raymund

+0

Grazie, il problema però è che l'applicazione che devo eseguire per conto dell'utente sta usando servizi che richiedono che l'account abbia accesso al desktop, quindi questo non funzionerà. – joelc

0

Ho trovato il vostro problema su Elance.com e trovato questo link.

Ho avuto lo stesso tipo di problema con uno dei miei progetti. Ciò ha richiesto il servizio Windows per avviare un comunicatore terminale POS e che dovrebbe essere dotato di interfaccia utente con accesso amministratore. Ho provato la stessa imitazione di winlogon.exe per evitare il controllo dell'account utente, ma questo non ha aiutato.

Per il mio problema, ho utilizzato Attività pianificate e ho creato il mio compito utilizzando C#. Puoi trovare una buona libreria qui http://taskscheduler.codeplex.com. Ora su una chiamata richiesta è possibile eseguire l'attività in modo dinamico e si ha il pieno controllo su di essa.

È possibile creare la propria attività/modifica/eliminazione in modo dinamico e può eseguire le app evitando il controllo dell'account utente.

0

Stai cercando di creare una nuova sessione interattiva. Sfortunatamente, questo non è possibile. Per quanto ho capito, si desidera avviare un processo e quindi controllare la macchina in remoto con VNC. Forse hai solo bisogno di usare Remote Desktop?

+0

Ciao Codeguard, è tecnicamente possibile come molti chioschi hanno costruito i propri provider di autenticazione per fare esattamente questo e sto cercando di farlo all'interno della mia app. Per ragioni a cui non posso accedere, è necessario farlo a livello di codice senza consentire all'utente di visualizzare o interagire direttamente con la schermata di accesso. – joelc