Solved

Delphi7 SetEntriesInAcl Error 87

Posted on 2010-08-19
16
1,889 Views
Last Modified: 2012-05-10
Hi all.
For several day I try to set new permissions to file in Windows 7 / XP. (Allow All to Everyone)
I do it in Delphi 7.

In theory - everything is not so difficult:
const
 SECURITY_WORLD_SID_AUTHORITY: SID_IDENTIFIER_AUTHORITY = (Value: (0, 0, 0, 0, 0, 1));
 SECURITY_WORLD_RID = $0;
var
 ExplicitAccess: EXPLICIT_ACCESS_A;
 psidEveryOne: PSID;
 pSD: PSECURITY_DESCRIPTOR;
 ptACL: PACL;
 ErrNo: Cardinal;
begin
 psidEveryOne := nil;
 pSD := nil;
 ptACL := nil;
 try
   win32check(AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY,
     1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, psidEveryone));

   try
     ZeroMemory(@ExplicitAccess, SizeOf(ExplicitAccess));
     with ExplicitAccess do
     begin
       grfAccessPermissions:= GENERIC_ALL;
       grfAccessMode:= GRANT_ACCESS;
       grfInheritance:= NO_INHERITANCE;
       Trustee.TrusteeForm:= TRUSTEE_IS_SID;
       Trustee.TrusteeType:= TRUSTEE_IS_WELL_KNOWN_GROUP;
       Trustee.ptstrName:= psidEveryone;
     end;
     
     ErrNo := SetEntriesInAcl(1, @ExplicitAccess, nil, ptACL);
     if ErrNo <> ERROR_SUCCESS then
       raise Exception.Create(Format('Error ¿ %u', [ErrNo]))
     // And so on....

Open in new window


But, function SetEntriesInAcl always return 87 error (ERROR_INVALID_PARAMETER).
Can anybody say to me what am i doing wrong?

P.S. This code perfectly works on Delphi 2010 without any errors. But I need to make it work in Delphi 7
0
Comment
Question by:ZeBriD
  • 6
  • 5
  • 4
16 Comments
 
LVL 13

Accepted Solution

by:
aflarin earned 250 total points
ID: 33475668
the size of EXPLICIT_ACCESS_A is 24, but it must be 32.

the problem happens because the delphi's enumeration type (ACCESS_MODE, TRUSTEE_FORM, TRUSTEE_TYPE) generates only one byte instead of 4.

What you can do. Copy Delphi7\Source\Rtl\Win\AccCtrl.pas to your project folder and rename it (to AccCtrl2.pas for example), then add {$MINENUMSIZE 4} to its header:

unit AccCtrl2;

{$WEAKPACKAGEUNIT}
{$MINENUMSIZE 4} <---------------------------------- this line

Don't forget to change AccCtrl to AccCtrl2 in your uses sections. Make sure that SizeOf(ExplicitAccess) is 32 now.

If it works, you can compile new version of AccCtrl and replace previous version into Delphi\Lib and Delphi\Lib\Debug dirs
0
 
LVL 9

Expert Comment

by:sas13
ID: 33476590
its working code from my defrager


// do this before
function TDefrag.LoadPrivelege: boolean;
var
  _token_handle: THandle;
  _priv: TTokenPrivileges;
begin
 Result := false;
 if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, _token_handle) then begin
  if LookupPrivilegeValue(nil, PChar('SeTakeOwnershipPrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeManageVolumePrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeSecurityPrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeBackupPrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeCreatePagefilePrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  if LookupPrivilegeValue(nil, PChar('SeShutdownPrivilege'), _priv.Privileges[0].Luid) then begin
   _priv.PrivilegeCount := 1;
   _priv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
   Result := AdjustTokenPrivileges(_token_handle, false, _priv, 0, PTokenPrivileges(nil)^, PDWord(nil)^)
  end;
  CloseHandle(_token_handle)
 end
end;

function TDefrDrive.TakeOwnership(const APath: PAnsiChar): boolean;
var
  _ea: EXPLICIT_ACCESS;
  _old_ACL: PACL;
  _new_ACL: PACL;
  _sd: pointer;
  _err: cardinal;
begin
 Result := false;      
 if GetNamedSecurityInfo(APath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, @_old_ACL, nil, _sd) = ERROR_SUCCESS then begin
  ZeroMemory(@_ea, SizeOf(EXPLICIT_ACCESS));
  _ea.grfAccessPermissions := GENERIC_ALL;
  _ea.grfAccessMode := SET_ACCESS;
  _ea.grfInheritance := SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  _ea.Trustee.TrusteeForm := TRUSTEE_IS_NAME;
  _ea.Trustee.TrusteeType := TRUSTEE_IS_USER;
  _ea.Trustee.ptstrName := 'CURRENT_USER';
  _new_ACL := nil;
  _err := SetEntriesInAcl(1, @_ea, _old_ACL, _new_ACL);
  if _err = ERROR_SUCCESS then begin
   Result := SetNamedSecurityInfo(APath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, _new_ACL, nil) = ERROR_SUCCESS;
   LocalFree(cardinal(_new_ACL));
  end;
  LocalFree(cardinal(_sd))
 end
end;

Open in new window

0
 

Author Comment

by:ZeBriD
ID: 33481910
>{$MINENUMSIZE 4} <---------------------------------- this line
Already tried. Still not working.
0
Easy, flexible multimedia distribution & control

Coming soon!  Ideal for large-scale A/V applications, ATEN's VM3200 Modular Matrix Switch is an all-in-one solution that simplifies video wall integration. Easily customize display layouts to see what you want, how you want it in 4k.

 
LVL 13

Expert Comment

by:aflarin
ID: 33482406
>> Already tried. Still not working.

I've checked it under D7.  It works.

Make sure that SizeOf(ExplicitAccess) is 32.
0
 
LVL 9

Assisted Solution

by:sas13
sas13 earned 250 total points
ID: 33482957
modules AccAPI.pas & AccCtrl.pas attached.
they worked in Delphi 7
AclAPI.zip
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33483011
>> modules AccAPI.pas & AccCtrl.pas attached.

sas31, there is no sense to add {$MINENUMSIZE 4} to AccAPI, because there is not any enumeration type there.
0
 

Author Comment

by:ZeBriD
ID: 33508863
>Make sure that SizeOf(ExplicitAccess) is 32.
Checked. It is 32.

>modules AccAPI.pas & AccCtrl.pas attached
I've tried use your units. Now there is no error.
BUT now there is no access rights (look at image bellow. it is in russian, but I hope you will understand the error)
dLjX2Maj31.png
0
 
LVL 9

Expert Comment

by:sas13
ID: 33508908
where is function "SetNamedSecurityInfo" which set security object  ptACL after call "SetEntriesInAcl"?

see may example above (function "TakeOwnership").
0
 

Author Comment

by:ZeBriD
ID: 33509178
Well... I set permissions to crypto container.
Full current code in attach.
const
  SECURITY_WORLD_SID_AUTHORITY: SID_IDENTIFIER_AUTHORITY = (Value: (0, 0, 0, 0, 0, 1));
  SECURITY_WORLD_RID = $0;

var
  ExplicitAccess: EXPLICIT_ACCESS;
  psidEveryOne: PSID;
  pSD: PSECURITY_DESCRIPTOR;
  ptACL: PACL;
  ErrFunc: String;
  ErrNo: Cardinal;
  lpName,lpDomain : PAnsiChar;
  cbName,cbDomain : Cardinal;
  peUse : Cardinal;
begin
  psidEveryOne := nil;
  pSD := nil;
  ptACL := nil;
  try

    win32check(AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY,
      1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, psidEveryone));

    cbName:=64;
    cbDomain:=64;

    GetMem(lpName,cbName*SizeOf(WideChar));
    GetMem(lpDomain,cbDomain*SizeOf(WideChar));

    if not LookupAccountSid(nil, psidEveryOne, lpName, cbName, lpDomain, cbDomain, peUse)
       and (GetLastError=122) then
    begin

      ReAllocMem(lpName,cbName*SizeOf(WideChar));
      ReAllocMem(lpDomain,cbDomain*SizeOf(WideChar));

      if not LookupAccountSid(nil, psidEveryOne, lpName, cbName, lpDomain, cbDomain, peUse) then
        raise Exception.Create(SysErrorMessage(GetLastError));
    end;

    ZeroMemory(@ExplicitAccess, SizeOf(ExplicitAccess));
     //BuildExplicitAccessWithNameW(@ExplicitAccess, PAnsiChar(WideCharToString(lpName)), GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);
    BuildExplicitAccessWithName(@ExplicitAccess, lpName, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);

    try
      ErrNo := SetEntriesInAcl(1, @ExplicitAccess, nil, ptACL);
      if ErrNo <> ERROR_SUCCESS then
        raise Exception.Create(Format('SetEntriesInAcl error: %s', [SysErrorMessage(ErrNo)]));

      try
        pSD:= Pointer(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
        try
          win32check(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
          win32check(SetSecurityDescriptorDacl(pSD, false, ptACL, false));
          win32check(CryptSetProvParam(AhProv, PP_KEYSET_SEC_DESCR, pSD, DACL_SECURITY_INFORMATION));
        finally
          LocalFree(Cardinal(pSD));
        end;
      finally
        LocalFree(Cardinal(ptACL));
      end;
    finally
      FreeSid(psidEveryOne);
    end;

Open in new window

0
 

Author Comment

by:ZeBriD
ID: 33509198
I've tryed to create ExplicitAccess by two ways:

BuildExplicitAccessWithName(@ExplicitAccess, lpName, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);

and

with ExplicitAccess do
begin
  grfAccessPermissions := GENERIC_ALL;
  grfAccessMode := SET_ACCESS;
  grfInheritance := NO_INHERITANCE;
  Trustee.TrusteeForm := TRUSTEE_IS_SID;
  Trustee.TrusteeType := TRUSTEE_IS_GROUP;
  Trustee.ptstrName := psidEveryone;
end;
0
 
LVL 9

Expert Comment

by:sas13
ID: 33509287
sorry, i didnt work with crypto containers.
i can expect what problem might be in "CryptSetProvParam" function, may be some parameter is invalid or something else.
try to change some parameters...
may be AhProv opened with restrictions to change security...
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33509312
>>modules AccAPI.pas & AccCtrl.pas attached
>I've tried use your units. Now there is no error.

It's interesting. Those are the Delphi's unit with {$MINENUMSIZE 4} added. But as I said before there is no sense to add {$MINENUMSIZE 4} to AccAPI.
0
 
LVL 13

Expert Comment

by:aflarin
ID: 33509381
btw, It would be better to ask one question per thread
http://www.experts-exchange.com/help.jsp#hs=23&hi=23
0
 

Author Comment

by:ZeBriD
ID: 33509577
yippee
It's work. Error was in func SetSecurityDescriptorDacl(pSD, false, ptACL, false).
Second parametr needs to be 'true'.
So, what was done.

Since the user can use not only in eng windows version, user group named 'Everyone' may be called differently, such as '¿¿¿' for russian version. But the SID of the group is always the same. Thats why I get SID at first. Then, using the function LookupAccountSid I get the name of this group. And only then, with the name of group 'Everyone', I create object ExplicitAccess and set these new rights to crypto-container.
I attached the working code below.
Thanks everyone.
procedure TInetSession.SetProvPermiss(AhProv: HCRYPTPROV);
const
  SECURITY_WORLD_SID_AUTHORITY: SID_IDENTIFIER_AUTHORITY = (Value: (0, 0, 0, 0, 0, 1));
  SECURITY_WORLD_RID = $0;

var
  ExplicitAccess: EXPLICIT_ACCESS;
  psidEveryOne: PSID;
  pSD: PSECURITY_DESCRIPTOR;
  ptACL: PACL;
  ErrNo: Cardinal;
  lpName,lpDomain : PAnsiChar;
  cbName,cbDomain : Cardinal;
  peUse : Cardinal;
begin
  psidEveryOne := nil;
  pSD := nil;
  ptACL := nil;
  cbName := 0;
  cbDomain := 0;

  try
    win32check(AllocateAndInitializeSid(SECURITY_WORLD_SID_AUTHORITY,
      1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, psidEveryone));

    LookupAccountSid(nil, psidEveryOne, nil, cbName, nil, cbDomain, peUse);
    GetMem(lpName,cbName*SizeOf(WideChar));
    GetMem(lpDomain,cbDomain*SizeOf(WideChar));
    try
      win32check(LookupAccountSid(nil, psidEveryOne, lpName, cbName, lpDomain, cbDomain, peUse));
    finally
      FreeMem(lpName);
      FreeMem(lpDomain);
    end;

    ZeroMemory(@ExplicitAccess, SizeOf(ExplicitAccess));
    BuildExplicitAccessWithName(@ExplicitAccess, lpName, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);

    try
      ErrFunc := 'SetEntriesInAcl';
      ErrNo := SetEntriesInAcl(1, @ExplicitAccess, nil, ptACL);
      if ErrNo <> ERROR_SUCCESS then
        raise Exception.Create(Format('System Error.  Code: %u'#13#10'%s', [ErrNo, SysErrorMessage(ErrNo)]));

      try
        pSD:= Pointer(LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
        try
          win32check(InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION));
          win32check(SetSecurityDescriptorDacl(pSD, true, ptACL, false));
          win32check(CryptSetProvParam(AhProv, PP_KEYSET_SEC_DESCR, pSD, DACL_SECURITY_INFORMATION));
        finally
          LocalFree(Cardinal(pSD));
        end;
      finally
        LocalFree(Cardinal(ptACL));
      end;
    finally
      FreeSid(psidEveryOne);
    end;
  except
    on E: Exception do
    begin
      do something...
      Exit;
    end;
  end;
end;

Open in new window

0
 

Author Closing Comment

by:ZeBriD
ID: 33509616
Only one problem was solved by experts.
Second I solved by my self.
0

Featured Post

Easy, flexible multimedia distribution & control

Coming soon!  Ideal for large-scale A/V applications, ATEN's VM3200 Modular Matrix Switch is an all-in-one solution that simplifies video wall integration. Easily customize display layouts to see what you want, how you want it in 4k.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you get continual lockouts after changing your Active Directory password, there are several possible reasons.  Two of the most common are using other devices to access your email and stored passwords in the credential manager of windows.
Learn how to PXE Boot both BIOS & UEFI machines with DHCP Policies and Custom Vendor Classes
Windows 8 comes with a dramatically different user interface known as Metro. Notably missing from the new interface is a Start button and Start Menu. Many users do not like it, much preferring the interface of earlier versions — Windows 7, Windows X…
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…

808 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question