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.
1839 lines
59 KiB
1839 lines
59 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>
|
|
#include <mprapi.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, PWINSTATIONNAMEW );
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* 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/sizeof(TCHAR) ) ) {
|
|
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, NULL );
|
|
|
|
/*
|
|
* 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->WFHomeDirDrive),
|
|
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 ))
|
|
{
|
|
pUser->fErrorInvalidProfile = TRUE;
|
|
}
|
|
}
|
|
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, NULL );
|
|
|
|
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;
|
|
|
|
wcsncpy(tmpUserName, pDsResult->rItems[0].pName, MAX_PATH-1);
|
|
tmpUserName[MAX_PATH-1] = L'\0';
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
//This code is back-porting of a Win2K SP3 fix:
|
|
// Winse #25510 : As per KBArticle Q317853
|
|
// See also KBArticle Q277631
|
|
//
|
|
|
|
//
|
|
// MprAdminUser APIs
|
|
//
|
|
{
|
|
typedef DWORD (APIENTRY *MPR_ADMIN_USER_GET_INFO)(
|
|
IN const WCHAR * lpszServer,
|
|
IN const WCHAR * lpszUser,
|
|
IN DWORD dwLevel,
|
|
OUT LPBYTE lpbBuffer
|
|
);
|
|
|
|
typedef DWORD (APIENTRY *MPR_ADMIN_USER_SET_INFO)(
|
|
IN const WCHAR * lpszServer,
|
|
IN const WCHAR * lpszUser,
|
|
IN DWORD dwLevel,
|
|
IN const LPBYTE lpbBuffer
|
|
);
|
|
|
|
//
|
|
//This code initializes RAS userparams
|
|
//If we don't do this, SamSetInformationUser()
|
|
//will set Remote Access Permission (msNPAllowDialin)
|
|
//to a wrong value.
|
|
//
|
|
RAS_USER_1 ru1;
|
|
MPR_ADMIN_USER_GET_INFO pMprAdminUserGetInfo = NULL;
|
|
MPR_ADMIN_USER_SET_INFO pMprAdminUserSetInfo = NULL;
|
|
|
|
HMODULE hMprDLL = LoadLibrary(L"mprapi.dll");
|
|
|
|
if(hMprDLL)
|
|
{
|
|
pMprAdminUserGetInfo = (MPR_ADMIN_USER_GET_INFO)GetProcAddress(hMprDLL,"MprAdminUserGetInfo");
|
|
pMprAdminUserSetInfo = (MPR_ADMIN_USER_SET_INFO)GetProcAddress(hMprDLL,"MprAdminUserSetInfo");
|
|
|
|
if(pMprAdminUserGetInfo && pMprAdminUserSetInfo)
|
|
{
|
|
if(pMprAdminUserGetInfo( pServerName, pUserName, 1, (PBYTE) &ru1 ) == NO_ERROR )
|
|
{
|
|
pMprAdminUserSetInfo( pServerName, pUserName, 1, (PBYTE) &ru1 );
|
|
}
|
|
}
|
|
|
|
FreeLibrary(hMprDLL);
|
|
}
|
|
|
|
}
|
|
|
|
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 ) );
|
|
}
|
|
|