windows-nt/Source/XPSP1/NT/net/rras/ras/rassfm/usrparms.c
2020-09-26 16:20:57 +08:00

1204 lines
31 KiB
C

/*
File usrparms.c
Callback routines exported to SAM for migrating and updating
user parms.
Paul Mayfield, 9/10/98
*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <samrpc.h>
#include <samisrv.h>
#include <windows.h>
#include <lm.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>
#include <raserror.h>
#include <rasman.h>
#include <rasppp.h>
#include <mprapi.h>
#include <mprapip.h>
#include <usrparms.h> // for UP_CLIENT_DIAL
#include <cleartxt.h> // for IASParmsGetUserPassword
#include <rassfmhp.h> // for RasSfmHeap
#include <oaidl.h>
//
// Flags that restrict the values generated for a given
// set of ras user properties. See UPGenerateDsAttribs
//
#define UP_F_Dialin 0x1 // Generate dialup params
#define UP_F_Callback 0x2 // Generate callback params
#define UP_F_Upgrade 0x4 // Generate upgraded params
//
// Constants in the profiles
//
#define SDO_FRAMED 2
#define SDO_FRAMED_CALLBACK 4
// Names of user attributes that we set
//
static const WCHAR pszAttrDialin[] = L"msNPAllowDialin";
static const WCHAR pszAttrServiceType[] = L"msRADIUSServiceType";
static const WCHAR pszAttrCbNumber[] = L"msRADIUSCallbackNumber";
static const WCHAR pszAttrSavedCbNumber[] = L"msRASSavedCallbackNumber";
//
// Will be equal to the number of times the common allocation
// routine is called minus the number of times the common free
// routine is called. Should be zero else leaking memory.
//
DWORD dwUpLeakCount = 0;
//
// Prototype of free func.
//
VOID WINAPI
UserParmsFree(
IN PVOID pvData);
//
// Common tracing for the UserParm functions.
//
DWORD UpTrace (LPSTR pszTrace, ...) {
#if 0
va_list arglist;
char szBuffer[1024], szTemp[1024];
va_start(arglist, pszTrace);
vsprintf(szTemp, pszTrace, arglist);
va_end(arglist);
sprintf(szBuffer, "UserParms: %s\n", szTemp);
OutputDebugStringA(szBuffer);
#endif
return NO_ERROR;
}
//
// Allocation and free routines for UserParms functions
//
PVOID
UpAlloc(
IN DWORD dwSize,
IN BOOL bZero)
{
dwUpLeakCount++;
return RtlAllocateHeap(
RasSfmHeap(),
(bZero ? HEAP_ZERO_MEMORY : 0),
dwSize
);
}
//
// Callback function called by NT5 SAM to free the blob
// returned by UserParmsConvert.
//
VOID
UpFree(
IN PVOID pvData)
{
dwUpLeakCount--;
if (pvData)
RtlFreeHeap(
RasSfmHeap(),
0,
pvData
);
}
//
// Returns a heap-allocated copy of the given
// string
//
PWCHAR
UpStrDup(
IN PCWSTR pszSrc)
{
PWCHAR pszRet = NULL;
DWORD dwLen = wcslen(pszSrc);
pszRet = (PWCHAR) UpAlloc((dwLen + 1) * sizeof(WCHAR), FALSE);
if (pszRet)
wcscpy(pszRet, pszSrc);
return pszRet;
}
//
// Returns a heap-allocated copy of the given unicode
// string converted into multibyte.
//
PUCHAR
UpWcstombsDup(
IN PWCHAR pszSrc)
{
PUCHAR pszRet = NULL;
DWORD dwSize = (wcslen(pszSrc) + 1) * sizeof(WCHAR);
pszRet = (PUCHAR) UpAlloc(dwSize, TRUE);
if (pszRet)
wcstombs(pszRet, pszSrc, dwSize);
return pszRet;
}
//
// Returns a heap-allocated copy of the given
// blob
//
PVOID
UpBlobDup(
IN PVOID pvSrc,
IN ULONG ulLen)
{
PVOID pvRet = NULL;
if (ulLen == 0)
return NULL;
pvRet = UpAlloc(ulLen + sizeof(WCHAR), TRUE);
if (pvRet)
{
CopyMemory(pvRet, pvSrc, ulLen);
}
else
{
UpTrace("UpBlobDup: Failed to dupe %x %d.", pvSrc, ulLen);
}
return pvRet;
}
//
// Allocates and initializes a dword attribute
//
NTSTATUS
UpInitializeDwordAttr(
IN SAM_USERPARMS_ATTR * pAttr,
IN PWCHAR pszAttr,
IN DWORD dwVal)
{
if (pszAttr == NULL)
{
return STATUS_NO_MEMORY;
}
// Initialize the name
RtlInitUnicodeString (&(pAttr->AttributeIdentifier), pszAttr);
pAttr->Syntax = Syntax_Attribute;
// Alloc/Initailze the value structure
pAttr->Values =
(SAM_USERPARMS_ATTRVALS*)
UpAlloc(sizeof(SAM_USERPARMS_ATTRVALS), TRUE);
if (pAttr->Values == NULL)
return STATUS_NO_MEMORY;
// Alloc/Init the value
pAttr->Values->value = UpAlloc(sizeof(DWORD), TRUE);
if (pAttr->Values->value == NULL)
return STATUS_NO_MEMORY;
*((DWORD*)pAttr->Values->value) = dwVal;
pAttr->Values->length = sizeof(DWORD);
// Put in the value count
pAttr->CountOfValues = 1;
return STATUS_SUCCESS;
}
//
// Allocates and initializes a dword attribute
//
NTSTATUS
UpInitializeStringAttrA(
OUT SAM_USERPARMS_ATTR * pAttr,
IN PWCHAR pszAttr,
IN PUCHAR pszVal)
{
if (pszAttr == NULL)
{
return STATUS_NO_MEMORY;
}
// Initialize the name
RtlInitUnicodeString (&(pAttr->AttributeIdentifier), pszAttr);
pAttr->Syntax = Syntax_Attribute;
// Alloc/Initailze the value structure
pAttr->Values =
(SAM_USERPARMS_ATTRVALS*)
UpAlloc(sizeof(SAM_USERPARMS_ATTRVALS), TRUE);
if (pAttr->Values == NULL)
return STATUS_NO_MEMORY;
// Alloc/Init the value
pAttr->Values->value = pszVal;
if (pszVal)
{
pAttr->Values->length = (strlen(pszVal) + 1) * sizeof(CHAR);
}
else
{
pAttr->Values->length = 1 * sizeof(CHAR);
}
// Put in the value count
pAttr->CountOfValues = 1;
return STATUS_SUCCESS;
}
//
// Allocates and initializes a cleartext password attribute
//
NTSTATUS
UpInitializePasswordAttr(
OUT SAM_USERPARMS_ATTR * pAttr,
IN PWSTR pszPassword)
{
// Alloc/Initialize the value structure
pAttr->Values =
(SAM_USERPARMS_ATTRVALS*)
UpAlloc(sizeof(SAM_USERPARMS_ATTRVALS), TRUE);
if (pAttr->Values == NULL)
return STATUS_NO_MEMORY;
// Alloc/Init the value
pAttr->Values->value = pszPassword;
pAttr->Values->length = (wcslen(pszPassword) + 1) * sizeof(WCHAR);
// Put in the value count
pAttr->CountOfValues = 1;
// Initialize the name and syntax.
RtlInitUnicodeString(
&pAttr->AttributeIdentifier,
UpStrDup(L"CLEARTEXT")
);
pAttr->Syntax = Syntax_EncryptedAttribute;
return STATUS_SUCCESS;
}
//
// Allocates and initializes an attribute
// to be deleted.
//
NTSTATUS
UpInitializeDeletedAttr(
OUT SAM_USERPARMS_ATTR * pAttr,
IN PWCHAR pszAttr)
{
if (pszAttr == NULL)
{
return STATUS_NO_MEMORY;
}
// Initialize the name
RtlInitUnicodeString (&(pAttr->AttributeIdentifier), pszAttr);
pAttr->Syntax = Syntax_Attribute;
// Value count of zero means delete
//
pAttr->CountOfValues = 0;
return STATUS_SUCCESS;
}
//
// Converts the given user parms blob into a set of
// ras attributes
//
NTSTATUS
UpUserParmsToRasUser0 (
IN PVOID pvUserParms,
OUT RAS_USER_0 * pRasUser0)
{
DWORD dwErr;
// Initalize
ZeroMemory(pRasUser0, sizeof(RAS_USER_0));
pRasUser0->bfPrivilege = RASPRIV_NoCallback;
pRasUser0->wszPhoneNumber[0] = UNICODE_NULL;
// The the user parms are null, the defaults
// will do.
if (pvUserParms == NULL)
{
return STATUS_SUCCESS;
}
// Truncate user parms at sizeof USER_PARMS
if (lstrlenW((PWCHAR)pvUserParms) >= sizeof(USER_PARMS))
{
// We slam in a null at sizeof(USER_PARMS)-1 which
// corresponds to user_parms.up_Null
((PWCHAR)pvUserParms)[sizeof(USER_PARMS)-1] = L'\0';
}
// Get RAS info (and validate) from usr_parms
dwErr = MprGetUsrParams(
UP_CLIENT_DIAL,
(LPWSTR) pvUserParms,
(LPWSTR) pRasUser0);
if (dwErr == NO_ERROR)
{
// Get RAS Privilege and callback number
RasPrivilegeAndCallBackNumber(FALSE, pRasUser0);
}
return STATUS_SUCCESS;
}
/////////
// Signature of the extraction function.
/////////
typedef HRESULT (WINAPI *IASPARMSQUERYUSERPROPERTY)(
IN PCWSTR pszUserParms,
IN PCWSTR pszName,
OUT VARIANT *pvarValue
);
//////////
// Uplevel per-user attributes that will be migrated.
//////////
CONST PCWSTR UPLEVEL_PARMS[] =
{
L"msNPAllowDialin",
L"msNPCallingStationID",
L"msRADIUSCallbackNumber",
L"msRADIUSFramedIPAddress",
L"msRADIUSFramedRoute",
L"msRADIUSServiceType"
};
//////////
// Number of per-user attributes.
//////////
#define NUM_UPLEVEL_PARMS (sizeof(UPLEVEL_PARMS)/sizeof(UPLEVEL_PARMS[0]))
/////////
// Converts a ULONG into a SAM_USERPARMS_ATTRVALS struct.
/////////
NTSTATUS
NTAPI
ConvertULongToAttrVal(
IN ULONG ulValue,
OUT PSAM_USERPARMS_ATTRVALS pAttrVal
)
{
// Allocate memory to hold the ULONG.
pAttrVal->value = UpAlloc(sizeof(ULONG), FALSE);
if (pAttrVal->value == NULL) { return STATUS_NO_MEMORY; }
// Copy in the value.
*(PULONG)pAttrVal->value = ulValue;
// Set the length.
pAttrVal->length = sizeof(ULONG);
return STATUS_SUCCESS;
}
//////////
// Converts a single-valued VARIANT into a SAM_USERPARMS_ATTRVALS struct.
//////////
NTSTATUS
NTAPI
ConvertVariantToAttrVal(
IN CONST VARIANT *pvarValue,
OUT PSAM_USERPARMS_ATTRVALS pAttrVal
)
{
NTSTATUS status;
ULONG length;
UNICODE_STRING wide;
ANSI_STRING ansi;
switch (V_VT(pvarValue))
{
case VT_EMPTY:
{
// VT_EMPTY means the attribute was deleted.
pAttrVal->value = NULL;
pAttrVal->length = 0;
return STATUS_SUCCESS;
}
case VT_I2:
return ConvertULongToAttrVal(V_I2(pvarValue), pAttrVal);
case VT_I4:
return ConvertULongToAttrVal(V_I4(pvarValue), pAttrVal);
case VT_BSTR:
{
// Check the BSTR.
if (V_BSTR(pvarValue) == NULL) { return STATUS_INVALID_PARAMETER; }
// Initialize the source string.
RtlInitUnicodeString(&wide, V_BSTR(pvarValue));
// Initialize the destination buffer.
ansi.Length = 0;
ansi.MaximumLength = wide.MaximumLength / sizeof(WCHAR);
ansi.Buffer = UpAlloc(ansi.MaximumLength, FALSE);
if (ansi.Buffer == NULL) { return STATUS_NO_MEMORY; }
// Convert from wide to ansi.
status = RtlUnicodeStringToAnsiString(&ansi, &wide, FALSE);
if (!NT_SUCCESS(status))
{
UpFree(ansi.Buffer);
return status;
}
// Store the result.
pAttrVal->value = ansi.Buffer;
pAttrVal->length = ansi.Length + 1;
return STATUS_SUCCESS;
}
case VT_BOOL:
return ConvertULongToAttrVal((V_BOOL(pvarValue) ? 1 : 0), pAttrVal);
case VT_I1:
return ConvertULongToAttrVal(V_I1(pvarValue), pAttrVal);
case VT_UI1:
return ConvertULongToAttrVal(V_UI1(pvarValue), pAttrVal);
case VT_UI2:
return ConvertULongToAttrVal(V_UI2(pvarValue), pAttrVal);
case VT_UI4:
return ConvertULongToAttrVal(V_UI4(pvarValue), pAttrVal);
case VT_ARRAY | VT_I1:
case VT_ARRAY | VT_UI1:
{
// Check the SAFEARRAY.
if (V_ARRAY(pvarValue) == NULL) { return STATUS_INVALID_PARAMETER; }
// Allocate memory for the octet string.
length = V_ARRAY(pvarValue)->rgsabound[0].cElements;
pAttrVal->value = UpAlloc(length, FALSE);
if (pAttrVal->value == NULL) { return STATUS_NO_MEMORY; }
// Copy in the data.
memcpy(pAttrVal->value, V_ARRAY(pvarValue)->pvData, length);
// Set the length.
pAttrVal->length = length;
return STATUS_SUCCESS;
}
}
// If we made it here it was an unsupported VARTYPE.
return STATUS_INVALID_PARAMETER;
}
//////////
// Frees the values array of a SAM_USERPARMS_ATTR struct.
//////////
VOID
NTAPI
FreeUserParmsAttrValues(
IN PSAM_USERPARMS_ATTR pAttrs
)
{
ULONG i;
if (pAttrs)
{
for (i = 0; i < pAttrs->CountOfValues; ++i)
{
UpFree(pAttrs->Values[i].value);
}
UpFree(pAttrs->Values);
}
}
//////////
// Converts a VARIANT into a SAM_USERPARMS_ATTR struct.
//////////
NTSTATUS
NTAPI
ConvertVariantToUserParmsAttr(
IN CONST VARIANT *pvarSrc,
OUT PSAM_USERPARMS_ATTR pAttrs
)
{
NTSTATUS status;
ULONG nelem;
CONST VARIANT *srcVal;
SAM_USERPARMS_ATTRVALS *dstVal;
// Get the array of values to be converted.
if (V_VT(pvarSrc) != (VT_VARIANT | VT_ARRAY))
{
nelem = 1;
srcVal = pvarSrc;
}
else
{
nelem = V_ARRAY(pvarSrc)->rgsabound[0].cElements;
srcVal = (CONST VARIANT *)V_ARRAY(pvarSrc)->pvData;
}
// Initialize CountOfValues to zero. We'll use this to track how many
// values have been successfully converted.
pAttrs->CountOfValues = 0;
// Allocate memory to hold the values.
pAttrs->Values = UpAlloc(sizeof(SAM_USERPARMS_ATTRVALS) * nelem, TRUE);
if (pAttrs->Values == NULL) { return STATUS_NO_MEMORY; }
// Loop through each value to be converted.
for (dstVal = pAttrs->Values; nelem > 0; ++srcVal, ++dstVal, --nelem)
{
status = ConvertVariantToAttrVal(srcVal, dstVal);
if (!NT_SUCCESS(status))
{
// Clean-up the partial results.
FreeUserParmsAttrValues(pAttrs);
return status;
}
++(pAttrs->CountOfValues);
}
return STATUS_SUCCESS;
}
//////////
// Extracts the NT5 per-user attributes from a SAM UserParameters string and
// converts them to a SAM_USERPARMS_ATTRBLOCK struct.
//////////
NTSTATUS
NTAPI
ConvertUserParmsToAttrBlock(
IN PCWSTR lpUserParms,
OUT PSAM_USERPARMS_ATTRBLOCK *ppAttrs
)
{
static IASPARMSQUERYUSERPROPERTY IASParmsQueryUserProperty;
NTSTATUS status;
PSAM_USERPARMS_ATTR dst;
PWSTR szPassword;
ULONG i;
HRESULT hr;
VARIANT src;
//////////
// Make sure we have the extraction function loaded.
//////////
if (IASParmsQueryUserProperty == NULL)
{
IASParmsQueryUserProperty = (IASPARMSQUERYUSERPROPERTY)
GetProcAddress(
LoadLibraryW(
L"IASSAM.DLL"
),
"IASParmsQueryUserProperty"
);
if (!IASParmsQueryUserProperty) { return STATUS_PROCEDURE_NOT_FOUND; }
}
//////////
// Allocate memory for the SAM_USERPARMS_ATTRBLOCK.
//////////
*ppAttrs = (PSAM_USERPARMS_ATTRBLOCK)
UpAlloc(
sizeof(SAM_USERPARMS_ATTRBLOCK),
TRUE
);
if (*ppAttrs == NULL)
{
return STATUS_NO_MEMORY;
}
(*ppAttrs)->UserParmsAttr = (PSAM_USERPARMS_ATTR)
UpAlloc(
sizeof(SAM_USERPARMS_ATTR) *
(NUM_UPLEVEL_PARMS + 1),
TRUE
);
if ((*ppAttrs)->UserParmsAttr == NULL)
{
UpFree(*ppAttrs);
return STATUS_NO_MEMORY;
}
//////////
// Convert the cleartext password.
//////////
dst = (*ppAttrs)->UserParmsAttr;
szPassword = NULL;
IASParmsGetUserPassword(
lpUserParms,
&szPassword
);
if (szPassword)
{
status = UpInitializePasswordAttr(
dst,
UpStrDup(szPassword)
);
LocalFree(szPassword);
if (NT_SUCCESS(status))
{
++dst;
}
}
//////////
// Convert the dial-in parameters.
//////////
for (i = 0; i < NUM_UPLEVEL_PARMS; ++i)
{
// Try to extract the parameter from UserParms.
hr = IASParmsQueryUserProperty(
lpUserParms,
UPLEVEL_PARMS[i],
&src
);
if (FAILED(hr) || V_VT(&src) == VT_EMPTY) { continue; }
// Convert to a SAM_USERPARMS_ATTRVALS array.
status = ConvertVariantToUserParmsAttr(
&src,
dst
);
if (NT_SUCCESS(status))
{
// Fill in the AttributeIdentifier ...
RtlInitUnicodeString(
&dst->AttributeIdentifier,
UpStrDup(UPLEVEL_PARMS[i])
);
// ... and the Syntax.
dst->Syntax = Syntax_Attribute;
// All went well, so advance to the next element in the array.
++dst;
}
// We're done with the VARIANT.
VariantClear(&src);
}
(*ppAttrs)->attCount = (ULONG)(dst - (*ppAttrs)->UserParmsAttr);
// If there weren't any attributes, then free the UserParmsAttr array.
if ((*ppAttrs)->attCount == 0)
{
UpFree((*ppAttrs)->UserParmsAttr);
(*ppAttrs)->UserParmsAttr = NULL;
}
return status;
}
//
// Generate an appropriate set of ds attributes based on the
// ras user information provided
//
NTSTATUS
UpGenerateDsAttribs (
IN DWORD dwFlags,
IN RAS_USER_0 * pRasUser0,
IN PWSTR szPassword,
OUT PSAM_USERPARMS_ATTRBLOCK * ppAttrs)
{
PSAM_USERPARMS_ATTRBLOCK pRet = NULL;
SAM_USERPARMS_ATTR * pCurAttr = NULL;
PWCHAR pszDupPassword, pszCurAttr = NULL;
DWORD dwCurVal = 0, dwDsParamCount;
NTSTATUS ntStatus = STATUS_SUCCESS;
UpTrace("UpGenerateDsAttribs: enter %x", dwFlags);
do
{
// pmay: 330184
//
// If we're upgrading, then having NULL userparms or having
// deny set explicitly should cause us to not add the msNPAllowDialin
// value so that user will be managed by policy.
//
if (
(dwFlags & UP_F_Upgrade) &&
(!(pRasUser0->bfPrivilege & RASPRIV_DialinPrivilege))
)
{
dwFlags &= ~UP_F_Dialin;
}
// Initialize the return value
pRet = (PSAM_USERPARMS_ATTRBLOCK)
UpAlloc(sizeof(SAM_USERPARMS_ATTRBLOCK), TRUE);
if (pRet == NULL)
{
UpTrace("UpGenerateDsAttribs: alloc block failed");
ntStatus = STATUS_NO_MEMORY;
break;
}
// Calculate the total number of values
dwDsParamCount = 0;
if (dwFlags & UP_F_Dialin)
{
dwDsParamCount += 1;
}
if (dwFlags & UP_F_Callback)
{
dwDsParamCount += 3;
}
if (szPassword != NULL)
{
dwDsParamCount += 1;
}
//
// Set the array to be big enough to accomodate 4 attributes:
// 1. Dialin bit
// 2. Callback Number or Saved Callback Number
// 3. Deleted version of #2
// 4. Service Type (for callback policy)
//
pCurAttr = (SAM_USERPARMS_ATTR*)
UpAlloc(sizeof(SAM_USERPARMS_ATTR) * dwDsParamCount, TRUE);
if (pCurAttr == NULL)
{
ntStatus = STATUS_NO_MEMORY;
UpTrace("UpGenerateDsAttribs: alloc of %d values failed",
dwDsParamCount);
break;
}
pRet->attCount = dwDsParamCount;
pRet->UserParmsAttr = pCurAttr;
// Set any appropriate dialin parameters
//
if (dwFlags & UP_F_Dialin)
{
dwCurVal =
(pRasUser0->bfPrivilege & RASPRIV_DialinPrivilege) ? 1 : 0;
// Initialize the dialin setting
ntStatus = UpInitializeDwordAttr(
pCurAttr,
UpStrDup((PWCHAR)pszAttrDialin),
dwCurVal);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail dialin val %x", ntStatus);
break;
}
pCurAttr++;
}
// Set any appropriate callback parameters
//
if (dwFlags & UP_F_Callback)
{
// The following logic was modified for SP1 of Win2K. The reason is that
// the values being set did not conform to the rules outlined in the
// comments to the UserParmsConvert function.
//
// Namely,
// 1. the msRADIUSServiceType was being set to SDO_FRAMED instead of
// <empty> when RASPRIV_NoCallback was set.
//
// 2. When RASPRIV_NoCallback was set, the msRADIUSCallbackNumber was
// set and the msRASSavedCallbackNumber was deleted instead of the
// vice-versa
//
// Initialize the service type
if (pRasUser0->bfPrivilege & RASPRIV_NoCallback)
{
ntStatus = UpInitializeDeletedAttr(
pCurAttr,
UpStrDup((PWCHAR)pszAttrServiceType));
}
else
{
ntStatus = UpInitializeDwordAttr(
pCurAttr,
UpStrDup((PWCHAR)pszAttrServiceType),
SDO_FRAMED_CALLBACK);
}
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail ST val %x", ntStatus);
break;
}
pCurAttr++;
// Initialize the callback number that will be committed
pszCurAttr = (pRasUser0->bfPrivilege & RASPRIV_AdminSetCallback) ?
(PWCHAR) pszAttrCbNumber :
(PWCHAR) pszAttrSavedCbNumber;
if (*(pRasUser0->wszPhoneNumber))
{
ntStatus = UpInitializeStringAttrA(
pCurAttr,
UpStrDup(pszCurAttr),
UpWcstombsDup(pRasUser0->wszPhoneNumber));
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail CB val %x", ntStatus);
break;
}
}
else
{
ntStatus = UpInitializeDeletedAttr(
pCurAttr,
UpStrDup(pszCurAttr));
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail del CB val %x", ntStatus);
break;
}
}
pCurAttr++;
// Remove the callback number that doesn't apply.
pszCurAttr = (pszCurAttr == pszAttrCbNumber) ?
(PWCHAR) pszAttrSavedCbNumber :
(PWCHAR) pszAttrCbNumber;
ntStatus = UpInitializeDeletedAttr(
pCurAttr,
UpStrDup(pszCurAttr));
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail del SCB val %x", ntStatus);
break;
}
pCurAttr++;
}
// Set the cleartext password if present
//
if (szPassword != NULL)
{
// Make a duplicate copy of the password
if ((pszDupPassword = UpStrDup(szPassword)) == NULL)
{
ntStatus = STATUS_NO_MEMORY;
break;
}
// Initialize the password attribute
ntStatus = UpInitializePasswordAttr(
pCurAttr,
pszDupPassword);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UpGenerateDsAttribs: fail password val %x", ntStatus);
break;
}
pCurAttr++;
}
} while (FALSE);
// Cleanup
{
if (ntStatus != STATUS_SUCCESS)
{
UserParmsFree(pRet);
*ppAttrs = NULL;
}
else
{
*ppAttrs = pRet;
}
}
return ntStatus;
}
//
// Callback function called by NT5 SAM whenever the user parms
// of a particular user are modified. The job of this callout
// is to take the new value of user parms and generate a set of
// domain attributes that need to be set for the given user so
// that per-user DS attributes and userparms are kept in sync.
//
// This callout will be invoked during dcpromo to upgrade user parms
// and whenever userparms is modified (by downlevel api's and apps).
//
// Callback functions for NT5 SAM are registered in the following
// registry key:
//
// HKLM\SYS\CCS\Control\LSA\NotificationPackages
//
// The following are the rules of the RAS LDAP parameters:
//
// msNPAllowDialin
// - Empty = Use policy to determine dialin privilege
// - 1 = Allow dialin
// - 2 = Deny dialin
//
// msRADIUSServiceType
// - Empty = NoCallback policy
// - 4 = CallerCallback if msRADIUSCallbackNumber is empty
// AdminCallback if msRADIUSCallbackNumber is not empty
//
// msRADIUSCallbackNumber
// - Determines the callback policy depending on msRADIUSServiceType
//
// msRASSavedCallbackNumber
// - Used to store the last known value of msRADIUSCallbackNumber when
// switching from AdminCallback policy to some other policy.
//
NTSTATUS
UserParmsConvert (
IN ULONG ulFlags,
IN PSID pDomainSid,
IN ULONG ulObjectRid,
IN ULONG ulOrigLen,
IN PVOID pvOrigUserParms,
IN ULONG ulNewLen,
IN PVOID pvNewUserParms,
OUT PSAM_USERPARMS_ATTRBLOCK * ppAttrs)
{
RAS_USER_0 RasUser00, *pOrigUser = &RasUser00;
RAS_USER_0 RasUser01, *pNewUser = &RasUser01;
NTSTATUS ntStatus = STATUS_SUCCESS;
PVOID pvOrig = NULL, pvNew = NULL;
DWORD dwFlags = 0, dwMask;
PWSTR szPassword = NULL;
UpTrace(
"UPConvert: F=%x, Rid=%x, OLen=%d, OPar=%x, NLen=%d, NPar=%x",
ulFlags, ulObjectRid, ulOrigLen, pvOrigUserParms,
ulNewLen, pvNewUserParms);
// Validate parameters
if (ppAttrs == NULL)
return STATUS_INVALID_PARAMETER;
// Initialize the return value;
*ppAttrs = NULL;
// If the user parms passed to us are NULL,
// then keep defaults.
if ((pvNewUserParms == NULL) || (ulNewLen == 0))
{
return STATUS_SUCCESS;
}
do
{
// Allocate and initialize local copies of
// the user parms
pvOrig = UpBlobDup(pvOrigUserParms, ulOrigLen);
pvNew = UpBlobDup(pvNewUserParms, ulNewLen);
// If this is a NT5 standalone being promoted to a DC, then we
// just convert the uplevel userparms 'as is'.
if ((ulFlags & SAM_USERPARMS_DURING_UPGRADE) &&
!SamINT4UpgradeInProgress())
{
ntStatus = ConvertUserParmsToAttrBlock(pvNew, ppAttrs);
break;
}
// Get the new ras properties
ntStatus = UpUserParmsToRasUser0(
pvNew,
pNewUser);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UPConvert: Conversion to RAS_USER_0 failed.(1)");
break;
}
// If we're upgrading, then we should blindly
// set whatever information is stored in the user.
if (ulFlags & SAM_USERPARMS_DURING_UPGRADE)
{
IASParmsGetUserPassword(pvNewUserParms, &szPassword);
ntStatus = UpGenerateDsAttribs(
UP_F_Dialin | UP_F_Callback | UP_F_Upgrade,
pNewUser,
szPassword,
ppAttrs);
LocalFree(szPassword);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UPConvert: GenerateDsAttribs failed %x", ntStatus);
}
break;
}
// Get the ras properties of the old user parms
ntStatus = UpUserParmsToRasUser0(
pvOrig,
pOrigUser);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UPConvert: Conversion to RAS_USER_0 failed.(2)");
break;
}
// Find out if the dialin privilege should be updated
dwFlags = 0;
if (!!(pOrigUser->bfPrivilege & RASPRIV_DialinPrivilege) !=
!!(pNewUser->bfPrivilege & RASPRIV_DialinPrivilege))
{
dwFlags |= UP_F_Dialin;
}
// pmay: 264409
//
// If we are adding null usrparms for the first time,
// go ahead and add the dialin bit value to the ds.
//
if ((pvOrig == NULL) && (pvNew != NULL))
{
dwFlags |= UP_F_Dialin;
}
// Findout if any callback info should be updated
dwMask = RASPRIV_NoCallback |
RASPRIV_CallerSetCallback |
RASPRIV_AdminSetCallback;
if (((pOrigUser->bfPrivilege & dwMask) !=
(pNewUser->bfPrivilege & dwMask)) ||
(wcscmp(pOrigUser->wszPhoneNumber, pNewUser->wszPhoneNumber) != 0)
)
{
dwFlags |= UP_F_Callback;
}
// If there were no changes, we're done.
if (dwFlags == 0)
{
UpTrace("UPConvert: nothing to update.");
ntStatus = STATUS_SUCCESS;
break;
}
// Create the new attributes
ntStatus = UpGenerateDsAttribs(dwFlags, pNewUser, NULL, ppAttrs);
if (ntStatus != STATUS_SUCCESS)
{
UpTrace("UPConvert: UpGenerateDsAttribs failed %x.", ntStatus);
break;
}
} while (FALSE);
// Cleanup
{
if (pvOrig)
{
UpFree(pvOrig);
}
if (pvNew)
{
UpFree(pvNew);
}
}
return ntStatus;
}
//
// Callback function called by NT5 SAM to free the blob
// returned by UserParmsConvert.
//
VOID
UserParmsFree(
IN PSAM_USERPARMS_ATTRBLOCK pData)
{
SAM_USERPARMS_ATTR * pCur = NULL;
DWORD i, j;
UpTrace("UserParmsFree: Entered. %x", pData);
// If no attributes were given, we're all done
if (pData == NULL)
return;
if (pData->UserParmsAttr)
{
// Loop through all the attributes, freeing them
// as you go.
for (i = 0; i < pData->attCount; i++)
{
// Keep track of the current attribute
pCur = &(pData->UserParmsAttr[i]);
// Free the copied attribute name
if (pCur->AttributeIdentifier.Buffer)
UpFree(pCur->AttributeIdentifier.Buffer);
// Free any associated values as well.
if (pCur->Values)
{
for (j = 0; j < pCur->CountOfValues; j++)
{
// Assume there's only one value since that's
// all we ever set. Free the value
if (pCur->Values[j].value)
UpFree(pCur->Values[j].value);
}
// Free the value structure
UpFree(pCur->Values);
}
}
// Free the array of attributes
UpFree (pData->UserParmsAttr);
}
// Finally, free the whole structure
UpFree (pData);
}