Нашел решение. Это шароварный код на рабоче-крестьянском Паскале, что мне нравится больше всего. Работает без закидонов, только имейте ввиду оговорочку внизу насчет неосвобождения дескриптора.
Код | { Named object permissions demo. Special Edition for TenderHawk. This code displays permissions of a given file or directory. File/directory name is passed as a parameter. This code will work actually under NT-Family systems with NTFS volumes (otherwise you always get NULL DACL). (c)Kid_Deceiver } program test; uses Windows, Aclapi, AccCtrl; {$R *.RES} const ACCESS_ALLOWED_ACE_TYPE = $00; ACCESS_DENIED_ACE_TYPE = $01; SYSTEM_AUDIT_ACE_TYPE = $02; type ACL_SIZE_INFORMATION = record AceCount : DWORD; AclBytesInUse : DWORD; AclBytesFree : DWORD; end; ACE_HEADER = record AceType : BYTE; AceFlags : BYTE; AceSize : WORD; end; ACCESS_MASK = DWORD; ACCESS_ALLOWED_ACE = record Header : ACE_HEADER; Mask : ACCESS_MASK; SidStart : DWORD; end; PACE = ^ACCESS_ALLOWED_ACE; procedure finish( error : Integer ); begin writeln( 'Program terminated, exit code ', error ); Halt ( error ); end; var pSD : PSECURITY_DESCRIPTOR; pDACL : PACL; aclSize : ACL_SIZE_INFORMATION; err : Integer; res : DWORD; ace_idx : DWORD; AcePtr : Pointer; SidPtr : PSID; user : array[0..255] of Char; domain : array[0..255] of Char; user_len : DWORD; domain_len : DWORD; sid_nu : SID_NAME_USE; begin // File/Directory name is passed as a first parameter if (ParamCount() < 1) then begin writeln( 'object names is not specified' ); finish( 1 ); end; // Get DACL for the specified named object. res := GetNamedSecurityInfo( PChar( ParamStr(1) ), SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, PACL(@pDACL), nil, pSD ); // PACL(@pDACL) due to error in declaration in ACLAPI.PAS if(ERROR_SUCCESS <> res) then begin writeln( 'GetNamedSecurityInfo failed ' ); finish( res ); end; // Permissions are not specified (you have FAT ;-)) if (nil = pDACL) then begin writeln( ParamStr(1), ' has no DACL' ); finish( 0 ); end; // Here we valid DACL with a list of ACEs (with SIDs). // Let's get number of ACEs. if( not GetAclInformation( pDACL^, @aclSize, sizeOf(aclSize), AclSizeInformation )) then begin err := GetLastError(); writeln( 'GetAclInformation failed ' ); finish( err ); end; // Walk through ACEs and display information about each entry ace_idx := 0; while( ace_idx < aclSize.AceCount ) do begin if (GetAce( pDACL^, ace_idx, AcePtr )) then begin // Take SID from ACE and get accoount name // Note some trick. ACE structures begin with the same // members in all cases. So I just use ACCESS_ALLOWED_ACE // for simplicity. // Correct way is to convert to PACE_HEADER, then check type // and then convert to proper ACE type. user_len := SizeOf( user ); domain_len := SizeOf( domain ); SidPtr := PSID(@(PACE(AcePtr)^.SidStart)); write( ace_idx, ') ' ); if (LookupAccountSid( nil, SidPtr, user, user_len, domain, domain_len, sid_nu)) then write( domain, '\', user ) else write( 'unknown' ); // Display ACE type case (PACE(AcePtr)^.Header.AceType) of ACCESS_ALLOWED_ACE_TYPE : write( ' allowed' ); ACCESS_DENIED_ACE_TYPE : write( ' denied' ); else write( ' audit' ); // actually 'audit' never happens in this example end; // Display access MASK writeln( ' mask ', PACE(AcePtr)^.Mask ); end // GetAce failed else begin err := GetLastError(); writeln( 'GetAce failed at index ', ace_idx ); finish( err ); end; Inc( ace_idx ); end; // ace_idx // Note: Security descriptor is not freed end.
|
|