2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
22 * shar_win32.cpp -- the SHAR "main" code on Win32
25 #include "config_win32.h"
27 #define _CRT_NONSTDC_NO_DEPRECATE 1
28 #define _CRT_SECURE_NO_DEPRECATE 1
30 #include <shibsp/base.h>
36 extern bool shibd_shutdown; // signals shutdown to Unix side
37 extern const char* shar_schemadir;
38 extern const char* shar_config;
39 extern const char* shar_prefix;
40 extern bool shar_checkonly;
43 SERVICE_STATUS ssStatus; // current status of the service
44 SERVICE_STATUS_HANDLE sshStatusHandle;
46 BOOL bConsole = FALSE;
48 LPCSTR lpszInstall = nullptr;
49 LPCSTR lpszRemove = nullptr;
51 // internal function prototypes
52 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
53 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
54 VOID CmdInstallService(LPCSTR);
55 VOID CmdRemoveService(LPCSTR);
56 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
59 LPCTSTR lpUNCServerName,
65 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
67 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
68 void AddToMessageLog(LPSTR lpszMsg);
70 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
74 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
75 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
83 int real_main(int); // The revised two-phase main() in shar.cpp
85 int main(int argc, char *argv[])
88 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
90 if (_stricmp("install", argv[i]+1) == 0)
93 lpszInstall = argv[i++];
95 else if (_stricmp("remove", argv[i]+1) == 0)
98 lpszRemove = argv[i++];
100 else if (_stricmp( "console", argv[i]+1) == 0)
105 else if (_stricmp( "check", argv[i]+1) == 0)
111 else if (_stricmp( "config", argv[i]+1) == 0)
114 shar_config = argv[i++];
116 else if (_stricmp( "prefix", argv[i]+1) == 0)
119 shar_prefix = argv[i++];
121 else if (_stricmp( "catalogs", argv[i]+1) == 0)
124 shar_schemadir = argv[i++];
134 // Install break handler, then run the C routine twice, once to setup, once to start running.
135 SetConsoleCtrlHandler(&BreakHandler,TRUE);
136 if ((i=real_main(1))!=0)
138 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
143 else if (lpszInstall)
145 CmdInstallService(lpszInstall);
150 CmdRemoveService(lpszRemove);
155 // if it doesn't match any of the above parameters
156 // the service control manager may be starting the service
157 // so we must call StartServiceCtrlDispatcher
159 // this is just to be friendly
160 printf("%s -install <name> to install the named service\n", argv[0]);
161 printf("%s -remove <name> to remove the named service\n", argv[0]);
162 printf("%s -console to run as a console app for debugging\n", argv[0]);
163 printf("%s -check to run as a console app and check configuration\n", argv[0]);
164 printf("\t-prefix <dir> to specify the installation directory\n");
165 printf("\t-config <file> to specify the config file to use\n");
166 printf("\t-catalogs <catalog1:catalog2> to specify schema catalogs\n");
167 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
169 SERVICE_TABLE_ENTRY dispatchTable[] =
171 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
175 if (!StartServiceCtrlDispatcher(dispatchTable))
176 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "StartServiceCtrlDispatcher failed.");
181 // FUNCTION: ServiceStart
183 // PURPOSE: Actual code of the service
184 // that does the work.
186 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
191 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
195 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7700, nullptr, "shibd started successfully.");
197 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
205 // FUNCTION: ServiceStop
207 // PURPOSE: Stops the service
212 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7701, nullptr, "shibd stopping...");
217 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
220 // register our service control handler:
221 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
222 if (!sshStatusHandle)
225 // SERVICE_STATUS members that don't change in example
226 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
227 ssStatus.dwServiceSpecificExitCode = 0;
230 // report the status to the service control manager.
231 if (!ReportStatusToSCMgr(
232 SERVICE_START_PENDING, // service state
233 NO_ERROR, // exit code
238 ServiceStart(dwArgc, lpszArgv);
242 // try to report the stopped status to the service control manager.
245 (VOID)ReportStatusToSCMgr(
255 // FUNCTION: service_ctrl
257 // PURPOSE: This function is called by the SCM whenever
258 // ControlService() is called on this service.
261 // dwCtrlCode - type of control requested
266 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
268 // Handle the requested control code.
274 case SERVICE_CONTROL_STOP:
275 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
279 // Update the service status.
281 case SERVICE_CONTROL_INTERROGATE:
284 // invalid control code
291 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
296 // FUNCTION: ReportStatusToSCMgr()
298 // PURPOSE: Sets the current status of the service and
299 // reports it to the Service Control Manager
302 // dwCurrentState - the state of the service
303 // dwWin32ExitCode - error code to report
304 // dwWaitHint - worst case estimate to next checkpoint
310 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
311 DWORD dwWin32ExitCode,
314 static DWORD dwCheckPoint = 1;
318 if (!bConsole) // when console we don't report to the SCM
320 if (dwCurrentState == SERVICE_START_PENDING)
321 ssStatus.dwControlsAccepted = 0;
323 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
325 ssStatus.dwCurrentState = dwCurrentState;
326 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
327 ssStatus.dwWaitHint = dwWaitHint;
329 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
330 ( dwCurrentState == SERVICE_STOPPED ) )
331 ssStatus.dwCheckPoint = 0;
333 ssStatus.dwCheckPoint = dwCheckPoint++;
336 // Report the status of the service to the service control manager.
338 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
339 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "SetServiceStatus failed.");
345 ///////////////////////////////////////////////////////////////////
347 // The following code handles service installation and removal
350 void CmdInstallService(LPCSTR name)
352 SC_HANDLE schService;
353 SC_HANDLE schSCManager;
357 if ( GetModuleFileName( nullptr, szPath, 256 ) == 0 )
359 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
363 string dispName = string("Shibboleth 2 Daemon (") + name + ")";
364 string realName = string("shibd_") + name;
367 cmd = cmd + " -prefix " + shar_prefix;
369 cmd = cmd + " -config " + shar_config;
371 cmd = cmd + " -schemadir " + shar_schemadir;
373 schSCManager = OpenSCManager(
374 nullptr, // machine (nullptr == local)
375 nullptr, // database (nullptr == default)
376 SC_MANAGER_ALL_ACCESS // access required
382 schService = CreateService(
383 schSCManager, // SCManager database
384 realName.c_str(), // name of service
385 dispName.c_str(), // name to display
386 SERVICE_ALL_ACCESS, // desired access
387 SERVICE_WIN32_OWN_PROCESS, // service type
388 SERVICE_AUTO_START, // start type
389 SERVICE_ERROR_NORMAL, // error control type
390 cmd.c_str(), // service's command line
391 nullptr, // no load ordering group
392 nullptr, // no tag identifier
393 nullptr, // dependencies
394 nullptr, // LocalSystem account
395 nullptr); // no password
399 printf("%s installed.\n", realName.c_str());
400 CloseServiceHandle(schService);
404 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
407 CloseServiceHandle(schSCManager);
410 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
413 void CmdRemoveService(LPCSTR name)
415 SC_HANDLE schService;
416 SC_HANDLE schSCManager;
419 _snprintf(realName,sizeof(realName),"shibd_%s",name);
421 schSCManager = OpenSCManager(
422 nullptr, // machine (nullptr == local)
423 nullptr, // database (nullptr == default)
424 SC_MANAGER_ALL_ACCESS // access required
428 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
432 // try to stop the service
433 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
435 printf("Stopping shibd (%s).", name);
438 while( QueryServiceStatus( schService, &ssStatus ) )
440 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
449 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
450 printf("\n%s stopped.\n", realName);
452 printf("\n%s failed to stop.\n", realName);
456 // now remove the service
457 if( DeleteService(schService) )
458 printf("%s removed.\n", realName);
460 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
463 CloseServiceHandle(schService);
466 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
468 CloseServiceHandle(schSCManager);
471 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
476 // FUNCTION: GetLastErrorText
478 // PURPOSE: copies error message text to string
481 // lpszBuf - destination buffer
482 // dwSize - size of buffer
485 // destination buffer
489 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
492 LPSTR lpszTemp = nullptr;
494 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
502 // supplied buffer is not long enough
503 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
507 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
508 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
512 LocalFree((HLOCAL) lpszTemp );
518 LPCSTR lpUNCServerName,
524 LPCSTR messages[] = {message, nullptr};
526 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
527 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
528 return (DeregisterEventSource(hElog) && res);