Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1776 lines
55 KiB

/*************************************************************************
*
* reguc.c
*
* Registry APIs for SAM-based user configuration data
*
* Copyright (c) 1998 Microsoft Corporation
*
*
*
*************************************************************************/
/*
* Includes
*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <lm.h>
#include <ntddkbd.h>
#include <ntddmou.h>
#include <winstaw.h>
#include <regapi.h>
#include <regsam.h>
#include <rpc.h>
#include <rpcdce.h>
#include <ntdsapi.h>
// For more info, check out \\index1\src\nt\private\security\tools\delegate\ldap.c
#include "usrprop.h"
/*
* !!! WARNING !!! WARNING !!!
*
* A lot of time could be spent on making this calculation accurate and
* automatic, but time is of the essence. So a brute force
* approach is used. The size of the User Configuration section that
* Citrix is going to add to the User Parameters is based on NOT
* ONLY the size of the USERCONFIG structure, but must account for the
* Value names and the buffer management pointers as well, since the
* User Parameters section is a linear buffer that holds CITRIX data
* and Microsoft Services for Netware data.
*
* It is assumed that the overhead of the value name strings and
* the buffer management pointers will NOT be greater than twice the
* maximum data size. If this assumption is false, buffer overruns
* will occur.
*
* Bruce Fortune. 1/31/97.
*/
#define CTX_USER_PARAM_MAX_SIZE (3 * sizeof(USERCONFIG))
/*
* CTXPREFIX is the prefix for all value names placed in the User
* Parameters section of the SAM. This is a defensive measure since
* this section of the SAM is shared with MS Services for Netware.
*/
#define CTXPREFIX L"Ctx"
/*
* WIN_FLAGS1 is the name of the Flags value that is used to hold
* all of the F1MSK_... flags defined below. This is done in order to
* reduce the amount of space required in the User Parameters section
* of the SAM, since the value name of each flag is eliminated.
*/
#define WIN_FLAGS1 L"CfgFlags1"
/*
* WIN_CFGPRESENT is used to indicate that the Citrix configuration
* information is present in the User Parameters section of the user's
* SAM record.
*/
#define WIN_CFGPRESENT L"CfgPresent"
#define CFGPRESENT_VALUE 0xB00B1E55
#define F1MSK_INHERITAUTOLOGON 0x80000000
#define F1MSK_INHERITRESETBROKEN 0x40000000
#define F1MSK_INHERITRECONNECTSAME 0x20000000
#define F1MSK_INHERITINITIALPROGRAM 0x10000000
#define F1MSK_INHERITCALLBACK 0x08000000
#define F1MSK_INHERITCALLBACKNUMBER 0x04000000
#define F1MSK_INHERITSHADOW 0x02000000
#define F1MSK_INHERITMAXSESSIONTIME 0x01000000
#define F1MSK_INHERITMAXDISCONNECTIONTIME 0x00800000
#define F1MSK_INHERITMAXIDLETIME 0x00400000
#define F1MSK_INHERITAUTOCLIENT 0x00200000
#define F1MSK_INHERITSECURITY 0x00100000
#define F1MSK_PROMPTFORPASSWORD 0x00080000
#define F1MSK_RESETBROKEN 0x00040000
#define F1MSK_RECONNECTSAME 0x00020000
#define F1MSK_LOGONDISABLED 0x00010000
#define F1MSK_AUTOCLIENTDRIVES 0x00008000
#define F1MSK_AUTOCLIENTLPTS 0x00004000
#define F1MSK_FORCECLIENTLPTDEF 0x00002000
#define F1MSK_DISABLEENCRYPTION 0x00001000
#define F1MSK_HOMEDIRECTORYMAPROOT 0x00000800
#define F1MSK_USEDEFAULTGINA 0x00000400
#define F1MSK_DISABLECPM 0x00000200
#define F1MSK_DISABLECDM 0x00000100
#define F1MSK_DISABLECCM 0x00000080
#define F1MSK_DISABLELPT 0x00000040
#define F1MSK_DISABLECLIP 0x00000020
#define F1MSK_DISABLEEXE 0x00000010
#define F1MSK_WALLPAPERDISABLED 0x00000008
#define F1MSK_DISABLECAM 0x00000004
//#define F1MSK_unused 0x00000002
//#define F1MSK_unused 0x00000001
VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * );
NTSTATUS GetDomainName ( PWCHAR, PWCHAR * );
ULONG GetFlagMask( PUSERCONFIG );
VOID QueryUserConfig( HKEY, PUSERCONFIG );
/*******************************************************************************
*
* UsrPropSetValue (UNICODE)
*
* Sets a 1-, 2-, or 4-byte value into the supplied User Parameters buffer
*
* ENTRY:
* pValueName (input)
* Points to the Value Name string
* pValue (input)
* Points to value
* ValueLength (input)
* Number of bytes in the Value
* pUserParms (input)
* Points to the specially formatted User Parameters buffer
* UserParmsLength (input)
* Length in bytes of the pUserParms buffer
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
UsrPropSetValue(
WCHAR * pValueName,
PVOID pValue,
USHORT ValueLength,
BOOL fDefaultValue,
WCHAR * pUserParms,
ULONG UserParmsLength
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING uniValue;
LPWSTR lpNewUserParms = NULL;
BOOL fUpdate;
PWCHAR pNameBuf;
ULONG NBLen;
/*
* Prefix the name with a unique string so that other users of
* the user parameters section of the SAM won't collide with our
* value names.
*/
NBLen = sizeof(CTXPREFIX) + ((wcslen(pValueName) + 1) * sizeof(WCHAR));
pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
if ( !pNameBuf ) {
return( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy( pNameBuf, CTXPREFIX );
wcscat( pNameBuf, pValueName );
uniValue.Buffer = (PWCHAR) pValue;
uniValue.Length = ValueLength;
uniValue.MaximumLength = uniValue.Length;
Status = SetUserProperty( pUserParms,
pNameBuf,
uniValue,
USER_PROPERTY_TYPE_ITEM,
fDefaultValue,
&lpNewUserParms,
&fUpdate );
LocalFree( pNameBuf );
if ((Status == STATUS_SUCCESS) && (lpNewUserParms != NULL)) {
if (fUpdate) {
if ( (wcslen( lpNewUserParms ) * sizeof(WCHAR)) > UserParmsLength ) {
return( STATUS_BUFFER_TOO_SMALL );
}
lstrcpyW( pUserParms, lpNewUserParms);
}
LocalFree( lpNewUserParms );
}
return( Status );
}
/*******************************************************************************
*
* UsrPropGetValue (UNICODE)
*
* Gets a value from the supplied User Parameters buffer
*
* ENTRY:
* pValuegName (input)
* Points to the Value Name string
* pValue (output)
* Points to the buffer to receive the value
* ValueLength (input)
* Number of bytes in the buffer pointer to by pValue
* pUserParms (input)
* Points to the specially formatted User Parameters buffer
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
UsrPropGetValue(
TCHAR * pValueName,
PVOID pValue,
ULONG ValueLength,
WCHAR * pUserParms
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING uniValue;
WCHAR Flag;
PWCHAR pNameBuf;
ULONG NBLen;
/*
* Prefix the name with a unique string so that other users of
* the user parameters section of the SAM won't collide with our
* usage.
*/
NBLen = sizeof(CTXPREFIX) + ((wcslen(pValueName) + 1) * sizeof(WCHAR));
pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
if ( !pNameBuf ) {
return( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy( pNameBuf, CTXPREFIX );
wcscat( pNameBuf, pValueName );
Status = QueryUserProperty( pUserParms, pNameBuf, &Flag, &uniValue );
LocalFree( pNameBuf );
if ( Status != STATUS_SUCCESS ) {
return( Status );
}
if ( !uniValue.Buffer ) {
memset( pValue, 0, ValueLength );
} else {
memcpy( pValue, uniValue.Buffer, ValueLength );
LocalFree( uniValue.Buffer );
}
return( Status );
}
/*******************************************************************************
*
* UsrPropSetString (UNICODE)
*
* Sets a variable length string into the supplied User Parameters buffer
*
* ENTRY:
* pStringName (input)
* Points to the String Name string
* pStringValue (input)
* Points to the string
* pUserParms (input)
* Points to the specially formatted User Parameters buffer
* UserParmsLength (input)
* Length in bytes of the pUserParms buffer
* fDefaultValue
* Indicates that this value is a default value and should not be saved
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
UsrPropSetString(
WCHAR * pStringName,
WCHAR * pStringValue,
WCHAR * pUserParms,
ULONG UserParmsLength,
BOOL fDefaultValue
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING uniString;
CHAR * pchTemp = NULL;
LPWSTR lpNewUserParms = NULL;
BOOL fUpdate;
PWCHAR pNameBuf;
ULONG NBLen;
INT nMBLen;
if (pStringValue == NULL) {
uniString.Buffer = NULL;
uniString.Length = 0;
uniString.MaximumLength = 0;
}
else
{
BOOL fDummy;
INT nStringLength = lstrlen(pStringValue) + 1;
// Determine the length of the mulitbyte string
// allocate it and convert to
// this fixes bug 264907
// Next release we'll need to change from ansi code page to
// UTF8.
nMBLen = WideCharToMultiByte(CP_ACP,
0,
pStringValue,
nStringLength,
pchTemp,
0,
NULL,
NULL );
pchTemp = ( CHAR * )LocalAlloc( LPTR , nMBLen );
if ( pchTemp == NULL )
{
#ifdef DBG
OutputDebugString( L"REGAPI : UsrPropSetString - STATUS_INSUFFICIENT_RESOURCES\n" );
#endif
Status = STATUS_INSUFFICIENT_RESOURCES;
}
else if( !WideCharToMultiByte( CP_ACP,
0 ,
pStringValue ,
nStringLength ,
pchTemp ,
nMBLen ,
NULL ,
NULL ) )
{
#ifdef DBG
// OutputDebugString( L"REGAPI : UsrPropSetString - STATUS_UNSUCCESSFUL wctomb failed.\n" );
DbgPrint( "REGAPI : UsrPropSetString - STATUS_UNSUCCESSFUL wctomb failed with 0x%x.\n" , GetLastError( ) );
#endif
Status = STATUS_UNSUCCESSFUL;
}
if( Status == STATUS_SUCCESS )
{
uniString.Buffer = (WCHAR *) pchTemp;
uniString.Length = (USHORT)nMBLen;
uniString.MaximumLength = (USHORT)nMBLen;
}
}
/*
* Prefix the name with a unique string so that other users of
* the user parameters section of the SAM won't collide with our
* usage.
*/
NBLen = sizeof(CTXPREFIX) + ((wcslen(pStringName) + 1) * sizeof(WCHAR));
pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
if ( !pNameBuf ) {
return( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy( pNameBuf, CTXPREFIX );
wcscat( pNameBuf, pStringName );
Status = Status ? Status : SetUserProperty( pUserParms,
pNameBuf,
uniString,
USER_PROPERTY_TYPE_ITEM,
fDefaultValue,
&lpNewUserParms,
&fUpdate );
LocalFree( pNameBuf );
if ( (Status == STATUS_SUCCESS) && (lpNewUserParms != NULL))
{
if ( fUpdate )
{
if ( (wcslen( lpNewUserParms ) * sizeof(WCHAR)) > UserParmsLength )
{
return( STATUS_BUFFER_TOO_SMALL );
}
lstrcpyW( pUserParms, lpNewUserParms);
}
LocalFree( lpNewUserParms );
}
if ( pchTemp != NULL )
{
LocalFree( pchTemp );
}
return( Status );
}
/*******************************************************************************
*
* UsrPropGetString (UNICODE)
*
* Gets a variable length string from the supplied User Parameters buffer
*
* ENTRY:
* pStringName (input)
* Points to the String Name string
* pStringValue (output)
* Points to the string
* StringValueLength (input)
* Number of bytes in the buffer pointer to by pStringValue
* pUserParms (input)
* Points to the specially formatted User Parameters buffer
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
UsrPropGetString(
TCHAR * pStringName,
TCHAR * pStringValue,
ULONG StringValueLength,
WCHAR * pUserParms
)
{
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING uniString;
WCHAR Flag;
PWCHAR pNameBuf;
ULONG NBLen;
/*
* Prefix the name with a unique string so that other users of
* the user parameters section of the SAM won't collide with our
* usage.
*/
NBLen = sizeof(CTXPREFIX) + ((wcslen(pStringName) + 1) * sizeof(WCHAR));
pNameBuf = (PWCHAR) LocalAlloc( LPTR, NBLen );
if ( !pNameBuf ) {
return( STATUS_INSUFFICIENT_RESOURCES );
}
wcscpy( pNameBuf, CTXPREFIX );
wcscat( pNameBuf, pStringName );
pStringValue[0] = L'\0';
Status = QueryUserProperty( pUserParms, pNameBuf, &Flag, &uniString );
LocalFree( pNameBuf );
if ( !( Status == STATUS_SUCCESS && uniString.Length && uniString.Buffer) ) {
pStringValue[0] = L'\0';
} else {
if ( !MultiByteToWideChar( CP_ACP,
0,
(CHAR *)uniString.Buffer,
uniString.Length,
pStringValue,
StringValueLength ) ) {
Status = STATUS_UNSUCCESSFUL;
}
}
if ( uniString.Buffer ) {
LocalFree( uniString.Buffer );
}
return( Status );
}
/*******************************************************************************
*
* ConnectToSAM (UNICODE)
*
* Given a Server name and a Domain name, connect to the SAM
*
* ENTRY:
* pServerName (input)
* Points to the Server name
* pDomainValue (input)
* Points to the Domain name
* pSAMHandle (output)
* Pointer to the Handle to the SAM
* pDomainHandle (output)
* Pointer to the Handle to the Domain
* pDomainID (ouptut)
* Pointer to the Domain SID
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
ConnectToSam(
BOOLEAN fReadOnly,
LPTSTR pServerName,
LPTSTR pDomainName,
SAM_HANDLE * pSAMHandle,
SAM_HANDLE * pDomainHandle,
PSID * pDomainID
)
{
NTSTATUS status;
OBJECT_ATTRIBUTES object_attrib;
UNICODE_STRING UniDomainName;
UNICODE_STRING UniServerName;
*pSAMHandle = NULL;
*pDomainHandle = NULL;
*pDomainID = NULL;
//
// connect to SAM (Security Account Manager)
//
#ifdef DEBUG
DbgPrint( "ConnectToSam: pServerName %ws, pDomainName %ws\n", pServerName, pDomainName );
#endif // DEBUG
RtlInitUnicodeString(&UniServerName, pServerName);
RtlInitUnicodeString(&UniDomainName, pDomainName);
InitializeObjectAttributes(&object_attrib, NULL, 0, NULL, NULL);
status = SamConnect( &UniServerName,
pSAMHandle,
fReadOnly
? SAM_SERVER_READ |
SAM_SERVER_EXECUTE
: STANDARD_RIGHTS_WRITE |
SAM_SERVER_EXECUTE,
&object_attrib );
#ifdef DEBUG
DbgPrint( "ConnectToSam: SamConnect returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto exit;
}
status = SamLookupDomainInSamServer( *pSAMHandle,
&UniDomainName,
pDomainID);
#ifdef DEBUG
DbgPrint( "ConnectToSam: SamLookupDomainInSamServer returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto cleanupconnect;
}
status = SamOpenDomain( *pSAMHandle,
fReadOnly
? DOMAIN_READ |
DOMAIN_LOOKUP |
DOMAIN_READ_PASSWORD_PARAMETERS
: DOMAIN_READ |
DOMAIN_CREATE_ALIAS |
DOMAIN_LOOKUP |
DOMAIN_CREATE_USER |
DOMAIN_READ_PASSWORD_PARAMETERS,
*pDomainID,
pDomainHandle );
#ifdef DEBUG
DbgPrint( "ConnectToSam: SamOpenDomain returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto cleanuplookup;
}
return( STATUS_SUCCESS );
/*
* Error returns
*/
cleanuplookup:
SamFreeMemory( *pDomainID );
*pDomainID = NULL;
cleanupconnect:
SamCloseHandle( *pSAMHandle );
*pSAMHandle = NULL;
exit:
return( status );
}
/*******************************************************************************
*
* UsrPropQueryUserConfig
*
* Query USERCONFIG info from SAM's User Parameters
*
* ENTRY:
* pUserParms (input)
* pointer to a wide char buffer containing the SAM's User Parameters
* UPlength (input )
* length of the pUserParms buffer
* pUser (output)
* pointer to USERCONFIG structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
UsrPropQueryUserConfig(
WCHAR *pUserParms,
ULONG UPLength,
PUSERCONFIG pUser )
{
ULONG Flags1;
NTSTATUS Status;
ULONG CfgPresent;
USERCONFIG ucDefault;
QueryUserConfig( HKEY_LOCAL_MACHINE , &ucDefault );
/*
* Check if the configuration exits in the User Parameters
*/
if( ( ( Status = UsrPropGetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
pUserParms ) ) != NO_ERROR ) )
{
KdPrint( ( "UsrPropQueryUserConfig: UsrPropGetValue returned NTSTATUS = 0x%x\n", Status ) );
return( Status );
}
else
{
if( CfgPresent != CFGPRESENT_VALUE )
{
KdPrint( ( "UsrPropQueryUserConfig: UsrPropGetValue returned NTSTATUS = 0x%x but TS-signature was not present\n", Status ) );
return( STATUS_OBJECT_NAME_NOT_FOUND );
}
}
Status = UsrPropGetValue( WIN_FLAGS1,
&Flags1,
sizeof(Flags1),
pUserParms );
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_CALLBACK,
&pUser->Callback,
sizeof(pUser->Callback),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->Callback = ucDefault.Callback;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_SHADOW,
&pUser->Shadow,
sizeof(pUser->Shadow),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->Shadow = ucDefault.Shadow;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_MAXCONNECTIONTIME,
&pUser->MaxConnectionTime,
sizeof(pUser->MaxConnectionTime),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->MaxConnectionTime = ucDefault.MaxConnectionTime;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_MAXDISCONNECTIONTIME,
&pUser->MaxDisconnectionTime,
sizeof(pUser->MaxDisconnectionTime),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->MaxDisconnectionTime = ucDefault.MaxDisconnectionTime;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_MAXIDLETIME,
&pUser->MaxIdleTime,
sizeof(pUser->MaxIdleTime),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->MaxIdleTime = ucDefault.MaxIdleTime;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_KEYBOARDLAYOUT,
&pUser->KeyboardLayout,
sizeof(pUser->KeyboardLayout),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->KeyboardLayout = ucDefault.KeyboardLayout;
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetValue( WIN_MINENCRYPTIONLEVEL,
&pUser->MinEncryptionLevel,
sizeof(pUser->MinEncryptionLevel),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
pUser->MinEncryptionLevel = ucDefault.MinEncryptionLevel;
Status = STATUS_SUCCESS;
}
}
// String properties that do not exist are init to NULL
// default values are null so need to fix if ret status is a failure.
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_WORKDIRECTORY,
pUser->WorkDirectory,
sizeof(pUser->WorkDirectory),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_NWLOGONSERVER,
pUser->NWLogonServer,
sizeof(pUser->NWLogonServer),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_WFHOMEDIR,
pUser->WFHomeDir,
sizeof(pUser->WFHomeDir),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_WFHOMEDIRDRIVE,
pUser->WFHomeDirDrive,
sizeof(pUser->WFHomeDir),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_WFPROFILEPATH,
pUser->WFProfilePath,
sizeof(pUser->WFProfilePath),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_INITIALPROGRAM,
pUser->InitialProgram,
sizeof(pUser->InitialProgram),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( NT_SUCCESS( Status ) )
{
Status = UsrPropGetString( WIN_CALLBACKNUMBER,
pUser->CallbackNumber,
sizeof(pUser->CallbackNumber),
pUserParms );
if( Status == STATUS_OBJECT_NAME_NOT_FOUND )
{
Status = STATUS_SUCCESS;
}
}
if( !( NT_SUCCESS( Status ) ) )
{
return( Status );
}
pUser->fInheritAutoLogon =
Flags1 & F1MSK_INHERITAUTOLOGON ? TRUE : FALSE;
pUser->fInheritResetBroken =
Flags1 & F1MSK_INHERITRESETBROKEN ? TRUE : FALSE;
pUser->fInheritReconnectSame =
Flags1 & F1MSK_INHERITRECONNECTSAME ? TRUE : FALSE;
pUser->fInheritInitialProgram =
Flags1 & F1MSK_INHERITINITIALPROGRAM ? TRUE : FALSE;
pUser->fInheritCallback =
Flags1 & F1MSK_INHERITCALLBACK ? TRUE : FALSE;
pUser->fInheritCallbackNumber =
Flags1 & F1MSK_INHERITCALLBACKNUMBER ? TRUE : FALSE;
pUser->fInheritShadow =
Flags1 & F1MSK_INHERITSHADOW ? TRUE : FALSE;
pUser->fInheritMaxSessionTime =
Flags1 & F1MSK_INHERITMAXSESSIONTIME ? TRUE : FALSE;
pUser->fInheritMaxDisconnectionTime =
Flags1 & F1MSK_INHERITMAXDISCONNECTIONTIME ? TRUE : FALSE;
pUser->fInheritMaxIdleTime =
Flags1 & F1MSK_INHERITMAXIDLETIME ? TRUE : FALSE;
pUser->fInheritAutoClient =
Flags1 & F1MSK_INHERITAUTOCLIENT ? TRUE : FALSE;
pUser->fInheritSecurity =
Flags1 & F1MSK_INHERITSECURITY ? TRUE : FALSE;
pUser->fPromptForPassword =
Flags1 & F1MSK_PROMPTFORPASSWORD ? TRUE : FALSE;
pUser->fResetBroken =
Flags1 & F1MSK_RESETBROKEN ? TRUE : FALSE;
pUser->fReconnectSame =
Flags1 & F1MSK_RECONNECTSAME ? TRUE : FALSE;
pUser->fLogonDisabled =
Flags1 & F1MSK_LOGONDISABLED ? TRUE : FALSE;
pUser->fAutoClientDrives =
Flags1 & F1MSK_AUTOCLIENTDRIVES ? TRUE : FALSE;
pUser->fAutoClientLpts =
Flags1 & F1MSK_AUTOCLIENTLPTS ? TRUE : FALSE;
pUser->fForceClientLptDef =
Flags1 & F1MSK_FORCECLIENTLPTDEF ? TRUE : FALSE;
pUser->fDisableEncryption =
Flags1 & F1MSK_DISABLEENCRYPTION ? TRUE : FALSE;
pUser->fHomeDirectoryMapRoot =
Flags1 & F1MSK_HOMEDIRECTORYMAPROOT ? TRUE : FALSE;
pUser->fUseDefaultGina =
Flags1 & F1MSK_USEDEFAULTGINA ? TRUE : FALSE;
pUser->fDisableCpm =
Flags1 & F1MSK_DISABLECPM ? TRUE : FALSE;
pUser->fDisableCdm =
Flags1 & F1MSK_DISABLECDM ? TRUE : FALSE;
pUser->fDisableCcm =
Flags1 & F1MSK_DISABLECCM ? TRUE : FALSE;
pUser->fDisableLPT =
Flags1 & F1MSK_DISABLELPT ? TRUE : FALSE;
pUser->fDisableClip =
Flags1 & F1MSK_DISABLECLIP ? TRUE : FALSE;
pUser->fDisableExe =
Flags1 & F1MSK_DISABLEEXE ? TRUE : FALSE;
pUser->fWallPaperDisabled =
Flags1 & F1MSK_WALLPAPERDISABLED ? TRUE : FALSE;
pUser->fDisableCam =
Flags1 & F1MSK_DISABLECAM ? TRUE : FALSE;
return( STATUS_SUCCESS );
}
/*******************************************************************************
*
* UsrPropMergeUserConfig
*
* Merge USERCONFIG structure into User Properties section of SAM
*
* ENTRY:
* pUserParms (input/output)
* pointer to a wide char buffer containing the SAM's User Parameters
* UPlength (input )
* length of the pUserParms buffer
* pUser (input)
* pointer to USERCONFIG structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
* NOTES:
* Certain properties have to be stored regardless if they're default or not
* this is done to maintain compatibility for TSE4.0 and W2K servers
******************************************************************************/
NTSTATUS
UsrPropMergeUserConfig(
WCHAR *pUserParms,
ULONG UPLength,
PUSERCONFIG pUser )
{
ULONG Flags1;
NTSTATUS Status;
USERCONFIG ucDefault;
ULONG CfgPresent = CFGPRESENT_VALUE;
BOOL fDefaultValue = FALSE;
// 1st parameter forces default values to be placed in ucDefault
QueryUserConfig( HKEY_LOCAL_MACHINE , &ucDefault );
Flags1 = GetFlagMask( pUser );
// this value needs to be written out
Status = UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pUserParms,
UPLength );
if( NT_SUCCESS( Status ) )
{
// these values must be written out for TS4 & TS5.0
Status = UsrPropSetValue( WIN_FLAGS1,
&Flags1,
sizeof(Flags1),
FALSE,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->Callback == ucDefault.Callback );
Status = UsrPropSetValue( WIN_CALLBACK,
&pUser->Callback,
sizeof(pUser->Callback),
fDefaultValue,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
// this value must be written out for backcompat servers
Status = UsrPropSetValue( WIN_SHADOW,
&pUser->Shadow,
sizeof(pUser->Shadow),
FALSE,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->MaxConnectionTime == ucDefault.MaxConnectionTime );
Status = UsrPropSetValue( WIN_MAXCONNECTIONTIME,
&pUser->MaxConnectionTime,
sizeof(pUser->MaxConnectionTime),
fDefaultValue,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->MaxDisconnectionTime == ucDefault.MaxDisconnectionTime );
Status = UsrPropSetValue( WIN_MAXDISCONNECTIONTIME,
&pUser->MaxDisconnectionTime,
sizeof(pUser->MaxDisconnectionTime),
fDefaultValue,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->MaxIdleTime == ucDefault.MaxIdleTime );
Status = UsrPropSetValue( WIN_MAXIDLETIME,
&pUser->MaxIdleTime,
sizeof(pUser->MaxIdleTime),
fDefaultValue,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->KeyboardLayout == ucDefault.KeyboardLayout );
Status = UsrPropSetValue( WIN_KEYBOARDLAYOUT,
&pUser->KeyboardLayout,
sizeof(pUser->KeyboardLayout),
fDefaultValue,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
// always store minencryption level for backwards compatibilty purposes
Status = UsrPropSetValue( WIN_MINENCRYPTIONLEVEL,
&pUser->MinEncryptionLevel,
sizeof(pUser->MinEncryptionLevel),
FALSE,
pUserParms,
UPLength );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->WorkDirectory[0] == 0 );
Status = UsrPropSetString( WIN_WORKDIRECTORY,
pUser->WorkDirectory,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->NWLogonServer[0] == 0 );
Status = UsrPropSetString( WIN_NWLOGONSERVER,
pUser->NWLogonServer,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->WFHomeDir[0] == 0 );
Status = UsrPropSetString( WIN_WFHOMEDIR,
pUser->WFHomeDir,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->WFHomeDirDrive[0] == 0 );
Status = UsrPropSetString( WIN_WFHOMEDIRDRIVE,
pUser->WFHomeDirDrive,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->WFProfilePath[0] == 0 );
Status = UsrPropSetString( WIN_WFPROFILEPATH,
pUser->WFProfilePath,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->InitialProgram[0] == 0 );
Status = UsrPropSetString( WIN_INITIALPROGRAM,
pUser->InitialProgram,
pUserParms,
UPLength,
fDefaultValue );
}
if( NT_SUCCESS( Status ) )
{
fDefaultValue = ( pUser->CallbackNumber[0] == 0 );
Status = UsrPropSetString( WIN_CALLBACKNUMBER,
pUser->CallbackNumber,
pUserParms,
UPLength,
fDefaultValue );
}
return( Status );
}
/*******************************************************************************
GetFlagMask
Assembles a bitmask of flags set in pUser
*******************************************************************************/
ULONG GetFlagMask( PUSERCONFIG pUser )
{
ULONG Flags1 = 0;
if ( pUser->fInheritAutoLogon ) {
Flags1 |= F1MSK_INHERITAUTOLOGON;
}
if ( pUser->fInheritResetBroken ) {
Flags1 |= F1MSK_INHERITRESETBROKEN;
}
if ( pUser->fInheritReconnectSame ) {
Flags1 |= F1MSK_INHERITRECONNECTSAME;
}
if ( pUser->fInheritInitialProgram ) {
Flags1 |= F1MSK_INHERITINITIALPROGRAM;
}
if ( pUser->fInheritCallback ) {
Flags1 |= F1MSK_INHERITCALLBACK;
}
if ( pUser->fInheritCallbackNumber ) {
Flags1 |= F1MSK_INHERITCALLBACKNUMBER;
}
if ( pUser->fInheritShadow ) {
Flags1 |= F1MSK_INHERITSHADOW;
}
if ( pUser->fInheritMaxSessionTime ) {
Flags1 |= F1MSK_INHERITMAXSESSIONTIME;
}
if ( pUser->fInheritMaxDisconnectionTime ) {
Flags1 |= F1MSK_INHERITMAXDISCONNECTIONTIME;
}
if ( pUser->fInheritMaxIdleTime ) {
Flags1 |= F1MSK_INHERITMAXIDLETIME;
}
if ( pUser->fInheritAutoClient ) {
Flags1 |= F1MSK_INHERITAUTOCLIENT;
}
if ( pUser->fInheritSecurity ) {
Flags1 |= F1MSK_INHERITSECURITY;
}
if ( pUser->fPromptForPassword ) {
Flags1 |= F1MSK_PROMPTFORPASSWORD;
}
if ( pUser->fResetBroken ) {
Flags1 |= F1MSK_RESETBROKEN;
}
if ( pUser->fReconnectSame ) {
Flags1 |= F1MSK_RECONNECTSAME;
}
if ( pUser->fLogonDisabled ) {
Flags1 |= F1MSK_LOGONDISABLED;
}
if ( pUser->fAutoClientDrives ) {
Flags1 |= F1MSK_AUTOCLIENTDRIVES;
}
if ( pUser->fAutoClientLpts ) {
Flags1 |= F1MSK_AUTOCLIENTLPTS;
}
if ( pUser->fForceClientLptDef ) {
Flags1 |= F1MSK_FORCECLIENTLPTDEF;
}
if ( pUser->fDisableEncryption ) {
Flags1 |= F1MSK_DISABLEENCRYPTION;
}
if ( pUser->fHomeDirectoryMapRoot ) {
Flags1 |= F1MSK_HOMEDIRECTORYMAPROOT;
}
if ( pUser->fUseDefaultGina ) {
Flags1 |= F1MSK_USEDEFAULTGINA;
}
if ( pUser->fDisableCpm ) {
Flags1 |= F1MSK_DISABLECPM;
}
if ( pUser->fDisableCdm ) {
Flags1 |= F1MSK_DISABLECDM;
}
if ( pUser->fDisableCcm ) {
Flags1 |= F1MSK_DISABLECCM;
}
if ( pUser->fDisableLPT ) {
Flags1 |= F1MSK_DISABLELPT;
}
if ( pUser->fDisableClip ) {
Flags1 |= F1MSK_DISABLECLIP;
}
if ( pUser->fDisableExe ) {
Flags1 |= F1MSK_DISABLEEXE;
}
if ( pUser->fWallPaperDisabled ) {
Flags1 |= F1MSK_WALLPAPERDISABLED;
}
if ( pUser->fDisableCam ) {
Flags1 |= F1MSK_DISABLECAM;
}
return Flags1;
}
/*******************************************************************************
*
* RegMergeUserConfigWithUserParameters
*
* Merge the User Configuration with the supplied SAM's User
* Parameters buffer.
*
* ENTRY:
* pUserParms (input/output)
* pointer to a wide char buffer containing the SAM's User Parameters
* UPlength (input)
* length of the pUserParms buffer
* pUser (input)
* pointer to USERCONFIG structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
RegMergeUserConfigWithUserParameters(
PUSER_PARAMETERS_INFORMATION pUserParmInfo,
PUSERCONFIGW pUser,
PUSER_PARAMETERS_INFORMATION pNewUserParmInfo
)
{
NTSTATUS status;
ULONG ObjectID;
PWCHAR lpNewUserParms = NULL;
ULONG UPLength;
WCHAR *pUserParms;
/*
* Compute the size the user parameter buffer must be
* in order to accommodate the CITRIX data plus the existing
* User Parameters data.
*/
KdPrint( ("TSUSEREX: User parameter length is %d\n", pUserParmInfo->Parameters.Length ) );
UPLength = (pUserParmInfo->Parameters.Length +
CTX_USER_PARAM_MAX_SIZE) *
sizeof(WCHAR);
pUserParms = (WCHAR *) LocalAlloc( LPTR, UPLength );
if ( pUserParms == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
/*
* Copy SAM data to the local buffer.
* Let the Set/Get operation terminate the buffer.
*/
memcpy( pUserParms,
pUserParmInfo->Parameters.Buffer,
pUserParmInfo->Parameters.Length );
/*
* Zero fill the unused portion of the pUserParms buffer.
*/
memset( &pUserParms[ pUserParmInfo->Parameters.Length / sizeof(WCHAR) ],
0,
UPLength - pUserParmInfo->Parameters.Length );
status = UsrPropMergeUserConfig( pUserParms, UPLength, pUser );
if ( status != NO_ERROR ) {
goto cleanupoperation;
}
RtlInitUnicodeString( &pNewUserParmInfo->Parameters, pUserParms );
return( STATUS_SUCCESS );
/*
* Error returns
*/
cleanupoperation:
LocalFree( pUserParms );
exit:
return( status );
}
/*******************************************************************************
*
* RegGetUserConfigFromUserParameters
*
* Get the User Configuration from the supplied SAM's
* User Parameters buffer.
*
* ENTRY:
* pUserParmInfo (input)
* pointer to a USER_PARAMETERS_INFORMATION structure obtained from
* a user's SAM entry
* pUser (input)
* pointer to USERCONFIG structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
RegGetUserConfigFromUserParameters(
PUSER_PARAMETERS_INFORMATION pUserParmInfo,
PUSERCONFIGW pUser
)
{
NTSTATUS status;
ULONG ObjectID;
PWCHAR lpNewUserParms = NULL;
ULONG UPLength;
WCHAR *pUserParms;
/*
* Compute the size the user parameter buffer must be
* in order to accommodate the existing User Parameters.
*/
UPLength = pUserParmInfo->Parameters.Length + sizeof(WCHAR);
pUserParms = (WCHAR *) LocalAlloc( LPTR, UPLength );
if ( pUserParms == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
/*
* Copy SAM data to the local buffer and terminate the buffer.
*/
memcpy( pUserParms,
pUserParmInfo->Parameters.Buffer,
pUserParmInfo->Parameters.Length );
pUserParms[ pUserParmInfo->Parameters.Length / sizeof(WCHAR) ] = L'\0';
/*
* Extract the User Configuration from the SAM's User
* Parameters.
*/
status = UsrPropQueryUserConfig( pUserParms, UPLength, pUser );
LocalFree( pUserParms );
if ( status != NO_ERROR ) {
goto exit;
}
return( STATUS_SUCCESS );
/*
* Error returns
*/
exit:
#ifdef DEBUG
DbgPrint( "RegGetUserConfigFromUserParameters: status = 0x%x\n", status );
#endif // DEBUG
return( status );
}
/*******************************************************************************
*
* RegSAMUserConfig
*
* Set or Get the User Configuration for a user from the Domain whose
* PDC is server is given.
*
* ENTRY:
* fGetConfig (input)
* TRUE for Get config, FALSE for Set configuration
* pUsername (input)
* points to the user name
* pServerName (input)
* points to the name of the server. UNC names permitted.
* pUser (input/output)
* pointer to USERCONFIG structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
DWORD
RegSAMUserConfig(
BOOLEAN fGetConfig,
PWCHAR pUserName,
PWCHAR pServerName,
PUSERCONFIGW pUser
)
{
NTSTATUS status;
UNICODE_STRING UniUserName;
PULONG pRids = NULL;
PSID_NAME_USE pSidNameUse = NULL;
ULONG ObjectID;
SID_NAME_USE SidNameUse;
SAM_HANDLE Handle = (SAM_HANDLE) 0;
PUSER_PARAMETERS_INFORMATION UserParmInfo = NULL;
ULONG UPLength;
SAM_HANDLE SAMHandle = NULL;
SAM_HANDLE DomainHandle = NULL;
PWCHAR ServerName = NULL;
PSID DomainID = NULL;
PWCHAR pUserParms;
PWCHAR pDomainName = NULL;
WCHAR wCompName[MAX_COMPUTERNAME_LENGTH+1];
ULONG openFlag;
DWORD dwErr = ERROR_SUCCESS;
ULONG cValues;
HANDLE hDS = NULL;
PDS_NAME_RESULTW pDsResult = NULL;
typedef DWORD (WINAPI *PFNDSCRACKNAMES) ( HANDLE, DS_NAME_FLAGS, DS_NAME_FORMAT, \
DS_NAME_FORMAT, DWORD, LPTSTR *, PDS_NAME_RESULT *);
typedef void (WINAPI *PFNDSFREENAMERESULT) (DS_NAME_RESULT *);
typedef DWORD (WINAPI *PFNDSBIND) (TCHAR *, TCHAR *, HANDLE *);
typedef DWORD (WINAPI *PFNDSUNBIND) (HANDLE *);
PFNDSCRACKNAMES pfnDsCrackNamesW;
PFNDSFREENAMERESULT pfnDsFreeNameResultW;
PFNDSBIND pfnDsBindW;
PFNDSUNBIND pfnDsUnBindW;
// vars used for handling UPN anmes
WCHAR tmpUserName[MAX_PATH];
WCHAR *pUserAlias;
HINSTANCE hNtdsApi = NULL;
// We dont' care about the domain since we get it otherwise.
// WCHAR tmpDomainName[ MAX_PATH];
// tmpDomainName[0]=NULL;
tmpUserName[0]=0;
pUserAlias=NULL;
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig %s, User %ws, Server %ws\n", fGetConfig ? "GET" : "SET", pUserName, pServerName ? pServerName : L"-NULL-" );
#endif // DEBUG
if (pServerName == NULL) {
UPLength = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerName(wCompName, &UPLength)) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
}
// init this to the name passed in, if it is not a UPN name, we will continue to use
// the names passed into this function.
pUserAlias = pUserName;
//
//
// NEW code to handle UPN if the name passed in contains a '@' in the name.
// The call to CrackName is to seperate the UPN name into the user alias by
// contacting the DS and looking in the Gloabl-Catalog.
//
//
if ( wcschr(pUserName,L'@') != NULL )
{
hNtdsApi = LoadLibrary(TEXT("ntdsapi.dll"));
if ( hNtdsApi )
{
pfnDsCrackNamesW = (PFNDSCRACKNAMES)GetProcAddress(hNtdsApi, "DsCrackNamesW");
pfnDsFreeNameResultW = (PFNDSFREENAMERESULT)GetProcAddress(hNtdsApi, "DsFreeNameResultW");
pfnDsBindW = (PFNDSBIND)GetProcAddress(hNtdsApi, "DsBindW");
pfnDsUnBindW = (PFNDSUNBIND)GetProcAddress(hNtdsApi, "DsUnBindW");
if (pfnDsBindW && pfnDsCrackNamesW )
{
dwErr = pfnDsBindW(NULL, NULL, &hDS);
}
else
{
dwErr = ERROR_INVALID_FUNCTION;
}
if(dwErr == ERROR_SUCCESS)
{
dwErr = pfnDsCrackNamesW(hDS,
DS_NAME_NO_FLAGS,
DS_UNKNOWN_NAME,
DS_NT4_ACCOUNT_NAME,
1,
&pUserName,
&pDsResult);
if(dwErr == ERROR_SUCCESS)
{
if(pDsResult)
{
if( pDsResult->rItems )
{
if (pDsResult->rItems[0].pName )
{
// no error
status = STATUS_SUCCESS;
wcscpy(tmpUserName, pDsResult->rItems[0].pName);
KdPrint(("RegSAMUserConfig: tmpUserName=%ws\n",tmpUserName));
// do we have a non-null name?
if ( tmpUserName[0] ) {
pUserAlias = wcschr(tmpUserName,L'\\');
pUserAlias++; //move pass the wack.
// we are not using the domain name, we already have this
// wcscpy(tmpDomainName, pDsResult->rItems[0].pDomain);
}
}
else
{
KdPrint(("RegSAMUserConfig: pDsResult->rItems[0].pName is NULL\n"));
}
}
else
{
KdPrint(("RegSAMUserConfig: pDsResult->rItems=0x%lx\n",pDsResult->rItems));
}
}
else
{
KdPrint(("RegSAMUserConfig: pDsResult=0x%lx\n",pDsResult));
}
}
else
{
switch( dwErr )
{
case ERROR_INVALID_PARAMETER:
status = STATUS_INVALID_PARAMETER;
break;
case ERROR_NOT_ENOUGH_MEMORY:
status = STATUS_NO_MEMORY;
break;
default:
status = STATUS_UNSUCCESSFUL;
break;
}
// have decided to continue using the passed-in pUserName instead of what
// would have been returned from CrackName. Hence, no need to exit.
// goto exit;
}
}
else
{
status = STATUS_UNSUCCESSFUL; // DsBindW doesn't have a clean set of errors.
// have decided to continue using the passed-in pUserName instead of what
// would have been returned from DsBind/CrackName. Hence, no need to exit.
// goto exit;
}
}
else
{
status = STATUS_DLL_NOT_FOUND;
// have decided to continue using the passed-in pUserName instead of what
// would have been returned from DsBind/CrackName. Hence, no need to exit.
// goto exit;
}
}
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig: pUserAlias=%ws\n", pUserAlias);
#endif // DEBUG
status = GetDomainName( pServerName, &pDomainName );
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig: GetDomainName returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto exit;
}
/*
* With the PDC Server name and the Domain Name,
* connect to the SAM
*/
status = ConnectToSam( fGetConfig,
pServerName,
pDomainName,
&SAMHandle,
&DomainHandle,
&DomainID );
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig: ConnectToSam returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto cleanupconnect;
}
RtlInitUnicodeString( &UniUserName, pUserAlias );
status = SamLookupNamesInDomain( DomainHandle,
1,
&UniUserName,
&pRids,
&pSidNameUse );
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig: SamLookupNamesInDomain returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ((status != STATUS_SUCCESS) ||
(pRids == NULL) ||
(pSidNameUse == NULL)) {
goto cleanuplookup;
}
/*
* Found the user name in the SAM, copy and free SAM info
*/
ObjectID = pRids[ 0 ];
SidNameUse = pSidNameUse[ 0 ];
SamFreeMemory( pRids );
SamFreeMemory( pSidNameUse );
/*
* Open the SAM entry for this user
*/
openFlag = fGetConfig ? USER_READ
: USER_WRITE_ACCOUNT| USER_READ;
#ifdef DEBUG
DbgPrint("calling SamOpenUSer with flag = 0x%x\n", openFlag);
#endif
status = SamOpenUser( DomainHandle,
openFlag,
ObjectID,
&Handle );
// For getting config parametesr...
// The call will fail if it goes to the DC, for that case, change
// flag, since DC does allow access to read user-parameters (for
// legacy compat reasons).
if (!NT_SUCCESS( status ) && fGetConfig )
{
openFlag = 0;
#ifdef DEBUG
DbgPrint("calling SamOpenUSer with flag = 0x%x\n", openFlag);
#endif
status = SamOpenUser( DomainHandle,
openFlag,
ObjectID,
&Handle );
}
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig: SamOpenUser returned NTSTATUS = 0x%x\n", status );
#endif // DEBUG
if ( status != STATUS_SUCCESS ) {
goto cleanupsamopen;
}
/*
* Get the user parameters from the SAM
*/
status = SamQueryInformationUser( Handle,
UserParametersInformation,
(PVOID *) &UserParmInfo );
KdPrint( ( "RegSAMUserConfig: SamQueryInformationUser returned NTSTATUS = 0x%x\n", status ) );
if ( status != STATUS_SUCCESS || UserParmInfo == NULL ) {
goto cleanupsamquery;
}
if( fGetConfig )
{
/*
* Extract the User Configuration from the SAM's User
* Parameters.
*
* For Whistler builds and higher we assume that not every field
* has been stored in the SAM we'll need to retrieve the default
* values first
*/
KdPrint( ( "RegSAMUserConfig: UserParmInfo %d\n", UserParmInfo->Parameters.Length ) );
status = RegGetUserConfigFromUserParameters( UserParmInfo, pUser );
KdPrint( ( "RegSAMUserConfig: RegGetUserConfigFromUserParameters returned NTSTATUS = 0x%x\n", status ) );
SamFreeMemory( UserParmInfo );
UserParmInfo = NULL;
if ( status != NO_ERROR )
{
goto cleanupoperation;
}
}
else
{
USER_PARAMETERS_INFORMATION NewUserParmInfo;
/*
* Set the SAM based on the supplied User Configuration.
*/
status = RegMergeUserConfigWithUserParameters( UserParmInfo,
pUser,
&NewUserParmInfo );
KdPrint( ( "RegSAMUserConfig: RegMergeUserConfigWithUserParameters returned NTSTATUS = 0x%x\n", status ) );
SamFreeMemory( UserParmInfo );
UserParmInfo = NULL;
if( status != NO_ERROR )
{
goto cleanupoperation;
}
status = SamSetInformationUser( Handle,
UserParametersInformation,
(PVOID) &NewUserParmInfo );
KdPrint( ( "RegSAMUserConfig: NewUserParmInfo.Parameters.Length = %d\n" , NewUserParmInfo.Parameters.Length ) );
KdPrint( ( "RegSAMUserConfig: SamSetInformationUser returned NTSTATUS = 0x%x\n", status ) );
LocalFree( NewUserParmInfo.Parameters.Buffer );
if ( status != STATUS_SUCCESS )
{
goto cleanupoperation;
}
}
cleanupoperation:
if ( UserParmInfo ) {
SamFreeMemory( UserParmInfo );
}
cleanupsamquery:
if ( Handle != (SAM_HANDLE) 0 ) {
SamCloseHandle( Handle );
}
cleanupsamopen:
cleanuplookup:
if ( SAMHandle != (SAM_HANDLE) 0 ) {
SamCloseHandle( SAMHandle );
}
if ( DomainHandle != (SAM_HANDLE) 0 ) {
SamCloseHandle( DomainHandle );
}
if ( DomainID != (PSID) 0 ) {
SamFreeMemory( DomainID );
}
cleanupconnect:
if ( pDomainName ) {
NetApiBufferFree( pDomainName );
}
exit:
if (hNtdsApi)
{
if (hDS)
{
if ( pfnDsUnBindW ) // it should never be otherwise.
pfnDsUnBindW( & hDS );
}
if (pDsResult)
{
if (pfnDsFreeNameResultW ) // it should never be otherwise.
pfnDsFreeNameResultW( pDsResult );
}
FreeLibrary(hNtdsApi);
}
#ifdef DEBUG
DbgPrint( "RegSAMUserConfig %s NTSTATUS = 0x%x\n", fGetConfig ? "GET" : "SET", status );
#endif // DEBUG
return( RtlNtStatusToDosError( status ) );
}