Regards,
Michiel
Some code that produces the error would help if you posted it. Normally you
get this error when you pass an invalid buffer, and a kernel-mode component
discovers that. It can't just raise an exception as user-mode code would do
in such a situation, because raising_exceptions_from_KM == BSOD. So it just
returns an error status to you. The following code will produce this error:
HANDLE h;
// open/create a file/pipe/etc for h
// so that h is valid handle now
DWORD bytes;
if( !ReadFile(h, (LPBYTE)13, 512, &bytes, 0) )
{
DWORD err = GetLastError();
}
--
Slava
Please send any replies to this newsgroup.
#define _WIN32_WINNT 0x0500
#define WINVER 0x0500
#include <windows.h>
#include <aclapi.h>
#include <stdio.h>
#include <iostream.h>
int main (int argc, char *argv[])
{
HANDLE hToken;
PRIVILEGE_SET psPrivilege;
GENERIC_MAPPING gmMapping;
DWORD dwGotLen, dwGrantedAccess = 0, dwPrivilegeLength = sizeof
(psPrivilege);
static byte buf[1024];
BOOL bAccessAllowed;
if ( ! ImpersonateSelf (SecurityImpersonation) )
{
printf ("ImpersonateSelf failed, error %lu\n", GetLastError());
return 1;
}
if ( ! OpenThreadToken(GetCurrentThread(),TOKEN_QUERY, TRUE, &hToken) )
{
printf ("OpenThreadToken failed, error %lu\n", GetLastError());
RevertToSelf();
return 1;
}
if ( ! GetFileSecurity (argv[1], DACL_SECURITY_INFORMATION,
(SECURITY_DESCRIPTOR *) &buf[0], sizeof buf, &dwGotLen))
{
printf ("GetFileSecurity() failed, error %lu\n", GetLastError());
CloseHandle (hToken);
return 1;
}
if ( ! AccessCheck ((SECURITY_DESCRIPTOR *) buf[0], hToken,
MAXIMUM_ALLOWED, &gmMapping, &psPrivilege, &dwPrivilegeLength,
&dwGrantedAccess, &bAccessAllowed) )
{
printf ("AccessCheck failed, error %lu\n", GetLastError());
RevertToSelf();
CloseHandle (hToken);
return 1;
}
if ( bAccessAllowed == FALSE && ERROR_ACCESS_DENIED != GetLastError() )
{
printf ("Internal error Access Check, error %lu\n", GetLastError());
RevertToSelf();
CloseHandle (hToken);
return 1;
}
if ( bAccessAllowed == FALSE && ERROR_ACCESS_DENIED == GetLastError() )
{
printf ("Access denied to file or directory.");
}
if ( bAccessAllowed == TRUE )
{
printf ("Access allowed to file or directory.");
}
RevertToSelf();
CloseHandle (hToken);
return 0;
}
Regards,
Michiel
Slava M. Usov <stripit...@usa.net> wrote in message
news:OiXyZlCt#GA.238@cppssbbsa03...
> if ( ! AccessCheck ((SECURITY_DESCRIPTOR *) buf[0], hToken,
> MAXIMUM_ALLOWED, &gmMapping, &psPrivilege, &dwPrivilegeLength,
> &dwGrantedAccess, &bAccessAllowed) )
> {
> printf ("AccessCheck failed, error %lu\n", GetLastError());
> RevertToSelf();
> CloseHandle (hToken);
> return 1;
> }
>
>
> if ( bAccessAllowed == FALSE && ERROR_ACCESS_DENIED != GetLastError() )
You shouldn't call GetLastError() when AccessCheck() returns TRUE.
GetLastError() is only reliable when the API fails, but it is not the case.
AccessCheck() returns !FALSE, and the result of GetLastError() is totally
bogus.
Other than that, your code is incomplete: you should prepare GENERIC_MAPPING
structure before passing it to AccessCheck(). It's *your* responsibility to
tell AccessCheck() how generic rights map to standard and specific ones;
AccessCheck() has no way to learn it otherwise...
P.S. What was the reason for calling ImpersonateSelf()?
> > if ( ! AccessCheck ((SECURITY_DESCRIPTOR *) buf[0], hToken,
> > MAXIMUM_ALLOWED, &gmMapping, &psPrivilege, &dwPrivilegeLength,
> > &dwGrantedAccess, &bAccessAllowed) )
> > {
> > printf ("AccessCheck failed, error %lu\n", GetLastError());
> > RevertToSelf();
> > CloseHandle (hToken);
> > return 1;
> > }
> >
> >
> > if ( bAccessAllowed == FALSE && ERROR_ACCESS_DENIED != GetLastError() )
>
> You shouldn't call GetLastError() when AccessCheck() returns TRUE.
> GetLastError() is only reliable when the API fails, but it is not the
case.
> AccessCheck() returns !FALSE, and the result of GetLastError() is totally
> bogus.
Yes, I have to, because otherwise the function will always return FALSE, but
not because of having no access rights!
>
> Other than that, your code is incomplete: you should prepare
GENERIC_MAPPING
> structure before passing it to AccessCheck(). It's *your* responsibility
to
> tell AccessCheck() how generic rights map to standard and specific ones;
> AccessCheck() has no way to learn it otherwise...
That's strange, because I use a sample code which uses AccessCheck in this
way (from the book Windows NT Security by Nik Okuntseff). And the sample
does work! Also other samples use it this way.
> P.S. What was the reason for calling ImpersonateSelf()?
>
When I don't use it, the program stops with the error message that there
'was an attempt made to a token that doesn't exist'. because of lack of
literature, I have to base on the samples I have. Most samples use
ImpersonateSelf and OpenThreadToken to get the user SID (in hToken).
Michiel
> Yes, I have to [call GLE()]
I'm sorry, but Slava is correct. If AccessCheck() returns TRUE, the
value of GetLastError() is unreliable. if bAccessAllowed is FALSE after
a successful call to AccessCheck(), then access is denied, period.
> That's strange, because I use a sample code which uses AccessCheck in this
> way (from the book Windows NT Security by Nik Okuntseff).
The problem is that the author didn't understand how generic mappings
work, and he attempted to apply makeup to the problem instead of saying
outright that he was uncertain.
Your code will fail if I check for GENERIC_READ access. Why? because
GENERIC_READ is supposed to be shorthand for a specific combination of
"normal" permissions ("specific" ones). The GENERIC_MAPPING structure
tells AccessCheck() which bits to _really_ look at when someone asks for
GENERIC_READ (or any other GENERIC_something). If you were looking at
the ACL for a file, for instance, your GENERIC_MAPPING struct would be
GENERIC_MAPPING gm = {
// FILE_GENERIC_READ, see WINNT.H
STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES |
FILE_READ_EA | SYNCHRONIZE,
// FILE_GENERIC_WRITE
STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE,
// FILE_GENERIC_EXECUTE
STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE |
SYNCHRONIZE,
// FILE_GENERIC_ALL
FILE_ALL_ACCESS
};
> When I don't use [ImpersonateSelf{}], the program stops with the
> error message that there 'was an attempt made to a token that
> doesn't exist'.
Ah. I usually fall back on OpenProcessToken() in that case.
--
Cheers,
Felix.
If you post a reply, kindly refrain from emailing it, too.
Note to spammers: fel...@mvps.org is my real email address.
No anti-spam address here. Just one comment: IN YOUR FACE!
Michael,
> > You shouldn't call GetLastError() when AccessCheck() returns TRUE.
> > GetLastError() is only reliable when the API fails, but it is not the
> case.
> > AccessCheck() returns !FALSE, and the result of GetLastError() is
totally
> > bogus.
>
> Yes, I have to, because otherwise the function will always return FALSE,
but
> not because of having no access rights!
Nothing to add to Felix's comments.
And I've found a bug in your code: you're calling
AccessCheck((SECURITY_DESCRIPTOR*)buf[0], ... )
While you should
AccessCheck((SECURITY_DESCRIPTOR*)&buf[0], ... )
or
AccessCheck((SECURITY_DESCRIPTOR*)buf, ... )
I.e., you're *not* passing the *address* of the descriptor, but the value of
its very first byte.
> That's strange, because I use a sample code which uses AccessCheck in this
> way (from the book Windows NT Security by Nik Okuntseff). And the sample
> does work! Also other samples use it this way.
Again, refer to Felix's comments. (Just a side note: Don't trust *that* much
to authors of *books*; browse the SDK articles instead).
> I'm sorry, but Slava is correct. If AccessCheck() returns TRUE, the
> value of GetLastError() is unreliable. if bAccessAllowed is FALSE after
> a successful call to AccessCheck(), then access is denied, period.
>
I'm sorry Slava, but I trusted too much on the author of the book. Now I
know better :-)
> Your code will fail if I check for GENERIC_READ access. Why? because
> GENERIC_READ is supposed to be shorthand for a specific combination of
> "normal" permissions ("specific" ones). The GENERIC_MAPPING structure
> tells AccessCheck() which bits to _really_ look at when someone asks for
> GENERIC_READ (or any other GENERIC_something). If you were looking at
> the ACL for a file, for instance, your GENERIC_MAPPING struct would be
>
> GENERIC_MAPPING gm = {
> // FILE_GENERIC_READ, see WINNT.H
> STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES |
> FILE_READ_EA | SYNCHRONIZE,
> // FILE_GENERIC_WRITE
> STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES |
> FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE,
> // FILE_GENERIC_EXECUTE
> STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE |
> SYNCHRONIZE,
> // FILE_GENERIC_ALL
> FILE_ALL_ACCESS
> };
>
Ah I see, but I don't see how to use it. Because AccessCheck aks for a
PGENERIC_MAPPING instead of a GENERIC_MAPPING. Do I also need the function
MapGenericMask or can I use MAXIMUM_ALLOWED as value for parameter 3 of
AccessCheck.
> > When I don't use [ImpersonateSelf{}], the program stops with the
> > error message that there 'was an attempt made to a token that
> > doesn't exist'.
>
> Ah. I usually fall back on OpenProcessToken() in that case.
>
Gives also problems, right now I receive error message 1309 (...attempt made
to operate on an impersonation token by a thread that is not currently
impersonating a client) when AccessCheck is processed.
Michiel
> Ah I see, but I don't see how to use it. Because AccessCheck aks for a
> PGENERIC_MAPPING instead of a GENERIC_MAPPING. Do I also need the function
> MapGenericMask or can I use MAXIMUM_ALLOWED as value for parameter 3 of
> AccessCheck.
Michael,
please do lookup the article on AccessCheck() in the Platform SDK. Read
carefully about the third parameter (DesiredAccess) and the fourth one
(GenericMapping). Also, reading the *second" sentence from the very
beginning of the article might help. OK, I'll paste it here:
"Typically, server applications use this function to check access to a
private object."
The keyword is "server applications". Clients just does not usually have
enough knowledge on the ultimate bits and pieces of how generic righst map
into the stndard and the specific ones. Even if you can find how NTFS
generic rights map into the standard & specific, this may be misleading for
your application, for the following two reasons.
1. The NTFS may evolve - you'll have to modify your app.
2. The file that you're checking access to may reside on a filesystem other
than NTFS (some networked drive - NFS for example, etc.) - you'll be getting
wrong results, as, naturally, the specific rights does not have to equal to
those of NTFS.
The bottom line is: don't use AccessCheck() for checking access to objects
that you know nothing about. Just impersonate the client, and perform
CreateFile() - if this fails with error code 0x5, the access was denied.
> Gives also problems, right now I receive error message 1309 (...attempt
made
> to operate on an impersonation token by a thread that is not currently
> impersonating a client) when AccessCheck is processed.
Huh? I guess you should be using something similar to
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token);
....
// psd is the pointer to the sec. descriptor
AccessCheck(psd, token, ... );
What's your actual code look like?