Exemple : ajout d’un jeton d’assistance à un travail de transfert BITS
Vous pouvez configurer un travail de transfert BITS (Background Intelligent Transfer Service) avec un jeton de sécurité supplémentaire. Le travail de transfert BITS utilise ce jeton d’assistance pour l’authentification et pour accéder aux ressources.
Pour plus d’informations, consultez Jetons d’assistance pour les travaux de transfert BITS.
La procédure suivante crée un travail de transfert BITS dans le contexte de l’utilisateur local, obtient les informations d’identification d’un deuxième utilisateur, crée un jeton d’assistance avec ces informations d’identification, puis définit le jeton d’assistance sur le travail de transfert BITS.
Cet exemple utilise l’en-tête et l’implémentation définis dans Exemple : Classes communes.
Pour ajouter un jeton d’assistance à un travail de transfert BITS
Initialisez les paramètres COM en appelant la fonction CCoInitializer. Pour plus d’informations sur la fonction CCoInitializer, consultez Exemple : classes communes.
Obtenez un pointeur vers l’interface IBackgroundCopyJob . Cet exemple utilise la classe CComPtr pour gérer les pointeurs d’interface COM.
Initialisez la sécurité des processus COM en appelant CoInitializeSecurity. BITS nécessite au moins le niveau d’emprunt d’identité IMPERSONATE. BITS échoue avec E_ACCESSDENIED si le niveau d’emprunt d’identité correct n’est pas défini.
Obtenez un pointeur vers l’interface IBackgroundCopyManager et obtenez le localisateur initial vers BITS en appelant la fonction CoCreateInstance .
Créez un travail de transfert BITS en appelant la méthode IBackgroundCopyManager::CreateJob .
Obtenez un pointeur vers l’interface de rappel CNotifyInterface et appelez la méthode IBackgroundCopyJob::SetNotifyInterface pour recevoir une notification des événements liés au travail. Pour plus d’informations sur CNotifyInterface, consultez Exemple : Classes communes.
Appelez la méthode IBackgroundCopyJob::SetNotifyFlags pour définir les types de notifications à recevoir. Dans cet exemple, les indicateurs BG_NOTIFY_JOB_TRANSFERRED et BG_NOTIFY_JOB_ERROR sont définis.
Obtenez un pointeur vers l’interface IBitsTokenOptions en appelant la méthode IBackgroundCopyJob::QueryInterface avec l’identificateur d’interface approprié.
Essayez de connecter l’utilisateur du jeton d’assistance. Créez un handle d’emprunt d’identité et appelez la fonction LogonUser pour remplir le handle d’emprunt d’identité. En cas de réussite, appelez la fonction ImpersonateLoggedOnUser. En cas d’échec, l’exemple appelle la fonction RevertToSelf pour mettre fin à l’emprunt d’identité de l’utilisateur connecté, une erreur est générée et le handle est fermé.
Appelez la méthode IBitsTokenOptions::SetHelperToken pour emprunter l’identité du jeton de l’utilisateur connecté. Si cette méthode échoue, l’exemple appelle la fonction RevertToSelf pour mettre fin à l’emprunt d’identité de l’utilisateur connecté, une erreur est générée et le handle est fermé.
Notes
Dans les versions de Windows prises en charge avant Windows 10, version 1607, le propriétaire du travail doit disposer d’informations d’identification d’administration pour appeler la méthode IBitsTokenOptions::SetHelperToken.
À compter de Windows 10, version 1607, les propriétaires de travaux non administrateurs peuvent définir des jetons d’assistance non administrateur sur les travaux BITS dont ils sont propriétaires. Les propriétaires de travaux doivent toujours avoir des informations d’identification administratives pour définir des jetons d’assistance avec des privilèges d’administrateur.
Appelez la méthode IBitsTokenOptions::SetHelperTokenFlags pour spécifier les ressources auxquelles accéder à l’aide du contexte de sécurité du jeton d’assistance.
Une fois l’emprunt d’identité terminé, l’exemple appelle la fonction RevertToSelf pour mettre fin à l’emprunt d’identité de l’utilisateur connecté, et le handle est fermé.
Ajoutez des fichiers au travail de transfert BITS en appelant IBackgroundCopyJob::AddFile.
Une fois le fichier ajouté, appelez IBackgroundCopyJob::Resume pour reprendre le travail.
Configurez une boucle while pour attendre le message de quitter l’interface de rappel pendant le transfert du travail. La boucle while utilise la fonction GetTickCount pour récupérer le nombre de millisecondes écoulées depuis le début du transfert du travail.
Une fois le travail de transfert BITS terminé, supprimez le travail de la file d’attente en appelant IBackgroundCopyJob::Complete.
L’exemple de code suivant ajoute un jeton d’assistance à un travail de transfert 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]);
}
Rubriques connexes