aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/win32-service.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/win32-service.c')
-rw-r--r--framework/src/suricata/src/win32-service.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/framework/src/suricata/src/win32-service.c b/framework/src/suricata/src/win32-service.c
new file mode 100644
index 00000000..257447e5
--- /dev/null
+++ b/framework/src/suricata/src/win32-service.c
@@ -0,0 +1,394 @@
+/* Copyright (C) 2007-2010 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Ondrej Slanina <oslanina@kerio.com>
+ *
+ * Windows service functions
+ */
+
+#ifdef OS_WIN32
+
+#include "suricata-common.h"
+#include "suricata.h"
+#include "win32-service.h"
+
+static SERVICE_STATUS_HANDLE service_status_handle = 0;
+
+static int service_argc = 0;
+
+static char **service_argv = NULL;
+
+static int service_initialized = 0;
+
+int main(int argc, char **argv);
+
+/**
+ * \brief Detect if running as service or console app
+ */
+int SCRunningAsService(void)
+{
+ HANDLE h = INVALID_HANDLE_VALUE;
+ if ((h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
+ SCLogInfo("Running as service: yes");
+ return 1;
+ }
+ CloseHandle(h);
+ SCLogInfo("Running as service: no");
+ return 0;
+}
+
+/**
+ * \brief Detect if running as service or console app
+ */
+void SCAtExitHandler(void)
+{
+ SERVICE_STATUS status = {
+ SERVICE_WIN32,
+ SERVICE_STOPPED,
+ SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
+ NO_ERROR,
+ NO_ERROR,
+ 0,
+ 0
+ };
+
+ SCLogInfo("Exit handler called.");
+
+ /* mark service as stopped */
+ if (!SetServiceStatus(service_status_handle, &status)) {
+ SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
+ } else {
+ SCLogInfo("Service status set to: SERVICE_STOPPED");
+ }
+}
+
+/**
+ * \brief Service handler
+ */
+static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata, LPVOID context)
+{
+ if (code == SERVICE_CONTROL_SHUTDOWN || code == SERVICE_CONTROL_STOP) {
+ SERVICE_STATUS status = {
+ SERVICE_WIN32,
+ SERVICE_STOP_PENDING,
+ SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
+ NO_ERROR,
+ NO_ERROR,
+ 0,
+ 0
+ };
+
+ SCLogInfo("Service control handler called with %s control code.",
+ ((code == SERVICE_CONTROL_SHUTDOWN) ? ("SERVICE_CONTROL_SHUTDOWN") : ("SERVICE_CONTROL_STOP")));
+
+ /* mark service as stop pending */
+ if (!SetServiceStatus(service_status_handle, &status)) {
+ SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
+ } else {
+ SCLogInfo("Service status set to: SERVICE_STOP_PENDING");
+ }
+
+ /* mark engine as stopping */
+ EngineStop();
+
+ return NO_ERROR;
+ }
+
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/**
+ * \brief Service main function
+ */
+static void WINAPI SCServiceMain(uint32_t argc, char** argv)
+{
+ SERVICE_STATUS status = {
+ SERVICE_WIN32,
+ SERVICE_RUNNING,
+ SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
+ NO_ERROR,
+ NO_ERROR,
+ 0,
+ 0
+ };
+
+ if ((service_status_handle = RegisterServiceCtrlHandlerEx(PROG_NAME, SCServiceCtrlHandlerEx, NULL)) == (SERVICE_STATUS_HANDLE)0) {
+ SCLogError(SC_ERR_SVC, "Can't register service control handler: %d", (int)GetLastError());
+ return;
+ }
+
+ /* register exit handler */
+ if (atexit(SCAtExitHandler)) {
+ SCLogWarning(SC_ERR_SVC, "Can't register exit handler: %d", (int)GetLastError());
+ }
+
+ /* mark service as running immediately */
+ if (!SetServiceStatus(service_status_handle, &status)) {
+ SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
+ } else {
+ SCLogInfo("Service status set to: SERVICE_RUNNING");
+ }
+
+ SCLogInfo("Entering main function...");
+
+ /* suricata initialization -> main loop -> uninitialization */
+ main(service_argc, service_argv);
+
+ SCLogInfo("Leaving main function.");
+
+ /* mark service as stopped */
+ status.dwCurrentState = SERVICE_STOPPED;
+
+ if (!SetServiceStatus(service_status_handle, &status)) {
+ SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
+ } else {
+ SCLogInfo("Service status set to: SERVICE_STOPPED");
+ }
+}
+
+/**
+ * \brief Init suricata service
+ *
+ * \param argc num of arguments
+ * \param argv passed arguments
+ */
+int SCServiceInit(int argc, char **argv)
+{
+ SERVICE_TABLE_ENTRY DispatchTable[] = {
+ {PROG_NAME, (LPSERVICE_MAIN_FUNCTION) SCServiceMain},
+ {NULL, NULL}
+ };
+
+ /* continue with suricata initialization */
+ if (service_initialized) {
+ SCLogWarning(SC_ERR_SVC, "Service is already initialized.");
+ return 0;
+ }
+
+ /* save args */
+ service_argc = argc;
+ service_argv = argv;
+
+ service_initialized = 1;
+
+ SCLogInfo("Entering service control dispatcher...");
+
+ if (!StartServiceCtrlDispatcher(DispatchTable)) {
+ /* exit with failure */
+ exit(EXIT_FAILURE);
+ }
+
+ SCLogInfo("Leaving service control dispatcher.");
+
+ /* exit with success */
+ exit(EXIT_SUCCESS);
+}
+
+/**
+ * \brief Install suricata as service
+ *
+ * \param argc num of arguments
+ * \param argv passed arguments
+ */
+int SCServiceInstall(int argc, char **argv)
+{
+ char path[2048];
+ SC_HANDLE service = NULL;
+ SC_HANDLE scm = NULL;
+ int ret = -1;
+ int i = 0;
+
+ do {
+ memset(path, 0, sizeof(path));
+
+ if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){
+ SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError());
+ break;
+ }
+
+ /* skip name of binary itself */
+ for (i = 1; i < argc; i++) {
+ if ((strlen(argv[i]) <= strlen("--service-install")) && (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) {
+ continue;
+ }
+ strlcat(path, " ", sizeof(path) - strlen(path) - 1);
+ strlcat(path, argv[i], sizeof(path) - strlen(path) - 1);
+ }
+
+ if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
+ break;
+ }
+
+ service = CreateService(
+ scm,
+ PROG_NAME,
+ PROG_NAME,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (service == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't create service: %d", (int)GetLastError());
+ break;
+ }
+
+ ret = 0;
+
+ } while(0);
+
+ if (service) {
+ CloseServiceHandle(service);
+ }
+
+ if (scm) {
+ CloseServiceHandle(scm);
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Remove suricata service
+ *
+ * \param argc num of arguments
+ * \param argv passed arguments
+ */
+int SCServiceRemove(int argc, char **argv)
+{
+ SERVICE_STATUS status;
+ SC_HANDLE service = NULL;
+ SC_HANDLE scm = NULL;
+ int ret = -1;
+
+ do {
+ if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
+ break;
+ }
+
+ if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError());
+ break;
+ }
+
+ if (!QueryServiceStatus(service, &status)) {
+ SCLogError(SC_ERR_SVC, "Can't query service status: %d", (int)GetLastError());
+ break;
+ }
+
+ if (status.dwCurrentState != SERVICE_STOPPED) {
+ SCLogError(SC_ERR_SVC, "Service isn't in stopped state: %d", (int)GetLastError());
+ break;
+ }
+
+ if (!DeleteService(service)) {
+ SCLogError(SC_ERR_SVC, "Can't delete service: %d", (int)GetLastError());
+ break;
+ }
+
+ ret = 0;
+
+ } while(0);
+
+ if (service) {
+ CloseServiceHandle(service);
+ }
+
+ if (scm) {
+ CloseServiceHandle(scm);
+ }
+
+ return ret;
+}
+
+/**
+ * \brief Change suricata service startup parameters
+ *
+ * \param argc num of arguments
+ * \param argv passed arguments
+ */
+int SCServiceChangeParams(int argc, char **argv)
+{
+ char path[2048];
+ SC_HANDLE service = NULL;
+ SC_HANDLE scm = NULL;
+ int ret = -1;
+ int i = 0;
+
+ do {
+ memset(path, 0, sizeof(path));
+
+ if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){
+ SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError());
+ break;
+ }
+
+ /* skip name of binary itself */
+ for (i = 1; i < argc; i++) {
+ if ((strlen(argv[i]) <= strlen("--service-change-params")) && (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) {
+ continue;
+ }
+ strlcat(path, " ", sizeof(path) - strlen(path) - 1);
+ strlcat(path, argv[i], sizeof(path) - strlen(path) - 1);
+ }
+
+ if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
+ break;
+ }
+
+ if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) {
+ SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError());
+ break;
+ }
+
+ if (!ChangeServiceConfig(
+ service,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ path,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ PROG_NAME))
+ {
+ SCLogError(SC_ERR_SVC, "Can't change service configuration: %d", (int)GetLastError());
+ break;
+ }
+
+ ret = 0;
+
+ } while(0);
+
+ return ret;
+}
+
+#endif /* OS_WIN32 */