示例:将帮助程序令牌添加到 BITS 传输作业

可以使用额外的安全令牌配置后台智能传输服务 (BITS) 传输作业。 BITS 传输作业使用此帮助程序令牌进行身份验证和访问资源。

有关详细信息,请参阅 BITS 传输作业的帮助程序令牌

以下过程在本地用户的上下文中创建 BITS 传输作业,获取第二个用户的凭据,使用这些凭据创建帮助程序令牌,然后在 BITS 传输作业上设置帮助程序令牌。

此示例使用示例:公共类中定义的标头和实现。

将帮助程序令牌添加到 BITS 传输作业

  1. 通过调用 CCoInitializer 函数初始化 COM 参数。 有关 CCoInitializer 函数的详细信息,请参阅示例:公共类

  2. 获取指向 IBackgroundCopyJob 接口的指针。 此示例使用 CComPtr 类管理 COM 接口指针。

  3. 通过调用 CoInitializeSecurity 初始化 COM 进程安全性。 BITS 至少需要模拟级别的模拟。 如果未设置正确的模拟级别,BITS 将以 E_ACCESSDENIED 失败。

  4. 获取指向 IBackgroundCopyManager 接口的指针,并通过调用 CoCreateInstance 函数获取 BITS 的初始定位符。

  5. 通过调用 IBackgroundCopyManager::CreateJob 方法创建 BITS 传输作业。

  6. 获取指向 CNotifyInterface 回调接口的指针,并调用 IBackgroundCopyJob::SetNotifyInterface 方法以接收与作业相关的事件的通知。 有关 CNotifyInterface 的详细信息,请参阅示例:公共类

  7. 调用 IBackgroundCopyJob::SetNotifyFlags 方法以设置要接收的通知类型。 在此示例中,设置了 BG_NOTIFY_JOB_TRANSFERREDBG_NOTIFY_JOB_ERROR 标志。

  8. 通过使用正确的接口标识符调用 IBackgroundCopyJob::QueryInterface 方法,获取指向 IBitsTokenOptions 接口的指针。

  9. 尝试登录帮助程序令牌的用户。 创建模拟句柄,并调用 LogonUser 函数以填充模拟句柄。 如果成功,请调用 ImpersonateLoggedOnUser 函数。 如果失败,该示例将调用 RevertToSelf 函数以终止登录用户的模拟,将引发错误,并关闭句柄。

  10. 调用 IBitsTokenOptions::SetHelperToken 方法来模拟已登录用户的令牌。 如果此方法失败,该示例将调用 RevertToSelf 函数以终止登录用户的模拟,将引发错误,并关闭句柄。

    注意

    在 Windows 10 版本 1607 之前的受支持 Windows 版本中,作业所有者必须具有管理凭据才能调用 IBitsTokenOptions::SetHelperToken 方法。

    从 Windows 10 版本 1607 开始,非管理员作业所有者可以在自己拥有的 BITS 作业上设置非管理员帮助程序令牌。 作业所有者仍必须具有管理凭据才能使用管理员权限设置帮助程序令牌。

     

  11. 调用 IBitsTokenOptions::SetHelperTokenFlags 方法以指定要使用帮助程序令牌的安全上下文访问哪些资源。

  12. 模拟完成后,该示例调用 RevertToSelf Function 以终止已登录用户的模拟,并关闭句柄。

  13. 通过调用 IBackgroundCopyJob::AddFile 将文件添加到 BITS 传输作业。

  14. 添加文件后,调用 IBackgroundCopyJob::Resume 以恢复作业。

  15. 设置 while 循环,以在作业传输时等待来自回调接口的退出消息。 while 循环使用 GetTickCount 函数检索自作业开始传输以来已用过的毫秒数。

  16. 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]);

}

BITS 传输作业的帮助程序令牌

IBitsTokenOptions

示例:公共类