CreateProcessWithTokenW 関数 (winbase.h)
新しいプロセスとそのプライマリ スレッドを作成します。 新しいプロセスは、指定されたトークンのセキュリティ コンテキストで実行されます。 必要に応じて、指定したユーザーのユーザー プロファイルを読み込むことができます。
CreateProcessWithTokenW を呼び出すプロセスには、SE_IMPERSONATE_NAME特権が必要です。 この関数が ERROR_PRIVILEGE_NOT_HELD (1314) で失敗する場合は、代わりに CreateProcessAsUser または CreateProcessWithLogonW 関数を使用します。 通常は、 を呼び出すプロセス
CreateProcessAsUser にはSE_INCREASE_QUOTA_NAME特権が必要であり、トークンが割り当てできない場合はSE_ASSIGNPRIMARYTOKEN_NAME特権が必要になる場合があります。 CreateProcessWithLogonW には特別な特権は必要ありませんが、指定されたユーザー アカウントで対話形式でログオンできるようにする必要があります。 通常、 CreateProcessWithLogonW を使用して、代替資格情報を使用してプロセスを作成することをお勧めします。
構文
BOOL CreateProcessWithTokenW(
[in] HANDLE hToken,
[in] DWORD dwLogonFlags,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
パラメーター
[in] hToken
ユーザーを表すプライマリ トークンへのハンドル。 ハンドルには、TOKEN_QUERY、TOKEN_DUPLICATE、およびTOKEN_ASSIGN_PRIMARYアクセス権が必要です。 詳細については、「 Access-Token オブジェクトのアクセス権」を参照してください。 トークンで表されるユーザーは、 lpApplicationName または lpCommandLine パラメーターで指定されたアプリケーションに対する読み取りおよび実行アクセス権を持っている必要があります。
指定したユーザーを表すプライマリ トークンを取得するには、 LogonUser 関数を呼び出します。 または、 DuplicateTokenEx 関数を呼び出して、偽装トークンをプライマリ トークンに変換することもできます。 これにより、クライアントを偽装しているサーバー アプリケーションは、クライアントのセキュリティ コンテキストを持つプロセスを作成できます。
ターミナル サービス: 呼び出し元のプロセスは、トークンで指定されたセッションではなく、呼び出し元のセッションで常に実行されます。 トークンで指定されたセッションでプロセスを実行するには、CreateProcessAsUser 関数を使用します。
[in] dwLogonFlags
ログオン オプション。 このパラメーターには、0 または次のいずれかの値を指定できます。
[in, optional] lpApplicationName
実行するモジュールの名前。 このモジュールは、Windows ベースのアプリケーションにすることができます。 ローカル コンピューターで適切なサブシステムが使用可能な場合は、他の種類のモジュール (MS-DOS や OS/2 など) を使用できます。
文字列は、実行するモジュールの完全なパスとファイル名を指定するか、部分的な名前を指定できます。 部分名の場合、関数は現在のドライブと現在のディレクトリを使用して仕様を完了します。 関数は検索パスを使用しません。 このパラメーターには、ファイル名拡張子を含める必要があります。既定の拡張機能は想定されません。
lpApplicationName パラメーターには NULL を指定できます。 その場合、モジュール名は lpCommandLine 文字列の最初の空白区切りトークンである必要があります。 スペースを含む長いファイル名を使用している場合は、引用符で囲まれた文字列を使用して、ファイル名の末尾と引数の開始位置を示します。それ以外の場合、ファイル名はあいまいです。 たとえば、文字列 "c:\program files\sub dir\program name" を考えてみましょう。 この文字列は、さまざまな方法で解釈できます。 システムは、次の順序で可能性を解釈しようとします。
c:\program.exec:\ program files\sub files\sub.exedir\program.exec:\program files\sub dir\program.exec:\program files\sub dir\program name.exe 実行可能モジュールが 16 ビット アプリケーションの場合、 lpApplicationName は NULL で、 lpCommandLine が指す文字列は実行可能モジュールとその引数を指定する必要があります。
[in, out, optional] lpCommandLine
実行するコマンド ライン。
この文字列の最大長は 1024 文字です。 lpApplicationName が NULL の場合、lpCommandLine のモジュール名の部分はMAX_PATH文字に制限されます。
関数は、この文字列の内容を変更できます。 したがって、このパラメーターは読み取り専用メモリ ( const 変数やリテラル文字列など) へのポインターにすることはできません。 このパラメーターが定数文字列の場合、関数によってアクセス違反が発生する可能性があります。
lpCommandLine パラメーターには NULL を指定できます。 その場合、関数は lpApplicationName が指す文字列をコマンド ラインとして使用します。
lpApplicationName と lpCommandLine の両方が NULL 以外の場合、*lpApplicationName は実行するモジュールを指定し、*lpCommandLine はコマンド ラインを指定します。 新しいプロセスでは 、GetCommandLine を 使用してコマンド ライン全体を取得できます。 C で記述されたコンソール プロセスでは、 argc 引数と argv 引数を使用してコマンド ラインを解析できます。 argv[0] はモジュール名であるため、C プログラマは通常、モジュール名をコマンド ラインの最初のトークンとして繰り返します。
lpApplicationName が NULL の場合、コマンド ラインの最初の空白区切りトークンはモジュール名を指定します。 スペースを含む長いファイル名を使用している場合は、引用符で囲まれた文字列を使用して、ファイル名の末尾と引数の開始位置を示します ( lpApplicationName パラメーターの説明を参照してください)。 ファイル名に拡張子が含まれていない場合は、.exe が追加されます。 したがって、ファイル名拡張子が.com場合、このパラメーターには.com拡張子を含める必要があります。 ファイル名が拡張子のないピリオド (.) で終わる場合、またはファイル名にパスが含まれている場合、.exe は追加されません。 ファイル名にディレクトリ パスが含まれていない場合、システムは次の順序で実行可能ファイルを検索します。
- アプリケーションの読み込み元のディレクトリ。
- 親プロセスの現在のディレクトリ。
- 32 ビット Windows システム ディレクトリ。 GetSystemDirectory 関数を使用して、このディレクトリのパスを取得します。
- 16 ビット Windows システム ディレクトリ。 このディレクトリのパスを取得する関数はありませんが、検索されます。
- Windows ディレクトリ。 GetWindowsDirectory 関数を使用して、このディレクトリのパスを取得します。
- PATH 環境変数に一覧表示されているディレクトリ。 この関数は、 App Paths レジストリ キーで指定されたアプリケーションごとのパスを検索しないことに注意してください。 このアプリケーションごとのパスを検索シーケンスに含めるには、 ShellExecute 関数を使用します。
[in] dwCreationFlags
プロセスの作成方法を制御するフラグ。 既定では、CREATE_DEFAULT_ERROR_MODE、CREATE_NEW_CONSOLE、およびCREATE_NEW_PROCESS_GROUPフラグが有効になっています。 値の一覧については、「 プロセス作成フラグ」を参照してください。
このパラメーターは、新しいプロセスの優先度クラスも制御します。これは、プロセスのスレッドのスケジュールの優先順位を決定するために使用されます。 値の一覧については、「 GetPriorityClass」を参照してください。 優先度クラス フラグが指定されていない場合、作成プロセスの優先度クラスがIDLE_PRIORITY_CLASSまたはBELOW_NORMAL_PRIORITY_CLASSでない限り、優先度クラスは既定でNORMAL_PRIORITY_CLASSされます。 この場合、子プロセスは呼び出し元プロセスの既定の優先度クラスを受け取ります。
dwCreationFlags パラメーターの値が 0 の場合:
- このプロセスは、既定のエラー モードを取得し、新しいコンソールを作成し、新しいプロセス グループを作成します。
- 新しいプロセスの環境ブロックには ANSI 文字が含まれていると見なされます (詳細については、 lpEnvironment パラメーターを参照してください)。
- 16 ビットの Windows ベースのアプリケーションは、共有 Virtual DOS マシン (VDM) で実行されます。
[in, optional] lpEnvironment
新しいプロセスの環境ブロックへのポインター。 このパラメーターが NULL の場合、新しいプロセスでは lpUsername で指定されたユーザーのプロファイルから作成された環境が使用されます。
環境ブロックは、null で終わる文字列の null で終わるブロックで構成されます。 各文字列の形式は次のとおりです。
名前=値
等号 (=) は区切り記号として使用されるため、環境変数の名前には使用しないでください。
環境ブロックには、Unicode または ANSI 文字を含めることができます。 lpEnvironment が指す環境ブロックに Unicode 文字が含まれている場合は、dwCreationFlags にCREATE_UNICODE_ENVIRONMENTが含まれていることを確認してください。
ANSI 環境ブロックは、2 つのゼロ バイトで終了されます。1 つは最後の文字列で、もう 1 つはブロックを終了します。 Unicode 環境ブロックは 4 つのゼロ バイトで終了されます。最後の文字列の場合は 2 バイト、ブロックを終了するにはさらに 2 バイトです。
特定のユーザーの環境ブロックのコピーを取得するには、 CreateEnvironmentBlock 関数を使用します。
[in, optional] lpCurrentDirectory
プロセスの現在のディレクトリへの完全なパス。 この文字列では、UNC パスを指定することもできます。
このパラメーターが NULL の場合、新しいプロセスは呼び出し元プロセスと同じ現在のドライブとディレクトリを持つことになります。 (この機能は、主にアプリケーションを起動し、初期ドライブと作業ディレクトリを指定する必要があるシェル用に提供されます。
[in] lpStartupInfo
STARTUPINFO または STARTUPINFOEX 構造体へのポインター。
lpDesktop メンバーが NULL または空の文字列の場合、新しいプロセスは親プロセスのデスクトップステーションとウィンドウステーションを継承します。 関数は、継承されたウィンドウ ステーションとデスクトップに、指定したユーザー アカウントのアクセス許可を追加します。 それ以外の場合、このメンバーがデスクトップを指定する場合、WinSta0\Default の場合でも、指定したユーザー アカウントのアクセス許可を指定されたウィンドウ ステーションとデスクトップに追加するのはアプリケーションの役割です。
STARTUPINFO または STARTUPINFOEX のハンドルは、必要なくなったら CloseHandle で閉じる必要があります。
[out] lpProcessInformation
プロセスへの ハンドルを含 む、新しいプロセスの識別情報を受け取るPROCESS_INFORMATION構造体へのポインター。
PROCESS_INFORMATIONのハンドルは、必要なくなったときに CloseHandle 関数で閉じる必要があります。
戻り値
関数が成功すると、戻り値は 0 以外になります。
関数が失敗した場合は、0 を返します。 詳細なエラー情報を得るには、GetLastError を呼び出します。
関数は、プロセスの初期化が完了する前に が返されることに注意してください。 必要な DLL が見つからないか、初期化に失敗した場合、プロセスは終了します。 プロセスの終了状態を取得するには、 GetExitCodeProcess を呼び出します。
注釈
既定では、 CreateProcessWithTokenW では、指定したユーザーのプロファイルが HKEY_USERS レジストリ キーに読み込まれません。 つまり、 HKEY_CURRENT_USER レジストリ キー内の情報にアクセスしても、通常の対話型ログオンと一致する結果が得られない可能性があります。 LOGON_WITH_PROFILEを使用するか、この関数を呼び出す 前にLoadUserProfile 関数を呼び出して、ユーザーのレジストリ ハイブをHKEY_USERSに読み込む必要があります。
lpEnvironment パラメーターが NULL の場合、新しいプロセスでは、lpUserName で指定されたユーザーのプロファイルから作成された環境ブロックが使用されます。 HOMEDRIVE 変数と HOMEPATH 変数が設定されていない場合、 CreateProcessWithTokenW は、ユーザーの作業ディレクトリのドライブとパスを使用するように環境ブロックを変更します。
作成されると、新しいプロセスとスレッド ハンドルはフル アクセス権 (PROCESS_ALL_ACCESSとTHREAD_ALL_ACCESS) を受け取ります。 どちらのハンドルでも、セキュリティ記述子が指定されていない場合は、その型のオブジェクト ハンドルを必要とする任意の関数でハンドルを使用できます。 セキュリティ記述子を指定すると、アクセスが許可される前に、ハンドルの後続のすべての使用に対してアクセス チェックが実行されます。 アクセスが拒否された場合、要求プロセスは ハンドルを使用してプロセスまたはスレッドにアクセスできません。
セキュリティ トークンを取得するには、 PROCESS_INFORMATION 構造体のプロセス ハンドルを OpenProcessToken 関数に渡します。
プロセスにはプロセス識別子が割り当てられます。 識別子は、プロセスが終了するまで有効です。 これを使用してプロセスを識別するか、 OpenProcess 関数で指定してプロセスへのハンドルを開くことができます。 プロセス内の初期スレッドにもスレッド識別子が割り当てられます。 スレッドへのハンドルを開くには、 OpenThread 関数で指定できます。 識別子は、スレッドが終了するまで有効であり、システム内のスレッドを一意に識別するために使用できます。 これらの識別子は 、PROCESS_INFORMATIONで返されます。
呼び出し元のスレッドは WaitForInputIdle 関数を使用して、新しいプロセスの初期化が完了し、入力が保留されていないユーザー入力を待機しています。 これは、親プロセスと子プロセスの間の同期に役立ちます。 CreateProcessWithTokenW は、新しいプロセスが初期化を完了するのを待たずに を返します。 たとえば、作成プロセスでは、新しいプロセスに関連付けられているウィンドウを検索する前に WaitForInputIdle を使用します。
プロセスをシャットダウンする推奨される方法は 、ExitProcess 関数を使用することです。この関数は、プロセスにアタッチされているすべての DLL に終了に近づくという通知を送信するためです。 プロセスをシャットダウンするその他の方法では、アタッチされている DLL は通知されません。 スレッドが ExitProcess を呼び出すと、プロセスの他のスレッドは、追加のコード (アタッチされた DLL のスレッド終了コードを含む) を実行する機会なしに終了されることに注意してください。 詳細については、「 プロセスの終了」を参照してください。
この関数を使用するアプリケーションをコンパイルするには、_WIN32_WINNTを 0x0500 以降として定義します。 詳細については、「 Windows ヘッダーの使用」を参照してください。
セキュリティに関する備考
lpApplicationName パラメーターには NULL を指定できます。この場合、実行可能ファイル名は lpCommandLine の最初の空白で区切られた文字列である必要があります。 実行可能ファイルまたはパス名にスペースが含まれている場合、関数がスペースを解析する方法により、別の実行可能ファイルが実行される可能性があります。 次の例は、関数が "MyApp.exe" ではなく "Program.exe" を実行しようとするため、危険です。 LPTSTR szCmdline = L"C:\\Program Files\\MyApp";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
悪意のあるユーザーがシステムで "Program.exe" というアプリケーションを作成した場合、Program Files ディレクトリを使用して CreateProcessWithTokenW を誤って呼び出すプログラムは、目的のアプリケーションではなく、このアプリケーションを実行します。
この問題を回避するには、 lpApplicationName に NULL を渡さないでください。 lpApplicationName に NULL を渡す場合は、次の例に示すように、lpCommandLine の実行可能パスを引用符で囲みます。
LPTSTR szCmdline = L"\"C:\\Program Files\\MyApp\"";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
要件
要件 | 値 |
---|---|
サポートされている最小のクライアント | Windows Vista [デスクトップ アプリのみ] |
サポートされている最小のサーバー | Windows Server 2003 (デスクトップ アプリのみ) |
対象プラットフォーム | Windows |
ヘッダー | winbase.h (Windows.h を含む) |
Library | Advapi32.lib |
[DLL] | Advapi32.dll |