/************************************************************************* * * reguc.c * * Registry APIs for SAM-based user configuration data * * Copyright (c) 1998 Microsoft Corporation * * * *************************************************************************/ /* * Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 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 ) ); }