WCF服务Process.Start在网络服务帐户下模拟为不同的用户

时间:2013-07-05 11:50:03

标签: c# wcf process credentials network-service

我使用带有网络服务标识的AppPool .NET 4.0在IIS,Windows Server 2008 R2中托管了Wcf服务。

我的Wcf服务有一个使用Process.Start调用命令EXE的方法。

我需要使用其他用户作为执行命令EXE(域用户帐户)的凭据。

我尝试执行它但它对我不起作用:它似乎没有执行命令EXE。

更新:进程退出,但不执行代码

我收到的错误如下:

退出代码-1073741502

和eventvwr:

            Process Information:
            Process ID:            0xc50
            Process Name:      C:\DeployTools\DeployTools.Commands.Ejecutar.exe
            Exit Status:            0xc0000142
  

appplication无法正确启动(0xC0000142)。单击确定   关闭应用程序

有什么建议吗?

代码:

        StreamReader sr = null;
        StreamReader serr = null;

        try
        {
            var psi = new ProcessStartInfo(MY_COMMAND_EXE);
            psi.WorkingDirectory = Path.GetDirectoryName(MY_COMMAND_EXE);
            psi.Arguments = arguments;
            psi.Domain = DOMAIN;
            psi.UserName = USER_IN_DOMAIN;
            psi.Password = SecureStringHelper.ToSecureString(pwd);

            psi.LoadUserProfile = true;
            psi.UseShellExecute = false;

            psi.ErrorDialog = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            psi.CreateNoWindow = true;
            psi.WindowStyle = ProcessWindowStyle.Minimized;

            using (Process pr = Process.Start(psi))
            {
                sr = pr.StandardOutput;
                serr = pr.StandardError;

                if (!pr.HasExited)
                {
                    pr.WaitForExit(300000);
                }
                output = pr.StandardOutput.ReadToEnd();
                errors = pr.StandardError.ReadToEnd();
                exitCode = pr.ExitCode;

                return output;
            }
        }
        catch (Exception exc)
        {
            return "EXCEPCIÓN: " + exc.Message;
        }
        finally
        {
            if (sr != null)
            {
                sr.Close();
                sr.Dispose();
                sr = null;
            }

            if (serr != null)
            {
                serr.Close();
                serr.Dispose();
                serr = null;
            }
        }

1 个答案:

答案 0 :(得分:4)

我必须添加对AsproLock.dll及相关代码的引用,以便允许用户帐户访问正在运行的资源。

            //The following security adjustments are necessary to give the new 
            //process sufficient permission to run in the service's window station
            //and desktop. This uses classes from the AsproLock library also from 
            //Asprosys.
            IntPtr hWinSta = NativeMethods.GetProcessWindowStation();
            WindowStationSecurity ws = new WindowStationSecurity(hWinSta,
              System.Security.AccessControl.AccessControlSections.Access);
            ws.AddAccessRule(new WindowStationAccessRule(userPassDto.Usuario,
                WindowStationRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
            ws.AcceptChanges();

            IntPtr hDesk = NativeMethods.GetThreadDesktop(NativeMethods.GetCurrentThreadId());
            DesktopSecurity ds = new DesktopSecurity(hDesk,
                System.Security.AccessControl.AccessControlSections.Access);
            ds.AddAccessRule(new DesktopAccessRule(userPassDto.Usuario,
                DesktopRights.AllAccess, System.Security.AccessControl.AccessControlType.Allow));
            ds.AcceptChanges();

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetThreadDesktop(int dwThreadId);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern int GetCurrentThreadId();

Asprosys在新证书下启动流程的危险和陷阱

这不是常见的需求,但也不是那么罕见,所以我想我最好发布这个一步一步的指南来解决在模拟凭据下启动流程的问题。这基于使用.Net Process类的Start方法,但它也适用于底层API调用:CreateProcessWithLogonW和CreateProcessWithTokenW。

访问被拒绝 - 第一次尝试和访问被拒绝的例外。这是最常见的初始问题,是由于服务在LOCAL SYSTEM帐户下运行而引起的。奇怪的是,SYSTEM帐户是计算机上最强大的帐户,但它无法做的少数事情之一就是使用CreateProcessWithLogonW启动一个进程,这是调用Process.Start的API。因此,将您的服务帐户更改为本地服务,无论如何,它可能是更合适的帐户。

再次拒绝访问 - Aargh,我以为我们解决了这个问题。糟糕,请仔细检查您尝试启动的应用程序的权限。请记住,系统尝试访问应用程序文件作为将在其下运行进程的用户帐户,而不是服务帐户。

目录错误无效 - 什么?所有路径都是正确的。所有目录拼写正确,没有无效字符。这是一个令人难以置信的恼人错误,并不是很一致。通常当我们运行一个进程时,我们不打扰设置WorkingDirectory属性,只接受父进程的默认值。使用新凭据启动进程时,您无法执行此操作,您必须显式设置WorkingDirectory的路径,否则您将获得“目录名无效”。 Win32Exception。

失败:没有错误? - Process.Start可以很好地为新进程处理环境块的创建。所以只有在使用底层API时才会出现问题。在调用其中一个CreateProcess * API时,将lpEnvironment参数保留为NULL并让系统使用从父进程复制块的默认值是正常的。但是,在新凭据下启动时,您必须手动或使用CreateEnvironmentBlock显式创建环境块。是什么让这个更糟糕的是,如果你离开了这一点,在CreateProcess的*调用将失败,但GetLastError函数将返回ERROR_SUCCESS,如果你做出了错误创建环境块就没有错误,但过程可能只是无法运行。

应用程序无法正常初始化 - 没有更多例外,您已解决所有问题并且已启动该流程。再次哎呀,这个过程在哪里?检查事件日志(或者您可能已收到“应用程序错误”弹出窗口)。应用程序错误应该有一个条目,表明您的进程是错误的应用程序,user32.dll或kernel32.dll是错误模块,异常是:0xC0000142。这可能有一些细微的变化,但基本上它是说您的应用程序无法初始化。原因是在初始化时,在运行任何应用程序代码之前,所有进程都附加到Window Station,并且所有线程都附加到桌面,但是您在其下启动的用户无权访问Window Station和Desktop你的进程正在启动,它无法初始化。必须调整Window Station和Desktop的安全描述符,以便为正在启动该进程的用户授予AllAccess权限。这是一个直接在.Net中做的恶魔,所以你可能会发现这里的安全包装类非常有用。

没有更多错误 - 真的,没有更多错误,您的流程现在应该顺利运行。根据用户的身份(例如,管理员在某些情况下已经拥有正确的权限)或者您要启动的会话类型,您可能需要做些什么变化。但是按照这些步骤应该让您的生活变得更好顺利而轻松(也许不是你的整个生命)。

参考文献:

The Perils and Pitfalls of Launching a Process Under New Credentials

Aspro Lock - Access Control

Code Samples

Creating New Process Under Alternate Credentials (createprocessasuser)

processstart-hangs