Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CreateProcessAsUser:服务获取;5:访问被拒绝”;正在尝试访问网络共享_C#_Networking_Windows Services_Impersonation - Fatal编程技术网

C# CreateProcessAsUser:服务获取;5:访问被拒绝”;正在尝试访问网络共享

C# CreateProcessAsUser:服务获取;5:访问被拒绝”;正在尝试访问网络共享,c#,networking,windows-services,impersonation,C#,Networking,Windows Services,Impersonation,我使用Windows服务中的CreateProcessAsUser为当前活动用户启动应用程序。到目前为止,它与本地驱动器上的应用程序配合得非常好 但是,如果可执行文件存在于网络共享上,则当我使用完整的服务器名(\myserver\path\app.exe)时,服务将生成5:ERROR\u ACCESS\u DENIED。如果改用映射驱动器(P:\path\app.exe),我还可以生成2:ERROR\u FILE\u NOT\u FOUND 我可以从资源管理器启动应用程序。听起来好像我无法获得正

我使用Windows服务中的CreateProcessAsUser为当前活动用户启动应用程序。到目前为止,它与本地驱动器上的应用程序配合得非常好

但是,如果可执行文件存在于网络共享上,则当我使用完整的服务器名(\myserver\path\app.exe)时,服务将生成5:ERROR\u ACCESS\u DENIED。如果改用映射驱动器(P:\path\app.exe),我还可以生成2:ERROR\u FILE\u NOT\u FOUND

我可以从资源管理器启动应用程序。听起来好像我无法获得正确的令牌副本,因为服务无法在服务器上正确模拟我

我在不同的帖子中尝试了CreateProcessAsUser的几种不同实现,但都没有成功。这对我来说是全新的(迷幻的)东西,坦率地说,我迫不及待地想回到.NET:)我想这里有一句冒犯的话:

DuplicateTokenEx(
    hUserToken,
    (Int32)MAXIMUM_ALLOWED,
    ref sa,
    (Int32)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
    (Int32)TOKEN_TYPE.TokenPrimary,
    ref hUserTokenDup);

CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true);

Int32 dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;

PROCESS_INFORMATION pi;
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";

CreateProcessAsUser(hUserTokenDup,    // client's access token
    null,                             // file to execute
    commandLine,                      // command line
    ref sa,                           // pointer to process SECURITY_ATTRIBUTES
    ref sa,                           // pointer to thread SECURITY_ATTRIBUTES
    false,                            // handles are not inheritable
    dwCreationFlags,                  // creation flags
    pEnv,                             // pointer to new environment block 
    workingDirectory,                 // name of current directory 
    ref si,                           // pointer to STARTUPINFO structure
    out pi);                          // receives information about new process
以下是完整的示例代码,我想它可能很有用:

using System;
using System.Text;
using System.Security;
using System.Management;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Win32
{
    public class Win32API
    {
        [StructLayout(LayoutKind.Sequential)]
        struct SECURITY_ATTRIBUTES
        {
            public Int32 Length;
            public IntPtr lpSecurityDescriptor;
            public Boolean bInheritHandle;
        }

        enum TOKEN_TYPE
        {
            TokenPrimary = 1,
            TokenImpersonation = 2
        }

        [StructLayout(LayoutKind.Sequential)]
        struct STARTUPINFO
        {
            public Int32 cb;
            public String lpReserved;
            public String lpDesktop;
            public String lpTitle;
            public UInt32 dwX;
            public UInt32 dwY;
            public UInt32 dwXSize;
            public UInt32 dwYSize;
            public UInt32 dwXCountChars;
            public UInt32 dwYCountChars;
            public UInt32 dwFillAttribute;
            public UInt32 dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public UInt32 dwProcessId;
            public UInt32 dwThreadId;
        }

        enum SECURITY_IMPERSONATION_LEVEL
        {
            SecurityAnonymous = 0,
            SecurityIdentification = 1,
            SecurityImpersonation = 2,
            SecurityDelegation = 3,
        }

        const UInt32 MAXIMUM_ALLOWED = 0x2000000;
        const Int32 CREATE_UNICODE_ENVIRONMENT = 0x00000400;
        const Int32 NORMAL_PRIORITY_CLASS = 0x20;
        const Int32 CREATE_NEW_CONSOLE = 0x00000010;

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern Boolean CloseHandle(IntPtr hSnapshot);

        [DllImport("kernel32.dll")]
        public static extern UInt32 WTSGetActiveConsoleSessionId();

        [DllImport("Wtsapi32.dll")]
        static extern UInt32 WTSQueryUserToken(UInt32 SessionId, ref IntPtr phToken);

        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        extern static Boolean CreateProcessAsUser(
            IntPtr hToken,
            String lpApplicationName,
            String lpCommandLine,
            ref SECURITY_ATTRIBUTES lpProcessAttributes,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            Boolean bInheritHandle,
            Int32 dwCreationFlags,
            IntPtr lpEnvironment,
            String lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            out PROCESS_INFORMATION lpProcessInformation);

        [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
        extern static Boolean DuplicateTokenEx(
            IntPtr ExistingTokenHandle,
            UInt32 dwDesiredAccess,
            ref SECURITY_ATTRIBUTES lpThreadAttributes,
            Int32 TokenType,
            Int32 ImpersonationLevel,
            ref IntPtr DuplicateTokenHandle);

        [DllImport("userenv.dll", SetLastError = true)]
        static extern Boolean CreateEnvironmentBlock(
            ref IntPtr lpEnvironment,
            IntPtr hToken,
            Boolean bInherit);

        [DllImport("userenv.dll", SetLastError = true)]
        static extern Boolean DestroyEnvironmentBlock(IntPtr lpEnvironment);

        /// <summary>
        /// Creates the process in the interactive desktop with credentials of the logged in user.
        /// </summary>
        public static Boolean CreateProcessAsUser(String commandLine, String workingDirectory, out StringBuilder output)
        {
            Boolean processStarted = false;
            output = new StringBuilder();

            try
            {
                UInt32 dwSessionId = WTSGetActiveConsoleSessionId();
                output.AppendLine(String.Format("Active console session Id: {0}", dwSessionId));

                IntPtr hUserToken = IntPtr.Zero;
                WTSQueryUserToken(dwSessionId, ref hUserToken);

                SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
                sa.Length = Marshal.SizeOf(sa);

                IntPtr hUserTokenDup = IntPtr.Zero;
                DuplicateTokenEx(
                    hUserToken,
                    (Int32)MAXIMUM_ALLOWED,
                    ref sa,
                    (Int32)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                    (Int32)TOKEN_TYPE.TokenPrimary,
                    ref hUserTokenDup);


                if (hUserTokenDup != IntPtr.Zero)
                {
                    output.AppendLine(String.Format("DuplicateTokenEx() OK (hToken: {0})", hUserTokenDup));

                    Int32 dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

                    IntPtr pEnv = IntPtr.Zero;
                    if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
                    {
                        dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
                        output.AppendLine(String.Format("CreateEnvironmentBlock() success."));
                    }
                    else
                    {
                        output.AppendLine(String.Format("CreateEnvironmentBlock() FAILED (Last Error: {0})", Marshal.GetLastWin32Error()));
                        pEnv = IntPtr.Zero;
                    }

                    // Launch the process in the client's logon session.
                    PROCESS_INFORMATION pi;

                    STARTUPINFO si = new STARTUPINFO();
                    si.cb = Marshal.SizeOf(si);
                    si.lpDesktop = "winsta0\\default";

                    output.AppendLine(String.Format("CreateProcess (Path:{0}, CurrDir:{1})", commandLine, workingDirectory));

                    if (CreateProcessAsUser(hUserTokenDup,    // client's access token
                            null,                // file to execute
                            commandLine,        // command line
                            ref sa,                // pointer to process SECURITY_ATTRIBUTES
                            ref sa,                // pointer to thread SECURITY_ATTRIBUTES
                            false,                // handles are not inheritable
                            dwCreationFlags,    // creation flags
                            pEnv,                // pointer to new environment block 
                            workingDirectory,    // name of current directory 
                            ref si,                // pointer to STARTUPINFO structure
                            out pi                // receives information about new process
                        ))
                    {
                        processStarted = true;
                        output.AppendLine(String.Format("CreateProcessAsUser() OK (PID: {0})", pi.dwProcessId));
                    }
                    else
                    {
                        output.AppendLine(String.Format("CreateProcessAsUser() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
                    }

                    if (DestroyEnvironmentBlock(pEnv))
                    {
                        output.AppendLine("DestroyEnvironmentBlock: Success");
                    }
                    else
                    {
                        output.AppendLine(String.Format("DestroyEnvironmentBlock() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
                    }
                }
                else
                {
                    output.AppendLine(String.Format("DuplicateTokenEx() failed (Last Error: {0})", Marshal.GetLastWin32Error()));
                }
                CloseHandle(hUserTokenDup);
                CloseHandle(hUserToken);
            }
            catch (Exception ex)
            {
                output.AppendLine("Exception occurred: " + ex.Message);
            }
            return processStarted;
        }
    }
}

我的问题:需要调整什么才能使用重复令牌正确访问网络共享?

当您对允许来宾访问的共享(即没有用户名/密码)使用此命令时,该命令正常工作,但当您对需要身份验证才能使用的共享使用此命令时,该命令不起作用

UI调用会涉及重定向器,它会自动建立到执行所需的远程服务器的连接

请注意,一种解决方法是使用基于
cmd
的中继来访问可执行文件,因此对于命令行,您可以将其设置为:

CreateProcessAsUser(@"cmd /c ""start \\server\share\binary.exe""", @"C:\Windows", out result);
然后使用以下方法将startupinfo更改为
SW_HIDE
cmd窗口:

si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
si.dwFlags = 0x1; // STARTF_USESHOWWINDOW
si.wShowWindow = 0; // SW_HIDE
cmd
调用是在启动命令之前完全进入用户环境的一部分-这将利用访问服务器的所有凭据


请注意,您可能需要有一点逻辑来防止直接调用应用程序的
SW_HIDE
(例如,在命令行字符串的开头检查cmd?)

检查DuplicateTokenEx和CreateProcessAsUser的返回值,如果无法了解失败原因,则获取最后一个错误。@500 InternalServerError-DuplicateTokenEx工作正常,但CreateProcessAsUser给我5:错误\u访问\u拒绝。你对我可以改变哪些选项来更接近真实用户有什么建议吗?让它发挥作用似乎并不简单。可能会提供一些线索。@500内部服务器错误谢谢!它确实提供了线索,现在我创建/销毁了一个环境块。但不幸的是,我仍然无法使它在网络共享上工作(但它在本地工作)。我想我已经找出了原因,所以我用新的解释和代码示例完全更新了我的问题。谢谢Petesh,“cmd”解决方案成功了!但是在CreateProcessAsUser()期间,带引号的语法在我的端部不起作用。当我将lpApplicationName和lpCurrentDirectory设置为null,并将lpCommandName格式设置为“cmd/c\\\\myserver\\path\\myapp.exe”,去掉“start”和引号后,它就工作了。是的,引号很难正确引用。启动
的原因是在远程应用程序启动后终止shell。我会尝试添加它,谢谢你的帮助。在假期之前,我就一直被这个问题困扰着:Pindeded,start也可以。最后一条命令行:“cmd/c start\\\\myserver\\mypath\\myapp.exe”。
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
si.dwFlags = 0x1; // STARTF_USESHOWWINDOW
si.wShowWindow = 0; // SW_HIDE