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;
41 extern bool shar_version;
44 SERVICE_STATUS ssStatus; // current status of the service
45 SERVICE_STATUS_HANDLE sshStatusHandle;
47 BOOL bConsole = FALSE;
49 LPCSTR lpszInstall = nullptr;
50 LPCSTR lpszRemove = nullptr;
51 LPCSTR lpszStdout = nullptr;
52 LPCSTR lpszStderr = nullptr;
54 // internal function prototypes
55 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
56 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
57 VOID CmdInstallService(LPCSTR);
58 VOID CmdRemoveService(LPCSTR);
59 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
62 LPCTSTR lpUNCServerName,
68 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
70 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
71 void AddToMessageLog(LPSTR lpszMsg);
73 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
77 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
78 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
86 int real_main(int); // The revised two-phase main() in shibd.cpp
88 int main(int argc, char *argv[])
91 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
93 if (_stricmp("install", argv[i]+1) == 0)
96 lpszInstall = argv[i++];
98 else if (_stricmp("remove", argv[i]+1) == 0)
101 lpszRemove = argv[i++];
103 else if (_stricmp("stdout", argv[i]+1) == 0)
106 lpszStdout = argv[i++];
107 freopen(lpszStdout, "a+", stdout);
110 else if (_stricmp("stderr", argv[i]+1) == 0)
113 lpszStderr = argv[i++];
114 freopen(lpszStderr, "a+", stderr);
117 else if (_stricmp( "console", argv[i]+1) == 0)
122 else if (_stricmp( "check", argv[i]+1) == 0)
126 shar_checkonly = true;
128 else if (_stricmp( "version", argv[i]+1) == 0)
134 else if (_stricmp( "config", argv[i]+1) == 0)
137 shar_config = argv[i++];
139 else if (_stricmp( "prefix", argv[i]+1) == 0)
142 shar_prefix = argv[i++];
144 else if (_stricmp( "catalogs", argv[i]+1) == 0)
147 shar_schemadir = argv[i++];
157 // Install break handler, then run the C routine twice, once to setup, once to start running.
158 SetConsoleCtrlHandler(&BreakHandler,TRUE);
159 if ((i=real_main(1))!=0)
161 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
166 else if (lpszInstall)
168 CmdInstallService(lpszInstall);
173 CmdRemoveService(lpszRemove);
178 // if it doesn't match any of the above parameters
179 // the service control manager may be starting the service
180 // so we must call StartServiceCtrlDispatcher
182 // this is just to be friendly
183 printf("%s -install <name> to install the named service\n", argv[0]);
184 printf("%s -remove <name> to remove the named service\n", argv[0]);
185 printf("%s -console to run as a console app for debugging\n", argv[0]);
186 printf("%s -check to run as a console app and check configuration\n", argv[0]);
187 printf("%s -version to run as a console app and print the version\n", argv[0]);
188 printf("\t-stdout <path> to redirect stdout stream\n");
189 printf("\t-stderr <path> to redirect stderr stream\n");
190 printf("\t-prefix <dir> to specify the installation directory\n");
191 printf("\t-config <file> to specify the config file to use\n");
192 printf("\t-catalogs <catalog1:catalog2> to specify schema catalogs\n");
193 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
195 SERVICE_TABLE_ENTRY dispatchTable[] =
197 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
201 if (!StartServiceCtrlDispatcher(dispatchTable))
202 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "StartServiceCtrlDispatcher failed.");
207 // FUNCTION: ServiceStart
209 // PURPOSE: Actual code of the service
210 // that does the work.
212 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
217 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
221 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7700, nullptr, "shibd started successfully.");
223 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
231 // FUNCTION: ServiceStop
233 // PURPOSE: Stops the service
238 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7701, nullptr, "shibd stopping...");
243 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
246 // register our service control handler:
247 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
248 if (!sshStatusHandle)
251 // SERVICE_STATUS members that don't change in example
252 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
253 ssStatus.dwServiceSpecificExitCode = 0;
256 // report the status to the service control manager.
257 if (!ReportStatusToSCMgr(
258 SERVICE_START_PENDING, // service state
259 NO_ERROR, // exit code
264 ServiceStart(dwArgc, lpszArgv);
268 // try to report the stopped status to the service control manager.
271 (VOID)ReportStatusToSCMgr(
281 // FUNCTION: service_ctrl
283 // PURPOSE: This function is called by the SCM whenever
284 // ControlService() is called on this service.
287 // dwCtrlCode - type of control requested
292 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
294 // Handle the requested control code.
300 case SERVICE_CONTROL_STOP:
301 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
305 // Update the service status.
307 case SERVICE_CONTROL_INTERROGATE:
310 // invalid control code
317 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
322 // FUNCTION: ReportStatusToSCMgr()
324 // PURPOSE: Sets the current status of the service and
325 // reports it to the Service Control Manager
328 // dwCurrentState - the state of the service
329 // dwWin32ExitCode - error code to report
330 // dwWaitHint - worst case estimate to next checkpoint
336 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
337 DWORD dwWin32ExitCode,
340 static DWORD dwCheckPoint = 1;
344 if (!bConsole) // when console we don't report to the SCM
346 if (dwCurrentState == SERVICE_START_PENDING)
347 ssStatus.dwControlsAccepted = 0;
349 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
351 ssStatus.dwCurrentState = dwCurrentState;
352 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
353 ssStatus.dwWaitHint = dwWaitHint;
355 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
356 ( dwCurrentState == SERVICE_STOPPED ) )
357 ssStatus.dwCheckPoint = 0;
359 ssStatus.dwCheckPoint = dwCheckPoint++;
362 // Report the status of the service to the service control manager.
364 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
365 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "SetServiceStatus failed.");
371 ///////////////////////////////////////////////////////////////////
373 // The following code handles service installation and removal
376 void CmdInstallService(LPCSTR name)
378 SC_HANDLE schService;
379 SC_HANDLE schSCManager;
383 if ( GetModuleFileName( nullptr, szPath, 256 ) == 0 )
385 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
389 string dispName = string("Shibboleth 2 Daemon (") + name + ")";
390 string realName = string("shibd_") + name;
393 cmd = cmd + " -prefix " + shar_prefix;
395 cmd = cmd + " -config " + shar_config;
397 cmd = cmd + " -schemadir " + shar_schemadir;
399 cmd = cmd + " -stdout " + lpszStdout;
401 cmd = cmd + " -stderr " + lpszStderr;
403 schSCManager = OpenSCManager(
404 nullptr, // machine (nullptr == local)
405 nullptr, // database (nullptr == default)
406 SC_MANAGER_ALL_ACCESS // access required
412 schService = CreateService(
413 schSCManager, // SCManager database
414 realName.c_str(), // name of service
415 dispName.c_str(), // name to display
416 SERVICE_ALL_ACCESS, // desired access
417 SERVICE_WIN32_OWN_PROCESS, // service type
418 SERVICE_AUTO_START, // start type
419 SERVICE_ERROR_NORMAL, // error control type
420 cmd.c_str(), // service's command line
421 nullptr, // no load ordering group
422 nullptr, // no tag identifier
423 nullptr, // dependencies
424 nullptr, // LocalSystem account
425 nullptr); // no password
429 printf("%s installed.\n", realName.c_str());
430 CloseServiceHandle(schService);
434 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
437 CloseServiceHandle(schSCManager);
440 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
443 void CmdRemoveService(LPCSTR name)
445 SC_HANDLE schService;
446 SC_HANDLE schSCManager;
449 _snprintf(realName,sizeof(realName),"shibd_%s",name);
451 schSCManager = OpenSCManager(
452 nullptr, // machine (nullptr == local)
453 nullptr, // database (nullptr == default)
454 SC_MANAGER_ALL_ACCESS // access required
458 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
462 // try to stop the service
463 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
465 printf("Stopping shibd (%s).", name);
468 while( QueryServiceStatus( schService, &ssStatus ) )
470 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
479 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
480 printf("\n%s stopped.\n", realName);
482 printf("\n%s failed to stop.\n", realName);
486 // now remove the service
487 if( DeleteService(schService) )
488 printf("%s removed.\n", realName);
490 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
493 CloseServiceHandle(schService);
496 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
498 CloseServiceHandle(schSCManager);
501 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
506 // FUNCTION: GetLastErrorText
508 // PURPOSE: copies error message text to string
511 // lpszBuf - destination buffer
512 // dwSize - size of buffer
515 // destination buffer
519 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
522 LPSTR lpszTemp = nullptr;
524 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
532 // supplied buffer is not long enough
533 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
537 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
538 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
542 LocalFree((HLOCAL) lpszTemp );
548 LPCSTR lpUNCServerName,
554 LPCSTR messages[] = {message, nullptr};
556 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
557 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
558 return (DeregisterEventSource(hElog) && res);