server/windows/USBEventSvc/OpenSecUSBEventSvc/OpenSecUSBEventSvc.cpp
changeset 7 903480cebdfb
child 9 50b1cfe9576b
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/server/windows/USBEventSvc/OpenSecUSBEventSvc/OpenSecUSBEventSvc.cpp	Tue Dec 03 18:04:46 2013 +0100
     1.3 @@ -0,0 +1,399 @@
     1.4 +#include <InitGuid.h>
     1.5 +#include <Windows.h>
     1.6 +#include <SetupApi.h>
     1.7 +
     1.8 +#include <tchar.h>
     1.9 +#include <strsafe.h>
    1.10 +#include <dbt.h>
    1.11 +#include <usbiodef.h>
    1.12 +#include <Winhttp.h>
    1.13 +#include "OpenSecUSBEventSvcLog.h"
    1.14 +
    1.15 +#pragma comment(lib, "advapi32.lib")
    1.16 +
    1.17 +#define SVCNAME TEXT("OpenSecUSBEventSvc")
    1.18 +
    1.19 +//sc create "USBEventSvc" binPath= "C:\Users\BarthaM\Documents\Visual Studio 2010\Projects\USBEventSvc\Debug\USBEventSvc.exe"
    1.20 +//sc delete "USBEventSvc"
    1.21 +
    1.22 +// USB Raw Device Interface Class GUID
    1.23 +//{ 0xa5dcbf10, 0x6530, 0x11d2, { 0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51,0xed } }
    1.24 +// Disk Device Interface Class GUID
    1.25 +//{ 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } }
    1.26 +
    1.27 +// This GUID is for all USB serial host PnP drivers
    1.28 +//GUID WceusbshGUID = { 0x25dbce51, 0x6c8f, 0x4a72, 0x8a, 0x6d, 0xb5, 0x4c, 0x2b, 0x4f, 0xc8, 0x35 };
    1.29 +
    1.30 +GUID WceusbshGUID = { 0x88bae032, 0x5a81, 0x49f0, 0xbc, 0x3d, 0xa4, 0xff, 0x13, 0x82, 0x16, 0xd6 };
    1.31 +//DEFINE_GUID(GUID_CLASS_STORAGE_VOLUME, 0x53F5630DL, 0xB6BF, 0x11D0, 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B);
    1.32 +
    1.33 +
    1.34 +SERVICE_STATUS          gSvcStatus;
    1.35 +SERVICE_STATUS_HANDLE   gSvcStatusHandle = NULL;
    1.36 +HANDLE                  ghSvcStopEvent = NULL;
    1.37 +HDEVNOTIFY				ghDeviceNotify;
    1.38 +
    1.39 +DWORD WINAPI ServiceWorkerThread(LPVOID lpParam);
    1.40 +
    1.41 +VOID SvcInstall(void);
    1.42 +VOID WINAPI SvcCtrlHandler(DWORD);
    1.43 +VOID WINAPI SvcMain(DWORD, LPTSTR *);
    1.44 +
    1.45 +VOID ReportSvcStatus(DWORD, DWORD, DWORD);
    1.46 +VOID SvcInit(DWORD, LPTSTR *);
    1.47 +VOID SvcReportEvent(WORD, LPTSTR);
    1.48 +
    1.49 +
    1.50 +// DoRegisterDeviceInterfaceToHwnd
    1.51 +//     Registers an HWND for notification of changes in the device interfaces
    1.52 +//     for the specified interface class GUID. 
    1.53 +// Parameters:
    1.54 +//     InterfaceClassGuid - The interface class GUID for the device 
    1.55 +//         interfaces. 
    1.56 +//     hWnd - Window handle to receive notifications.
    1.57 +//     hDeviceNotify - Receives the device notification handle. On failure, 
    1.58 +//         this value is NULL.
    1.59 +// Return Value:
    1.60 +//     If the function succeeds, the return value is TRUE.
    1.61 +//     If the function fails, the return value is FALSE.
    1.62 +// Note:
    1.63 +//     RegisterDeviceNotification also allows a service handle be used,
    1.64 +//     so a similar wrapper function to this one supporting that scenario
    1.65 +//     could be made from this template.
    1.66 +
    1.67 +BOOL DoRegisterDeviceInterfaceToHwnd(void) {
    1.68 +	DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
    1.69 +	ZeroMemory(&NotificationFilter, sizeof (NotificationFilter));
    1.70 +	NotificationFilter.dbcc_size = sizeof (DEV_BROADCAST_DEVICEINTERFACE);
    1.71 +	NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
    1.72 +	NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
    1.73 +	memcpy(&(NotificationFilter.dbcc_classguid), &(GUID_DEVINTERFACE_USB_DEVICE), sizeof(struct _GUID));
    1.74 +
    1.75 +	ghDeviceNotify = RegisterDeviceNotification(gSvcStatusHandle,
    1.76 +		&NotificationFilter, 
    1.77 +		DEVICE_NOTIFY_SERVICE_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
    1.78 +
    1.79 +	if (NULL == ghDeviceNotify) {
    1.80 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, _T("RegisterDeviceNotification failed!"));
    1.81 +		return FALSE;
    1.82 +	}
    1.83 +	return TRUE;
    1.84 +}
    1.85 +
    1.86 +//
    1.87 +// Purpose: 
    1.88 +//   Entry point for the process
    1.89 +//
    1.90 +// Parameters:
    1.91 +//   None
    1.92 +// 
    1.93 +// Return value:
    1.94 +//   None
    1.95 +//
    1.96 +void __cdecl _tmain(int argc, TCHAR *argv[]) {
    1.97 +	// If command-line parameter is "install", install the service. 
    1.98 +	// Otherwise, the service is probably being started by the SCM.
    1.99 +	if (lstrcmpi(argv[1], TEXT("install")) == 0){
   1.100 +		SvcInstall();
   1.101 +		return;
   1.102 +	}
   1.103 +
   1.104 +	// TO_DO: Add any additional services for the process to this table.
   1.105 +	SERVICE_TABLE_ENTRY DispatchTable[] = {
   1.106 +		{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
   1.107 +		{ NULL, NULL }
   1.108 +	};
   1.109 +
   1.110 +	// This call returns when the service has stopped. 
   1.111 +	// The process should simply terminate when the call returns.
   1.112 +	if (!StartServiceCtrlDispatcher(DispatchTable)) {
   1.113 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("StartServiceCtrlDispatcher"));
   1.114 +	}
   1.115 +}
   1.116 +
   1.117 +// Purpose: 
   1.118 +//   Installs a service in the SCM database
   1.119 +//
   1.120 +// Parameters:
   1.121 +//   None
   1.122 +// 
   1.123 +// Return value:
   1.124 +//   None
   1.125 +//
   1.126 +VOID SvcInstall() {
   1.127 +	SC_HANDLE schSCManager;
   1.128 +	SC_HANDLE schService;
   1.129 +	TCHAR szPath[MAX_PATH];
   1.130 +
   1.131 +	if (!GetModuleFileName(NULL, szPath, MAX_PATH)) {
   1.132 +		printf("Cannot install service (%d)\n", GetLastError());
   1.133 +		return;
   1.134 +	}
   1.135 +
   1.136 +	// Get a handle to the SCM database. local computer, ServicesActive database, full access rights 
   1.137 +	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
   1.138 +	if (NULL == schSCManager) {
   1.139 +		printf("Open SCManager failed (%d)\n", GetLastError());
   1.140 +		return;
   1.141 +	}
   1.142 +
   1.143 +	// Create the service
   1.144 +	schService = CreateService(
   1.145 +		schSCManager,              // SCM database 
   1.146 +		SVCNAME,                   // name of service 
   1.147 +		SVCNAME,                   // service name to display 
   1.148 +		SERVICE_ALL_ACCESS,        // desired access 
   1.149 +		SERVICE_WIN32_OWN_PROCESS, // service type 
   1.150 +		SERVICE_DEMAND_START,      // start type 
   1.151 +		SERVICE_ERROR_NORMAL,      // error control type 
   1.152 +		szPath,                    // path to service's binary 
   1.153 +		NULL,                      // no load ordering group 
   1.154 +		NULL,                      // no tag identifier 
   1.155 +		NULL,                      // no dependencies 
   1.156 +		NULL,                      // LocalSystem account 
   1.157 +		NULL);                     // no password 
   1.158 +
   1.159 +	if (schService == NULL) {
   1.160 +		printf("CreateService failed (%d)\n", GetLastError());
   1.161 +		CloseServiceHandle(schSCManager);
   1.162 +		return;
   1.163 +	}
   1.164 +	else printf("Service installed successfully\n");
   1.165 +
   1.166 +	CloseServiceHandle(schService);
   1.167 +	CloseServiceHandle(schSCManager);
   1.168 +}
   1.169 +
   1.170 +//
   1.171 +// Purpose: 
   1.172 +//   Entry point for the service
   1.173 +//
   1.174 +// Parameters:
   1.175 +//   dwArgc - Number of arguments in the lpszArgv array
   1.176 +//   lpszArgv - Array of strings. The first string is the name of
   1.177 +//     the service and subsequent strings are passed by the process
   1.178 +//     that called the StartService function to start the service.
   1.179 +// 
   1.180 +// Return value:
   1.181 +//   None.
   1.182 +//
   1.183 +VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv) {
   1.184 +	// Register the handler function for the service
   1.185 +	gSvcStatusHandle = RegisterServiceCtrlHandlerEx(SVCNAME, (LPHANDLER_FUNCTION_EX)SvcCtrlHandler, 0);
   1.186 +	if (!gSvcStatusHandle) {
   1.187 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("RegisterServiceCtrlHandler"));
   1.188 +		return;
   1.189 +	}
   1.190 +
   1.191 +	// These SERVICE_STATUS members remain as set here
   1.192 +	gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
   1.193 +	gSvcStatus.dwServiceSpecificExitCode = 0;
   1.194 +
   1.195 +	// Report initial status to the SCM
   1.196 +	ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
   1.197 +
   1.198 +	if (!DoRegisterDeviceInterfaceToHwnd()) {
   1.199 +		// Terminate on failure.
   1.200 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("DoRegisterDeviceInterfaceToHwnd"));
   1.201 +		ExitProcess(1);
   1.202 +	}
   1.203 +	
   1.204 +	// default security attributes, manual reset, not signaled, no name
   1.205 +	ghSvcStopEvent = CreateEvent(NULL, TRUE, FALSE,	NULL);
   1.206 +	if (ghSvcStopEvent == NULL) {
   1.207 +		ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
   1.208 +		return;
   1.209 +	}
   1.210 +
   1.211 +	// Report running status when initialization is complete.
   1.212 +	ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
   1.213 +	SvcReportEvent(EVENTLOG_INFORMATION_TYPE, TEXT("OpenSecUSBEventSvc is running"));
   1.214 +
   1.215 +	// Wait until our worker thread exits signaling that the service needs to stop
   1.216 +	WaitForSingleObject(ghSvcStopEvent, INFINITE);
   1.217 +	
   1.218 +	SvcReportEvent(EVENTLOG_INFORMATION_TYPE, TEXT("OpenSecUSBEventSvc is exiting"));
   1.219 +	// Perform any cleanup tasks
   1.220 +	CloseHandle(ghSvcStopEvent);
   1.221 +
   1.222 +	// Report running status when initialization is complete.
   1.223 +	ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
   1.224 +}
   1.225 +
   1.226 +void NotifyOpenSecManager (void) {
   1.227 +	HINTERNET	hSession = NULL,
   1.228 +				hConnect = NULL,
   1.229 +				hRequest = NULL;
   1.230 +	BOOL		bResults = FALSE;
   1.231 +
   1.232 +	//devices_json = url_encode(devices_json);
   1.233 +	// Use WinHttpOpen to obtain a session handle.
   1.234 +	hSession = WinHttpOpen(L"OpenSecUSBEventSvc", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
   1.235 +	if (!hSession) {
   1.236 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("Error notifying the OpenSec manager. WinHttpOpen failed! "));
   1.237 +		return;
   1.238 +	}
   1.239 +	// Specify an HTTP server.
   1.240 +	hConnect = WinHttpConnect(hSession, L"localhost", 8080, 0);
   1.241 +	if (!hConnect) {
   1.242 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("Error notifying the OpenSec manager. WinHttpConnect failed! "));
   1.243 +		return;
   1.244 +	}
   1.245 +
   1.246 +	// Create an HTTP request handle.
   1.247 +	hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/device_change", NULL, WINHTTP_NO_REFERER, NULL, NULL);
   1.248 +	if(!hRequest) {
   1.249 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("Error notifying the OpenSec manager. WinHttpOpenRequest failed! "));
   1.250 +		return;
   1.251 +	}
   1.252 +
   1.253 +	// Send a request.
   1.254 +	bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
   1.255 +	if (!bResults) {
   1.256 +		SvcReportEvent(EVENTLOG_ERROR_TYPE, TEXT("Error notifying the OpenSec manager. WinHttpSendRequest failed! "));
   1.257 +		return;
   1.258 +	}
   1.259 +
   1.260 +	// End the request.
   1.261 +	//if (bResults)
   1.262 +	//	bResults = WinHttpReceiveResponse(hRequest, NULL);
   1.263 +
   1.264 +	//DWORD dwSize = 0;
   1.265 +	//LPVOID lpOutBuffer = NULL;
   1.266 +	//if (bResults) {
   1.267 +	//	WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, NULL, &dwSize, WINHTTP_NO_HEADER_INDEX);
   1.268 +	//	// Allocate memory for the buffer.
   1.269 +	//	if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
   1.270 +	//		lpOutBuffer = new WCHAR[dwSize / sizeof(WCHAR)];
   1.271 +	//		// Now, use WinHttpQueryHeaders to retrieve the header.
   1.272 +	//		bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, WINHTTP_HEADER_NAME_BY_INDEX, lpOutBuffer, &dwSize, WINHTTP_NO_HEADER_INDEX);
   1.273 +	//	}
   1.274 +	//}
   1.275 +	//// Print the header contents.
   1.276 +	//if (bResults)
   1.277 +	//	printf("Header contents: \n%S", lpOutBuffer);
   1.278 +	//// Free the allocated memory.
   1.279 +	//delete [] lpOutBuffer;
   1.280 +
   1.281 +}
   1.282 +
   1.283 +//
   1.284 +// Purpose: 
   1.285 +//   Sets the current service status and reports it to the SCM.
   1.286 +//
   1.287 +// Parameters:
   1.288 +//   dwCurrentState - The current state (see SERVICE_STATUS)
   1.289 +//   dwWin32ExitCode - The system error code
   1.290 +//   dwWaitHint - Estimated time for pending operation, 
   1.291 +//     in milliseconds
   1.292 +// 
   1.293 +// Return value:
   1.294 +//   None
   1.295 +//
   1.296 +VOID ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) {
   1.297 +	static DWORD dwCheckPoint = 1;
   1.298 +	// Fill in the SERVICE_STATUS structure.
   1.299 +	gSvcStatus.dwCurrentState = dwCurrentState;
   1.300 +	gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
   1.301 +	gSvcStatus.dwWaitHint = dwWaitHint;
   1.302 +
   1.303 +	if (dwCurrentState == SERVICE_START_PENDING)
   1.304 +		gSvcStatus.dwControlsAccepted = 0;
   1.305 +	else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
   1.306 +
   1.307 +	if ((dwCurrentState == SERVICE_RUNNING) ||
   1.308 +		(dwCurrentState == SERVICE_STOPPED))
   1.309 +		gSvcStatus.dwCheckPoint = 0;
   1.310 +	else gSvcStatus.dwCheckPoint = dwCheckPoint++;
   1.311 +
   1.312 +	// Report the status of the service to the SCM.
   1.313 +	SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
   1.314 +}
   1.315 +
   1.316 +// Purpose: 
   1.317 +//   Called by SCM whenever a control code is sent to the service
   1.318 +//   using the ControlService function.
   1.319 +//
   1.320 +// Parameters:
   1.321 +//   dwCtrl - control code
   1.322 +// 
   1.323 +// Return value:
   1.324 +//   None
   1.325 +//
   1.326 +VOID WINAPI SvcCtrlHandler(DWORD dwCtrl) {
   1.327 +	// Handle the requested control code. 
   1.328 +	switch (dwCtrl) {
   1.329 +		case SERVICE_CONTROL_STOP:
   1.330 +			UnregisterDeviceNotification(ghDeviceNotify);
   1.331 +			ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
   1.332 +			// Signal the service to stop.
   1.333 +			SetEvent(ghSvcStopEvent);
   1.334 +			ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
   1.335 +			return;
   1.336 +
   1.337 +		case SERVICE_CONTROL_INTERROGATE:
   1.338 +			break;
   1.339 +
   1.340 +		case SERVICE_CONTROL_DEVICEEVENT:
   1.341 +			SvcReportEvent(EVENTLOG_INFORMATION_TYPE, _T("Received SERVICE_CONTROL_DEVICEEVENT"));
   1.342 +			//NotifyOpenSecManager();
   1.343 +			break;
   1.344 +
   1.345 +		default:
   1.346 +			break;
   1.347 +	}
   1.348 +}
   1.349 +
   1.350 +//
   1.351 +// Purpose: 
   1.352 +//   Logs messages to the event log
   1.353 +//
   1.354 +// Parameters:
   1.355 +//   szFunction - name of function that failed
   1.356 +// 
   1.357 +// Return value:
   1.358 +//   None
   1.359 +//
   1.360 +// Remarks:
   1.361 +//   The service must have an entry in the Application event log.
   1.362 +//
   1.363 +VOID SvcReportEvent(WORD type, LPTSTR szFunction) {
   1.364 +	HANDLE hEventSource;
   1.365 +	LPCTSTR lpszStrings[2];
   1.366 +	TCHAR Buffer[80];
   1.367 +
   1.368 +	hEventSource = RegisterEventSource(NULL, SVCNAME);
   1.369 +
   1.370 +	if (NULL != hEventSource) {
   1.371 +		if (type == EVENTLOG_ERROR_TYPE)
   1.372 +			StringCchPrintf(Buffer, 80, TEXT("Error has occured. %s failed with %d"), szFunction, GetLastError());
   1.373 +		else
   1.374 +			StringCchPrintf(Buffer, 80, TEXT("%s"), szFunction);
   1.375 +
   1.376 +		lpszStrings[0] = SVCNAME;
   1.377 +		lpszStrings[1] = Buffer;
   1.378 +
   1.379 +		if (type == EVENTLOG_ERROR_TYPE)
   1.380 +			ReportEvent(hEventSource,       
   1.381 +				type, // event type
   1.382 +				0,                   // event category
   1.383 +				SVC_ERROR,           // event identifier
   1.384 +				NULL,                // no security identifier
   1.385 +				2,                   // size of lpszStrings array
   1.386 +				0,                   // no binary data
   1.387 +				lpszStrings,         // array of strings
   1.388 +				NULL);               // no binary data
   1.389 +		else
   1.390 +			ReportEvent(hEventSource,
   1.391 +				type, // event type
   1.392 +				0,                   // event category
   1.393 +				SVC_ERROR,		     // event identifier
   1.394 +				NULL,                // no security identifier
   1.395 +				2,                   // size of lpszStrings array
   1.396 +				0,                   // no binary data
   1.397 +				lpszStrings,         // array of strings
   1.398 +				NULL);               // no binary data
   1.399 +
   1.400 +		DeregisterEventSource(hEventSource);
   1.401 +	}
   1.402 +}