mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-24 07:13:33 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			571 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			571 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* ------------------------------------------------------------------------
 | |
|    Windows NT Service class library
 | |
|    Copyright Abandoned 1998 Irena Pancirov - Irnet Snc
 | |
|    This file is public domain and comes with NO WARRANTY of any kind
 | |
|  -------------------------------------------------------------------------- */
 | |
| #include <windows.h>
 | |
| #include <process.h>
 | |
| #include <stdio.h>
 | |
| #include "nt_servc.h"
 | |
| 
 | |
| 
 | |
| static NTService *pService;
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| NTService::NTService()
 | |
| {
 | |
| 
 | |
|     bOsNT	     = FALSE;
 | |
|     //service variables
 | |
|     ServiceName      = NULL;
 | |
|     hExitEvent	     = 0;
 | |
|     bPause	     = FALSE;
 | |
|     bRunning	     = FALSE;
 | |
|     hThreadHandle    = 0;
 | |
|     fpServiceThread  = NULL;
 | |
| 
 | |
|     //time-out variables
 | |
|     nStartTimeOut    = 15000;
 | |
|     nStopTimeOut     = 86400000;
 | |
|     nPauseTimeOut    = 5000;
 | |
|     nResumeTimeOut   = 5000;
 | |
| 
 | |
|     //install variables
 | |
|     dwDesiredAccess  = SERVICE_ALL_ACCESS;
 | |
|     dwServiceType    = SERVICE_WIN32_OWN_PROCESS;
 | |
|     dwStartType      = SERVICE_AUTO_START;
 | |
|     dwErrorControl   = SERVICE_ERROR_NORMAL;
 | |
|     szLoadOrderGroup = NULL;
 | |
|     lpdwTagID	     = NULL;
 | |
|     szDependencies   = NULL;
 | |
| 
 | |
|     my_argc	     = 0;
 | |
|     my_argv	     = NULL;
 | |
|     hShutdownEvent   = 0;
 | |
|     nError	     = 0;
 | |
|     dwState	     = 0;
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| NTService::~NTService()
 | |
| {
 | |
|   if (ServiceName != NULL) delete[] ServiceName;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| BOOL NTService::GetOS()
 | |
| {
 | |
|   bOsNT = FALSE;
 | |
|   memset(&osVer, 0, sizeof(OSVERSIONINFO));
 | |
|   osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 | |
|   if (GetVersionEx(&osVer))
 | |
|   {
 | |
|     if (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
 | |
|       bOsNT = TRUE;
 | |
|   }
 | |
|   return bOsNT;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|  Init()  Registers the main service thread with the service manager
 | |
| 
 | |
|     ServiceThread - pointer to the main programs entry function
 | |
| 		    when the service is started
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| long NTService::Init(LPCSTR szInternName,void *ServiceThread)
 | |
| {
 | |
| 
 | |
|   pService = this;
 | |
| 
 | |
|   fpServiceThread = (THREAD_FC)ServiceThread;
 | |
|   ServiceName = new char[lstrlen(szInternName)+1];
 | |
|   lstrcpy(ServiceName,szInternName);
 | |
| 
 | |
|   SERVICE_TABLE_ENTRY stb[] =
 | |
|   {
 | |
|     { (char *)szInternName,(LPSERVICE_MAIN_FUNCTION) ServiceMain} ,
 | |
|     { NULL, NULL }
 | |
|   };
 | |
| 
 | |
|   return StartServiceCtrlDispatcher(stb); //register with the Service Manager
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|   Install() - Installs the service with Service manager
 | |
|   nError values:
 | |
| 	0  success
 | |
| 	1  Can't open the Service manager
 | |
| 	2  Failed to create service
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| BOOL NTService::Install(int startType, LPCSTR szInternName,
 | |
| 			LPCSTR szDisplayName,
 | |
| 			LPCSTR szFullPath, LPCSTR szAccountName,
 | |
| 			LPCSTR szPassword)
 | |
| {
 | |
|   BOOL ret_val=FALSE;
 | |
|   SC_HANDLE newService, scm;
 | |
| 
 | |
|   if (!SeekStatus(szInternName,1))
 | |
|    return FALSE;
 | |
| 
 | |
|   char szFilePath[_MAX_PATH];
 | |
|   GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
 | |
| 
 | |
|   // open a connection to the SCM
 | |
|   if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
 | |
|     printf("Failed to install the service (Couldn't open the SCM)\n");
 | |
|   else 				// Install the new service
 | |
|   {
 | |
|     if (!(newService=
 | |
| 	  CreateService(scm,
 | |
| 			szInternName,
 | |
| 			szDisplayName,
 | |
| 			dwDesiredAccess,//default: SERVICE_ALL_ACCESS
 | |
| 			dwServiceType,	//default: SERVICE_WIN32_OWN_PROCESS
 | |
| 		    			//default: SERVICE_AUTOSTART
 | |
| 			(startType == 1 ? SERVICE_AUTO_START :
 | |
| 			 SERVICE_DEMAND_START),
 | |
| 			dwErrorControl,	//default: SERVICE_ERROR_NORMAL
 | |
| 			szFullPath,	//exec full path
 | |
| 			szLoadOrderGroup, //default: NULL
 | |
| 			lpdwTagID,	//default: NULL
 | |
| 			szDependencies,	//default: NULL
 | |
| 			szAccountName,	//default: NULL
 | |
| 			szPassword)))	//default: NULL
 | |
|       printf("Failed to install the service (Couldn't create service)\n");
 | |
|      else
 | |
|      {
 | |
|        printf("Service successfully installed.\n");
 | |
|        CloseServiceHandle(newService);
 | |
|        ret_val=TRUE;				// Everything went ok
 | |
|      }
 | |
|      CloseServiceHandle(scm);
 | |
|   }
 | |
|   return ret_val;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|   Remove() - Removes  the service
 | |
|   nError values:
 | |
| 	0  success
 | |
| 	1  Can't open the Service manager
 | |
| 	2  Failed to locate service
 | |
| 	3  Failed to delete service
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| BOOL NTService::Remove(LPCSTR szInternName)
 | |
| {
 | |
|   BOOL ret_value=FALSE;
 | |
|   SC_HANDLE service, scm;
 | |
| 
 | |
|   if (!SeekStatus(szInternName,0))
 | |
|    return FALSE;
 | |
| 
 | |
|   nError=0;
 | |
| 
 | |
|   // open a connection to the SCM
 | |
|   if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
 | |
|   {
 | |
|     printf("Failed to remove the service (Couldn't open the SCM)\n");
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     if ((service = OpenService(scm,szInternName, DELETE)))
 | |
|     {
 | |
|       if (!DeleteService(service))
 | |
|         printf("Failed to remove the service\n");
 | |
|       else
 | |
|       {
 | |
|         printf("Service successfully removed.\n");
 | |
| 	ret_value=TRUE;				// everything went ok
 | |
|       }
 | |
|       CloseServiceHandle(service);
 | |
|     }
 | |
|     else
 | |
|       printf("Failed to remove the service (Couldn't open the service)\n");
 | |
|     CloseServiceHandle(scm);
 | |
|   }
 | |
|   return ret_value;
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|    Stop() - this function should be called before the app. exits to stop
 | |
| 	    the service
 | |
|  -------------------------------------------------------------------------- */
 | |
| void NTService::Stop(void)
 | |
| {
 | |
|   SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1, 60000);
 | |
|   StopService();
 | |
|   SetStatus(SERVICE_STOPPED, NO_ERROR, 0, 1, 1000);
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|   ServiceMain() - This is the function that is called from the
 | |
| 		  service manager to start the service
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
 | |
| {
 | |
| 
 | |
|   // registration function
 | |
|   if (!(pService->hServiceStatusHandle =
 | |
| 	RegisterServiceCtrlHandler(pService->ServiceName,
 | |
| 				   (LPHANDLER_FUNCTION)
 | |
| 				   NTService::ServiceCtrlHandler)))
 | |
|     goto error;
 | |
| 
 | |
|   // notify SCM of progress
 | |
|   if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 1, 8000))
 | |
|     goto error;
 | |
| 
 | |
|   // create the exit event
 | |
|   if (!(pService->hExitEvent = CreateEvent (0, TRUE, FALSE,0)))
 | |
|     goto error;
 | |
| 
 | |
|   if (!pService->SetStatus(SERVICE_START_PENDING,NO_ERROR, 0, 3,
 | |
| 			   pService->nStartTimeOut))
 | |
|     goto error;
 | |
| 
 | |
|   // save start arguments
 | |
|   pService->my_argc=argc;
 | |
|   pService->my_argv=argv;
 | |
| 
 | |
|   // start the service
 | |
|   if (!pService->StartService())
 | |
|     goto error;
 | |
| 
 | |
|   // Check that the service is now running.
 | |
|   if (!pService->SetStatus(SERVICE_RUNNING,NO_ERROR, 0, 0, 0))
 | |
|     goto error;
 | |
| 
 | |
|   // wait for exit event
 | |
|   WaitForSingleObject (pService->hExitEvent, INFINITE);
 | |
| 
 | |
|   // wait for thread to exit
 | |
|   if (WaitForSingleObject (pService->hThreadHandle, INFINITE) == WAIT_TIMEOUT)
 | |
|    CloseHandle(pService->hThreadHandle);
 | |
| 
 | |
|   pService->Exit(0);
 | |
|   return;
 | |
| 
 | |
| error:
 | |
|   pService->Exit(GetLastError());
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
|    StartService() - starts the appliaction thread
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| BOOL NTService::StartService()
 | |
| {
 | |
|   // Start the real service's thread (application)
 | |
|   if (!(hThreadHandle = (HANDLE) _beginthread((THREAD_FC)fpServiceThread,0,
 | |
| 					      (void *) this)))
 | |
|     return FALSE;
 | |
|   bRunning = TRUE;
 | |
|   return TRUE;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| void NTService::StopService()
 | |
| {
 | |
|   bRunning=FALSE;
 | |
| 
 | |
|   // Set the event for application
 | |
|   if (hShutdownEvent)
 | |
|      SetEvent(hShutdownEvent);
 | |
| 
 | |
|   // Set the event for ServiceMain
 | |
|   SetEvent(hExitEvent);
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| void NTService::PauseService()
 | |
| {
 | |
|   bPause = TRUE;
 | |
|   SuspendThread(hThreadHandle);
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| void NTService::ResumeService()
 | |
| {
 | |
|   bPause=FALSE;
 | |
|   ResumeThread(hThreadHandle);
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| BOOL NTService::SetStatus (DWORD dwCurrentState,DWORD dwWin32ExitCode,
 | |
| 			   DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,
 | |
| 			   DWORD dwWaitHint)
 | |
| {
 | |
|   BOOL bRet;
 | |
|   SERVICE_STATUS serviceStatus;
 | |
| 
 | |
|   dwState=dwCurrentState;
 | |
| 
 | |
|   serviceStatus.dwServiceType	= SERVICE_WIN32_OWN_PROCESS;
 | |
|   serviceStatus.dwCurrentState = dwCurrentState;
 | |
| 
 | |
|   if (dwCurrentState == SERVICE_START_PENDING)
 | |
|     serviceStatus.dwControlsAccepted = 0;	//don't accept control events
 | |
|   else
 | |
|     serviceStatus.dwControlsAccepted =    (SERVICE_ACCEPT_STOP |
 | |
| 					   SERVICE_ACCEPT_PAUSE_CONTINUE |
 | |
| 					   SERVICE_ACCEPT_SHUTDOWN);
 | |
| 
 | |
|   // if a specific exit code is defined,set up the win32 exit code properly
 | |
|   if (dwServiceSpecificExitCode == 0)
 | |
|     serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
 | |
|   else
 | |
|     serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
 | |
| 
 | |
|   serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
 | |
| 
 | |
|   serviceStatus.dwCheckPoint = dwCheckPoint;
 | |
|   serviceStatus.dwWaitHint   = dwWaitHint;
 | |
| 
 | |
|   // Pass the status to the Service Manager
 | |
|   if (!(bRet=SetServiceStatus (hServiceStatusHandle, &serviceStatus)))
 | |
|     StopService();
 | |
| 
 | |
|   return bRet;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| void NTService::ServiceCtrlHandler(DWORD ctrlCode)
 | |
| {
 | |
|   DWORD  dwState;
 | |
| 
 | |
|   if (!pService)
 | |
|     return;
 | |
| 
 | |
|   dwState=pService->dwState;  // get current state
 | |
| 
 | |
|   switch(ctrlCode) {
 | |
| 
 | |
| #ifdef NOT_USED	 /* do we need this ? */
 | |
|   case SERVICE_CONTROL_PAUSE:
 | |
|     if (pService->bRunning && ! pService->bPause)
 | |
|     {
 | |
|       dwState = SERVICE_PAUSED;
 | |
|       pService->SetStatus(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1,
 | |
| 			  pService->nPauseTimeOut);
 | |
|       pService->PauseService();
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case SERVICE_CONTROL_CONTINUE:
 | |
|     if (pService->bRunning && pService->bPause)
 | |
|     {
 | |
|       dwState = SERVICE_RUNNING;
 | |
|       pService->SetStatus(SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1,
 | |
| 			  pService->nResumeTimeOut);
 | |
|       pService->ResumeService();
 | |
|     }
 | |
|     break;
 | |
| #endif
 | |
| 
 | |
|   case SERVICE_CONTROL_SHUTDOWN:
 | |
|   case SERVICE_CONTROL_STOP:
 | |
|     dwState = SERVICE_STOP_PENDING;
 | |
|     pService->SetStatus(SERVICE_STOP_PENDING,NO_ERROR, 0, 1,
 | |
| 			pService->nStopTimeOut);
 | |
|     pService->StopService();
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
 | |
|     break;
 | |
|   }
 | |
|   //pService->SetStatus(dwState, NO_ERROR,0, 0, 0);
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| void NTService::Exit(DWORD error)
 | |
| {
 | |
|   if (hExitEvent)
 | |
|     CloseHandle(hExitEvent);
 | |
| 
 | |
|   // Send a message to the scm to tell that we stop
 | |
|   if (hServiceStatusHandle)
 | |
|     SetStatus(SERVICE_STOPPED, error,0, 0, 0);
 | |
| 
 | |
|   // If the thread has started kill it ???
 | |
|   // if (hThreadHandle) CloseHandle(hThreadHandle);
 | |
| 
 | |
| }
 | |
| 
 | |
| /* ------------------------------------------------------------------------
 | |
| 
 | |
|  -------------------------------------------------------------------------- */
 | |
| 
 | |
| BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType)
 | |
| {
 | |
|   BOOL ret_value=FALSE;
 | |
|   SC_HANDLE service, scm;
 | |
| 
 | |
|   // open a connection to the SCM
 | |
|   if (!(scm = OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
 | |
|   {
 | |
|     DWORD ret_error=GetLastError();
 | |
|     if (ret_error == ERROR_ACCESS_DENIED)
 | |
|     {
 | |
|      printf("Install/Remove of the Service Denied!\n");
 | |
|      if (!is_super_user())
 | |
|       printf("That operation should be made by an user with Administrator privileges!\n");
 | |
|     }
 | |
|     else
 | |
|      printf("There is a problem for to open the Service Control Manager!\n");
 | |
|   }
 | |
|   else
 | |
|   {
 | |
|     if (OperationType == 1)
 | |
|     {
 | |
|       /* an install operation */
 | |
|       if ((service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
 | |
|       {
 | |
| 	LPQUERY_SERVICE_CONFIG ConfigBuf;
 | |
| 	DWORD dwSize;
 | |
| 
 | |
| 	ConfigBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 4096);
 | |
| 	printf("The service already exists!\n");
 | |
| 	if (QueryServiceConfig(service,ConfigBuf,4096,&dwSize))
 | |
| 	  printf("The current server installed: %s\n",
 | |
| 		 ConfigBuf->lpBinaryPathName);
 | |
| 	LocalFree(ConfigBuf);
 | |
| 	CloseServiceHandle(service);
 | |
|       }
 | |
|       else
 | |
| 	ret_value=TRUE;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       /* a remove operation */
 | |
|       if (!(service = OpenService(scm,szInternName, SERVICE_ALL_ACCESS )))
 | |
| 	printf("The service doesn't exist!\n");
 | |
|       else
 | |
|       {
 | |
| 	SERVICE_STATUS ss;
 | |
| 
 | |
| 	memset(&ss, 0, sizeof(ss));
 | |
| 	if (QueryServiceStatus(service,&ss))
 | |
| 	{
 | |
| 	  DWORD dwState = ss.dwCurrentState;
 | |
| 	  if (dwState == SERVICE_RUNNING)
 | |
| 	    printf("Failed to remove the service because the service is running\nStop the service and try again\n");
 | |
| 	  else if (dwState == SERVICE_STOP_PENDING)
 | |
| 	    printf("\
 | |
| Failed to remove the service because the service is in stop pending state!\n\
 | |
| Wait 30 seconds and try again.\n\
 | |
| If this condition persist, reboot the machine and try again\n");
 | |
| 	  else
 | |
| 	    ret_value= TRUE;
 | |
| 	}
 | |
| 	CloseServiceHandle(service);
 | |
|       }
 | |
|     }
 | |
|     CloseServiceHandle(scm);
 | |
|   }
 | |
| 
 | |
|   return ret_value;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
|  -------------------------------------------------------------------------- */
 | |
| BOOL NTService::IsService(LPCSTR ServiceName)
 | |
| {
 | |
|   BOOL ret_value=FALSE;
 | |
|   SC_HANDLE service, scm;
 | |
|   
 | |
|   if ((scm= OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE)))
 | |
|   {
 | |
|     if ((service = OpenService(scm,ServiceName, SERVICE_QUERY_STATUS)))
 | |
|     {
 | |
|       ret_value=TRUE;
 | |
|       CloseServiceHandle(service);
 | |
|     }
 | |
|     CloseServiceHandle(scm);
 | |
|   }
 | |
|   return ret_value;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
|  -------------------------------------------------------------------------- */
 | |
| BOOL NTService::got_service_option(char **argv, char *service_option)
 | |
| {
 | |
|   char *option;
 | |
|   for (option= argv[1]; *option; option++)
 | |
|     if (!strcmp(option, service_option))
 | |
|       return TRUE;
 | |
|   return FALSE;
 | |
| }
 | |
| /* ------------------------------------------------------------------------
 | |
|  -------------------------------------------------------------------------- */
 | |
| BOOL NTService::is_super_user()
 | |
| {
 | |
|   HANDLE hAccessToken;
 | |
|   UCHAR InfoBuffer[1024];
 | |
|   PTOKEN_GROUPS ptgGroups=(PTOKEN_GROUPS)InfoBuffer;
 | |
|   DWORD dwInfoBufferSize;
 | |
|   PSID psidAdministrators;
 | |
|   SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
 | |
|   UINT x;
 | |
|   BOOL ret_value=FALSE;
 | |
|  
 | |
|   if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken ))
 | |
|   {
 | |
|    if (GetLastError() != ERROR_NO_TOKEN)
 | |
|      return FALSE;
 | |
|  
 | |
|    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken))
 | |
|      return FALSE;
 | |
|   }
 | |
|  
 | |
|   ret_value= GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
 | |
|                                  1024, &dwInfoBufferSize);
 | |
| 
 | |
|   CloseHandle(hAccessToken);
 | |
|  
 | |
|   if (!ret_value )
 | |
|     return FALSE;
 | |
|  
 | |
|   if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
 | |
| 				SECURITY_BUILTIN_DOMAIN_RID,
 | |
| 				DOMAIN_ALIAS_RID_ADMINS,
 | |
| 				0, 0, 0, 0, 0, 0,
 | |
| 				&psidAdministrators))
 | |
|     return FALSE;
 | |
| 
 | |
|   ret_value = FALSE;
 | |
|  
 | |
|   for (x=0;x<ptgGroups->GroupCount;x++)
 | |
|   {
 | |
|    if ( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
 | |
|    {
 | |
|     ret_value = TRUE;
 | |
|     break;
 | |
|    }
 | |
|  
 | |
|   }
 | |
|   FreeSid(psidAdministrators);
 | |
|   return ret_value;
 | |
| }
 | 
