2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution, if any, must include
17 * the following acknowledgment: "This product includes software developed by
18 * the University Corporation for Advanced Internet Development
19 * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20 * may appear in the software itself, if and wherever such third-party
21 * acknowledgments normally appear.
23 * Neither the name of Shibboleth nor the names of its contributors, nor
24 * Internet2, nor the University Corporation for Advanced Internet Development,
25 * Inc., nor UCAID may be used to endorse or promote products derived from this
26 * software without specific prior written permission. For written permission,
27 * please contact shibboleth@shibboleth.org
29 * Products derived from this software may not be called Shibboleth, Internet2,
30 * UCAID, or the University Corporation for Advanced Internet Development, nor
31 * may Shibboleth appear in their name, without prior written permission of the
32 * University Corporation for Advanced Internet Development.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 * shar_win32.cpp -- the SHAR "main" code on Win32
53 * Created By: Scott Cantor (cantor.2@osu.edu)
58 #include "config_win32.h"
59 #include "shar-utils.h"
61 extern int shar_run; // signals shutdown to Unix side
62 extern const char* shar_schemadir;
63 extern const char* shar_config;
64 extern bool shar_checkonly;
67 SERVICE_STATUS ssStatus; // current status of the service
68 SERVICE_STATUS_HANDLE sshStatusHandle;
70 BOOL bConsole = FALSE;
72 LPCSTR lpszInstall = NULL;
73 LPCSTR lpszRemove = NULL;
75 // internal function prototypes
76 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
77 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
78 VOID CmdInstallService(LPCSTR);
79 VOID CmdRemoveService(LPCSTR);
80 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
83 LPCTSTR lpUNCServerName,
89 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
91 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
92 void AddToMessageLog(LPSTR lpszMsg);
94 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
98 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
99 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
107 int real_main(int); // The revised two-phase main() in shar.cpp
109 int main(int argc, char *argv[])
112 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
114 if (_stricmp("install", argv[i]+1) == 0)
117 lpszInstall = argv[i++];
119 else if (_stricmp("remove", argv[i]+1) == 0)
122 lpszRemove = argv[i++];
124 else if (_stricmp( "console", argv[i]+1) == 0)
129 else if (_stricmp( "check", argv[i]+1) == 0)
135 else if (_stricmp( "config", argv[i]+1) == 0)
138 shar_config = argv[i++];
140 else if (_stricmp( "schemadir", argv[i]+1) == 0)
143 shar_schemadir = argv[i++];
153 // Install break handler, then run the C routine twice, once to setup, once to start running.
154 SetConsoleCtrlHandler(&BreakHandler,TRUE);
157 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
162 else if (lpszInstall)
164 CmdInstallService(lpszInstall);
169 CmdRemoveService(lpszRemove);
174 // if it doesn't match any of the above parameters
175 // the service control manager may be starting the service
176 // so we must call StartServiceCtrlDispatcher
178 // this is just to be friendly
179 printf("%s -install <name> to install the named service\n", argv[0]);
180 printf("%s -remove <name> to remove the named service\n", argv[0]);
181 printf("%s -console to run as a console app for debugging\n", argv[0]);
182 printf("%s -check to run as a console app and check configuration\n", argv[0]);
183 printf("\t-config <file> to specify the config file to use\n");
184 printf("\t-schemadir <dir> to specify where schemas are\n");
185 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
187 SERVICE_TABLE_ENTRY dispatchTable[] =
189 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
193 if (!StartServiceCtrlDispatcher(dispatchTable))
194 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "StartServiceCtrlDispatcher failed.");
199 // FUNCTION: ServiceStart
201 // PURPOSE: Actual code of the service
202 // that does the work.
204 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
209 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
213 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7700, NULL, "shibd started successfully.");
215 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
223 // FUNCTION: ServiceStop
225 // PURPOSE: Stops the service
230 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7701, NULL, "shibd stopping...");
235 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
238 // register our service control handler:
239 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
240 if (!sshStatusHandle)
243 // SERVICE_STATUS members that don't change in example
244 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
245 ssStatus.dwServiceSpecificExitCode = 0;
248 // report the status to the service control manager.
249 if (!ReportStatusToSCMgr(
250 SERVICE_START_PENDING, // service state
251 NO_ERROR, // exit code
256 ServiceStart(dwArgc, lpszArgv);
260 // try to report the stopped status to the service control manager.
263 (VOID)ReportStatusToSCMgr(
273 // FUNCTION: service_ctrl
275 // PURPOSE: This function is called by the SCM whenever
276 // ControlService() is called on this service.
279 // dwCtrlCode - type of control requested
284 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
286 // Handle the requested control code.
292 case SERVICE_CONTROL_STOP:
293 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
297 // Update the service status.
299 case SERVICE_CONTROL_INTERROGATE:
302 // invalid control code
309 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
314 // FUNCTION: ReportStatusToSCMgr()
316 // PURPOSE: Sets the current status of the service and
317 // reports it to the Service Control Manager
320 // dwCurrentState - the state of the service
321 // dwWin32ExitCode - error code to report
322 // dwWaitHint - worst case estimate to next checkpoint
328 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
329 DWORD dwWin32ExitCode,
332 static DWORD dwCheckPoint = 1;
336 if (!bConsole) // when console we don't report to the SCM
338 if (dwCurrentState == SERVICE_START_PENDING)
339 ssStatus.dwControlsAccepted = 0;
341 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
343 ssStatus.dwCurrentState = dwCurrentState;
344 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
345 ssStatus.dwWaitHint = dwWaitHint;
347 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
348 ( dwCurrentState == SERVICE_STOPPED ) )
349 ssStatus.dwCheckPoint = 0;
351 ssStatus.dwCheckPoint = dwCheckPoint++;
354 // Report the status of the service to the service control manager.
356 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
357 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "SetServiceStatus failed.");
363 ///////////////////////////////////////////////////////////////////
365 // The following code handles service installation and removal
368 void CmdInstallService(LPCSTR name)
370 SC_HANDLE schService;
371 SC_HANDLE schSCManager;
378 if ( GetModuleFileName( NULL, szPath, 256 ) == 0 )
380 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
384 sprintf(dispName,"Shibboleth %s Daemon (%s)",PACKAGE_VERSION,name);
385 sprintf(realName,"shibd_%s",name);
386 if (shar_config && shar_schemadir)
387 sprintf(cmd,"%s -config %s -schemadir %s",szPath,shar_config,shar_schemadir);
388 else if (shar_config)
389 sprintf(cmd,"%s -config %s",szPath,shar_config);
390 else if (shar_schemadir)
391 sprintf(cmd,"%s -schemadir %s",szPath,shar_schemadir);
393 sprintf(cmd,"%s",szPath);
395 schSCManager = OpenSCManager(
396 NULL, // machine (NULL == local)
397 NULL, // database (NULL == default)
398 SC_MANAGER_ALL_ACCESS // access required
404 schService = CreateService(
405 schSCManager, // SCManager database
406 realName, // name of service
407 dispName, // name to display
408 SERVICE_ALL_ACCESS, // desired access
409 SERVICE_WIN32_OWN_PROCESS, // service type
410 SERVICE_AUTO_START, // start type
411 SERVICE_ERROR_NORMAL, // error control type
412 cmd, // service's command line
413 NULL, // no load ordering group
414 NULL, // no tag identifier
415 NULL, // dependencies
416 NULL, // LocalSystem account
417 NULL); // no password
421 printf("%s installed.\n",realName);
422 CloseServiceHandle(schService);
426 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
429 CloseServiceHandle(schSCManager);
432 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
435 void CmdRemoveService(LPCSTR name)
437 SC_HANDLE schService;
438 SC_HANDLE schSCManager;
441 sprintf(realName,"shibd_%s",name);
443 schSCManager = OpenSCManager(
444 NULL, // machine (NULL == local)
445 NULL, // database (NULL == default)
446 SC_MANAGER_ALL_ACCESS // access required
450 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
454 // try to stop the service
455 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
457 printf("Stopping shibd (%s).", name);
460 while( QueryServiceStatus( schService, &ssStatus ) )
462 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
471 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
472 printf("\n%s stopped.\n", realName);
474 printf("\n%s failed to stop.\n", realName);
478 // now remove the service
479 if( DeleteService(schService) )
480 printf("%s removed.\n", realName);
482 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
485 CloseServiceHandle(schService);
488 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
490 CloseServiceHandle(schSCManager);
493 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
498 // FUNCTION: GetLastErrorText
500 // PURPOSE: copies error message text to string
503 // lpszBuf - destination buffer
504 // dwSize - size of buffer
507 // destination buffer
511 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
514 LPSTR lpszTemp = NULL;
516 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
524 // supplied buffer is not long enough
525 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
529 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
530 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
534 LocalFree((HLOCAL) lpszTemp );
540 LPCSTR lpUNCServerName,
546 LPCSTR messages[] = {message, NULL};
548 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
549 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);
550 return (DeregisterEventSource(hElog) && res);