Compartilhar via


Exemplo: Adicionando um token auxiliar a um trabalho de transferência do BITS

Você pode configurar um trabalho de transferência do Serviço de Transferência Inteligente em Segundo Plano (BITS) com um token de segurança adicional. O trabalho de transferência do BITS usa esse token auxiliar para autenticação e acesso a recursos.

Para obter mais informações, consulte Tokens auxiliares para trabalhos de transferência do BITS.

O procedimento a seguir cria um trabalho de transferência do BITS no contexto do usuário local, obtém credenciais de um segundo usuário, cria um token auxiliar com essas credenciais e define o token auxiliar no trabalho de transferência do BITS.

Este exemplo usa o cabeçalho e a implementação definidos em Example: Common Classes.

Para adicionar um token auxiliar a um trabalho de transferência do BITS

  1. Inicialize os parâmetros COM chamando a função CCoInitializer. Para obter mais informações sobre a função CCoInitializer, consulte Exemplo: classes comuns.

  2. Obtenha um ponteiro para a interface IBackgroundCopyJob. Este exemplo usa a classe CComPtr para gerenciar ponteiros de interface COM.

  3. Inicialize a segurança do processo COM chamando CoInitializeSecurity. O BITS requer pelo menos o nível IMPERSONATE de representação. O BITS falhará com E_ACCESSDENIED se o nível de representação correto não estiver definido.

  4. Obtenha um ponteiro para a interface IBackgroundCopyManager e obtenha o localizador inicial para o BITS chamando a função CoCreateInstance.

  5. Crie um trabalho de transferência do BITS chamando o método IBackgroundCopyManager::CreateJob .

  6. Obtenha um ponteiro para a interface de retorno de chamada CNotifyInterface e chame o método IBackgroundCopyJob::SetNotifyInterface para receber notificação de eventos relacionados ao trabalho. Para obter mais informações sobre CNotifyInterface, consulte Exemplo: classes comuns.

  7. Chame o método IBackgroundCopyJob::SetNotifyFlags para definir os tipos de notificações a serem recebidas. Neste exemplo, os sinalizadores BG_NOTIFY_JOB_TRANSFERRED e BG_NOTIFY_JOB_ERROR são definidos.

  8. Obtenha um ponteiro para a interface IBitsTokenOptions chamando o método IBackgroundCopyJob::QueryInterface com o identificador de interface adequado.

  9. Tente fazer logon no usuário do token auxiliar. Crie um identificador de representação e chame a função LogonUser para preencher o identificador de representação. Se for bem-sucedido, chame a função ImpersonateLoggedOnUser. Se não for bem-sucedido, o exemplo chama a função RevertToSelf para encerrar a representação do usuário conectado, um erro é lançado e o identificador é fechado.

  10. Chame o método IBitsTokenOptions::SetHelperToken para representar o token do usuário conectado. Se esse método falhar, o exemplo chama a função RevertToSelf para encerrar a representação do usuário conectado, um erro é lançado e o identificador é fechado.

    Observação

    Em versões com suporte do Windows antes do Windows 10, versão 1607, o proprietário do trabalho deve ter credenciais administrativas para chamar o método IBitsTokenOptions::SetHelperToken.

    A partir do Windows 10, versão 1607, os proprietários de trabalhos que não são administradores podem definir tokens auxiliares de não administradores em trabalhos do BITS que possuem. Os proprietários de trabalhos ainda devem ter credenciais administrativas para definir tokens auxiliares com privilégios de administrador.

     

  11. Chame o método IBitsTokenOptions::SetHelperTokenFlags para especificar quais recursos acessar usando o contexto de segurança do token auxiliar.

  12. Depois que a representação for concluída, o exemplo chama a função RevertToSelf para encerrar a representação do usuário conectado e o identificador é fechado.

  13. Adicione arquivos ao trabalho de transferência do BITS chamando IBackgroundCopyJob::AddFile.

  14. Depois que o arquivo for adicionado, chame IBackgroundCopyJob::Resume para retomar o trabalho.

  15. Configure um loop while para aguardar a mensagem de encerramento da interface de retorno de chamada enquanto o trabalho está sendo transferido. O loop while usa a função GetTickCount para recuperar o número de milissegundos decorridos desde que o trabalho começou a ser transferido.

  16. Depois que o trabalho de transferência do BITS for concluído, remova o trabalho da fila chamando IBackgroundCopyJob::Complete.

O exemplo de código a seguir adiciona um token auxiliar a um trabalho de transferência do 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]);

}

Tokens auxiliares para trabalhos de transferência do BITS

IBitsTokenOptions

Exemplo: Classes comuns