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

Win 32 Error Code nr. 998

306 views
Skip to first unread message

Michiel Bom

unread,
Jun 11, 1999, 3:00:00 AM6/11/99
to
Can someone explain code 998 to me (invalid access to memory allocation) and
/ or tell me how to solve this?

Regards,

Michiel


Slava M. Usov

unread,
Jun 11, 1999, 3:00:00 AM6/11/99
to

Michiel Bom <mbom@_NO_SPAM_jungle.bt.co.uk> wrote in message
news:7jqrfd$hra$1...@pheidippides.axion.bt.co.uk...

> Can someone explain code 998 to me (invalid access to memory allocation)
and
> / or tell me how to solve this?

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.


Michiel Bom

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to
Here's the code you asked for, it's quite similar to examples, which I've
found at MSDN:

#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...

Slava M. Usov

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to

Michiel Bom <mbom@_NO_SPAM_jungle.bt.co.uk> wrote in message
news:7k2isk$o1r$1...@pheidippides.axion.bt.co.uk...

> 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()?

Michiel Bom

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to
Hi Slava,

> > 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

Michiel Bom

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to

Felix Kasza [MVP]

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to
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!

Slava M. Usov

unread,
Jun 14, 1999, 3:00:00 AM6/14/99
to

Michiel Bom <mbom@_NO_SPAM_jungle.bt.co.uk> wrote in message
news:7k2o7n$rhd$1...@pheidippides.axion.bt.co.uk...

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).

Michiel Bom

unread,
Jun 15, 1999, 3:00:00 AM6/15/99
to
Hello Felix and Slava,


> 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


Michiel Bom

unread,
Jun 15, 1999, 3:00:00 AM6/15/99
to

Slava M. Usov

unread,
Jun 15, 1999, 3:00:00 AM6/15/99
to

Michiel Bom <mbom@_NO_SPAM_jungle.bt.co.uk> wrote in message
news:7k53jv$78p$1...@pheidippides.axion.bt.co.uk...

> 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?

0 new messages