ntservice.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #ifndef CONFIG
  2. #define CONFIG "config.h"
  3. #endif // CONFIG
  4. #include CONFIG
  5. #include "ntservice.h"
  6. #include "shared_globals.h"
  7. #include "vlmcsd.h"
  8. #include "output.h"
  9. #include "helpers.h"
  10. #ifdef _NTSERVICE
  11. SERVICE_STATUS gSvcStatus;
  12. SERVICE_STATUS_HANDLE gSvcStatusHandle;
  13. static VOID WINAPI ServiceCtrlHandler(const DWORD dwCtrl)
  14. {
  15. // Handle the requested control code.
  16. switch(dwCtrl)
  17. {
  18. case SERVICE_CONTROL_STOP:
  19. case SERVICE_CONTROL_SHUTDOWN:
  20. ServiceShutdown = TRUE;
  21. ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
  22. // Remove PID file and free ressources
  23. cleanup();
  24. # ifdef USE_MSRPC
  25. ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
  26. # endif // !USE_MSRPC
  27. return;
  28. /*case SERVICE_CONTROL_INTERROGATE:
  29. break;*/
  30. default:
  31. break;
  32. }
  33. }
  34. static VOID WINAPI ServiceMain(const int argc_unused, CARGV argv_unused)
  35. {
  36. // Register the handler function for the service
  37. gSvcStatusHandle = RegisterServiceCtrlHandler(
  38. NT_SERVICE_NAME,
  39. ServiceCtrlHandler
  40. );
  41. if(!gSvcStatusHandle)
  42. {
  43. //ServiceReportEvent(RegisterServiceCtrlHandler);
  44. return;
  45. }
  46. // These SERVICE_STATUS members remain as set here
  47. gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  48. gSvcStatus.dwServiceSpecificExitCode = 0;
  49. // Run the actual program
  50. ReportServiceStatus(SERVICE_STOPPED, newmain(), 3000);
  51. }
  52. SERVICE_TABLE_ENTRY NTServiceDispatchTable[] = {
  53. {
  54. (LPSTR)NT_SERVICE_NAME,
  55. (LPSERVICE_MAIN_FUNCTION) ServiceMain
  56. },
  57. {
  58. NULL,
  59. NULL
  60. }
  61. };
  62. VOID ReportServiceStatus(const DWORD dwCurrentState, const DWORD dwWin32ExitCode, const DWORD dwWaitHint)
  63. {
  64. static DWORD dwCheckPoint = 1;
  65. // Fill in the SERVICE_STATUS structure.
  66. gSvcStatus.dwCurrentState = dwCurrentState;
  67. gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
  68. gSvcStatus.dwWaitHint = dwWaitHint;
  69. if (dwCurrentState == SERVICE_START_PENDING)
  70. gSvcStatus.dwControlsAccepted = 0;
  71. else
  72. gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  73. if ( (dwCurrentState == SERVICE_RUNNING) ||
  74. (dwCurrentState == SERVICE_STOPPED) )
  75. gSvcStatus.dwCheckPoint = 0;
  76. else
  77. gSvcStatus.dwCheckPoint = dwCheckPoint++;
  78. // Report the status of the service to the SCM.
  79. SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
  80. }
  81. /*VOID ServiceReportEvent(char *szFunction)
  82. {
  83. HANDLE hEventSource;
  84. const char *eventStrings[2];
  85. TCHAR Buffer[80];
  86. hEventSource = RegisterEventSource(NULL, NT_SERVICE_NAME);
  87. if (hEventSource)
  88. {
  89. snprintf(Buffer, 80, "%s failed with %d", szFunction, GetLastError());
  90. eventStrings[0] = NT_SERVICE_NAME;
  91. eventStrings[1] = Buffer;
  92. ReportEvent(hEventSource, // event log handle
  93. EVENTLOG_ERROR_TYPE, // event type
  94. 0, // event category
  95. 00, // event identifier
  96. NULL, // no security identifier
  97. 2, // size of lpszStrings array
  98. 0, // no binary data
  99. eventStrings, // array of strings
  100. NULL); // no binary data
  101. DeregisterEventSource(hEventSource);
  102. }
  103. }*/
  104. //Returns 0=Error, 1=Success, 2=Doesn't exist
  105. static uint_fast8_t OpenAndRemoveService(DWORD *dwPreviousState, SC_HANDLE *schSCManager)
  106. {
  107. SERVICE_STATUS status;
  108. uint_fast8_t i;
  109. SC_HANDLE installedService;
  110. uint_fast8_t result = 1;
  111. BOOL closeManager = FALSE;
  112. // Allow NULL for both Arguments
  113. if (!dwPreviousState) dwPreviousState = (DWORD*)alloca(sizeof(*dwPreviousState));
  114. if (!schSCManager)
  115. {
  116. schSCManager = (SC_HANDLE*)alloca(sizeof(*schSCManager));
  117. closeManager = TRUE;
  118. }
  119. *schSCManager = OpenSCManager(
  120. NULL, // local computer
  121. NULL, // ServicesActive database
  122. SC_MANAGER_ALL_ACCESS); // full access rights
  123. if (!*schSCManager) return 0;
  124. if (!(installedService = OpenService(*schSCManager, NT_SERVICE_NAME, SERVICE_ALL_ACCESS)))
  125. {
  126. result = 2;
  127. }
  128. else
  129. {
  130. *dwPreviousState = SERVICE_STOPPED;
  131. if (QueryServiceStatus(installedService, &status)) *dwPreviousState = status.dwCurrentState;
  132. ControlService(installedService, SERVICE_CONTROL_STOP, &status);
  133. for (i = 0; i < 10; i++)
  134. {
  135. QueryServiceStatus(installedService, &status);
  136. // Give it 100 ms after it reported SERVICE_STOPPED. Subsequent CreateService will fail otherwise
  137. Sleep(100);
  138. if (status.dwCurrentState == SERVICE_STOPPED) break;
  139. }
  140. if (!DeleteService(installedService)) result = 0;
  141. CloseServiceHandle(installedService);
  142. }
  143. if (closeManager) CloseServiceHandle(*schSCManager);
  144. return result;
  145. }
  146. static VOID ServiceInstaller(const char *restrict ServiceUser, const char *const ServicePassword)
  147. {
  148. SC_HANDLE schSCManager;
  149. SC_HANDLE schService;
  150. char szPath[MAX_PATH] = "\"";
  151. if (!GetModuleFileName(NULL, szPath + sizeof(char), MAX_PATH - 1))
  152. {
  153. errorout("Cannot install service (%d)\n", (uint32_t)GetLastError());
  154. return;
  155. }
  156. strcat(szPath,"\"");
  157. int i;
  158. for (i = 1; i < global_argc; i ++)
  159. {
  160. // Strip unneccessary parameters, especially the password
  161. if (!strcmp(global_argv[i], "-s")) continue;
  162. if (!strcmp(global_argv[i], "-W") ||
  163. !strcmp(global_argv[i], "-U"))
  164. {
  165. i++;
  166. continue;
  167. }
  168. strcat(szPath, " ");
  169. if (strchr(global_argv[i], ' '))
  170. {
  171. strcat(szPath, "\"");
  172. strcat(szPath, global_argv[i]);
  173. strcat(szPath, "\"");
  174. }
  175. else
  176. strcat(szPath, global_argv[i]);
  177. }
  178. // Get a handle to the SCM database.
  179. SERVICE_STATUS status;
  180. DWORD dwPreviousState;
  181. if (!OpenAndRemoveService(&dwPreviousState, &schSCManager))
  182. {
  183. errorout("Service removal failed (%d)\n", (uint32_t)GetLastError());
  184. return;
  185. }
  186. char *tempUser = NULL;
  187. if (ServiceUser)
  188. {
  189. // Shortcuts for some well known users
  190. if (!strcasecmp(ServiceUser, "/l")) ServiceUser="NT AUTHORITY\\LocalService";
  191. if (!strcasecmp(ServiceUser, "/n")) ServiceUser="NT AUTHORITY\\NetworkService";
  192. // Allow Local Users without .\ , e.g. "johndoe" instead of ".\johndoe"
  193. if (!strchr(ServiceUser, '\\'))
  194. {
  195. tempUser = (char*)vlmcsd_malloc(strlen(ServiceUser) + 3);
  196. strcpy(tempUser, ".\\");
  197. strcat(tempUser, ServiceUser);
  198. ServiceUser = tempUser;
  199. }
  200. }
  201. schService = CreateService(
  202. schSCManager, // SCM database
  203. NT_SERVICE_NAME, // name of service
  204. NT_SERVICE_DISPLAY_NAME, // service name to display
  205. SERVICE_ALL_ACCESS, // desired access
  206. SERVICE_WIN32_OWN_PROCESS, // service type
  207. SERVICE_AUTO_START, // start type
  208. SERVICE_ERROR_NORMAL, // error control type
  209. szPath, // path to service's binary
  210. NULL, // no load ordering group
  211. NULL, // no tag identifier
  212. "tcpip\0", // depends on TCP/IP
  213. ServiceUser, // LocalSystem account
  214. ServicePassword); // no password
  215. # if __clang__ && (__CYGWIN__ || __MINGW64__ )
  216. // Workaround for clang not understanding some GCC asm syntax used in <w32api/psdk_inc/intrin-impl.h>
  217. ZeroMemory((char*)ServicePassword, strlen(ServicePassword));
  218. # else
  219. SecureZeroMemory((char*)ServicePassword, strlen(ServicePassword));
  220. # endif
  221. if (tempUser) free(tempUser);
  222. if (schService == NULL)
  223. {
  224. errorout("CreateService failed (%u)\n", (uint32_t)GetLastError());
  225. CloseServiceHandle(schSCManager);
  226. return;
  227. }
  228. else
  229. {
  230. errorout("Service installed successfully\n");
  231. if (dwPreviousState == SERVICE_RUNNING)
  232. {
  233. printf("Restarting " NT_SERVICE_NAME " service => ");
  234. status.dwCurrentState = SERVICE_STOPPED;
  235. if (StartService(schService, 0, NULL))
  236. {
  237. for (i = 0; i < 10; i++)
  238. {
  239. if (!QueryServiceStatus(schService, &status) || status.dwCurrentState != SERVICE_START_PENDING) break;
  240. Sleep(100);
  241. }
  242. if (status.dwCurrentState == SERVICE_RUNNING)
  243. printf("Success\n");
  244. else if (status.dwCurrentState == SERVICE_START_PENDING)
  245. printf("Not ready within a second\n");
  246. else
  247. errorout("Error\n");
  248. }
  249. else
  250. errorout("Error %u\n", (uint32_t)GetLastError());
  251. }
  252. }
  253. CloseServiceHandle(schService);
  254. CloseServiceHandle(schSCManager);
  255. }
  256. int NtServiceInstallation(const int_fast8_t installService, const char *restrict ServiceUser, const char *const ServicePassword)
  257. {
  258. if (IsNTService) return 0;
  259. if (installService == 1) // Install
  260. {
  261. ServiceInstaller(ServiceUser, ServicePassword);
  262. return(0);
  263. }
  264. if (installService == 2) // Remove
  265. {
  266. switch(OpenAndRemoveService(NULL, NULL))
  267. {
  268. case 0:
  269. errorout("Error removing service %s\n", NT_SERVICE_NAME);
  270. return(!0);
  271. case 1:
  272. printf("Service %s removed successfully\n", NT_SERVICE_NAME);
  273. return(0);
  274. default:
  275. errorout("Service %s does not exist.\n", NT_SERVICE_NAME);
  276. return(!0);
  277. }
  278. }
  279. // Do nothing
  280. return(0);
  281. }
  282. #endif // _NTSERVICE