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.
397 lines
11 KiB
397 lines
11 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// IdentityHelper.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// This file defines the class IdentityHelper.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "ias.h"
|
|
#include "iaslsa.h"
|
|
#include "memory"
|
|
#include "samutil.h"
|
|
#include "identityhelper.h"
|
|
|
|
#define STRSAFE_NO_DEPRECATE
|
|
#include <strsafe.h>
|
|
|
|
|
|
bool IdentityHelper::initialized = false;
|
|
|
|
|
|
/////////
|
|
// Registry keys and values.
|
|
/////////
|
|
const WCHAR PARAMETERS_KEY[] =
|
|
L"SYSTEM\\CurrentControlSet\\Services\\RemoteAccess\\Policy";
|
|
|
|
const WCHAR IDENTITY_ATTR_VALUE[] = L"User Identity Attribute";
|
|
const WCHAR DEFAULT_IDENTITY_VALUE[] = L"Default User Identity";
|
|
const WCHAR OVERRIDE_USERNAME_VALUE[] = L"Override User-Name";
|
|
|
|
HRESULT IdentityHelper::IASReadRegistryDword(
|
|
HKEY& hKey,
|
|
PCWSTR valueName,
|
|
DWORD defaultValue,
|
|
DWORD* result
|
|
)
|
|
{
|
|
_ASSERT (result != 0);
|
|
|
|
DWORD cbData = sizeof(DWORD);
|
|
DWORD type;
|
|
LONG status = RegQueryValueExW(
|
|
hKey,
|
|
valueName,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)result,
|
|
&cbData
|
|
);
|
|
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
if (status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
IASTracePrintf("Cannot read value %S. error %ld",
|
|
valueName,
|
|
status
|
|
);
|
|
return HRESULT_FROM_WIN32(status);
|
|
}
|
|
else
|
|
{
|
|
// The attribute does not exist. Set the default
|
|
IASTracePrintf("The registry value %S does not exist. Using default %ld",
|
|
valueName,
|
|
defaultValue
|
|
);
|
|
*result = defaultValue;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
if (type != REG_DWORD || cbData != sizeof(DWORD))
|
|
{
|
|
IASTracePrintf("Cannot read value %S. Wrong type %ld. Size = %ld",
|
|
valueName,
|
|
type,
|
|
cbData
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// IdentityHelper::initialize
|
|
// CAUTION: calls to this API MUST be serialized.
|
|
// i.e. the handler's calling MapNAme::Initialize MUST complete a successful
|
|
// init of each handler's before calling the Init of the next one.
|
|
//
|
|
HRESULT IdentityHelper::initialize() throw()
|
|
{
|
|
if (initialized)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// Open the Parameters registry key.
|
|
HKEY hKey = (HKEY) INVALID_HANDLE_VALUE;
|
|
LONG status = RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE,
|
|
PARAMETERS_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
IASTracePrintf("Cannot open the reg key %S, error %ld",
|
|
PARAMETERS_KEY,
|
|
status
|
|
);
|
|
return HRESULT_FROM_WIN32(status);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
do
|
|
{
|
|
// Query the Identity Attribute.
|
|
hr = IASReadRegistryDword(
|
|
hKey,
|
|
IDENTITY_ATTR_VALUE,
|
|
RADIUS_ATTRIBUTE_USER_NAME,
|
|
&identityAttr
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Query the Override User-Name flag.
|
|
hr = IASReadRegistryDword(
|
|
hKey,
|
|
OVERRIDE_USERNAME_VALUE,
|
|
FALSE,
|
|
&overrideUsername
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
DWORD type;
|
|
|
|
// Query the length of the Default Identity.
|
|
defaultLength = 0;
|
|
status = RegQueryValueExW(
|
|
hKey,
|
|
DEFAULT_IDENTITY_VALUE,
|
|
NULL,
|
|
&type,
|
|
NULL,
|
|
&defaultLength
|
|
);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
if (status != ERROR_FILE_NOT_FOUND)
|
|
{
|
|
IASTracePrintf("Cannot read value %S. error %ld",
|
|
DEFAULT_IDENTITY_VALUE,
|
|
status
|
|
);
|
|
hr = HRESULT_FROM_WIN32(status);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// Done.
|
|
defaultIdentity = NULL;
|
|
defaultLength = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (type != REG_SZ)
|
|
{
|
|
IASTracePrintf("Cannot read value %S. Wrong type %ld",
|
|
DEFAULT_IDENTITY_VALUE,
|
|
type
|
|
);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
if (defaultLength < sizeof(WCHAR))
|
|
{
|
|
IASTracePrintf("Cannot read value %S. Wrong Size = %ld",
|
|
DEFAULT_IDENTITY_VALUE,
|
|
defaultLength
|
|
);
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
// Allocate memory to hold the Default Identity.
|
|
defaultIdentity = new (std::nothrow)
|
|
WCHAR[defaultLength / sizeof(WCHAR)];
|
|
if (defaultIdentity == 0)
|
|
{
|
|
IASTraceString("Default Identity could not be retrieved due to"
|
|
"out of memory condition.");
|
|
defaultLength = 0;
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// Query the value of the Default Identity.
|
|
status = RegQueryValueExW(
|
|
hKey,
|
|
DEFAULT_IDENTITY_VALUE,
|
|
NULL,
|
|
&type,
|
|
(LPBYTE)defaultIdentity,
|
|
&defaultLength
|
|
);
|
|
if (status != ERROR_SUCCESS)
|
|
{
|
|
delete[] defaultIdentity;
|
|
defaultIdentity = NULL;
|
|
defaultLength = 0;
|
|
hr = HRESULT_FROM_WIN32(status);
|
|
IASTracePrintf("Failed to read the value %S. Error is %ld",
|
|
DEFAULT_IDENTITY_VALUE,
|
|
status);
|
|
break;
|
|
}
|
|
}
|
|
while(false);
|
|
|
|
if (hKey != INVALID_HANDLE_VALUE)
|
|
{
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IASTracePrintf("User identity attribute: %lu", identityAttr);
|
|
IASTracePrintf("Override User-Name: %s",
|
|
overrideUsername ? "TRUE" : "FALSE");
|
|
IASTracePrintf("Default user identity: %S",
|
|
(defaultIdentity ? defaultIdentity : L"<Guest>"));
|
|
|
|
// Initialized completed
|
|
initialized = true;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
IdentityHelper::IdentityHelper() throw()
|
|
: identityAttr(1), defaultIdentity(NULL), defaultLength(0)
|
|
{
|
|
}
|
|
|
|
|
|
IdentityHelper::~IdentityHelper() throw()
|
|
{
|
|
delete[] defaultIdentity;
|
|
}
|
|
|
|
|
|
bool IdentityHelper::getIdentity(IASRequest& request,
|
|
wchar_t* pIdentity,
|
|
size_t& identitySize)
|
|
{
|
|
wchar_t* identity;
|
|
IASAttribute attr;
|
|
HRESULT hr;
|
|
WCHAR name[DNLEN + UNLEN + 2];
|
|
|
|
if ((identityAttr == RADIUS_ATTRIBUTE_USER_NAME) || (!overrideUsername))
|
|
{
|
|
// identity chosen for override is user-name
|
|
// can be more than 1 RADIUS_ATTRIBUTE_USER_NAME attribute
|
|
// Use the one from access accept.
|
|
getRadiusUserName(request, attr);
|
|
}
|
|
|
|
if (!attr && (identityAttr != RADIUS_ATTRIBUTE_USER_NAME))
|
|
{
|
|
// identity chosen is not user-name
|
|
// only one possible identity attribute
|
|
attr.load(request, identityAttr, IASTYPE_OCTET_STRING);
|
|
}
|
|
|
|
// if an 'identity' was retrieved, convert it then return
|
|
if (attr != NULL && attr->Value.OctetString.dwLength != 0)
|
|
{
|
|
// previous step was successful
|
|
// Convert it to a UNICODE string.
|
|
if (identitySize < IAS_OCT2WIDE_LEN(attr->Value.OctetString))
|
|
{
|
|
IASTraceString("IASOctetStringToWide failed");
|
|
identitySize = IAS_OCT2WIDE_LEN(attr->Value.OctetString);
|
|
return false;
|
|
}
|
|
|
|
IASOctetStringToWide(attr->Value.OctetString, pIdentity);
|
|
|
|
// if that fails, then the string is empty ("")
|
|
if (wcslen(pIdentity) == 0)
|
|
{
|
|
IASTraceString("IASOctetStringToWide failed");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
IASTracePrintf(
|
|
"NT-SAM Names handler received request with user identity %S.",
|
|
pIdentity
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// previous step was not successful (No identity attribute)
|
|
// use default identity or guest
|
|
if (defaultIdentity)
|
|
{
|
|
// Use the default identity if set.
|
|
identity = defaultIdentity;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise use the guest account for the default domain.
|
|
IASGetGuestAccountName(name);
|
|
identity = name;
|
|
}
|
|
|
|
IASTracePrintf(
|
|
"NT-SAM Names handler using default user identity %S.",
|
|
identity
|
|
);
|
|
}
|
|
|
|
IASTracePrintf("identity is \"%S\"", identity);
|
|
|
|
hr = StringCbCopyW(pIdentity, identitySize, identity);
|
|
if (FAILED(hr))
|
|
{
|
|
identitySize = (wcslen(identity) + 1) * sizeof(wchar_t) ;
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//
|
|
// set attr to the RADIUS_ATTRIBUTE_USER_NAME found if any
|
|
// if 2 are present, take the one returned by the backend server.
|
|
//
|
|
//
|
|
void IdentityHelper::getRadiusUserName(IASRequest& request, IASAttribute &attr)
|
|
{
|
|
IASAttributeVectorWithBuffer<2> vector;
|
|
DWORD Error = vector.load(request, RADIUS_ATTRIBUTE_USER_NAME);
|
|
switch (vector.size())
|
|
{
|
|
case 0:
|
|
// no attribute found
|
|
break;
|
|
case 1:
|
|
// only one attribute: use it
|
|
attr = vector.front().pAttribute;
|
|
break;
|
|
case 2:
|
|
attr = vector.front().pAttribute;
|
|
// IAS_RECVD_FROM_CLIENT is set when the proxy receives the attribute
|
|
// in the access request or accounting request
|
|
if(attr.testFlag(IAS_RECVD_FROM_CLIENT))
|
|
{
|
|
// if the 1st attribute was received from the client (i.e. was in the
|
|
// REQUEST, then use the other one, the other should come from the
|
|
// back-end server
|
|
attr = vector.back().pAttribute;
|
|
if (attr.testFlag(IAS_RECVD_FROM_CLIENT))
|
|
{
|
|
IASTraceString("ERROR 2 RADIUS_ATTRIBUTE_USER_NAME found in the"
|
|
"request but both came from the client");
|
|
_com_issue_error(IAS_PROXY_MALFORMED_RESPONSE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
_com_issue_error(IAS_PROXY_MALFORMED_RESPONSE);
|
|
}
|
|
}
|