191 lines
4.5 KiB
C
191 lines
4.5 KiB
C
/* Copyright (c) Microsoft Corporation. All rights reserved. */
|
|
|
|
#include "windows.h"
|
|
#include "authif.h"
|
|
#include "lmcons.h"
|
|
#include "ntsecapi.h"
|
|
#include "radutil.h"
|
|
|
|
/* The registry value where this extension is registered. */
|
|
LPCWSTR pwszDllType = AUTHSRV_EXTENSIONS_VALUE_W;
|
|
|
|
/* Global handle to the LSA. This is initialized once at start-up and reused
|
|
* until shutdown. */
|
|
LSA_HANDLE hPolicy = NULL;
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
RadiusExtensionInit( VOID )
|
|
{
|
|
NTSTATUS status;
|
|
LSA_OBJECT_ATTRIBUTES objectAttributes;
|
|
|
|
memset(&objectAttributes, 0, sizeof(objectAttributes));
|
|
status = LsaOpenPolicy(
|
|
NULL,
|
|
&objectAttributes,
|
|
POLICY_LOOKUP_NAMES,
|
|
&hPolicy
|
|
);
|
|
|
|
return LsaNtStatusToWinError(status);
|
|
}
|
|
|
|
|
|
VOID
|
|
WINAPI
|
|
RadiusExtensionTerm( VOID )
|
|
{
|
|
LsaClose(hPolicy);
|
|
hPolicy = NULL;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
RadiusExtensionProcess2(
|
|
PRADIUS_EXTENSION_CONTROL_BLOCK pECB
|
|
)
|
|
{
|
|
PRADIUS_ATTRIBUTE_ARRAY pInAttrs;
|
|
const RADIUS_ATTRIBUTE* pAttr;
|
|
int nChar;
|
|
WCHAR wszUserName[UNLEN];
|
|
CHAR szUserName[UNLEN];
|
|
LSA_UNICODE_STRING lusName;
|
|
NTSTATUS status;
|
|
PLSA_REFERENCED_DOMAIN_LIST pReferencedDomains;
|
|
PLSA_TRANSLATED_SID pSids;
|
|
DWORD cbDataLength, dwResult;
|
|
RADIUS_ATTRIBUTE raNewName;
|
|
|
|
/* We only process authentication. */
|
|
if (pECB->repPoint != repAuthentication)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* We only process Access-Requests. */
|
|
if (pECB->rcRequestType != rcAccessRequest)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Don't process if it's already been rejected. */
|
|
if (pECB->rcResponseType == rcAccessReject)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Get the attributes from the Access-Request. */
|
|
pInAttrs = pECB->GetRequest(pECB);
|
|
|
|
/* Only process Windows users */
|
|
pAttr = RadiusFindFirstAttribute(pInAttrs, ratProvider);
|
|
if ((pAttr == NULL) || (pAttr->dwValue != rapWindowsNT))
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Retrieve the username. If it doesn't exist, there's nothing to do. */
|
|
pAttr = RadiusFindFirstAttribute(pInAttrs, ratUserName);
|
|
if (pAttr == NULL)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* If the username already includes a domain name or if it's a user
|
|
* principal name (UPN), then we don't have to do anything. */
|
|
if (memchr(pAttr->lpValue, '\\', pAttr->cbDataLength) != NULL)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
if (memchr(pAttr->lpValue, '@', pAttr->cbDataLength) != NULL)
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/* Convert the username to Unicode. */
|
|
nChar = MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_ERR_INVALID_CHARS,
|
|
pAttr->lpValue,
|
|
pAttr->cbDataLength,
|
|
wszUserName,
|
|
UNLEN
|
|
);
|
|
if (nChar == 0)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
/* Pack the username into an LSA_UNICODE_STRING struct. */
|
|
lusName.Length = nChar * sizeof(WCHAR);
|
|
lusName.MaximumLength = lusName.Length;
|
|
lusName.Buffer = wszUserName;
|
|
|
|
/* Lookup the name. */
|
|
status = LsaLookupNames(
|
|
hPolicy,
|
|
1,
|
|
&lusName,
|
|
&pReferencedDomains,
|
|
&pSids
|
|
);
|
|
if (!LSA_SUCCESS(status))
|
|
{
|
|
return LsaNtStatusToWinError(status);
|
|
}
|
|
|
|
/* Get the domain which has the user account */
|
|
lusName = pReferencedDomains->Domains[pSids[0].DomainIndex].Name;
|
|
|
|
/* Convert to an ANSI string. */
|
|
nChar = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
lusName.Buffer,
|
|
(lusName.Length / sizeof(WCHAR)),
|
|
szUserName,
|
|
UNLEN,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
LsaFreeMemory(pReferencedDomains);
|
|
LsaFreeMemory(pSids);
|
|
|
|
if (nChar == 0)
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
/* New attribute is the domain plus delimiter plus username */
|
|
cbDataLength = nChar + 1 + pAttr->cbDataLength;
|
|
if (cbDataLength > UNLEN)
|
|
{
|
|
return ERROR_BAD_USERNAME;
|
|
}
|
|
|
|
/* Build the fully-qualified username. */
|
|
szUserName[nChar] = '\\';
|
|
memcpy(szUserName + nChar + 1, pAttr->lpValue, pAttr->cbDataLength);
|
|
|
|
/* Fill in the RADIUS_ATTRIBUTE struct. */
|
|
raNewName.fDataType = rdtString;
|
|
raNewName.cbDataLength = cbDataLength;
|
|
raNewName.lpValue = szUserName;
|
|
|
|
/* Add as both the ratStrippedUserName and the ratFQUserName. */
|
|
raNewName.dwAttrType = ratStrippedUserName;
|
|
dwResult = RadiusReplaceFirstAttribute(pInAttrs, &raNewName);
|
|
if (dwResult == NO_ERROR)
|
|
{
|
|
raNewName.dwAttrType = ratFQUserName;
|
|
dwResult = RadiusReplaceFirstAttribute(pInAttrs, &raNewName);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|