예제 #1
0
        /// <summary>
        /// Uses P/Invoke to start the process using the login token obtained for the user.
        /// </summary>
        /// <param name="token">The login token to use to create the process with.</param>
        private void StartWithCreateProcessAsUser(IntPtr token)
        {
            var  startinfo      = _process.StartInfo;
            var  path           = Path.GetFullPath(startinfo.FileName);
            var  dir            = Path.GetDirectoryName(path);
            bool processCreated = false;

            Win32NativeMethods.PROCESS_INFORMATION pi        = new Win32NativeMethods.PROCESS_INFORMATION();
            Win32NativeMethods.SECURITY_ATTRIBUTES saProcess = new Win32NativeMethods.SECURITY_ATTRIBUTES();
            saProcess.bInheritHandle = true;
            saProcess.nLength        = (uint)Marshal.SizeOf(saProcess);

            Win32NativeMethods.SECURITY_ATTRIBUTES saThread = new Win32NativeMethods.SECURITY_ATTRIBUTES();
            saThread.bInheritHandle = true;
            saThread.nLength        = (uint)Marshal.SizeOf(saThread);

            Win32NativeMethods.STARTUPINFO si = new Win32NativeMethods.STARTUPINFO();
            si.lpDesktop = string.Empty;
            si.cb        = (uint)Marshal.SizeOf(si);

            lock (createProcessLock)
            {
                _pipeServerToClient        = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
                _pipeServerFromClient      = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
                _pipeServerErrorFromClient = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);

                try
                {
                    // although these are separate if statements, in reality all standard streams must be
                    // redirected otherwise it just won't work in SACS.
                    if (startinfo.RedirectStandardInput)
                    {
                        _standardInput           = new StreamWriter(_pipeServerToClient);
                        _standardInput.AutoFlush = true;
                    }

                    if (startinfo.RedirectStandardOutput)
                    {
                        Encoding encoding = (startinfo.StandardOutputEncoding != null) ? startinfo.StandardOutputEncoding : Console.OutputEncoding;
                        _standardOutput = new StreamReader(_pipeServerFromClient);
                    }

                    if (startinfo.RedirectStandardError)
                    {
                        Encoding encoding2 = (startinfo.StandardErrorEncoding != null) ? startinfo.StandardErrorEncoding : Console.OutputEncoding;
                        _standardError = new StreamReader(_pipeServerErrorFromClient);
                    }

                    ArgumentObject["pipeIn"]  = _pipeServerToClient.GetClientHandleAsString();
                    ArgumentObject["pipeOut"] = _pipeServerFromClient.GetClientHandleAsString();
                    ArgumentObject["pipeErr"] = _pipeServerErrorFromClient.GetClientHandleAsString();

                    processCreated = Win32NativeMethods.CreateProcessAsUser(
                        token,
                        path,
                        string.Format("\"{0}\" {1}", startinfo.FileName.Replace("\"", "\"\""), JsonConvert.SerializeObject(this.ArgumentObject)),
                        ref saProcess,
                        ref saThread,
                        true,
                        0,
                        IntPtr.Zero,
                        dir,
                        ref si,
                        out pi);

                    if (!processCreated)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    // For the last step, since we're not using the in-build methods to start the process,
                    // we need to replace the now outdated process
                    _process = Process.GetProcessById((int)pi.dwProcessId);
                }
                finally
                {
                    _pipeServerToClient.DisposeLocalCopyOfClientHandle();
                    _pipeServerFromClient.DisposeLocalCopyOfClientHandle();
                    _pipeServerErrorFromClient.DisposeLocalCopyOfClientHandle();

                    if (pi.hProcess != IntPtr.Zero)
                    {
                        Win32NativeMethods.CloseHandle(pi.hProcess);
                    }

                    if (pi.hThread != IntPtr.Zero)
                    {
                        Win32NativeMethods.CloseHandle(pi.hThread);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Impersonates the specified user account.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="domainName">Name of the domain.</param>
        /// <param name="password">The password. <see cref="String"/></param>
        /// <param name="logonType">Type of the logon.</param>
        /// <param name="logonProvider">The logon provider.</param>
        /// /// <param name="impersonationAction">A callback to perform during the impersonation initialization.</param>
        public virtual void Impersonate(string userName, string domainName, SecureString password, LogonType logonType, LogonProvider logonProvider, Action <IntPtr> impersonationAction = null)
        {
            UndoImpersonation();

            IntPtr logonToken          = IntPtr.Zero;
            IntPtr logonTokenDuplicate = IntPtr.Zero;
            IntPtr passwordPtr         = new IntPtr();

            passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);
            bool logonValue = false;

            try
            {
                // revert to the application pool identity, saving the identity of the current requestor
                this._wic = WindowsIdentity.Impersonate(IntPtr.Zero);

                // do logon & impersonate
                logonValue = Win32NativeMethods.LogonUser(
                    userName,
                    domainName,
                    passwordPtr,
                    (int)logonType,
                    (int)logonProvider,
                    ref logonToken);

                if (logonValue)
                {
                    Win32NativeMethods.SECURITY_ATTRIBUTES sa = new Win32NativeMethods.SECURITY_ATTRIBUTES();
                    sa.nLength = (uint)Marshal.SizeOf(sa);

                    if (Win32NativeMethods.DuplicateTokenEx(
                            logonToken,
                            Win32NativeMethods.TOKEN_ASSIGN_PRIMARY | Win32NativeMethods.TOKEN_DUPLICATE | Win32NativeMethods.TOKEN_QUERY,
                            ref sa,
                            (int)Win32NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
                            (int)Win32NativeMethods.TOKEN_TYPE.TokenPrimary,
                            ref logonTokenDuplicate))
                    {
                        // Looks like it is working without impersonating. To be revisited.
                        ////var wi = new WindowsIdentity(logonTokenDuplicate);
                        ////wi.Impersonate(); // discard the returned identity context (which is the context of the application)
                        ////this.IsImpersonating = true;
                        if (impersonationAction != null)
                        {
                            impersonationAction(logonTokenDuplicate);
                        }
                    }
                    else
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                }
                else
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);

                if (logonToken != IntPtr.Zero)
                {
                    Win32NativeMethods.CloseHandle(logonToken);
                }

                if (logonTokenDuplicate != IntPtr.Zero)
                {
                    Win32NativeMethods.CloseHandle(logonTokenDuplicate);
                }
            }
        }