Process.Start()抛出"访问被拒绝"冒充后

时间:2013-05-29 05:11:48

标签: c# .net process impersonation

我在使用Process.Start()+ Impersonation从文件服务器执行文件时遇到问题。请帮我解决我的问题。还有另一种方法吗?

这是按钮点击事件。

private void btnOpen_Click(object sender, EventArgs e)
    {
        try
        {
            newUser = cls.ImpersonateUser("username", "domain", "password");

            string fileName = @"\\network_computer\Test\Test.doc";

            System.Diagnostics.Process.Start(fileName);
        }
        catch (Exception ex) { throw ex; }
        finally
        {
            if (newUser != null)
                newUser.Undo();
        }
    }

这是假冒课程。

public class clsImpersonate
    {
        #region 'Impersonation'

        // group type enum
        public enum SECURITY_IMPERSONATION_LEVEL : int
        {
            SecurityAnonymous = 0,
            SecurityIdentification = 1,
            SecurityImpersonation = 2,
            SecurityDelegation = 3
        }

        // obtains user token
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

        // closes open handes returned by LogonUser
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        // creates duplicate token handle
        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
            int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

        private System.Security.Principal.WindowsImpersonationContext newUser;

        public WindowsImpersonationContext ImpersonateUser(string sUsername, string sDomain, string sPassword)
        {
            // initialize tokens
            IntPtr pExistingTokenHandle = new IntPtr(0);
            IntPtr pDuplicateTokenHandle = new IntPtr(0);
            pExistingTokenHandle = IntPtr.Zero;
            pDuplicateTokenHandle = IntPtr.Zero;

            // if domain name was blank, assume local machine
            if (sDomain == "")
                sDomain = System.Environment.MachineName;

            try
            {
                string sResult = null;

                const int LOGON32_PROVIDER_DEFAULT = 0;

                // create token
                const int LOGON32_LOGON_INTERACTIVE = 2;
                //const int SecurityImpersonation = 2;

                // get handle to token
                bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

                // did impersonation fail?
                if (false == bImpersonated)
                {
                    int nErrorCode = Marshal.GetLastWin32Error();
                    sResult = "LogonUser() failed with error code: " + nErrorCode + "\r\n";

                    // show the reason why LogonUser failed
                    //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

                // Get identity before impersonation
                sResult += "Before impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";

                bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);

                // did DuplicateToken fail?
                if (false == bRetVal)
                {
                    int nErrorCode = Marshal.GetLastWin32Error();
                    CloseHandle(pExistingTokenHandle); // close existing handle
                    sResult += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n";

                    // show the reason why DuplicateToken failed
                    //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return null;
                }
                else
                {
                    // create new identity using new primary token
                    WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
                    WindowsImpersonationContext impersonatedUser = newId.Impersonate();

                    // check the identity after impersonation
                    sResult += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";

                    //MessageBox.Show(sResult, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return impersonatedUser;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                // close handle(s)
                if (pExistingTokenHandle != IntPtr.Zero)
                    CloseHandle(pExistingTokenHandle);
                if (pDuplicateTokenHandle != IntPtr.Zero)
                    CloseHandle(pDuplicateTokenHandle);
            }
        }

        #endregion
    }

1 个答案:

答案 0 :(得分:2)

如果您进行调试,您会在

中看到任何错误
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);

在按钮点击事件中,尝试添加Using声明:

private void btnOpen_Click(object sender, EventArgs e)
{
    try
    {
        using (newUser = cls.ImpersonateUser("username", "domain", "password"))
        {
            string fileName = @"\\network_computer\Test\Test.doc";
            System.Diagnostics.Process.Start(fileName);
        }
    }
    catch (Exception ex) { throw ex; }
    finally
    {
        if (newUser != null)
            newUser.Undo();
    }
}

答案更新(#01):

请尝试以下代码:

public class clsImpersonate
{
    #region 'Impersonation'

    // obtains user token
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
        int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    // closes open handes returned by LogonUser
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    public extern static bool CloseHandle(IntPtr handle);

    public IntPtr ImpersonateUser(string sUsername, string sDomain, string sPassword)
    {
        // initialize token
        IntPtr pExistingTokenHandle = new IntPtr(0);

        // if domain name was blank, assume local machine
        if (sDomain == "")
            sDomain = System.Environment.MachineName;

        try
        {
            string sResult = null;

            const int LOGON32_PROVIDER_DEFAULT = 0;

            // create token
            const int LOGON32_LOGON_INTERACTIVE = 2;

            // get handle to token
            bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
                LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

            // did impersonation fail?
            if (false == bImpersonated)
            {
                int nErrorCode = Marshal.GetLastWin32Error();
                sResult = "LogonUser() failed with error code: " + nErrorCode + "\r\n";

                // show the reason why LogonUser failed
                //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // Get identity before impersonation
            sResult += "Before impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";

            return pExistingTokenHandle;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public bool FreeImpersonationResource(IntPtr _token)
    {
        // close handle(s)
        if (_token != IntPtr.Zero)
            return CloseHandle(_token);
        else return true;
    }

    #endregion
}

然后,按钮点击事件:

private void btnOpen_Click(object sender, EventArgs e)
    {
        try
        {
            IntPtr token = cls.ImpersonateUser("username", "domain", "password");

            using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(token))
            {
                string fileName = @"\\network_computer\Test\Test.doc";
                System.Diagnostics.Process.Start(fileName);
            }

            cls.FreeImpersonationResource(token);
        }
        catch (Exception ex) { throw ex; }
    }

注意:
- 如果在LogonUser函数中使用LOGON32_LOGON_INTERACTIVE,则无需复制令牌,因为您获得的句柄是可以立即使用的主令牌。 (看看this MSDN page) - 如果您为模拟上下文使用using语句,则不需要Undo,因为它会在using的末尾“自动撤消”。 - 如果仍然无效,请尝试使用服务器的IP地址而不是其域名 - 如果它仍然不起作用,我可以建议的最后一件事是获取原始代码并在按钮单击事件中移动整个方法ImpersonateUser,然后立即执行原始指令System.Diagnostics.Process.Start(fileName);指令System.Diagnostics.Process.Start(fileName);

我希望这个答案中至少有一部分会有所帮助:)

更新(#02)

我自己尝试了这个并且它正在运行,使用我之前编辑中的代码进行了以下修改:

    在课程clsImpersonate
  • ,您必须将LogonUser函数的类型更改为LOGON32_LOGON_NEW_CREDENTIALS

    // create token
    const int LOGON32_LOGON_INTERACTIVE = 2;
    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
    
    // get handle to token
    bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
        LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);
    
  • 在按钮单击事件中,您必须更改使用Process.Start()的方式。 另请在{。3}}上查看Process.Start功能

    上的一些示例
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            IntPtr token = cls.ImpersonateUser("username", "domain", "password");
    
            using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(token))
            {
                string fileName = @"Winword.exe"; // the name of the sw you will use to open your file, I suppose MS Word
                string argument = @"\\network_computer\Test\Test.doc"; // the path pf the file you want to open
    
                Process process = new Process();
                ProcessStartInfo info = new ProcessStartInfo();
                info.FileName = fileName;
                info.Arguments = argument;
    
                process.StartInfo = info;
                process.Start();
            }
    
            cls.FreeImpersonationResource(token);
        }
        catch (Exception ex) { throw ex; }
    }