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


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

Проверка доступа определяет, предоставляет ли дескриптор безопасности указанный набор прав доступа клиенту или потоку, определенному маркером доступа. Функцию безопасности 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")

В следующем примере кода показано, как проверка, что маркер безопасности потока клиентского приложения содержит разрешения, соответствующие указанному дескриптору безопасности. Функция принимает строку "домен\пользователь" и возвращает идентификатор безопасности. Если вызов завершается сбоем, функция возвращает значение 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