2 #define CONFIG "config.h"
7 #include "shared_globals.h"
14 SERVICE_STATUS gSvcStatus
;
15 SERVICE_STATUS_HANDLE gSvcStatusHandle
;
17 static VOID WINAPI
ServiceCtrlHandler(const DWORD dwCtrl
)
19 // Handle the requested control code.
23 case SERVICE_CONTROL_STOP
:
24 case SERVICE_CONTROL_SHUTDOWN
:
26 ServiceShutdown
= TRUE
;
27 ReportServiceStatus(SERVICE_STOP_PENDING
, NO_ERROR
, 0);
29 // Remove PID file and free ressources
32 ReportServiceStatus(SERVICE_STOPPED
, NO_ERROR
, 0);
36 /*case SERVICE_CONTROL_INTERROGATE:
44 static VOID WINAPI
ServiceMain(const int argc_unused
, CARGV argv_unused
)
46 // Register the handler function for the service
48 gSvcStatusHandle
= RegisterServiceCtrlHandler(
55 //ServiceReportEvent(RegisterServiceCtrlHandler);
59 // These SERVICE_STATUS members remain as set here
61 gSvcStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
62 gSvcStatus
.dwServiceSpecificExitCode
= 0;
64 // Run the actual program
65 ReportServiceStatus(SERVICE_STOPPED
, newmain(), 3000);
68 SERVICE_TABLE_ENTRY NTServiceDispatchTable
[] = {
70 (LPSTR
)NT_SERVICE_NAME
,
71 (LPSERVICE_MAIN_FUNCTION
) ServiceMain
79 VOID
ReportServiceStatus(const DWORD dwCurrentState
, const DWORD dwWin32ExitCode
, const DWORD dwWaitHint
)
81 static DWORD dwCheckPoint
= 1;
83 // Fill in the SERVICE_STATUS structure.
85 gSvcStatus
.dwCurrentState
= dwCurrentState
;
86 gSvcStatus
.dwWin32ExitCode
= dwWin32ExitCode
;
87 gSvcStatus
.dwWaitHint
= dwWaitHint
;
89 if (dwCurrentState
== SERVICE_START_PENDING
)
90 gSvcStatus
.dwControlsAccepted
= 0;
92 gSvcStatus
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
94 if ( (dwCurrentState
== SERVICE_RUNNING
) ||
95 (dwCurrentState
== SERVICE_STOPPED
) )
96 gSvcStatus
.dwCheckPoint
= 0;
98 gSvcStatus
.dwCheckPoint
= dwCheckPoint
++;
100 // Report the status of the service to the SCM.
101 SetServiceStatus(gSvcStatusHandle
, &gSvcStatus
);
104 /*VOID ServiceReportEvent(char *szFunction)
107 const char *eventStrings[2];
110 hEventSource = RegisterEventSource(NULL, NT_SERVICE_NAME);
114 snprintf(Buffer, 80, "%s failed with %d", szFunction, GetLastError());
116 eventStrings[0] = NT_SERVICE_NAME;
117 eventStrings[1] = Buffer;
119 ReportEvent(hEventSource, // event log handle
120 EVENTLOG_ERROR_TYPE, // event type
122 00, // event identifier
123 NULL, // no security identifier
124 2, // size of lpszStrings array
126 eventStrings, // array of strings
127 NULL); // no binary data
129 DeregisterEventSource(hEventSource);
133 //Returns 0=Error, 1=Success, 2=Doesn't exist
136 static uint_fast8_t OpenAndRemoveService(DWORD
*dwPreviousState
, SC_HANDLE
*schSCManager
)
138 SERVICE_STATUS status
;
140 SC_HANDLE installedService
;
141 uint_fast8_t result
= 1;
142 BOOL closeManager
= FALSE
;
144 // Allow NULL for both Arguments
145 if (!dwPreviousState
) dwPreviousState
= (DWORD
*)alloca(sizeof(*dwPreviousState
));
148 schSCManager
= (SC_HANDLE
*)alloca(sizeof(*schSCManager
));
152 *schSCManager
= OpenSCManager(
153 NULL
, // local computer
154 NULL
, // ServicesActive database
155 SC_MANAGER_ALL_ACCESS
); // full access rights
157 if (!*schSCManager
) return 0;
159 if (!(installedService
= OpenService(*schSCManager
, NT_SERVICE_NAME
, SERVICE_ALL_ACCESS
)))
165 *dwPreviousState
= SERVICE_STOPPED
;
166 if (QueryServiceStatus(installedService
, &status
)) *dwPreviousState
= status
.dwCurrentState
;
168 ControlService(installedService
, SERVICE_CONTROL_STOP
, &status
);
170 for (i
= 0; i
< 10; i
++)
172 QueryServiceStatus(installedService
, &status
);
173 // Give it 100 ms after it reported SERVICE_STOPPED. Subsequent CreateService will fail otherwise
175 if (status
.dwCurrentState
== SERVICE_STOPPED
) break;
178 if (!DeleteService(installedService
)) result
= 0;
179 CloseServiceHandle(installedService
);
182 if (closeManager
) CloseServiceHandle(*schSCManager
);
186 static VOID
ServiceInstaller(const char *restrict ServiceUser
, const char *const ServicePassword
)
188 SC_HANDLE schSCManager
;
189 SC_HANDLE schService
;
190 char szPath
[MAX_PATH
] = "\"";
192 if (!GetModuleFileName(NULL
, szPath
+ sizeof(char), MAX_PATH
- 1))
194 errorout("Cannot install service (%d)\n", (uint32_t)GetLastError());
201 for (i
= 1; i
< global_argc
; i
++)
203 // Strip unneccessary parameters, especially the password
204 if (!strcmp(global_argv
[i
], "-s")) continue;
206 if (!strcmp(global_argv
[i
], "-W") ||
207 !strcmp(global_argv
[i
], "-U"))
215 if (strchr(global_argv
[i
], ' '))
217 strcat(szPath
, "\"");
218 strcat(szPath
, global_argv
[i
]);
219 strcat(szPath
, "\"");
222 strcat(szPath
, global_argv
[i
]);
225 // Get a handle to the SCM database.
227 SERVICE_STATUS status
;
228 DWORD dwPreviousState
;
230 if (!OpenAndRemoveService(&dwPreviousState
, &schSCManager
))
232 errorout("Service removal failed (%d)\n", (uint32_t)GetLastError());
236 char *tempUser
= NULL
;
240 // Shortcuts for some well known users
241 if (!strcasecmp(ServiceUser
, "/l")) ServiceUser
="NT AUTHORITY\\LocalService";
242 if (!strcasecmp(ServiceUser
, "/n")) ServiceUser
="NT AUTHORITY\\NetworkService";
244 // Allow Local Users without .\ , e.g. "johndoe" instead of ".\johndoe"
245 if (!strchr(ServiceUser
, '\\'))
247 tempUser
= (char*)vlmcsd_malloc(strlen(ServiceUser
) + 3);
248 strcpy(tempUser
, ".\\");
249 strcat(tempUser
, ServiceUser
);
250 ServiceUser
= tempUser
;
254 schService
= CreateService(
255 schSCManager
, // SCM database
256 NT_SERVICE_NAME
, // name of service
257 NT_SERVICE_DISPLAY_NAME
, // service name to display
258 SERVICE_ALL_ACCESS
, // desired access
259 SERVICE_WIN32_OWN_PROCESS
, // service type
260 SERVICE_AUTO_START
, // start type
261 SERVICE_ERROR_NORMAL
, // error control type
262 szPath
, // path to service's binary
263 NULL
, // no load ordering group
264 NULL
, // no tag identifier
265 "tcpip\0", // depends on TCP/IP
266 ServiceUser
, // LocalSystem account
267 ServicePassword
); // no password
269 # if __clang__ && (__CYGWIN__ || __MINGW64__ )
270 // Workaround for clang not understanding some GCC asm syntax used in <w32api/psdk_inc/intrin-impl.h>
271 ZeroMemory((char*)ServicePassword
, strlen(ServicePassword
));
273 SecureZeroMemory((char*)ServicePassword
, strlen(ServicePassword
));
275 if (tempUser
) free(tempUser
);
277 if (schService
== NULL
)
279 errorout("CreateService failed (%u)\n", (uint32_t)GetLastError());
280 CloseServiceHandle(schSCManager
);
285 errorout("Service installed successfully\n");
287 if (dwPreviousState
== SERVICE_RUNNING
)
289 printf("Restarting " NT_SERVICE_NAME
" service => ");
290 status
.dwCurrentState
= SERVICE_STOPPED
;
292 if (StartService(schService
, 0, NULL
))
294 for (i
= 0; i
< 10; i
++)
296 if (!QueryServiceStatus(schService
, &status
) || status
.dwCurrentState
!= SERVICE_START_PENDING
) break;
300 if (status
.dwCurrentState
== SERVICE_RUNNING
)
302 else if (status
.dwCurrentState
== SERVICE_START_PENDING
)
303 printf("Not ready within a second\n");
308 errorout("Error %u\n", (uint32_t)GetLastError());
312 CloseServiceHandle(schService
);
313 CloseServiceHandle(schSCManager
);
316 int NtServiceInstallation(const int_fast8_t installService
, const char *restrict ServiceUser
, const char *const ServicePassword
)
318 if (IsNTService
) return 0;
320 if (installService
== 1) // Install
322 ServiceInstaller(ServiceUser
, ServicePassword
);
326 if (installService
== 2) // Remove
328 switch(OpenAndRemoveService(NULL
, NULL
))
331 errorout("Error removing service %s\n", NT_SERVICE_NAME
);
334 printf("Service %s removed successfully\n", NT_SERVICE_NAME
);
337 errorout("Service %s does not exist.\n", NT_SERVICE_NAME
);