C#:以“启动流程”;“真正的”;具有硬编码权限的管理员

C#:以“启动流程”;“真正的”;具有硬编码权限的管理员,c#,.net,impersonation,runas,C#,.net,Impersonation,Runas,我需要以管理员权限静默安装不同的设置。 我必须硬编码特权,因为用户不知道自己安装设置的用户名和密码 我尝试了两种不同的方法 ProcessStartInfo,用户名、密码和UseShellExecute=false 使用 [DllImport("advapi32.dll", SetLastError = true)] private static extern bool LogonUser(...); 在这两种情况下windowsPrincipal.IsInRole(WindowsBuilt

我需要以管理员权限静默安装不同的设置。 我必须硬编码特权,因为用户不知道自己安装设置的用户名和密码

我尝试了两种不同的方法

  • ProcessStartInfo,用户名、密码和UseShellExecute=false
  • 使用

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LogonUser(...);
    
  • 在这两种情况下
    windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator)
    返回false 由于权限不足,我的设置无法运行

    奇怪的行为:LogonUser总是返回true,即使凭据无效

    以下是模拟类:

    namespace BlackBlade.Utilities
    {
        /// <summary>
        /// Quelle: http://www.blackbladeinc.com/en-us/community/blogs/archive/2009/08/10/runas-in-c.aspx
        /// </summary>
        public class SecurityUtilities
        {
            [DllImport("advapi32.dll", SetLastError = true)]
            private static extern bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
    
            public delegate void RunAsDelegate();
    
            public static void RunAs(RunAsDelegate methodToRunAs, string username, string password)
            {
                string userName;
    
                string domain;
                if (username.IndexOf('\\') > 0)
                {
                    //a domain name was supplied
                    string[] usernameArray = username.Split('\\');
                    userName = usernameArray[1];
                    domain = usernameArray[0];
                }
                else
                {
                    //there was no domain name supplied
                    userName = username;
                    domain = ".";
                }
                RunAs(methodToRunAs, userName, password, domain);
            }
    
            public static void RunAs(RunAsDelegate methodToRunAs, string username, string password, string domain)
            {
                IntPtr userToken;
                WindowsIdentity adminIdentity = null;
                WindowsImpersonationContext adminImpersonationContext = null;
    
                try
                {
                    if (LogonUser(username, string.IsNullOrEmpty(domain) ? "." : domain, password, 9, 0, out userToken))
                    {
                        //the impersonation suceeded
                        adminIdentity = new WindowsIdentity(userToken);
                        adminImpersonationContext = adminIdentity.Impersonate();
    
                        // todo: Entfernen.
                        WindowsPrincipal p = new WindowsPrincipal(adminIdentity);
                        MessageBox.Show(p.IsInRole(WindowsBuiltInRole.Administrator).ToString());
    
                        //run the delegate method
                        //methodToRunAs();
                    }
                    else
                        throw new Exception(string.Format("Could not impersonate user {0} in domain {1} with the specified password.", username, domain));
                }
                catch (Exception se)
                {
                    int ret = Marshal.GetLastWin32Error();
                    if (adminImpersonationContext != null)
                        adminImpersonationContext.Undo();
                    throw new Exception("Error code: " + ret.ToString(), se);
                }
                finally
                {
                    //revert to self
                    if (adminImpersonationContext != null)
                        adminImpersonationContext.Undo();
                }
            }
        }
    }
    
    namespace BlackBlade.Utilities
    {
    /// 
    ///奎尔:http://www.blackbladeinc.com/en-us/community/blogs/archive/2009/08/10/runas-in-c.aspx
    /// 
    公共类安全实用程序
    {
    [DllImport(“advapi32.dll”,SetLastError=true)]
    私有静态外部bool LogonUser(字符串lpszUserName、字符串lpszDomain、字符串lpszPassword、int-dwLogonType、int-dwLogonProvider、out-IntPtr phToken);
    公共委托void RunAsDelegate();
    公共静态无效RunAs(RunAsDelegate methodToRunAs、字符串用户名、字符串密码)
    {
    字符串用户名;
    字符串域;
    if(username.IndexOf('\\')>0)
    {
    //提供了一个域名
    字符串[]usernameArray=username.Split('\\');
    userName=usernameArray[1];
    domain=usernameArray[0];
    }
    其他的
    {
    //没有提供域名
    用户名=用户名;
    domain=“.”;
    }
    RunAs(methodToRunAs、用户名、密码、域);
    }
    公共静态无效RunAs(RunAsDelegate methodToRunAs、字符串用户名、字符串密码、字符串域)
    {
    IntPtr用户令牌;
    WindowsIdentity adminIdentity=null;
    WindowsImpersonationContext adminImpersonationContext=null;
    尝试
    {
    if(LogonUser(用户名,字符串。IsNullOrEmpty(域)?“:域,密码,9,0,out userToken))
    {
    //模仿成功了
    adminIdentity=新的WindowsIdentity(userToken);
    adminImpersonationContext=adminIdentity.Impersonate();
    //托多:恩特弗宁。
    WindowsPrincipal p=新的WindowsPrincipal(adminIdentity);
    Show(p.IsInRole(WindowsBuiltInRole.Administrator.ToString());
    //运行委托方法
    //methodorunas();
    }
    其他的
    抛出新异常(string.Format(“无法使用指定的密码模拟域{1}中的用户{0}。”,用户名,域));
    }
    捕获(异常se)
    {
    int-ret=Marshal.GetLastWin32Error();
    if(adminImpersonationContext!=null)
    adminImpersonationContext.Undo();
    抛出新异常(“错误代码:+ret.ToString(),se);
    }
    最后
    {
    //回归自我
    if(adminImpersonationContext!=null)
    adminImpersonationContext.Undo();
    }
    }
    }
    }
    
    使用组策略推出MSI或EXE安装程序


    或者,使用任务计划程序以本地系统帐户的身份运行安装程序。

    是否尝试将dwLogonType设置为2而不是9

    下面是一个适用于我的代码示例:

        public const int LOGON32_LOGON_INTERACTIVE = 2;
        public const int LOGON32_PROVIDER_DEFAULT = 0;
    
        WindowsImpersonationContext impersonationContext;
    
        [DllImport("advapi32.dll")]
        public static extern int LogonUserA(String lpszUserName,
            String lpszDomain,
            String lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DuplicateToken(IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);
    
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();
    
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern bool CloseHandle(IntPtr handle);
    
            WindowsIdentity tempWindowsIdentity;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
    
            if (RevertToSelf())
            {
                if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                    LOGON32_PROVIDER_DEFAULT, ref token) != 0)
                {
                    if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                    {
                        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                        impersonationContext = tempWindowsIdentity.Impersonate();
                        if (impersonationContext != null)
                        {
                            CloseHandle(token);
                            CloseHandle(tokenDuplicate);
                            return true;
                        }
                    }
                }
            }
            if (token != IntPtr.Zero)
                CloseHandle(token);
            if (tokenDuplicate != IntPtr.Zero)
                CloseHandle(tokenDuplicate);
    
    以运行方式启动的进程请求提升


    编辑:首先,使用已知的管理员凭据启动进程,可以使用LogonUser/CreateProcessAsUser或CreateProcessWithLogon。然后检查真正的管理员权限(可能UAC已关闭),如有必要,让此进程(以非提升管理员身份运行)使用启动自身的另一个副本。这是。UAC被明确设计为在未经用户确认的情况下禁止提升


    用户必须确认标高,除非UAC关闭。要获得更好的用户体验(减少可怕的消息框),请获取代码签名证书并签署此可执行文件。

    请为您的问题提供一个更有意义的标题!感谢您提供了一个更好的位置:)LogonUser返回true是正确的,即使凭据无效,因为使用新的\u凭据登录类型,它实际上不会登录提供的用户!它只是将凭证存储在呼叫用户令牌的副本中,以便在网络操作中使用(想想
    net use/U
    )。如果您想将用户登录到本地计算机上,请使用rdkleine建议的交互式登录类型。根据您的评论,我必须对这个问题投反对票。你没有向用户详细解释情况。但是我描述了我想要什么,但似乎没有人关心,并且描述了其他方式。我知道安全问题,但这是实际的设置。不可能。这些设备是无域的。第二条建议也是不可能的。我们将发送一个U盘给我们的用户,它应该像“单击我们的setup.exe”一样简单。那么谁有管理员登录?用户?你呢?用户的系统管理员?正确的答案是将你的设置标记为需要管理员权限,然后让用户的系统管理员处理。换句话说:不要这样做。您基本上是要求用户关闭安全性。thumb驱动器的任何收件人都将获得其机器的管理员密码。是的,安全是一种痛苦。我无法改变这一点。情况如上所述。“保存它的代码将被模糊化”:对。。。像那样永远有效。如果奖品是值得的,一个人就可以破获它