7 #include "ldap_pvt_thread.h"
10 #include <ac/string.h>
12 #include "ldap_defaults.h"
16 #define SCM_NOTIFICATION_INTERVAL 5000
17 #define THIRTY_SECONDS (30 * 1000)
19 int is_NT_Service = 1; /* assume this is an NT service until determined that */
20 /* startup was from the command line */
22 SERVICE_STATUS SLAPDServiceStatus;
23 SERVICE_STATUS_HANDLE hSLAPDServiceStatus;
25 ldap_pvt_thread_cond_t started_event, stopped_event;
26 ldap_pvt_thread_t start_status_tid, stop_status_tid;
28 void (*stopfunc)(int);
31 void WINAPI ServiceMain( DWORD argc, LPTSTR *argv );
35 char *WSAGetLastErrorString( void );
38 char *GetLastErrorString( void );
40 int srv_install(LPCTSTR lpszServiceName, LPCTSTR lpszBinaryPathName)
43 DWORD dwValue, dwDisposition;
44 SC_HANDLE schSCManager, schService;
46 fprintf( stderr, "The install path is %s.\n", lpszBinaryPathName );
47 if ((schSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE ) ) != NULL )
49 if ((schService = CreateService(
52 TEXT("OpenLDAP Directory Service"),
53 SC_MANAGER_CREATE_SERVICE,
54 SERVICE_WIN32_OWN_PROCESS,
58 NULL, NULL, NULL, NULL, NULL)) != NULL)
61 CloseServiceHandle(schService);
62 CloseServiceHandle(schSCManager);
64 sprintf( regpath, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s",
66 /* Create the registry key for event logging to the Windows NT event log. */
67 if ( RegCreateKeyEx(HKEY_LOCAL_MACHINE,
69 "REG_SZ", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey,
70 &dwDisposition) != ERROR_SUCCESS)
72 fprintf( stderr, "RegCreateKeyEx() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
76 if ( RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, lpszBinaryPathName, strlen(lpszBinaryPathName) + 1) != ERROR_SUCCESS)
78 fprintf( stderr, "RegSetValueEx(EventMessageFile) failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
83 dwValue = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
84 if ( RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwValue, sizeof(DWORD)) != ERROR_SUCCESS)
86 fprintf( stderr, "RegCreateKeyEx(TypesSupported) failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
95 fprintf( stderr, "CreateService() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
96 CloseServiceHandle(schSCManager);
101 fprintf( stderr, "OpenSCManager() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
106 int srv_remove(LPCTSTR lpszServiceName, LPCTSTR lpszBinaryPathName)
108 SC_HANDLE schSCManager, schService;
110 fprintf( stderr, "The installed path is %s.\n", lpszBinaryPathName );
111 if ((schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT|SC_MANAGER_CREATE_SERVICE)) != NULL )
113 if ((schService = OpenService(schSCManager, lpszServiceName, DELETE)) != NULL)
115 if ( DeleteService(schService) == TRUE)
117 CloseServiceHandle(schService);
118 CloseServiceHandle(schSCManager);
121 fprintf( stderr, "DeleteService() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
122 fprintf( stderr, "The %s service has not been removed.\n", lpszBinaryPathName);
123 CloseServiceHandle(schService);
124 CloseServiceHandle(schSCManager);
128 fprintf( stderr, "OpenService() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
129 CloseServiceHandle(schSCManager);
134 fprintf( stderr, "OpenSCManager() failed. GetLastError=%d (%s)\n", GetLastError(), GetLastErrorString() );
140 static void *start_status_routine( void *ptr )
147 wait_result = WaitForSingleObject( started_event, SCM_NOTIFICATION_INTERVAL );
148 switch ( wait_result )
152 /* the object that we were waiting for has been destroyed (ABANDONED) or
153 * signalled (TIMEOUT_0). We can assume that the startup process is
154 * complete and tell the Service Control Manager that we are now runnng */
155 SLAPDServiceStatus.dwCurrentState = SERVICE_RUNNING;
156 SLAPDServiceStatus.dwWin32ExitCode = NO_ERROR;
157 SLAPDServiceStatus.dwCheckPoint++;
158 SLAPDServiceStatus.dwWaitHint = 1000;
159 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
163 /* We've waited for the required time, so send an update to the Service Control
164 * Manager saying to wait again. */
165 SLAPDServiceStatus.dwCheckPoint++;
166 SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
167 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
170 /* theres been some proble with WaitForSingleObject so tell the Service
171 * Control Manager to wait 30 seconds before deploying its assasin and
172 * then leave the thread. */
173 SLAPDServiceStatus.dwCheckPoint++;
174 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
175 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
180 ldap_pvt_thread_exit(NULL);
186 static void *stop_status_routine( void *ptr )
193 wait_result = WaitForSingleObject( stopped_event, SCM_NOTIFICATION_INTERVAL );
194 switch ( wait_result )
198 /* the object that we were waiting for has been destroyed (ABANDONED) or
199 * signalled (TIMEOUT_0). The shutting down process is therefore complete
200 * and the final SERVICE_STOPPED message will be sent to the service control
201 * manager prior to the process terminating. */
205 /* We've waited for the required time, so send an update to the Service Control
206 * Manager saying to wait again. */
207 SLAPDServiceStatus.dwCheckPoint++;
208 SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
209 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
212 /* theres been some proble with WaitForSingleObject so tell the Service
213 * Control Manager to wait 30 seconds before deploying its assasin and
214 * then leave the thread. */
215 SLAPDServiceStatus.dwCheckPoint++;
216 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
217 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
222 ldap_pvt_thread_exit(NULL);
228 void WINAPI SLAPDServiceCtrlHandler( IN DWORD Opcode)
232 case SERVICE_CONTROL_STOP:
233 case SERVICE_CONTROL_SHUTDOWN:
235 Debug( LDAP_DEBUG_TRACE, "Service Shutdown ordered\n", 0, 0 );
236 SLAPDServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
237 SLAPDServiceStatus.dwCheckPoint++;
238 SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
239 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
241 ldap_pvt_thread_cond_init( &stopped_event );
242 if ( stopped_event == NULL )
244 /* the event was not created. We will ask the service control manager for 30
245 * seconds to shutdown */
246 SLAPDServiceStatus.dwCheckPoint++;
247 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
248 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
252 /* start a thread to report the progress to the service control manager
253 * until the stopped_event is fired. */
254 if ( ldap_pvt_thread_create( &stop_status_tid, 0, stop_status_routine, NULL ) == 0 )
259 /* failed to create the thread that tells the Service Control Manager that the
260 * service stopping is proceeding.
261 * tell the Service Control Manager to wait another 30 seconds before deploying its
263 SLAPDServiceStatus.dwCheckPoint++;
264 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
265 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
271 case SERVICE_CONTROL_INTERROGATE:
272 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
278 void *getRegParam( char *svc, char *value )
283 static char vValue[1024];
284 DWORD valLen = sizeof( vValue );
287 sprintf ( path, "SOFTWARE\\OpenLDAP\\%s\\Parameters", svc );
289 strcpy (path, "SOFTWARE\\OpenLDAP\\Parameters" );
291 if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
293 /*Debug( LDAP_DEBUG_ANY, "RegOpenKeyEx() %s\n", GetLastErrorString(), 0, 0); */
297 if ( RegQueryValueEx( hkey, value, NULL, &vType, vValue, &valLen ) != ERROR_SUCCESS )
299 /*Debug( LDAP_DEBUG_ANY, "RegQueryValueEx() %s\n", GetLastErrorString(), 0, 0 );*/
309 return (void*)&vValue;
311 return (void*)&vValue;
316 void LogSlapdStartedEvent( char *svc, int slap_debug, char *configfile, short port, int udp )
322 hEventLog = RegisterEventSource( NULL, svc );
324 Inserts[i] = (char *)malloc( 20 );
325 itoa( slap_debug, Inserts[i++], 10 );
326 Inserts[i++] = ldap_pvt_strdup( configfile );
327 Inserts[i] = (char *)malloc( 20 );
328 itoa( port, Inserts[i++], 10 );
329 Inserts[i++] = ldap_pvt_strdup( udp ? "udp" : "tcp" );
330 Inserts[i++] = ldap_pvt_strdup( is_NT_Service ? "svc" : "cmd" );
332 ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, MSG_SLAPD_STARTED, NULL, i, 0, Inserts, NULL );
334 for ( j = 0; j < i; j++ )
335 ldap_memfree( Inserts[j] );
336 DeregisterEventSource( hEventLog );
341 void LogSlapdStoppedEvent( char *svc )
345 hEventLog = RegisterEventSource( NULL, svc );
346 ReportEvent( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, MSG_SLAPD_STOPPED, NULL, 0, 0, NULL, NULL );
347 DeregisterEventSource( hEventLog );
351 void CommenceStartupProcessing( LPCTSTR lpszServiceName,
352 void (*stopper)(int) )
354 hSLAPDServiceStatus = RegisterServiceCtrlHandler( lpszServiceName, (LPHANDLER_FUNCTION)SLAPDServiceCtrlHandler);
358 /* initialize the Service Status structure */
359 SLAPDServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
360 SLAPDServiceStatus.dwCurrentState = SERVICE_START_PENDING;
361 SLAPDServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
362 SLAPDServiceStatus.dwWin32ExitCode = NO_ERROR;
363 SLAPDServiceStatus.dwServiceSpecificExitCode = 0;
364 SLAPDServiceStatus.dwCheckPoint = 1;
365 SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL * 2;
367 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
369 /* start up a thread to keep sending SERVICE_START_PENDING to the Service Control Manager
370 * until the slapd listener is completed and listening. Only then should we send
371 * SERVICE_RUNNING to the Service Control Manager. */
372 ldap_pvt_thread_cond_init( &started_event );
373 if ( started_event == NULL)
375 /* failed to create the event to determine when the startup process is complete so
376 * tell the Service Control Manager to wait another 30 seconds before deploying its
378 SLAPDServiceStatus.dwCheckPoint++;
379 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
380 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
384 /* start a thread to report the progress to the service control manager
385 * until the started_event is fired. */
386 if ( ldap_pvt_thread_create( &start_status_tid, 0, start_status_routine, NULL ) == 0 )
391 /* failed to create the thread that tells the Service Control Manager that the
392 * service startup is proceeding.
393 * tell the Service Control Manager to wait another 30 seconds before deploying its
395 SLAPDServiceStatus.dwCheckPoint++;
396 SLAPDServiceStatus.dwWaitHint = THIRTY_SECONDS;
397 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);
402 void ReportSlapdShutdownComplete( )
406 /* stop sending SERVICE_STOP_PENDING messages to the Service Control Manager */
407 ldap_pvt_thread_cond_signal( &stopped_event );
408 ldap_pvt_thread_cond_destroy( &stopped_event );
410 /* wait for the thread sending the SERVICE_STOP_PENDING messages to the Service Control Manager to die.
411 * if the wait fails then put ourselves to sleep for half the Service Control Manager update interval */
412 if (ldap_pvt_thread_join( stop_status_tid, (void *) NULL ) == -1)
413 ldap_pvt_thread_sleep( SCM_NOTIFICATION_INTERVAL / 2 );
415 SLAPDServiceStatus.dwCurrentState = SERVICE_STOPPED;
416 SLAPDServiceStatus.dwCheckPoint++;
417 SLAPDServiceStatus.dwWaitHint = SCM_NOTIFICATION_INTERVAL;
418 SetServiceStatus(hSLAPDServiceStatus, &SLAPDServiceStatus);