以不同用户身份从.NET服务启动.NET应用程序时出现权限问题?

25

我正在尝试从.NET服务中以不同的用户启动.NET应用程序。这个想法是在Windows中创建一个沙盒托管应用程序。在服务中,我通过编程方式在Windows中创建了用户,为该用户创建了一个文件夹,并从服务器下载主机.exe到该文件夹中。然后我使用System.Diagnostics.Process运行主机.exe。以下是该进程的StartInfo:

_process = new Process
{
    StartInfo =
    {
        Arguments = " -debug",
        FileName = instanceDirectory + "host.exe",
        WorkingDirectory = instanceDirectory,
        UseShellExecute = false,
        RedirectStandardError = true,
        RedirectStandardOutput = true,
        RedirectStandardInput = true,
        UserName = Helpers.GetUserNameForInstance(_hostid),
        Password = _hostpass,
        Domain = ""
    },
    EnableRaisingEvents = true
};

当我将服务作为SERVICE运行时,进程会立即崩溃,并以错误代码-1073741502结束。但是,当我将服务作为在Windows服务中指定的相同用户交互式地在控制台中运行时,一切都可以正常工作。只有在作为SERVICE运行服务时才会出现这种情况,而不是直接在控制台中运行。

任何帮助都将非常感激。这已经让我头疼很长时间了,这是最后的选择:(


你测试过在控制台应用程序中运行同样的代码吗? - Jader Dias
2
是的,在独立模式下一切都正常运行。但作为服务运行时会出现问题。 - Andrew Ortman
1
你好,正如你所说,这听起来像是一个权限问题,因为它在不是服务时运行。这个链接可能会有所帮助: http://asprosys.blogspot.com/2009/03/perils-and-pitfalls-of-launching.html - keyboardP
你是如何定义和注册你的服务的?请记住,它们可以自动运行,而无需创建任何用户实例。 - ChrisBD
@AndrewOrtman,很遗憾这里没有答案,因为我遇到了完全相同的问题。 - John-Philip
4个回答

14

看起来使用带有用户名和密码以及服务模式的new Process()似乎“不合适” :)

引用MSDN的话:

在调用Start方法之前,可以更改StartInfo属性中指定的参数。启动进程后,更改StartInfo值不会影响或重新启动关联进程。如果使用设置了ProcessStartInfo..::.UserName和ProcessStartInfo..::.Password属性的Start(ProcessStartInfo)方法,则会调用未托管的CreateProcessWithLogonW函数,即使CreateNoWindow属性值为true或WindowStyle属性值为Hidden,它也会在新窗口中启动进程。

此外,查看CreateProcessWithLogonW文档:

lpStartupInfo [in]

STARTUPINFO结构的指针。应用程序必须添加对指定用户帐户到指定的窗口站和桌面的权限,即使是WinSta0\Default。

如果lpDesktop成员为NULL或空字符串,则新进程继承其父进程的桌面和窗口站。应用程序必须向继承的窗口站和桌面添加对指定用户帐户的权限。

.NET StartupInfo中没有lpDesktop,在另一方面,SERVICE用户没有桌面,这可能会导致您的问题。

长话短说,尝试LoadUserProfile设置为true以从注册表中加载用户信息,或者可能需要设置工作目录等。

为了进一步调查,您应该检查您的环境,也可以使用FileMon记录访问的文件。


5
我会尝试在新创建的用户的模拟环境下创建进程,如下所示。
[DllImport("advapi32.DLL", SetLastError = true)]
public static extern int LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);

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

[DllImport("advapi32.DLL")]
public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);

static void Main()
{             
    IntPtr admin_token = new IntPtr();
    WindowsIdentity wid_admin = null;
    WindowsImpersonationContext wic = null;

    LogonUser("username", "domain", "password", 9, 3, out admin_token);
    wid_admin = new WindowsIdentity(admin_token);
    wic = wid_admin.Impersonate();

    _process = new Process
    {
        StartInfo =
        {
            Arguments = " -debug",
            FileName = instanceDirectory + "host.exe",
            WorkingDirectory = instanceDirectory,
            UseShellExecute = false,
            RedirectStandardError = true,
            RedirectStandardOutput = true,
            RedirectStandardInput = true,
            UserName = Helpers.GetUserNameForInstance(_hostid),
            Password = _hostpass,
            Domain = ""
        },
        EnableRaisingEvents = true
    };

    if (wic != null) wic.Undo();
    CloseHandle(admin_token);
}

我尝试过了,似乎没有帮助。回顾Gyuri引用的内容,似乎需要给用户授权使用服务所属的窗口站和桌面。 - jamessan

3

2

0xc0000142 (-1073741502) 是 STATUS_DLL_INIT_FAILED:

动态链接库[name]的初始化失败。进程异常终止。

正如网站TenaciousImpy所指出的,您需要为帐户授予窗口站和桌面权限。但如果程序是交互式的,则还需要设置进程令牌的会话ID。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接