added possibility to run suricata as WIN32 service

remotes/origin/master-1.0.x
Ondrej Slanina 15 years ago committed by Victor Julien
parent cc76aa4bc6
commit 6bf7d76005

@ -202,6 +202,7 @@ app-layer-ssl.c app-layer-ssl.h \
defrag.c defrag.h \
output.c output.h \
win32-misc.c win32-misc.h \
win32-service.c win32-service.h \
util-action.c util-action.h \
win32-syslog.h \
util-profiling.c util-profiling.h

@ -64,6 +64,7 @@
#ifdef OS_WIN32
#include "win32-misc.h"
#include "win32-service.h"
#endif /* OS_WIN32 */
#if HAVE_CONFIG_H
#include <config.h>

@ -292,7 +292,13 @@ void usage(const char *progname)
#endif /* IPFW */
printf("\t-s <path> : path to signature file (optional)\n");
printf("\t-l <dir> : default log directory\n");
#ifndef OS_WIN32
printf("\t-D : run as daemon\n");
#else
printf("\t--service-install : install as service\n");
printf("\t--service-remove : remove service\n");
printf("\t--service-change-params : change service startup parameters\n");
#endif /* OS_WIN32 */
#ifdef UNITTESTS
printf("\t-u : run the unittests and exit\n");
printf("\t-U, --unittest-filter=REGEX : filter unittests with a regex\n");
@ -351,16 +357,34 @@ int main(int argc, char **argv)
sc_set_caps = FALSE;
/* initialize the logging subsys */
SCLogInitLogModule(NULL);
#ifdef OS_WIN32
/* service initialization */
if (SCRunningAsService()) {
char path[MAX_PATH];
char *p = NULL;
strlcpy(path, argv[0], MAX_PATH);
if ((p = strrchr(path, '\\'))) {
*p = '\0';
}
if (!SetCurrentDirectory(path)) {
SCLogError(SC_ERR_FATAL, "Can't set current directory to: %s", path);
return -1;
}
SCLogInfo("Current directory is set to: %s", path);
daemon = 1;
SCServiceInit(argc, argv);
}
/* Windows socket subsystem initialization */
WSADATA wsaData;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) {
fprintf(stderr, "ERROR: Failed to initialize Windows sockets.\n");
SCLogError(SC_ERR_FATAL, "Can't initialize Windows sockets: %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
#endif
/* initialize the logging subsys */
SCLogInitLogModule(NULL);
#endif /* OS_WIN32 */
SCLogInfo("This is %s version %s", PROG_NAME, PROG_VER);
@ -375,6 +399,11 @@ int main(int argc, char **argv)
{"pcap-buffer-size", required_argument, 0, 0},
{"unittest-filter", required_argument, 0, 'U'},
{"list-unittests", 0, &list_unittests, 1},
#ifdef OS_WIN32
{"service-install", 0, 0, 0},
{"service-remove", 0, 0, 0},
{"service-change-params", 0, 0, 0},
#endif /* OS_WIN32 */
{"pidfile", required_argument, 0, 0},
{"init-errors-fatal", 0, 0, 0},
{"fatal-unittests", 0, 0, 0},
@ -441,6 +470,29 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
#endif /* UNITTESTS */
}
#ifdef OS_WIN32
else if(strcmp((long_opts[option_index]).name, "service-install") == 0) {
if (SCServiceInstall(argc, argv)) {
exit(EXIT_FAILURE);
}
SCLogInfo("Suricata service has been successfuly installed.");
exit(EXIT_SUCCESS);
}
else if(strcmp((long_opts[option_index]).name, "service-remove") == 0) {
if (SCServiceRemove(argc, argv)) {
exit(EXIT_FAILURE);
}
SCLogInfo("Suricata service has been successfuly removed.");
exit(EXIT_SUCCESS);
}
else if(strcmp((long_opts[option_index]).name, "service-change-params") == 0) {
if (SCServiceChangeParams(argc, argv)) {
exit(EXIT_FAILURE);
}
SCLogInfo("Suricata service startup parameters has been successfuly changed.");
exit(EXIT_SUCCESS);
}
#endif /* OS_WIN32 */
else if(strcmp((long_opts[option_index]).name, "pidfile") == 0) {
pid_filename = optarg;
}
@ -494,9 +546,11 @@ int main(int argc, char **argv)
case 'c':
conf_filename = optarg;
break;
#ifndef OS_WIN32
case 'D':
daemon = 1;
break;
#endif /* OS_WIN32 */
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
@ -1111,6 +1165,10 @@ int main(int argc, char **argv)
* cuda contexts in any way */
SCCudaHlDeRegisterAllRegisteredModules();
#endif
#ifdef OS_WIN32
if (daemon) {
return 0;
}
#endif /* OS_WIN32 */
exit(EXIT_SUCCESS);
}

@ -180,6 +180,7 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_LIBCAP_NG_REQUIRED);
CASE_CODE (SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG);
CASE_CODE (SC_WARN_FLOW_EMERGENCY);
CASE_CODE (SC_ERR_SVC);
default:
return "UNKNOWN_ERROR";

@ -188,6 +188,7 @@ typedef enum {
SC_ERR_LIBCAP_NG_REQUIRED,
SC_ERR_LIBNET11_INCOMPATIBLE_WITH_LIBCAP_NG,
SC_WARN_FLOW_EMERGENCY,
SC_ERR_SVC,
SC_ERR_FATAL,
} SCError;

@ -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;
}
strncat(path, " ", sizeof(path) - strlen(path) - 1);
strncat(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;
}
strncat(path, " ", sizeof(path) - strlen(path) - 1);
strncat(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 */

@ -0,0 +1,35 @@
/* 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>
*/
#ifndef __WIN32_SERVICE_H__
#define __WIN32_SERVICE_H__
#ifdef OS_WIN32
int SCRunningAsService(void);
int SCServiceInit(int argc, char **argv);
int SCServiceInstall(int argc, char **argv);
int SCServiceRemove(int argc, char **argv);
int SCServiceChangeParams(int argc, char **argv);
#endif /* OS_WIN32 */
#endif
Loading…
Cancel
Save