Why is there a GENERIC_MAPPING parameter to the AccessCheck API?

Ok, back to techie stuff. I recently received the following piece of mail sent to an internal mailing list:

How is GenericMapping used by AccessCheck function?

I thought it would be used to map GENERIC_XXX rights in the ACEs contained by the security descriptor passed, but it seems that I'm wrong.

It seems that the ACEs in the SD need to have the specific rights, otherwise the validation would fail.

If the SD contains specific rights and DesiredAccess parameter also contains specific rights what's the purpose of GenericMapping parameter?

It’s a good question, and makes a good follow up to my AccessCheck posts last week.

The answer is subtle (really subtle). 

The contract for the AccessCheck API specifies that if you’re requesting the MAXIMUM_ALLOWED DesiredAccess to the resource, then on return, the DWORD pointed to by the GrantedAccess parameter will contain the access rights granted.

So what happens if the pSecurityDescriptor parameter passed into the AccessCheck API specifies an object with a NULL DACL?  Remember a NULL DACL grants full access to the object, which means that the caller has every right that they could possibly be granted.  Ordinarily, in the presence of a DACL, the MAXIMUM_ALLOWED access rights can be easily calculated – you just enable all the bits in the ACEs that apply to the user and you’re done.  But in this case,  there’s no DACL on the object.  Since there’s no ACL to collect the requestor’s rights, those have to come from somewhere else.  And that somewhere else happens to be the GenericMapping parameter passed into the API.

If you call AccessCheck requesting MAXIMUM_ALLOWED access rights, and you’re security descriptor has a NULL DACL, then in addition to the rights you may have been previously granted (WRITE_DAC, for example if you’re the object’s owner), all the access rights in the GENERIC_MAPPING->GenericAll field are also granted to the user.