2 * Copyright 2001-2010 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
21 #include "config_win32.h"
23 #define _CRT_NONSTDC_NO_DEPRECATE 1
24 #define _CRT_SECURE_NO_DEPRECATE 1
26 #include <shibsp/base.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 const char* shar_prefix;
36 extern bool shar_checkonly;
39 SERVICE_STATUS ssStatus; // current status of the service
40 SERVICE_STATUS_HANDLE sshStatusHandle;
42 BOOL bConsole = FALSE;
44 LPCSTR lpszInstall = nullptr;
45 LPCSTR lpszRemove = nullptr;
47 // internal function prototypes
48 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
49 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
50 VOID CmdInstallService(LPCSTR);
51 VOID CmdRemoveService(LPCSTR);
52 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
55 LPCTSTR lpUNCServerName,
61 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
63 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
64 void AddToMessageLog(LPSTR lpszMsg);
66 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
70 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
71 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
79 int real_main(int); // The revised two-phase main() in shar.cpp
81 int main(int argc, char *argv[])
84 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
86 if (_stricmp("install", argv[i]+1) == 0)
89 lpszInstall = argv[i++];
91 else if (_stricmp("remove", argv[i]+1) == 0)
94 lpszRemove = argv[i++];
96 else if (_stricmp( "console", argv[i]+1) == 0)
101 else if (_stricmp( "check", argv[i]+1) == 0)
107 else if (_stricmp( "config", argv[i]+1) == 0)
110 shar_config = argv[i++];
112 else if (_stricmp( "prefix", argv[i]+1) == 0)
115 shar_prefix = argv[i++];
117 else if (_stricmp( "catalogs", argv[i]+1) == 0)
120 shar_schemadir = argv[i++];
130 // Install break handler, then run the C routine twice, once to setup, once to start running.
131 SetConsoleCtrlHandler(&BreakHandler,TRUE);
132 if ((i=real_main(1))!=0)
134 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
139 else if (lpszInstall)
141 CmdInstallService(lpszInstall);
146 CmdRemoveService(lpszRemove);
151 // if it doesn't match any of the above parameters
152 // the service control manager may be starting the service
153 // so we must call StartServiceCtrlDispatcher
155 // this is just to be friendly
156 printf("%s -install <name> to install the named service\n", argv[0]);
157 printf("%s -remove <name> to remove the named service\n", argv[0]);
158 printf("%s -console to run as a console app for debugging\n", argv[0]);
159 printf("%s -check to run as a console app and check configuration\n", argv[0]);
160 printf("\t-prefix <dir> to specify the installation directory\n");
161 printf("\t-config <file> to specify the config file to use\n");
162 printf("\t-catalogs <catalog1:catalog2> to specify schema catalogs\n");
163 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
165 SERVICE_TABLE_ENTRY dispatchTable[] =
167 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
171 if (!StartServiceCtrlDispatcher(dispatchTable))
172 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "StartServiceCtrlDispatcher failed.");
177 // FUNCTION: ServiceStart
179 // PURPOSE: Actual code of the service
180 // that does the work.
182 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
187 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
191 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7700, nullptr, "shibd started successfully.");
193 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
201 // FUNCTION: ServiceStop
203 // PURPOSE: Stops the service
208 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7701, nullptr, "shibd stopping...");
213 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
216 // register our service control handler:
217 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
218 if (!sshStatusHandle)
221 // SERVICE_STATUS members that don't change in example
222 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
223 ssStatus.dwServiceSpecificExitCode = 0;
226 // report the status to the service control manager.
227 if (!ReportStatusToSCMgr(
228 SERVICE_START_PENDING, // service state
229 NO_ERROR, // exit code
234 ServiceStart(dwArgc, lpszArgv);
238 // try to report the stopped status to the service control manager.
241 (VOID)ReportStatusToSCMgr(
251 // FUNCTION: service_ctrl
253 // PURPOSE: This function is called by the SCM whenever
254 // ControlService() is called on this service.
257 // dwCtrlCode - type of control requested
262 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
264 // Handle the requested control code.
270 case SERVICE_CONTROL_STOP:
271 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
275 // Update the service status.
277 case SERVICE_CONTROL_INTERROGATE:
280 // invalid control code
287 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
292 // FUNCTION: ReportStatusToSCMgr()
294 // PURPOSE: Sets the current status of the service and
295 // reports it to the Service Control Manager
298 // dwCurrentState - the state of the service
299 // dwWin32ExitCode - error code to report
300 // dwWaitHint - worst case estimate to next checkpoint
306 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
307 DWORD dwWin32ExitCode,
310 static DWORD dwCheckPoint = 1;
314 if (!bConsole) // when console we don't report to the SCM
316 if (dwCurrentState == SERVICE_START_PENDING)
317 ssStatus.dwControlsAccepted = 0;
319 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
321 ssStatus.dwCurrentState = dwCurrentState;
322 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
323 ssStatus.dwWaitHint = dwWaitHint;
325 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
326 ( dwCurrentState == SERVICE_STOPPED ) )
327 ssStatus.dwCheckPoint = 0;
329 ssStatus.dwCheckPoint = dwCheckPoint++;
332 // Report the status of the service to the service control manager.
334 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
335 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "SetServiceStatus failed.");
341 ///////////////////////////////////////////////////////////////////
343 // The following code handles service installation and removal
346 void CmdInstallService(LPCSTR name)
348 SC_HANDLE schService;
349 SC_HANDLE schSCManager;
353 if ( GetModuleFileName( nullptr, szPath, 256 ) == 0 )
355 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
359 string dispName = string("Shibboleth 2 Daemon (") + name + ")";
360 string realName = string("shibd_") + name;
363 cmd = cmd + " -prefix " + shar_prefix;
365 cmd = cmd + " -config " + shar_config;
367 cmd = cmd + " -schemadir " + shar_schemadir;
369 schSCManager = OpenSCManager(
370 nullptr, // machine (nullptr == local)
371 nullptr, // database (nullptr == default)
372 SC_MANAGER_ALL_ACCESS // access required
378 schService = CreateService(
379 schSCManager, // SCManager database
380 realName.c_str(), // name of service
381 dispName.c_str(), // name to display
382 SERVICE_ALL_ACCESS, // desired access
383 SERVICE_WIN32_OWN_PROCESS, // service type
384 SERVICE_AUTO_START, // start type
385 SERVICE_ERROR_NORMAL, // error control type
386 cmd.c_str(), // service's command line
387 nullptr, // no load ordering group
388 nullptr, // no tag identifier
389 nullptr, // dependencies
390 nullptr, // LocalSystem account
391 nullptr); // no password
395 printf("%s installed.\n", realName.c_str());
396 CloseServiceHandle(schService);
400 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
403 CloseServiceHandle(schSCManager);
406 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
409 void CmdRemoveService(LPCSTR name)
411 SC_HANDLE schService;
412 SC_HANDLE schSCManager;
415 _snprintf(realName,sizeof(realName),"shibd_%s",name);
417 schSCManager = OpenSCManager(
418 nullptr, // machine (nullptr == local)
419 nullptr, // database (nullptr == default)
420 SC_MANAGER_ALL_ACCESS // access required
424 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
428 // try to stop the service
429 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
431 printf("Stopping shibd (%s).", name);
434 while( QueryServiceStatus( schService, &ssStatus ) )
436 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
445 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
446 printf("\n%s stopped.\n", realName);
448 printf("\n%s failed to stop.\n", realName);
452 // now remove the service
453 if( DeleteService(schService) )
454 printf("%s removed.\n", realName);
456 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
459 CloseServiceHandle(schService);
462 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
464 CloseServiceHandle(schSCManager);
467 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
472 // FUNCTION: GetLastErrorText
474 // PURPOSE: copies error message text to string
477 // lpszBuf - destination buffer
478 // dwSize - size of buffer
481 // destination buffer
485 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
488 LPSTR lpszTemp = nullptr;
490 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
498 // supplied buffer is not long enough
499 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
503 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
504 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
508 LocalFree((HLOCAL) lpszTemp );
514 LPCSTR lpUNCServerName,
520 LPCSTR messages[] = {message, nullptr};
522 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
523 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
524 return (DeregisterEventSource(hElog) && res);