Peter Laman wrote:
After some msdn searhing, I came up with the following to determine the
effective access rights on a file:

function CheckAccessRights(const UserName, Filename: string): ACCESS_MASK;
var
  DACL: PACL;
  SecDesc: PSECURITY_DESCRIPTOR;
  User: TRUSTEE;
  ActualUser: string;
begin
  DACL := nil;
  SecDesc := nil;
  Win32Check(GetNamedSecurityInfo(PChar(FileName), SE_FILE_OBJECT,
    DACL_SECURITY_INFORMATION,
    nil, nil, @DACL, nil, SecDesc) = ERROR_SUCCESS);
  try
    if Assigned(DACL) then
      begin
        FillChar(User, SizeOf(User), 0);
        User.MultipleTrusteeOperation := NO_MULTIPLE_TRUSTEE;
        User.TrusteeForm := TRUSTEE_IS_NAME;
        User.TrusteeType := TRUSTEE_IS_USER;
        if Length(UserName) > 0 then
          ActualUser := PChar(UserName)
        else
          ActualUser := PChar(LoggedOnUser);
        User.ptstrName := PChar(ActualUser);
        Win32Check(GetEffectiveRightsFromAcl(DACL^, User, Result) =
ERROR_SUCCESS);
      end
    else
      Result := 0;
  finally
    Win32Check(LocalFree(Cardinal(SecDesc)) = 0);
  end;
end;

The call to GetEffectiveRightsFromAcl(DACL^, User, Result) results in an
exception "System Error.  Code: 998. Invalid access to memory location".
What's going wrong here?

I tried your code, and it seems to work for me. I made two changes, which I don't think are relevant, but I'll describe them anyway. First, I had to type-cast "@DACL" in the first call since Borland misdeclared the function and you probably don't use the "typed @ operator" compiler option. Second, I did away with the LoggedOnUser stuff since I don't have that function and it's easier to test this function without worrying about what ActualUser is.

Perhaps the error message is wrong. When you pass a False value to Win32Check, it generates its error message based on the result from GetLastError. But the security functions say nothing about using GetLastError. Instead, they say their return values _are_ the error code.

Instead of Win32Check, try this:

procedure SecurityCheck(ErrCode: DWord);
begin
  if ErrCode <> Error_Success then RaiseLastOSError(ErrCode);
end;

If your version of Delphi doesn't have a one-argument RaiseLastOSError, then implement it like this:

procedure RaiseLastOSError(ErrCode: DWord);
begin
  SetLastError(ErrCode);
  SysUtils.RaiseLastOSError;
end;

None of this will actually fix the problem, but it might get you a more accurate error message, so diagnosing the problem might become easier.

--
Rob

__________________________________________________
Delphi-Talk mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi-talk

Reply via email to