例: BITS 転送ジョブへのヘルパー トークンの追加
追加のセキュリティ トークンを使用して、バックグラウンド インテリジェント転送サービス (BITS) 転送ジョブを構成できます。 BITS 転送ジョブは、認証とリソースへのアクセスにこのヘルパー トークンを使用します。
詳細については、 「BITS転送ジョブのヘルパートークン」 を参照してください。
次の手順では、ローカル ユーザーのコンテキストで BITS 転送ジョブを作成し、2 番目のユーザーの資格情報を取得し、これらの資格情報を使用してヘルパー トークンを作成し、ヘルパー トークンを BITS 転送ジョブに設定します。
この例では、「例: 共通クラス」で定義されているヘッダーと実装を使用します。
BITS 転送ジョブにヘルパー トークンを追加するには
CCoInitializer 関数を呼び出して COM パラメーターを初期化します。 CCoInitializer 関数の詳細については、「例: 共通クラス」を参照してください。
IBackgroundCopyJob インターフェイスへのポインターを取得します。 この例では、CComPtr クラスを使用して COM インターフェイス ポインターを管理します。
CoInitializeSecurity を呼び出して COM プロセスのセキュリティを初期化します。 BITS には、少なくとも IMPERSONATE レベルの偽装が必要です。 BITS は、適切な偽装レベルが設定されていない場合、E_ACCESSDENIED で失敗します。
IBackgroundCopyManager インターフェイスへのポインターを取得し、CoCreateInstance 関数を呼び出して BITS への初期ロケーターを取得します。
IBackgroundCopyManager::CreateJob メソッドを呼び出して、転送ジョブを作成します。
CNotifyInterface コールバック インターフェイスへのポインターを取得し、IBackgroundCopyJob::SetNotifyInterface メソッドを呼び出して、ジョブ関連のイベントの通知を受信します。 CNotifyInterface の詳細については、「例: 共通クラス」を参照してください。
IBackgroundCopyJob::SetNotifyFlags メソッドを呼び出して、受信する通知の種類を設定します。 この例では、BG_NOTIFY_JOB_TRANSFERRED フラグと BG_NOTIFY_JOB_ERROR フラグが設定されています。
IBackgroundCopyJob::QueryInterface メソッドを適切なインターフェイス識別子で呼び出して、IBitsTokenOptions インターフェイスへのポインターを取得します。
ヘルパー トークンのユーザーのログオンを試みます。 偽装ハンドルを作成し、LogonUser 関数を呼び出して偽装ハンドルを設定します。 成功した場合は、ImpersonateLoggedOnUser 関数を呼び出します。 失敗した場合、この例では RevertToSelf 関数を呼び出してログオンしているユーザーの偽装を終了し、エラーがスローされ、ハンドルが閉じられます。
IBitsTokenOptions::SetHelperToken メソッドを呼び出して、ログオンしているユーザーのトークンを偽装します。 このメソッドが失敗した場合、この例では RevertToSelf 関数を呼び出してログオンしているユーザーの偽装を終了し、エラーがスローされ、ハンドルが閉じられます。
Note
Windows 10 バージョン 1607 より前のサポートされているバージョンの Windows では、ジョブ所有者は IBitsTokenOptions::SetHelperToken メソッドを呼び出す管理者資格情報を持っている必要があります。
Windows 10 バージョン 1607 以降では、管理者以外のジョブ所有者は、自分が所有する BITS ジョブに管理者以外のヘルパー トークンを設定できます。 管理者特権を持つヘルパー トークンを設定するには、ジョブの所有者は引き続き管理者資格情報を持っている必要があります。
IBitsTokenOptions::SetHelperTokenFlags メソッドを呼び出して、ヘルパー トークンのセキュリティ コンテキストを使用してアクセスするリソースを指定します。
偽装が完了したら、RevertToSelf 関数を呼び出してログオンしているユーザーの偽装を終了し、ハンドルを閉じます。
IBackgroundCopyJob::AddFile を呼び出して、BITS 転送ジョブにファイルを追加します。
ファイルが追加されたら、IBackgroundCopyJob::Resume を呼び出してジョブを再開します。
ジョブの転送中にコールバック インターフェイスからの終了メッセージを待機するように while ループを設定します。 while ループでは、GetTickCount 関数を使用して、ジョブの転送が開始されてから経過したミリ秒数を取得します。
BITS 転送ジョブが完了したら、IBackgroundCopyJob::Complete を呼び出して、キューからジョブを削除します。
次のコード例では、BITS 転送ジョブにヘルパー トークンを追加します。
#include <bits.h>
#include <bits4_0.h>
#include <stdio.h>
#include <tchar.h>
#include <lm.h>
#include <iostream>
#include <exception>
#include <string>
#include <atlbase.h>
#include <memory>
#include <new>
#include "CommonCode.h"
void HelperToken(const LPWSTR &remoteFile, const LPWSTR &localFile, const LPWSTR &domain, const LPWSTR &username, const LPWSTR &password)
{
// If CoInitializeEx fails, the exception is unhandled and the program terminates
CCoInitializer coInitializer(COINIT_APARTMENTTHREADED);
CComPtr<IBackgroundCopyJob> pJob;
try
{
//The impersonation level must be at least RPC_C_IMP_LEVEL_IMPERSONATE.
HRESULT hr = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_CONNECT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_DYNAMIC_CLOAKING,
0
);
if (FAILED(hr))
{
throw MyException(hr, L"CoInitializeSecurity");
}
// Connect to BITS.
CComPtr<IBackgroundCopyManager> pQueueMgr;
hr = CoCreateInstance(__uuidof(BackgroundCopyManager), NULL,
CLSCTX_LOCAL_SERVER,
__uuidof(IBackgroundCopyManager),
(void **)&pQueueMgr);
if (FAILED(hr))
{
// Failed to connect.
throw MyException(hr, L"CoCreateInstance");
}
// Create a job.
wprintf(L"Creating Job...\n");
GUID guidJob;
hr = pQueueMgr->CreateJob(L"HelperTokenSample",
BG_JOB_TYPE_DOWNLOAD,
&guidJob,
&pJob);
if(FAILED(hr))
{
// Failed to create job.
throw MyException(hr, L"CreateJob");
}
// Set the File Completed call.
CComPtr<CNotifyInterface> pNotify;
pNotify = new CNotifyInterface();
hr = pJob->SetNotifyInterface(pNotify);
if (FAILED(hr))
{
// Failed to SetNotifyInterface.
throw MyException(hr, L"SetNotifyInterface");
}
hr = pJob->SetNotifyFlags(BG_NOTIFY_JOB_TRANSFERRED |
BG_NOTIFY_JOB_ERROR);
if (FAILED(hr))
{
// Failed to SetNotifyFlags.
throw MyException(hr, L"SetNotifyFlags");
}
//Retrieve the IBitsTokenOptions interface pointer from the BITS transfer job.
CComPtr<IBitsTokenOptions> pTokenOptions;
hr = pJob->QueryInterface(__uuidof(IBitsTokenOptions), (void** ) &pTokenOptions);
if (FAILED(hr))
{
// Failed to QueryInterface.
throw MyException(hr, L"QueryInterface");
}
// Log on user of the helper token.
wprintf(L"Credentials for helper token %s\\%s %s\n", domain, username, password);
HANDLE hImpersonation = INVALID_HANDLE_VALUE;
if(LogonUser(username, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hImpersonation))
{
// Impersonate the logged-on user.
if(ImpersonateLoggedOnUser(hImpersonation))
{
// Configure the impersonated logged-on user's token as the helper token.
hr = pTokenOptions->SetHelperToken();
if (FAILED(hr))
{
//Failed to set helper token.
CloseHandle(hImpersonation);
RevertToSelf();
throw MyException(hr, L"SetHelperToken");
}
hr = pTokenOptions->SetHelperTokenFlags(BG_TOKEN_LOCAL_FILE);
if (FAILED(hr))
{
//Failed to set helper token flags.
CloseHandle(hImpersonation);
RevertToSelf();
throw MyException(hr, L"SetHelperTokenFlags");
}
RevertToSelf();
}
CloseHandle(hImpersonation);
}
// Add a file.
// Replace parameters with variables that contain valid paths.
wprintf(L"Adding File to Job\n");
hr = pJob->AddFile(remoteFile,localFile);
if(FAILED(hr))
{
//Failed to add file to job.
throw MyException(hr, L"AddFile");
}
//Resume the job.
wprintf(L"Resuming Job...\n");
hr = pJob->Resume();
if (FAILED(hr))
{
// Resume failed.
throw MyException(hr, L"Resume");
}
}
catch(const std::bad_alloc &)
{
wprintf(L"Memory allocation failed");
if (pJob)
{
pJob->Cancel();
}
return;
}
catch(const MyException &ex)
{
wprintf(L"Error 0x%x occurred during operation", ex.Error);
if (pJob)
{
pJob->Cancel();
}
return;
}
wprintf(L"Transferring file and waiting for callback.\n");
// Wait for QuitMessage from CallBack
DWORD dwLimit = GetTickCount() + (15 * 60 * 1000); // set 15 minute limit
while (dwLimit > GetTickCount())
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// If it is a quit message, exit.
if (msg.message == WM_QUIT)
{
return;
}
// Otherwise, dispatch the message.
DispatchMessage(&msg);
} // End of PeekMessage while loop
}
pJob->Cancel();
return;
}
void _cdecl _tmain(int argc, LPWSTR* argv)
{
if (argc != 6)
{
wprintf(L"Usage:");
wprintf(L"%s ", argv[0]);
wprintf(L"[remote name] [local name] [helpertoken domain] [helpertoken userrname] [helpertoken password]\n");
return;
}
HelperToken(argv[1],argv[2],argv[3],argv[4],argv[5]);
}
関連トピック