CreateProcessAsUser error code 6

0

I am using LogonUser to get primary user token and then CreateProcessAsUser APIs to create process. But I am getting error code 6. Not sure what the problem is. Below is the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LogOnUserTestWindows
{
    using System;
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Principal;

    class Program
    {
        // Define the Windows LogonUser and CloseHandle functions.
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool LogonUser(String username, String domain, IntPtr password,
                int logonType, int logonProvider, ref IntPtr token);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        private enum SW
        {
            SW_HIDE = 0,
            SW_SHOWNORMAL = 1,
            SW_NORMAL = 1,
            SW_SHOWMINIMIZED = 2,
            SW_SHOWMAXIMIZED = 3,
            SW_MAXIMIZE = 3,
            SW_SHOWNOACTIVATE = 4,
            SW_SHOW = 5,
            SW_MINIMIZE = 6,
            SW_SHOWMINNOACTIVE = 7,
            SW_SHOWNA = 8,
            SW_RESTORE = 9,
            SW_SHOWDEFAULT = 10,
            SW_MAX = 10
        }


        [StructLayout(LayoutKind.Sequential)]
        private struct STARTUPINFO
        {
            public int cb;
            public String lpReserved;
            public String lpDesktop;
            public String lpTitle;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct PROCESS_INFORMATION
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public uint dwProcessId;
            public uint dwThreadId;
        }


        [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        private static extern bool CreateProcessAsUser(
                IntPtr hToken,
                String lpApplicationName,
                String lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandle,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);
        // Define the required LogonUser enumerations.
        const int LOGON32_PROVIDER_DEFAULT = 0;
        const int LOGON32_LOGON_INTERACTIVE = 2;

        private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
        private const int CREATE_NO_WINDOW = 0x08000000;

        private const int CREATE_NEW_CONSOLE = 0x00000010;


        static void Main()
        {
            // Display the current user before impersonation.
            Console.WriteLine("Before impersonation: {0}",
                              WindowsIdentity.GetCurrent().Name);

            // Ask the user for a network domain.
            Console.Write("Please enter your domain: ");
            string domain = Console.ReadLine();

            // Ask the user for a user name.
            Console.Write("Please enter your user name: ");
            string username = Console.ReadLine();

            // Ask the user for a password.
            Console.Write("Please enter your password: ");
            SecureString passWord = GetPassword();

            // Impersonate the account provided by the user.
            try
            {
                //WindowsImpersonationContext userContext = ImpersonateUser(passWord, username, domain);
                IntPtr token = ImpersonateUser(passWord, username, domain);

                // Display the current user after impersonation.
                Console.WriteLine("After impersonation: {0}",
                                  WindowsIdentity.GetCurrent().Name);
            }
            catch (ArgumentException e)
            {
                Console.WriteLine("{0}: {1}", e.GetType().Name, e.Message);
            }
            catch (Win32Exception e)
            {
                Console.WriteLine("{0}: {1}", e.GetType().Name, e.Message);
            }
            finally
            {
                passWord.Dispose();
            }
        }

        public static SecureString GetPassword()
        {
            SecureString password = new SecureString();

            // get the first character of the password
            ConsoleKeyInfo nextKey = Console.ReadKey(true);

            while (nextKey.Key != ConsoleKey.Enter)
            {
                if (nextKey.Key == ConsoleKey.Backspace)
                {
                    if (password.Length > 0)
                    {
                        password.RemoveAt(password.Length - 1);

                        // erase the last * as well
                        Console.Write(nextKey.KeyChar);
                        Console.Write(" ");
                        Console.Write(nextKey.KeyChar);
                    }
                }
                else
                {
                    password.AppendChar(nextKey.KeyChar);
                    Console.Write("*");
                }

                nextKey = Console.ReadKey(true);
            }

            Console.WriteLine();

            // lock the password down
            password.MakeReadOnly();
            return password;
        }

        public static IntPtr ImpersonateUser(SecureString password, string userName, string domainName)
        {
            IntPtr tokenHandle = IntPtr.Zero;
            IntPtr passwordPtr = IntPtr.Zero;
            bool returnValue = false;
            int error = 0;

            // Marshal the SecureString to unmanaged memory.
            passwordPtr = Marshal.SecureStringToGlobalAllocUnicode(password);

            // Pass LogonUser the unmanaged (and decrypted) copy of the password.
            returnValue = LogonUser(userName, domainName, passwordPtr,
                                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                                    ref tokenHandle);
            if (!returnValue && tokenHandle == IntPtr.Zero)
                error = Marshal.GetLastWin32Error();

            // Perform cleanup whether or not the call succeeded.
            // Zero-out and free the unmanaged string reference.
            Marshal.ZeroFreeGlobalAllocUnicode(passwordPtr);
            // Close the token handle.
            CloseHandle(tokenHandle);

            // Throw an exception if an error occurred.
            if (error != 0)
            {
                throw new System.ComponentModel.Win32Exception(error);
            }
            // The token that is passed to the following constructor must 
            // be a primary token in order to use it for impersonation.
            //WindowsIdentity newId = new WindowsIdentity(tokenHandle);

            //String workgroup;
            string cmdLine = null;
            string workDir = null;
            bool visible = true;
            var pEnv = IntPtr.Zero;
            var startInfo = new STARTUPINFO();
            var procInfo = new PROCESS_INFORMATION();
            int iResultOfCreateProcessAsUser;

            uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
            startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
            startInfo.lpDesktop = "winsta0\\default";




            if (!CreateProcessAsUser(
                tokenHandle,
                "C:/Windows/System32/notepad.exe", // Application Name
                cmdLine, // Command Line
                IntPtr.Zero,
                IntPtr.Zero,
                false,
                dwCreationFlags,
                pEnv,
                workDir, // Working directory
                ref startInfo,
                out procInfo))
            {
                iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();

                throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);
            }
            return tokenHandle;
        }
    }
}

Below is the error

System.Exception
  HResult=0x80131500
  Message=StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -6
  Source=LogOnUserTestWindows
  StackTrace:
   at LogOnUserTestWindows.Program.ImpersonateUser(SecureString password, String userName, String domainName) in C:\Users\santosh\source\repos\LogOnUserTestWindows\LogOnUserTestWindows\Program.cs:line 242
   at LogOnUserTestWindows.Program.Main() in C:\Users\santosh\source\repos\LogOnUserTestWindows\LogOnUserTestWindows\Program.cs:line 122

I am not able to find any proper documentation for both logonUser and CreateProcessAsUser APIs. I am trying to run this code on my machine which has multiple usets. I am logged in from one user and trying to create process from another user. It would be really great if someone can point me to proper documentation or examples. Please help. Thanks in Advance.

windows
winapi
process
createprocess
createprocessasuser
asked on Stack Overflow Jun 8, 2018 by uttam.aaseri • edited Jun 8, 2018 by uttam.aaseri

2 Answers

3

You closed tokenHandle before you passed it to CreateProcessAsUser.

Result: ERROR_INVALID_HANDLE (= 6).

answered on Stack Overflow Jun 8, 2018 by Paul Sanders
-1

Please try CreateProcessWithToken instead, although I don't know why the function returned error code -6, but a few days ago I tried to start up an application with specified user token, but CreateProcessAsUser didn't work, but CreateProcessWithToken did. Maybe it will also work for you, good luck.

answered on Stack Overflow Jun 8, 2018 by jinchx

User contributions licensed under CC BY-SA 3.0