简体   繁体   English

CreateProcessAsUser用户上下文

[英]CreateProcessAsUser user context

I've already been searching long time but couldn't find a working solution yet :-( 我已经搜索了很长时间,但是找不到有效的解决方案:-(

I have created a window service that launches a client on every user logged on to a machine using CreateProcessAsUser ( http://www.pinvoke.net/default.aspx/advapi32/createprocessasuser.html ), WTSEnumerateSessions and so on... 我创建了一个窗口服务,该窗口服务使用CreateProcessAsUser( http://www.pinvoke.net/default.aspx/advapi32/createprocessasuser.html ),WTSEnumerateSessions等登录到计算机上的每个用户启动一个客户端...

This works fine already. 这已经可以了。 The client starts in the user's session, shows its taskbar icon, and communication with the service is working fine. 客户端从用户会话开始,显示其任务栏图标,并且与服务的通信正常。

The problem I have is that I need to have that client store temporary files in the user's profile. 我遇到的问题是,我需要让该客户端将临时文件存储在用户的配置文件中。 I tried starting with a small log file so that I can keep track of any errors that my user's could eventually experience. 我尝试从一个小的日志文件开始,以便可以跟踪用户最终可能遇到的任何错误。 Unfortunately I can not save to the user's temp folder because the client somehow seems to be running in LocalSystem's context although WindowsIdentity shows the correct user: System.IO.Path.GetTempPath() always returns 'C:\\Windows\\Temp' but my user's don't have administrative rights so they are not able to write there... furthermore, I planned to store settings in the current user's registry which is not working, too. 不幸的是,我无法保存到用户的temp文件夹,因为尽管WindowsIdentity显示了正确的用户,但客户端似乎以某种方式正在LocalSystem的上下文中运行:System.IO.Path.GetTempPath()始终返回'C:\\ Windows \\ Temp',但我的用户的没有管理权限,因此他们不能在此处写...此外,我计划将设置存储在当前用户的注册表中,该注册表也无法使用。 I think this is related to the wrong temp path in some way. 我认为这在某种程度上与错误的临时路径有关。

I also tried CreateEnvironmentBlock ( http://www.pinvoke.net/default.aspx/userenv/CreateEnvironmentBlock.html ) but I could not make it work and somewhere I found an article saying that this won't work any more on Vista or higher so I stopped researching on that one. 我还尝试了CreateEnvironmentBlock( http://www.pinvoke.net/default.aspx/userenv/CreateEnvironmentBlock.html ),但是我无法使其正常工作,在某处我发现有一篇文章说这在Vista或Windows Vista上将不再起作用更高,所以我停止研究那个。

For testing I have created a small test form just doing this: 为了进行测试,我只是创建了一个小的测试表单:

        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");

This one always shows the same results before and after impersonation: "Temp: C:\\Windows\\Temp User:testdomain\\testuser" :-( 在模拟之前和之后,此结果始终显示相同的结果:“ Temp:C:\\ Windows \\ Temp User:testdomain \\ testuser” :-(

If it helps here's my function to start a process (user token is delivered by WTSEnumerateSessions) - of course this only works under LocalSystem's context: 如果这有助于启动进程(我的功能由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;
    }

Any ideas how I could start my processes in the user's contexts and not in the context of LocalSystem? 有什么想法可以在用户上下文而不是LocalSystem上下文中启动我的流程吗?

Thanks a lot! 非常感谢!

Ok I have found a workaround: I switched to using the USERS hive instead of the CURRENT_USER hive by using the SID provided by WindowsIdentity: 好的,我找到了一种解决方法:通过使用WindowsIdentity提供的SID,我切换为使用USERS配置单元而不是CURRENT_USER配置单元:

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

This works perfectly although it feels a bit uncomfortable to get environment variables from the user's "environment" and "volatile environment" registry paths instead of just using .Net's built-in functions... 尽管感觉从用户的“环境”和“易失环境”注册表路径中获取环境变量而不是仅仅使用.Net的内置函数感到有些不舒服,但这仍然可以很好地工作。

But thanks a lot for your help ;-) 但是非常感谢您的帮助;-)

EDIT: I will not mark this as an answer because it is a) my own solution and b) just a workaround 编辑:我不会将其标记为答案,因为它是a)我自己的解决方案和b)只是一种解决方法

Leaving this here for anyone else wondering how to do this: CreateEnvironmentBlock is what you need to use. 让其他想知道如何执行此操作的人留在这里: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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM