I would like to get the permissions on a folder. I'm using the libraries ffi and ref to invoke native Windows functions. I'm calling the function GetNamedSecurityInfoA to get the DACL but the returned struct contains wrong values. Could you please help me? Thanks!
Edit 20191208: Function GetAce seems to work though...
Some Structures and Definitions:
/*typedef struct _ACE_HEADER {
BYTE AceType;
BYTE AceFlags;
WORD AceSize;
} ACE_HEADER;*/
export const ACE_HEADER = struct({
AceType:win32types.UCHAR,
AceFlags:win32types.UCHAR,
AceSize:win32types.WORD
});
/*typedef struct _ACCESS_ALLOWED_ACE {
ACE_HEADER Header;
ACCESS_MASK Mask;
DWORD SidStart;
} ACCESS_ALLOWED_ACE;*/
export const ACCESS_ALLOWED_ACL = struct({
Header:ACE_HEADER,
Mask:win32types.DWORD,
SidStart:win32types.DWORD
});
export const ACL = struct({
AclRevision:win32types.UCHAR,
Sbz1:win32types.UCHAR,
AclSize:win32types.USHORT,
AceCount:win32types.USHORT,
Sbz2:win32types.USHORT
});
/*
typedef struct _SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
SECURITY_DESCRIPTOR_CONTROL Control;
PSID Owner;
PSID Group;
PACL Sacl;
PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
**/
export const SECURITY_DESCRIPTOR = struct({
Revision:win32types.UCHAR,
Sbz1:win32types.UCHAR,
Control:win32types.WORD,
Owner:win32types.PVOID,
Group:win32types.PVOID,
Sacl:win32types.PVOID,
Dacl:win32types.PVOID
});
const PACL = ref.refType(ACL);
const PSECURITY_DESCRIPTOR = ref.refType(SECURITY_DESCRIPTOR);
const PACE = ref.refType(ACCESS_ALLOWED_ACL);
export const advApi = ffi.Library('Advapi32', {
/*
DWORD GetNamedSecurityInfoW(
LPCWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSID *ppsidOwner,
PSID *ppsidGroup,
PACL *ppDacl,
PACL *ppSacl,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
*/
GetNamedSecurityInfoW:[win32types.DWORD,[win32types.LPCTSTR,'int','uint', 'pointer', 'pointer', PACL, PACL, PSECURITY_DESCRIPTOR]],
/*
BOOL GetAce(
PACL pAcl,
DWORD dwAceIndex,
LPVOID *pAce);
*/
GetAce:[win32types.BOOL, [ACL, win32types.DWORD, ref.refType(PACE)]],
});
How the function is called:
import {advApi} from "../win32";
import {ACL as defACL, SECURITY_DESCRIPTOR as defSecDesc, ACCESS_ALLOWED_ACL as ace} from "../win32defs"
let dAclRef = new defACL().ref();
let securityDescriptorRef = new defSecDesc().ref();
let childPathBuffer = Buffer.from(newChild.path+'\0', 'ucs-2');
await advApi.GetNamedSecurityInfoW
.async(childPathBuffer, 1, 4, null, null, dAclRef, null, securityDescriptorRef,
(err, res) => {
if(err) throw err;
if(res === 0)
{
let aclValue = dAclRef.deref();
let i = 0;
let success = true;
while(i<aclValue.AceCount && success)
{
let aceRefRef = new ace().ref().ref();
success = advApi.GetAce(aclValue, i, aceRefRef);
if(success)
{
}
i++;
}
};
});
the returned ACL Struct contains wrong values, with AceCount > 500.
Finally I was able to retrieve the permissions (that wasn't dead easy).
Still I don't know why AceCount is that big.
Here some Code excerpts:
/*typedef struct _ACE_HEADER {
BYTE AceType;
BYTE AceFlags;
WORD AceSize;
} ACE_HEADER;*/
export const ACE_HEADER = struct({
AceType:win32types.UCHAR,
AceFlags:win32types.UCHAR,
AceSize:win32types.WORD
});
/*typedef struct _ACCESS_ALLOWED_ACE {
ACE_HEADER Header;
ACCESS_MASK Mask;
DWORD SidStart;
} ACCESS_ALLOWED_ACE;*/
export const ACCESS_ALLOWED_ACL = struct({
Header:ACE_HEADER,
Mask:win32types.DWORD,
SidStart:win32types.DWORD
});
export const ACL = struct({
AclRevision:win32types.UCHAR,
Sbz1:win32types.UCHAR,
AclSize:win32types.USHORT,
AceCount:win32types.USHORT,
Sbz2:win32types.USHORT
});
/*
typedef struct _SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
SECURITY_DESCRIPTOR_CONTROL Control;
PSID Owner;
PSID Group;
PACL Sacl;
PACL Dacl;
} SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;
**/
export const SECURITY_DESCRIPTOR = struct({
Revision:win32types.UCHAR,
Sbz1:win32types.UCHAR,
Control:win32types.WORD,
Owner:win32types.PVOID,
Group:win32types.PVOID,
Sacl:win32types.PVOID,
Dacl:win32types.PVOID
});
const PACL = ref.refType(ACL);
const PSECURITY_DESCRIPTOR = ref.refType(SECURITY_DESCRIPTOR);
const PACE = ref.refType(ACCESS_ALLOWED_ACL);
export const advApi = ffi.Library('Advapi32', {
/*
DWORD GetNamedSecurityInfoW(
LPCWSTR pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
PSID *ppsidOwner,
PSID *ppsidGroup,
PACL *ppDacl,
PACL *ppSacl,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
*/
GetNamedSecurityInfoW:[win32types.DWORD,[win32types.LPCTSTR,'int','uint', 'pointer', 'pointer', PACL, PACL, PSECURITY_DESCRIPTOR]],
/*
BOOL GetAce(
PACL pAcl,
DWORD dwAceIndex,
LPVOID *pAce);
*/
GetAce:[win32types.BOOL, [ACL, win32types.DWORD, ref.refType(PACE)]],
/*BOOL IsValidSid(
PSID pSid
)*/
IsValidSid:[win32types.BOOL, [win32types.LPVOID]],
/*BOOL LookupAccountSidW(
LPCWSTR lpSystemName,
PSID Sid,
LPWSTR Name,
LPDWORD cchName,
LPWSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName,
PSID_NAME_USE peUse
);*/
LookupAccountSidW:[win32types.BOOL, [win32types.LPCTSTR, win32types.LPVOID, win32types.LPCTSTR, win32types.LPDWORD, win32types.LPCTSTR, win32types.LPDWORD, ref.refType('int')]],
});
How the function is called. The important bit here is this one: let sidBuffer = ref.reinterpret(aceRef, 4, 8).
import {advApi} from "../win32";
import {ACL as defACL, SECURITY_DESCRIPTOR as defSecDesc, ACCESS_ALLOWED_ACL as ace} from "../win32defs"
let dAclRef = new defACL().ref();
let securityDescriptorRef = new defSecDesc().ref();
let childPathBuffer = Buffer.from(newChild.path+'\0', 'ucs-2');
await advApi.GetNamedSecurityInfoW
.async(childPathBuffer, 1, 4, null, null, dAclRef, null, securityDescriptorRef,
(err, res) => {
if(err) throw err;
if(res === 0)
{
let aclValue = dAclRef.deref();
let i = 0;
let success = true;
while(i<aclValue.AceCount && success)
{
let aceRefRef = new ace().ref().ref();
success = advApi.GetAce(aclValue, i, aceRefRef);
if(success)
{
let aceRef = aceRefRef.deref();
let sidBuffer = ref.reinterpret(aceRef, 4, 8);
if(advApi.IsValidSid(sidBuffer))
{
let cchNameRef = ref.alloc(win32types.DWORD, new Buffer(ref.sizeof.pointer));
let cchReferencedDomainNameRef = ref.alloc(win32types.DWORD, new Buffer(ref.sizeof.pointer));
let peUseRef = ref.alloc('int', new Buffer(ref.sizeof.pointer));
advApi.LookupAccountSidW(null, sidBuffer, null, cchNameRef, null, cchReferencedDomainNameRef, peUseRef);
let nameRef = Buffer.alloc(cchNameRef.deref()*2);
let domainNameRef = Buffer.alloc(cchReferencedDomainNameRef.deref()*2);
let accessArray = [];
if(advApi.LookupAccountSidW(null, sidBuffer, nameRef, cchNameRef, domainNameRef, cchReferencedDomainNameRef, peUseRef))
{
let aceValue = aceRef.deref();
...
}
}
}
i++;
}
};