2 * Copyright 2001-2007 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * shar_win32.cpp -- the SHAR "main" code on Win32
20 * Created By: Scott Cantor (cantor.2@osu.edu)
25 #include "config_win32.h"
27 #define _CRT_NONSTDC_NO_DEPRECATE 1
28 #define _CRT_SECURE_NO_DEPRECATE 1
30 #include <shib-target/shib-target.h>
32 extern bool shibd_shutdown; // signals shutdown to Unix side
33 extern const char* shar_schemadir;
34 extern const char* shar_config;
35 extern bool shar_checkonly;
38 SERVICE_STATUS ssStatus; // current status of the service
39 SERVICE_STATUS_HANDLE sshStatusHandle;
41 BOOL bConsole = FALSE;
43 LPCSTR lpszInstall = NULL;
44 LPCSTR lpszRemove = NULL;
46 // internal function prototypes
47 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
48 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
49 VOID CmdInstallService(LPCSTR);
50 VOID CmdRemoveService(LPCSTR);
51 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
54 LPCTSTR lpUNCServerName,
60 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
62 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
63 void AddToMessageLog(LPSTR lpszMsg);
65 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
69 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
70 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
78 int real_main(int); // The revised two-phase main() in shar.cpp
80 int main(int argc, char *argv[])
83 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
85 if (_stricmp("install", argv[i]+1) == 0)
88 lpszInstall = argv[i++];
90 else if (_stricmp("remove", argv[i]+1) == 0)
93 lpszRemove = argv[i++];
95 else if (_stricmp( "console", argv[i]+1) == 0)
100 else if (_stricmp( "check", argv[i]+1) == 0)
106 else if (_stricmp( "config", argv[i]+1) == 0)
109 shar_config = argv[i++];
111 else if (_stricmp( "schemadir", argv[i]+1) == 0)
114 shar_schemadir = argv[i++];
124 // Install break handler, then run the C routine twice, once to setup, once to start running.
125 SetConsoleCtrlHandler(&BreakHandler,TRUE);
126 if ((i=real_main(1))!=0)
128 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
133 else if (lpszInstall)
135 CmdInstallService(lpszInstall);
140 CmdRemoveService(lpszRemove);
145 // if it doesn't match any of the above parameters
146 // the service control manager may be starting the service
147 // so we must call StartServiceCtrlDispatcher
149 // this is just to be friendly
150 printf("%s -install <name> to install the named service\n", argv[0]);
151 printf("%s -remove <name> to remove the named service\n", argv[0]);
152 printf("%s -console to run as a console app for debugging\n", argv[0]);
153 printf("%s -check to run as a console app and check configuration\n", argv[0]);
154 printf("\t-config <file> to specify the config file to use\n");
155 printf("\t-schemadir <dir> to specify where schemas are\n");
156 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
158 SERVICE_TABLE_ENTRY dispatchTable[] =
160 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
164 if (!StartServiceCtrlDispatcher(dispatchTable))
165 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "StartServiceCtrlDispatcher failed.");
170 // FUNCTION: ServiceStart
172 // PURPOSE: Actual code of the service
173 // that does the work.
175 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
180 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
184 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7700, NULL, "shibd started successfully.");
186 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
194 // FUNCTION: ServiceStop
196 // PURPOSE: Stops the service
201 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7701, NULL, "shibd stopping...");
206 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
209 // register our service control handler:
210 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
211 if (!sshStatusHandle)
214 // SERVICE_STATUS members that don't change in example
215 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
216 ssStatus.dwServiceSpecificExitCode = 0;
219 // report the status to the service control manager.
220 if (!ReportStatusToSCMgr(
221 SERVICE_START_PENDING, // service state
222 NO_ERROR, // exit code
227 ServiceStart(dwArgc, lpszArgv);
231 // try to report the stopped status to the service control manager.
234 (VOID)ReportStatusToSCMgr(
244 // FUNCTION: service_ctrl
246 // PURPOSE: This function is called by the SCM whenever
247 // ControlService() is called on this service.
250 // dwCtrlCode - type of control requested
255 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
257 // Handle the requested control code.
263 case SERVICE_CONTROL_STOP:
264 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
268 // Update the service status.
270 case SERVICE_CONTROL_INTERROGATE:
273 // invalid control code
280 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
285 // FUNCTION: ReportStatusToSCMgr()
287 // PURPOSE: Sets the current status of the service and
288 // reports it to the Service Control Manager
291 // dwCurrentState - the state of the service
292 // dwWin32ExitCode - error code to report
293 // dwWaitHint - worst case estimate to next checkpoint
299 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
300 DWORD dwWin32ExitCode,
303 static DWORD dwCheckPoint = 1;
307 if (!bConsole) // when console we don't report to the SCM
309 if (dwCurrentState == SERVICE_START_PENDING)
310 ssStatus.dwControlsAccepted = 0;
312 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
314 ssStatus.dwCurrentState = dwCurrentState;
315 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
316 ssStatus.dwWaitHint = dwWaitHint;
318 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
319 ( dwCurrentState == SERVICE_STOPPED ) )
320 ssStatus.dwCheckPoint = 0;
322 ssStatus.dwCheckPoint = dwCheckPoint++;
325 // Report the status of the service to the service control manager.
327 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
328 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "SetServiceStatus failed.");
334 ///////////////////////////////////////////////////////////////////
336 // The following code handles service installation and removal
339 void CmdInstallService(LPCSTR name)
341 SC_HANDLE schService;
342 SC_HANDLE schSCManager;
349 if ( GetModuleFileName( NULL, szPath, 256 ) == 0 )
351 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
355 sprintf(dispName,"Shibboleth %s Daemon (%s)",PACKAGE_VERSION,name);
356 sprintf(realName,"shibd_%s",name);
357 if (shar_config && shar_schemadir)
358 sprintf(cmd,"%s -config %s -schemadir %s",szPath,shar_config,shar_schemadir);
359 else if (shar_config)
360 sprintf(cmd,"%s -config %s",szPath,shar_config);
361 else if (shar_schemadir)
362 sprintf(cmd,"%s -schemadir %s",szPath,shar_schemadir);
364 sprintf(cmd,"%s",szPath);
366 schSCManager = OpenSCManager(
367 NULL, // machine (NULL == local)
368 NULL, // database (NULL == default)
369 SC_MANAGER_ALL_ACCESS // access required
375 schService = CreateService(
376 schSCManager, // SCManager database
377 realName, // name of service
378 dispName, // name to display
379 SERVICE_ALL_ACCESS, // desired access
380 SERVICE_WIN32_OWN_PROCESS, // service type
381 SERVICE_AUTO_START, // start type
382 SERVICE_ERROR_NORMAL, // error control type
383 cmd, // service's command line
384 NULL, // no load ordering group
385 NULL, // no tag identifier
386 NULL, // dependencies
387 NULL, // LocalSystem account
388 NULL); // no password
392 printf("%s installed.\n",realName);
393 CloseServiceHandle(schService);
397 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
400 CloseServiceHandle(schSCManager);
403 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
406 void CmdRemoveService(LPCSTR name)
408 SC_HANDLE schService;
409 SC_HANDLE schSCManager;
412 sprintf(realName,"shibd_%s",name);
414 schSCManager = OpenSCManager(
415 NULL, // machine (NULL == local)
416 NULL, // database (NULL == default)
417 SC_MANAGER_ALL_ACCESS // access required
421 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
425 // try to stop the service
426 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
428 printf("Stopping shibd (%s).", name);
431 while( QueryServiceStatus( schService, &ssStatus ) )
433 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
442 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
443 printf("\n%s stopped.\n", realName);
445 printf("\n%s failed to stop.\n", realName);
449 // now remove the service
450 if( DeleteService(schService) )
451 printf("%s removed.\n", realName);
453 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
456 CloseServiceHandle(schService);
459 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
461 CloseServiceHandle(schSCManager);
464 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
469 // FUNCTION: GetLastErrorText
471 // PURPOSE: copies error message text to string
474 // lpszBuf - destination buffer
475 // dwSize - size of buffer
478 // destination buffer
482 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
485 LPSTR lpszTemp = NULL;
487 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
495 // supplied buffer is not long enough
496 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
500 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
501 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
505 LocalFree((HLOCAL) lpszTemp );
511 LPCSTR lpUNCServerName,
517 LPCSTR messages[] = {message, NULL};
519 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
520 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);
521 return (DeregisterEventSource(hElog) && res);