Exécution de vérifications d’accès

Une vérification d’accès détermine si un descripteur de sécurité accorde un ensemble spécifié de droits d’accès au client ou au thread identifié par un token d’accès. Vous pouvez appeler la fonction de sécurité AccessCheck à partir d’applications clientes WMI ou de fournisseurs écrits en C++ ou C#. Les scripts et applications Visual Basic ne peuvent pas effectuer de vérifications d’accès à l’aide de la méthode décrite ici.

Les applications clientes doivent effectuer une vérification d’accès pour déterminer l’identité du rappel lors du retour des résultats au récepteur fourni par l’appel asynchrone du client.

Lorsque les fournisseurs ne peuvent pas emprunter l’identité de l’application cliente ou du script qui demande des données, ils doivent effectuer des vérifications d’accès pour les situations suivantes :

  • Lors de l’accès à des ressources qui ne sont pas protégées par des listes de contrôle d’accès (ACL).
  • Lorsque le client s'est connecté au niveau d'identification RPC_C_LEVEL_IDENTIFY.

Notes

Les applications C++ et C# peuvent contrôler si les vérifications d’accès sont effectuées par un processus distinct. Les scripts et les applications Visual Basic peuvent lire ou modifier une clé de Registre pour s’assurer que WMI effectue des vérifications d’accès. Pour plus d’informations, voir Définition de la sécurité sur un appel asynchrone.

 

L'exemple de code présenté dans cette rubrique nécessite les références et les instructions #include suivantes pour être compilé correctement.

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

L’exemple de code suivant montre comment vérifier que le token de sécurité d’un thread d’application client contient les autorisations appropriées pour un descripteur de sécurité spécifié. La fonction prend la chaîne « domain\user » et retourne le SID. Si l’appel échoue, la fonction retourne NULL, sinon l’appelant doit libérer le pointeur retourné.

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

Choix du bon enregistrement

Maintenance de la sécurité WMI

Sécurisation de votre fournisseur

Accès aux espaces de noms WMI