Поделиться через


Выполнение проверок доступа

Проверка доступа определяет, предоставляет ли дескриптор безопасности указанный набор прав доступа клиенту или потоку, определяемого маркером доступа. Вы можете вызвать функцию безопасности AccessCheck из клиентских приложений или поставщиков WMI, написанных на C++ или C#. Скрипты и приложения Visual Basic не могут выполнять проверки доступа с помощью метода, описанного здесь.

Клиентские приложения должны выполнить проверку доступа, чтобы определить идентификацию обратного вызова при возврате результатов приемнику, предоставленному клиента, совершившего асинхронный вызов.

Если поставщики не могут олицетворить клиентское приложение или скрипт, запрашивающий данные, они должны выполнять проверки доступа для следующих ситуаций:

  • При доступе к ресурсам, которые не защищены списками управления доступом (ACL).
  • Когда клиент подключился на уровне имитации RPC_C_LEVEL_IDENTIFY.

Заметка

Приложения C++ и C# могут контролировать, выполняются ли проверки доступа отдельным процессом. Скрипты и приложения Visual Basic могут считывать или изменять раздел реестра, чтобы WMI выполнял проверку доступа. Дополнительные сведения см. в разделе Настройка безопасности для асинхронного вызова.

 

В примере кода в этой теме требуются следующие ссылки и директивы #include для правильной компиляции.

#include <lmcons.h>
#define _WIN32_DCOM
#define SECURITY_WIN32
#include <wbemidl.h>
#include <security.h>
#include <safestr.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "Secur32.lib")

В следующем примере кода показано, как проверить, содержит ли маркер безопасности потока клиентского приложения разрешения, соответствующие указанному дескриптору безопасности. Функция принимает строку "domain\user" и возвращает идентификатор безопасности. Если вызов завершается ошибкой, функция возвращает NULL, в противном случае вызывающий объект должен освободить возвращенный указатель.

BYTE * GetSid(LPWSTR pwcUserName)
{
    DWORD dwSidSize = 0, dwDomainSize = 0;
    SID_NAME_USE use;

    // first call is to get the size
    BOOL bRet = LookupAccountNameW(

      NULL,            // system name
      pwcUserName,     // account name
      NULL,            // security identifier
      &dwSidSize,      // size of security identifier
      NULL,            // domain name
      &dwDomainSize,   // size of domain name
      &use             // SID-type indicator
      );    

    if(bRet == FALSE && ERROR_INSUFFICIENT_BUFFER 
        != GetLastError())\
        return NULL;

    BYTE * buff = new BYTE[dwSidSize];

    if(buff == NULL)
        return NULL;

    WCHAR * pwcDomain = new WCHAR[dwDomainSize];

    if(pwcDomain == NULL)

    {
        delete [] buff;
        return FALSE;
    }

    // Call to LookupAccountNameW actually gets the SID
    bRet = LookupAccountNameW(

      NULL,           // system name
      pwcUserName,    // account name
      buff,           // security identifier
      &dwSidSize,     // size of security identifier
      pwcDomain,      // domain name
      &dwDomainSize,  // size of domain name
      &use            // SID-type indicator
      );    

    delete [] pwcDomain;

    if(bRet == FALSE)
    {
        delete [] buff;
        return NULL;
    }

    return buff;
}

// This returns true if the caller is coming 
//   from the expected computer in the expected domain.

BOOL IsAllowed(LPWSTR pwsExpectedDomain, 
   LPWSTR pwsExpectedMachine)
{

    WCHAR wCallerName[UNLEN + 1];
    DWORD nSize = UNLEN + 1;

// Impersonate the caller and get its name

    HRESULT hr = CoImpersonateClient();
    if(FAILED(hr))

        return FALSE;

    BOOL bRet = GetUserNameExW(NameSamCompatible, 
       wCallerName, &nSize);

    CoRevertToSelf();

    if(bRet == FALSE)

        return FALSE;


    // take the expected domain and lan manager 
    //   style name and create a SID.  In actual
    // production code, it would be more efficient 
    //   to do this only when necessary

    WCHAR wExpectedName[UNLEN + 1];

    HRESULT hrCopyCat;
    hrCopyCat = StringCchCopy(wExpectedName,
        sizeof(pwsExpectedDomain)*sizeof(WCHAR)+1, 
        pwsExpectedDomain);
    if (FAILED(hrCopyCat))
    {
        return FALSE;
    }
    hrCopyCat = 
        StringCchCat(wExpectedName,sizeof(wExpectedName)
        + 2*sizeof(WCHAR)+1, L"\\");
    if (FAILED(hrCopyCat))
    {
        return FALSE;
    }
    hrCopyCat = StringCchCat(wExpectedName,sizeof(wExpectedName)
        + sizeof(pwsExpectedMachine)*sizeof(WCHAR)+1, 
        pwsExpectedMachine);
    if (FAILED(hrCopyCat))
    {
        return FALSE;
    }
    hrCopyCat = StringCchCat(wExpectedName,sizeof(wExpectedName)
        + sizeof(WCHAR)+1, L"$");
    if (FAILED(hrCopyCat))
    {
        return FALSE;
    }
  

    // convert the two names to SIDs and compare.  
    // Note that SIDs are used since 
    //   the format of the names might vary.  

    BYTE * pCaller = GetSid(wCallerName);

    if(pCaller == NULL)

        return FALSE;

    BYTE * pExpected = GetSid(wExpectedName);

    if(pExpected == NULL)
    {
        delete [] pCaller;

        return FALSE;
    }

    bRet = EqualSid((PSID)pCaller, (PSID)pExpected);

    delete [] pCaller;
    delete [] pExpected;

    return bRet;
}

Выбор правильной регистрации

Поддержание безопасности WMI

Обеспечение безопасности вашего поставщика

Доступ к пространствам имен WMI