/************************************************************************* * * regwin.c * * Register APIs for window stations * * Copyright (c) 1998 Microsoft Corporation * * *************************************************************************/ /* * Includes */ #include #include #include #include #include #include #include #include // extern HKEY g_hTSPolicyKey;//handle to TS_POLICY_SUB_TREE key extern HKEY g_hTSControlKey;//handle to REG_CONTROL_TSERVER key /* * External Procedures defined here */ LONG WINAPI RegWinStationAccessCheck( HANDLE, REGSAM ); LONG WINAPI RegWinStationEnumerateW( HANDLE, PULONG, PULONG, PWINSTATIONNAMEW, PULONG ); LONG WINAPI RegWinStationEnumerateA( HANDLE, PULONG, PULONG, PWINSTATIONNAMEA, PULONG ); LONG WINAPI RegWinStationCreateW( HANDLE, PWINSTATIONNAMEW, BOOLEAN, PWINSTATIONCONFIG2W, ULONG ); LONG WINAPI RegWinStationCreateA( HANDLE, PWINSTATIONNAMEA, BOOLEAN, PWINSTATIONCONFIG2A, ULONG ); LONG WINAPI RegWinStationQueryW( HANDLE, PWINSTATIONNAMEW, PWINSTATIONCONFIG2W, ULONG, PULONG ); LONG WINAPI RegWinStationQueryA( HANDLE, PWINSTATIONNAMEA, PWINSTATIONCONFIG2A, ULONG, PULONG ); LONG WINAPI RegWinStationDeleteW( HANDLE, PWINSTATIONNAMEW ); LONG WINAPI RegWinStationDeleteA( HANDLE, PWINSTATIONNAMEA ); LONG WINAPI RegWinStationSetSecurityW( HANDLE, PWINSTATIONNAMEW, PSECURITY_DESCRIPTOR, ULONG ); LONG WINAPI RegWinStationSetSecurityA( HANDLE, PWINSTATIONNAMEA, PSECURITY_DESCRIPTOR, ULONG ); LONG WINAPI RegWinStationQuerySecurityW( HANDLE, PWINSTATIONNAMEW, PSECURITY_DESCRIPTOR, ULONG, PULONG ); LONG WINAPI RegWinStationQuerySecurityA( HANDLE, PWINSTATIONNAMEA, PSECURITY_DESCRIPTOR, ULONG, PULONG ); LONG WINAPI RegWinStationQueryDefaultSecurity( HANDLE, PSECURITY_DESCRIPTOR, ULONG, PULONG ); LONG WINAPI RegWinStationSetNumValueW( HANDLE, PWINSTATIONNAMEW, LPWSTR, ULONG ); LONG WINAPI RegWinStationQueryNumValueW( HANDLE, PWINSTATIONNAMEW, LPWSTR, PULONG ); LONG WINAPI RegConsoleShadowQueryA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, PWDPREFIXA pWdPrefixName, PWINSTATIONCONFIG2A pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ); LONG WINAPI RegConsoleShadowQueryW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PWDPREFIXW pWdPrefixName, PWINSTATIONCONFIG2W pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ); /* * Private Procedures defined here */ LONG _RegOpenWinStation( PWINSTATIONNAMEW, REGSAM, HKEY * ); LONG _RegGetWinStationSecurity( HKEY, LPWSTR, PSECURITY_DESCRIPTOR, ULONG, PULONG ); /* * other internal Procedures used (not defined here) */ VOID CreateWinStaCreate( HKEY, PWINSTATIONCREATE ); VOID CreateConfig( HKEY, PWINSTATIONCONFIG, PWINSTATIONNAMEW ); VOID CreateUserConfig( HKEY, PUSERCONFIG, PWINSTATIONNAMEW ); VOID CreateWd( HKEY, PWDCONFIG ); VOID CreateCd( HKEY, PCDCONFIG ); VOID CreatePdConfig( BOOLEAN, HKEY, PPDCONFIG, ULONG ); VOID QueryWinStaCreate( HKEY, PWINSTATIONCREATE ); VOID QueryConfig( HKEY, PWINSTATIONCONFIG, PWINSTATIONNAMEW ); VOID QueryTSProfileAndHomePaths( PUSERCONFIG ); VOID QueryWd( HKEY, PWDCONFIG ); VOID QueryCd( HKEY, PCDCONFIG ); VOID QueryPdConfig( HKEY, PPDCONFIG, PULONG ); VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * ); VOID AnsiToUnicode( WCHAR *, ULONG, CHAR * ); VOID PdConfigU2A( PPDCONFIGA, PPDCONFIGW ); VOID PdConfigA2U( PPDCONFIGW, PPDCONFIGA ); VOID WdConfigU2A( PWDCONFIGA, PWDCONFIGW ); VOID WdConfigA2U( PWDCONFIGW, PWDCONFIGA ); VOID CdConfigU2A( PCDCONFIGA, PCDCONFIGW ); VOID CdConfigA2U( PCDCONFIGW, PCDCONFIGA ); VOID WinStationCreateU2A( PWINSTATIONCREATEA, PWINSTATIONCREATEW ); VOID WinStationCreateA2U( PWINSTATIONCREATEW, PWINSTATIONCREATEA ); VOID WinStationConfigU2A( PWINSTATIONCONFIGA, PWINSTATIONCONFIGW ); VOID WinStationConfigA2U( PWINSTATIONCONFIGW, PWINSTATIONCONFIGA ); VOID DeleteUserOverRideSubkey(HKEY); /**************************************************************************** * * DllEntryPoint * * Function is called when the DLL is loaded and unloaded. * * ENTRY: * hinstDLL (input) * Handle of DLL module * * fdwReason (input) * Why function was called * * lpvReserved (input) * Reserved; must be NULL * * EXIT: * TRUE - Success * FALSE - Error occurred * ****************************************************************************/ #ifndef REGAPILIB BOOL WINAPI DllEntryPoint( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) { switch ( fdwReason ) { case DLL_PROCESS_ATTACH: break; case DLL_PROCESS_DETACH: if( g_hTSPolicyKey ) { RegCloseKey(g_hTSPolicyKey); } if( g_hTSControlKey ) { RegCloseKey(g_hTSControlKey); } break; default: break; } return( TRUE ); } #endif /******************************************************************************* * * RegWinStationAccessCheck (ANSI or UNICODE) * * Determines if the current user has the requested access to the * WinStation registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * samDesired (input) * Specifies the security access mask to be used in determining access * to the WinStation registry. * * EXIT: * ERROR_SUCCESS if the user has the requested access * other error value (most likely ERROR_ACCESS_DENIED) if the user does * not have the requested access. * ******************************************************************************/ LONG WINAPI RegWinStationAccessCheck( HANDLE hServer, REGSAM samDesired ) { LONG Status; HKEY Handle; /* * Attempt to open the registry (LOCAL_MACHINE\....\Citrix\Pd) * at the requested access level. */ if ( (Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, samDesired, &Handle )) == ERROR_SUCCESS ) RegCloseKey( Handle ); return( Status ); } /******************************************************************************* * * RegWinStationEnumerateA (ANSI stub) * * Returns a list of configured WinStations in the registry. * * ENTRY: * see RegWinStationEnumerateW * * EXIT: * see RegWinStationEnumerateW, plus * * ERROR_NOT_ENOUGH_MEMORY - the LocalAlloc failed * ******************************************************************************/ LONG WINAPI RegWinStationEnumerateA( HANDLE hServer, PULONG pIndex, PULONG pEntries, PWINSTATIONNAMEA pWinStationName, PULONG pByteCount ) { PWINSTATIONNAMEW pBuffer = NULL, pWinStationNameW; LONG Status; ULONG Count, ByteCountW = (*pByteCount << 1); /* * If the caller supplied a buffer and the length is not 0, * allocate a corresponding (*2) buffer for UNICODE strings. */ if ( pWinStationName && ByteCountW ) { if ( !(pBuffer = LocalAlloc(0, ByteCountW)) ) return ( ERROR_NOT_ENOUGH_MEMORY ); } /* * Enumerate WinStations */ pWinStationNameW = pBuffer; Status = RegWinStationEnumerateW( hServer, pIndex, pEntries, pWinStationNameW, &ByteCountW ); /* * Always /2 the resultant ByteCount (whether sucessful or not). */ *pByteCount = (ByteCountW >> 1); /* * If the function completed sucessfully and caller * (and stub) defined a buffer to copy into, perform conversion * from UNICODE to ANSI. Note: sucessful return may have copied * 0 items from registry (end of enumeration), denoted by *pEntries * == 0. */ if ( ((Status == ERROR_SUCCESS) || (Status == ERROR_NO_MORE_ITEMS)) && pWinStationNameW && pWinStationName ) { for ( Count = *pEntries; Count; Count-- ) { UnicodeToAnsi( pWinStationName, sizeof(WINSTATIONNAMEA), pWinStationNameW ); (char*)pWinStationName += sizeof(WINSTATIONNAMEA); (char*)pWinStationNameW += sizeof(WINSTATIONNAMEW); } } /* * If we defined a buffer, free it now, then return the status * of the Reg...EnumerateW function call. */ if ( pBuffer ) LocalFree(pBuffer); return ( Status ); } /******************************************************************************* * * RegWinStationEnumerateW (UNICODE) * * Returns a list of configured window stations in the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pIndex (input/output) * Specifies the subkey index for the \Citrix\WinStations subkeys in the * registry. Should be set to 0 for the initial call, and supplied * again (as modified by this function) for multi-call enumeration. * pEntries (input/output) * Points to a variable specifying the number of entries requested. * If the number requested is 0xFFFFFFFF, the function returns as * many entries as possible. When the function finishes successfully, * the variable pointed to by the pEntries parameter contains the * number of entries actually read. * pWinStationName (input) * Points to the buffer to receive the enumeration results, which are * returned as an array of WINSTATIONNAME structures. If this parameter * is NULL, then no data will be copied, but just an enumeration count * will be made. * pByteCount (input/output) * Points to a variable that specifies the size, in bytes, of the * pWinStationName parameter. If the buffer is too small to receive even * one entry, the function returns an error code (ERROR_OUTOFMEMORY) * and this variable receives the required size of the buffer for a * single subkey. When the function finishes sucessfully, the variable * pointed to by the pByteCount parameter contains the number of bytes * actually stored in pWinStationName. * * EXIT: * * "No Error" codes: * ERROR_SUCCESS - The enumeration completed as requested and there * are more WinStations subkeys (WINSTATIONNAMEs) to * be read. * ERROR_NO_MORE_ITEMS - The enumeration completed as requested and there * are no more WinStations subkeys (WINSTATIONNAMEs) * to be read. * * "Error" codes: * ERROR_OUTOFMEMORY - The pWinStationName buffer is too small for even * one entry. * ERROR_CANTOPEN - The Citrix\WinStations key can't be opened. * ******************************************************************************/ LONG WINAPI RegWinStationEnumerateW( HANDLE hServer, PULONG pIndex, PULONG pEntries, PWINSTATIONNAMEW pWinStationName, PULONG pByteCount ) { LONG Status; HKEY Handle; ULONG Count; ULONG i; /* * Get the number of names to return */ Count = pWinStationName ? min( *pByteCount / sizeof(WINSTATIONNAME), *pEntries ) : (ULONG) -1; *pEntries = *pByteCount = 0; /* * Make sure buffer is big enough for at least one name */ if ( Count == 0 ) { *pByteCount = sizeof(WINSTATIONNAME); return( ERROR_OUTOFMEMORY ); } /* * Open registry (LOCAL_MACHINE\....\Citrix\WinStations) */ if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, KEY_ENUMERATE_SUB_KEYS, &Handle ) != ERROR_SUCCESS ) { goto DefaultConsole; } /* * Get list of window stations */ for ( i = 0; i < Count; i++ ) { WINSTATIONNAME WinStationName; if ( (Status = RegEnumKey(Handle, *pIndex, WinStationName, sizeof(WINSTATIONNAME)/sizeof(TCHAR) )) != ERROR_SUCCESS ) break; /* * If caller supplied a buffer, then copy the WinStationName * and increment the pointer and byte count. Always increment the * entry count and index for the next iteration. */ if ( pWinStationName ) { wcscpy( pWinStationName, WinStationName ); (char*)pWinStationName += sizeof(WINSTATIONNAME); *pByteCount += sizeof(WINSTATIONNAME); } (*pEntries)++; (*pIndex)++; } /* * Close registry */ RegCloseKey( Handle ); if ( Status == ERROR_NO_MORE_ITEMS ) { if ( (*pEntries == 0) && (*pIndex == 0) ) goto DefaultConsole; } return( Status ); /* * We come here when there are no WinStations defined. * We return a default "Console" name (if pWinStationName isn't NULL). */ DefaultConsole: if ( pWinStationName ) wcscpy( pWinStationName, L"Console" ); *pEntries = 1; *pByteCount = sizeof(WINSTATIONNAME); return( ERROR_NO_MORE_ITEMS ); } /******************************************************************************* * * RegWinStationCreateA (ANSI stub) * * Creates a new WinStaton in the registry or updates an existing entry. * (See RegWinStationCreateW) * * ENTRY: * see RegWinStationCreateW * * EXIT: * see RegWinStationCreateW * ******************************************************************************/ LONG WINAPI RegWinStationCreateA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, BOOLEAN bCreate, PWINSTATIONCONFIG2A pWinStationConfig, ULONG WinStationConfigLength ) { WINSTATIONNAMEW WinStationNameW; WINSTATIONCONFIG2W WinStationConfig2W; int i; /* * Validate target buffer size. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Convert ANSI WinStationName to UNICODE. */ AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName ); /* * Copy WINSTATIONCONFIG2A elements to WINSTATIONCONFIG2W elements. */ WinStationCreateA2U( &(WinStationConfig2W.Create), &(pWinStationConfig->Create) ); for ( i=0; iPd[i]) ); } WdConfigA2U( &(WinStationConfig2W.Wd), &(pWinStationConfig->Wd) ); CdConfigA2U( &(WinStationConfig2W.Cd), &(pWinStationConfig->Cd) ); WinStationConfigA2U( &(WinStationConfig2W.Config), &(pWinStationConfig->Config) ); /* * Call RegWinStationCreateW & return it's status. */ return ( RegWinStationCreateW( hServer, WinStationNameW, bCreate, &WinStationConfig2W, sizeof(WinStationConfig2W)) ); } /******************************************************************************* * * RegCreateUserConfigW (UNICODE) * * Updates the UserConfig section in the registry. This API was necessary * because RegWinStationCreate was all that was available, and that updates * all of the Winstation data, which may not be what we want, especially * if that RegWinStationQuery had been used which merges in machine policy data. * This can't be used to create a new section - it only updates an existing one * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a new or exisiting window station in the registry. * pUser (input) * Pointer to a PUSERCONFIG structure containing configuration * information for the specified window station name. * * EXIT: * ERROR_SUCCESS - no error * * ERROR_FILE_NOT_FOUND - can't open ...\Terminal Server\WinStations key * ERROR_CANTOPEN - update; but WinStation key could not be opened * ******************************************************************************/ LONG WINAPI RegCreateUserConfigW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PUSERCONFIG pUser) { HKEY WinStationParentHandle; HKEY WinStationHandle; DWORD Disp; //Open registry (LOCAL_MACHINE\....\Terminal Server\WinStations). if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, KEY_ALL_ACCESS, &WinStationParentHandle ) != ERROR_SUCCESS) { return( ERROR_FILE_NOT_FOUND ); } // Open the registry key for the specified WinStation name. if ( RegOpenKeyEx( WinStationParentHandle, pWinStationName, 0, KEY_ALL_ACCESS, &WinStationHandle ) != ERROR_SUCCESS ) { RegCloseKey( WinStationParentHandle ); return( ERROR_CANTOPEN ); } RegCloseKey( WinStationParentHandle ); CreateUserConfig(WinStationHandle, pUser, pWinStationName ); //Close registry handle RegCloseKey( WinStationHandle ); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegWinStationCreateW (UNICODE) * * Creates a new WinStaton in the registry or updates an existing entry. * The state of the bCreate flag determines whether this function will * expect to create a new WinStation entry (bCreate == TRUE) or expects to * update an existing entry (bCreate == FALSE). * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a new or exisiting window station in the registry. * bCreate (input) * TRUE if this is a creation of a new WinStation * FALSE if this is an update to an existing WinStation * pWinStationConfig (input) * Pointer to a WINSTATIONCONFIG2 structure containing configuration * information for the specified window station name. * WinStationConfigLength (input) * Specifies the length in bytes of the pWinStationConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * * ERROR_INSUFFICIENT_BUFFER - pWinStationConfig buffer too small * ERROR_FILE_NOT_FOUND - can't open ...\Citrix\WinStations key * ERROR_CANNOT_MAKE - can't create WinStation key (registry problem) * ERROR_ALREADY_EXISTS - create; but WinStation key already present * ERROR_CANTOPEN - update; but WinStation key could not be opened * ******************************************************************************/ LONG WINAPI RegWinStationCreateW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, BOOLEAN bCreate, PWINSTATIONCONFIG2W pWinStationConfig, ULONG WinStationConfigLength ) { HKEY Handle; HKEY Handle1; DWORD Disp; /* * Validate length of buffer */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Open registry (LOCAL_MACHINE\....\Citrix\WinStations). * If it doesn't exist, we attemp to create it. */ if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, KEY_ALL_ACCESS, &Handle1 ) != ERROR_SUCCESS && RegCreateKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &Handle1, &Disp ) != ERROR_SUCCESS ) { return( ERROR_FILE_NOT_FOUND ); } if ( bCreate ) { /* * Create requested: create a registry key for the specified * WinStation name. */ if ( RegCreateKeyEx( Handle1, pWinStationName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &Handle, &Disp ) != ERROR_SUCCESS ) { RegCloseKey( Handle1 ); return( ERROR_CANNOT_MAKE ); } /* * If an existing key was returned instead of a new one being * created, return error (don't update). */ if ( Disp != REG_CREATED_NEW_KEY ) { RegCloseKey( Handle1 ); RegCloseKey( Handle ); return( ERROR_ALREADY_EXISTS ); } } else { /* * Update requested: open the registry key for the specified * WinStation name. */ if ( RegOpenKeyEx( Handle1, pWinStationName, 0, KEY_ALL_ACCESS, &Handle ) != ERROR_SUCCESS ) { RegCloseKey( Handle1 ); return( ERROR_CANTOPEN ); } } RegCloseKey( Handle1 ); /* * Save WINSTATIONCONFIG2 Structure */ CreateWinStaCreate( Handle, &pWinStationConfig->Create ); CreatePdConfig( bCreate, Handle, pWinStationConfig->Pd, MAX_PDCONFIG ); CreateWd( Handle, &pWinStationConfig->Wd ); CreateCd( Handle, &pWinStationConfig->Cd ); CreateConfig( Handle, &pWinStationConfig->Config, pWinStationName ); /* * Close registry handle */ RegCloseKey( Handle ); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegWinStationQueryA (ANSI stub) * * Query configuration information of a window station in the registry. * * ENTRY: * see RegWinStationQueryW * * EXIT: * see RegWinStationQueryW * ******************************************************************************/ LONG WINAPI RegWinStationQueryA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, PWINSTATIONCONFIG2A pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ) { WINSTATIONNAMEW WinStationNameW; WINSTATIONCONFIG2W WinStationConfig2W; LONG Status; ULONG ReturnLengthW; int i; /* * Validate length and zero-initialize the destination * WINSTATIONCONFIG2A structure. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) ) return( ERROR_INSUFFICIENT_BUFFER ); memset(pWinStationConfig, 0, WinStationConfigLength); /* * Convert ANSI WinStationName to UNICODE. */ AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName ); /* * Query WinStation. */ if ( (Status = RegWinStationQueryW( hServer, WinStationNameW, &WinStationConfig2W, sizeof(WINSTATIONCONFIG2W), &ReturnLengthW)) != ERROR_SUCCESS ) return ( Status ); /* * Copy WINSTATIONCONFIG2W elements to WINSTATIONCONFIG2A elements. */ WinStationCreateU2A( &(pWinStationConfig->Create), &(WinStationConfig2W.Create) ); for ( i=0; iPd[i]), &(WinStationConfig2W.Pd[i]) ); } WdConfigU2A( &(pWinStationConfig->Wd), &(WinStationConfig2W.Wd) ); CdConfigU2A( &(pWinStationConfig->Cd), &(WinStationConfig2W.Cd) ); WinStationConfigU2A( &(pWinStationConfig->Config), &(WinStationConfig2W.Config) ); *pReturnLength = sizeof(WINSTATIONCONFIG2A); return( ERROR_SUCCESS ); } /******************************************************************************* * * * * RegWinStationQueryEx (UNICODE) * * USE THIS CALL if you are in TermSrv.DLL, since it will update the global policy object * * Same as RegWinStationQueryW with the excpetion that a pointer to a global policy object is passed in. * * Query configuration information of a window station in the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pMachinePolicy (input) * pointer to a gloabl machine policy struct * pWinStationName (input) * Name of an exisiting window station in the registry. * pWinStationConfig (input) * Pointer to a WINSTATIONCONFIG2 structure that will receive * information about the specified window station name. * WinStationConfigLength (input) * Specifies the length in bytes of the pWinStationConfig buffer. * pReturnLength (output) * Receives the number of bytes placed in the pWinStationConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQueryEx( HANDLE hServer, PPOLICY_TS_MACHINE pMachinePolicy, PWINSTATIONNAMEW pWinStationName, PWINSTATIONCONFIG2W pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength, BOOLEAN bPerformMerger) { LONG Status; HKEY Handle; ULONG Count; /* * Validate length and zero-initialize the destination * WINSTATIONCONFIG2W buffer. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) ) return( ERROR_INSUFFICIENT_BUFFER ); memset(pWinStationConfig, 0, WinStationConfigLength); /* * Open registry */ Status = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ); if ( Status ) Handle = 0; /* * Query WINSTATIONCONFIG2 Structure */ QueryWinStaCreate( Handle, &pWinStationConfig->Create ); Count = MAX_PDCONFIG; QueryPdConfig( Handle, pWinStationConfig->Pd, &Count ); QueryWd( Handle, &pWinStationConfig->Wd ); QueryCd( Handle, &pWinStationConfig->Cd ); // This will populate the winstation's userconfig data with machine's version of that data. QueryConfig( Handle, &pWinStationConfig->Config, pWinStationName ); //This reads the WinFrame parameters from the machine settings (not group policy) QueryTSProfileAndHomePaths(&pWinStationConfig->Config.User); // Since we want to co-exist with the legacy path thru TSCC, we continue to call QueryConfig() // as we have done above, however, we follow up with a call that get's data from the group policy // tree, and then overrides the existing data (aquired above) by the specific data from group policy. RegGetMachinePolicy( pMachinePolicy ); if (bPerformMerger) RegMergeMachinePolicy( pMachinePolicy, &pWinStationConfig->Config.User , &pWinStationConfig->Create ); /* * Close registry */ if ( Status == ERROR_SUCCESS ) RegCloseKey( Handle ); *pReturnLength = sizeof(WINSTATIONCONFIG2); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegWinStationQueryW (UNICODE) * * Query configuration information of a window station in the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of an exisiting window station in the registry. * pWinStationConfig (input) * Pointer to a WINSTATIONCONFIG2 structure that will receive * information about the specified window station name. * WinStationConfigLength (input) * Specifies the length in bytes of the pWinStationConfig buffer. * pReturnLength (output) * Receives the number of bytes placed in the pWinStationConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQueryW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PWINSTATIONCONFIG2W pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ) { LONG Status; HKEY Handle; ULONG Count; POLICY_TS_MACHINE MachinePolicy; /* * Validate length and zero-initialize the destination * WINSTATIONCONFIG2W buffer. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) ) return( ERROR_INSUFFICIENT_BUFFER ); memset(pWinStationConfig, 0, WinStationConfigLength); /* * Open registry */ Status = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ); if ( Status ) Handle = 0; /* * Query WINSTATIONCONFIG2 Structure */ QueryWinStaCreate( Handle, &pWinStationConfig->Create ); Count = MAX_PDCONFIG; QueryPdConfig( Handle, pWinStationConfig->Pd, &Count ); QueryWd( Handle, &pWinStationConfig->Wd ); QueryCd( Handle, &pWinStationConfig->Cd ); // This will populate the winstation's userconfig data with machine's version of that data. QueryConfig( Handle, &pWinStationConfig->Config, pWinStationName ); // Since we want to co-exist with the legacy path thru TSCC, we continue to call QueryConfig() // as we have done above, however, we follow up with a call that get's data from the group policy // tree, and then overrides the existing data (aquired above) by the specific data from group policy. RegGetMachinePolicy( & MachinePolicy ); RegMergeMachinePolicy( & MachinePolicy, &pWinStationConfig->Config.User , &pWinStationConfig->Create ); /* * Close registry */ if ( Status == ERROR_SUCCESS ) RegCloseKey( Handle ); *pReturnLength = sizeof(WINSTATIONCONFIG2); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegConsoleShadowQueryA (ANSI stub) * * Query configuration information for the console shadow in the registry. * * ENTRY: * see RegConsoleShadowQueryW * * EXIT: * see RegConsoleShadowQueryW * ******************************************************************************/ LONG WINAPI RegConsoleShadowQueryA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, PWDPREFIXA pWdPrefixName, PWINSTATIONCONFIG2A pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ) { WINSTATIONNAMEW WinStationNameW; WDPREFIXW WdPrefixNameW; WINSTATIONCONFIG2W WinStationConfig2W; LONG Status; ULONG ReturnLengthW; int i; /* * Validate length and zero-initialize the destination * WINSTATIONCONFIG2A structure. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2A) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Convert ANSI WinStationName and prefix name to UNICODE. */ AnsiToUnicode( WinStationNameW, sizeof(WINSTATIONNAMEW), pWinStationName ); AnsiToUnicode( WdPrefixNameW, sizeof(WDPREFIXW), pWdPrefixName ); /* * Query WinStation. */ if ( (Status = RegConsoleShadowQueryW( hServer, WinStationNameW, WdPrefixNameW, &WinStationConfig2W, sizeof(WINSTATIONCONFIG2W), &ReturnLengthW)) != ERROR_SUCCESS ) return ( Status ); /* * Copy WINSTATIONCONFIG2W elements to WINSTATIONCONFIG2A elements. */ for ( i=0; iPd[i]), &(WinStationConfig2W.Pd[i]) ); } WdConfigU2A( &(pWinStationConfig->Wd), &(WinStationConfig2W.Wd) ); CdConfigU2A( &(pWinStationConfig->Cd), &(WinStationConfig2W.Cd) ); *pReturnLength = sizeof(WINSTATIONCONFIG2A); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegConsoleShadowQueryW (UNICODE) * * Query configuration information for the console shadow in the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of an exisiting window station in the registry. * pWdPrefixName (input) * Name of the Wd prefix used to point to the sub-winstation key. * pWinStationConfig (input) * Pointer to a WINSTATIONCONFIG2 structure that will receive * information about the specified window station name. * WinStationConfigLength (input) * Specifies the length in bytes of the pWinStationConfig buffer. * pReturnLength (output) * Receives the number of bytes placed in the pWinStationConfig buffer. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegConsoleShadowQueryW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PWDPREFIXW pWdPrefixName, PWINSTATIONCONFIG2W pWinStationConfig, ULONG WinStationConfigLength, PULONG pReturnLength ) { LONG Status; LONG lLength; HKEY Handle; ULONG Count; WCHAR szRegName[ WINSTATIONNAME_LENGTH + WDPREFIX_LENGTH + 2 ]; /* * Validate length and zero-initialize the destination * WINSTATIONCONFIG2W buffer. */ if ( WinStationConfigLength < sizeof(WINSTATIONCONFIG2) ) return( ERROR_INSUFFICIENT_BUFFER ); /* * Open registry */ wcsncpy( szRegName, pWinStationName, sizeof(szRegName)/sizeof(WCHAR) - 1 ); szRegName[sizeof(szRegName)/sizeof(WCHAR) - 1] = 0; // terminate the string even if pWinStationName is longer than the buffer lLength = wcslen( szRegName ); if ( sizeof(szRegName)/sizeof(WCHAR) > ( lLength + 1 + wcslen( pWdPrefixName ) ) ) { wcsncat( szRegName, L"\\", sizeof(szRegName)/sizeof(WCHAR) - lLength - 1 ); wcsncat( szRegName, pWdPrefixName, sizeof(szRegName)/sizeof(WCHAR) - lLength - 2 ); } else { return ERROR_INVALID_PARAMETER; } Status = _RegOpenWinStation( szRegName, KEY_READ, &Handle ); if ( Status ) Handle = 0; /* * Query WINSTATIONCONFIG2 Structure */ Count = MAX_PDCONFIG; QueryPdConfig( Handle, pWinStationConfig->Pd, &Count ); QueryWd( Handle, &pWinStationConfig->Wd ); QueryCd( Handle, &pWinStationConfig->Cd ); /* * Close registry */ if ( Status == ERROR_SUCCESS ) RegCloseKey( Handle ); *pReturnLength = sizeof(WINSTATIONCONFIG2); return( ERROR_SUCCESS ); } /******************************************************************************* * * RegWinStationDeleteA (ANSI stub) * * Deletes a window station from the registry. * * ENTRY: * see RegWinStationDeleteW * * EXIT: * see RegWinStationDeleteW * ******************************************************************************/ LONG WINAPI RegWinStationDeleteA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName ) { WINSTATIONNAMEW WinStationNameW; AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName ); return ( RegWinStationDeleteW ( hServer, WinStationNameW ) ); } /******************************************************************************* * * RegWinStationDeleteW (UNICODE) * * Deletes a window station from the registry. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to delete from the registry. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationDeleteW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName ) { LONG Status; HKEY Handle1, Handle2; /* * Open registry (LOCAL_MACHINE\....\Citrix\WinStations). */ if ( (Status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, KEY_ALL_ACCESS, &Handle1 ) != ERROR_SUCCESS) ) { return( Status ); } /* * Open the registry key for the specified WinStation name. */ if ( (Status = RegOpenKeyEx( Handle1, pWinStationName, 0, KEY_ALL_ACCESS, &Handle2 ) != ERROR_SUCCESS) ) { RegCloseKey( Handle1 ); return( Status ); } DeleteUserOverRideSubkey(Handle2); /* * Close the WinStation key handle just opened (so we can delete key), * delete the key, and close the Citrix registry handle. */ RegCloseKey( Handle2 ); Status = RegDeleteKey( Handle1, pWinStationName ); RegCloseKey( Handle1 ); return( Status ); } /******************************************************************************* * * RegWinStationSetSecurityA (ANSI stub) * * Sets security info for the specified WinStation. * * ENTRY: * see RegWinStationSetSecurityW * * EXIT: * see RegWinStationSetSecurityW * ******************************************************************************/ LONG WINAPI RegWinStationSetSecurityA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length ) { WINSTATIONNAMEW WinStationNameW; AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName ); return ( RegWinStationSetSecurityW( hServer, WinStationNameW, SecurityDescriptor, Length ) ); } /******************************************************************************* * * RegWinStationSetSecurityW (UNICODE) * * Sets security info for the specified WinStation. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to set security for. * pSecurityDescriptor (input) * Pointer to Security Descriptor to save * Length (input) * Length of SecurityDescriptor above * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationSetSecurityW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length ) { HKEY Handle; ULONG SrLength; PSECURITY_DESCRIPTOR SrSecurityDescriptor; LONG Error; NTSTATUS Status; /* * Open registry */ if ( Error = _RegOpenWinStation( pWinStationName, KEY_ALL_ACCESS, &Handle ) ) return( Error ); /* * Determine buffer length needed to convert SD to self-relative format. */ SrLength = 0; Status = RtlMakeSelfRelativeSD( SecurityDescriptor, NULL, &SrLength ); if ( Status != STATUS_BUFFER_TOO_SMALL ) { RegCloseKey( Handle ); return( RtlNtStatusToDosError( Status ) ); } /* * Allocate buffer for self-relative SD. */ SrSecurityDescriptor = LocalAlloc( 0, SrLength ); if ( SrSecurityDescriptor == NULL ) { RegCloseKey( Handle ); return( ERROR_NOT_ENOUGH_MEMORY ); } /* * Now convert SD to self-relative format. */ Status = RtlMakeSelfRelativeSD( SecurityDescriptor, SrSecurityDescriptor, &SrLength ); if ( !NT_SUCCESS( Status ) ) { LocalFree( SrSecurityDescriptor ); RegCloseKey( Handle ); return( RtlNtStatusToDosError( Status ) ); } /* * Save the security data */ Error = RegSetValueEx( Handle, L"Security", 0, REG_BINARY, (BYTE *)SrSecurityDescriptor, SrLength ); /* * Free memory used for Self-relative Security Descriptor */ LocalFree( SrSecurityDescriptor ); /* * Close registry */ RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * RegWinStationQuerySecurityA (ANSI stub) * * Query security info for the specified WinStation. * * ENTRY: * see RegWinStationQuerySecurityW * * EXIT: * see RegWinStationQuerySecurityW * ******************************************************************************/ LONG WINAPI RegWinStationQuerySecurityA( HANDLE hServer, PWINSTATIONNAMEA pWinStationName, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length, PULONG ReturnLength ) { WINSTATIONNAMEW WinStationNameW; AnsiToUnicode( WinStationNameW, sizeof(WinStationNameW), pWinStationName ); return ( RegWinStationQuerySecurityW( hServer, WinStationNameW, SecurityDescriptor, Length, ReturnLength ) ); } /******************************************************************************* * * RegWinStationQuerySecurityW (UNICODE) * * Query security info for the specified WinStation. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to query security for. * pSecurityDescriptor (output) * Pointer to location to return SecurityDescriptor. * Length (input) * Length of SecurityDescriptor buffer. * ReturnLength (output) * Pointer to location to return length of SecurityDescriptor returned. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQuerySecurityW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length, PULONG ReturnLength ) { HKEY Handle; LONG Error; /* * Open registry */ if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) ) return( Error ); /* * Call RegGetWinStationSecurity() to do all the work */ Error = _RegGetWinStationSecurity( Handle, L"Security", SecurityDescriptor, Length, ReturnLength ); RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * RegWinStationQueryDefaultSecurity * * Query default WinStation security. * * ENTRY: * hServer (input) * Handle to WinFrame Server * pSecurityDescriptor (output) * Pointer to location to return SecurityDescriptor. * Length (input) * Length of SecurityDescriptor buffer. * ReturnLength (output) * Pointer to location to return length of SecurityDescriptor returned. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQueryDefaultSecurity( HANDLE hServer, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length, PULONG ReturnLength ) { HKEY Handle; LONG Error; /* * Open registry */ if ( Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, KEY_READ, &Handle ) ) return( Error ); /* * Call RegGetWinStationSecurity() to do all the work */ Error = _RegGetWinStationSecurity( Handle, L"DefaultSecurity", SecurityDescriptor, Length, ReturnLength ); RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * RegWinStationSetNumValueW (UNICODE) * * Set numeric value in WinStation registry configuration * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to modify from the registry. * pValueName (input) * name of registry value to set * ValueData (input) * data (DWORD) for registry value to set * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationSetNumValueW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, LPWSTR pValueName, ULONG ValueData ) { HKEY Handle; LONG Error; /* * Open registry */ if ( Error = _RegOpenWinStation( pWinStationName, KEY_ALL_ACCESS, &Handle ) ) return( Error ); /* * Set the numeric value */ Error = RegSetValueEx( Handle, pValueName, 0, REG_DWORD, (BYTE *)&ValueData, sizeof(DWORD) ); /* * Close registry */ RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * RegWinStationQueryNumValueW (UNICODE) * * Query numeric value from WinStation registry configuration * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to modify from the registry. * pValueName (input) * name of registry value to set * pValueData (output) * address to return data (DWORD) value from registry * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQueryNumValueW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, LPWSTR pValueName, PULONG pValueData ) { DWORD ValueSize = sizeof(DWORD); DWORD ValueType; HKEY Handle; LONG Error; /* * Open registry */ if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) ) return( Error ); /* * Query the numeric value */ Error = RegQueryValueEx( Handle, pValueName, NULL, &ValueType, (LPBYTE) pValueData, &ValueSize ); /* * Close registry */ RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * RegWinStationQueryValueW (UNICODE) * * Query value from WinStation registry configuration * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to modify from the registry. * pValueName (input) * name of registry value to set * pValueData (output) * address to return data (DWORD) value from registry * ValueSize (input) * size of value buffer * pValueSize (input) * actual value size * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG WINAPI RegWinStationQueryValueW( HANDLE hServer, PWINSTATIONNAMEW pWinStationName, LPWSTR pValueName, PVOID pValueData, ULONG ValueSize, PULONG pValueSize ) { DWORD ValueType; HKEY Handle; LONG Error; *pValueSize = ValueSize; /* * Open registry */ if ( Error = _RegOpenWinStation( pWinStationName, KEY_READ, &Handle ) ) return( Error ); /* * Query the numeric value */ Error = RegQueryValueEx( Handle, pValueName, NULL, &ValueType, (LPBYTE) pValueData, pValueSize ); /* * Close registry */ RegCloseKey( Handle ); return( Error ); } /******************************************************************************* * * -- private routine -- * * _RegOpenWinStation * * open registry of specified winstation * * NOTE: handle must be closed with "RegCloseKey" * * ENTRY: * hServer (input) * Handle to WinFrame Server * pWinStationName (input) * Name of a window station to modify from the registry. * samDesired (input) * REGSAM access level for registry open. * pHandle (output) * address to return handle * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG _RegOpenWinStation( PWINSTATIONNAMEW pWinStationName, REGSAM samDesired, HKEY * pHandle ) { HKEY Handle1; LONG Error; /* * Open registry (LOCAL_MACHINE\....\Citrix\WinStations). */ if ( (Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE, WINSTATION_REG_NAME, 0, samDesired, &Handle1 ) != ERROR_SUCCESS) ) { return( Error ); } /* * Open the registry key for the specified WinStation name. */ Error = RegOpenKeyEx( Handle1, pWinStationName, 0, samDesired, pHandle); RegCloseKey( Handle1 ); return( Error ); } /******************************************************************************* * * -- private routine -- * * _RegGetWinStationSecurity * * Query the security descriptor from the specified registry key. * * ENTRY: * Handle (input) * Open registry key handle. * ValueName (input) * Name of security value. * pSecurityDescriptor (output) * Pointer to location to return SecurityDescriptor. * Length (input) * Length of SecurityDescriptor buffer. * ReturnLength (output) * Pointer to location to return length of SecurityDescriptor returned. * * EXIT: * ERROR_SUCCESS - no error * otherwise: the error code * ******************************************************************************/ LONG _RegGetWinStationSecurity( HKEY Handle, LPWSTR ValueName, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length, PULONG ReturnLength ) { DWORD ValueType; DWORD SrLength; ULONG SdSize, DaclSize, SaclSize, OwnerSize, GroupSize; PSECURITY_DESCRIPTOR SrSecurityDescriptor; PACL pDacl, pSacl; PSID pOwner, pGroup; LONG Error; NTSTATUS Status; /* * Query the length of the Security value */ SrLength = 0; if ( Error = RegQueryValueEx( Handle, ValueName, NULL, &ValueType, NULL, &SrLength ) ) { return( Error ); } /* * Return error if not correct data type */ if ( ValueType != REG_BINARY ) { return( ERROR_FILE_NOT_FOUND ); } /* * Allocate a buffer to read the Security info and read it */ SrSecurityDescriptor = LocalAlloc( 0, SrLength ); if ( SrSecurityDescriptor == NULL ) { return( ERROR_NOT_ENOUGH_MEMORY ); } if ( Error = RegQueryValueEx( Handle, ValueName, NULL, &ValueType, SrSecurityDescriptor, &SrLength ) ) { LocalFree( SrSecurityDescriptor ); return( Error ); } /* * Determine amount of space required to convert SD from * self-relative format to absolute format. */ SdSize = DaclSize = SaclSize = OwnerSize = GroupSize = 0; Status = RtlSelfRelativeToAbsoluteSD( SrSecurityDescriptor, NULL, &SdSize, NULL, &DaclSize, NULL, &SaclSize, NULL, &OwnerSize, NULL, &GroupSize ); if ( Status != STATUS_BUFFER_TOO_SMALL ) { LocalFree( SrSecurityDescriptor ); return( RtlNtStatusToDosError( Status ) ); } *ReturnLength = SdSize + DaclSize + SaclSize + OwnerSize + GroupSize; /* * If required size is greater than callers buffer size, then return */ if ( *ReturnLength > Length ) { LocalFree( SrSecurityDescriptor ); return( ERROR_INSUFFICIENT_BUFFER ); } pDacl = (PACL)((PCHAR)SecurityDescriptor + SdSize); pSacl = (PACL)((PCHAR)pDacl + DaclSize); pOwner = (PSID)((PCHAR)pSacl + SaclSize); pGroup = (PSID)((PCHAR)pOwner + OwnerSize); /* * Now convert self-relative SD to absolute format. */ Status = RtlSelfRelativeToAbsoluteSD( SrSecurityDescriptor, SecurityDescriptor, &SdSize, pDacl, &DaclSize, pSacl, &SaclSize, pOwner, &OwnerSize, pGroup, &GroupSize ); if ( !NT_SUCCESS( Status ) ) Error = RtlNtStatusToDosError( Status ); /* * Free memory used for Self-relative Security Descriptor */ LocalFree( SrSecurityDescriptor ); return( Error ); }