Numéro d'article: 132958 - Dernière mise à jour: mardi 1 mars 2005 - Version: 3.2

Comment faire pour gérer des privilèges des utilisateurs par programme dans Windows NT

A noterCet article s'applique à un système d'exploitation différent de celui que vous utilisez. Le contenu de l'article qui ne vous concerne peut-être pas est désactivé.

Sommaire

Agrandir tout | Réduire tout

Résumé

Dans Windows NT, les privilèges sont utilisés pour fournir un moyen de contrôle d'accès qui diffère de contrôle d'accès discrétionnaire. Un administrateur système utilise des privilèges pour les utilisateurs/groupes qui sont en mesure de manipuler les divers aspects du système de contrôle. Une application peut utiliser des privilèges lorsqu'il modifie une ressource système, telles que l'heure système, ou lorsqu'il arrête le système.

L'outil Gestionnaire des utilisateurs peut être utilisé pour accorder et révoquer des privilèges de comptes.

Windows NT 3.51 fournit une fonctionnalité qui permet au développeur gérer par programme des privilèges. Cette fonctionnalité est rendue disponible via LSA (autorité de sécurité locale).

Un programme d'installation du service est un exemple d'une application qui pourrait présenter un avantage à partir de LSA. Si le service est configuré pour s'exécuter sous un compte d'utilisateur, il est nécessaire pour ce compte possède le privilège de «ouverture de session en tant que service» SeServiceLogonRight. Cet article explique comment tirer parti de LSA pour accorder et révoquer des privilèges des utilisateurs et groupes.

Plus d'informations

Gestion des privilèges utilisateur peuvent être atteints par programme en procédant comme suit :
  1. Ouvrez la stratégie sur l'ordinateur cible avec LsaOpenPolicy(). Pour accorder des privilèges, ouvrez la stratégie accès POLICY_CREATE_ACCOUNT et POLICY_LOOKUP_NAMES. Pour révoquer des privilèges, ouvrez la stratégie avec accès POLICY_LOOKUP_NAMES.
  2. Obtenir un SID (identificateur de sécurité) représentant l'utilisateur/groupe d'intérêt. Les API de LsaLookupNames() et LookupAccountName() peuvent obtenir un SID à partir d'un nom de compte.
  3. Appelez LsaAddAccountRights() pour accorder des privilèges pour les utilisateurs représentés par le SID fourni.
  4. Appelez LsaRemoveAccountRights() pour révoquer des privilèges de l'utilisateur représenté par le SID fourni.
  5. Fermez la stratégie avec LsaClose().
Pour accorder et révoquer des privilèges correctement, l'appelant doit être un administrateur sur le système cible.

Le LsaEnumerateAccountRights() API LSA peut être utilisé pour déterminer quels privilèges ont été accordées à un compte.

Le LsaEnumerateAccountsWithUserRight() API LSA peut être utilisé pour déterminer quels comptes ont reçu un privilège spécifié.

Fichiers de documentation et l'en-tête de ces API LSA est fourni dans le Kit de développement Windows 32 dans le répertoire MSTOOLS\SECURITY.

Dans les versions dernier du Kit de développement Win32 SDK, les en-têtes s'affichent dans le répertoire mstools\samples\win32\winnt\security\include et la documentation se trouve dans.... \security\lsasamp\lsaapi.hlp.

Remarque : Ces API LSA sont actuellement implémenté en tant qu'Unicode uniquement.

Cet exemple accorde le privilège SeServiceLogonRight sur le compte spécifié sur argv [1].

Cet exemple repose sur ces importer des bibliothèques
Advapi32.lib (pour LsaXxx)
User32.lib (pour wsprintf)
Cet exemple fonctionnera correctement compilé ANSI ou Unicode.

Exemple de code

/*++

You can use domain\account as argv[1]. For instance, mydomain\scott will
grant the privilege to the mydomain domain account scott.

The optional target machine is specified as argv[2], otherwise, the
account database is updated on the local machine.

The LSA APIs used by this sample are Unicode only.

Use LsaRemoveAccountRights() to remove account rights.

Scott Field (sfield)    12-Jul-95
--*/ 

#ifndef UNICODE
#define UNICODE
#endif // UNICODE

#include <windows.h>
#include <stdio.h>

#include "ntsecapi.h"

NTSTATUS
OpenPolicy(
    LPWSTR ServerName,          // machine to open policy on (Unicode)
    DWORD DesiredAccess,        // desired access to policy
    PLSA_HANDLE PolicyHandle    // resultant policy handle
    );

BOOL
GetAccountSid(
    LPTSTR SystemName,          // where to lookup account
    LPTSTR AccountName,         // account of interest
    PSID *Sid                   // resultant buffer containing SID
    );

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    );

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString, // destination
    LPWSTR String                  // source (Unicode)
    );

void
DisplayNtStatus(
    LPSTR szAPI,                // pointer to function name (ANSI)
    NTSTATUS Status             // NTSTATUS error value
    );

void
DisplayWinError(
    LPSTR szAPI,                // pointer to function name (ANSI)
    DWORD WinError              // DWORD WinError
    );

#define RTN_OK 0
#define RTN_USAGE 1
#define RTN_ERROR 13

// 
// If you have the ddk, include ntstatus.h.
// 
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
#endif

int _cdecl
main(int argc, char *argv[])
{
    LSA_HANDLE PolicyHandle;
    WCHAR wComputerName[256]=L"";   // static machine name buffer
    TCHAR AccountName[256];         // static account name buffer
    PSID pSid;
    NTSTATUS Status;
    int iRetVal=RTN_ERROR;          // assume error from main

    if(argc == 1)
    {
        fprintf(stderr,"Usage: %s <Account> [TargetMachine]\n",
            argv[0]);
        return RTN_USAGE;
    }

    // 
    // Pick up account name on argv[1].
    // Assumes source is ANSI. Resultant string is ANSI or Unicode
    // 
    wsprintf(AccountName, TEXT("%hS"), argv[1]);

    // 
    // Pick up machine name on argv[2], if appropriate
    // assumes source is ANSI. Resultant string is Unicode.
    // 
    if(argc == 3) wsprintfW(wComputerName, L"%hS", argv[2]);

    // 
    // Open the policy on the target machine.
    // 
    if((Status=OpenPolicy(
                wComputerName,      // target machine
                POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
                &PolicyHandle       // resultant policy handle
                )) != STATUS_SUCCESS) {
        DisplayNtStatus("OpenPolicy", Status);
        return RTN_ERROR;
    }

    // 
    // Obtain the SID of the user/group.
    // Note that we could target a specific machine, but we don't.
    // Specifying NULL for target machine searches for the SID in the
    // following order: well-known, Built-in and local, primary domain,
    // trusted domains.
    // 
    if(GetAccountSid(
            NULL,       // default lookup logic
            AccountName,// account to obtain SID
            &pSid       // buffer to allocate to contain resultant SID
            )) {
        // 
        // We only grant the privilege if we succeeded in obtaining the
        // SID. We can actually add SIDs which cannot be looked up, but
        // looking up the SID is a good sanity check which is suitable for
        // most cases.

        // 
        // Grant the SeServiceLogonRight to users represented by pSid.
        // 
        if((Status=SetPrivilegeOnAccount(
                    PolicyHandle,           // policy handle
                    pSid,                   // SID to grant privilege
                    L"SeServiceLogonRight", // Unicode privilege
                    TRUE                    // enable the privilege
                    )) == STATUS_SUCCESS)
            iRetVal=RTN_OK;
        else
            DisplayNtStatus("AddUserRightToAccount", Status);
    }
    else {
        // 
        // Error obtaining SID.
        // 
        DisplayWinError("GetAccountSid", GetLastError());
    }

    // 
    // Close the policy handle.
    // 
    LsaClose(PolicyHandle);

    // 
    // Free memory allocated for SID.
    // 
    if(pSid != NULL) HeapFree(GetProcessHeap(), 0, pSid);

    return iRetVal;
}

void
InitLsaString(
    PLSA_UNICODE_STRING LsaString,
    LPWSTR String
    )
{
    DWORD StringLength;

    if (String == NULL) {
        LsaString->Buffer = NULL;
        LsaString->Length = 0;
        LsaString->MaximumLength = 0;
        return;
    }

    StringLength = wcslen(String);
    LsaString->Buffer = String;
    LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
    LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
}

NTSTATUS
OpenPolicy(
    LPWSTR ServerName,
    DWORD DesiredAccess,
    PLSA_HANDLE PolicyHandle
    )
{
    LSA_OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_UNICODE_STRING ServerString;
    PLSA_UNICODE_STRING Server = NULL;

    // 
    // Always initialize the object attributes to all zeroes.
    // 
    ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));

    if (ServerName != NULL) {
        // 
        // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
        // 
        InitLsaString(&ServerString, ServerName);
        Server = &ServerString;
    }

    // 
    // Attempt to open the policy.
    // 
    return LsaOpenPolicy(
                Server,
                &ObjectAttributes,
                DesiredAccess,
                PolicyHandle
                );
}

/*++
This function attempts to obtain a SID representing the supplied
account on the supplied system.

If the function succeeds, the return value is TRUE. A buffer is
allocated which contains the SID representing the supplied account.
This buffer should be freed when it is no longer needed by calling
HeapFree(GetProcessHeap(), 0, buffer)

If the function fails, the return value is FALSE. Call GetLastError()
to obtain extended error information.

Scott Field (sfield)    12-Jul-95
--*/ 

BOOL
GetAccountSid(
    LPTSTR SystemName,
    LPTSTR AccountName,
    PSID *Sid
    )
{
    LPTSTR ReferencedDomain=NULL;
    DWORD cbSid=128;    // initial allocation attempt
    DWORD cchReferencedDomain=16; // initial allocation size
    SID_NAME_USE peUse;
    BOOL bSuccess=FALSE; // assume this function will fail

    __try {

    // 
    // initial memory allocations
    // 
    if((*Sid=HeapAlloc(
                    GetProcessHeap(),
                    0,
                    cbSid
                    )) == NULL) __leave;

    if((ReferencedDomain=(LPTSTR)HeapAlloc(
                    GetProcessHeap(),
                    0,
                    cchReferencedDomain * sizeof(TCHAR)
                    )) == NULL) __leave;

    // 
    // Obtain the SID of the specified account on the specified system.
    // 
    while(!LookupAccountName(
                    SystemName,         // machine to lookup account on
                    AccountName,        // account to lookup
                    *Sid,               // SID of interest
                    &cbSid,             // size of SID
                    ReferencedDomain,   // domain account was found on
                    &cchReferencedDomain,
                    &peUse
                    )) {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
            // 
            // reallocate memory
            // 
            if((*Sid=HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        *Sid,
                        cbSid
                        )) == NULL) __leave;

            if((ReferencedDomain=(LPTSTR)HeapReAlloc(
                        GetProcessHeap(),
                        0,
                        ReferencedDomain,
                        cchReferencedDomain * sizeof(TCHAR)
                        )) == NULL) __leave;
        }
        else __leave;
    }

    // 
    // Indicate success.
    // 
    bSuccess=TRUE;

    } // finally
    __finally {

    // 
    // Cleanup and indicate failure, if appropriate.
    // 

    HeapFree(GetProcessHeap(), 0, ReferencedDomain);

    if(!bSuccess) {
        if(*Sid != NULL) {
            HeapFree(GetProcessHeap(), 0, *Sid);
            *Sid = NULL;
        }
    }

    } // finally

    return bSuccess;
}

NTSTATUS
SetPrivilegeOnAccount(
    LSA_HANDLE PolicyHandle,    // open policy handle
    PSID AccountSid,            // SID to grant privilege to
    LPWSTR PrivilegeName,       // privilege to grant (Unicode)
    BOOL bEnable                // enable or disable
    )
{
    LSA_UNICODE_STRING PrivilegeString;

    // 
    // Create a LSA_UNICODE_STRING for the privilege name.
    // 
    InitLsaString(&PrivilegeString, PrivilegeName);

    // 
    // grant or revoke the privilege, accordingly
    // 
    if(bEnable) {
        return LsaAddAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
    else {
        return LsaRemoveAccountRights(
                PolicyHandle,       // open policy handle
                AccountSid,         // target SID
                FALSE,              // do not disable all rights
                &PrivilegeString,   // privileges
                1                   // privilege count
                );
    }
}

void
DisplayNtStatus(
    LPSTR szAPI,
    NTSTATUS Status
    )
{
    // 
    // Convert the NTSTATUS to Winerror. Then call DisplayWinError().
    // 
    DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
}

void
DisplayWinError(
    LPSTR szAPI,
    DWORD WinError
    )
{
    LPSTR MessageBuffer;
    DWORD dwBufferLength;

    // 
    // TODO: Get this fprintf out of here!
    // 
    fprintf(stderr,"%s error!\n", szAPI);

    if(dwBufferLength=FormatMessageA(
                        FORMAT_MESSAGE_ALLOCATE_BUFFER |
                        FORMAT_MESSAGE_FROM_SYSTEM,
                        NULL,
                        WinError,
                        GetUserDefaultLangID(),
                        (LPSTR) &MessageBuffer,
                        0,
                        NULL
                        ))
    {
        DWORD dwBytesWritten; // unused

        // 
        // Output message string on stderr.
        // 
        WriteFile(
            GetStdHandle(STD_ERROR_HANDLE),
            MessageBuffer,
            dwBufferLength,
            &dwBytesWritten,
            NULL
            );

        // 
        // Free the buffer allocated by the system.
        // 
        LocalFree(MessageBuffer);
    }
}
				
/*++
This function enables system access on the account represented by the
supplied SID. An example of such access is the SeLogonServiceRight.

Note: to disable a given system access, simply remove the supplied
access flag from the existing flag, and apply the result to the
account.

If the function succeeds, the return value is STATUS_SUCCESS.
If the function fails, the return value is an NTSTATUS value.

Scott Field (sfield)    14-Jul-95
--*/ 
NTSTATUS
AddSystemAccessToAccount(
   LSA_HANDLE PolicyHandle,
   PSID AccountSid,
   ULONG NewAccess
   )
{
   LSA_HANDLE AccountHandle;
   ULONG PreviousAccess;
   NTSTATUS Status;

   // 
   // open the account object. If it doesn't exist, create a new one
   // 
   if((Status=LsaOpenAccount(
           PolicyHandle,
           AccountSid,
           ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
           &AccountHandle
           )) == STATUS_OBJECT_NAME_NOT_FOUND)
   {
       Status=LsaCreateAccount(
               PolicyHandle,
               AccountSid,
               ACCOUNT_ADJUST_SYSTEM_ACCESS | ACCOUNT_VIEW,
               &AccountHandle
               );
   }

   // 
   // if an error occurred opening or creating, return
   // 
   if(Status != STATUS_SUCCESS) return Status;

   // 
   // obtain current system access flags
   // 
   if((Status=LsaGetSystemAccessAccount(
           AccountHandle,
           &PreviousAccess
           )) == STATUS_SUCCESS)
   {
       // 
       // Add the specified access to the account
       // 
       Status=LsaSetSystemAccessAccount(
               AccountHandle,
               PreviousAccess | NewAccess
               );
   }

   LsaClose(AccountHandle);

   return Status;
}

/*++
This function grants a privilege to the account represented by the
supplied SID. An example of such a privilege is the
SeBackupPrivilege.

Note: To revoke a privilege, use LsaRemovePrivilegesFromAccount.

If the function succeeds, the return value is STATUS_SUCCESS.
If the function fails, the return value is an NTSTATUS value.

Scott Field (sfield)    13-Jul-95
--*/ 

NTSTATUS
AddPrivilegeToAccount(
   LSA_HANDLE PolicyHandle,
   PSID AccountSid,
   LPWSTR PrivilegeName
   )
{
   PRIVILEGE_SET ps;
   LUID_AND_ATTRIBUTES luidattr;
   LSA_HANDLE AccountHandle;
   LSA_UNICODE_STRING PrivilegeString;
   NTSTATUS Status;

   // 
   // Create a LSA_UNICODE_STRING for the privilege name
   // 
   InitLsaString(&PrivilegeString, PrivilegeName);

   // 
   // obtain the LUID of the supplied privilege
   // 
   if((Status=LsaLookupPrivilegeValue(
           PolicyHandle,
           &PrivilegeString,
           &luidattr.Luid
           )) != STATUS_SUCCESS) return Status;

   // 
   // setup PRIVILEGE_SET
   // 
   luidattr.Attributes=0;
   ps.PrivilegeCount=1;
   ps.Control=0;
   ps.Privilege[0]=luidattr;

   // 
   // open the account object if it doesn't exist, create a new one
   // 
   if((Status=LsaOpenAccount(
           PolicyHandle,
           AccountSid,
           ACCOUNT_ADJUST_PRIVILEGES,
           &AccountHandle
           )) == STATUS_OBJECT_NAME_NOT_FOUND)
   {
       Status=LsaCreateAccount(
               PolicyHandle,
               AccountSid,
               ACCOUNT_ADJUST_PRIVILEGES,
               &AccountHandle
               );
   }

   // 
   // if an error occurred opening or creating, return
   // 
   if(Status != STATUS_SUCCESS) return Status;

   // 
   // add the privileges to the account
   // 
   Status=LsaAddPrivilegesToAccount(
           AccountHandle,
           &ps
           );

   LsaClose(AccountHandle);

   return Status;
}
				

Les informations contenues dans cet article s'appliquent au(x) produit(s) suivant(s):
  • Microsoft Win32 Application Programming Interface sur le système suivant
    • Microsoft Windows NT 3.51 Service Pack 5
    • Microsoft Windows NT 4.0
    • the operating system: Microsoft Windows 2000
Mots-clés : 
kbmt kbapi kbhowto kbkernbase kblsa kbsecurity KB132958 KbMtfr
Traduction automatiqueTraduction automatique
IMPORTANT : Cet article est issu du système de traduction automatique mis au point par Microsoft (http://support.microsoft.com/gp/mtdetails). Un certain nombre d?articles obtenus par traduction automatique sont en effet mis à votre disposition en complément des articles traduits en langue française par des traducteurs professionnels. Cela vous permet d?avoir accès, dans votre propre langue, à l?ensemble des articles de la base de connaissances rédigés originellement en langue anglaise. Les articles traduits automatiquement ne sont pas toujours parfaits et peuvent comporter des erreurs de vocabulaire, de syntaxe ou de grammaire (probablement semblables aux erreurs que ferait une personne étrangère s?exprimant dans votre langue !). Néanmoins, mis à part ces imperfections, ces articles devraient suffire à vous orienter et à vous aider à résoudre votre problème. Microsoft s?efforce aussi continuellement de faire évoluer son système de traduction automatique.
La version anglaise de cet article est la suivante: 132958  (http://support.microsoft.com/kb/132958/en-us/ )
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.