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