/* File usrparms.c Callback routines exported to SAM for migrating and updating user parms. Paul Mayfield, 9/10/98 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for UP_CLIENT_DIAL #include // for IASParmsGetUserPassword #include // for RasSfmHeap #include // // 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 // 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); }