/** * Obtain registry string (if it exists). * @param key: key string * @param name: name of value to fetch. * @return malloced string with the result or NULL if it did not * exist on an error (logged) was encountered. */ static char* lookup_reg_str(const char* key, const char* name) { HKEY hk = NULL; DWORD type = 0; BYTE buf[1024]; DWORD len = (DWORD)sizeof(buf); LONG ret; char* result = NULL; ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk); if(ret == ERROR_FILE_NOT_FOUND) return NULL; /* key does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegOpenKeyEx failed"); return NULL; } ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len); if(RegCloseKey(hk)) reportev("RegCloseKey"); if(ret == ERROR_FILE_NOT_FOUND) return NULL; /* name does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegQueryValueEx failed"); return NULL; } if(type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ) { buf[sizeof(buf)-1] = 0; buf[sizeof(buf)-2] = 0; /* for multi_sz */ result = strdup((char*)buf); if(!result) reportev("out of memory"); } return result; }
/** * Obtain registry binary data (if it exists). * @param key: key string * @param name: name of value to fetch. * @param len: (returned value on success) length of the binary data. * @return malloced binary data with the result or NULL if it did not * exist on an error (logged) was encountered. */ uint8_t* lookup_reg_binary(const char* key, const char* name, size_t* retlen) { HKEY hk = NULL; DWORD type = 0; BYTE buf[10240]; DWORD len = (DWORD)sizeof(buf); LONG ret; uint8_t* result = NULL; ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk); if(ret == ERROR_FILE_NOT_FOUND) return NULL; /* key does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegOpenKeyEx failed"); return NULL; } ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len); if(RegCloseKey(hk)) reportev("RegCloseKey"); if(ret == ERROR_FILE_NOT_FOUND) return NULL; /* name does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegQueryValueEx failed"); return NULL; } if(type == REG_BINARY) { result = memdup(buf, len); *retlen = len; if(!result) reportev("out of memory"); } return result; }
/** * The main function for the service. * Called by the services API when starting on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct cfg* cfg = NULL; struct svr* svr = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(&svr, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } wsvc_setup_worker(svr->base); /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* register DHCP hook and perform first sweep */ netlist_start(svr); /* daemon performs work */ svr_service(svr); /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); netlist_stop(); wsvc_desetup_worker(); service_deinit(svr, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }
/** * Obtain registry integer (if it exists). * @param key: key string * @param name: name of value to fetch. * @return integer value (if it exists), or 0 on error. */ static int lookup_reg_int(const char* key, const char* name) { HKEY hk = NULL; DWORD type = 0; BYTE buf[1024]; DWORD len = (DWORD)sizeof(buf); LONG ret; int result = 0; ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk); if(ret == ERROR_FILE_NOT_FOUND) return 0; /* key does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegOpenKeyEx failed"); return 0; } ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len); if(RegCloseKey(hk)) reportev("RegCloseKey"); if(ret == ERROR_FILE_NOT_FOUND) return 0; /* name does not exist */ else if(ret != ERROR_SUCCESS) { reportev("RegQueryValueEx failed"); return 0; } if(type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ) { buf[sizeof(buf)-1] = 0; buf[sizeof(buf)-2] = 0; /* for multi_sz */ result = atoi((char*)buf); } else if(type == REG_DWORD) { DWORD r; memmove(&r, buf, sizeof(r)); result = r; } return result; }
/** start the service */ static void service_start(const char* cfgfile, int v, int c) { SERVICE_TABLE_ENTRY myservices[2] = { {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, {NULL, NULL} }; verbosity=v; if(verbosity >= VERB_QUERY) { /* log to file about start sequence */ fclose(fopen("C:\\unbound.log", "w")); log_init("C:\\unbound.log", 0, 0); verbose(VERB_QUERY, "open logfile"); } else log_init(0, 1, 0); /* otherwise, use Application log */ if(c) { service_cfgfile = strdup(cfgfile); if(!service_cfgfile) fatal_exit("out of memory"); } else service_cfgfile = NULL; service_cmdline_verbose = v; /* this call returns when service has stopped. */ if(!StartServiceCtrlDispatcher(myservices)) { reportev("Could not StartServiceCtrlDispatcher"); } }
/** * The main function for the service. * Called by the services API when starting unbound on windows in background. * Arguments could have been present in the string 'path'. * @param argc: nr args * @param argv: arg text. */ static void service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { reportev("Could not RegisterServiceCtrlHandler"); return; } service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_status.dwServiceSpecificExitCode = 0; /* see if we have root anchor update enabled */ call_root_update(); /* we are now starting up */ report_status(SERVICE_START_PENDING, NO_ERROR, 3000); if(!service_init(0, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } /* event that gets signalled when we want to quit; it * should get registered in the worker-0 waiting loop. */ service_stop_event = WSACreateEvent(); if(service_stop_event == WSA_INVALID_EVENT) { log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError())); reportev("Could not WSACreateEvent"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } if(!WSAResetEvent(service_stop_event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } /* SetServiceStatus SERVICE_RUNNING;*/ report_status(SERVICE_RUNNING, NO_ERROR, 0); verbose(VERB_QUERY, "winservice - init complete"); /* daemon performs work */ while(!service_stop_shutdown) { daemon_fork(daemon); if(!service_stop_shutdown) { daemon_cleanup(daemon); config_delete(cfg); cfg=NULL; if(!service_init(1, &daemon, &cfg)) { reportev("Could not service_init"); report_status(SERVICE_STOPPED, NO_ERROR, 0); return; } } } /* exit */ verbose(VERB_ALGO, "winservice - cleanup."); report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); service_deinit(daemon, cfg); free(service_cfgfile); if(service_stop_event) (void)WSACloseEvent(service_stop_event); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); }