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!
Related
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
Is it safe to call XGetErrorText from a error handler set by XSetErrorHandler?
E.g.
int errorHandler(Display *dpy, XErrorEvent *err)
{
char buf[BUFLEN];
XGetErrorText(dpy, err->error_code, buf, BUFLEN);
printf("%s\n", buf)
return 0;
}
XSetErrorHandler(errorHandler);
I'm asking because the man page says you should not call any functions (directly or indirectly) on the display that will generate protocol requests but it does not tell if XGetErrorText does.
XGetErrorText doesn't generate any server traffic. It's not supposed to: the server doesn't know your locale, for example, and cannot supply localised messages. XLib can, and indeed does with a couple of local Xrm database lookups.
The source code of XGetErrorText can be viewed e.g. here. We can see that XGetErrorText calls XGetErrorDatabaseText, and this latter function is not even using its dpy parameter.
Each X extension provides its own error-event-to-error-string translation function. This function does accept a dpy parameter, but, just like XGetErrorDatabaseText is not supposed to use it too generate any server traffic. This error-handling function is by default generateed by the XEXT_GENERATE_ERROR_STRING macro here, which just encapsulates another call to XGetErrorDatabaseText.
(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)
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
Reading Microsoft's documentation on RegOpenKeyEx and RegCloseKey I am unsure of whether or not I need to call the close function if RegOpenKeyEx fails.
Please point me to a definitive source indicating if I need to always call RegCloseKey or if it only needs to be called when RegOpenKeyEx returns ERROR_SUCCESS.
References:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724897%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724837%28v=vs.85%29.aspx
RegOpenKeyEx will only return a valid key handle if ERROR_SUCCESS is the returned value. This is where the caller is responsible for closing the key, otherwise no closing required and key is not opened. This is the the assumed agreement regarding responsibility to close the opened handle, though not explicitly mentioned in RegOpenKeyEx function documentation.
This is also consistent across API samples. If you are unsure after checking sample code in the MSDN article, here is another one: http://msdn.microsoft.com/en-us/library/aa384182%28VS.85%29.aspx
I think if you look at the example listed under your reference links you can see that it does not call RegCloseKey if lResult does not return ERROR_SUCCESS
This is the link to it:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724235(v=vs.85).aspx