【问题标题】:CreateProcessAsUser user contextCreateProcessAsUser 用户上下文
【发布时间】:2014-02-17 12:32:50
【问题描述】:

我已经搜索了很长时间,但还没有找到可行的解决方案:-(

我创建了一个窗口服务,它在每个使用 CreateProcessAsUser (http://www.pinvoke.net/default.aspx/advapi32/createprocessasuser.html)、WTSEnumerateSessions 等登录到计算机的用户上启动客户端...

这已经很好了。客户端在用户会话中启动,显示其任务栏图标,并且与服务的通信正常。

我遇到的问题是我需要让该客户端将临时文件存储在用户的配置文件中。我尝试从一个小日志文件开始,以便跟踪用户最终可能遇到的任何错误。不幸的是,我无法保存到用户的临时文件夹,因为客户端似乎在 LocalSystem 的上下文中运行,尽管 WindowsIdentity 显示正确的用户: System.IO.Path.GetTempPath() 总是返回 'C:\Windows\Temp' 但我的用户的没有管理权限,所以他们不能在那里写...此外,我计划将设置存储在当前用户的注册表中,这也不起作用。我认为这在某种程度上与错误的临时路径有关。

我也尝试过 CreateEnvironmentBlock (http://www.pinvoke.net/default.aspx/userenv/CreateEnvironmentBlock.html),但我无法让它工作,并且在某处我发现一篇文章说这在 Vista 或更高版本上不再工作,所以我停止研究那个。

为了测试,我创建了一个小测试表单,只是这样做:

        MessageBox.Show("Temp: " + System.IO.Path.GetTempPath() + Environment.NewLine + "User: " + WindowsIdentity.GetCurrent().Name, "Before impersonation");

        WindowsIdentity currentUserId = WindowsIdentity.GetCurrent();
        WindowsImpersonationContext impersonatedUser = currentUserId.Impersonate();

        MessageBox.Show("Temp: " + System.IO.Path.GetTempPath() + Environment.NewLine + "User: " + WindowsIdentity.GetCurrent().Name, "After impersonation");

这个在模拟之前和之后总是显示相同的结果:“Temp: C:\Windows\Temp User:testdomain\testuser” :-(

如果这对我的启动进程有帮助(用户令牌由 WTSEnumerateSessions 提供)- 当然这只适用于 LocalSystem 的上下文:

    public static Process StartProcessAsUser(IntPtr UserToken, string App, string AppPath, string AppParameters)
    {
        Process ResultProcess = null;

        IntPtr hDupedToken = IntPtr.Zero;
        NativeProcessAPI.PROCESS_INFORMATION oProcessInformation = new NativeProcessAPI.PROCESS_INFORMATION();

        try
        {
            NativeProcessAPI.SECURITY_ATTRIBUTES oSecurityAttributes = new NativeProcessAPI.SECURITY_ATTRIBUTES();
            oSecurityAttributes.Length = Marshal.SizeOf(oSecurityAttributes);

            bool result = NativeProcessAPI.DuplicateTokenEx(
                  UserToken,
                  NativeProcessAPI.GENERIC_ALL_ACCESS,
                  ref oSecurityAttributes,
                  (int)NativeProcessAPI.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                  (int)NativeProcessAPI.TOKEN_TYPE.TokenPrimary,
                  ref hDupedToken
               );

            if (!result)
            {
                return null;
            }

            NativeProcessAPI.STARTUPINFO oStartupInfo = new NativeProcessAPI.STARTUPINFO();
            oStartupInfo.cb = Marshal.SizeOf(oStartupInfo);
            oStartupInfo.lpDesktop = String.Empty;

            result = NativeProcessAPI.CreateProcessAsUser(
                                 hDupedToken,
                                 null,
                                 App + " " + AppParameters,
                                 ref oSecurityAttributes, ref oSecurityAttributes,
                                 false, 0, IntPtr.Zero,
                                 AppPath, ref oStartupInfo, ref oProcessInformation
                           );

            if (result)
            {
                try
                {
                    int ProcessID = oProcessInformation.dwProcessID;

                    try
                    {
                        ResultProcess = System.Diagnostics.Process.GetProcessById(ProcessID);
                    }
                    catch
                    {
                        ResultProcess = null;
                    }
                }
                catch (Exception ex)
                {
                    ResultProcess = null;
                }
            }
        }
        catch
        {
            ResultProcess = null;
        }
        finally
        {
            if (oProcessInformation.hProcess != IntPtr.Zero)
                NativeProcessAPI.CloseHandle(oProcessInformation.hProcess);
            if (oProcessInformation.hThread != IntPtr.Zero)
                NativeProcessAPI.CloseHandle(oProcessInformation.hThread);
            if (hDupedToken != IntPtr.Zero)
                NativeProcessAPI.CloseHandle(hDupedToken);
        }

        return ResultProcess;
    }

有什么想法可以在用户的​​上下文中而不是在 LocalSystem 的上下文中启动我的进程吗?

非常感谢!

【问题讨论】:

  • 您检查过 %USERPFORILE% 环境变量吗? Environment.GetEnvironmentVariable("USERPROFILE", EnvironmentVariableTarget.User)
  • 引用自 MSDN:“CreateProcessAsUser 不会将指定用户的配置文件加载到 HKEY_USERS 注册表项中。因此,要访问 HKEY_CURRENT_USER 注册表项中的信息,您必须将用户的配置文件信息加载到 HKEY_USERS 中调用 CreateProcessAsUser 之前的 LoadUserProfile 函数。一定要在新进程退出后调用 UnloadUserProfile。"
  • 感谢您的回答...我试过 Environment.GetEnvironmentVariable("USERPROFILE", EnvironmentVariableTarget.User) 但它返回一个空字符串
  • 感谢有关 loadProfile 的提示 - 我会检查的。我的第一次测试没有成功,因为在当前用户的注册表中写入失败......我要进一步检查为什么会发生这种情况......也许这可以解决问题......
  • 好的,我已经检查了 LoadUserProfile,但不幸的是它没有解决我的问题 :-( LoadUserProfiles 成功运行且没有错误并返回 true,但它不会改变整体行为...我无法从当前用户的注册表,我也无法写入它......好吧,至少我可以在从 WindowsIdentity.GetCurrent().User 获取 SID 后使用 HKEY_Users 解决这个问题

标签: c# windows windows-services createprocessasuser


【解决方案1】:

将此留给其他想知道如何执行此操作的人:您需要使用 CreateEnvironmentBlock。

DuplicateTokenEx(userToken, MAXIMUM_ALLOWED | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, IntPtr.Zero, SecurityIdentification, TokenPrimary, out dupUserToken);
CreateEnvironmentBlock(out envBlock, dupUserToken, false);
CreateProcessAsUserW(dupUserToken, null, cmdLine, IntPtr.Zero, IntPtr.Zero, false,
            (uint)(CreateProcessFlags.CREATE_NEW_CONSOLE | CreateProcessFlags.CREATE_UNICODE_ENVIRONMENT),
            envBlock, processDir, ref startupInfo, out procInfo);

【讨论】:

    【解决方案2】:

    好的,我找到了解决方法:我通过使用 WindowsIdentity 提供的 SID 切换到使用 USERS 配置单元而不是 CURRENT_USER 配置单元:

    Microsoft.Win32.Registry.Users.OpenSubKey(System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString() + ..., true)
    

    虽然从用户的“环境”和“易失环境”注册表路径中获取环境变量而不是仅使用 .Net 的内置函数,但感觉有点不舒服,但效果很好……

    但非常感谢您的帮助 ;-)

    编辑: 我不会将此标记为答案,因为它是 a)我自己的解决方案和 b)只是一种解决方法

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 2010-10-14
      • 1970-01-01
      • 2011-05-27
      相关资源
      最近更新 更多