MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
nt_servc.cc
Go to the documentation of this file.
1 
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  -------------------------------------------------------------------------- */
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  -------------------------------------------------------------------------- */
59 NTService::~NTService()
60 {
61  if (ServiceName != NULL) delete[] ServiceName;
62 }
63 /* ------------------------------------------------------------------------
64 
65  -------------------------------------------------------------------------- */
66 
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 
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 
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 
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 
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 
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 
276 void NTService::SetRunning()
277 {
278  if (pService)
279  pService->SetStatus(SERVICE_RUNNING, NO_ERROR, 0, 0, 0);
280 }
281 
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 
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  -------------------------------------------------------------------------- */
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  -------------------------------------------------------------------------- */
319 void NTService::PauseService()
320 {
321  bPause = TRUE;
322  SuspendThread(hThreadHandle);
323 }
324 /* ------------------------------------------------------------------------
325 
326  -------------------------------------------------------------------------- */
327 void NTService::ResumeService()
328 {
329  bPause=FALSE;
330  ResumeThread(hThreadHandle);
331 }
332 /* ------------------------------------------------------------------------
333 
334  -------------------------------------------------------------------------- */
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  -------------------------------------------------------------------------- */
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 
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 
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  -------------------------------------------------------------------------- */
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  -------------------------------------------------------------------------- */
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  -------------------------------------------------------------------------- */
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 }