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.
 
 
 
 
 
 

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);
}
}