如何将 RUNAS /NETONLY 功能构建到 (C#/.NET/WinForms) 程序中?

发布于 2024-07-17 09:07:46 字数 803 浏览 5 评论 0原文

我们的工作站不是 SQL Server 所在域的成员。 (它们实际上根本不在域中 - 不要问)。

当我们使用 SSMS 或任何其他方式连接到 SQL Server 时,我们将 RUNAS /NETONLY 与 DOMAIN\user 一起使用。 然后我们输入密码并启动程序。 (RUNAS /NETONLY 不允许您在批处理文件中包含密码)。

因此,我有一个需要 SQL 连接的 .NET WinForms 应用程序,用户必须通过运行具有 RUNAS /NETONLY 命令行的批处理文件来启动它,然后启动 EXE。

如果用户不小心直接启动EXE,则无法连接到SQL Server。

右键单击该应用程序并使用“运行方式...”选项不起作用(可能是因为工作站并不真正了解该域)。

我正在寻找一种方法,让应用程序在启动任何重要操作之前在内部执行 RUNAS /NETONLY 功能。

请参阅此链接以了解 RUNAS /NETONLY 如何工作的说明: http:// /www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982

我想我必须将 LOGON_NETCREDENTIALS_ONLYCreateProcessWithLogonW 一起使用>

Our workstations are not members of the domain our SQL Server is on. (They're not actually on a domain at all - don't ask).

When we use SSMS or anything to connect to the SQL Server, we use RUNAS /NETONLY with DOMAIN\user. Then we type in the password and it launches the program. (RUNAS /NETONLY does not allow you to include the password in the batch file).

So I've got a .NET WinForms app which needs a SQL connection, and the users have to launch it by running a batch file which has the RUNAS /NETONLY command-line and then it launches the EXE.

If the user accidentally launches the EXE directly, it cannot connect to SQL Server.

Right-clicking on the app and using the "Run As..." option doesn't work (presumably because the workstation doesn't really know about the domain).

I'm looking for a way for the application to do the RUNAS /NETONLY functionality internally before it starts anything significant.

Please see this link for a description of how RUNAS /NETONLY works: http://www.eggheadcafe.com/conversation.aspx?messageid=32443204&threadid=32442982

I'm thinking I'm going to have to use LOGON_NETCREDENTIALS_ONLY with CreateProcessWithLogonW

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

℡寂寞咖啡 2024-07-24 09:07:46

我知道这是一个旧线程,但它非常有用。 我的情况与 Cade Roux 完全相同,因为我想要 /netonly 风格的功能。

John Rasch 的答案只需稍作修改即可!!!

添加以下常量(在第 102 行左右以保持一致性):

private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

然后将对 LogonUser 的调用更改为使用 LOGON32_LOGON_NEW_CREDENTIALS< /code> 而不是 LOGON32_LOGON_INTERACTIVE

这是我必须做出的唯一更改才能使其完美运行! 谢谢约翰和凯德!

以下是完整的修改后的代码,以便于复制/粘贴:

namespace Tools
{
    #region Using directives.
    // ----------------------------------------------------------------------

    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    // ----------------------------------------------------------------------
    #endregion

    /////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>   
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///     ...
    ///     using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///     {
    ///         ...
    ///         [code that executes under the new context]
    ///         ...
    ///     }
    ///     ...
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected])
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.
        // ------------------------------------------------------------------

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.
        // ------------------------------------------------------------------

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        userName,
                        domain,
                        password,
                        LOGON32_LOGON_NEW_CREDENTIALS,
                        LOGON32_PROVIDER_DEFAULT,
                        ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }

    /////////////////////////////////////////////////////////////////////////
}

I know this is an old thread, but it was very useful. I have the exact same situation as Cade Roux, as I wanted /netonly style functionality.

John Rasch's answer works with one small modification!!!

Add the following constant (around line 102 for consistency):

private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;

Then change the call to LogonUser to use LOGON32_LOGON_NEW_CREDENTIALS instead of LOGON32_LOGON_INTERACTIVE.

That's the only change I had to make to get this to work perfectly!!! Thank you John and Cade!!!

Here's the modified code in full for ease of copy/pasting:

namespace Tools
{
    #region Using directives.
    // ----------------------------------------------------------------------

    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    // ----------------------------------------------------------------------
    #endregion

    /////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>   
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///     ...
    ///     using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///     {
    ///         ...
    ///         [code that executes under the new context]
    ///         ...
    ///     }
    ///     ...
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected])
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.
        // ------------------------------------------------------------------

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.
        // ------------------------------------------------------------------

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        userName,
                        domain,
                        password,
                        LOGON32_LOGON_NEW_CREDENTIALS,
                        LOGON32_PROVIDER_DEFAULT,
                        ref token) != 0)
                    {
                        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                        {
                            tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                            impersonationContext = tempWindowsIdentity.Impersonate();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }

    /////////////////////////////////////////////////////////////////////////
}
叹倦 2024-07-24 09:07:46

我刚刚使用 ImpersonationContext 做了类似的事情。 它使用起来非常直观,并且非常适合我。

要以不同用户身份运行,语法为:

using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
    // code that executes under the new context...
}

这是类:

namespace Tools
{
    #region Using directives.
    // ----------------------------------------------------------------------

    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    // ----------------------------------------------------------------------
    #endregion

    /////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>   
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///     ...
    ///     using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///     {
    ///         ...
    ///         [code that executes under the new context]
    ///         ...
    ///     }
    ///     ...
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected])
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.
        // ------------------------------------------------------------------

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.
        // ------------------------------------------------------------------

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        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();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }

    /////////////////////////////////////////////////////////////////////////
}

I just did something similar to this using an ImpersonationContext. It's very intuitive to use and has worked perfectly for me.

To run as a different user, the syntax is:

using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
    // code that executes under the new context...
}

Here is the class:

namespace Tools
{
    #region Using directives.
    // ----------------------------------------------------------------------

    using System;
    using System.Security.Principal;
    using System.Runtime.InteropServices;
    using System.ComponentModel;

    // ----------------------------------------------------------------------
    #endregion

    /////////////////////////////////////////////////////////////////////////

    /// <summary>
    /// Impersonation of a user. Allows to execute code under another
    /// user context.
    /// Please note that the account that instantiates the Impersonator class
    /// needs to have the 'Act as part of operating system' privilege set.
    /// </summary>
    /// <remarks>   
    /// This class is based on the information in the Microsoft knowledge base
    /// article http://support.microsoft.com/default.aspx?scid=kb;en-us;Q306158
    /// 
    /// Encapsulate an instance into a using-directive like e.g.:
    /// 
    ///     ...
    ///     using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///     {
    ///         ...
    ///         [code that executes under the new context]
    ///         ...
    ///     }
    ///     ...
    /// 
    /// Please contact the author Uwe Keim (mailto:[email protected])
    /// for questions regarding this class.
    /// </remarks>
    public class Impersonator :
        IDisposable
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Constructor. Starts the impersonation with the given credentials.
        /// Please note that the account that instantiates the Impersonator class
        /// needs to have the 'Act as part of operating system' privilege set.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        public Impersonator(
            string userName,
            string domainName,
            string password)
        {
            ImpersonateValidUser(userName, domainName, password);
        }

        // ------------------------------------------------------------------
        #endregion

        #region IDisposable member.
        // ------------------------------------------------------------------

        public void Dispose()
        {
            UndoImpersonation();
        }

        // ------------------------------------------------------------------
        #endregion

        #region P/Invoke.
        // ------------------------------------------------------------------

        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern int LogonUser(
            string lpszUserName,
            string lpszDomain,
            string lpszPassword,
            int dwLogonType,
            int dwLogonProvider,
            ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int DuplicateToken(
            IntPtr hToken,
            int impersonationLevel,
            ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool RevertToSelf();

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(
            IntPtr handle);

        private const int LOGON32_LOGON_INTERACTIVE = 2;
        private const int LOGON32_PROVIDER_DEFAULT = 0;

        // ------------------------------------------------------------------
        #endregion

        #region Private member.
        // ------------------------------------------------------------------

        /// <summary>
        /// Does the actual impersonation.
        /// </summary>
        /// <param name="userName">The name of the user to act as.</param>
        /// <param name="domainName">The domain name of the user to act as.</param>
        /// <param name="password">The password of the user to act as.</param>
        private void ImpersonateValidUser(
            string userName,
            string domain,
            string password)
        {
            WindowsIdentity tempWindowsIdentity = null;
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;

            try
            {
                if (RevertToSelf())
                {
                    if (LogonUser(
                        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();
                        }
                        else
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                if (token != IntPtr.Zero)
                {
                    CloseHandle(token);
                }
                if (tokenDuplicate != IntPtr.Zero)
                {
                    CloseHandle(tokenDuplicate);
                }
            }
        }

        /// <summary>
        /// Reverts the impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            if (impersonationContext != null)
            {
                impersonationContext.Undo();
            }
        }

        private WindowsImpersonationContext impersonationContext = null;

        // ------------------------------------------------------------------
        #endregion
    }

    /////////////////////////////////////////////////////////////////////////
}
在风中等你 2024-07-24 09:07:46

我收集了这些有用的链接:

http://www .developmentnow.com/g/36_2006_3_0_0_725350/Need-help-with-impersonation-please-.htm

http://blrchen.spaces.live.com/blog/cns!572204F8C4F8A77A!251.entry

链接

http://msmvps.com/blogs/martinzugec/archive/2008/06 /03/use-runas-from-non-domain-computer.aspx

事实证明,我将不得不将 LOGON_NETCREDENTIALS_ONLYCreateProcessWithLogonW 一起使用。 我将看看是否可以让程序检测它是否已以这种方式启动,如果没有,则收集域凭据并自行启动。 这样就只有一个自我管理的 EXE。

I gathered these useful links:

http://www.developmentnow.com/g/36_2006_3_0_0_725350/Need-help-with-impersonation-please-.htm

http://blrchen.spaces.live.com/blog/cns!572204F8C4F8A77A!251.entry

Link

http://msmvps.com/blogs/martinzugec/archive/2008/06/03/use-runas-from-non-domain-computer.aspx

It turns out I'm going to have to use LOGON_NETCREDENTIALS_ONLY with CreateProcessWithLogonW. I'm going to see if I can have the program detect if it has been launched that way and if not, gather the domain credentials and launch itself. That way there will only be one self-managing EXE.

北凤男飞 2024-07-24 09:07:46

使用此处非常有用的答案,我创建了下面的简化类,该类使用 .NET Standard 中也提供的 API:

public class Impersonator
{
    [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool LogonUser(
        string lpszUsername,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        out SafeAccessTokenHandle phToken);

    public void RunAs(string domain, string username, string password, Action action)
    {
        using (var accessToken = GetUserAccessToken(domain, username, password))
        {
            WindowsIdentity.RunImpersonated(accessToken, action);
        }
    }

    private SafeAccessTokenHandle GetUserAccessToken(string domain, string username, string password)
    {
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_NETONLY = 9;

        bool isLogonSuccessful = LogonUser(username, domain, password, LOGON32_LOGON_NETONLY, LOGON32_PROVIDER_DEFAULT, out var safeAccessTokenHandle);
        if (!isLogonSuccessful)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        return safeAccessTokenHandle;
    }
}

以下是使用它的方法:

_impersonator.RunAs(
    "DOMAIN",
    "Username",
    "Password",
    () =>
    {
        Console.WriteLine("code executed here runs as the specified user with /netonly");
    });

Using the very helpful answers here, I created the below simplified class which uses APIs that are also available in .NET Standard:

public class Impersonator
{
    [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool LogonUser(
        string lpszUsername,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        out SafeAccessTokenHandle phToken);

    public void RunAs(string domain, string username, string password, Action action)
    {
        using (var accessToken = GetUserAccessToken(domain, username, password))
        {
            WindowsIdentity.RunImpersonated(accessToken, action);
        }
    }

    private SafeAccessTokenHandle GetUserAccessToken(string domain, string username, string password)
    {
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_NETONLY = 9;

        bool isLogonSuccessful = LogonUser(username, domain, password, LOGON32_LOGON_NETONLY, LOGON32_PROVIDER_DEFAULT, out var safeAccessTokenHandle);
        if (!isLogonSuccessful)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        return safeAccessTokenHandle;
    }
}

Here's how you use it:

_impersonator.RunAs(
    "DOMAIN",
    "Username",
    "Password",
    () =>
    {
        Console.WriteLine("code executed here runs as the specified user with /netonly");
    });
2024-07-24 09:07:46

此代码是 RunAs 类的一部分,我们用它来启动具有提升权限的外部进程。 为用户名和参数传递 null 密码将通过标准 UAC 警告提示。 当传递用户名和密码的值时,您实际上可以在没有 UAC 提示的情况下启动提升的应用程序。

public static Process Elevated( string process, string args, string username, string password, string workingDirectory )
{
    if( process == null || process.Length == 0 ) throw new ArgumentNullException( "process" );

    process = Path.GetFullPath( process );
    string domain = null;
    if( username != null )
        username = GetUsername( username, out domain );
    ProcessStartInfo info = new ProcessStartInfo();
    info.UseShellExecute = false;
    info.Arguments = args;
    info.WorkingDirectory = workingDirectory ?? Path.GetDirectoryName( process );
    info.FileName = process;
    info.Verb = "runas";
    info.UserName = username;
    info.Domain = domain;
    info.LoadUserProfile = true;
    if( password != null )
    {
        SecureString ss = new SecureString();
        foreach( char c in password )
            ss.AppendChar( c );
        info.Password = ss;
    }

    return Process.Start( info );
}

private static string GetUsername( string username, out string domain ) 
{
    SplitUserName( username, out username, out domain );

    if( domain == null && username.IndexOf( '@' ) < 0 )
        domain = Environment.GetEnvironmentVariable( "USERDOMAIN" );
    return username;
}

This code is part of an RunAs class that we use to launch an external process with elevated privleges. Passing null for username & password will prompt with the standard UAC warnings. When passing a value for the username and password you can actually launch the application elevated without the UAC prompt.

public static Process Elevated( string process, string args, string username, string password, string workingDirectory )
{
    if( process == null || process.Length == 0 ) throw new ArgumentNullException( "process" );

    process = Path.GetFullPath( process );
    string domain = null;
    if( username != null )
        username = GetUsername( username, out domain );
    ProcessStartInfo info = new ProcessStartInfo();
    info.UseShellExecute = false;
    info.Arguments = args;
    info.WorkingDirectory = workingDirectory ?? Path.GetDirectoryName( process );
    info.FileName = process;
    info.Verb = "runas";
    info.UserName = username;
    info.Domain = domain;
    info.LoadUserProfile = true;
    if( password != null )
    {
        SecureString ss = new SecureString();
        foreach( char c in password )
            ss.AppendChar( c );
        info.Password = ss;
    }

    return Process.Start( info );
}

private static string GetUsername( string username, out string domain ) 
{
    SplitUserName( username, out username, out domain );

    if( domain == null && username.IndexOf( '@' ) < 0 )
        domain = Environment.GetEnvironmentVariable( "USERDOMAIN" );
    return username;
}
放手` 2024-07-24 09:07:46

我想你不能只将应用程序的用户添加到 sql server,然后使用 sql 身份验证而不是 windows 身份验证?

I suppose you can't just add a user for the app to sql server and then use sql authentication rather than windows authentication?

失与倦" 2024-07-24 09:07:46

对于 .NET Core,WindowsImpersonationContextWindowsIdentity.Impersonate() 不可用。

以下是 .NET Core 类似解决方案的链接。 WindowsImpersonationContext 和 WindowsImpersonationContext 在 ASP.Core 中找不到 Impersonate()

For .NET Core, WindowsImpersonationContext and WindowsIdentity.Impersonate() are not available.

Here is a link to a similar solution for .NET Core. WindowsImpersonationContext & Impersonate() not found in ASP.Core

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文