]> git.ipfire.org Git - people/ms/suricata.git/blame - src/win32-service.c
core: Remove unneeded consts
[people/ms/suricata.git] / src / win32-service.c
CommitLineData
6bf7d760
OS
1/* Copyright (C) 2007-2010 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Ondrej Slanina <oslanina@kerio.com>
22 *
23 * Windows service functions
24 */
25
26#ifdef OS_WIN32
27
28#include "suricata-common.h"
29#include "suricata.h"
30#include "win32-service.h"
d4613e5c 31#include "util-debug.h"
6bf7d760
OS
32
33static SERVICE_STATUS_HANDLE service_status_handle = 0;
34
35static int service_argc = 0;
36
37static char **service_argv = NULL;
38
39static int service_initialized = 0;
40
41int main(int argc, char **argv);
42
43/**
44 * \brief Detect if running as service or console app
45 */
46int SCRunningAsService(void)
47{
9f135728
EL
48 HANDLE h = INVALID_HANDLE_VALUE;
49 if ((h = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
50 SCLogInfo("Running as service: yes");
51 return 1;
52 }
53 CloseHandle(h);
54 SCLogInfo("Running as service: no");
55 return 0;
6bf7d760
OS
56}
57
58/**
59 * \brief Detect if running as service or console app
60 */
8c31cd4b 61static void SCAtExitHandler(void)
6bf7d760 62{
9f135728
EL
63 SERVICE_STATUS status = {
64 SERVICE_WIN32,
65 SERVICE_STOPPED,
66 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
67 NO_ERROR,
68 NO_ERROR,
69 0,
70 0
71 };
72
73 SCLogInfo("Exit handler called.");
74
75 /* mark service as stopped */
76 if (!SetServiceStatus(service_status_handle, &status)) {
77 SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
78 } else {
79 SCLogInfo("Service status set to: SERVICE_STOPPED");
80 }
6bf7d760
OS
81}
82
83/**
84 * \brief Service handler
85 */
86static DWORD WINAPI SCServiceCtrlHandlerEx(DWORD code, DWORD etype, LPVOID edata, LPVOID context)
87{
9f135728
EL
88 if (code == SERVICE_CONTROL_SHUTDOWN || code == SERVICE_CONTROL_STOP) {
89 SERVICE_STATUS status = {
90 SERVICE_WIN32,
91 SERVICE_STOP_PENDING,
92 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
93 NO_ERROR,
94 NO_ERROR,
95 0,
96 0
97 };
98
99 SCLogInfo("Service control handler called with %s control code.",
100 ((code == SERVICE_CONTROL_SHUTDOWN) ? ("SERVICE_CONTROL_SHUTDOWN") : ("SERVICE_CONTROL_STOP")));
101
102 /* mark service as stop pending */
103 if (!SetServiceStatus(service_status_handle, &status)) {
104 SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
105 } else {
106 SCLogInfo("Service status set to: SERVICE_STOP_PENDING");
107 }
108
109 /* mark engine as stopping */
110 EngineStop();
111
112 return NO_ERROR;
113 }
114
115 return ERROR_CALL_NOT_IMPLEMENTED;
6bf7d760
OS
116}
117
118/**
119 * \brief Service main function
120 */
121static void WINAPI SCServiceMain(uint32_t argc, char** argv)
122{
9f135728
EL
123 SERVICE_STATUS status = {
124 SERVICE_WIN32,
125 SERVICE_RUNNING,
126 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
127 NO_ERROR,
128 NO_ERROR,
129 0,
130 0
131 };
132
8c31cd4b 133 if ((service_status_handle = RegisterServiceCtrlHandlerEx((char *)PROG_NAME, SCServiceCtrlHandlerEx, NULL)) == (SERVICE_STATUS_HANDLE)0) {
9f135728
EL
134 SCLogError(SC_ERR_SVC, "Can't register service control handler: %d", (int)GetLastError());
135 return;
136 }
137
138 /* register exit handler */
139 if (atexit(SCAtExitHandler)) {
140 SCLogWarning(SC_ERR_SVC, "Can't register exit handler: %d", (int)GetLastError());
141 }
142
143 /* mark service as running immediately */
144 if (!SetServiceStatus(service_status_handle, &status)) {
145 SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
146 } else {
147 SCLogInfo("Service status set to: SERVICE_RUNNING");
148 }
149
150 SCLogInfo("Entering main function...");
151
152 /* suricata initialization -> main loop -> uninitialization */
153 main(service_argc, service_argv);
154
155 SCLogInfo("Leaving main function.");
156
157 /* mark service as stopped */
158 status.dwCurrentState = SERVICE_STOPPED;
159
160 if (!SetServiceStatus(service_status_handle, &status)) {
161 SCLogWarning(SC_ERR_SVC, "Can't set service status: %d", (int)GetLastError());
162 } else {
163 SCLogInfo("Service status set to: SERVICE_STOPPED");
164 }
6bf7d760
OS
165}
166
167/**
168 * \brief Init suricata service
169 *
170 * \param argc num of arguments
171 * \param argv passed arguments
172 */
173int SCServiceInit(int argc, char **argv)
174{
9f135728 175 SERVICE_TABLE_ENTRY DispatchTable[] = {
223a38ae 176 {(char *)PROG_NAME, (LPSERVICE_MAIN_FUNCTION) SCServiceMain},
9f135728
EL
177 {NULL, NULL}
178 };
6bf7d760 179
9f135728
EL
180 /* continue with suricata initialization */
181 if (service_initialized) {
182 SCLogWarning(SC_ERR_SVC, "Service is already initialized.");
183 return 0;
184 }
6bf7d760 185
9f135728
EL
186 /* save args */
187 service_argc = argc;
188 service_argv = argv;
6bf7d760 189
9f135728 190 service_initialized = 1;
6bf7d760 191
9f135728 192 SCLogInfo("Entering service control dispatcher...");
6bf7d760 193
9f135728
EL
194 if (!StartServiceCtrlDispatcher(DispatchTable)) {
195 /* exit with failure */
196 exit(EXIT_FAILURE);
197 }
6bf7d760 198
9f135728 199 SCLogInfo("Leaving service control dispatcher.");
6bf7d760 200
9f135728
EL
201 /* exit with success */
202 exit(EXIT_SUCCESS);
6bf7d760
OS
203}
204
205/**
206 * \brief Install suricata as service
207 *
208 * \param argc num of arguments
209 * \param argv passed arguments
210 */
211int SCServiceInstall(int argc, char **argv)
212{
9f135728
EL
213 char path[2048];
214 SC_HANDLE service = NULL;
215 SC_HANDLE scm = NULL;
216 int ret = -1;
217 int i = 0;
218
219 do {
220 memset(path, 0, sizeof(path));
221
222 if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){
223 SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError());
224 break;
225 }
226
227 /* skip name of binary itself */
228 for (i = 1; i < argc; i++) {
229 if ((strlen(argv[i]) <= strlen("--service-install")) && (strncmp("--service-install", argv[i], strlen(argv[i])) == 0)) {
230 continue;
231 }
232 strlcat(path, " ", sizeof(path) - strlen(path) - 1);
233 strlcat(path, argv[i], sizeof(path) - strlen(path) - 1);
234 }
235
236 if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
237 SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
238 break;
239 }
240
241 service = CreateService(
242 scm,
243 PROG_NAME,
244 PROG_NAME,
245 SERVICE_ALL_ACCESS,
246 SERVICE_WIN32_OWN_PROCESS,
247 SERVICE_DEMAND_START,
248 SERVICE_ERROR_NORMAL,
249 path,
250 NULL,
251 NULL,
252 NULL,
253 NULL,
254 NULL);
255
256 if (service == NULL) {
257 SCLogError(SC_ERR_SVC, "Can't create service: %d", (int)GetLastError());
258 break;
259 }
260
261 ret = 0;
262
263 } while(0);
264
265 if (service) {
266 CloseServiceHandle(service);
267 }
268
269 if (scm) {
270 CloseServiceHandle(scm);
271 }
272
273 return ret;
6bf7d760
OS
274}
275
276/**
277 * \brief Remove suricata service
278 *
279 * \param argc num of arguments
280 * \param argv passed arguments
281 */
282int SCServiceRemove(int argc, char **argv)
283{
9f135728
EL
284 SERVICE_STATUS status;
285 SC_HANDLE service = NULL;
286 SC_HANDLE scm = NULL;
287 int ret = -1;
288
289 do {
290 if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
291 SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
292 break;
293 }
294
295 if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) {
296 SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError());
297 break;
298 }
299
300 if (!QueryServiceStatus(service, &status)) {
301 SCLogError(SC_ERR_SVC, "Can't query service status: %d", (int)GetLastError());
302 break;
303 }
304
305 if (status.dwCurrentState != SERVICE_STOPPED) {
306 SCLogError(SC_ERR_SVC, "Service isn't in stopped state: %d", (int)GetLastError());
307 break;
308 }
309
310 if (!DeleteService(service)) {
311 SCLogError(SC_ERR_SVC, "Can't delete service: %d", (int)GetLastError());
312 break;
313 }
314
315 ret = 0;
316
317 } while(0);
318
319 if (service) {
320 CloseServiceHandle(service);
321 }
322
323 if (scm) {
324 CloseServiceHandle(scm);
325 }
326
327 return ret;
6bf7d760
OS
328}
329
330/**
331 * \brief Change suricata service startup parameters
332 *
333 * \param argc num of arguments
334 * \param argv passed arguments
335 */
336int SCServiceChangeParams(int argc, char **argv)
337{
9f135728
EL
338 char path[2048];
339 SC_HANDLE service = NULL;
340 SC_HANDLE scm = NULL;
341 int ret = -1;
342 int i = 0;
343
344 do {
345 memset(path, 0, sizeof(path));
346
347 if (GetModuleFileName(NULL, path, MAX_PATH) == 0 ){
348 SCLogError(SC_ERR_SVC, "Can't get path to service binary: %d", (int)GetLastError());
349 break;
350 }
351
352 /* skip name of binary itself */
353 for (i = 1; i < argc; i++) {
354 if ((strlen(argv[i]) <= strlen("--service-change-params")) && (strncmp("--service-change-params", argv[i], strlen(argv[i])) == 0)) {
355 continue;
356 }
357 strlcat(path, " ", sizeof(path) - strlen(path) - 1);
358 strlcat(path, argv[i], sizeof(path) - strlen(path) - 1);
359 }
360
361 if ((scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) {
362 SCLogError(SC_ERR_SVC, "Can't open SCM: %d", (int)GetLastError());
363 break;
364 }
365
366 if ((service = OpenService(scm, PROG_NAME, SERVICE_ALL_ACCESS)) == NULL) {
367 SCLogError(SC_ERR_SVC, "Can't open service: %d", (int)GetLastError());
368 break;
369 }
370
371 if (!ChangeServiceConfig(
372 service,
373 SERVICE_WIN32_OWN_PROCESS,
374 SERVICE_DEMAND_START,
375 SERVICE_ERROR_NORMAL,
376 path,
377 NULL,
378 NULL,
379 NULL,
380 NULL,
381 NULL,
382 PROG_NAME))
383 {
384 SCLogError(SC_ERR_SVC, "Can't change service configuration: %d", (int)GetLastError());
385 break;
386 }
387
388 ret = 0;
389
390 } while(0);
391
392 return ret;
6bf7d760
OS
393}
394
395#endif /* OS_WIN32 */