Windows create process as user
Функция CreateProcessAsUser создает новый процесс и его первичный (главный) поток. Новый процесс затем запускает заданный исполняемый файл. Функция CreateProcessAsUser похожа на функцию CreateProcess , за исключением того, что новый процесс запускается в контексте системы безопасности пользователя, обозначенного параметром hToken . По умолчанию, новый процесс не интерактивный, то есть он запускает рабочий стол, который не видим и не может получать ввод данных от пользователя. К тому же, по умолчанию, новый процесс наследует конфигурацию вызывающего процесса, а не конфигурацию, связанную с определениями пользователя.
Функция CreateProcessWithLogonW похожа на CreateProcessAsUser , за исключением того, что вызывающей программе не нужно вызывать функцию LogonUser , чтобы подтвердить подлинность пользователя и получить маркер безопасности.
Эта функция также подобна и функции SHCreateProcessAsUserW .
[in] Дескриптор первичного маркера, который обозначает пользователя. Дескриптор должен иметь права доступа TOKEN_QUERY , TOKEN_DUPLICATE и TOKEN_ASSIGN_PRIMARY . Для получения дополнительной информации, см. статью Права доступа для Объектов маркера доступа . Пользователь, обозначенный маркером, может иметь доступ к чтению и исполнению кода, программы, указанной параметрами lpApplicationName или lpCommandLine .
Чтобы получить первичный маркер, который обозначает заданного пользователя, вызовите функцию LogonUser . Или же, Вы можете вызывать функцию DuplicateTokenEx , чтобы преобразовать маркер заимствования прав в первичный маркер. Это дает возможность серверному приложению, представляющему клиента, создать процесс, который имеет контекст системы безопасности клиента.
Обслуживание терминала: Процесс запускается в сеансе, заданном маркером. По умолчанию, это такой же самый сеанс, который вызывается функцией LogonUser . Чтобы изменить сеанс, используйте функцию SetTokenInformation .
[in] Указатель на строку с нулем в конце, которая определяет модуль исполняемого кода. Заданный модуль может быть базирующейся на Windows прикладной программой. Это может быть какой-то другой тип модуля (например, MS-DOS или OS/2 ), если соответствующая подсистема доступна на локальном компьютере.
Строка может указывать полный путь и имя файла исполняемого модуля или она может определять часть имени. В случае если это часть имени, функция использует текущий диск и текущий каталог, чтобы завершить определение. Функция не будет использовать найденный путь. Если имя файла не содержит расширение, подразумевается расширение .exe. Поэтому, если расширение имени файла — .com, этот параметр должен включить в себя расширение .com.
Параметр lpApplicationName может быть значением ПУСТО (NULL). В этом случае, имя модуля должно быть в строке lpCommandLine как первое незаполненное пространство, разграниченное маркером.
Если Вы используете длинное имя файла, которое содержит пробел, применяйте строки в кавычках, чтобы обозначить, где имя файла заканчивается, и начинаются параметры; иначе, имя файла становится неоднозначным. Например, рассмотрим строку » c:\program files\sub dir\program name «. Эта строка может интерпретироваться несколькими способами. Попытки системы интерпретировать ее, возможны в нижеследующем порядке :
c:\program.exe files\sub dir\program name c:\program files\sub.exe dir\program name c:\program files\sub dir\program.exe name c:\program files\sub dir\program name.exe |
Если выполняемый модуль — 16-разрядное приложение, параметр lpApplicationName должен быть значением ПУСТО (NULL), а строка, указанная в параметре lpCommandLine должна задать выполняемый модуль, также как его параметры. По умолчанию, все 16-разрядные, базирующиеся на Windows прикладные программы, созданные функцией CreateProcessAsUser , работают в отдельной виртуальной машине DOS (VDM) (эквивалент CREATE_SEPARATE_WOW_VDM в функции CreateProcess ).
[in] Указатель на строку с символом нуля в конце, определяющую командную строку для выполнения.
Версия Уникода этой функции, CreateProcessAsUserW , завершится ошибкой, если этот параметр является строкой типа const .
Параметр lpCommandLine может быть значением ПУСТО (NULL). В этом случае, функция использует строку, указанную параметром lpApplicationName как командную строку.
Если и lpApplicationName и lpCommandLine не пустые (non-NULL), *lpApplicationName задает модуль выполнения, а * lpCommandLine определяет командную строку. Новый процесс может использовать функцию GetCommandLine , чтобы извлечь взятую в целом командную строку. Консольные процессы, написанные на языке C, могут использовать параметры argc и argv , чтобы подробно анализировать командную строку. Поскольку argv [0] — имя модуля, C — программисты обычно повторяют имя модуля как первый маркер в командной строке.
Если lpApplicationName имеет значение ПУСТО (NULL), первое незаполненное пространство, ограниченное маркером командной строки, определяет имя модуля. Если Вы используете длинное имя файла, которое содержит пробел, используйте строки в кавычках, чтобы обозначить, где заканчивается имя файла, и начинаются параметры (см. объяснение параметра lpApplicationName ).Если имя файла не содержит расширения, предполагается расширение .exe. Поэтому, если расширение имени файла — .com, этот параметр должен включать в себя расширение .com. Если имя файла заканчивается точкой ( . ) без расширения, или имя файла содержит путь, расширение .exe не присоединяется. Если имя файла не содержит путь к каталогу, система ищет исполняемый файл в нижеследующей последовательности:
|
Система добавляет нулевой символ к командной строке, чтобы отделить имя файла от параметров. Он делит исходную строку на две строки для внутренней обработки.
[in] Указатель на структуру SECURITY_ATTRIBUTES , которая определяет дескриптор безопасности для нового процесса и выявляет, может ли возвращенный дескриптор быть унаследован дочерними процессами. Если lpProcessAttributes имеет значение ПУСТО (NULL), или lpSecurityDescriptor имеет значение ПУСТО (NULL), процесс получает заданный по умолчанию дескриптор безопасности, а дескриптор не может быть унаследован. Заданный по умолчанию дескриптор безопасности — это ссылка пользователя на параметр hToken . Этот дескриптор безопасности не может разрешить доступ для вызывающей программы, в этом случае процесс не может быть открыт снова после того, как он запускается. Дескриптор процесса правильный и продолжает иметь полные права доступа.
[in] Указатель на структуру SECURITY_ATTRIBUTES , которая определяет дескриптор безопасности для нового процесса и выявляет, может ли возвращенный дескриптор быть унаследован дочерними процессами. Если lpThreadAttributes имеет значение ПУСТО (NULL), или lpSecurityDescriptor имеет значение ПУСТО (NULL), то поток получает заданный по умолчанию дескриптор безопасности и дескриптор не может быть унаследован. Заданный по умолчанию дескриптор безопасности — это ссылка пользователя на параметр hToken . Этот дескриптор безопасности не может разрешить доступ для вызывающей программы.
[in] Если этот параметр — ИСТИНА (TRUE), каждый наследуемый дескриптор в вызывающем процессе наследуется новым процессом. Если этот параметр — ЛОЖЬ (FALSE), дескрипторы не наследуются.
Обратите внимание! на то, что унаследованные дескрипторы имеют то же самое значение и права доступа, что и первоначальные дескрипторы.
[in] Флажки, которые управляют классом приоритета и созданием процесса. За перечнем значений обратитесь к статье Флажки создания процесса .
Этот параметр также управляет и классом приоритета нового процесса, который используется в определении приоритетов диспетчеризации потоков процесса. За перечнем значений обратитесь к статье о функции GetPriorityClass . Если ни один из флажков класса приоритета не установлен, значения по умолчанию класса приоритета NORMAL_PRIORITY_CLASS , если класс приоритета процесса созданного процесса не является IDLE_PRIORITY_CLASS или BELOW_NORMAL_PRIORITY_CLASS . В данном случае дочерние процессы получают заданный по умолчанию класс приоритета вызывающего процесса.
[in] Указатель на блок конфигурации нового процесса. Если этот параметр имеет значение ПУСТО (NULL), новый процесс использует конфигурацию вызывающего процесса.
Блок конфигурации состоит из блока строк с символом нуля в конце, который завершается также нулем. Каждая строка представляется в форме:
Поскольку знак «=» используется как разделитель, он не должен быть использован в имени переменной окружения.
Блок конфигурации может содержать или символы Unicode или ANSI . Если блок конфигурации, указанный параметром lpEnvironment , содержит символы Unicode , убедитесь, что в параметре dwCreationFlags установлен флажок CREATE_UNICODE_ENVIRONMENT . Если блок содержит символы ANSI , этот флажок будет сброшен.
Обратите внимание! на то, что блок конфигурации в ANSI заканчивается двумя нулевыми байтами: один для последней строки, еще один, чтобы завершить блок. Блок конфигурации Уникода заканчивается четырьмя нулевыми байтами: два — для последней строки, еще два, чтобы завершить блок.
Чтобы получить копию блока конфигурации для данного пользователя, используйте функцию CreateEnvironmentBlock .
[in] Указатель на строку с символом нуля в конце, определяющую текущий диск и каталог для нового процесса. Строка должна быть полным путем, который включает в себя букву (имя) диска. Если этот параметр является значением ПУСТО (NULL), новый процесс будет иметь тот же самый текущий диск и каталог, что и вызывающий процесс. (Этот параметр дается, прежде всего, для оболочек, которым нужно запустить прикладную программу и установить ее исходный диск и рабочий каталог).
[in] Указатель на структуру STARTUPINFO , которая устанавливает оконный режим терминала, рабочий стол, стандартные дескрипторы и внешний вид главного окна для нового процесса.
[out] Указатель на структуру PROCESS_INFORMATION , которая принимает идентифицирующую информацию о новом процессе.
Дескрипторы в структуре PROCESS_INFORMATION , когда они больше не нужны, должны быть закрыты функцией CloseHandle .
Возвращаемые значения
Если функция завершается успешно, величина возвращаемого значения — не ноль.
Если функция завершается с ошибкой, величина возвращаемого значения — ноль. Чтобы получить дополнительные данные об ошибках, вызовите GetLastError .
Замечания
Как правило, процесс, который вызывает функцию CreateProcessAsUser , должен иметь права доступа SE_ASSIGNPRIMARYTOKEN_NAME и SE_INCREASE_QUOTA_NAME . Однако если параметр hToken блокируется версией первичного маркера безопасности вызывающей программы, право доступа SE_ASSIGNPRIMARYTOKEN_NAME не требуется. Если необходимые права доступа ещё не разрешены, функция CreateProcessAsUser дает возможность им для продолжения вызова. Для получения дополнительной информации, см. статью Запуск со специальными правами доступа .
Функция CreateProcessAsUser должна быть в состоянии открыть первичный маркер безопасности вызывающего процесса с правами доступа TOKEN_DUPLICATE и TOKEN_IMPERSONATE .
По умолчанию, функция CreateProcessAsUser создает новый процесс для не интерактивной оконной станции с рабочим столом, который не видим и не может получать ввод данных от пользователя. Чтобы дать возможность пользователю воздействовать с новым процессом, Вы должны определить имя заданного по умолчанию интерактивного оконного режима терминала и рабочего стола, «winsta0\default», в члене lpDesktop структуры STARTUPINFO . Кроме того, перед вызовом функции CreateProcessAsUser , Вы должны изменить список разграничительного контроля доступа ( DACL ) и заданный по умолчанию интерактивный режим терминала и заданный по умолчанию рабочий стол. Списки DACL для оконного режима терминала и рабочего стола должны предоставлять доступ пользователю или сеансу входа в систему, обозначенному параметром hToken .
Функция CreateProcessAsUser не загружает заданный в ключе системного реестра HKEY_USERS профиль пользователя. По этой причине, чтобы обратиться к информации в ключе системного реестра HKEY_CURRENT_USER , Вы должны загрузить информацию о конфигурации пользователя в HKEY_USERS при помощи функции LoadUserProfile перед вызовом CreateProcessAsUser .
Если параметр lpEnvironment имеет значение ПУСТО (NULL), новый процесс наследует конфигурацию вызывающего процесса. Функция CreateProcessAsUser автоматически не изменяет блок конфигурации, чтобы включить переменные окружения, конкретные для пользователя, обозначенного параметром hToken . Например, переменные USERNAME и USERDOMAIN наследуются от вызывающего процесса, если lpEnvironment — значение ПУСТО (NULL). Это — вы отвечаете за подготовку блока конфигурации нового процесса и устанавливаете его в lpEnvironment .
Функция CreateProcessAsUser позволяет Вам обратиться к заданному каталогу и исполняемому образу в контексте системы безопасности вызывающей программы или конкретного пользователя. По умолчанию, CreateProcessAsUser обращается к каталогу и выполнимому образу в контексте системы безопасности вызывающей программы. В этом случае, если вызывающая программа не имеет доступа к каталогу и исполняемому образу, функция завершается ошибкой. Чтобы обратиться к каталогу и исполняемому образу, используя контекст системы безопасности конкретного пользователя, установите параметр hToken при вызове функции ImpersonateLoggedOnUser перед вызовом CreateProcessAsUser .
Процессу присваивается идентификатор. Идентификатор является правильным до тех пор, пока процесс не завершит работу. Он может быть использован, чтобы идентифицировать процесс, или открыть определяемый функцией OpenProcess дескриптор процесса. Начальный поток в процессе также получает свой идентификатор. Он может быть задан функцией OpenThread , чтобы открыть дескриптор потока. Идентификатор правильный до тех пор, пока поток закончит свою работу и может быть использован, чтобы уникально идентифицировать поток в пределах системы. Эти идентификаторы возвращаются в структуре PROCESS_INFORMATION .
Вызывающий поток может использовать функцию WaitForInputIdle , чтобы ждать до тех пор, пока новый процесс не завершит свою инициализацию и станет ждать от пользователя ввода данных без задержки ввода. Этот прием может быть полезным для синхронизации родительского и дочернего процессов, поскольку функция CreateProcessAsUser возвращает значение не ожидая, когда новый процесс закончит свою инициализацию. Например, создающий процесс должен использовать функцию WaitForInputIdle перед попыткой найти окно, связанное с новым процессом.
Предпочтительным способом выключить процесс является использование функции ExitProcess , потому что эта функция уведомляет все динамически подключаемые библиотеки ( DLL ), связанные с процессом о приближающемся завершении работы. Другой способ завершения процесса не уведомляет связанные DLL .
Обратите внимание! на то, что когда поток вызывает ExitProcess , другие потоки процесса, завершают работу без возможности выполнить какой-либо дополнительный код (включая код завершения потока связанных DLL ). За дополнительной информацией обратитесь к статье Завершение работы процесса.
Замечания по безопасности
Параметр lpApplicationName , может иметь значение ПУСТО (NULL), в этом случае имя исполняемой программы должно быть первое незаполненное пространство разграничивающее строку в параметре lpCommandLine . Если имя пути или исполняемой программы имеют пробел, имеется риск того, что может быть запущена другая исполняемая программа из-за способа, которым функция подробно анализирует пробелы. Нижеследующий пример демонстрирует эту опасность, потому что функция вместо «MyApp.exe» будет пытаться запустить «Program.exe», если таковая существует .
Если неграмотный пользователь создаст в системе прикладную программу, называемую «Program.exe», любая программа, которая неправильно вызывает функцию CreateProcessAsUser , используя каталог Program Files, будет запускать это приложение вместо заданной программы .
Чтобы избежать этой проблемы, не передавайте значение ПУСТО (NULL) для параметра lpApplicationName . Если Вы передаете это значение ПУСТО (NULL) для lpApplicationName , используйте кавычки вокруг пути к исполняемой программе в параметре lpCommandLine , как показано в примере ниже.
Пример смотри в статье Запуск интерактивного процесса-клиента
Смотри также
Размещение и совместимость CreateProcessAsUser