Como executar verificações de acesso

Uma verificação de acesso determina se um descritor de segurança concede um conjunto especificado de direitos de acesso ao cliente ou thread identificado por um token de acesso. Você pode chamar a função de segurança AccessCheck de aplicativos cliente do WMI ou provedores gravados em C++ ou C#. Os scripts e aplicativos do Visual Basic não podem executar verificações de acesso usando o método descrito aqui.

Os aplicativos cliente devem fazer uma verificação de acesso para determinar a identidade do retorno de chamada ao retornar resultados para o coletor fornecido pela chamada assíncrona do cliente.

Quando os provedores não podem representar o aplicativo cliente ou o script que está solicitando dados, eles devem executar verificações de acesso para as seguintes situações:

  • Ao acessar recursos que não estão protegidos por ACL (listas de controle de acesso).
  • Quando o cliente tiver se conectado no nível de representação RPC_C_LEVEL_IDENTIFY.

Observação

Os aplicativos C++ e C# podem controlar se as verificações de acesso são executadas por um processo separado. Os scripts e aplicativos do Visual Basic podem ler ou alterar uma chave do registro para garantir que o WMI execute as verificações de acesso. Para obter mais informações, confira Como configurar a segurança em uma chamada assíncrona.

 

Os exemplos de código neste tópico exigem que as referências e instruções #include a seguir sejam compiladas corretamente.

#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")

O exemplo de código a seguir mostra como verificar se o token de segurança de um thread de aplicativo cliente contém as permissões apropriadas para um descritor de segurança especificado. A função usa a cadeia de caracteres "domain\user" e retorna o SID. Se a chamada falhar, a função retornará NULL. Caso contrário, o chamador deverá liberar o ponteiro retornado.

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;
}

Como escolher o registro correto

Como manter a segurança do WMI

Como proteger seu provedor

Acesso a namespaces do WMI