예제 #1
0
        private static int StartProcessAsCurrentUser(string fileName, string arguments, string workingDirectory)
        {
            var procInfo       = new PROCESS_INFORMATION();
            var userToken      = IntPtr.Zero;
            var primaryToken   = IntPtr.Zero;
            var ptrEnvironment = IntPtr.Zero;

            try
            {
                var activeUserSessionId = ProcessNativeMethods.WTSGetActiveConsoleSessionId();
                if (activeUserSessionId == 0xFFFFFFFF)
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: WTSGetActiveConsoleSessionId failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                var buffer        = IntPtr.Zero;
                var bytesReturned = (UInt32)0;
                if (!ProcessNativeMethods.WTSQuerySessionInformation(IntPtr.Zero, (int)activeUserSessionId, WTS_INFO_CLASS.WTSUserName, out buffer, out bytesReturned))
                {
                    var error = Marshal.GetLastWin32Error();
                    //On earlier operating systems from Vista, when no one is logged in, you get RPC_S_INVALID_BINDING which is ok, we just won't impersonate
                    if (error != ProcessNativeConstants.RPC_S_INVALID_BINDING)
                    {
                        var message = string.Format("StartProcessAsCurrentUser: WTSQuerySessionInformation failed, Error: {0}", error);
                        throw new Win32Exception(error, message);
                    }

                    //No one logged in so let's just do this the simple way
                    return(StartProcess(fileName, arguments, workingDirectory));
                }

                var activeUserName = Marshal.PtrToStringAnsi(buffer);
                ProcessNativeMethods.WTSFreeMemory(buffer);

                //We are supposedly running as a service so we're going to be running in session 0 so get a user token from the active user session
                if (!ProcessNativeMethods.WTSQueryUserToken(activeUserSessionId, out userToken))
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: WTSQueryUserToken failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                // Convert the impersonation token to a primary token
                if (!ProcessNativeMethods.DuplicateTokenEx(userToken, TokenAccess.TOKEN_ASSIGN_PRIMARY | TokenAccess.TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken))
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: DuplicateTokenEx failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                //Create an appropriate environment block for this user token (if we have one)
                if (!ProcessNativeMethods.CreateEnvironmentBlock(out ptrEnvironment, primaryToken, false))
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: CreateEnvironmentBlock failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                var profileInfo = new PROFILEINFO();
                profileInfo.dwSize     = Marshal.SizeOf(profileInfo);
                profileInfo.lpUserName = activeUserName;

                //Remember, sometimes nobody is logged in (especially when we're set to Automatically startup)
                if (!ProcessNativeMethods.LoadUserProfile(primaryToken, ref profileInfo))
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: LoadUserProfile failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                var startInfo = new STARTUPINFO();
                startInfo.cb = Marshal.SizeOf(startInfo);
                //DO NOT set this to "winsta0\\default" (even though many online resources say to do so)
                //startInfo.lpDesktop = string.Empty;

                var commandLine = "\"" + fileName + "\"";
                commandLine = !string.IsNullOrEmpty(arguments) ? (commandLine + " " + arguments) : commandLine;
                if (!ProcessNativeMethods.CreateProcessAsUser(primaryToken, null, commandLine, IntPtr.Zero, IntPtr.Zero, false, CreationFlags.CREATE_NO_WINDOW | CreationFlags.NORMAL_PRIORITY_CLASS | CreationFlags.CREATE_UNICODE_ENVIRONMENT, ptrEnvironment, workingDirectory, ref startInfo, ref procInfo))
                {
                    var error   = Marshal.GetLastWin32Error();
                    var message = string.Format("StartProcessAsCurrentUser: CreateProcessAsUser failed, Error: {0}", error);
                    throw new Win32Exception(error, message);
                }

                return(procInfo.dwProcessID);
            }
            finally
            {
                if (userToken != IntPtr.Zero)
                {
                    ProcessNativeMethods.CloseHandle(userToken);
                }

                if (primaryToken != IntPtr.Zero)
                {
                    ProcessNativeMethods.CloseHandle(primaryToken);
                }

                if (ptrEnvironment != IntPtr.Zero)
                {
                    ProcessNativeMethods.DestroyEnvironmentBlock(ptrEnvironment);
                }

                if (procInfo.hProcess != IntPtr.Zero)
                {
                    ProcessNativeMethods.CloseHandle(procInfo.hProcess);
                }

                if (procInfo.hThread != IntPtr.Zero)
                {
                    ProcessNativeMethods.CloseHandle(procInfo.hThread);
                }
            }
        }