private static SecurityIdentifier GetTokenUserSID(SafeNativeHandle hToken)
 {
     using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken, NativeHelpers.TokenInformationClass.TokenUser))
     {
         NativeHelpers.TOKEN_USER tokenUser = (NativeHelpers.TOKEN_USER)Marshal.PtrToStructure(tokenInfo.DangerousGetHandle(),
                                                                                               typeof(NativeHelpers.TOKEN_USER));
         return(new SecurityIdentifier(tokenUser.User.Sid));
     }
 }
 public static extern bool CreateProcessWithTokenW(
     SafeNativeHandle hToken,
     LogonFlags dwLogonFlags,
     [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName,
     StringBuilder lpCommandLine,
     Process.NativeHelpers.ProcessCreationFlags dwCreationFlags,
     SafeMemoryBuffer lpEnvironment,
     [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory,
     Process.NativeHelpers.STARTUPINFOEX lpStartupInfo,
     out Process.NativeHelpers.PROCESS_INFORMATION lpProcessInformation);
        /// <summary>
        /// Creates a process as another user account. This method will attempt to run as another user with the
        /// highest possible permissions available. The main privilege required is the SeDebugPrivilege, without
        /// this privilege you can only run as a local or domain user if the username and password is specified.
        /// </summary>
        /// <param name="username">The username of the runas user</param>
        /// <param name="password">The password of the runas user</param>
        /// <param name="logonFlags">LogonFlags to control how to logon a user when the password is specified</param>
        /// <param name="logonType">Controls what type of logon is used, this only applies when the password is specified</param>
        /// <param name="lpApplicationName">The name of the executable or batch file to executable</param>
        /// <param name="lpCommandLine">The command line to execute, typically this includes lpApplication as the first argument</param>
        /// <param name="lpCurrentDirectory">The full path to the current directory for the process, null will have the same cwd as the calling process</param>
        /// <param name="environment">A dictionary of key/value pairs to define the new process environment</param>
        /// <param name="stdin">Bytes sent to the stdin pipe</param>
        /// <returns>Ansible.Process.Result object that contains the command output and return code</returns>
        public static Result CreateProcessAsUser(string username, string password, LogonFlags logonFlags, LogonType logonType,
                                                 string lpApplicationName, string lpCommandLine, string lpCurrentDirectory, IDictionary environment, byte[] stdin)
        {
            // While we use STARTUPINFOEX having EXTENDED_STARTUPINFO_PRESENT causes a parameter validation error
            Process.NativeHelpers.ProcessCreationFlags creationFlags = Process.NativeHelpers.ProcessCreationFlags.CREATE_UNICODE_ENVIRONMENT;
            Process.NativeHelpers.PROCESS_INFORMATION  pi            = new Process.NativeHelpers.PROCESS_INFORMATION();
            Process.NativeHelpers.STARTUPINFOEX        si            = new Process.NativeHelpers.STARTUPINFOEX();
            si.startupInfo.dwFlags = Process.NativeHelpers.StartupInfoFlags.USESTDHANDLES;

            SafeFileHandle stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinRead, stdinWrite;

            ProcessUtil.CreateStdioPipes(si, out stdoutRead, out stdoutWrite, out stderrRead, out stderrWrite,
                                         out stdinRead, out stdinWrite);
            FileStream stdinStream = new FileStream(stdinWrite, FileAccess.Write);

            // $null from PowerShell ends up as an empty string, we need to convert back as an empty string doesn't
            // make sense for these parameters
            if (lpApplicationName == "")
            {
                lpApplicationName = null;
            }

            if (lpCurrentDirectory == "")
            {
                lpCurrentDirectory = null;
            }

            using (SafeMemoryBuffer lpEnvironment = ProcessUtil.CreateEnvironmentPointer(environment))
            {
                // A user may have 2 tokens, 1 limited and 1 elevated. GetUserToken will try and get both but we will
                // only find out if the elevated token is valid when running here.
                List <SafeNativeHandle> userTokens = GetUserTokens(username, password, logonType);

                bool          launchSuccess = false;
                StringBuilder commandLine   = new StringBuilder(lpCommandLine);
                foreach (SafeNativeHandle token in userTokens)
                {
                    if (NativeMethods.CreateProcessWithTokenW(token, logonFlags, lpApplicationName, commandLine,
                                                              creationFlags, lpEnvironment, lpCurrentDirectory, si, out pi))
                    {
                        launchSuccess = true;
                        break;
                    }
                }

                if (!launchSuccess)
                {
                    throw new Win32Exception("CreateProcessWithTokenW() failed");
                }
            }
            return(ProcessUtil.WaitProcess(stdoutRead, stdoutWrite, stderrRead, stderrWrite, stdinStream, stdin, pi.hProcess));
        }
        private static List <string> GetTokenPrivileges(SafeNativeHandle hToken)
        {
            using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken, NativeHelpers.TokenInformationClass.TokenPrivileges))
            {
                NativeHelpers.TOKEN_PRIVILEGES tokenPrivileges = (NativeHelpers.TOKEN_PRIVILEGES)Marshal.PtrToStructure(
                    tokenInfo.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_PRIVILEGES));

                NativeHelpers.LUID_AND_ATTRIBUTES[] luidAndAttributes = new NativeHelpers.LUID_AND_ATTRIBUTES[tokenPrivileges.PrivilegeCount];
                PtrToStructureArray(luidAndAttributes, IntPtr.Add(tokenInfo.DangerousGetHandle(), Marshal.SizeOf(tokenPrivileges.PrivilegeCount)));

                return(luidAndAttributes.Select(x => GetPrivilegeName(x.Luid)).ToList());
            }
        }
        private static NativeHelpers.SECURITY_LOGON_TYPE GetTokenLogonType(SafeNativeHandle hToken)
        {
            UInt64 tokenLuidId;

            using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken, NativeHelpers.TokenInformationClass.TokenStatistics))
            {
                NativeHelpers.TOKEN_STATISTICS stats = (NativeHelpers.TOKEN_STATISTICS)Marshal.PtrToStructure(
                    tokenInfo.DangerousGetHandle(), typeof(NativeHelpers.TOKEN_STATISTICS));
                tokenLuidId = (UInt64)stats.AuthenticationId;
            }

            // Default to Network, if we weren't able to get the actual type treat it as an error and assume
            // we don't want to run a process with the token
            NativeHelpers.SECURITY_LOGON_TYPE logonType = NativeHelpers.SECURITY_LOGON_TYPE.Network;
            UInt32 sessionCount;
            SafeLsaMemoryBuffer sessionPtr;
            UInt32 res = NativeMethods.LsaEnumerateLogonSessions(out sessionCount, out sessionPtr);

            if (res != 0)
            {
                throw new Win32Exception((int)NativeMethods.LsaNtStatusToWinError(res), "LsaEnumerateLogonSession() failed");
            }
            using (sessionPtr)
            {
                for (IntPtr p = sessionPtr.DangerousGetHandle();
                     p != IntPtr.Add(sessionPtr.DangerousGetHandle(), (int)(IntPtr.Size * sessionCount));
                     p = IntPtr.Add(p, Marshal.SizeOf(typeof(NativeHelpers.LUID))))
                {
                    SafeLsaMemoryBuffer sessionDataPtr;
                    res = NativeMethods.LsaGetLogonSessionData(p, out sessionDataPtr);
                    if (res != 0)
                    {
                        continue;
                    }

                    using (sessionDataPtr)
                    {
                        NativeHelpers.SECURITY_LOGON_SESSION_DATA sessionData = (NativeHelpers.SECURITY_LOGON_SESSION_DATA)Marshal.PtrToStructure(
                            sessionDataPtr.DangerousGetHandle(), typeof(NativeHelpers.SECURITY_LOGON_SESSION_DATA));
                        UInt64 sessionId = (UInt64)sessionData.LogonId;
                        if (sessionId == tokenLuidId)
                        {
                            logonType = sessionData.LogonType;
                            break;
                        }
                    }
                }
            }

            return(logonType);
        }
        private static SafeNativeHandle GetElevatedToken(SafeNativeHandle hToken)
        {
            // First determine if the current token is a limited token
            using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken, NativeHelpers.TokenInformationClass.TokenElevationType))
            {
                NativeHelpers.TokenElevationType tet = (NativeHelpers.TokenElevationType)Marshal.ReadInt32(tokenInfo.DangerousGetHandle());
                // We already have the best token we can get, just use it
                if (tet != NativeHelpers.TokenElevationType.TokenElevationTypeLimited)
                {
                    return(hToken);
                }
            }

            // We have a limited token, get the linked elevated token
            using (SafeMemoryBuffer tokenInfo = GetTokenInformation(hToken, NativeHelpers.TokenInformationClass.TokenLinkedToken))
                return(new SafeNativeHandle(Marshal.ReadIntPtr(tokenInfo.DangerousGetHandle())));
        }
        private static SafeMemoryBuffer GetTokenInformation(SafeNativeHandle hToken, NativeHelpers.TokenInformationClass tokenClass)
        {
            UInt32 tokenLength;
            bool   res = NativeMethods.GetTokenInformation(hToken, tokenClass, new SafeMemoryBuffer(IntPtr.Zero), 0, out tokenLength);

            if (!res && tokenLength == 0)  // res will be false due to insufficient buffer size, we ignore if we got the buffer length
            {
                throw new Win32Exception(String.Format("GetTokenInformation({0}) failed to get buffer length", tokenClass.ToString()));
            }

            SafeMemoryBuffer tokenInfo = new SafeMemoryBuffer((int)tokenLength);

            if (!NativeMethods.GetTokenInformation(hToken, tokenClass, tokenInfo, tokenLength, out tokenLength))
            {
                throw new Win32Exception(String.Format("GetTokenInformation({0}) failed", tokenClass.ToString()));
            }

            return(tokenInfo);
        }
 public static extern bool GetTokenInformation(
     SafeNativeHandle TokenHandle,
     NativeHelpers.TokenInformationClass TokenInformationClass,
     SafeMemoryBuffer TokenInformation,
     UInt32 TokenInformationLength,
     out UInt32 ReturnLength);