Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2836 lines
80 KiB

/*
** s e c l a b e l. c p p
**
** Purpose: Security labels interface
**
** Ported from O2K fed release by YST
**
** Copyright (C) Microsoft Corp. 1996-1999
*/
#include "pch.hxx"
#include "ipab.h"
#include "secutil.h"
#include "wchar.h"
#include "goptions.h"
#include "SecLabel.h"
#include "mailnews.h"
#include "shlwapip.h"
#include "util.h"
#include "demand.h"
// #include "_digsigx.h"
// #include "..\_secext\SecExt.h"
// --------------------------------------------------------------------------------
// GUIDS
// --------------------------------------------------------------------------------
// {5073B6B4-AA66-11d2-9841-0060B0EC2DF3}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_ISMimePolicySimpleEdit ={0x5073b6b4, 0xaa66, 0x11d2, { 0x98, 0x41, 0x0, 0x60, 0xb0, 0xec, 0x2d, 0xf3} };
// {5073B6B5-AA66-11d2-9841-0060B0EC2DF3}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_ISMimePolicyFullEdit = {0x5073b6b5, 0xaa66, 0x11d2, { 0x98, 0x41, 0x0, 0x60, 0xb0, 0xec, 0x2d, 0xf3} };
// {5073B6B6-AA66-11d2-9841-0060B0EC2DF3}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_ISMimePolicyCheckAccess = {0x5073b6b6, 0xaa66, 0x11d2, { 0x98, 0x41, 0x0, 0x60, 0xb0, 0xec, 0x2d, 0xf3} };
// {5073B6B7-AA66-11d2-9841-0060B0EC2DF3}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_ISMimePolicyLabelInfo = {0x5073b6b7, 0xaa66, 0x11d2, { 0x98, 0x41, 0x0, 0x60, 0xb0, 0xec, 0x2d, 0xf3} };
// {5073B6B8-AA66-11d2-9841-0060B0EC2DF3}
EXTERN_C const GUID DECLSPEC_SELECTANY IID_ISMimePolicyValidateSend = {0x5073b6b8, 0xaa66, 0x11d2, { 0x98, 0x41, 0x0, 0x60, 0xb0, 0xec, 0x2d, 0xf3} };
//
// constant local data.
//
//$ M00Bug : GautamV Use the CryptoReg helper Api's to get the base crypto regkey.
const TCHAR c_szSecurityPoliciesRegKey[] =
TEXT("Software\\Microsoft\\Cryptography\\OID\\EncodingType 1\\SMIMESecurityLabel");
const TCHAR c_szSecurityPolicyDllPath[] = TEXT("DllPath"); // string.
const WCHAR c_wszSecurityPolicyCommonName[] = L"CommonName"; // string
const TCHAR c_szSecurityPolicyFuncName[] = TEXT("FuncName"); // string.
const TCHAR c_szSecurityPolicyOtherInfo[] = TEXT("OtherInfo"); // dword
const TCHAR SzRegSecurity[] = "Software\\Microsoft\\Office\\9.0\\Outlook\\Security";
// other constant strings.
const CHAR c_szDefaultPolicyOid[] = "default"; // The default policy
static const WCHAR c_PolwszEmpty[] = L""; //
const WCHAR c_wszPolicyNone[] = L"<None>"; //$ M00BUG: GautamV. This needs to be localized.
#define KEY_USAGE_SIGNING (CERT_DIGITAL_SIGNATURE_KEY_USAGE|CERT_NON_REPUDIATION_KEY_USAGE)
#define KEY_USAGE_ENCRYPTION (CERT_KEY_ENCIPHERMENT_KEY_USAGE|CERT_KEY_AGREEMENT_KEY_USAGE)
#define KEY_USAGE_SIGNENCRYPT (KEY_USAGE_SIGNING|KEY_USAGE_ENCRYPTION)
//
// static local data.
//
// The cached information about the security policies.
enum EPolicyRegInfoState {
ePolicyRegInfoNOTLOADED = 0,
ePolicyRegInfoPRESENT = 1,
ePolicyRegInfoABSENT = 2
};
const static HELPMAP g_rgCtxSecLabel[] =
{
{IDC_POLICY_COMBO, IDH_SECURITY_POLICY_MODULE},
{IDC_CLASSIF_COMB, IDH_SECURITY_CLASSIFICATION},
{IDC_PRIVACY_EDIT, IDH_SECURITY_PRIVACY},
{IDC_CONFIGURE, IDH_SECURITY_CONFIGURE},
{IDC_STATIC, IDH_NEWS_COMM_GROUPBOX},
{0, 0}
};
static EPolicyRegInfoState s_ePolicyRegInfoState = ePolicyRegInfoNOTLOADED;
static SMIME_SECURITY_POLICY *s_rgSsp = NULL; // array of Ssp's.
static ULONG s_cSsp = 0;
// local fn prototypes.
VOID _IncrPolicyUsage(PSMIME_SECURITY_POLICY pSsp);
HRESULT _HrFindLeastUsedPolicy(PSMIME_SECURITY_POLICY *ppSsp);
HRESULT _EnsureNewPolicyLoadable();
BOOL _FLoadedPolicyRegInfo();
// BOOL _FPresentPolicyRegInfo();
HRESULT _HrEnsurePolicyRegInfoLoaded(DWORD dwFlags);
HRESULT _HrLoadPolicyRegInfo(DWORD dwFlags);
HRESULT _HrReloadPolicyRegInfo(DWORD dwFlags);
BOOL _FFindPolicy(LPCSTR szPolicyOid, PSMIME_SECURITY_POLICY *ppSsp);
BOOL _FIsPolicyLoaded(PSMIME_SECURITY_POLICY pSsp);
HRESULT _HrUnloadPolicy(PSMIME_SECURITY_POLICY pSsp);
HRESULT _HrLoadPolicy(PSMIME_SECURITY_POLICY pSsp);
HRESULT _HrEnsurePolicyLoaded(PSMIME_SECURITY_POLICY pSsp);
HRESULT _HrGetPolicy(LPCSTR szPolicyOid, PSMIME_SECURITY_POLICY *ppSsp);
// Registry access functions
const int QRV_Suppress_HKLM = 1;
const int QRV_Suppress_HKCU = 2;
HRESULT HrQueryRegValue(DWORD dwFlags, LPSTR szRegKey, LPDWORD pdwType,
LPBYTE * ppbData, LPDWORD pcbData, DWORD dwDefaultType,
LPBYTE pbDefault, DWORD cbDefault);
HRESULT CategoriesToBinary(PSMIME_SECURITY_LABEL plabel, BYTE * *ppArray, int *cbSize);
HRESULT BinaryToCategories(CRYPT_ATTRIBUTE_TYPE_VALUE ** ppCategories, DWORD *cCat, BYTE * pArray);
//
// Increase the usage count of the given policy.
//
VOID _IncrPolicyUsage(PSMIME_SECURITY_POLICY pSsp)
{
if (!FPresentPolicyRegInfo()) return;
if ((pSsp->dwUsage + 1) < pSsp->dwUsage) {
// prevent overflow.
Assert(s_rgSsp);
for (ULONG iSsp = 0; iSsp<s_cSsp; iSsp++) {
s_rgSsp[iSsp].dwUsage /= 2; // Just halve each usage count.
}
}
pSsp->dwUsage ++;
}
//
// Find the least used policy.
//
HRESULT _HrFindLeastUsedPolicy(PSMIME_SECURITY_POLICY *ppSsp)
{
ULONG iSsp;
HRESULT hr = E_FAIL;
PSMIME_SECURITY_POLICY pSspFound = NULL;
// validate i/p params.
if (NULL == ppSsp) {
hr = E_INVALIDARG;
goto Error;
}
*ppSsp = NULL;
// find the least used policy.
for (iSsp=0; iSsp < s_cSsp; iSsp++) {
if (_FIsPolicyLoaded(& (s_rgSsp[iSsp]) )) {
// if we haven't found a ssp earlier,
// OR if this one is less used that the currently found one.
if ((NULL == pSspFound) ||
(s_rgSsp[iSsp].dwUsage < pSspFound->dwUsage)) {
pSspFound = & (s_rgSsp[iSsp]);
}
}
}
// have we found the result.
if (NULL == pSspFound) {
hr = E_FAIL;
goto Error;
}
// success.
*ppSsp = pSspFound;
hr = S_OK;
// Exit:
Error:
return hr;
}
//
// Unloads one or more policies from memory and ensures that there
// is room for a new policy to be loaded.
//
HRESULT _EnsureNewPolicyLoadable()
{
ULONG cSspLoaded = 0;
HRESULT hr = E_FAIL;
ULONG iSsp;
// count the number of policies loaded into memory.
for (iSsp=0; iSsp < s_cSsp; iSsp++) {
if (_FIsPolicyLoaded( &(s_rgSsp[iSsp]) )) {
cSspLoaded ++;
}
}
// If we have room for one more policy, then we don't need to do anything.
if (cSspLoaded < MAX_SECURITY_POLICIES_CACHED) {
hr = S_OK;
goto Exit;
}
// Assert that this isn't a "bad" condition, but we will handle it anyway.
Assert(cSspLoaded == MAX_SECURITY_POLICIES_CACHED);
// unload one or more policies.
while (cSspLoaded >= MAX_SECURITY_POLICIES_CACHED) {
PSMIME_SECURITY_POLICY pSsp = NULL;
if (FAILED(_HrFindLeastUsedPolicy(&pSsp))) {
goto Error;
}
if (FAILED(_HrUnloadPolicy(pSsp))) {
goto Error;
}
cSspLoaded --;
}
// success.
hr = S_OK;
Exit:
return hr;
Error:
AssertSz(FALSE, "_EnsureNewPolicyLoadable failed");
goto Exit;
}
//
// Return true if the info about the installed policies
// has been read in from the windows registry.
//
BOOL _FLoadedPolicyRegInfo()
{
return ( ! ( ePolicyRegInfoNOTLOADED == s_ePolicyRegInfoState ) );
}
//
// Ensure that the policy registration info has been read in.
//
HRESULT _HrEnsurePolicyRegInfoLoaded(DWORD dwFlags)
{
HRESULT hr = S_OK;
if ( !_FLoadedPolicyRegInfo() ) hr = _HrLoadPolicyRegInfo(dwFlags);
return hr;
}
//
// Are any policies installed(registered) ?
//
BOOL FPresentPolicyRegInfo()
{
HRESULT hr = S_OK;
BOOL fRegistered = FALSE;
// No label support without SMIME3 bits
if(!IsSMIME3Supported())
return FALSE;
hr = _HrEnsurePolicyRegInfoLoaded(0);
if (SUCCEEDED(hr)) {
fRegistered = (ePolicyRegInfoPRESENT == s_ePolicyRegInfoState);
Assert(!fRegistered || s_rgSsp); // ie ((registered_policies) => (NULL!=s_rgSsp)).
}
return fRegistered;
}
//
// Internal function.
// Load Policy Registration information.
//
// Returns:
// S_OK or E_FAIL.
//
// The format of the security policy registration info is assumed to be:
// HKLM\Software\Microsoft\Cryptography\SMIME\SecurityPolicies\
// szPolicyOid_1
// DLLPATH REG_SZ
// CommonName REG_SZ
// FuncName REG_SZ
// OtherInfo REG_SZ
// szPolicyOid_2
// Default
// ...
//
//
HRESULT _HrLoadPolicyRegInfo(DWORD dwFlags)
{
HRESULT hr = E_FAIL;
LONG lRes = 0;
HKEY hkey = NULL;
HKEY hkeySub = NULL;
ULONG cb = 0;
LPBYTE pb = NULL;
DWORD cSubKeys = 0;
ULONG iSubKey = 0;
if (_FLoadedPolicyRegInfo()) {
AssertSz(FALSE, "PolicyRegInfo is already loaded");
hr = S_OK;
goto Cleanup;
}
// Open the security policies key.
lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szSecurityPoliciesRegKey, 0,
KEY_READ, &hkey);
if ( (ERROR_SUCCESS != lRes) || (NULL == hkey) ) {
// we couldn't open the regkey, bail out.
hr = E_FAIL;
goto Error;
}
// find the number of security policies. (ie number of subkeys).
lRes = RegQueryInfoKey(hkey, NULL, NULL, NULL, &cSubKeys,
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if ( (ERROR_SUCCESS != lRes) || (0 == cSubKeys) ) {
// we counldn't get num of subkeys, or there are no subkeys.
hr = E_FAIL;
goto Error;
}
// Allocate enough memory to retrieve and store info about
// the registered security policies.
cb = sizeof(SMIME_SECURITY_POLICY) * cSubKeys;
pb = (LPBYTE) malloc(cb);
if (NULL == pb) {
hr = E_OUTOFMEMORY;
goto Error;
}
memset(pb, 0, cb); // initialize the whole blob to zeros.
Assert(NULL == s_rgSsp);
s_rgSsp = (PSMIME_SECURITY_POLICY) pb;
s_cSsp = 0;
//
// Enumerate over the subkeys and retrieve reqd info.
//
for (iSubKey=0; iSubKey<cSubKeys; iSubKey++) {
ULONG cbData;
DWORD dwType;
TCHAR szPolicyOid[MAX_OID_LENGTH];
TCHAR szDllPath[MAX_PATH];
TCHAR szExpanded[MAX_PATH];
TCHAR szFuncName[MAX_FUNC_NAME];
WCHAR wszPolicyName[MAX_POLICY_NAME];
DWORD dwOtherInfo;
// release previously opened subkeys.
if (NULL != hkeySub) {
RegCloseKey(hkeySub);
hkeySub = NULL;
}
// Get the subkey name. (ie policy oid).
lRes = RegEnumKey(hkey, iSubKey, szPolicyOid, DimensionOf(szPolicyOid));
if (ERROR_SUCCESS != lRes) {
goto NextSsp;
}
szPolicyOid[ DimensionOf(szPolicyOid) - 1 ] = '\0';
// Open the subkey. (ie the policy subkey).
lRes = RegOpenKeyEx(hkey, szPolicyOid, 0, KEY_READ, &hkeySub);
if (ERROR_SUCCESS != lRes) {
goto NextSsp;
}
//
// query the szOid policy values.
//
// get the path to the policy dll.
cbData = sizeof(szDllPath);
lRes = RegQueryValueEx(hkeySub, c_szSecurityPolicyDllPath, NULL,
&dwType, (LPBYTE)szDllPath, &cbData);
if (ERROR_SUCCESS != lRes) {
goto NextSsp;
}
else if (REG_EXPAND_SZ == dwType)
{
ExpandEnvironmentStrings(szDllPath, szExpanded, ARRAYSIZE(szExpanded));
StrCpyN(szDllPath, szExpanded, ARRAYSIZE(szDllPath));
}
else
szDllPath[ DimensionOf(szDllPath) - 1 ] = '\0';
// get the common name.
cbData = DimensionOf(wszPolicyName);
lRes = RegQueryValueExWrapW(hkeySub, c_wszSecurityPolicyCommonName, NULL,
&dwType, (LPBYTE)wszPolicyName, &cbData);
if (ERROR_SUCCESS != lRes) {
goto NextSsp;
}
wszPolicyName[ DimensionOf(wszPolicyName) - 1 ] = '\0';
// get the entry func name.
cbData = sizeof(szFuncName);
lRes = RegQueryValueEx(hkeySub, c_szSecurityPolicyFuncName, NULL,
&dwType, (LPBYTE)szFuncName, &cbData);
if (ERROR_SUCCESS != lRes) {
goto NextSsp;
}
szFuncName[ DimensionOf(szFuncName) - 1] = '\0';
// get other policy info.
cbData = sizeof(dwOtherInfo);
lRes = RegQueryValueEx(hkeySub, c_szSecurityPolicyOtherInfo, NULL,
&dwType, (LPBYTE)&dwOtherInfo, &cbData);
if (ERROR_SUCCESS != lRes) {
dwOtherInfo = 0; // ignore the absence of this value.
}
//
// Great: we were able to open subkey, and get all required info.
// Now we store all the info we retrieved.
//
s_rgSsp[s_cSsp].fValid = TRUE;
s_rgSsp[s_cSsp].fDefault = (0 == lstrcmpi(c_szDefaultPolicyOid, szPolicyOid));
StrCpyNA(s_rgSsp[s_cSsp].szPolicyOid, szPolicyOid, ARRAYSIZE(s_rgSsp[s_cSsp].szPolicyOid));
StrCpyNW(s_rgSsp[s_cSsp].wszPolicyName, wszPolicyName, ARRAYSIZE(s_rgSsp[s_cSsp].wszPolicyName));
StrCpyNA(s_rgSsp[s_cSsp].szDllPath, szDllPath, ARRAYSIZE(s_rgSsp[s_cSsp].szDllPath));
s_rgSsp[s_cSsp].dwOtherInfo = dwOtherInfo;
s_rgSsp[s_cSsp].dwUsage = 0;
s_rgSsp[s_cSsp].hinstDll = NULL;
StrCpyNA(s_rgSsp[s_cSsp].szFuncName, szFuncName, ARRAYSIZE(s_rgSsp[s_cSsp].szFuncName));
s_rgSsp[s_cSsp].punk = NULL;
s_cSsp++;
continue;
NextSsp:
AssertSz(FALSE, "Ignoring incorrectly registered Ssp");
}
// success.
if (0 == s_cSsp) {
AssertSz(FALSE, "There isn't even one correctly registered Ssp");
goto Error;
}
s_ePolicyRegInfoState = ePolicyRegInfoPRESENT;
hr = S_OK;
goto Cleanup;
Error:
// Any error is treated as if no security policies are registered.
s_ePolicyRegInfoState = ePolicyRegInfoABSENT;
free(pb); //ie free(s_rgSsp);
s_cSsp = 0;
s_rgSsp = NULL;
Cleanup:
if (NULL != hkeySub) RegCloseKey(hkeySub);
if (NULL != hkey) RegCloseKey(hkey);
return hr;
}
//
// Unload Policy Registration Information.
//
HRESULT HrUnloadPolicyRegInfo(DWORD dwFlags)
{
HRESULT hr = S_OK;
ULONG iSsp;
// If the policy reg info isn't loaded
if ( ! _FLoadedPolicyRegInfo() ) {
return S_OK;
}
// unload all policy modules.
if (FPresentPolicyRegInfo()) {
Assert(s_rgSsp && s_cSsp);
for (iSsp=0; iSsp<s_cSsp; iSsp++) {
SideAssert(SUCCEEDED(_HrUnloadPolicy(&s_rgSsp[iSsp])));
// if this fails, we don't have to abort.
}
}
// free memory, reset cache info and exit.
free(s_rgSsp);
s_rgSsp = NULL;
s_ePolicyRegInfoState = ePolicyRegInfoNOTLOADED;
s_cSsp = 0;
hr = S_OK;
return hr;
}
//
// Reload all the policy registration information.
//
HRESULT _HrReloadPolicyRegInfo(DWORD dwFlags)
{
HRESULT hr = S_OK;
hr = HrUnloadPolicyRegInfo(dwFlags);
Assert(SUCCEEDED(hr));
if (SUCCEEDED(hr)) {
hr = _HrLoadPolicyRegInfo(dwFlags);
}
return hr;
}
//
// Find a given policy, and return its reg info struct.
//
// Input:
// szPolicyOid [in]
// ppSsp [out]
//
// Output:
// TRUE/FALSE. (if true, *ppSsp contains the reqd info).
//
BOOL _FFindPolicy(LPCSTR szPolicyOid, PSMIME_SECURITY_POLICY *ppSsp)
{
BOOL fFound = FALSE;
HRESULT hr = E_FAIL;
ULONG iSsp;
// Validate i/p params and init o/p params.
if ( (NULL == szPolicyOid) || (NULL == ppSsp) ) {
hr = E_INVALIDARG;
goto Error;
}
*ppSsp = NULL;
// Load the info from the registry if reqd.
hr = _HrEnsurePolicyRegInfoLoaded(0);
if (FAILED(hr)) {
goto Error;
}
// If we haven any installed policies, search for the one we want.
if (FPresentPolicyRegInfo()) {
for (iSsp=0; iSsp<s_cSsp; iSsp++) {
if (0 == lstrcmpi(s_rgSsp[iSsp].szPolicyOid, szPolicyOid)) {
// found the policy.
*ppSsp = & (s_rgSsp[iSsp]);
fFound = TRUE;
break;
}
}
}
Error:
// Cleanup:
return fFound;
}
//
// Finds out if a given policy module is loaded.
//
// Input: pSsp [in].
// Output: true/false if policy is loaded or notloaded.
//
BOOL _FIsPolicyLoaded(PSMIME_SECURITY_POLICY pSsp)
{
BOOL fIsLoaded = FALSE;
HRESULT hr = E_FAIL;
// validate i/p params.
if (NULL == pSsp) {
hr = E_INVALIDARG;
goto Error;
}
// Find out if hinstDll, pfn, and punk are loaded and ok.
if ( (NULL != pSsp->hinstDll) &&
(NULL != pSsp->pfnGetSMimePolicy) &&
(NULL != pSsp->punk) ) {
fIsLoaded = TRUE;
}
Error:
return fIsLoaded;
}
//
// Unload a specified policy.
//
// Input : pSsp
// Output: hr.
//
HRESULT _HrUnloadPolicy(PSMIME_SECURITY_POLICY pSsp)
{
HRESULT hr;
// validate i/p params.
if (NULL == pSsp) {
hr = E_INVALIDARG;
goto Error;
}
// release the object.
if (NULL != pSsp->punk) {
if (! IsBadReadPtr(pSsp->punk, sizeof(IUnknown)) ) {
pSsp->punk->Release();
}
pSsp->punk = NULL;
}
// forget the proc address.
if (NULL != pSsp->pfnGetSMimePolicy) {
pSsp->pfnGetSMimePolicy = NULL;
}
// unload the library.
if (NULL != pSsp->hinstDll) {
FreeLibrary(pSsp->hinstDll);
// there's no point in aborting to error here.
pSsp->hinstDll = NULL;
}
hr = S_OK;
Error:
return hr;
}
//
// (Force) Load a specified policy.
//
// Input: pSsp
// Output: hr
//
HRESULT _HrLoadPolicy(PSMIME_SECURITY_POLICY pSsp)
{
HRESULT hr = E_FAIL;
// validate i/p params.
if (NULL == pSsp) {
hr = E_INVALIDARG;
goto Error;
}
// Unload any partial info we might have.
SideAssert(SUCCEEDED(_HrUnloadPolicy(pSsp)));
// Unload policies (if reqd) to make room for the new one.
hr = _EnsureNewPolicyLoadable();
if (FAILED(hr)) {
goto Error;
}
// Load the dll, get its proc address and get the interface ptr.
Assert(NULL != pSsp->szDllPath);
pSsp->hinstDll = LoadLibraryEx(pSsp->szDllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (NULL == pSsp->hinstDll) {
hr = E_FAIL;
goto Error;
}
Assert(NULL != pSsp->szFuncName);
pSsp->pfnGetSMimePolicy = (PFNGetSMimePolicy)
GetProcAddress(pSsp->hinstDll, pSsp->szFuncName);
if (NULL == pSsp->pfnGetSMimePolicy) {
hr = E_FAIL;
goto Error;
}
//$ M00BUG: GautamV. Need to pass in an appropriate lcid.
hr = (pSsp->pfnGetSMimePolicy) (0, pSsp->szPolicyOid, GetACP(),
IID_IUnknown, &(pSsp->punk) );
if (FAILED(hr)) {
goto Error;
}
if (NULL == pSsp->punk) {
hr = E_FAIL;
goto Error;
}
// Success.
hr = S_OK;
goto Cleanup;
Error:
// unload the policy module (since we may have partially loaded it).
SideAssert(SUCCEEDED(_HrUnloadPolicy(pSsp)));
Cleanup:
return hr;
}
//
// Ensure that the given policy is loaded.
// Input: pSsp
// Output: pSsp
//
HRESULT _HrEnsurePolicyLoaded(PSMIME_SECURITY_POLICY pSsp)
{
HRESULT hr = E_FAIL;
// validate i/p params.
if (NULL == pSsp) {
hr = E_INVALIDARG;
goto Error;
}
// if it is already loaded, then we are done.
if (_FIsPolicyLoaded(pSsp)) {
hr = S_OK;
goto Cleanup;
}
// else, load the policy.
hr = _HrLoadPolicy(pSsp);
if (FAILED(hr)) {
goto Error;
}
Assert(_FIsPolicyLoaded(pSsp));
hr = S_OK;
goto Cleanup;
Error:
Cleanup:
return hr;
}
//
// Given a oid, find it, ensure that it is loaded and
// return the structure contain its registration info.
//
// Returns:
// S_OK and a valid pSsp
// OR E_INVALIDARG, E_FAIL, etc.
//
HRESULT _HrGetPolicy(LPCSTR szPolicyOid, PSMIME_SECURITY_POLICY *ppSsp)
{
HRESULT hr = E_FAIL;
PSMIME_SECURITY_POLICY pSsp = NULL;
// Validate i/p params and initialize o/p params.
if ( (NULL == szPolicyOid) || (NULL == ppSsp) ) {
hr = E_INVALIDARG;
goto Error;
}
*ppSsp = NULL;
// Load all the registration information for all installed policies.
hr = _HrEnsurePolicyRegInfoLoaded(0);
if (FAILED(hr)) {
goto Error;
}
// find the policy we want.
if (! _FFindPolicy(szPolicyOid, &pSsp)) {
hr = NTE_NOT_FOUND;
goto Error; // not found.
}
// If needed, load the policy.
hr = _HrEnsurePolicyLoaded(pSsp);
if (FAILED(hr)) {
goto Error;
}
// success
*ppSsp = pSsp;
// We increment the usage count, each time someone "gets" a policy.
_IncrPolicyUsage(pSsp);
hr = S_OK;
Error:
return hr;
// Cleanup:
}
//
// SecurityPolicy - QI clone.
// Given a policy oid, finds and loads it, does a
// qi and returns the reqd interface to the policy module.
//
HRESULT HrQueryPolicyInterface(DWORD dwFlags, LPCSTR szPolicyOid, REFIID riid, LPVOID * ppv)
{
HRESULT hr = E_FAIL;
PSMIME_SECURITY_POLICY pSsp = NULL;
// Validate i/p params, initialize o/p params.
if ((NULL == szPolicyOid) || (NULL == ppv)) {
hr = E_INVALIDARG;
goto Error;
}
*ppv = NULL;
// Get the policy.
hr = _HrGetPolicy(szPolicyOid, &pSsp);
if (FAILED(hr)) {
goto Error;
}
Assert(NULL != pSsp->punk);
hr = pSsp->punk->QueryInterface(riid, ppv);
// fall through to Error.
// Cleanup:
Error:
return hr;
}
//
// The allocators we pass in to the Crypto Api's.
//
LPVOID WINAPI SecLabelAlloc(size_t cbSize)
{
return SecPolicyAlloc(cbSize);
}
VOID WINAPI SecLabelFree(LPVOID pv)
{
SecPolicyFree(pv);
}
CRYPT_DECODE_PARA SecLabelDecode = {
sizeof(SecLabelDecode), SecLabelAlloc, SecLabelFree
};
CRYPT_ENCODE_PARA SecLabelEncode = {
sizeof(SecLabelEncode), SecLabelAlloc, SecLabelFree
};
//
// Decode and allocate a label.
//
HRESULT HrDecodeAndAllocLabel(LPBYTE pbLabel, DWORD cbLabel, PSMIME_SECURITY_LABEL *pplabel, DWORD *pcbLabel)
{
BOOL f;
f = CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_Security_Label, pbLabel, cbLabel,
CRYPT_ENCODE_ALLOC_FLAG, &SecLabelDecode,
pplabel, pcbLabel);
if (!f) {
return E_FAIL; // HrCryptError();
}
return S_OK;
}
//
// Encode and Allocate a label.
//
HRESULT HrEncodeAndAllocLabel(const PSMIME_SECURITY_LABEL plabel, BYTE ** ppbLabel, DWORD * pcbLabel)
{
BOOL f;
f = CryptEncodeObjectEx(X509_ASN_ENCODING, szOID_SMIME_Security_Label, plabel,
CRYPT_ENCODE_ALLOC_FLAG, &SecLabelEncode,
ppbLabel, pcbLabel);
if (!f) {
return E_FAIL; // HrCryptError();
}
return S_OK;
}
// HrDupLabel
// Duplicate a given label.
//
// Parameters:
// plabel [in]
// pplabel [out]
//
// Returns:
// on success, returns S_OK with a valid label *pplabelOut.
// else returns failure code, (as well as frees *pplabelOut).
//
HRESULT HrDupLabel(PSMIME_SECURITY_LABEL *pplabelOut, const PSMIME_SECURITY_LABEL plabelIn)
{
HRESULT hr = E_FAIL;
ULONG cbLabel = 0;
LPBYTE pbLabel = NULL;
ULONG cbLabel2 = 0;
PSMIME_SECURITY_LABEL plabel = NULL;
// validate i/p parameters.
if ((NULL == plabelIn) || (NULL == pplabelOut)) {
hr = E_INVALIDARG;
goto Error;
}
SecPolicyFree(*pplabelOut);
// encode it.
hr = HrEncodeAndAllocLabel(plabelIn, &pbLabel, &cbLabel);
if (FAILED(hr)) {
goto Error;
}
Assert( (NULL != pbLabel) && (0 < cbLabel) );
// decode it.
hr = HrDecodeAndAllocLabel(pbLabel, cbLabel, &plabel, &cbLabel2);
if (FAILED(hr)) {
goto Error;
}
Assert( (NULL != plabel) && (0 < cbLabel2) );
// succcess.
*pplabelOut = plabel;
hr = S_OK;
Exit:
SecLabelEncode.pfnFree(pbLabel);
return hr;
Error:
SecLabelDecode.pfnFree(plabel);
goto Exit;
}
// FSafeCompareString
// Given two strings, compare them and return TRUE if they are equivalent
// (safe for NULL pointers)
//
// Parameters:
// pwz1 - wide string 1
// pwz2 - wide string 2
//
// Returns:
// TRUE if the strings are equivalent
// FALSE otherwise
//
BOOL FSafeCompareStringW(LPCWSTR pwz1, LPCWSTR pwz2)
{
if (pwz1 == pwz2) {
return TRUE;
}
else if ((NULL == pwz1)||(NULL == pwz2)) {
return FALSE;
}
return (0 == wcscmp(pwz1, pwz2));
}
BOOL FSafeCompareStringA(LPCSTR psz1, LPCSTR psz2)
{
if (psz1 == psz2) {
return TRUE;
}
else if ((NULL == psz1)||(NULL == psz2)) {
return FALSE;
}
return (0 == strcmp(psz1, psz2));
}
// FCompareLabels
// Given the label, return TRUE if the labels are equivalent
//
// Parameters:
// plabel1 [in]
// plabel2 [in]
//
// Returns:
// TRUE if the labels are equivalent
// FALSE otherwise
//
BOOL FCompareLabels(PSMIME_SECURITY_LABEL plabel1, PSMIME_SECURITY_LABEL plabel2)
{
BOOL fEqual = FALSE;
UINT i;
if (plabel1 == plabel2) {
fEqual = TRUE;
goto Exit;
}
if ((NULL == plabel1)||(NULL == plabel2)) {
goto Exit;
}
if ((plabel1->fHasClassification != plabel2->fHasClassification)||
(plabel1->dwClassification != plabel2->dwClassification)||
(plabel1->cCategories != plabel2->cCategories)) {
goto Exit;
}
if (!FSafeCompareStringA(plabel1->pszObjIdSecurityPolicy,
plabel2->pszObjIdSecurityPolicy)||
!FSafeCompareStringW(plabel1->wszPrivacyMark, plabel2->wszPrivacyMark)) {
goto Exit;
}
//$M00REVIEW: What if the categories are in different order???
for (i=0; i<plabel1->cCategories; ++i) {
if ((plabel1->rgCategories[i].Value.cbData !=
plabel2->rgCategories[i].Value.cbData)||
(0 != memcmp(plabel1->rgCategories[i].Value.pbData,
plabel2->rgCategories[i].Value.pbData,
plabel2->rgCategories[i].Value.cbData))) {
goto Exit;
}
}
fEqual = TRUE;
Exit:
return fEqual;
}
// HrGetLabelFromData
// Given the label data, allocate and store the info in a label struct.
//
// Parameters:
// pplabel [out]
// others [in]
//
// Returns:
// on success, returns S_OK with a valid label *pplabel.
// else returns failure code, (as well as frees *pplabel).
//
HRESULT HrGetLabelFromData(PSMIME_SECURITY_LABEL *pplabel, LPCSTR szPolicyOid,
DWORD fHasClassification, DWORD dwClassification, LPCWSTR wszPrivacyMark,
DWORD cCategories, CRYPT_ATTRIBUTE_TYPE_VALUE *rgCategories)
{
HRESULT hr = E_FAIL;
SMIME_SECURITY_LABEL label = {0};
PSMIME_SECURITY_LABEL plabel = NULL;
// validate i/p parameters.
if ((NULL == pplabel) || (NULL == szPolicyOid)) {
hr = E_INVALIDARG;
goto Error;
}
SecPolicyFree(*pplabel);
// set up our temporary label structure.
label.pszObjIdSecurityPolicy = const_cast<LPSTR> (szPolicyOid);
label.fHasClassification = fHasClassification;
if (fHasClassification) {
label.dwClassification = dwClassification;
}
label.wszPrivacyMark = const_cast<LPWSTR> (wszPrivacyMark);
label.cCategories = cCategories;
if (label.cCategories) {
label.rgCategories = rgCategories;
}
// dupe and get a contiguous label structure.
hr = HrDupLabel(&plabel, &label);
if (FAILED(hr)) {
goto Error;
}
// success. set return value.
*pplabel = plabel;
hr = S_OK;
Exit:
return hr;
Error:
SecPolicyFree(plabel);
goto Exit;
}
//
// Utility fn to "Select NO label".
//
// Input: hwndDlg, idc's of controls.
// Output: hr
//
HRESULT HrSetLabelNone(HWND hwndDlg, INT idcPolicyModule, INT idcClassification,
INT idcPrivacyMark, INT idcConfigure)
{
HRESULT hr = E_FAIL;
LONG_PTR iEntry;
// Make sure the policy Module name is <none> and that it is selected.
// First try to select the <none> policy module.
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule,
CB_SELECTSTRING, (WPARAM) (-1),
(LPARAM) (c_wszPolicyNone));
if (CB_ERR == iEntry) {
// Otherwise, add the <none>policy module and select it.
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule,
CB_ADDSTRING, (WPARAM) 0,
(LPARAM) c_wszPolicyNone);
Assert(NULL == SendDlgItemMessage(hwndDlg, idcPolicyModule, CB_GETITEMDATA, iEntry, 0));
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule,
CB_SETCURSEL, (WPARAM) iEntry, 0);
Assert(CB_ERR != iEntry);
}
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LPARAM)iEntry);
// Reset and disable the other controls.
SendDlgItemMessage(hwndDlg, idcClassification, CB_RESETCONTENT, 0, 0);
EnableWindow(GetDlgItem(hwndDlg, idcClassification), FALSE);
EnableWindow(GetDlgItem(hwndDlg, idcClassification+1), FALSE);
SetDlgItemTextW(hwndDlg, idcPrivacyMark, c_PolwszEmpty);
EnableWindow(GetDlgItem(hwndDlg, idcPrivacyMark), FALSE);
EnableWindow(GetDlgItem(hwndDlg, idcPrivacyMark+1), FALSE);
EnableWindow(GetDlgItem(hwndDlg, idcConfigure), FALSE);
hr = S_OK;
return hr;
}
//
// Select a label in the dlg.
//
// Given pssl, sets that label.
// Given pSsp, sets that policy's default info.
// If neither is given, sets label to none.
//
// Input:
// hwndDlg, idc's of the various controls [in].
// pSsp [in, optional] smime security policy.
// plabel [in, optional] security label.
//
// Returns:
// returns either S_OK or an error code.
//
HRESULT HrSetLabel(HWND hwndDlg, INT idcPolicyModule, INT idcClassification,
INT idcPrivacyMark, INT idcConfigure,
PSMIME_SECURITY_POLICY pSsp, PSMIME_SECURITY_LABEL plabel)
{
HRESULT hr = E_FAIL;
ULONG iClassification;
LONG_PTR iEntry;
LPCWSTR wszT = NULL;
DWORD dwPolicyFlags = 0;
ULONG cClassifications = 0;
LPWSTR *pwszClassifications = NULL;
LPDWORD pdwClassifications = NULL;
DWORD dwDefaultClassification = 0;
DWORD dwT = 0;
WCHAR *pwchPrivacyMark = NULL;
BOOL fPrivMarkReadOnly = FALSE;
SpISMimePolicySimpleEdit spspse = NULL;
// Validate the i/p parameters.
if ( ! IsWindow(hwndDlg) ) {
hr = E_INVALIDARG;
goto Exit;
}
// If we are neither given a policy nor a ssl, set the label to <none>.
if ((NULL == pSsp) && (NULL == plabel)) {
hr = S_OK;
goto Error;
}
// if given a label, but not a policy, try to locate & load the policy.
if ((NULL == pSsp) && (NULL != plabel)) {
if (NULL != plabel->pszObjIdSecurityPolicy) {
hr = _HrGetPolicy(plabel->pszObjIdSecurityPolicy, &pSsp);
// if unable to locate/load the policy, set the label to <none>
if (FAILED(hr)) {
goto PolicyNotFoundError;
}
}
else {
hr = S_OK;
goto Error;
}
}
// ensure that the policy is loaded.
hr = _HrEnsurePolicyLoaded(pSsp);
if (FAILED(hr)) {
goto PolicyNotFoundError;
}
Assert(_FIsPolicyLoaded(pSsp) && pSsp->punk);
hr = pSsp->punk->QueryInterface(IID_ISMimePolicySimpleEdit,
(LPVOID *) & spspse);
if (FAILED(hr)) {
goto PolicyNotFoundError;
}
// get the policy flags
hr = spspse->GetPolicyInfo(0, &dwPolicyFlags);
if (FAILED(hr)) {
goto PolicyError;
}
// get the classification information.
hr = spspse->GetClassifications(0, &cClassifications, &pwszClassifications,
&pdwClassifications,
&dwDefaultClassification);
if (FAILED(hr)) {
goto PolicyError;
}
// get the default policy info.
hr = spspse->GetDefaultPolicyInfo(0, &dwT, &pwchPrivacyMark);
if (FAILED(hr)) {
goto PolicyError;
}
Assert(dwT == dwDefaultClassification);
// initialize the classification and privacy strings.
Assert((NULL == plabel) || (plabel->fHasClassification)); // UI currently doesn't allow one to not specify one.
SendDlgItemMessage(hwndDlg, idcClassification, CB_RESETCONTENT, 0, 0);
for (iClassification=0; iClassification<cClassifications; iClassification++) {
// add the classification strings to the listbox.
iEntry = SendDlgItemMessageW(hwndDlg, idcClassification, CB_ADDSTRING,
(WPARAM) 0,
(LPARAM) pwszClassifications[iClassification]);
if ((CB_ERR == iEntry) || (CB_ERRSPACE == iEntry)) {
AssertSz(FALSE, "Unable to add classification string");
hr = E_OUTOFMEMORY;
goto Error;
}
SendDlgItemMessageW(hwndDlg, idcClassification, CB_SETITEMDATA,
iEntry, (LPARAM) pdwClassifications[iClassification]);
// If this classification is the one in the label, remember it.
if ((NULL != plabel) &&
(pdwClassifications[iClassification] == plabel->dwClassification)) {
wszT = pwszClassifications[iClassification];
}
// if needed, pick up the default classification string.
if ((NULL == wszT) && (pdwClassifications[iClassification] == dwDefaultClassification)) {
wszT = pwszClassifications[iClassification];
}
}
if (NULL == wszT) {
Assert(FALSE);
wszT = pwszClassifications[0];
}
// select the classification specified in the security label or the default one.
Assert(wszT != NULL);
iEntry = SendDlgItemMessageW(hwndDlg, idcClassification, CB_SELECTSTRING,
(WPARAM) ((int) -1), (LPARAM) wszT);
Assert(CB_ERR != iEntry);
// Set the privacy mark string.
// if given label has one, use it, else if policy provided one, use it,
wszT = const_cast<LPWSTR>(c_PolwszEmpty);
if (NULL != plabel) {
if (NULL != plabel->wszPrivacyMark) {
wszT = plabel->wszPrivacyMark;
}
}
else if (NULL != pwchPrivacyMark) {
wszT = pwchPrivacyMark;
}
SendDlgItemMessageW(hwndDlg, idcPrivacyMark, WM_SETTEXT, 0,
(LPARAM)(LPWSTR)wszT);
#if 0
iEntry = SelectCBItemWithData(hwndDlg, idcPolicyModule, (DWORD) pSsp);
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule, CB_SELECTSTRING,
(WPARAM) ((int) -1), (LPARAM) pSsp);
AssertSz(CB_ERR != iEntry, "Hey why is this policy module missing from the listbox");
#else
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule,
CB_SELECTSTRING,
(WPARAM) (-1),
(LPARAM) pSsp->wszPolicyName);
AssertSz(CB_ERR != iEntry, "Hey why is this policy module missing from the listbox");
// SetWindowLongPtr(hwndDlg, GWLP_USERDATA, iEntry);
#endif
// enable the controls.
EnableWindow(GetDlgItem(hwndDlg, idcPolicyModule), TRUE);
EnableWindow(GetDlgItem(hwndDlg, idcClassification), TRUE);
EnableWindow(GetDlgItem(hwndDlg, idcClassification+1), TRUE);
EnableWindow(GetDlgItem(hwndDlg, idcPrivacyMark), TRUE);
EnableWindow(GetDlgItem(hwndDlg, idcPrivacyMark+1), TRUE);
// the configure button is enabled if the policy module supports adv config.
EnableWindow(GetDlgItem(hwndDlg, idcConfigure),
(dwPolicyFlags & SMIME_POLICY_MODULE_SUPPORTS_ADV_CONFIG));
// Set the privacy mark as read-only if the policy says so.
if (dwPolicyFlags & SMIME_POLICY_MODULE_PRIVACYMARK_READONLY) {
fPrivMarkReadOnly = TRUE;
}
SendDlgItemMessage(hwndDlg, idcPrivacyMark, EM_SETREADONLY,
(WPARAM) fPrivMarkReadOnly, 0);
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, iEntry);
hr = S_OK;
// fall through to Exit;
Exit:
SecPolicyFree(pwszClassifications);
SecPolicyFree(pdwClassifications);
SecPolicyFree(pwchPrivacyMark);
return hr;
Error:
// Set <none> as the security label.
SideAssert(SUCCEEDED(HrSetLabelNone(hwndDlg, idcPolicyModule,
idcClassification, idcPrivacyMark, idcConfigure)));
goto Exit;
PolicyError:
AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSecPolicyErr), NULL, MB_OK | MB_ICONSTOP);
goto Error;
PolicyNotFoundError:
AthMessageBoxW(hwndDlg, MAKEINTRESOURCEW(idsAthenaMail),
MAKEINTRESOURCEW(idsSecPolicyNotFound), NULL, MB_OK | MB_ICONSTOP);
goto Error;
}
//
// Initialize the Security Labels info.
// Input:
// hwndDlg, idc's of controls. [in]
// LPSEditSecLabelHelper. [in].
// Returns: TRUE/FALSE
//
BOOL SecurityLabelsOnInitDialog(HWND hwndDlg, PSMIME_SECURITY_LABEL plabel,
INT idcPolicyModule, INT idcClassification,
INT idcPrivacyMark, INT idcConfigure)
{
BOOL fRet = FALSE;
HRESULT hr = E_FAIL;
PSMIME_SECURITY_POLICY pSsp = NULL;
ULONG iSsp;
LONG_PTR iEntry;
// Validate i/p params.
if ( ! IsWindow(hwndDlg) ) {
fRet = FALSE;
hr = E_INVALIDARG;
goto Error;
}
SendDlgItemMessage(hwndDlg, idcPrivacyMark, EM_LIMITTEXT,
(WPARAM)(MAX_PRIVACYMARK_LENGTH-1), 0);
// Check if any policies are registered.
if (! FPresentPolicyRegInfo()) {
// Just set label to none and return.
hr = S_OK;
fRet = TRUE;
goto SetLabelNone;
}
// Load the common names in the policy module listbox.
Assert(s_cSsp && s_rgSsp);
for (iSsp=0; iSsp<s_cSsp; iSsp++) {
// Add the policy module string to the lbox. (skip the default policy).
if (0 == lstrcmpi(s_rgSsp[iSsp].szPolicyOid, c_szDefaultPolicyOid)) {
continue;
}
iEntry = SendDlgItemMessageW(hwndDlg, idcPolicyModule,
CB_ADDSTRING, (WPARAM) 0,
(LPARAM) s_rgSsp[iSsp].wszPolicyName);
Assert(iEntry != CB_ERR);
SendDlgItemMessage(hwndDlg, idcPolicyModule, CB_SETITEMDATA,
(WPARAM) iEntry, (LPARAM) &s_rgSsp[iSsp]);
}
// If we already have a label in the security profile.
// then try to initialize that policy and that label.
if ((NULL != plabel) && (NULL != plabel->pszObjIdSecurityPolicy)) {
// Next 3 lines for O2KFed
// Set the label if the function fails it sets the label to None so ignore return
hr = HrSetLabel(hwndDlg, idcPolicyModule, idcClassification,
idcPrivacyMark, idcConfigure, pSsp, plabel);
if (FAILED(hr)) {
goto Error;
}
}
else {
// if we aren't given a label to initialize with, then set <none>
fRet = TRUE;
goto SetLabelNone;
}
fRet = TRUE;
goto Cleanup;
Error:
SetLabelNone:
hr = HrSetLabelNone(hwndDlg, idcPolicyModule, idcClassification,
idcPrivacyMark, idcConfigure);
Assert(SUCCEEDED(hr));
Cleanup:
return fRet;
}
//
// Given a null-terminated wide string, returns TRUE if it
// consists of only white wchars.
//
BOOL FIsWhiteStringW(LPWSTR wsz)
{
BOOL fRet = TRUE;
if (NULL != wsz) {
while (*wsz) {
if (! iswspace(*wsz) ) {
fRet = FALSE;
break;
}
wsz++;
}
}
return fRet;
}
//
// HrUpdateLabel
//
// Input:
// hwndDlg, idc's of various controls. [in]
// PSMIME_SECURITY_LABEL *pplabel [in/out].
//
// Updates pplabel with the information in the seclabel dlg.
//
HRESULT HrUpdateLabel(HWND hwndDlg, INT idcPolicyModule,
INT idcClassification, INT idcPrivacyMark,
INT idcConfigure, PSMIME_SECURITY_LABEL *pplabel)
{
HRESULT hr = E_FAIL;
LONG_PTR iEntry = 0;
LONG cwchT = 0;
WCHAR rgwchPrivacyMark[MAX_PRIVACYMARK_LENGTH];
PSMIME_SECURITY_LABEL plabelT = NULL;
PSMIME_SECURITY_POLICY pSsp = NULL;
BOOL fPolicyNotChanged = FALSE;
LPSTR szPolicyOid = NULL;
DWORD fHasClassification = FALSE;
DWORD dwClassification = 0;
LPWSTR wszPrivacyMark = NULL;
// validate i/p params.
if ( ! (hwndDlg && idcPolicyModule && idcClassification &&
idcPrivacyMark && idcConfigure && pplabel) ) {
AssertSz(FALSE, "HrUpdateLabel : Invalid args.");
hr = E_INVALIDARG;
goto Error;
}
if (NULL != *pplabel) {
hr = HrDupLabel(&plabelT, *pplabel);
if (FAILED(hr)) {
goto Error;
}
}
SecPolicyFree(*pplabel);
// Update with the new information.
// Get the policy and retrieve its oid.
iEntry = SendMessage(GetDlgItem(hwndDlg, idcPolicyModule),
CB_GETCURSEL, 0, 0);
if (iEntry == CB_ERR) {
AssertSz(FALSE, "HrUpdateLabel : No label selected");
goto Error;
}
pSsp = (PSMIME_SECURITY_POLICY)
SendDlgItemMessage(hwndDlg, idcPolicyModule,
CB_GETITEMDATA, iEntry, 0);
if (NULL == pSsp) {
hr = S_OK;
goto Exit;
}
if (NULL == pSsp->szPolicyOid) {
AssertSz(FALSE, "HrUpdateLabel : Invalid policy oid");
hr = E_FAIL;
goto Error;
}
szPolicyOid = pSsp->szPolicyOid;
// set the classification.
iEntry = SendMessage(GetDlgItem(hwndDlg, idcClassification),
CB_GETCURSEL, 0, 0);
if (CB_ERR != iEntry) {
dwClassification = (DWORD) SendDlgItemMessage(hwndDlg,
idcClassification, CB_GETITEMDATA, iEntry, 0);
fHasClassification = TRUE;
}
// set the privacy mark.
cwchT = GetDlgItemTextW(hwndDlg, idcPrivacyMark,
rgwchPrivacyMark, DimensionOf(rgwchPrivacyMark) - 1);
rgwchPrivacyMark[DimensionOf(rgwchPrivacyMark) - 1] = '\0'; // null terminate the string.
if ((0 < cwchT) && !FIsWhiteStringW(rgwchPrivacyMark)) {
wszPrivacyMark = rgwchPrivacyMark;
}
if ( (NULL != plabelT) && (NULL != plabelT->pszObjIdSecurityPolicy) ) {
fPolicyNotChanged = (0 == lstrcmpi(plabelT->pszObjIdSecurityPolicy, szPolicyOid));
}
hr = HrGetLabelFromData(pplabel, szPolicyOid, fHasClassification,
dwClassification, wszPrivacyMark,
(fPolicyNotChanged ? plabelT->cCategories : 0),
(fPolicyNotChanged ? plabelT->rgCategories : NULL) );
if (FAILED(hr)) {
goto Error;
}
hr = S_OK;
// fall through to Exit.
Exit:
SecLabelDecode.pfnFree(plabelT);
return hr;
Error:
SecPolicyFree(*pplabel);
goto Exit;
}
//
// OnChangePolicy.
//
// Input:
// hwndDlg. idc's for various controls. [in]
// iEntry. index of newly selected policy [in]
// PSMIME_SECURITY_LABEL pplabel [in/out]
//
//
//
BOOL OnChangePolicy(HWND hwndDlg, LONG_PTR iEntry, INT idcPolicyModule,
INT idcClassification, INT idcPrivacyMark,
INT idcConfigure, PSMIME_SECURITY_LABEL *pplabel)
{
BOOL fRet = FALSE;
HRESULT hr = E_FAIL;
PSMIME_SECURITY_POLICY pSsp = NULL;
// validate i/p params.
if (! (hwndDlg && idcPolicyModule && idcClassification &&
idcPrivacyMark && idcConfigure && pplabel) ) {
AssertSz(FALSE, "OnChangePolicy : Invalid args");
hr = E_INVALIDARG;
goto Error;
}
pSsp = (PSMIME_SECURITY_POLICY) SendDlgItemMessage(hwndDlg,
idcPolicyModule, CB_GETITEMDATA, iEntry, 0);
hr = HrSetLabel(hwndDlg, idcPolicyModule, idcClassification,
idcPrivacyMark, idcConfigure, pSsp, NULL);
if (FAILED(hr)) {
goto Error;
}
// update the label.
hr = HrUpdateLabel(hwndDlg, idcPolicyModule, idcClassification,
idcPrivacyMark, idcConfigure, pplabel);
if (FAILED(hr)) {
goto Error;
}
hr = S_OK;
// fall through to exit;
Exit:
return fRet;
Error:
SecPolicyFree(*pplabel);
goto Exit;
}
//
// Security Labels Dialog Proc.
//
// IN/OUT pplabel.
//
// Note: The caller is responsible for freeing the *pplabel.
//
INT_PTR CALLBACK SecurityLabelsDlgProc(HWND hwndDlg, UINT msg,
WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
LONG_PTR iEntry;
LONG_PTR iPrevEntry;
PSMIME_SECURITY_LABEL *pplabel;
switch ( msg) {
case WM_INITDIALOG:
// Remember the pselh we were handed.
pplabel = (PSMIME_SECURITY_LABEL *) lParam;
Assert(NULL !=pplabel);
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR) pplabel);
CenterDialog(hwndDlg);
return SecurityLabelsOnInitDialog(hwndDlg, *pplabel,
IDC_POLICY_COMBO /*IDC_SL_POLICYMODULE*/, IDC_CLASSIF_COMB/* IDC_SL_CLASSIFICATION*/,
IDC_PRIVACY_EDIT/*IDC_SL_PRIVACYMARK*/, IDC_CONFIGURE/*IDC_SL_CONFIGURE*/);
break;
case WM_COMMAND:
pplabel = (PSMIME_SECURITY_LABEL *) GetWindowLongPtr(hwndDlg, DWLP_USER);
Assert(NULL != pplabel);
switch (LOWORD(wParam)) {
case IDC_POLICY_COMBO:
switch (HIWORD(wParam)) {
case CBN_SELENDOK:
case CBN_SELCHANGE:
iEntry = SendMessage(GetDlgItem(hwndDlg, IDC_POLICY_COMBO),
CB_GETCURSEL, 0, 0);
iPrevEntry = GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
if ((iEntry != CB_ERR) && (iEntry != iPrevEntry)) {
return OnChangePolicy(hwndDlg, iEntry, IDC_POLICY_COMBO,
IDC_CLASSIF_COMB, IDC_PRIVACY_EDIT,
IDC_CONFIGURE, pplabel);
}
break;
default:
return FALSE;
break;
}
break;
case IDC_CONFIGURE:
if ((NULL != *pplabel) && (NULL != (*pplabel)->pszObjIdSecurityPolicy)) {
SpISMimePolicyFullEdit spspfe;
hr = HrQueryPolicyInterface(0, (*pplabel)->pszObjIdSecurityPolicy,
IID_ISMimePolicyFullEdit,
(LPVOID *) &spspfe);
if (SUCCEEDED(hr)) {
hr = spspfe->DoAdvancedEdit(0, hwndDlg, pplabel);
if (SUCCEEDED(hr)) {
Assert(NULL != *pplabel);
hr = HrSetLabel(hwndDlg, IDC_POLICY_COMBO,
IDC_CLASSIF_COMB, IDC_PRIVACY_EDIT,
IDC_CONFIGURE, NULL, *pplabel);
Assert(SUCCEEDED(hr));
}
}
}
break;
case IDC_CLASSIF_COMB:
break;
case IDC_PRIVACY_EDIT:
break;
case IDOK:
hr = HrUpdateLabel(hwndDlg, IDC_POLICY_COMBO,
IDC_CLASSIF_COMB, IDC_PRIVACY_EDIT,
IDC_CONFIGURE, pplabel);
EndDialog(hwndDlg, IDOK);
break;
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
default:
return FALSE;
break;
}
break;
case WM_CONTEXTMENU:
case WM_HELP:
return OnContextHelp(hwndDlg, msg, wParam, lParam, g_rgCtxSecLabel);
break;
default:
return FALSE;
break;
}
return TRUE;
}
/////////////////////////////////
// Misc Label Utility fns.
/////////////////////////////////
//
// "Stringize" a given security label.
// Note: The caller must free the returned buffer pwszLabel with SecPolicyFree().
//
HRESULT HrGetStringizedLabel(PSMIME_SECURITY_LABEL plabel, LPWSTR *pwszLabel)
{
HRESULT hr = E_FAIL;
SpISMimePolicyLabelInfo spspli;
if ((NULL == plabel) || (NULL == pwszLabel) || (NULL == plabel->pszObjIdSecurityPolicy)) {
hr = E_INVALIDARG;
goto Error;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyLabelInfo,
(LPVOID *) &spspli);
if (FAILED(hr) || !(spspli)) {
goto Error;
}
// Get the stringized label.
hr = spspli->GetStringizedLabel(0, plabel, pwszLabel);
if (FAILED(hr)) {
goto Error;
}
// fall through to ExitHere.
ExitHere:
return hr;
Error:
goto ExitHere;
}
// mbcs version of above fn.
HRESULT HrGetStringizedLabelA(PSMIME_SECURITY_LABEL plabel, LPSTR *pszLabel)
{
HRESULT hr;
LPSTR pchLabel = NULL;
LPWSTR pwchLabel = NULL;
int cch, cchT;
// validate i/p params.
if ((NULL == plabel) || (NULL == pszLabel)) {
hr = E_INVALIDARG;
goto Error;
}
*pszLabel = NULL;
// get the wide-stringized label.
hr = HrGetStringizedLabel(plabel, &pwchLabel);
if (FAILED(hr)) {
goto Error;
}
// conver to an mbcs string.
cch = WideCharToMultiByte(CP_ACP, 0, pwchLabel, -1, NULL, 0, NULL, NULL);
if (0 == cch) {
hr = E_FAIL;
goto Error;
}
pchLabel = (LPSTR) SecPolicyAlloc(cch);
if (NULL == pchLabel) {
hr = E_OUTOFMEMORY;
goto Error;
}
cchT = WideCharToMultiByte(CP_ACP, 0, pwchLabel, -1, pchLabel, cch, NULL, NULL);
Assert(cch == cchT);
if (0 == cchT) {
Assert(FALSE);
hr = E_FAIL;
goto Error;
}
// success.
*pszLabel = pchLabel;
hr = S_OK;
ExitHere:
SecPolicyFree(pwchLabel);
return hr;
Error:
SecPolicyFree(pchLabel);
goto ExitHere;
}
//
// Given a policy oid, return its policy flags.
//
HRESULT HrGetPolicyFlags(LPSTR szPolicyOid, LPDWORD pdwFlags)
{
HRESULT hr = S_OK;
DWORD dwFlags;
SpISMimePolicySimpleEdit spspse;
// validate i/p parameters.
if ((NULL == szPolicyOid) || (NULL == pdwFlags)) {
hr = E_INVALIDARG;
goto Error;
}
*pdwFlags = 0;
// Get the reqd interface.
hr = HrQueryPolicyInterface(0, szPolicyOid, IID_ISMimePolicySimpleEdit,
(LPVOID *) &spspse);
if (FAILED(hr) || !(spspse)) {
goto Error;
}
// Get the policy flags.
hr = spspse->GetPolicyInfo(0, &dwFlags);
if (FAILED(hr)) {
goto Error;
}
// success, set return values.
*pdwFlags = dwFlags;
Exit:
return hr;
Error:
goto Exit;
}
//
// "Validate" a given security label and sender cert on Edit.
// The pplabel MAY be modified by the security policy.
//
HRESULT HrValidateLabelOnEdit(PSMIME_SECURITY_LABEL *pplabel, HWND hwndParent,
PCCERT_CONTEXT pccertSign, PCCERT_CONTEXT pccertKeyEx)
{
HRESULT hr = E_FAIL;
DWORD dwFlags = 0;
SpISMimePolicySimpleEdit spspse;
SpISMimePolicyValidateSend spspvs;
// Validate i/p parameters.
if ((NULL == pplabel) || (NULL == hwndParent) ||
(NULL == pccertSign) || (NULL == pccertKeyEx)) {
hr = E_INVALIDARG;
goto Error;
}
if (NULL == *pplabel) {
hr = S_OK;
goto Exit;
}
// Find out if the policy requires sender/recipient cert validation.
hr = HrQueryPolicyInterface(0, (*pplabel)->pszObjIdSecurityPolicy,
IID_ISMimePolicySimpleEdit, (LPVOID *) &spspse);
if (FAILED(hr) || !(spspse)) {
goto Error;
}
// Query the policy to see if the label is valid.
hr = spspse->IsLabelValid(0, hwndParent, pplabel);
if (FAILED(hr) || (NULL == *pplabel)) {
goto Error;
}
// get the policy flags.
hr = HrGetPolicyFlags((*pplabel)->pszObjIdSecurityPolicy, &dwFlags);
if (FAILED(hr)) {
goto Error;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, (*pplabel)->pszObjIdSecurityPolicy, IID_ISMimePolicyValidateSend,
(LPVOID *) &spspvs);
if (FAILED(hr) || !(spspvs)) {
goto Error;
}
// verify that the signing cert is allowed by the security policy.
if ((dwFlags & SMIME_POLICY_MODULE_VALIDATE_SENDER) && (NULL != pccertSign)) {
hr = spspvs->IsValidLabelSignerCert(0, hwndParent, *pplabel, pccertSign);
if (FAILED(hr)) {
goto Error;
}
}
// verify that the recipient certs are allowed by the security policy.
if ( (dwFlags & SMIME_POLICY_MODULE_VALIDATE_RECIPIENT) &&
(NULL != pccertKeyEx) ) {
//$ M00Bug:
// ValidateRecipient && !pccertKeyEx should probably be an error.
hr = spspvs->IsValidLabelRecipientCert(0, hwndParent, *pplabel, pccertKeyEx);
if (FAILED(hr)) {
goto Error;
}
}
// success. fall through to exit.
Exit:
Error:
return hr;
}
//
// "Validate" a given security label and recipient cert.
//
HRESULT HrValidateLabelRecipCert(PSMIME_SECURITY_LABEL plabel, HWND hwndParent,
PCCERT_CONTEXT pccertRecip)
{
HRESULT hr = S_OK;
DWORD dwFlags;
SpISMimePolicyValidateSend spspvs;
// Validate i/p parameters.
if ((NULL == plabel) || (NULL == pccertRecip)) {
hr = E_INVALIDARG;
goto Error;
}
// get the policy flags.
hr = HrGetPolicyFlags(plabel->pszObjIdSecurityPolicy, &dwFlags);
if (FAILED(hr)) {
goto Error;
}
// see if we need to validate sender.
if (! (dwFlags & SMIME_POLICY_MODULE_VALIDATE_RECIPIENT) ) {
// No Recipient validation is required.
hr = S_OK;
goto ExitHere;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyValidateSend,
(LPVOID *) &spspvs);
if (FAILED(hr) || !(spspvs)) {
goto Error;
}
// verify that the recipient certs are allowed by the security policy.
hr = spspvs->IsValidLabelRecipientCert(0, hwndParent, plabel, pccertRecip);
if (FAILED(hr)) {
goto Error;
}
// fall through to ExitHere.
ExitHere:
return hr;
Error:
goto ExitHere;
}
//
// "Validate" a given security label and signer cert.
//
HRESULT HrValidateLabelSignerCert(PSMIME_SECURITY_LABEL plabel, HWND hwndParent,
PCCERT_CONTEXT pccertSigner)
{
HRESULT hr = S_OK;
DWORD dwFlags;
SpISMimePolicyValidateSend spspvs;
// Validate i/p parameters.
if ((NULL == plabel) || (NULL == pccertSigner)) {
hr = E_INVALIDARG;
goto Error;
}
// get the policy flags.
hr = HrGetPolicyFlags(plabel->pszObjIdSecurityPolicy, &dwFlags);
if (FAILED(hr)) {
goto Error;
}
// see if we need to validate sender.
if (! (dwFlags & SMIME_POLICY_MODULE_VALIDATE_SENDER) ) {
// No Recipient validation is required.
hr = S_OK;
goto ExitHere;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyValidateSend,
(LPVOID *) &spspvs);
if (FAILED(hr) || !(spspvs)) {
goto Error;
}
// verify that the signer certs are allowed by the security policy.
hr = spspvs->IsValidLabelSignerCert(0, hwndParent, plabel, pccertSigner);
if (FAILED(hr)) {
goto Error;
}
// fall through to ExitHere.
ExitHere:
return hr;
Error:
goto ExitHere;
}
//
// "Validate" a given security label and certs.
//
HRESULT HrValidateLabelOnSend(PSMIME_SECURITY_LABEL plabel, HWND hwndParent,
PCCERT_CONTEXT pccertSign,
ULONG ccertRecip, PCCERT_CONTEXT *rgccertRecip)
{
HRESULT hr = S_OK;
DWORD dwFlags;
ULONG icert;
SpISMimePolicyValidateSend spspvs;
// Validate i/p parameters.
if ((NULL == plabel) || (NULL == pccertSign)) {
hr = E_INVALIDARG;
goto Error;
}
// get the policy flags.
hr = HrGetPolicyFlags(plabel->pszObjIdSecurityPolicy, &dwFlags);
if (FAILED(hr)) {
goto Error;
}
// see if we need to validate sender and/or recipient(s).
if (! (dwFlags &
(SMIME_POLICY_MODULE_VALIDATE_SENDER | SMIME_POLICY_MODULE_VALIDATE_RECIPIENT)) ) {
// No Sender/Recipient validation is required.
hr = S_OK;
goto ExitHere;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyValidateSend,
(LPVOID *) &spspvs);
if (FAILED(hr) || !(spspvs)) {
goto Error;
}
// verify that the signing cert is allowed by the security policy.
if ((dwFlags & SMIME_POLICY_MODULE_VALIDATE_SENDER) && (NULL != pccertSign)) {
hr = spspvs->IsValidLabelSignerCert(0, hwndParent, plabel, pccertSign);
if (FAILED(hr)) {
goto Error;
}
}
// verify that the recipient certs are allowed by the security policy.
if ( (dwFlags & SMIME_POLICY_MODULE_VALIDATE_RECIPIENT) &&
(0 < ccertRecip) && (NULL != rgccertRecip) ) {
for (icert=0; icert<ccertRecip; icert++) {
hr = spspvs->IsValidLabelRecipientCert(0, hwndParent, plabel, rgccertRecip[icert]);
if (FAILED(hr)) {
goto Error;
}
}
}
// fall through to ExitHere.
ExitHere:
return hr;
Error:
goto ExitHere;
}
//
// Does the admin force a security label on all S/MIME signed messages?
//
BOOL FForceSecurityLabel(void)
{
enum EForceLabel {
FORCELABEL_UNINIT = 0,
FORCELABEL_YES = 1,
FORCELABEL_NO = 2 };
static EForceLabel eForceLabel = FORCELABEL_UNINIT; // uninitialized.
if (!IsSMIME3Supported()) {
return FALSE;
}
if (eForceLabel == FORCELABEL_UNINIT) {
DWORD dwDefault = 0;
DWORD dwForceLabel = 0;
DWORD dwType;
LPBYTE pb = (LPBYTE) &dwForceLabel;
ULONG cb = sizeof(dwForceLabel);
static const CHAR SzForceSecurityLabel[] = "ForceSecurityLabel";
// Get our Admin key and check if we should enable Fed Features.
if (FAILED(HrQueryRegValue(0, (LPSTR) SzForceSecurityLabel, &dwType,
&pb, &cb, REG_DWORD, (LPBYTE) &dwDefault,
sizeof(dwDefault))) ||
(dwType != REG_DWORD) ) {
dwForceLabel = dwDefault;
}
if (dwForceLabel != 0) {
eForceLabel = FORCELABEL_YES;
}
else {
eForceLabel = FORCELABEL_NO;
}
}
return (eForceLabel == FORCELABEL_YES);
}
//
// Get the label we are forced to us by the admin
//
HRESULT HrGetForcedSecurityLabel(PSMIME_SECURITY_LABEL* ppLabel)
{
ULONG cb = 0;
DWORD dwType;
HRESULT hr = S_OK;
LPBYTE pbLabel = NULL;
PSMIME_SECURITY_LABEL pLabel = NULL;
static const CHAR SzForceSecurityLabelX[] = "ForceSecurityLabelX";
*ppLabel = NULL;
if (FForceSecurityLabel()) {
hr = HrQueryRegValue(0, (LPSTR) SzForceSecurityLabelX, &dwType,
&pbLabel, &cb, REG_BINARY, NULL, 0);
if (SUCCEEDED(hr) && (dwType == REG_BINARY)) {
DWORD cbLabel = 0;
hr = HrDecodeAndAllocLabel(pbLabel, cb,
&pLabel, &cbLabel);
if (SUCCEEDED(hr)) {
*ppLabel = pLabel;
pLabel = NULL;
}
}
}
if (pbLabel != NULL) free(pbLabel);
SecPolicyFree(pLabel);
return hr;
}
// Given a label, load its policy and show the read-only
// label info dialog.
HRESULT HrDisplayLabelInfo(HWND hwndParent, PSMIME_SECURITY_LABEL plabel)
{
HRESULT hr = E_FAIL;
SpISMimePolicyLabelInfo spspli;
// validate i/p params.
if ((NULL == plabel) || (NULL == plabel->pszObjIdSecurityPolicy)) {
hr = E_INVALIDARG;
goto Error;
}
// load the policy and get the reqd interface.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy,
IID_ISMimePolicyLabelInfo, (LPVOID *) &spspli);
if (FAILED(hr)) {
// the policy OR the reqd intf wasn't found.
goto Error;
}
// Display the label-info dlg.
hr = spspli->DisplayAdvancedLabelProperties(0, hwndParent, plabel);
if (FAILED(hr)) {
goto Error;
}
// success.
hr = S_OK;
Exit:
return hr;
Error:
goto Exit;
}
DWORD DetermineCertUsageWithLabel(PCCERT_CONTEXT pccert, PSMIME_SECURITY_LABEL pLabel)
{
DWORD dwUsage = 0;
HRESULT hr;
Assert(NULL != pccert);
Assert(NULL != pLabel);
hr = HrGetCertKeyUsage(pccert, &dwUsage);
if (S_OK != hr) {
goto Exit;
}
if (0 != (KEY_USAGE_SIGNING & dwUsage)) {
hr = HrValidateLabelSignerCert(pLabel, NULL, pccert);
if (FAILED(hr)) {
dwUsage &= (~KEY_USAGE_SIGNING);
}
}
if (0 != (KEY_USAGE_ENCRYPTION & dwUsage)) {
hr = HrValidateLabelRecipCert(pLabel, NULL, pccert);
if (FAILED(hr)) {
dwUsage &= (~KEY_USAGE_ENCRYPTION);
}
}
Exit:
return dwUsage;
}
// Create default label, if it's not exist
HRESULT HrGetDefaultLabel(PSMIME_SECURITY_LABEL *pplabel)
{
SpISMimePolicySimpleEdit spspse = NULL;
WCHAR *pwchPrivacyMark = NULL;
DWORD dwT = 0;
// Load the info from the registry if reqd.
HRESULT hr = _HrEnsurePolicyRegInfoLoaded(0);
if (FAILED(hr)) {
goto Error;
}
// If we haven any installed policies, search for the one we want.
if (FPresentPolicyRegInfo())
{
if(s_cSsp > 0)
{
// if it is already loaded, then we are done.
hr = HrQueryPolicyInterface(0, s_rgSsp[0].szPolicyOid, IID_ISMimePolicySimpleEdit,
(LPVOID *) & spspse);
if (FAILED(hr))
{
goto Error;
}
hr = spspse->GetDefaultPolicyInfo(0, &dwT, &pwchPrivacyMark);
if (FAILED(hr))
{
goto Error;
}
hr = HrGetLabelFromData(pplabel,
s_rgSsp[0].szPolicyOid,
TRUE, // fHasClassification,
dwT, // dwClassification,
pwchPrivacyMark, // wszPrivacyMark,
0, NULL);
}
}
Error:
// Cleanup:
if(pwchPrivacyMark)
SecPolicyFree(pwchPrivacyMark);
#ifdef YST // We don't need to relase spspse, because we use SpISMIME...(ATL does ecerything)
if(spspse)
{
spspse->Release();
}
#endif //YST
return hr;
}
// Check label in registry, is not exist then return default label
HRESULT HrGetOELabel(PSMIME_SECURITY_LABEL *pplabel)
{
HRESULT hr = E_FAIL;
LPWSTR pwchPolicyName = NULL;
LPWSTR pwchPrivacyMark = NULL;
LPBYTE pbCategory = NULL;
CRYPT_ATTRIBUTE_TYPE_VALUE *pCategories = NULL;
DWORD cCat =0;
DWORD dwSize;
TCHAR *pchPolicyName = NULL;
DWORD dwT = 0;
if(NULL == pplabel)
{
hr = E_INVALIDARG;
goto Error;
}
dwSize = DwGetOption(OPT_POLICYNAME_SIZE);
// if policy name is not set
if(dwSize <= 0)
return(HrGetDefaultLabel(pplabel));
if(!MemAlloc((LPVOID *)&pchPolicyName, dwSize + 1))
return(HrGetDefaultLabel(pplabel));
if( GetOption(OPT_POLICYNAME_DATA, pchPolicyName, dwSize) != dwSize)
{
hr = HrGetDefaultLabel(pplabel);
goto Error;
}
// get privacy mark
dwSize = DwGetOption(OPT_PRIVACYMARK_SIZE);
if(dwSize > 0)
{
if(MemAlloc((LPVOID *)&pwchPrivacyMark, (dwSize * sizeof(WCHAR)) + 1))
GetOption(OPT_PRIVACYMARK_DATA, pwchPrivacyMark, (dwSize * sizeof(WCHAR)));
}
// get category
dwSize = DwGetOption(OPT_CATEGORY_SIZE);
if(dwSize > 0)
{
if(MemAlloc((LPVOID *)&pbCategory, (dwSize * sizeof(BYTE))))
{
if(GetOption(OPT_CATEGORY_DATA, pbCategory, (dwSize * sizeof(BYTE))))
{
hr = BinaryToCategories(&pCategories, &cCat, pbCategory);
if(FAILED(hr))
goto Error;
}
}
}
// get classification
dwSize = DwGetOption(OPT_HAS_CLASSIFICAT);
if(dwSize > 0)
dwT = DwGetOption(OPT_CLASSIFICAT_DATA);
hr = HrGetLabelFromData(pplabel,
pchPolicyName,
dwSize, // fHasClassification,
dwT, // dwClassification,
pwchPrivacyMark, // wszPrivacyMark,
cCat,
pCategories);
Error:
if(cCat > 0)
{
UINT i;
for(i = 0; i < cCat; i++)
{
MemFree(pCategories[i].pszObjId);
MemFree(pCategories[i].Value.pbData);
}
MemFree(pCategories);
}
MemFree(pwchPrivacyMark);
MemFree(pbCategory);
MemFree(pchPolicyName);
return hr;
}
// Save label in registry
HRESULT HrSetOELabel(PSMIME_SECURITY_LABEL plabel)
{
HRESULT hr = E_FAIL;
LPWSTR pwchPolicyName = NULL;
LPWSTR pwchClassification = NULL;
LPWSTR pwchPrivacyMark = NULL;
LPWSTR pwchCategory = NULL;
DWORD dwSize;
BYTE *pArray = NULL;
int Size = 0;
SpISMimePolicyLabelInfo spspli;
if ((NULL == plabel) || (NULL == plabel->pszObjIdSecurityPolicy))
{
hr = E_INVALIDARG;
goto Error;
}
// Get the required interface to the policy module.
hr = HrQueryPolicyInterface(0, plabel->pszObjIdSecurityPolicy, IID_ISMimePolicyLabelInfo,
(LPVOID *) &spspli);
if (FAILED(hr) || !(spspli))
{
goto Error;
}
// get label as strings
hr = spspli->GetLabelAsStrings(0, plabel, &pwchPolicyName, &pwchClassification, &pwchPrivacyMark, &pwchCategory);
if (FAILED(hr))
goto Error;
// save Policy name
if(pwchPolicyName == NULL)
{
Assert(FALSE);
goto Error;
}
dwSize = lstrlen(plabel->pszObjIdSecurityPolicy) + 1;
SetDwOption(OPT_POLICYNAME_SIZE, dwSize, NULL, 0);
SetOption(OPT_POLICYNAME_DATA, plabel->pszObjIdSecurityPolicy, dwSize, NULL, 0);
// Save Classification
SetDwOption(OPT_HAS_CLASSIFICAT, plabel->fHasClassification, NULL, 0);
if(plabel->fHasClassification)
SetDwOption(OPT_CLASSIFICAT_DATA, plabel->dwClassification, NULL, 0);
// Save Privacy mark
dwSize = pwchPrivacyMark ? (wcslen(pwchPrivacyMark) + 1) : 0;
SetDwOption(OPT_PRIVACYMARK_SIZE, dwSize, NULL, 0);
if(dwSize)
SetOption(OPT_PRIVACYMARK_DATA, pwchPrivacyMark, dwSize*sizeof(WCHAR), NULL, 0);
// Save Category
hr = CategoriesToBinary(plabel, &pArray, &Size);
if(FAILED(hr))
goto Error;
SetDwOption(OPT_CATEGORY_SIZE, Size, NULL, 0);
if(Size)
SetOption(OPT_CATEGORY_DATA, pArray, Size*sizeof(BYTE), NULL, 0);
Error:
MemFree(pArray);
SecPolicyFree(pwchPolicyName);
SecPolicyFree(pwchClassification);
SecPolicyFree(pwchPrivacyMark);
SecPolicyFree(pwchCategory);
return hr;
}
//// QueryRegistry
//
// Description:
// This is a common function which should be used to get information from the
// registry in most cases. It will look in both the HLKM and HKCU registries
// as requested.
//
// M00TODO -- Should check for errors and distinguish between denied and
// non-existance.
//
HRESULT HrQueryRegValue(DWORD dwFlags, LPSTR szRegKey, LPDWORD pdwType,
LPBYTE * ppbData, LPDWORD pcbData, DWORD dwDefaultType,
LPBYTE pbDefault, DWORD cbDefault)
{
DWORD cbData;
HKEY hKey;
DWORD l;
LPBYTE pbData;
//
// Start by getting the Local Machine first if possible
//
if (!(dwFlags & QRV_Suppress_HKLM)) {
//
// Open the key if it exists
//
l = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SzRegSecurity, 0, KEY_QUERY_VALUE,
&hKey);
//
// If we succeed in opening the key, then we will look for the value
//
if (l == ERROR_SUCCESS) {
//
// If they passed in a size, then we use that as the size, otherwise
// we need to find the size of the object to be used
//
if ((pcbData != NULL) && (*pcbData != 0)) {
cbData = *pcbData;
pbData = *ppbData;
}
else {
cbData = 0;
pbData = NULL;
}
//
// Query for the actual value.
//
l = RegQueryValueEx(hKey, szRegKey, NULL, pdwType, pbData, &cbData);
//
// On success -- return the value
//
if (l == ERROR_SUCCESS) {
if ((pcbData == NULL) || (*pcbData == 0)) {
pbData = (LPBYTE) malloc(cbData);
if (pbData == NULL) {
RegCloseKey(hKey);
return E_OUTOFMEMORY;
}
l = RegQueryValueEx(hKey, szRegKey, NULL, pdwType, pbData, &cbData);
RegCloseKey(hKey);
if (l == ERROR_SUCCESS) {
if (pcbData != NULL) {
*pcbData = cbData;
}
*ppbData = pbData;
return S_OK;
}
free(pbData);
return 0x80070000 | l;
}
if (pcbData != NULL) {
*pcbData = cbData;
}
RegCloseKey(hKey);
return S_OK;
}
else if (l != ERROR_FILE_NOT_FOUND) {
RegCloseKey(hKey);
return 0x80070000 | l;
}
RegCloseKey(hKey);
}
//
// If we failed to open the key for some reason other than non-presence,
// return that error
//
else if (l != ERROR_FILE_NOT_FOUND) {
return 0x80070000 | l;
}
//
// Not found error -- try the next registry object
//
}
//
// Start by getting the Local Machine first if possible
//
if (!(dwFlags & QRV_Suppress_HKCU)) {
//
// Open the key if it exists
//
l = RegOpenKeyEx(HKEY_CURRENT_USER, SzRegSecurity, 0, KEY_QUERY_VALUE, &hKey);
//
// If we succeed in opening the key, then we will look for the value
//
if (l == ERROR_SUCCESS) {
//
// If they passed in a size, then we use that as the size, otherwise
// we need to find the size of the object to be used
//
if ((pcbData != NULL) && (*pcbData != 0)) {
cbData = *pcbData;
pbData = *ppbData;
}
else {
cbData = 0;
pbData = NULL;
}
//
// Query for the actual value.
//
l = RegQueryValueEx(hKey, szRegKey, NULL, pdwType, pbData, &cbData);
//
// On success -- return the value
//
if (l == ERROR_SUCCESS) {
if ((pcbData == NULL) || (*pcbData == 0)) {
pbData = (LPBYTE) malloc(cbData);
if (pbData == NULL) {
RegCloseKey(hKey);
return E_OUTOFMEMORY;
}
l = RegQueryValueEx(hKey, szRegKey, NULL, pdwType, pbData, &cbData);
RegCloseKey(hKey);
if (l == ERROR_SUCCESS) {
if (pcbData != NULL) {
*pcbData = cbData;
}
*ppbData = pbData;
return S_OK;
}
free(pbData);
return 0x80070000 | l;
}
if (pcbData != NULL) {
*pcbData = cbData;
}
RegCloseKey(hKey);
return S_OK;
}
else if (l != ERROR_FILE_NOT_FOUND) {
RegCloseKey(hKey);
return 0x80070000 | l;
}
RegCloseKey(hKey);
}
//
// If we failed to open the key for some reason other than non-presence,
// return that error
//
else if (l != ERROR_FILE_NOT_FOUND) {
return 0x80070000 | l;
}
//
// Not found error -- try the next registry object
//
}
//
// No value found, return the default value if it is present
//
if (pbDefault == NULL) {
return 0x80070000 | ERROR_FILE_NOT_FOUND; // Not found
}
if ((pcbData != NULL) && (*pcbData != 0) && (cbDefault > *pcbData)) {
return 0x80070000 | ERROR_MORE_DATA;
}
if ((pcbData != NULL) && (*pcbData == 0)) {
*ppbData = (LPBYTE) malloc(cbDefault);
if (*ppbData == NULL) {
return E_OUTOFMEMORY;
}
}
memcpy(*ppbData, pbDefault, cbDefault);
if (pcbData != NULL) *pcbData = cbDefault;
if (pdwType != NULL) *pdwType = dwDefaultType;
return S_OK;
}
HRESULT CategoriesToBinary(PSMIME_SECURITY_LABEL plabel, BYTE * *ppArray, int *cbSize)
{
HRESULT hr = S_OK;
int i = 0;
PCRYPT_ATTRIBUTE_TYPE_VALUE pcatv = NULL;
LPBYTE pv = NULL;
int size;
// pArray = NULL;
*cbSize = 0;
if(plabel->cCategories == 0)
return S_OK;
// Find size of memory that we need
size = sizeof(int);
for (i = 0; i < ((int) plabel->cCategories); i++)
{
pcatv = & (plabel->rgCategories[i]);
size += sizeof(int);
size += lstrlen(pcatv->pszObjId) + 1;
size += sizeof(DWORD);
size += pcatv->Value.cbData;
}
Assert(size > sizeof(int));
// allocate the required memory.
if(!MemAlloc((LPVOID *)ppArray, size*sizeof(BYTE)))
return E_OUTOFMEMORY;
*cbSize = size;
// construct array
pv = *ppArray;
memcpy(pv, &(plabel->cCategories), sizeof(DWORD));
pv += sizeof(DWORD);
for (i = 0; i < ((int) plabel->cCategories); i++)
{
pcatv = & (plabel->rgCategories[i]);
size = lstrlen(pcatv->pszObjId);
memcpy(pv, &size, sizeof(int));
pv += sizeof(int);
memcpy(pv, pcatv->pszObjId, size);
pv += size;
memcpy(pv, &(pcatv->Value.cbData), sizeof(DWORD));
pv += sizeof(DWORD);
memcpy(pv, pcatv->Value.pbData, pcatv->Value.cbData);
pv += pcatv->Value.cbData;
}
return(S_OK);
}
HRESULT BinaryToCategories(CRYPT_ATTRIBUTE_TYPE_VALUE ** ppCategories, DWORD *cCat, BYTE * pArray)
{
HRESULT hr = S_OK;
int i = 0;
PCRYPT_ATTRIBUTE_TYPE_VALUE pcatv = NULL;
LPBYTE pv = pArray;
int size;
DWORD dwVal = 0;
// Number of elements in array
memcpy(&dwVal, pv, sizeof(DWORD));
pv += sizeof(DWORD);
Assert(dwVal > 0);
// Allocate memory for array of categories
if(!MemAlloc((LPVOID *)ppCategories, dwVal*sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE)))
return E_OUTOFMEMORY;
*cCat = dwVal;
// construct array
for (i = 0; i < ((int) *cCat); i++)
{
pcatv = &((*ppCategories)[i]);
// pszObjId is ANSI string
memcpy(&size, pv, sizeof(int));
pv += sizeof(int);
if(!MemAlloc((LPVOID *)&(pcatv->pszObjId), size*sizeof(CHAR)+1))
return E_OUTOFMEMORY;
memcpy(pcatv->pszObjId, pv, size);
pcatv->pszObjId[size] = '\0';
pv += size;
// Value
memcpy(&dwVal, pv, sizeof(DWORD));
pv += sizeof(DWORD);
pcatv->Value.cbData = dwVal;
if(!MemAlloc((LPVOID *)&(pcatv->Value.pbData), dwVal*sizeof(BYTE)))
return E_OUTOFMEMORY;
memcpy(pcatv->Value.pbData, pv, dwVal);
pv += dwVal;
}
return(S_OK);
}