1 /**
2 @file
3
4 @brief
5 Windows NT Service class library.
6
7 Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
8 This file is public domain and comes with NO WARRANTY of any kind
9 */
10 #include <windows.h>
11 #include <process.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include "nt_servc.h"
15
16
17 static NTService *pService;
18
19 /* ------------------------------------------------------------------------
20
21 -------------------------------------------------------------------------- */
NTService()22 NTService::NTService()
23 {
24
25 bOsNT = FALSE;
26 //service variables
27 ServiceName = NULL;
28 hExitEvent = 0;
29 bPause = FALSE;
30 bRunning = FALSE;
31 hThreadHandle = 0;
32 fpServiceThread = NULL;
33
34 //time-out variables
35 nStartTimeOut = 15000;
36 nStopTimeOut = 86400000;
37 nPauseTimeOut = 5000;
38 nResumeTimeOut = 5000;
39
40 //install variables
41 dwDesiredAccess = SERVICE_ALL_ACCESS;
42 dwServiceType = SERVICE_WIN32_OWN_PROCESS;
43 dwStartType = SERVICE_AUTO_START;
44 dwErrorControl = SERVICE_ERROR_NORMAL;
45 szLoadOrderGroup = NULL;
46 lpdwTagID = NULL;
47 szDependencies = NULL;
48
49 my_argc = 0;
50 my_argv = NULL;
51 hShutdownEvent = 0;
52 nError = 0;
53 dwState = 0;
54 }
55
56 /* ------------------------------------------------------------------------
57
58 -------------------------------------------------------------------------- */
~NTService()59 NTService::~NTService()
60 {
61 if (ServiceName != NULL) delete[] ServiceName;
62 }
63 /* ------------------------------------------------------------------------
64
65 -------------------------------------------------------------------------- */
66
GetOS()67 BOOL NTService::GetOS()
68 {
69 bOsNT = FALSE;
70 memset(&osVer, 0, sizeof(OSVERSIONINFO));
71 osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
72 if (GetVersionEx(&osVer))
73 {
74 if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
75 bOsNT = TRUE;
76 }
77 return bOsNT;
78 }
79
80
81 /**
82 Registers the main service thread with the service manager.
83
84 @param ServiceThread pointer to the main programs entry function
85 when the service is started
86 */
87
88
Init(LPCSTR szInternName,void * ServiceThread)89 long NTService::Init(LPCSTR szInternName,void *ServiceThread)
90 {
91
92 pService = this;
93
94 fpServiceThread = (THREAD_FC)ServiceThread;
95 ServiceName = new char[lstrlen(szInternName)+1];
96 lstrcpy(ServiceName,szInternName);
97
98 SERVICE_TABLE_ENTRY stb[] =
99 {
100 { (char *)szInternName,(LPSERVICE_MAIN_FUNCTION) ServiceMain} ,
101 { NULL, NULL }
102 };
103
104 return StartServiceCtrlDispatcher(stb); //register with the Service Manager
105 }
106
107
108 /**
109 Installs the service with Service manager.
110
111 nError values:
112 - 0 success
113 - 1 Can't open the Service manager
114 - 2 Failed to create service.
115 */
116
117
Install(int startType,LPCSTR szInternName,LPCSTR szDisplayName,LPCSTR szFullPath,LPCSTR szAccountName,LPCSTR szPassword)118 BOOL NTService::Install(int startType, LPCSTR szInternName,
119 LPCSTR szDisplayName,
120 LPCSTR szFullPath, LPCSTR szAccountName,
121 LPCSTR szPassword)
122 {
123 BOOL ret_val=FALSE;
124 SC_HANDLE newService, scm;
125
126 if (!SeekStatus(szInternName,1))
127 return FALSE;
128
129 char szFilePath[_MAX_PATH];
130 GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
131
132 // open a connection to the SCM
133 if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
134 printf("Failed to install the service (Couldn't open the SCM)\n");
135 else // Install the new service
136 {
137 if (!(newService=
138 CreateService(scm,
139 szInternName,
140 szDisplayName,
141 dwDesiredAccess,//default: SERVICE_ALL_ACCESS
142 dwServiceType, //default: SERVICE_WIN32_OWN_PROCESS
143 //default: SERVICE_AUTOSTART
144 (startType == 1 ? SERVICE_AUTO_START :
145 SERVICE_DEMAND_START),
146 dwErrorControl, //default: SERVICE_ERROR_NORMAL
147 szFullPath, //exec full path
148 szLoadOrderGroup, //default: NULL
149 lpdwTagID, //default: NULL
150 szDependencies, //default: NULL
151 szAccountName, //default: NULL
152 szPassword))) //default: NULL
153 printf("Failed to install the service (Couldn't create service)\n");
154 else
155 {
156 printf("Service successfully installed.\n");
157 CloseServiceHandle(newService);
158 ret_val=TRUE; // Everything went ok
159 }
160 CloseServiceHandle(scm);
161 }
162 return ret_val;
163 }
164
165
166 /**
167 Removes the service.
168
169 nError values:
170 - 0 success
171 - 1 Can't open the Service manager
172 - 2 Failed to locate service
173 - 3 Failed to delete service.
174 */
175
176
Remove(LPCSTR szInternName)177 BOOL NTService::Remove(LPCSTR szInternName)
178 {
179 BOOL ret_value=FALSE;
180 SC_HANDLE service, scm;
181
182 if (!SeekStatus(szInternName,0))
183 return FALSE;
184
185 nError=0;
186
187 // open a connection to the SCM
188 if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
189 {
190 printf("Failed to remove the service (Couldn't open the SCM)\n");
191 }
192 else
193 {
194 if ((service = OpenService(scm,szInternName, DELETE)))
195 {
196 if (!DeleteService(service))
197 printf("Failed to remove the service\n");
198 else
199 {
200 printf("Service successfully removed.\n");
201 ret_value=TRUE; // everything went ok
202 }
203 CloseServiceHandle(service);
204 }
205 else
206 printf("Failed to remove the service (Couldn't open the service)\n");
207 CloseServiceHandle(scm);
208 }
209 return ret_value;
210 }
211
212 /**
213 this function should be called before the app. exits to stop
214 the service
215 */
Stop(void)216 void NTService::Stop(void)
217 {
218 SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000);
219 StopService();
220 SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000);
221 }
222
223 /**
224 This is the function that is called from the
225 service manager to start the service.
226 */
227
228
ServiceMain(DWORD argc,LPTSTR * argv)229 void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
230 {
231
232 // registration function
233 if (!(pService->hServiceStatusHandle =
234 RegisterServiceCtrlHandler(pService->ServiceName,
235 (LPHANDLER_FUNCTION)
236 NTService::ServiceCtrlHandler)))
237 goto error;
238
239 // notify SCM of progress
240 if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 1, 8000))
241 goto error;
242
243 // create the exit event
244 if (!(pService->hExitEvent = CreateEvent (0, TRUE, FALSE,0)))
245 goto error;
246
247 if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 3,
248 pService->nStartTimeOut))
249 goto error;
250
251 // save start arguments
252 pService->my_argc=argc;
253 pService->my_argv=argv;
254
255 // start the service
256 if (!pService->StartService())
257 goto error;
258
259 // wait for exit event
260 WaitForSingleObject (pService->hExitEvent, INFINITE);
261
262 // wait for thread to exit
263 if (WaitForSingleObject (pService->hThreadHandle, INFINITE) == WAIT_TIMEOUT)
264 CloseHandle(pService->hThreadHandle);
265
266 pService->Exit(0);
267 return;
268
269 error:
270 pService->Exit(GetLastError());
271 return;
272 }
273
274
275
SetRunning()276 void NTService::SetRunning()
277 {
278 if (pService)
279 pService->SetStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
280 }
281
SetSlowStarting(unsigned long timeout)282 void NTService::SetSlowStarting(unsigned long timeout)
283 {
284 if (pService)
285 pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 0, timeout);
286 }
287
288
289 /* ------------------------------------------------------------------------
290 StartService() - starts the application thread
291 -------------------------------------------------------------------------- */
292
StartService()293 BOOL NTService::StartService()
294 {
295 // Start the real service's thread (application)
296 if (!(hThreadHandle = (HANDLE) _beginthread((THREAD_FC)fpServiceThread,0,
297 (void *) this)))
298 return FALSE;
299 bRunning = TRUE;
300 return TRUE;
301 }
302 /* ------------------------------------------------------------------------
303
304 -------------------------------------------------------------------------- */
StopService()305 void NTService::StopService()
306 {
307 bRunning=FALSE;
308
309 // Set the event for application
310 if (hShutdownEvent)
311 SetEvent(hShutdownEvent);
312
313 // Set the event for ServiceMain
314 SetEvent(hExitEvent);
315 }
316 /* ------------------------------------------------------------------------
317
318 -------------------------------------------------------------------------- */
PauseService()319 void NTService::PauseService()
320 {
321 bPause = TRUE;
322 SuspendThread(hThreadHandle);
323 }
324 /* ------------------------------------------------------------------------
325
326 -------------------------------------------------------------------------- */
ResumeService()327 void NTService::ResumeService()
328 {
329 bPause=FALSE;
330 ResumeThread(hThreadHandle);
331 }
332 /* ------------------------------------------------------------------------
333
334 -------------------------------------------------------------------------- */
SetStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwServiceSpecificExitCode,DWORD dwCheckPoint,DWORD dwWaitHint)335 BOOL NTService::SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
336 DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
337 DWORD dwWaitHint)
338 {
339 BOOL bRet;
340 SERVICE_STATUS serviceStatus;
341
342 dwState=dwCurrentState;
343
344 serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
345 serviceStatus.dwCurrentState = dwCurrentState;
346
347 if (dwCurrentState == SERVICE_START_PENDING)
348 serviceStatus.dwControlsAccepted = 0; //don't accept control events
349 else
350 serviceStatus.dwControlsAccepted = (SERVICE_ACCEPT_STOP |
351 SERVICE_ACCEPT_PAUSE_CONTINUE |
352 SERVICE_ACCEPT_SHUTDOWN);
353
354 // if a specific exit code is defined,set up the win32 exit code properly
355 if (dwServiceSpecificExitCode == 0)
356 serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
357 else
358 serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
359
360 serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
361
362 serviceStatus.dwCheckPoint = dwCheckPoint;
363 serviceStatus.dwWaitHint = dwWaitHint;
364
365 // Pass the status to the Service Manager
366 if (!(bRet=SetServiceStatus (hServiceStatusHandle, &serviceStatus)))
367 StopService();
368
369 return bRet;
370 }
371 /* ------------------------------------------------------------------------
372
373 -------------------------------------------------------------------------- */
ServiceCtrlHandler(DWORD ctrlCode)374 void NTService::ServiceCtrlHandler(DWORD ctrlCode)
375 {
376 DWORD dwState;
377
378 if (!pService)
379 return;
380
381 dwState=pService->dwState; // get current state
382
383 switch(ctrlCode) {
384 case SERVICE_CONTROL_SHUTDOWN:
385 case SERVICE_CONTROL_STOP:
386 dwState = SERVICE_STOP_PENDING;
387 pService->SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1,
388 pService->nStopTimeOut);
389 pService->StopService();
390 break;
391
392 default:
393 pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
394 break;
395 }
396 //pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
397 }
398
399 /* ------------------------------------------------------------------------
400
401 -------------------------------------------------------------------------- */
402
Exit(DWORD error)403 void NTService::Exit(DWORD error)
404 {
405 if (hExitEvent)
406 CloseHandle(hExitEvent);
407
408 // Send a message to the scm to tell that we stop
409 if (hServiceStatusHandle)
410 SetStatus(SERVICE_STOPPED, error,0, 0, 0);
411
412 // If the thread has started kill it ???
413 // if (hThreadHandle) CloseHandle(hThreadHandle);
414
415 }
416
417 /* ------------------------------------------------------------------------
418
419 -------------------------------------------------------------------------- */
420
SeekStatus(LPCSTR szInternName,int OperationType)421 BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType)
422 {
423 BOOL ret_value=FALSE;
424 SC_HANDLE service, scm;
425
426 // open a connection to the SCM
427 if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
428 {
429 DWORD ret_error=GetLastError();
430 if (ret_error == ERROR_ACCESS_DENIED)
431 {
432 printf("Install/Remove of the Service Denied!\n");
433 if (!is_super_user())
434 printf("That operation should be made by an user with Administrator privileges!\n");
435 }
436 else
437 printf("There is a problem for to open the Service Control Manager!\n");
438 }
439 else
440 {
441 if (OperationType == 1)
442 {
443 /* an install operation */
444 if ((service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
445 {
446 LPQUERY_SERVICE_CONFIG ConfigBuf;
447 DWORD dwSize;
448
449 ConfigBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096);
450 printf("The service already exists!\n");
451 if (QueryServiceConfig(service,ConfigBuf,4096,&dwSize))
452 printf("The current server installed: %s\n",
453 ConfigBuf->lpBinaryPathName);
454 LocalFree(ConfigBuf);
455 CloseServiceHandle(service);
456 }
457 else
458 ret_value=TRUE;
459 }
460 else
461 {
462 /* a remove operation */
463 if (!(service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
464 printf("The service doesn't exist!\n");
465 else
466 {
467 SERVICE_STATUS ss;
468
469 memset(&ss, 0, sizeof(ss));
470 if (QueryServiceStatus(service,&ss))
471 {
472 DWORD dwState = ss.dwCurrentState;
473 if (dwState == SERVICE_RUNNING)
474 printf("Failed to remove the service because the service is running\nStop the service and try again\n");
475 else if (dwState == SERVICE_STOP_PENDING)
476 printf("\
477 Failed to remove the service because the service is in stop pending state!\n\
478 Wait 30 seconds and try again.\n\
479 If this condition persist, reboot the machine and try again\n");
480 else
481 ret_value= TRUE;
482 }
483 CloseServiceHandle(service);
484 }
485 }
486 CloseServiceHandle(scm);
487 }
488
489 return ret_value;
490 }
491 /* ------------------------------------------------------------------------
492 -------------------------------------------------------------------------- */
IsService(LPCSTR ServiceName)493 BOOL NTService::IsService(LPCSTR ServiceName)
494 {
495 BOOL ret_value=FALSE;
496 SC_HANDLE service, scm;
497
498 if ((scm= OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE)))
499 {
500 if ((service = OpenService(scm,ServiceName, SERVICE_QUERY_STATUS)))
501 {
502 ret_value=TRUE;
503 CloseServiceHandle(service);
504 }
505 CloseServiceHandle(scm);
506 }
507 return ret_value;
508 }
509 /* ------------------------------------------------------------------------
510 -------------------------------------------------------------------------- */
got_service_option(char ** argv,char * service_option)511 BOOL NTService::got_service_option(char **argv, char *service_option)
512 {
513 char *option;
514 for (option= argv[1]; *option; option++)
515 if (!strcmp(option, service_option))
516 return TRUE;
517 return FALSE;
518 }
519 /* ------------------------------------------------------------------------
520 -------------------------------------------------------------------------- */
is_super_user()521 BOOL NTService::is_super_user()
522 {
523 HANDLE hAccessToken;
524 UCHAR InfoBuffer[1024];
525 PTOKEN_GROUPS ptgGroups=(PTOKEN_GROUPS)InfoBuffer;
526 DWORD dwInfoBufferSize;
527 PSID psidAdministrators;
528 SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
529 UINT x;
530 BOOL ret_value=FALSE;
531
532 if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken ))
533 {
534 if (GetLastError() != ERROR_NO_TOKEN)
535 return FALSE;
536
537 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken))
538 return FALSE;
539 }
540
541 ret_value= GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
542 1024, &dwInfoBufferSize);
543
544 CloseHandle(hAccessToken);
545
546 if (!ret_value )
547 return FALSE;
548
549 if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
550 SECURITY_BUILTIN_DOMAIN_RID,
551 DOMAIN_ALIAS_RID_ADMINS,
552 0, 0, 0, 0, 0, 0,
553 &psidAdministrators))
554 return FALSE;
555
556 ret_value = FALSE;
557
558 for (x=0;x<ptgGroups->GroupCount;x++)
559 {
560 if ( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
561 {
562 ret_value = TRUE;
563 break;
564 }
565
566 }
567 FreeSid(psidAdministrators);
568 return ret_value;
569 }
570