// // Popup choices and install Timestamp driver. // // ShreeM (January 31, 1999) // // This command line based installation program does the following - // 1. TcEnumerateInterfaces. // 2. Display these interfaces to the user. // 3. Based on the user input - Plumb the registry. // 4. Ask the user if the service needs to be AUTO or MANUAL. // #define UNICODE #define INITGUID #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LAST_COMPATIBLE_OS_VERSION 2050 HANDLE hClient = NULL; ULONG ClientContext = 12; BOOLEAN WANlink = FALSE; #define REGKEY_SERVICES TEXT("System\\CurrentControlSet\\Services") #define REGKEY_PSCHED TEXT("System\\CurrentControlSet\\Services\\Psched") #define REGKEY_PSCHED_PARAMS TEXT("System\\CurrentControlSet\\Services\\Psched\\Parameters") #define REGKEY_PSCHED_PARAMS_ADAPTERS TEXT("System\\CurrentControlSet\\Services\\Psched\\Parameters\\Adapters") #define REGKEY_TIMESTMP TEXT("System\\CurrentControlSet\\Services\\TimeStmp") TCHAR Profiles[] = TEXT("LANTEST"); TCHAR Lantest[] = TEXT("TokenBucketConformer\0TrafficShaper\0DRRSequencer\0TimeStmp"); // // Function prototype // VOID ShutdownNT(); VOID _stdcall NotifyHandler( HANDLE ClRegCtx, HANDLE ClIfcCtx, ULONG Event, HANDLE SubCode, ULONG BufSize, PVOID Buffer) { // // This function may get executed in a new thread, so we can't fire the events directly (because // it breaks some clients, like VB and IE.) To get around this, we'll fire off an APC in the origina // thread, which will handle the actual event firing. // OutputDebugString(TEXT("Notify called\n")); } // // Delete the service and cleanup Psched regkeys // BOOLEAN DeleteTimeStamp(PTC_IFC_DESCRIPTOR pIf); // Just delete the service (no psched stuff) VOID RemoveTimeStampService(); void _cdecl main( INT argc, CHAR *argv[] ) { TCI_CLIENT_FUNC_LIST ClientHandlerList; ULONG err; TCHAR SzBuf[MAX_PATH], *TBuffer, *KeyBuffer; ULONG i = 0, len = 0, j = 0, cb = 0, Number = 0, size = 0, interfaceid = 0; WCHAR servicetype, response; BYTE *Buffer; TC_IFC_DESCRIPTOR *pIf, WanIf; DWORD ret, Disposition, starttype, choice, InstallFlag = -1; HKEY hConfigKey, TimeStampKey; SC_HANDLE schService; SC_HANDLE schSCManager; BOOLEAN Success = FALSE; OSVERSIONINFO osversion; ClientHandlerList.ClNotifyHandler = NotifyHandler; ClientHandlerList.ClAddFlowCompleteHandler = NULL; ClientHandlerList.ClModifyFlowCompleteHandler = NULL; ClientHandlerList.ClDeleteFlowCompleteHandler = NULL; wprintf(TEXT("Installer for Time Stamp module 1.0 for Windows NT (c) Microsoft Corp.\n\n")); // check if the psched versions will be compatible before doing anything here. osversion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); osversion.dwBuildNumber = 0; GetVersionEx(&osversion); if (osversion.dwBuildNumber < LAST_COMPATIBLE_OS_VERSION) { wprintf(TEXT("Install ERROR!\nYour current Windows 2000 OS build number is %d.\n"), osversion.dwBuildNumber); wprintf(TEXT("To use the version of TIMESTMP in the QoS Tools CD, you will be required to upgrade \nto an OS build number of atleast 2050 or later.\n")); return; } wprintf(TEXT("Running this program will (un)install this module on one Interface at a time.\n")); wprintf(TEXT("You will the prompted for basic choices in the installation process.\n")); j = 0; get_again: wprintf(TEXT("[1] Install\n[2] Uninstall\n[3] Exit\n Your Choice:")); fflush(stdin); wscanf(TEXT("%d"), &choice); if (1 == choice) { InstallFlag = 1; } else if (2 == choice) { InstallFlag = 0; } else if (3 == choice) { return; } else if (j < 3) { j++; goto get_again; } else { return; } err = TcRegisterClient( CURRENT_TCI_VERSION, (HANDLE)UlongToPtr(ClientContext), &ClientHandlerList, &hClient ); if (NO_ERROR != err) { hClient = NULL; wsprintf(SzBuf, TEXT("Error registering Client: %d - %d\n"), err, GetLastError()); OutputDebugString(SzBuf); wprintf(TEXT("INSTALLER: QoS is not installed on this machine\n\n")); // // However, if it should be ok to Uninstall the Timestmp service using this easily. // if (0 == InstallFlag) { RemoveTimeStampService(); } return; } else { OutputDebugString(TEXT("Registered Client:\n")); } size = 0; // Query Buffer Size required. err = TcEnumerateInterfaces( hClient, &size, (TC_IFC_DESCRIPTOR *)NULL ); if (NO_ERROR != err) { wsprintf(SzBuf, TEXT("Error Enumerating Interfaces: %d - (size reqd. %d) \n"), err, size); OutputDebugString(SzBuf); } else { wsprintf(SzBuf, TEXT("Enumerating Interfaces works??? : %d - ITS OK!\n"), size); OutputDebugString(SzBuf); wprintf(TEXT("INSTALLER: QoS is either not installed on this machine\n\t OR \n")); wprintf(TEXT("None of the adapters are enabled for QoS\n")); // // However, if it should be ok to Uninstall the Timestmp service using this easily. // if (0 == InstallFlag) { RemoveTimeStampService(); } wprintf(TEXT("Exiting...\n")); goto cleanup_no_free; } // if there are no interfaces (qos is not installed on this machine), get out. // if (!size) { wprintf(TEXT("INSTALLER: QoS is either not installed on this machine\n\t OR \n")); wprintf(TEXT("None of the adapters are enabled for QoS\n")); // // However, if it should be ok to Uninstall the Timestmp service using this easily. // if (0 == InstallFlag) { RemoveTimeStampService(); } wprintf(TEXT("Exiting...\n")); goto cleanup_no_free; } // query the interfaces Buffer = malloc (size); err = TcEnumerateInterfaces( hClient, &size, (TC_IFC_DESCRIPTOR *)Buffer ); if (NO_ERROR != err) { wsprintf(SzBuf, TEXT("Error Enumerating Interfaces: %d (size:%d)!\n"), err, size); OutputDebugString(SzBuf); // // However, if it should be ok to Uninstall the Timestmp service using this easily. // if (0 == InstallFlag) { RemoveTimeStampService(); } wprintf(TEXT("Exiting...\n")); goto cleanup; } else { OutputDebugString(TEXT("OK, so we got the interfaces.\n")); } // Display the interfaces for the user. wprintf(TEXT("\nThe interfaces available for (un)installing time stamp module are - \n")); len = 0; for (i = 1; len < size ; i++) { pIf = (PTC_IFC_DESCRIPTOR)(Buffer + len); wprintf(TEXT("[%d]:%ws\n\t%ws\n"), i, pIf->pInterfaceName, pIf->pInterfaceID); // Move to next interface len += pIf->Length; if (NULL != wcsstr(pIf->pInterfaceName, L"WAN")) { wprintf(TEXT("Please disconnect WAN links before installing Timestmp\n")); goto cleanup; } } wprintf(TEXT("[%d]:NDISWANIP (the WAN Interface)\n"), i); // Try to get the interface ID thrice... j = 0; get_interfaceid: wprintf(TEXT("\nYour choice:")); fflush(stdin); wscanf(TEXT("%d"), &interfaceid); if (interfaceid < 1 || (interfaceid > i)) { j++; if (j > 2) { wprintf(TEXT("Invalid Choice - Exiting...\n")); goto cleanup; } else { wprintf(TEXT("Invalid choice - pick again\n")); goto get_interfaceid; } } // Get to the interface ID for the Interface selected. pIf = NULL; len = 0; if (i == interfaceid) { wprintf(TEXT("\nInterface selected for (un)installing Time Stamp - \nNdisWanIp\n\n\n")); WANlink = TRUE; pIf = NULL; } else { for (i = 1; i <= interfaceid ; i++) { pIf = (PTC_IFC_DESCRIPTOR)(Buffer + len); wprintf(TEXT("[%d]:%ws\n\t%ws\n"), i, pIf->pInterfaceName, pIf->pInterfaceID); if (i == interfaceid) { break; } // Move to next interface len += pIf->Length; } wprintf(TEXT("\nInterface selected for (un)installing Time Stamp - \n%ws\n\n\n"), pIf->pInterfaceName); } // // Branch here for Uninstall/Install. // if (InstallFlag == FALSE) { if (!DeleteTimeStamp(pIf)) { wprintf(TEXT("Delete TimeStamp Failed!\n")); } return; } // // This is the regular install path. // j = 0; get_servicetype: wprintf(TEXT("\nWould you like this service to be- [A]UTO, [M]ANUAL, [D]ISABLED:")); fflush(stdin); wscanf(TEXT("%[a-z]"), &servicetype); switch (towupper(servicetype)) { case TEXT('A'): wprintf(TEXT("\nYou have chosen AUTO start up option\n")); starttype = SERVICE_AUTO_START; break; case TEXT('D'): wprintf(TEXT("\nYou have chosen DISABLED start up option\n")); starttype = SERVICE_DISABLED; break; case TEXT('M'): wprintf(TEXT("\nYou have chosen MANUAL start up option")); starttype = SERVICE_DEMAND_START; break; default: if (j > 2) { wprintf(TEXT("\nIncorrect choice. Exiting...\n")); goto cleanup; } else { j++; wprintf(TEXT("\nInvalid - Choose again.\n")); goto get_servicetype; } break; } wprintf(TEXT("\n\n\n")); // // We have enough info to muck with the registry now. // // 1.1 open psched regkey and add profile ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_PSCHED_PARAMS, 0, KEY_ALL_ACCESS, &hConfigKey); if (ret !=ERROR_SUCCESS){ wprintf(TEXT("Cant OPEN key\n")); goto cleanup; } ret = RegSetValueEx( hConfigKey, TEXT("Profiles"), 0, REG_MULTI_SZ, (LPBYTE)Profiles, sizeof(Profiles) ); if (ret !=ERROR_SUCCESS){ wprintf(TEXT("Cant SET Value:Profiles\n")); RegCloseKey(hConfigKey); goto cleanup; } ret = RegSetValueEx( hConfigKey, TEXT("LANTEST"), 0, REG_MULTI_SZ, (LPBYTE)Lantest, sizeof(Lantest) ); if (ret !=ERROR_SUCCESS){ wprintf(TEXT("Cant SET Value:LANTEST\n")); RegCloseKey(hConfigKey); goto cleanup; } RegCloseKey(hConfigKey); // 1.2 Open the adapters section and add the profile if (!WANlink) { KeyBuffer = malloc(sizeof(TCHAR) * (wcslen(pIf->pInterfaceID) + wcslen(REGKEY_PSCHED_PARAMS_ADAPTERS))); } else { KeyBuffer = malloc(sizeof(TCHAR) * (wcslen(TEXT("NdisWanIp")) + wcslen(REGKEY_PSCHED_PARAMS_ADAPTERS))); } wcscpy(KeyBuffer, REGKEY_PSCHED_PARAMS_ADAPTERS); wcscat(KeyBuffer, TEXT("\\")); if (!WANlink) { wcscat(KeyBuffer, pIf->pInterfaceID); } else { wcscat(KeyBuffer, TEXT("NdisWanIp")); } ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE, KeyBuffer, 0, KEY_ALL_ACCESS, &hConfigKey); if (ret != ERROR_SUCCESS) { wprintf(TEXT("INSTALLER: Couldn't open Regkey for Adapter specific info\n")); free(KeyBuffer); RegCloseKey(hConfigKey); goto cleanup; } ret = RegSetValueEx( hConfigKey, TEXT("Profile"), 0, REG_SZ, (LPBYTE)Profiles, sizeof(Profiles) ); if (ret !=ERROR_SUCCESS){ wprintf(TEXT("Cant SET Value:LANTEST under PARAMETERS\\ADAPTERS\n")); free(KeyBuffer); RegCloseKey(hConfigKey); goto cleanup; } free(KeyBuffer); RegCloseKey(hConfigKey); // 2. throw in time stamp into the registry ret = RegCreateKeyEx( HKEY_LOCAL_MACHINE, // handle of an open key REGKEY_TIMESTMP, // address of subkey name 0, // reserved TEXT(""), // address of class string REG_OPTION_NON_VOLATILE, // special options flag KEY_ALL_ACCESS, // desired security access NULL, // address of key security structure &TimeStampKey, // address of buffer for opened handle &Disposition // address of disposition value buffer ); if (ret != ERROR_SUCCESS) { wprintf(TEXT("Couldn't open Regkey to plumb time stamp module\n")); RegCloseKey(hConfigKey); goto cleanup; } if (Disposition == REG_OPENED_EXISTING_KEY) { wprintf(TEXT("Time Stamp module is already installed.\n\n\n\n")); RegCloseKey(hConfigKey); goto cleanup; } RegCloseKey(hConfigKey); // 3. Create the service... schSCManager = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if ( schSCManager ) { schService = CreateService( schSCManager, // SCManager database TEXT("TimeStmp"), // name of service TEXT("TimeStmp"), // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_KERNEL_DRIVER, // service type starttype, // start type SERVICE_ERROR_NORMAL, // error control type TEXT("System32\\Drivers\\timestmp.sys"), // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // BUGBUG: no depend upon PNP_TDI?? NULL, // LocalSystem account NULL); // no password if (!schService) { // couldn't create it. wprintf(TEXT("Could NOT create Time Stamp service - %d"), GetLastError()); goto cleanup; } else { wprintf(TEXT("\nThe service will start on reboot.\n")); Success = TRUE; } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); } else { wprintf(TEXT("\nINSTALLER: Couldn't open Service Control Manager - Do you have access?\n")); } wprintf(TEXT("The Time Stamp module installation is complete.\n")); wprintf(TEXT("Please ensure that a copy of timestmp.sys exists in your\n")); wprintf(TEXT("\\system32\\drivers directory before you reboot.\n")); cleanup: // cleanup before getting out free(Buffer); cleanup_no_free: // deregister before bailing... err = TcDeregisterClient(hClient); if (NO_ERROR != err) { hClient = NULL; wsprintf(SzBuf, TEXT("Error DEregistering Client: %d - %d\n"), err, GetLastError()); OutputDebugString(SzBuf); return; } if (Success) { ShutdownNT(); } } // // Delete the service and cleanup Psched regkeys // BOOLEAN DeleteTimeStamp(PTC_IFC_DESCRIPTOR pIf) { SC_HANDLE schService; SC_HANDLE schSCManager; TCHAR *KBuffer; DWORD err; HKEY hKey; // // 1. Delete Timestamp service. // schSCManager = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if ( schSCManager ) { schService = OpenService( schSCManager, // handle to service control manager TEXT("TimeStmp"), // pointer to name of service to start SERVICE_ALL_ACCESS // type of access to service ); if (!schService) { // couldn't open it. wprintf(TEXT("Could NOT open Time Stamp service - %d\n"), GetLastError()); wprintf(TEXT("Deletion of Time Stamp Service was UNSUCCESSFUL\n")); //return FALSE; } else { if (!DeleteService(schService)) { wprintf(TEXT("\nThe deletion of Timestamp service has failed - error (%d).\n"), GetLastError()); } else { wprintf(TEXT("\nThe service will NOT start on reboot.\n")); } } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); } else { wprintf(TEXT("\nINSTALLER: Couldn't open Service Control Manager - Do you have access?\n")); } // // 2. Clean up psched registry. // err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_PSCHED_PARAMS, 0, KEY_ALL_ACCESS, &hKey); if (err !=ERROR_SUCCESS){ wprintf(TEXT("Cant OPEN key\n")); return FALSE; } err = RegDeleteValue( hKey, TEXT("Profiles") ); if (err !=ERROR_SUCCESS){ wprintf(TEXT("Cant Delete Value:Profiles\n")); RegCloseKey(hKey); return FALSE; } err = RegDeleteValue( hKey, TEXT("LANTEST") ); if (err != ERROR_SUCCESS){ wprintf(TEXT("Cant Delete Value:LANTEST\n")); RegCloseKey(hKey); return FALSE; } RegCloseKey(hKey); // 2.2 Clean up the adapter specific registry if (!WANlink) { KBuffer = malloc(sizeof(TCHAR) * (wcslen(pIf->pInterfaceID) + wcslen(REGKEY_PSCHED_PARAMS_ADAPTERS))); } else { KBuffer = malloc(sizeof(TCHAR) * (wcslen(TEXT("NdisWanIp")) + wcslen(REGKEY_PSCHED_PARAMS_ADAPTERS))); } wcscpy(KBuffer, REGKEY_PSCHED_PARAMS_ADAPTERS); wcscat(KBuffer, TEXT("\\")); if (!WANlink) { wcscat(KBuffer, pIf->pInterfaceID); } else { wcscat(KBuffer, TEXT("NdisWanIp")); } err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, KBuffer, 0, KEY_ALL_ACCESS, &hKey); if (err != ERROR_SUCCESS) { wprintf(TEXT("INSTALLER: Couldn't open Regkey for Adapter specific info\n")); wprintf(TEXT("INSTALLER: CLEAN UP is partial\n")); free(KBuffer); return FALSE; } err = RegDeleteValue( hKey, TEXT("Profile") ); if (err !=ERROR_SUCCESS){ wprintf(TEXT("Cant Delete Value:LANTEST under PARAMETERS\\ADAPTERS\n")); wprintf(TEXT("INSTALLER: CLEAN UP is partial\n")); free(KBuffer); RegCloseKey(hKey); return FALSE; } free(KBuffer); RegCloseKey(hKey); wprintf(TEXT("The Time Stamp service is successfully deleted\n")); wprintf(TEXT("You need to reboot for the changes to take effect\n")); return TRUE; } // Just delete the service (no psched stuff) VOID RemoveTimeStampService( ) { SC_HANDLE schService; SC_HANDLE schSCManager; TCHAR *KBuffer; DWORD err; HKEY hKey; // // 1. Delete Timestamp service. // schSCManager = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if ( schSCManager ) { schService = OpenService( schSCManager, // handle to service control manager TEXT("TimeStmp"), // pointer to name of service to start SERVICE_ALL_ACCESS // type of access to service ); if (!schService) { // couldn't open it. wprintf(TEXT("Could NOT open Time Stamp service - %d\n"), GetLastError()); wprintf(TEXT("Deletion of Time Stamp Service was UNSUCCESSFUL\n")); return; } else { if (!DeleteService(schService)) { wprintf(TEXT("\nThe deletion of Timestamp service has failed - error (%d).\n"), GetLastError()); } else { wprintf(TEXT("\nThe service will NOT start on reboot.\n")); } } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); } else { wprintf(TEXT("\nINSTALLER: Couldn't open Service Control Manager - Do you have access?\n")); } wprintf(TEXT("The Time Stamp service is successfully deleted\n")); wprintf(TEXT("You need to reboot for the changes to take effect\n")); return; } VOID ShutdownNT() { HANDLE hToken; // handle to process token TOKEN_PRIVILEGES tkp; // ptr. to token structure TCHAR SzBuf[MAX_PATH]; BOOL fResult; // system shutdown flag INT nRet = IDYES; // Get the curren process token handle // so we can get shutdown privilege. if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { wsprintf(SzBuf, TEXT("OpenProcessToken failed (%d)\n"), GetLastError()); OutputDebugString(SzBuf); return; } // Get the LUID for shutdown privilege LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); tkp.PrivilegeCount = 1; // one privilege to set tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // Get shutdown privileges for this process AdjustTokenPrivileges (hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); // Cannot test the return value of AdjustTokenPrivileges if (GetLastError() != ERROR_SUCCESS) { wsprintf(SzBuf, TEXT("AdjustTokenPriviledges failed (%d)\n"), GetLastError()); OutputDebugString(SzBuf); CloseHandle(hToken); return; } CloseHandle(hToken); /*if (!InitiateSystemShutdownEx( NULL, , 0xffffff00, FALSE, //BOOL bForceAppsClosed, TRUE, //BOOL bRebootAfterShutdown, 0 //DWORD dwReason )) {*/ // // OK, so how about a popup? // nRet = MessageBox ( NULL,//hwndParent, TEXT("A reboot is required for TimeStamp Driver to get loaded. Please ensure that your %windir%\\system32\\driver's directory has a copy of timestmp.sys. Reboot now?"), TEXT("TIMESTAMP Driver Install Program"), MB_YESNO | MB_ICONEXCLAMATION ); if (nRet == IDYES) { if (!ExitWindowsEx(EWX_REBOOT, 10)) { wsprintf(SzBuf, TEXT("InitializeShutdownEx failed (%d)\n"), GetLastError()); OutputDebugString(SzBuf); } else { return; } } return; }