Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

BuildExplicitAccessWithName

842 views
Skip to first unread message

Karsten

unread,
Aug 29, 2001, 6:22:50 AM8/29/01
to
After lot of reading and little understanding have I created this piece of
code.
What I want to do is to give administrators full access to a file and
everybody else read access.
So far I'm only trying to set one ACE.

When I run the code I get this error: Class does not exists
from BuildExplicitAccessWithName.
I Hope that someone knows a bit more about this than I do.

var
pDACL: PACL;
pEA: PEXPLICIT_ACCESS_A;
begin
//Create new ACE
pEA := AllocMem(SizeOf(EXPLICIT_ACCESS));
ZeroMemory(pEA, SizeOf(EXPLICIT_ACCESS));

BuildExplicitAccessWithName(pEA,
'EVERYONE',
GENERIC_READ,
GRANT_ACCESS, //SET_ACCESS ?
NO_INHERITANCE);
showmessage( SysErrorMessage(GetLastError) ); //gives me this message:
Class does not exists


//Create new ACL
PDACL := AllocMem(SizeOf(ACL));
SetEntriesInAcl(1,
pEA,
nil,
pDACL);
showmessage( SysErrorMessage(GetLastError) );


//Assign ACL to file
SetNamedSecurityInfo('c:\test.txt',
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
nil, //owner SID?
nil, //group SID?
pDACL,
nil);
showmessage( SysErrorMessage(GetLastError) );
end;


Marcel van Brakel

unread,
Aug 29, 2001, 7:02:05 AM8/29/01
to
> When I run the code I get this error: Class does not exists
> from BuildExplicitAccessWithName.
> I Hope that someone knows a bit more about this than I do.

BuildExplicitAccessWithName does _not_ set the last error code; it
simply always succeeds. The value returned by GetLastError is the value
that happened to be there all along. Try inserting a SetLastError(0)
before the call to BuildExplicitAccessWithName to see this in action.

best regards,
Marcel van Brakel

Project JEDI: http://delphi-jedi.org

Do not send me private e-mail unless explicitly requested otherwise.
If you do anyway please include a billing address...

Karsten

unread,
Aug 29, 2001, 8:36:57 AM8/29/01
to
You are right, I thought every API call sets a last error code.
Then everything seems fine until SetNamedSecurityInfo which returns
"An attempt was made to reference a token that does not exists"

What does this means, the file c:\test.txt is there for sure and the drive
is ntfs

Marcel van Brakel

unread,
Aug 29, 2001, 3:30:23 PM8/29/01
to
In article <3b8ce2d7_2@dnews>, gl...@mail.com says...

> You are right, I thought every API call sets a last error code.
> Then everything seems fine until SetNamedSecurityInfo which returns
> "An attempt was made to reference a token that does not exists"

Everything is not fine because it's not the SetNamedSecurityInfo
function that fails but SetEntriesInAcl. This is one function that does
return an error code. What you want to do is check the result of this
function before you continue to SetNamedSecurityInfo. Additionally, I
think you misunderstood the parameters of SetEntriesInAcl, specifically
the last one. You should not allocate memory for it because
SetEntriesInAcl does that for you (you should free afterwards). Here's a
corrected version of your code which functions correctly:

procedure TForm1.Button1Click(Sender: TObject);


var
pDACL: PACL;
pEA: PEXPLICIT_ACCESS_A;

R: DWORD;
begin
pEA := AllocMem(SizeOf(EXPLICIT_ACCESS));
BuildExplicitAccessWithName(pEA, 'EVERYONE', GENERIC_READ,
GRANT_ACCESS, NO_INHERITANCE);
R := SetEntriesInAcl(1, pEA, nil, pDACL);
if R = ERROR_SUCCESS then
begin
if SetNamedSecurityInfo('c:\test.txt', SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
nil, nil, pDACL, nil) <> ERROR_SUCCESS then
ShowMessage('SetNamedSecurityInfo failed: ' + SysErrorMessage
(GetLastError));
LocalFree(Cardinal(pDACL));
end
else ShowMessage('SetEntriesInAcl failed: ' + SysErrorMessage(R));
end;

PS AllocMem already sets the allocate memory buffer to all 0's so the
explicit call to ZeroMemory is redundant (which is why I removed it)!

Karsten

unread,
Aug 29, 2001, 7:09:57 PM8/29/01
to
Hey it works great! thank you very much!! :-)

I tried to play a bit around with it and when I inserts this line
showmessage( SysErrorMessage(GetLastError) );
after BuildExplicitAccessWithName, SetNamedSecurityInfo fails.

Can you explain that, I thought that GetLastError was a non destructive read
function, this is wrong when I read the Delphi help, that says the error
state is usual reset after reading.

But why does this mean anything ?
I tried to SetLastError(0) before the other two procedures to see if they
wanted a succesfull error code of the preceding procedure, but it stills
fails.


Marcel van Brakel

unread,
Aug 30, 2001, 2:13:56 AM8/30/01
to

GetLastError is a non destructive read function (you can verify by
looking at the assembler) and no API function should be dependent on the
last error value upon entry.

The problem here is that the initial buffer for
BuildExplicitAccessWithName is too small and corrupts the stack. This in
turn is caused by an incorrect declaration of the EXPLICIT_ACCESS
structure in AccCtrl.pas. The problem seems to ly in the fact that the
enumeration types such as ACCESS_MODE are supposed to be 4 bytes each,
but AccCtrl.pas fails to include the $Z4 directive to accomplish this.
Note that the fact that this didn't show earlier is pure luck. The call
to SysErrorMessage simply surfaces it but is otherwise unrelated (any
function that allocates memory probably would have surfaced the
problem).

I suggest you copy the AccCtrl.pas file into your project directory, add
it too the project and include te {$Z4} directive somewhere at the top
of this unit. After a rebuild the problem should be solved.
Alternatively, you could download my Win32 API conversion package from
http://delphi-jedi.org and use those instead.

Karsten

unread,
Aug 30, 2001, 6:25:58 AM8/30/01
to
Thank you again - good thing we have jedi :)


0 new messages