1+ /*
2+ * Copyright (C) 2013-2021 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3+ * Copyright (C) 2007-2013 Sourcefire, Inc.
4+ *
5+ * Authors: Gianluigi Tiesi
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License version 2 as
9+ * published by the Free Software Foundation.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19+ * MA 02110-1301, USA.
20+ */
21+
22+ #include <platform.h>
23+ #include <winsvc.h>
24+
25+ #include "service.h"
26+ #include "output.h"
27+
28+ static SERVICE_STATUS svc ;
29+ static SERVICE_STATUS_HANDLE svc_handle ;
30+ static SERVICE_TABLE_ENTRYA DT [] = {{"Service" , ServiceMain }, {NULL , NULL }};
31+
32+ static HANDLE evStart ;
33+ static HANDLE DispatcherThread ;
34+ static int checkpoint_every = 5000 ;
35+
36+ int svc_uninstall (const char * name , int verbose )
37+ {
38+ SC_HANDLE sm , svc ;
39+ int ret = 1 ;
40+
41+ if (!(sm = OpenSCManagerA (NULL , NULL , DELETE ))) {
42+ if (GetLastError () == ERROR_CALL_NOT_IMPLEMENTED )
43+ fprintf (stderr , "Windows Services are not supported on this Platform\n" );
44+ else
45+ fprintf (stderr , "Unable to Open SCManager (%d)\n" , GetLastError ());
46+ return 0 ;
47+ }
48+
49+ if ((svc = OpenServiceA (sm , name , DELETE ))) {
50+ if (DeleteService (svc )) {
51+ if (verbose ) printf ("Service %s successfully removed\n" , name );
52+ } else {
53+ fprintf (stderr , "Unable to Open Service %s (%d)\n" , name , GetLastError ());
54+ ret = 0 ;
55+ }
56+ } else {
57+ if (GetLastError () == ERROR_SERVICE_DOES_NOT_EXIST ) {
58+ if (verbose ) printf ("Service %s does not exist\n" , name );
59+ } else {
60+ fprintf (stderr , "Unable to Open Service %s (%d)\n" , name , GetLastError ());
61+ ret = 0 ;
62+ }
63+ }
64+
65+ if (svc ) CloseServiceHandle (svc );
66+ CloseServiceHandle (sm );
67+ return ret ;
68+ }
69+
70+ int svc_install (const char * name , const char * dname , const char * desc )
71+ {
72+ SC_HANDLE sm , svc ;
73+ char modulepath [MAX_PATH ];
74+ char binpath [MAX_PATH ];
75+ SERVICE_DESCRIPTIONA sdesc = {(char * )desc };
76+
77+ if (!GetModuleFileName (NULL , modulepath , MAX_PATH - 1 )) {
78+ fprintf (stderr , "Unable to get the executable name (%d)\n" , GetLastError ());
79+ return 0 ;
80+ }
81+
82+ if (!svc_uninstall (name , 0 )) return 0 ;
83+
84+ if (!(sm = OpenSCManagerA (NULL , NULL , SC_MANAGER_CREATE_SERVICE | DELETE ))) {
85+ if (GetLastError () == ERROR_CALL_NOT_IMPLEMENTED )
86+ fprintf (stderr , "Windows Services are not supported on this Platform\n" );
87+ else
88+ fprintf (stderr , "Unable to Open SCManager (%d)\n" , GetLastError ());
89+ return 0 ;
90+ }
91+
92+ if (strchr (modulepath , ' ' ))
93+ snprintf (binpath , MAX_PATH - 1 , "\"%s\" --daemon" , modulepath );
94+ else
95+ snprintf (binpath , MAX_PATH - 1 , "%s --daemon" , modulepath );
96+
97+ svc = CreateServiceA (sm , name , dname , SERVICE_CHANGE_CONFIG ,
98+ SERVICE_WIN32_OWN_PROCESS ,
99+ SERVICE_DEMAND_START ,
100+ SERVICE_ERROR_NORMAL ,
101+ binpath ,
102+ NULL , /* Load group order */
103+ NULL , /* Tag Id */
104+ NULL , /* Dependencies */
105+ NULL , /* User -> Local System */
106+ "" );
107+
108+ if (!svc ) {
109+ fprintf (stderr , "Unable to Create Service %s (%d)\n" , name , GetLastError ());
110+ CloseServiceHandle (sm );
111+ return 0 ;
112+ }
113+
114+ /* ChangeServiceConfig2A() */
115+ if (!ChangeServiceConfig2A (svc , SERVICE_CONFIG_DESCRIPTION , & sdesc ))
116+ fprintf (stderr , "Unable to set description for Service %s (%d)\n" , name , GetLastError ());
117+
118+ CloseServiceHandle (svc );
119+ CloseServiceHandle (sm );
120+
121+ printf ("Service %s successfully created.\n" , name );
122+ printf ("Use 'net start %s' and 'net stop %s' to start/stop the service.\n" , name , name );
123+ return 1 ;
124+ }
125+
126+ static void svc_getcpvalue (const char * name )
127+ {
128+ HKEY hKey ;
129+ DWORD dwType ;
130+ DWORD value , vlen = sizeof (DWORD );
131+ char subkey [MAX_PATH ];
132+
133+ snprintf (subkey , MAX_PATH - 1 , "SYSTEM\\CurrentControlSet\\Services\\%s" , name );
134+
135+ if (RegOpenKeyExA (HKEY_LOCAL_MACHINE , subkey , 0 , KEY_QUERY_VALUE , & hKey ) != ERROR_SUCCESS )
136+ return ;
137+
138+ if ((RegQueryValueExA (hKey , "Checkpoint" , NULL , & dwType , (LPBYTE )& value , & vlen ) == ERROR_SUCCESS ) &&
139+ (vlen == sizeof (DWORD ) && (dwType == REG_DWORD )))
140+ checkpoint_every = value ;
141+
142+ RegCloseKey (hKey );
143+ }
144+
145+ void svc_register (const char * name )
146+ {
147+ DWORD tid ;
148+ DT -> lpServiceName = (char * )name ;
149+ svc_getcpvalue (name );
150+
151+ evStart = CreateEvent (NULL , TRUE, FALSE, NULL );
152+ DispatcherThread = CreateThread (NULL , 0 , (LPTHREAD_START_ROUTINE )StartServiceCtrlDispatcherA , (LPVOID )DT , 0 , & tid );
153+ }
154+
155+ void svc_ready (void )
156+ {
157+ WaitForSingleObject (evStart , INFINITE );
158+
159+ svc .dwCurrentState = SERVICE_RUNNING ;
160+ svc .dwControlsAccepted |= SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN ;
161+ svc .dwCheckPoint = 0 ;
162+
163+ if (!SetServiceStatus (svc_handle , & svc )) {
164+ logg ("[service] SetServiceStatus() failed with %d\n" , GetLastError ());
165+ exit (1 );
166+ }
167+ }
168+
169+ int svc_checkpoint (const char * type , const char * name , unsigned int custom , void * context )
170+ {
171+ if (svc .dwCurrentState == SERVICE_START_PENDING ) {
172+ svc .dwCheckPoint ++ ;
173+ if ((svc .dwCheckPoint % checkpoint_every ) == 0 )
174+ SetServiceStatus (svc_handle , & svc );
175+ }
176+ return 0 ;
177+ }
178+
179+ void WINAPI ServiceCtrlHandler (DWORD code )
180+ {
181+ switch (code ) {
182+ case SERVICE_CONTROL_STOP :
183+ case SERVICE_CONTROL_SHUTDOWN :
184+ svc .dwCurrentState = SERVICE_STOPPED ;
185+ svc .dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN );
186+ SetServiceStatus (svc_handle , & svc );
187+ return ;
188+ case SERVICE_CONTROL_INTERROGATE :
189+ break ;
190+ }
191+
192+ SetServiceStatus (svc_handle , & svc );
193+ }
194+
195+ BOOL WINAPI cw_stop_ctrl_handler (DWORD CtrlType )
196+ {
197+ if (CtrlType == CTRL_C_EVENT ) {
198+ SetConsoleCtrlHandler (cw_stop_ctrl_handler , FALSE);
199+ fprintf (stderr , "Control+C pressed, aborting...\n" );
200+ exit (0 );
201+ }
202+ return TRUE;
203+ }
204+
205+ void WINAPI ServiceMain (DWORD dwArgc , LPSTR * lpszArgv )
206+ {
207+ svc .dwServiceType = SERVICE_WIN32 ;
208+ svc .dwCurrentState = SERVICE_START_PENDING ;
209+ svc .dwControlsAccepted = 0 ;
210+ svc .dwWin32ExitCode = NO_ERROR ;
211+ svc .dwServiceSpecificExitCode = 0 ;
212+ svc .dwCheckPoint = 0 ;
213+ svc .dwWaitHint = 0 ;
214+
215+ if (!(svc_handle = RegisterServiceCtrlHandlerA (DT -> lpServiceName , ServiceCtrlHandler ))) {
216+ logg ("[service] RegisterServiceCtrlHandler() failed with %d\n" , GetLastError ());
217+ exit (1 );
218+ }
219+
220+ if (!SetServiceStatus (svc_handle , & svc )) {
221+ logg ("[service] SetServiceStatus() failed with %d\n" , GetLastError ());
222+ exit (1 );
223+ }
224+
225+ SetEvent (evStart );
226+ WaitForSingleObject (DispatcherThread , INFINITE );
227+ cw_stop_ctrl_handler (CTRL_C_EVENT );
228+ }
0 commit comments