/************************************************************************* * * query.c * * Query Register APIs * * Copyright (c) 1998 Microsoft Corporation * * *************************************************************************/ /* * Includes */ #include #include #include #include #include #include #include #include #include #include #include /* * Procedures defined */ VOID QueryWinStaCreate( HKEY, PWINSTATIONCREATE ); VOID QueryUserConfig( HKEY, PUSERCONFIG ); VOID QueryConfig( HKEY, PWINSTATIONCONFIG ); VOID QueryNetwork( HKEY, PNETWORKCONFIG ); VOID QueryNasi( HKEY, PNASICONFIG ); VOID QueryAsync( HKEY, PASYNCCONFIG ); VOID QueryOemTd( HKEY, POEMTDCONFIG ); VOID QueryFlow( HKEY, PFLOWCONTROLCONFIG ); VOID QueryConnect( HKEY, PCONNECTCONFIG ); VOID QueryCd( HKEY, PCDCONFIG ); VOID QueryWd( HKEY, PWDCONFIG ); VOID QueryPdConfig( HKEY, PPDCONFIG, PULONG ); VOID QueryPdConfig2( HKEY, PPDCONFIG2, ULONG ); VOID QueryPdConfig3( HKEY, PPDCONFIG3, ULONG ); VOID QueryPdParams( HKEY, SDCLASS, PPDPARAMS ); BOOLEAN WINAPI RegBuildNumberQuery( PULONG ); BOOLEAN RegQueryOEMId( PBYTE, ULONG ); BOOLEAN WINAPI RegGetCitrixVersion(WCHAR *, PULONG); BOOLEAN IsWallPaperDisabled( HKEY ); /* * procedures used */ DWORD GetNumValue( HKEY, LPWSTR, DWORD ); DWORD GetNumValueEx( HKEY, LPWSTR, DWORD, DWORD ); LONG GetStringValue( HKEY, LPWSTR, LPWSTR, LPWSTR, DWORD ); LONG GetStringValueEx( HKEY, LPWSTR, DWORD, LPWSTR, LPWSTR, DWORD ); VOID UnicodeToAnsi( CHAR *, ULONG, WCHAR * ); /******************************************************************************* * * QueryWinStaCreate * * query WINSTATIONCREATE structure * * ENTRY: * * Handle (input) * registry handle * pCreate (output) * address to return WINSTATIONCREATE structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryWinStaCreate( HKEY Handle, PWINSTATIONCREATE pCreate ) { pCreate->fEnableWinStation = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEWINSTATION, TRUE ); pCreate->MaxInstanceCount = GetNumValue( Handle, WIN_MAXINSTANCECOUNT, 1 ); } /******************************************************************************* * * QueryUserConfig * * query USERCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pUser (input) * pointer to USERCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryUserConfig( HKEY Handle, PUSERCONFIG pUser ) { UCHAR seed; UNICODE_STRING UnicodePassword; WCHAR encPassword[ PASSWORD_LENGTH + 2 ]; pUser->fInheritAutoLogon = (BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOLOGON, TRUE ); pUser->fInheritResetBroken = (BOOLEAN) GetNumValue( Handle, WIN_INHERITRESETBROKEN, TRUE ); pUser->fInheritReconnectSame = (BOOLEAN) GetNumValue( Handle, WIN_INHERITRECONNECTSAME, TRUE ); pUser->fInheritInitialProgram = (BOOLEAN) GetNumValue( Handle, WIN_INHERITINITIALPROGRAM, TRUE ); pUser->fInheritCallback = (BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACK, FALSE ); pUser->fInheritCallbackNumber = (BOOLEAN) GetNumValue( Handle, WIN_INHERITCALLBACKNUMBER, TRUE ); pUser->fInheritShadow = (BOOLEAN) GetNumValue( Handle, WIN_INHERITSHADOW, TRUE ); pUser->fInheritMaxSessionTime = (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXSESSIONTIME, TRUE ); pUser->fInheritMaxDisconnectionTime = (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXDISCONNECTIONTIME, TRUE ); pUser->fInheritMaxIdleTime = (BOOLEAN) GetNumValue( Handle, WIN_INHERITMAXIDLETIME, TRUE ); pUser->fInheritAutoClient = (BOOLEAN) GetNumValue( Handle, WIN_INHERITAUTOCLIENT, TRUE ); pUser->fInheritSecurity = (BOOLEAN) GetNumValue( Handle, WIN_INHERITSECURITY, FALSE ); //NA 2/23/01 pUser->fInheritColorDepth = (BOOLEAN) GetNumValue( Handle, WIN_INHERITCOLORDEPTH, TRUE ); pUser->fPromptForPassword = (BOOLEAN) GetNumValue( Handle, WIN_PROMPTFORPASSWORD, FALSE ); pUser->fResetBroken = (BOOLEAN) GetNumValue( Handle, WIN_RESETBROKEN, FALSE ); pUser->fReconnectSame = (BOOLEAN) GetNumValue( Handle, WIN_RECONNECTSAME, FALSE ); pUser->fLogonDisabled = (BOOLEAN) GetNumValue( Handle, WIN_LOGONDISABLED, FALSE ); pUser->fAutoClientDrives = (BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTDRIVES, TRUE ); pUser->fAutoClientLpts = (BOOLEAN) GetNumValue( Handle, WIN_AUTOCLIENTLPTS, TRUE ); pUser->fForceClientLptDef = (BOOLEAN) GetNumValue( Handle, WIN_FORCECLIENTLPTDEF, TRUE ); pUser->fDisableEncryption = (BOOLEAN) GetNumValue( Handle, WIN_DISABLEENCRYPTION, TRUE ); pUser->fHomeDirectoryMapRoot = (BOOLEAN) GetNumValue( Handle, WIN_HOMEDIRECTORYMAPROOT, FALSE ); pUser->fUseDefaultGina = (BOOLEAN) GetNumValue( Handle, WIN_USEDEFAULTGINA, FALSE ); pUser->fDisableCpm = (BOOLEAN) GetNumValue( Handle, WIN_DISABLECPM, FALSE ); pUser->fDisableCdm = (BOOLEAN) GetNumValue( Handle, WIN_DISABLECDM, FALSE ); pUser->fDisableCcm = (BOOLEAN) GetNumValue( Handle, WIN_DISABLECCM, FALSE ); pUser->fDisableLPT = (BOOLEAN) GetNumValue( Handle, WIN_DISABLELPT, FALSE ); pUser->fDisableClip = (BOOLEAN) GetNumValue( Handle, WIN_DISABLECLIP, FALSE ); pUser->fDisableExe = (BOOLEAN) GetNumValue( Handle, WIN_DISABLEEXE, FALSE ); pUser->fDisableCam = (BOOLEAN) GetNumValue( Handle, WIN_DISABLECAM, FALSE ); GetStringValue( Handle, WIN_USERNAME, NULL, pUser->UserName, USERNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_DOMAIN, NULL, pUser->Domain, DOMAIN_LENGTH + 1 ); // pull encrypted password out of registry GetStringValue( Handle, WIN_PASSWORD, NULL, encPassword, PASSWORD_LENGTH + 2 ); // check for password if there is one then decrypt it if ( wcslen( encPassword ) ) { // generate unicode string RtlInitUnicodeString( &UnicodePassword, &encPassword[1] ); // decrypt password in place seed = (UCHAR) encPassword[0]; RtlRunDecodeUnicodeString( seed, &UnicodePassword ); // pull clear text password RtlMoveMemory( pUser->Password, &encPassword[1], sizeof(pUser->Password) ); } else { // set to null pUser->Password[0] = (WCHAR) NULL; } GetStringValue( Handle, WIN_WORKDIRECTORY, NULL, pUser->WorkDirectory, DIRECTORY_LENGTH + 1 ); GetStringValue( Handle, WIN_INITIALPROGRAM, NULL, pUser->InitialProgram, INITIALPROGRAM_LENGTH + 1 ); GetStringValue( Handle, WIN_CALLBACKNUMBER, NULL, pUser->CallbackNumber, CALLBACK_LENGTH + 1 ); pUser->Callback = GetNumValue( Handle, WIN_CALLBACK, Callback_Disable ); pUser->Shadow = GetNumValue( Handle, WIN_SHADOW, Shadow_EnableInputNotify ); pUser->MaxConnectionTime = GetNumValue( Handle, WIN_MAXCONNECTIONTIME, 0 ); pUser->MaxDisconnectionTime = GetNumValue( Handle, WIN_MAXDISCONNECTIONTIME, 0 ); pUser->MaxIdleTime = GetNumValue( Handle, WIN_MAXIDLETIME, 0 ); pUser->KeyboardLayout = GetNumValue( Handle, WIN_KEYBOARDLAYOUT, 0 ); pUser->MinEncryptionLevel = (BYTE) GetNumValue( Handle, WIN_MINENCRYPTIONLEVEL, 1 ); pUser->fWallPaperDisabled = (BOOLEAN) IsWallPaperDisabled( Handle ); GetStringValue( Handle, WIN_NWLOGONSERVER, NULL, pUser->NWLogonServer, NASIFILESERVER_LENGTH + 1 ); GetStringValue( Handle, WIN_WFPROFILEPATH, NULL, pUser->WFProfilePath, DIRECTORY_LENGTH + 1 ); GetStringValue( Handle, WIN_WFHOMEDIR, NULL, pUser->WFHomeDir, DIRECTORY_LENGTH + 1 ); GetStringValue( Handle, WIN_WFHOMEDIRDRIVE, NULL, pUser->WFHomeDirDrive, 4 ); pUser->ColorDepth = GetNumValue( Handle, POLICY_TS_COLOR_DEPTH, TS_8BPP_SUPPORT ); } /******************************************************************************* * * QueryConfig * * query WINSTATIONCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pConfig (output) * address to return WINSTATIONCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryConfig( HKEY Handle, PWINSTATIONCONFIG pConfig ) { GetStringValue( Handle, WIN_COMMENT, NULL, pConfig->Comment, WINSTATIONCOMMENT_LENGTH + 1 ); QueryUserConfig( Handle, &pConfig->User ); (void) RegQueryOEMId( pConfig->OEMId, sizeof(pConfig->OEMId) ); } /******************************************************************************* * * QueryNetwork * * Query NETWORKCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pNetwork (output) * address to return NETWORKCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryNetwork( HKEY Handle, PNETWORKCONFIG pNetwork ) { pNetwork->LanAdapter = GetNumValue( Handle, WIN_LANADAPTER, 0 ); } /******************************************************************************* * * QueryNasi * * Query NASICONFIG structure * * ENTRY: * * Handle (input) * registry handle * pNasi (output) * address to return NASICONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryNasi( HKEY Handle, PNASICONFIG pNasi ) { UCHAR seed; UNICODE_STRING UnicodePassword; WCHAR encPassword[ NASIPASSWORD_LENGTH + 2 ]; // pull encrypted password out of registry GetStringValue( Handle, WIN_NASIPASSWORD, NULL, encPassword, NASIPASSWORD_LENGTH + 1 ); // check for password if there is one then decrypt it if ( wcslen( encPassword ) ) { // generate unicode string RtlInitUnicodeString( &UnicodePassword, &encPassword[1] ); // decrypt password in place seed = (UCHAR) encPassword[0]; RtlRunDecodeUnicodeString( seed, &UnicodePassword ); // pull clear text password RtlMoveMemory( pNasi->PassWord, &encPassword[1], sizeof(pNasi->PassWord) ); } else { // set to null pNasi->PassWord[0] = (WCHAR) NULL; } GetStringValue( Handle, WIN_NASISPECIFICNAME, NULL, pNasi->SpecificName, NASISPECIFICNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_NASIUSERNAME, NULL, pNasi->UserName, NASIUSERNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_NASISESSIONNAME, NULL, pNasi->SessionName, NASISESSIONNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_NASIFILESERVER, NULL, pNasi->FileServer, NASIFILESERVER_LENGTH + 1 ); pNasi->GlobalSession = (BOOLEAN)GetNumValue( Handle, WIN_NASIGLOBALSESSION, 0 ); } /******************************************************************************* * * QueryAsync * * query ASYNCCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pAsync (output) * address to return ASYNCCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryAsync( HKEY Handle, PASYNCCONFIG pAsync ) { GetStringValue( Handle, WIN_DEVICENAME, NULL, pAsync->DeviceName, DEVICENAME_LENGTH + 1 ); GetStringValue( Handle, WIN_MODEMNAME, NULL, pAsync->ModemName, MODEMNAME_LENGTH + 1 ); pAsync->BaudRate = GetNumValue( Handle, WIN_BAUDRATE, 9600 ); pAsync->Parity = GetNumValue( Handle, WIN_PARITY, NOPARITY ); pAsync->StopBits = GetNumValue( Handle, WIN_STOPBITS, ONESTOPBIT ); pAsync->ByteSize = GetNumValue( Handle, WIN_BYTESIZE, 8 ); pAsync->fEnableDsrSensitivity = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEDSRSENSITIVITY, FALSE ); pAsync->fConnectionDriver = (BOOLEAN) GetNumValue( Handle, WIN_CONNECTIONDRIVER, FALSE ); QueryFlow( Handle, &pAsync->FlowControl ); QueryConnect( Handle, &pAsync->Connect ); } /******************************************************************************* * * QueryOemTd * * Query OEMTDCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pOemTd (output) * address to return OEMTDCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryOemTd( HKEY Handle, POEMTDCONFIG pOemTd ) { pOemTd->Adapter = GetNumValue( Handle, WIN_OEMTDADAPTER, 0 ); GetStringValue( Handle, WIN_OEMTDDEVICENAME, NULL, pOemTd->DeviceName, DEVICENAME_LENGTH + 1 ); pOemTd->Flags = GetNumValue( Handle, WIN_OEMTDFLAGS, 0 ); } /******************************************************************************* * * QueryFlow * * query FLOWCONTROLCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pFlow (output) * address to return FLOWCONTROLCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryFlow( HKEY Handle, PFLOWCONTROLCONFIG pFlow ) { pFlow->fEnableSoftwareRx = (BOOLEAN) GetNumValue( Handle, WIN_FLOWSOFTWARERX, FALSE ); pFlow->fEnableSoftwareTx = (BOOLEAN) GetNumValue( Handle, WIN_FLOWSOFTWARETX, TRUE ); pFlow->fEnableDTR = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEDTR, TRUE ); pFlow->fEnableRTS = (BOOLEAN) GetNumValue( Handle, WIN_ENABLERTS, TRUE ); pFlow->XonChar = (UCHAR) GetNumValue( Handle, WIN_XONCHAR, 0 ); pFlow->XoffChar = (UCHAR) GetNumValue( Handle, WIN_XOFFCHAR, 0 ); pFlow->Type = GetNumValue( Handle, WIN_FLOWTYPE, FlowControl_Hardware ); pFlow->HardwareReceive = GetNumValue( Handle, WIN_FLOWHARDWARERX, ReceiveFlowControl_RTS ); pFlow->HardwareTransmit = GetNumValue( Handle, WIN_FLOWHARDWARETX, TransmitFlowControl_CTS ); } /******************************************************************************* * * QueryConnect * * query CONNECTCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pConnect (output) * address to return CONNECTCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryConnect( HKEY Handle, PCONNECTCONFIG pConnect ) { pConnect->Type = GetNumValue( Handle, WIN_CONNECTTYPE, Connect_DSR ); pConnect->fEnableBreakDisconnect = (BOOLEAN) GetNumValue( Handle, WIN_ENABLEBREAKDISCONNECT, FALSE ); } /******************************************************************************* * * QueryCd * * query CDCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pCdConfig (output) * address to return CDCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryCd( HKEY Handle, PCDCONFIG pCdConfig ) { pCdConfig->CdClass = GetNumValue( Handle, WIN_CDCLASS, CdNone ); GetStringValue( Handle, WIN_CDNAME, NULL, pCdConfig->CdName, CDNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_CDDLL, L"", pCdConfig->CdDLL, DLLNAME_LENGTH + 1 ); pCdConfig->CdFlag = GetNumValue( Handle, WIN_CDFLAG, 0 ); } /******************************************************************************* * * QueryWd * * query WDCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pWd (output) * address to return WDCONFIG structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryWd( HKEY Handle, PWDCONFIG pWd ) { GetStringValue( Handle, WIN_WDNAME, NULL, pWd->WdName, WDNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_WDDLL, L"", pWd->WdDLL, DLLNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_WSXDLL, NULL, pWd->WsxDLL, DLLNAME_LENGTH + 1 ); pWd->WdFlag = GetNumValue( Handle, WIN_WDFLAG, 0 ); pWd->WdInputBufferLength = GetNumValue( Handle, WIN_INPUTBUFFERLENGTH, 2048 ); GetStringValue( Handle, WIN_CFGDLL, NULL, pWd->CfgDLL, DLLNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_WDPREFIX, NULL, pWd->WdPrefix, WDPREFIX_LENGTH + 1 ); } /******************************************************************************* * * QueryPdConfig * * query PDCONFIG structure * * ENTRY: * * Handle (input) * registry handle * pConfig (output) * address to return array of PDCONFIG structures * pCount (input/output) * pointer to number of PDCONFIG array elements * * EXIT: * nothing * ******************************************************************************/ VOID QueryPdConfig( HKEY Handle, PPDCONFIG pConfig, PULONG pCount ) { ULONG i; for ( i=0; i < *pCount; i++ ) { QueryPdConfig2( Handle, &pConfig[i].Create, i ); QueryPdParams( Handle, pConfig[i].Create.SdClass, &pConfig[i].Params ); } *pCount = MAX_PDCONFIG; } /******************************************************************************* * * QueryPdConfig2 * * query PDCONFIG2 structure * * ENTRY: * * Handle (input) * registry handle * pPd2 (output) * address to return PDCONFIG2 structure * Index (input) * Index (array index) * * EXIT: * nothing * ******************************************************************************/ VOID QueryPdConfig2( HKEY Handle, PPDCONFIG2 pPd2, ULONG Index ) { GetStringValueEx( Handle, WIN_PDNAME, Index, NULL, pPd2->PdName, PDNAME_LENGTH + 1 ); pPd2->SdClass = GetNumValueEx( Handle, WIN_PDCLASS, Index, Index==0 ? SdAsync : SdNone ); GetStringValueEx( Handle, WIN_PDDLL, Index, NULL, pPd2->PdDLL, DLLNAME_LENGTH + 1 ); pPd2->PdFlag = GetNumValueEx( Handle, WIN_PDFLAG, Index, 0 ); /* * The following data is the same for all pds */ pPd2->OutBufLength = GetNumValue( Handle, WIN_OUTBUFLENGTH, 530 ); pPd2->OutBufCount = GetNumValue( Handle, WIN_OUTBUFCOUNT, 10 ); pPd2->OutBufDelay = GetNumValue( Handle, WIN_OUTBUFDELAY, 100 ); pPd2->InteractiveDelay = GetNumValue( Handle, WIN_INTERACTIVEDELAY, 10 ); pPd2->KeepAliveTimeout = GetNumValue( Handle, WIN_KEEPALIVETIMEOUT, 0 ); pPd2->PortNumber = GetNumValue( Handle, WIN_PORTNUMBER, 0 ); } /******************************************************************************* * * QueryPdConfig3 * * query PDCONFIG3 structure * * ENTRY: * * Handle (input) * registry handle * pPd (output) * address to return PDCONFIG3 structure * Index (input) * Index (array index) * * EXIT: * nothing * ******************************************************************************/ VOID QueryPdConfig3( HKEY Handle, PPDCONFIG3 pPd3, ULONG Index ) { int i; ULONG Length; LPWSTR tmp; WCHAR PdName[ MAX_PDCONFIG * ( PDNAME_LENGTH + 1 ) + 1 ]; ULONG ValueType; QueryPdConfig2( Handle, &pPd3->Data, Index ); GetStringValue( Handle, WIN_SERVICENAME, NULL, pPd3->ServiceName, PDNAME_LENGTH + 1 ); GetStringValue( Handle, WIN_CONFIGDLL, NULL, pPd3->ConfigDLL, DLLNAME_LENGTH + 1 ); Length = sizeof(PdName); pPd3->RequiredPdCount = 0; if ( RegQueryValueEx( Handle, WIN_REQUIREDPDS, NULL, &ValueType, (LPBYTE)PdName, &Length ) == ERROR_SUCCESS ) { tmp = PdName; i = 0; while ( *tmp != UNICODE_NULL ) { pPd3->RequiredPdCount++; wcscpy( pPd3->RequiredPds[i], tmp ); i++; tmp += wcslen(tmp) + 1; } } } /******************************************************************************* * * QueryPdParams * * query PDPARAMS structure * * ENTRY: * * Handle (input) * registry handle * SdClass (input) * type of PD * pParams (output) * address to return PDPARAMS structure * * EXIT: * nothing * ******************************************************************************/ VOID QueryPdParams( HKEY Handle, SDCLASS SdClass, PPDPARAMS pParams ) { pParams->SdClass = SdClass; switch ( SdClass ) { case SdNetwork : QueryNetwork( Handle, &pParams->Network ); break; case SdNasi : QueryNasi( Handle, &pParams->Nasi ); break; case SdAsync : QueryAsync( Handle, &pParams->Async ); break; case SdOemTransport : QueryOemTd( Handle, &pParams->OemTd ); break; } } #define CONTROL_PANEL L"Control Panel" #define DESKTOP L"Desktop" #define WALLPAPER L"Wallpaper" #define NONE L"(None)" /******************************************************************************* * * IsWallPaperDisabled * * Is the wall paper disabled? * * ENTRY: * Handle (input) * registry handle * EXIT: * TRUE or FALSE (returns FALSE as default) * ******************************************************************************/ BOOLEAN IsWallPaperDisabled( HKEY Handle ) { HKEY Handle1; WCHAR KeyString[256]; wcscpy( KeyString, WIN_USEROVERRIDE ); wcscat( KeyString, L"\\" ); wcscat( KeyString, CONTROL_PANEL ); wcscat( KeyString, L"\\" ); wcscat( KeyString, DESKTOP ); if ( RegOpenKeyEx( Handle, KeyString, 0, KEY_READ, &Handle1 ) != ERROR_SUCCESS ) return FALSE; GetStringValue( Handle1, WALLPAPER, NULL, KeyString, 256 ); RegCloseKey( Handle1 ); if( KeyString[0] == 0 || ( _wcsicmp( NONE, KeyString ) == 0 ) ) { return TRUE; } return FALSE; } /***************************************************************************** * * RegBuildNumberQuery * * Query the current build number from the registry. * * HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\Current Version\ * CurrentBuildNumber:REG_SZ:129 * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/ BOOLEAN WINAPI RegBuildNumberQuery( PULONG pBuildNum ) { ULONG Result, Value; HKEY hKey; WCHAR Buf[256]; Result = RegOpenKeyEx( HKEY_LOCAL_MACHINE, BUILD_NUMBER_KEY, 0, // Reserved KEY_READ, &hKey ); if( Result != ERROR_SUCCESS ) { #if DBG DbgPrint("RegBuildNumberQuery: Failed to open key %ws\n",BUILD_NUMBER_KEY); #endif return( FALSE ); } Result = GetStringValue( hKey, BUILD_NUMBER_VALUE, L"0", Buf, sizeof(Buf) ); if( Result != ERROR_SUCCESS ) { #if DBG DbgPrint("RegBuildNumberQuery: Failed to query value %ws\n",BUILD_NUMBER_VALUE); #endif RegCloseKey( hKey ); return( FALSE ); } RegCloseKey( hKey ); // // Now must convert it into a number // Value = 0; swscanf( Buf, L"%d", &Value ); *pBuildNum = Value; return( TRUE ); } /******************************************************************************* * * RegQueryOEMId * * query oem id * * ENTRY: * * pOEMId (output) * pointer to buffer to return oem id * Length (input) * length of buffer * * EXIT: * * TRUE -- The operation succeeded. * * FALSE -- The operation failed. Extended error status is available * using GetLastError. * ******************************************************************************/ BOOLEAN RegQueryOEMId( PBYTE pOEMId, ULONG Length ) { HKEY Handle2; WCHAR OEMIdW[10]; /* * Open registry (LOCAL_MACHINE\....\Terminal Server) */ if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CONTROL_TSERVER, 0, KEY_READ, &Handle2 ) == ERROR_SUCCESS ) { GetStringValue( Handle2, REG_CITRIX_OEMID, NULL, OEMIdW, 10 ); UnicodeToAnsi( pOEMId, Length, OEMIdW ); pOEMId[3] = '\0'; RegCloseKey( Handle2 ); } return( TRUE ); } /******************************************************************************* * * RegGetTServerVersion (UNICODE) * * Get the Terminal Server version number from the specified server. * * This version number is changed by Microsoft, and not OEM's. * * ENTRY: * pServerName (input) * Points to string of server to check. * * EXIT: * TRUE if Hydra Terminal Server; FALSE otherwise * ******************************************************************************/ BOOLEAN WINAPI RegGetTServerVersion( WCHAR * pServerName, PULONG pVersionNumber ) { LONG Error; HKEY ServerHandle, UserHandle; ULONG Value; /* * Connect to registry of specified server. */ if ( (Error = RegConnectRegistry( pServerName, HKEY_LOCAL_MACHINE, &ServerHandle )) != ERROR_SUCCESS ) return( FALSE ); /* * Open the Terminal Server key and get the Version value. */ if ( (Error = RegOpenKeyEx( ServerHandle, REG_CONTROL_TSERVER, 0, KEY_READ, &UserHandle )) != ERROR_SUCCESS ) { RegCloseKey( ServerHandle ); return( FALSE ); } Value = GetNumValue( UserHandle, REG_CITRIX_VERSION, 0 ); /* * Close registry handles. */ RegCloseKey( UserHandle ); RegCloseKey( ServerHandle ); *pVersionNumber = Value; return( TRUE ); } /******************************************************************************* * * RegQueryUtilityCommandList (UNICODE) * * Allocate and build an array of PROGRAMCALL structures for the specified * MultiUser utility. * * ENTRY: * pUtilityKey (input) * Points to string containing the utility's command registry key. * ppProgramCall (output) * Points to a PPROGRAMCALL variable that will be set to the API-allocated * array of PROGRAMCALL structures, containing n elements, where n = * number of commands supported by the utility (as specified in the * registry). The pFirst item of array element 0 will point to the * first command (sorted alphabetically by command name). The pNext items * are then used to walk the list, till pNext is NULL. * * EXIT: * ERROR_SUCCESS if all goes well; * An error code is returned if failure. * * If success, the caller must call RegFreeUtilityCommandList with the * ppProgramCall variable to free the PROGRAMCALL structure array when * finished using the array. * * The format of the REG_MULTI_SZ command item in the registry is as follows: * * string 1: "0" or "1" (required) * * 0 specifies that the command is a normal command which will * be presented as an option by the utility USAGE help. 1 * indicates a command alias (hidden option), which won't * appear in USAGE help. * * string 2: "number" (required) * * Specifies the minimum number of characters that must be * typed for the command to be recognized (base 10). * * string 3: "command" (required) * * This is the actual command that will be recognized and * displayed in the USAGE help (if not an aliased command). * * string 4: "program" (required) * * The file name of the program that will be executed. This * should be a standard name.extension filename, and can * include a full path, although this is not necessary since * the utilities will normally reside in the standard SYSTEM32 * directory, which is a part of the standard PATH. * * string 5: "extra args" (optional) * * If specified, this string will be passed along to the * utilsub.lib ExecProgram API to specify additional * hard-coded arguments that will be used, in addition to any * other arguments that were specified by the user on the * command line. * * Note: If the command item is not a REG_MULTI_SZ value, or the command item * is a REG_MULTI_SZ item but there is an error in its format, that * command will be omitted from the command list. The return value * from this function will still be ERROR_SUCCESS, but the command in * error will be ignored by the utilities. * ******************************************************************************/ LONG WINAPI RegQueryUtilityCommandList( LPWSTR pUtilityKey, PPROGRAMCALL * ppProgramCall ) { HKEY Handle = NULL; LONG status = ERROR_SUCCESS; DWORD iValue, cValues, ccValueName, cbValueData, ccTmpValueName, cbTmpValueData, dwType; LPWSTR pValueName = NULL, pValueData = NULL, pString; PPROGRAMCALL pProg = NULL, pProgNext, pProgPrev; ULONG ulCommandLen; PWCHAR pEndptr; int iCompare; *ppProgramCall = NULL; /* * Open specified utility key and determine number of values and maximum * value name and data length. */ if ( status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pUtilityKey, 0, KEY_READ, &Handle ) != ERROR_SUCCESS ) { #if DBG DbgPrint("RegQueryUtilityCommandList: Can't open command list utility key %ws; error = %d\n", pUtilityKey, status); #endif goto error; } if ( status = RegQueryInfoKey( Handle, NULL, // lpClass NULL, // lpcbClass NULL, // lpReserved NULL, // lpcSubKeys NULL, // lpcbMaxSubKeyLen NULL, // lpcbMaxClassLen &cValues, // lpcValues &ccValueName, // lpcbMaxValueNameLen &cbValueData, // lpcbMaxValueLen NULL, // lpcbSecurityDescriptor NULL // lpftLastWriteTime ) != ERROR_SUCCESS ) { #if DBG DbgPrint("RegQueryUtilityCommandList: Can't query info for utility %ws; error = %d\n", pUtilityKey, status); #endif goto error; } /* * Allocate space for #values + 1 PROGRAMCALL elements and value name and * data buffers. */ if ( ((*ppProgramCall = (PPROGRAMCALL)LocalAlloc( LPTR, (sizeof(PROGRAMCALL) * (cValues+1)) )) == NULL) || ((pValueName = (LPWSTR)LocalAlloc( LPTR, (int)(++ccValueName * sizeof(WCHAR)) )) == NULL) || ((pValueData = (LPWSTR)LocalAlloc( LPTR, (int)cbValueData )) == NULL) ) { status = GetLastError(); #if DBG DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer(s) for utility %ws; error = %d\n", pUtilityKey, status); #endif goto error; } /* * Enumerate and parse each value into the PROGRAMCALL components. */ for ( iValue = 0, pProg = *ppProgramCall; iValue < cValues; iValue++, pProg++ ) { ccTmpValueName = ccValueName; cbTmpValueData = cbValueData; if ( (status = RegEnumValue( Handle, iValue, pValueName, &ccTmpValueName, NULL, &dwType, (LPBYTE)pValueData, &cbTmpValueData )) != ERROR_SUCCESS ) { #if DBG DbgPrint("RegQueryUtilityCommandList: Can't enumerate command (index = %d) for utility %ws; error = %d\n", iValue, pUtilityKey, status); #endif goto error; } /* * If the data is not REG_MULTI_SZ, ignore it. */ if ( dwType != REG_MULTI_SZ ) goto CommandInError; /* * Allocate data storage for this command, then parse and assign * to the PROGRAMCALL structure items. */ if ( (pProg->pRegistryMultiString = LocalAlloc(LPTR, cbTmpValueData)) == NULL ) { status = GetLastError(); #if DBG DbgPrint("RegQueryUtilityCommandList: Can't allocate memory buffer for utility %ws; error = %d\n", pUtilityKey, status); #endif goto error; } memcpy(pProg->pRegistryMultiString, pValueData, cbTmpValueData); pString = pProg->pRegistryMultiString; /* * Parse alias flag. */ if ( !wcscmp(pString, L"1") ) pProg->fAlias = TRUE; else if ( !wcscmp(pString, L"0") ) pProg->fAlias = FALSE; else goto CommandInError; pString += (wcslen(pString) + 1); /* * Parse command length. */ if ( *pString == L'\0' ) goto CommandInError; ulCommandLen = wcstoul(pString, &pEndptr, 10); if ( *pEndptr != L'\0' ) goto CommandInError; pProg->CommandLen = (USHORT)ulCommandLen; pString += (wcslen(pString) + 1); /* * Parse command string. */ if ( *pString == L'\0' ) goto CommandInError; pProg->Command = pString; pString += (wcslen(pString) + 1); /* * Parse program string. */ if ( *pString == L'\0' ) goto CommandInError; pProg->Program = pString; pString += (wcslen(pString) + 1); /* * Parse (optional) Args string. */ if ( *pString != L'\0' ) pProg->Args = pString; /* * Walk the command list to link this item in it's proper * sorted place. */ if ( pProg == *ppProgramCall ) { pProg->pFirst = pProg; // first item in the list } else for ( pProgPrev = pProgNext = (*ppProgramCall)->pFirst; ; ) { if ( (iCompare = _wcsicmp(pProg->Command, pProgNext->Command)) < 0 ) { pProg->pNext = pProgNext; // point to next if ( pProgNext == (*ppProgramCall)->pFirst ) (*ppProgramCall)->pFirst = pProg; // first item else pProgPrev->pNext = pProg; // link after previous break; } else if ( iCompare == 0 ) { goto CommandInError; // duplicate command - ignore } if ( pProgNext->pNext == NULL ) { pProgNext->pNext = pProg; // link at end of list break; } else { pProgPrev = pProgNext; pProgNext = pProgNext->pNext; } } continue; CommandInError: /* * The command format is in error - ignore it. */ if ( pProg->pRegistryMultiString ) LocalFree(pProg->pRegistryMultiString); memset(pProg, 0, sizeof(PROGRAMCALL)); pProg--; } error: if ( Handle != NULL ) RegCloseKey(Handle); if ( pValueName ) LocalFree(pValueName); if ( pValueData ) LocalFree(pValueData); if ( status != ERROR_SUCCESS ) { if ( *ppProgramCall ) { RegFreeUtilityCommandList(*ppProgramCall); *ppProgramCall = NULL; } } return( status ); } /******************************************************************************* * * RegFreeUtilityCommandList (UNICODE) * * Free the specified array of PROGRAMCALL structures. * * ENTRY: * pProgramCall (input) * Points PROGRAMCALL array to free. * * EXIT: * ERROR_SUCCESS if all goes well; error code if failure * ******************************************************************************/ LONG WINAPI RegFreeUtilityCommandList( PPROGRAMCALL pProgramCall ) { PPROGRAMCALL pProg; LONG status = ERROR_SUCCESS; if ( pProgramCall ) { for ( pProg = pProgramCall->pFirst; pProg != NULL; pProg = pProg->pNext ) { if ( LocalFree( pProg->pRegistryMultiString ) != NULL ) { status = GetLastError(); #if DBG DbgPrint("RegFreeUtilityCommandList: Failed to free command list element for %ws; error = %d\n", pProg->Program, status); #endif } } if ( LocalFree( pProgramCall ) != NULL ) { status = GetLastError(); #if DBG DbgPrint("RegFreeUtilityCommandList: Failed to free command list array; error = %d\n", status); #endif } } return( status ); }