Why is AccessCheck NOT applying GenericMapping to the DACL? - winapi

The AccessCheck function gets a GenericMapping parameter. What is this parameter used for? It is NOT used for the DesiredAccess parameter since MapGenericMask must be applied to DesiredAccess before.
It is also not applied to the DACL contained in the SecurityDescriptor as I found out using a C program doing this:
open the current thread token
create a security descriptor with owner and default group from the token and an DACL granting GENERIC_ALL to the owner "D:(A;;GA;;;ownerSID)"
setup GENERIC_MAPPING, which maps (among others) GenericAll to my OWN_READ | OWN_WRITE (defined as 0x0001 and 0x0002)
call AccessCheck with security descriptor created above, the thread token, OWN_READ as DesiredAccess, the described GENERIC_MAPPING
However, this fails with an access denied error. When I change the security descriptor to "D:(A;;0x0001;;;ownerSID)" access is granted. This shows that AccessCheck is NOT using the GenericMapping parameter to convert generic access flags (GA/GW/GR/GX) in the DACL to the specific access rights. Why? Am I doing something wrong?
https://msdn.microsoft.com/de-de/library/windows/desktop/aa374815(v=vs.85).aspx does not give any hints on how the security descriptor should be set.

you do almost all correct, but you not take in account that when you try assign security descriptor(SD) to kernel object - system not exactly "as is" assigned your SD but apply GenericMapping to ACEs first.
every object - have assosiated _OBJECT_TYPE which containing _OBJECT_TYPE_INITIALIZER and here exist GENERIC_MAPPING GenericMapping; and this GenericMapping (unique for each type of object) used for convert you generic flags in ACCESS_MASK to non-generic.
for test i create file with next SD - "D:P(A;;GA;;;WD)" (10000000 - GenericAll for S-1-1-0 EveryOne). and then i query DACL from created file - and see really 001F01FF for S-1-1-0 but not 10000000.
when i use "D:P(A;;GX;;;WD)" (GenericExecute - 20000000 for S-1-1-0) - in final file i view 001200A0 for S-1-1-0
so real kernel object have no generic bits in ACCESS_MASK and your DACL in exactly form you cannot assign to any object.
Why is AccessCheck NOT applying GenericMapping to the DACL?
AccessCheck assume that ACCESS_MASK in DACL already converted (no generic bits)
i think this is performance optimization - better convert generic bits once (on object creating or assigning SD to it - than every time do this convertation when somebody try open object)
about how GenericMapping parameter used ?
really very weak - only in case when object have no DACL (or if PreviousMode == KernelMode) and you request MAXIMUM_ALLOWED as DesiredAccess - system grant you GenericMapping->GenericAll. this is based on looking source code from WRK (accessck.c)
no DACL and MAXIMUM_ALLOWED this is rare case, but in this case how system can calculate what concrete access need grant to caller ? he not ask concrete access (like read/write/delete) - but "ALL". so system and give him GenericMapping->GenericAll

Related

Best way to get the connected network domain name in Windows

I would like to find out whether the local Windows system is connected to a network domain (instead of a workgroup) and if so, read the domain's name.
I found these Windows API functions to achieve this:
GetEnvironmentVariable('USERDNSDOMAIN')
NetGetJoinInformation
NetServerGetInfo
NetWkstaGetInfo
LookupAccountSid
Are there any advantages or disadvantages between them? (faster, more reliable, more accurate, ...)
Which one would you recommend and why?
LookupAccountSid is more focused on searching for sid, NetServerGetInfo is focused on retrieving server information.
So neither of these applies to you.
The domain name gets from NetGetJoinInformation and NetWkstaGetInfo correspond to USERDOMAIN instead of USERDNSDOMAIN, Depending on the domain name you want.
GetEnvironmentVariable is the function that just get the value of a variable and can be modified by SetEnvironmentVariable at any time (Even though we usually don't do this), so I don't recommend it.
No special group membership is required to successfully execute the
NetGetJoinInformation function.
And it is more pure than NetWkstaGetInfo(according to your requirement)
most direct and efficient here - call LsaQueryInformationPolicy with PolicyDnsDomainInformation. on output you got filled POLICY_DNS_DOMAIN_INFO structure. here will be name and DNS name of the primary domain. and also it SID
If the computer associated with the Policy object is not a member of a
domain, all structure members except Name are NULL or zero.
#include <Ntsecapi.h>
NTSTATUS PrintDomainName()
{
LSA_HANDLE PolicyHandle;
static LSA_OBJECT_ATTRIBUTES oa = { sizeof(oa) };
NTSTATUS status = LsaOpenPolicy(0, &oa, POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
if (LSA_SUCCESS(status))
{
PPOLICY_DNS_DOMAIN_INFO ppddi;
if (LSA_SUCCESS(status = LsaQueryInformationPolicy(PolicyHandle, PolicyDnsDomainInformation, (void**)&ppddi)))
{
if (ppddi->Sid)
{
DbgPrint("DnsDomainName: %wZ\n", &ppddi->DnsDomainName);
}
else
{
DbgPrint("%wZ: not a member of a domain\n", &ppddi->Name);
}
LsaFreeMemory(ppddi);
}
LsaClose(PolicyHandle);
}
return status;
}
the NetGetJoinInformation internally do the same - query PolicyDnsDomainInformation, but do this not in your but in remote process (svchost.exe -k networkservice -p -s LanmanWorkstation - LanmanWorkstation service) and many additional calls do. so it less efficient, but and less source code for call this api

How to serialize a SecTrustRef object?

I have a SecTrustRef object from the system that I'd like to evaluate myself. Just calling SecTrustEvaluateAsync will be sufficient for this job. The problem is, I must evaluate it in a different process as only this other process has access to the keychains where the CA certificates are stored that may cause evaluation to succeed.
The two processes have an IPC link that allows me to exchange arbitrary byte data between them but I don't see any way to easily serialize a SecTrustRef into byte data and deserialize that data back to an object at the other process. There doesn't seem to be a persistent storage mechanism for SecTrustRef.
So am I overlooking something important here, or do I really have to get all the certs (SecTrustGetCertificateAtIndex) and all the policies (SecTrustCopyPolicies) and serialize these myself?
And if so, how would I serialize a policy?
For the certificate (SecCertificateRef) it's rather easy, I just call SecCertificateCopyData and later on SecCertificateCreateWithData.
But for policies I can only call SecPolicyCopyProperties on one side and later on SecPolicyCreateWithProperties, however the later one requires a 2nd parameter, a policyIdentifier and I see no way to get that value from an existing policy. What am I missing?
Reading through the source of the Security framework, I finally figured it out how to copy a SecPolicyRef:
SecPolicyCreateWithProperties wants what it calls a "policyIdentifier". It's a constant like kSecPolicyAppleIPsec.
This does not get stored directly by the function, it's comparing the value and calling dedicated internal "initializers" (like SecPolicyCreateIPsec).
These in turn call SecPolicyCreate (which is private). They end up passing the same identifier value that you passed to SecPolicyCreateWithProperties.
And this value then gets stored as-is in the _oid field!
The identifier is actually the OID. You can get it either via SecPolicyCopyProperties(policy) (stored in the dictionary with key kSecPolicyOid) or via SecPolicyGetOID (but that returns it as an inconvenient CSSM_OID). Some of those specialized initializers also use values from the properties dictionary passed to SecPolicyCreateWithProperties, those should be present in the copied properties dictionary already.
So this gives us:
Serialization:
CFDictionaryRef createSerializedPolicy(SecPolicyRef policy) {
// Already contains all the information needed.
return SecPolicyCopyProperties(policy);
}
Deserialization:
SecPolicyRef createDeserializedPolicy (CFDictionaryRef serialized) {
CFStringRef oid = CFDictionaryGetValue(serialized, kSecPolicyOid);
if (oid == NULL || CFGetTypeID(oid) != CFStringGetTypeID()) {
return NULL;
}
return SecPolicyCreateWithProperties(oid, serialized);
}
To reproduce the original SecTrustRef as closely as possible, the anchors need to be copied as well. There is an internal variable _anchorsOnly which is set to true once you set anchors. Unfortunately, there is no way to query this value and I've seen it being false in trusts passed by NSURLSession, for example. No idea yet on how to get this value in a public way.
Another problematic bit are the exceptions: if _exceptions is NULL but you query them via SecTrustCopyExceptions(trust), you do get data! And if you assign that to the deserialized trust via SecTrustSetExceptions(trust, exceptions) you suddenly end up with exceptions that were not there before and can change the evaluation result! (I've seen those suddenly appearing exceptions lead to an evaluation result of "proceed" instead of "recoverable trust failure").

Mapping of access mask in DACL for CNG keys

(Note: IMO the question is mainly about WinAPI and DACL and not about CNG, so please read on!)
I'm currently trying to modify the sample CNG key storage provider of Microsoft's Cryptographic Provider Development Kit in such a way that it does not store the keys in single files. However, I'm in trouble with the security descriptors that can be assigned to the private keys.
In the Certificates Snap-in of the Windows Server Management Console, private keys of certificates can be managed, i.e. the owner, DACL and SACL of a key can be changed, which results in a NCryptSetProperty call with a security descriptor as parameter. For the DACL, the snap-in only allows to allow/deny "full control" or "read", which results in the GENERIC_ALL or GENERIC_READ bit to be set in the access mask of the ACE.
As I have learnt, these generic bits need to be mapped to application specific rights - otherwise AccessCheck will not work. But do I really need to do this by hand???
CreatePrivateObjectSecurity+SetPrivateObjectSecurity does not always work since CreatePrivateObjectSecurity is very picky about the owner and group in the input security descriptor. Moreover, when the mapping is applied, the generic bits are cleared in the access mask, which results in the snap-in showing wrong settings (as I said, the snap-in only considers the GA and GR bits when displaying current permissions).
Seems I'm missing some pieces here...
in your CPSetProvParam implementation for PP_KEYSET_SEC_DESCR you got address of a SECURITY_DESCRIPTOR, which you need somehow apply to your private key storage. if your storage based on file(s) or registry key(s) ( in principle any kernel object type, but what more can be used here ?) you need call SetKernelObjectSecurity with file or key HANDLE (which must have WRITE_DAC access) (may be multiple time if you say have multiple files for store single key). in kernel GENERIC access to object will be auto converted to object specific rights.
if your implementation of storage not direct based on some kernel object, but custom - you need yourself at this point convert GENERIC access (0xF0000000 mask) to specific access rights (0x0000FFFF mask)
__________________ EDIT ____________________
after more check i found that provider must not only convert generic to specific access in CPSetProvParam but also convert specific to generic in CPGetProvParam despite this not directly point in documentation.
this is how MS_ENHANCED_PROV (implemented in rsaenh.dll) approximately do this:
void CheckAndChangeAccessMask(PSECURITY_DESCRIPTOR SecurityDescriptor)
{
BOOL bDaclPresent, bDaclDefaulted;
PACL Dacl;
ACL_SIZE_INFORMATION asi;
if (
GetSecurityDescriptorDacl(SecurityDescriptor, &bDaclPresent, &Dacl, &bDaclDefaulted)
&&
bDaclPresent
&&
Dacl
&&
GetAclInformation(Dacl, &asi, sizeof(asi), AclSizeInformation)
&&
asi.AceCount
)
{
union{
PVOID pAce;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paa;
};
do
{
if (GetAce(Dacl, --asi.AceCount, &pAce))
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
ACCESS_MASK Mask = paa->Mask, Gen_Mask = 0;
if (Mask & FILE_READ_DATA)
{
Gen_Mask |= GENERIC_READ;
}
if (Mask & FILE_WRITE_DATA)
{
Gen_Mask |= GENERIC_ALL;
}
paa->Mask = Gen_Mask;
break;
}
}
} while (asi.AceCount);
}
}
so FILE_READ_DATA converted to GENERIC_READ and FILE_WRITE_DATA to GENERIC_ALL (this is exactly algorithm) - however you can look yourself code of rsaenh.CheckAndChangeAccessMask (name from pdb symbols)
rsaenh first get SD from file by GetNamedSecurityInfoW (SE_FILE_OBJECT) and then convert it specific to generic access.
here the call graph and modified DACL (in the top-right, modified ACCESS_MASK in red color)

What is the difference between WinVerifyTrust() and WinVerifyTrustEx()?

MSDN documents the WinVerifyTrust() and WinVerifyTrustEx() functions, and it isn't very clear what the difference between them is.
The function signatures are the same except for the last parameter:
LONG WINAPI WinVerifyTrust(
_In_ HWND hWnd,
_In_ GUID *pgActionID,
_In_ LPVOID pWVTData
);
HRESULT WinVerifyTrustEx(
_In_ HWND hwnd,
_In_ GUID *pgActionID,
_In_ WINTRUST_DATA *pWinTrustData
);
However, the LPVOID pWVTData parameter to WinVerifyTrust() is actually a WINTRUST_DATA* just like the WinVerifyTrustEx():
pWVTData [in]
A pointer that, when cast as a WINTRUST_DATA structure, contains information that the trust provider needs to process the specified action identifier.
I diffed the two documentation pages to look for any other differences, and here's what I found, omitting trivial differences:
WinVerifyTrust():
If the trust provider does not verify that the subject is trusted for the specified action, the function returns a status code from the trust provider.
Note The return value is a LONG, not an HRESULT as previously documented. Do not use HRESULT macros such as SUCCEEDED to determine whether the function succeeded. Instead, check the return value for equality to zero.
Remarks
The WinVerifyTrust function enables applications to invoke a trust provider to verify that a specified object satisfies the criteria of a specified verification operation. The pgActionID parameter identifies the verification operation, and the pWinTrustData parameter identifies the object whose trust is to be verified. A trust provider is a DLL registered with the operating system. A call to WinVerifyTrust forwards that call to the registered trust provider, if there is one, that supports that specified action identifier.
For example, the Software Publisher Trust Provider can verify that an executable image file comes from a trusted software publisher and that the file has not been modified since it was published. In this case, the pWinTrustData parameter specifies the name of the file and the type of file, such as a Microsoft Portable Executable image file.
Each trust provider supports a specific set of actions that it can evaluate. Each action has a GUID that identifies it. A trust provider can support any number of action identifiers, but two trust providers cannot support the same action identifier.
For an example that demonstrates how to use this function to verify the signature of a portable executable (PE) file, see Example C Program: Verifying the Signature of a PE File.
WinVerifyTrustEx():
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Wintrust.dll.
WINTRUST_ACTION_GENERIC_CERT_VERIFY
Verify a certificate chain only. This is only valid when passing in a certificate context in the WinVerifyTrust input structures.
Note: We do not recommend using this function to perform certificate verification. To perform certificate verification, use the CertGetCertificateChain and CertVerifyCertificateChainPolicy functions.
If the trust provider verifies that the subject is trusted for the specified action, the return value is ERROR_SUCCESS. Otherwise, the function returns a status code from the trust provider.
As a test, I took the example program listed for WinVerifyTrust() and changed it to use WinVerifyTrustEx() instead. It gives identical results with either API call.
If anyone is familiar with these two functions and knows what is really different between them, any insights would be appreciated!

How can I pre-authorize authopen?

I'm using authopen inside one of my programs to modify files owned by root. As can be seen in the screenshot below authopen asks for a admin password. What I'd like to achieve is that the dialog shows my app's name and then passes the authorization to authopen.
Code
Launching authopen which returns an authorized file descriptor.
int pipe[2];
socketpair(AF_UNIX, SOCK_STREAM, 0, pipe);
if (fork() == 0) { // child
// close parent's pipe
close(pipe[0]);
dup2(pipe[1], STDOUT_FILENO);
const char *authopenPath = "/usr/libexec/authopen";
execl(authopenPath,
authopenPath,
"-stdoutpipe",
[self.device.devicePath fileSystemRepresentation],
NULL);
NSLog(#"Fatal error, we should never reach %s:%d", __FILE__, __LINE__);
exit(-1);
} else { // parent
close(pipe[1]);
}
// get file descriptor through sockets
I'd really like not to use AuthorizationExecuteWithPrivileges because then I'd have to get more rights than I want to.
Apple has added an option to authopen in OS X 10.9 Mavericks that allows exactly this. Prior this seemed to be impossible.
-extauth
specifies that authopen should read one AuthorizationExternalForm structure from stdin,
convert it to an AuthorizationRef, and attempt to use it to authorize the open(2)
operation.
The authorization should refer to the sys.openfile right corresponding to the requested operation.
The authorization data will be read before any additional data supplied on stdin, and will
not be included in data written with -w.
I have not used this yet, so I do not have any sample code. If someone has, please add it to this answer.
I think if you give your app path in the 1st arg:
execl(authopenPath,
"app path", // <--
"-stdoutpipe",
[self.device.devicePath fileSystemRepresentation],
NULL);
the dialog will show:
"app namerequires that you type your password"
You need to be looking directly at the security framework, introduced in 10.4, I think, and been the main authorization source since 10.5. OSX still works within PAM (like Linux), but /etc/authorization now supersedes this. Apple does have one or two samples of code on how you could pragmatically create a class/entry for someone to authorize themselves against (or preauthorize/be preauthorized like folks who are allowed to print).
This question is old but it seems to be possible, as explained in this technical note :
Technical Note TN2095 : Authorization for Everyone
http://developer.apple.com/library/mac/#technotes/tn2095/_index.html

Resources