2009-01-28 9 views
1

J'essaie d'écrire une fonction simple pour Windows qui répond à la question suivante.Comment vérifier si un utilisateur a des droits d'accès pour un fichier avec l'API Windows

L'utilisateur (U) a-t-il des droits (R) sur le fichier (F)?
Où,
R est une combinaison de (GENERIC_READ, GENERIC_WRITE, GENERIC_EXECUTE)
U ne doit pas être connecté ou personnifié

Le code que j'ai écrit est illustré ci-dessous. L'application appelle la première UserHasPermission qui est affichée.

Les droits d'accès renvoyés par GetEffectiveRightsFromAcl sont les mêmes pour toutes les combinaisons utilisateur/fichier que j'ai testées ($ 001200A9). J'ai vérifié et $ 001200A9 n'est pas seulement un pointeur vers l'endroit où les droits d'accès sont réellement stockés.

Ma question est double:
1. Y a-t-il une meilleure façon de procéder?
2. Quelqu'un peut-il me dire où je vais mal?

 
function UserHasPermission(APermission: Longword; out HasPermission: Boolean; AFileName: WideString; AUserName: String; ADomainName: String): Boolean; 
    var 
     SID: PSID; 
     ACL: PACL; 
    begin 
     SID := nil; 
     ACL := nil; 
     try 
     Result := GetUserSID(SID, AUserNAme, ADomainName); 
     Result := Result and GetFileDACL(AFileName, ACL); 
     Result := Result and UserHasPermission(APermission, HasPermission, ACL, SID); 
     finally 
     Dispose(SID); 
     end; 
    end; 

    function UserHasPermission(APermission: Longword; out HasPermission: Boolean; AACL: PACL; AUserSID: PSID): Boolean; 
    var 
     T: TRUSTEE; 
     Rights: ACCESS_MASK; 
    begin 
     BuildTrusteeWithSid(@T, AUserSID); 
     Result := GetEffectiveRightsFromAcl(AACL, @T, @Rights) = ERROR_SUCCESS; 
     HasPermission := (Rights and APermission) = APermission; 
    end; 

    function GetUserSID(out ASID: PSID; AUserName: WideString; const ADomainName: WideString): Boolean; 
    var 
     NSID, NDomain: Longword; 
     Use: SID_NAME_USE; 
     DomainName: WideString; 
    begin 
     Result := False; 
     if Length(AUserName) > 0 then 
     begin 
      if Length(ADomainName) > 0 then 
      AUserName := ADomainName + '\' + AUserName; 

      // determine memory requirements 
      NSID := 0; 
      NDomain := 0; 
      LookupAccountNameW(nil, PWideChar(AUserName), nil, NSID, nil, NDomain, Use); 

      // allocate memory 
      GetMem(ASID, NSID); 
      SetLength(DomainName, NDomain); 

      Result := LookupAccountNameW(nil, PWideChar(AUserName), ASID, NSID, PWideChar(DomainName), NDomain, Use); 
     end; 
    end; 

    function GetFileDACL(AFileName: WideString; out AACL: PACL): Boolean; 
    var 
     SD: PSecurityDescriptor; 
     NSD, NNeeded: Longword; 
     Present, Defualted: Longbool; 
    begin 
     GetFileSecurityW(PWideChar(AFileName), DACL_SECURITY_INFORMATION, nil, 0, NNeeded); 
     GetMem(SD, NNeeded); 
     try 
     NSD := NNeeded; 
     Result := GetFileSecurityW(PWideChar(AFileName), DACL_SECURITY_INFORMATION, SD, NSD, NNeeded); 
     Result := Result and GetSecurityDescriptorDacl(SD, Present, AACL, Defualted); 
     Result := Result and Present; 
     finally 
     Dispose(SD); 
     end; 
    end; 

Répondre

2

GetEffectiveRightsFromAcl sont les mêmes pour toutes les combinaisons utilisateur/fichier que j'ai testé (001200A9 $).

Tout dépend de l'ACL, par ex. Si tout le monde obtient le contrôle total, toute utilisation aura un contrôle total. Le code semble raisonnable et vous utilisez l'une des API de sécurité Win32 (GetEffectiveRightsFromAcl) pour effectuer le gros du travail. Suggestion: Créez des listes de contrôle d'accès très spécifiques pour tester votre code (SDDL facilite cela), en commençant par une qui ne fait pas de concession, puis une qui n'inclut qu'un utilisateur différent.

+0

Votre droit le code était à peu près correct. J'étais fatigué et frustré, c'est-à-dire négligent, pendant les tests. Merci pour la révision du code, tout fonctionne et maintenant je comprends ce qui se passe. –

+0

Sachez que GetEffectiveRightsFromAcl ne prend pas en compte les structures de groupe et les privilèges complexes imbriqués. Cela signifie que la fonction peut accorder ou refuser l'accès, même si ce n'est pas le cas. La fonction API AccessCheck est le moyen le plus sûr de le vérifier. Malheureusement, l'application doit emprunter l'identité de l'utilisateur en appelant AccessCheck. En fin de compte, les deux fonctions peuvent créer des résultats incorrects lorsqu'elles sont utilisées sur des objets distants car des vérifications d'accès supplémentaires sont effectuées par le système distant. – ChristianWimmer

Questions connexes