/*++ Copyright (c) 1992-1996 Microsoft Corporation Module Name: snmp.c Abstract: Provides service functionality for Proxy Agent. Environment: User Mode - Win32 Revision History: 10-May-1996 DonRyan Removed banner from Technology Dynamics, Inc. --*/ //--------------------------- WINDOWS DEPENDENCIES -------------------------- //--------------------------- STANDARD DEPENDENCIES -- #include ---- #include #include #include #include //--------------------------- MODULE DEPENDENCIES -- #include"xxxxx.h" ------ #include #include "snmpctrl.h" #include "..\common\evtlog.h" //--------------------------- SELF-DEPENDENCY -- ONE #include"module.h" ----- //--------------------------- PUBLIC VARIABLES --(same as in module.h file)-- BOOL noservice; DWORD platformId; DWORD WinVersion; //--------------------------- PRIVATE CONSTANTS ----------------------------- //--------------------------- PRIVATE STRUCTS ------------------------------- //--------------------------- PRIVATE VARIABLES ----------------------------- SERVICE_STATUS_HANDLE hService = 0; SERVICE_STATUS status = {SERVICE_WIN32, SERVICE_STOPPED, SERVICE_ACCEPT_STOP, NO_ERROR, 0, 0, 0}; //--------------------------- PRIVATE PROTOTYPES ---------------------------- BOOL agentConfigInit(VOID); //--------------------------- PRIVATE PROCEDURES ---------------------------- static VOID serviceHandlerFunction( IN DWORD dwControl) { extern HANDLE hExitTrapThreadEvent; SNMPDBG((SNMP_LOG_TRACE, "SNMP: SVC: serviceHandlerFunction entered, dwControl=%d.\n", dwControl)); // is it a LogLevel change control? if (SNMP_SERVICE_LOGLEVEL_BASE+SNMP_SERVICE_LOGLEVEL_MIN <= dwControl && dwControl <= SNMP_SERVICE_LOGLEVEL_BASE+SNMP_SERVICE_LOGLEVEL_MAX) { INT nLogLevel; nLogLevel = dwControl - SNMP_SERVICE_LOGLEVEL_BASE; SNMPDBG((SNMP_LOG_TRACE, "SNMP: SVC: loglevel changed to %d.\n", nLogLevel)); SnmpSvcSetLogLevel(nLogLevel); } // is it a LogType change control? else if (SNMP_SERVICE_LOGTYPE_BASE+SNMP_SERVICE_LOGTYPE_MIN <= dwControl && dwControl <= SNMP_SERVICE_LOGTYPE_BASE+SNMP_SERVICE_LOGTYPE_MAX) { INT nLogType; nLogType = dwControl - SNMP_SERVICE_LOGTYPE_BASE; if (!noservice) { // make sure console based log is prohibited when compiled as service nLogType &= ~SNMP_OUTPUT_TO_CONSOLE; } SNMPDBG((SNMP_LOG_TRACE, "SNMP: SVC: logtype changed to %d.\n", nLogType)); SnmpSvcSetLogType(nLogType); } else if (dwControl == SERVICE_CONTROL_STOP) { status.dwCurrentState = SERVICE_STOP_PENDING; status.dwCheckPoint++; status.dwWaitHint = 20000; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: SVC: error %d setting service status to pending.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } // set event causing trap thread to terminate, followed by comm thread if (!SetEvent(hExitTrapThreadEvent)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: SVC: error %s setting termination event.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); status.dwCurrentState = SERVICE_STOPPED; status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; status.dwServiceSpecificExitCode = 1; // OPENISSUE - svc err code status.dwCheckPoint = 0; status.dwWaitHint = 0; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: SVC: error %d setting service status to stopped.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } exit(1); } } else // dwControl == SERVICE_CONTROL_INTERROGATE // dwControl == SERVICE_CONTROL_PAUSE // dwControl == SERVICE_CONTROL_CONTINUE // dwControl == { if (status.dwCurrentState == SERVICE_STOP_PENDING || status.dwCurrentState == SERVICE_START_PENDING) { status.dwCheckPoint++; } if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: SVC: error %d updating service status.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } } } // end serviceHandlerFunction() static VOID serviceMainFunction( IN DWORD dwNumServicesArgs, IN LPSTR *lpServiceArgVectors) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: serviceMainFunction entered.\n")); while(dwNumServicesArgs--) { INT nLogLevel; INT nLogType; INT temp; if (1 == sscanf(*lpServiceArgVectors, "/loglevel:%d", &temp)) { nLogLevel = temp; SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: loglevel changed to %d.\n", temp)); SnmpSvcSetLogLevel(nLogLevel); } else if (1 == sscanf(*lpServiceArgVectors, "/logtype:%d", &temp)) { nLogType = temp; SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: logtype changed to %d.\n", temp)); SnmpSvcSetLogType(nLogType); } else { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: argument %s invalid.\n", *lpServiceArgVectors)); } lpServiceArgVectors++; } // end while() if (!noservice) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: registering service control handler.\n")); if ((hService = RegisterServiceCtrlHandler("SNMP", serviceHandlerFunction)) == 0) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on RegisterServiceCtrlHander %d\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); status.dwCurrentState = SERVICE_STOPPED; status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; status.dwServiceSpecificExitCode = 2; // OPENISSUE - svc err code status.dwCheckPoint = 0; status.dwWaitHint = 0; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d setting servicee status to stopped.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } else exit(1); } SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: setting service status to pending.\n")); status.dwCurrentState = SERVICE_START_PENDING; status.dwWaitHint = 20000; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d setting service status to pending.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } } if (!agentConfigInit()) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on agentConfigInit %d\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); status.dwCurrentState = SERVICE_STOPPED; status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; status.dwServiceSpecificExitCode = 3; // OPENISSUE - svc err code status.dwCheckPoint = 0; status.dwWaitHint = 0; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d setting service status to stopped.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } exit(1); } // above function will not return until running thread(s) terminate SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: setting service status to stopped.\n")); status.dwCurrentState = SERVICE_STOPPED; status.dwCheckPoint = 0; status.dwWaitHint = 0; if (!SetServiceStatus(hService, &status)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d setting service status to stopped.\n", GetLastError())); SnmpSvcReportEvent(SNMP_EVENT_FATAL_ERROR, 0, NULL, GetLastError()); exit(1); } } // end serviceMainFunction() static BOOL breakHandler( IN ULONG ulType) { extern HANDLE gsd; UNREFERENCED_PARAMETER(ulType); SNMPDBG((SNMP_LOG_TRACE, "SNMP: SVC: break intercepted, cleaning up...\n")); if (!CloseHandle(gsd)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: SVC: error on CloseHandle %d\n", GetLastError())); //not serious error. } return FALSE; } // end breakHandler() // to simulate service controller functionality when testing as a process static BOOL StartServiceCtrlLocalDispatcher(LPSERVICE_TABLE_ENTRY junk) { DWORD p1=0; LPSTR *p2=NULL; (*(junk->lpServiceProc))(p1, p2); return TRUE; } // end StartServiceCtrlDispatcher() #ifndef CHICAGO //--------------------------- PUBLIC PROCEDURES ----------------------------- //---- Win95's WinMain and NT's main are mutually exclusive routines--------- INT _CRTAPI1 main( IN int argc, //argument count IN char *argv[]) //argument vector { static SERVICE_TABLE_ENTRY serviceStartTable[2] = {{"SNMP", serviceMainFunction}, {NULL, NULL}}; OSVERSIONINFO OsInfo; UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&OsInfo)) exit(1); switch (OsInfo.dwPlatformId) { case VER_PLATFORM_WIN32_NT: noservice = FALSE; platformId = VER_PLATFORM_WIN32_NT; SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: platform is Windows NT.\n")); break; case VER_PLATFORM_WIN32_WINDOWS: noservice = TRUE; platformId = VER_PLATFORM_WIN32_WINDOWS; SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: platform in Windows 95.\n")); break; default: SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: unsupported platform 0x%x.\n", OsInfo.dwPlatformId)); SnmpSvcReportEvent(SNMP_EVENT_INVALID_PLATFORM_ID, 0, NULL, NO_ERROR); exit(1); } tryagain: if (noservice) { // intercept ctrl-c and ctrl-break to allow cleanup to be done if (!SetConsoleCtrlHandler(breakHandler, TRUE)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on SetConsoleCtrlHandler %d\n", GetLastError())); //not serious error. } } SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: service starting...\n")); //start service control dispatcher if (noservice) { if (!StartServiceCtrlLocalDispatcher(serviceStartTable)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on StartServiceCtrlDispatch %d\n", GetLastError())); exit(1); } } else { if (!StartServiceCtrlDispatcher(serviceStartTable)) { if (GetLastError() == 1063) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: retry with local service control dispatcher.\n")); noservice = TRUE; goto tryagain; } SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on StartServiceCtrlDispatch %d\n", GetLastError())); exit(1); } } // above function will not return until running service(s) terminate SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: service terminated.\n")); return 0; } // end main() //-------------------------------- END NT Specific ------------------------------- #else //------------------------------ Begin Win95 Specific ----------------------------- LRESULT CALLBACK WndProc( HWND hWnd, // window handle UINT message, // type of message WPARAM uParam, // additional information LPARAM lParam); // additional information #define SNMP_AGENT_EVENT "SNMP.Agent.Event" HINSTANCE hInst; // current instance char szAppName[64]; // The name of this application char szTitle[32]; // The title bar text char szHelpStr[32]; // Help flag "Help" char szQuestStr[32];// Abriev. Help Flag "?" char szCloseStr[32];// Close flag "close" char szDestroyStr[32]; //Destroy flag "destroy" char szHelpText1[256]; //Help String char szHelpText2[64]; //Help String char szHelpText3[128]; //Help String HWND hWnd; // Main window handle. BOOL InitApplication(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE hInstance, int nCmdShow); BOOL GetStrings(HINSTANCE hInstance); //int APIENTRY WinMain INT APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HANDLE SnmpAgentEvent, hThread, hKernel32 = NULL; DWORD threadId, LastError; BOOL fKillParent = FALSE, fRegSrvcProc = FALSE; FARPROC pRegSrvcProc; extern HANDLE hExitTrapThreadEvent; LPCSTR event_name = SNMP_AGENT_EVENT; DWORD err; if ((WinVersion = (GetVersion() & 0x000000ff)) == 0x04) { if ((hKernel32 = GetModuleHandle("kernel32.dll")) == NULL) { // This should never happen but we'll try and load the library anyway if ((hKernel32 = LoadLibrary("kernel32.dll")) == NULL) fRegSrvcProc = FALSE; } if (hKernel32) { if ((pRegSrvcProc = GetProcAddress(hKernel32,"RegisterServiceProcess")) == NULL) fRegSrvcProc = FALSE; else fRegSrvcProc = TRUE; } } else fRegSrvcProc = FALSE; // // Other instances of regserv running? // SnmpAgentEvent = OpenEvent(SYNCHRONIZE, FALSE, event_name); if (SnmpAgentEvent == NULL) { if ( (SnmpAgentEvent = CreateEvent(NULL, FALSE, TRUE, event_name)) == NULL) { LastError = GetLastError(); SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: Create Event Failed w/ %d\n", LastError)); return 1; } } else { SnmpAgentEvent = NULL; // another instance is running. } if (!GetStrings(hInstance)) { return 1; } platformId = VER_PLATFORM_WIN32_WINDOWS; // we are not on NT... is our command line setup to kill the parent? if ( ( lpCmdLine[0]=='-') || ( lpCmdLine[0]=='/') ) { // is it CLOSE or DESTROY?? if ( _strnicmp ( &lpCmdLine[1], szCloseStr, strlen(szCloseStr) ) ==0 ) fKillParent = TRUE; else if ( _strnicmp ( &lpCmdLine[1], szDestroyStr, strlen(szDestroyStr) ) ==0 ) fKillParent = TRUE; else if (( _strnicmp ( &lpCmdLine[1], szHelpStr, strlen(szHelpStr) )==0 )|| ( _strnicmp ( &lpCmdLine[1], szQuestStr, strlen(szQuestStr) )==0 )) { // they have asked for help... MessageBox (GetTopWindow(GetDesktopWindow()), szHelpText1, szHelpText2, MB_OK ); return 0; } } if ((hPrevInstance) || (SnmpAgentEvent == NULL)) { SNMPDBG((SNMP_LOG_ERROR,"SNMP: INIT: service already running\n")); if (!fKillParent) // if we are not killing the parent, only one agent at a time... { HANDLE hParentWin = GetTopWindow(GetDesktopWindow()); MessageBox (hParentWin, szHelpText3, szHelpText2, MB_OK ); return 1; } if (hPrevInstance == NULL) if ( (hPrevInstance = FindWindow(szAppName,NULL)) == NULL) return 1; // else send our parent a die message... PostMessage ( hPrevInstance, WM_CLOSE, 0,0 ); return 0; } if (fKillParent) // no parent to kill return 2; if(!InitApplication(hInstance)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: Unable to register window class\n")); return (FALSE); } if (!InitInstance(hInstance, SW_HIDE)) { // ignore nCmdShow SNMPDBG((SNMP_LOG_ERROR,"SNMP: INIT: Unable to create main window\n")); return (FALSE); } noservice = TRUE; if ((hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)serviceMainFunction, NULL, 0, &threadId)) == 0) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error %d creating main service thread.\n", GetLastError())); } else { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: created serviceMainFunction tid=0x%lx.\n", threadId)); } if (fRegSrvcProc) (*pRegSrvcProc)(GetCurrentProcessId(), RSP_SIMPLE_SERVICE); // Acquire and dispatch messages until a WM_QUIT message is received. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // Translates virtual key codes DispatchMessage(&msg); // Dispatches message to window } if (fRegSrvcProc) (*pRegSrvcProc)(GetCurrentProcessId(), RSP_UNREGISTER_SERVICE); // set event causing trap thread to terminate, followed by comm thread if (!SetEvent(hExitTrapThreadEvent)) { SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: error on SetEvent %d\n", GetLastError())); } SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: SNMP Service exiting 0\n")); return(0); UNREFERENCED_PARAMETER(lpCmdLine); } // // GetStrings - retrieves resource strings from exe // BOOL GetStrings(HINSTANCE hInstance) { DWORD err, LastError; if ((err = LoadString(hInstance, IDS_TITLE_BAR, szTitle, sizeof(szTitle))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_APP_NAME, szAppName, sizeof(szAppName))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_HELP_STRING, szHelpStr, sizeof(szHelpStr))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_QUEST_STRING, szQuestStr, sizeof(szQuestStr))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_CLOSE_STRING, szCloseStr, sizeof(szCloseStr))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_DESTROY_STRING, szDestroyStr, sizeof(szDestroyStr))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_HELP_TEXT1, szHelpText1, sizeof(szHelpText1))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_HELP_TEXT2, szHelpText2, sizeof(szHelpText2))) == 0) { goto ErrorExit; } if ((err = LoadString(hInstance, IDS_HELP_TEXT3, szHelpText3, sizeof(szHelpText3))) == 0) { goto ErrorExit; } return TRUE; ErrorExit: LastError = GetLastError(); SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: LoadString Failed w/ %d\n", LastError)); return FALSE; } // // InitInstance - save instance handle and create main window // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { // Save the instance handle in static variable, which will be used in // many subsequence calls from this application to Windows. hInst = hInstance; // Store instance handle in our global variable // Create a main window for this application instance. hWnd = CreateWindow( szAppName, szTitle, WS_EX_TRANSPARENT, // Window style. 0, 0, CW_USEDEFAULT, CW_USEDEFAULT, // Use default positioning CW_USEDEAULT NULL, // Overlapped windows have no parent. NULL, // Use the window class menu. hInstance, // This instance owns this window. NULL // We don't use any data in our WM_CREATE ); // If window could not be created, return "failure" if (!hWnd) { return (FALSE); } // Make the window visible; update its client area; and return "success" ShowWindow(hWnd, nCmdShow); // Show the window UpdateWindow(hWnd); // Sends WM_PAINT message return (TRUE); // We succeeded... } // // InitApplication - initialize window data and register window class // // Return - NULL => failure // BOOL InitApplication(HINSTANCE hInstance) { WNDCLASS wc; DWORD LastError; // Fill in window class structure with parameters that describe the // main window. wc.style = CS_HREDRAW | CS_VREDRAW;// Class style(s). wc.lpfnWndProc = (WNDPROC)WndProc; // Window Procedure wc.cbClsExtra = 0; // No per-class extra data. wc.cbWndExtra = 0; // No per-window extra data. wc.hInstance = hInstance; // Owner of this class wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);// Default color wc.lpszMenuName = szAppName; // Menu name from .RC wc.lpszClassName = szAppName; // Name to register as // Register the window class and return success/failure code. if (!RegisterClass(&wc)) { LastError = GetLastError(); SNMPDBG((SNMP_LOG_ERROR, "SNMP: INIT: RegisterClass failed w/ %d\n", LastError )); return FALSE; } else return TRUE; } // // WndProc - process messages // LRESULT CALLBACK WndProc( HWND hWnd, // window handle UINT message, // type of message WPARAM uParam, // additional information LPARAM lParam) // additional information { switch (message) { case WM_ENDSESSION: case WM_QUERYENDSESSION: if (lParam == 0) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: Received shutdown message\n")); } if (lParam == 1 ) //EWX_REALLYLOGOFF { SNMPDBG((SNMP_LOG_TRACE, "SNMP: INIT: Received logoff message\n")); } return(1); case WM_DESTROY: // message: window being destroyed PostQuitMessage(0); return(0); default: // Pass it on if unproccessed return (DefWindowProc(hWnd, message, uParam, lParam)); } } #endif