我前几天因工作原因需编写一个检查用户对NTFS分区下的文件夹访问权限的程序,其中有一个核心函数是判断指定的用户是否对指定的文件夹拥有访问权限,我最初是用Delphi编写以便利用其强大的组件。该函数代码如下:
type
ACE_HEADER=record
AceType:Byte;
AceFlags:Byte;
AceSize:Word;
end;
ACCESS_ALLOWED_ACE=record
Header:ACE_HEADER;
Mask:ACCESS_MASK;
SidStart:DWORD;
end;
ACL_SIZE_INFORMATION=record
AceCount:DWORD;
AclBytesInUse:DWORD;
AclBytesFree:DWORD;
end;
//...
function HasRight(UserName:String;FileName:String):Boolean;
var
snuType:SID_NAME_USE;
szDomai:PChar;
cbDomain:DWORD;
pUserSID:Pointer;
cbUserSID:DWORD;
pFileSD:PSECURITY_DESCRIPTOR;
cbFileSD:DWORD;
p_ACL:PACL;
fDaclPresent,fDaclDefaulted:LongBool;
AclInfo:ACL_SIZE_INFORMATION;
pTempAce:Pointer;
TempAce:ACCESS_ALLOWED_ACE;
CurrentAceIndex:Cardinal;
ReturnValue:LongBool;
begin
//初始化各个变量
Result:=False;
szDomain:=nil;
cbDomain:=0;
pUserSID:=nil;
cbUserSID:=0;
pFileSD:=nil;
cbFileSD:=0;
p_ACL:=nil;
pTempAce:=nil;
//第一次调用得到SID和Domain的大小
ReturnValue:=LookupAccountName(nil,PChar(UserName),pUserSID,cbUserSID,szDomain,cbDomain,snuType);
if (not ReturnValue) and (GetLastError<>ERROR_INSUFFICIENT_BUFFER) then RaiseLastOSError;
pUserSID:=AllocMem(cbUserSID);
szDomain:=AllocMem(cbDomain);
try
//第二次正式调用以取得用户的SID
ReturnValue:=LookupAccountName(nil,PChar(UserName),pUserSID,cbUserSID,szDomain,cbDomain,snuType);
if (not ReturnValue) then RaiseLastOSError;
//用类似的方法得指定文件的安全描述符
ReturnValue:=GetFileSecurity(PChar(FileName),DACL_SECURITY_INFORMATION,pFileSD,0,cbFileSD);
if (not ReturnValue) and (GetLastError<>ERROR_INSUFFICIENT_BUFFER) then RaiseLastOSError;
pFileSD:=AllocMem(cbFileSD);
ReturnValue:=GetFileSecurity(PChar(FileName),DACL_SECURITY_INFORMATION,pFileSD,cbFileSD,cbFileSD);
if (not ReturnValue) then RaiseLastOSError;
//从安全描述符中得到安全对象的访问控制列表
if (not GetSecurityDescriptorDacl(pFileSD,fDaclPresent,p_ACL,fDaclDefaulted)) then RaiseLastOSError;
AclInfo.AceCount:=0;
AclInfo.AclBytesFree:=0;
AclInfo.AclBytesInUse:=SizeOf(ACL);
if (fDaclPresent and Assigned(p_ACL)) then
begin
//取得访问控制列表的大小信息
if (not GetAclInformation(p_ACL^,@AclInfo,SizeOf(ACL_SIZE_INFORMATION),AclSizeInformation)) then RaiseLastOSError;
if (fDaclPresent and (AclInfo.AceCount>0)) then
begin
//循环访问控制列表,并判断是否包含指定的用户
for CurrentAceIndex:=0 to AclInfo.AceCount-1 do
begin
if (not GetAce(p_ACL^,CurrentAceIndex,pTempAce)) then RaiseLastOSError;
TempAce:=ACCESS_ALLOWED_ACE(pTempAce^);
//EqualSid用于比较两个SID是否相等,但问题是在此处这个函数的返回值总是为False
//如果改为C++版本,此处用以下语句时则能正确返回结果
//if (EqualSid(pUserSID,&(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart))) break;
if EqualSid(pUserSId,@(TempAce.SidStart)) then break;
end;
FreeSid(pUserSId);
//如果找到则设置函数返回值为True
if CurrentAceIndex<AclInfo.AceCount then Result:=True;
end;
end;
finally
//释放动态分配的存储空间,比较奇怪是释放其它几个指针时会出现运行时异常
if pUserSID<>nil then FreeMem(pUserSID);
if szDomain<>nil then FreeMem(szDomain);
end;
end;
但调用该函数时始终达不到目的,我在注释中已经指明:在Delphi代码中EqualSid函数无法返回预期的结果,但用C++语言来编写就能正确运行,盼各位大侠指点迷津!谢谢!