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;
50 LPCSTR lpszStdout = nullptr;
51 LPCSTR lpszStderr = nullptr;
53 // internal function prototypes
54 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
55 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
56 VOID CmdInstallService(LPCSTR);
57 VOID CmdRemoveService(LPCSTR);
58 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
61 LPCTSTR lpUNCServerName,
67 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
69 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
70 void AddToMessageLog(LPSTR lpszMsg);
72 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
76 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
77 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
85 int real_main(int); // The revised two-phase main() in shibd.cpp
87 int main(int argc, char *argv[])
90 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
92 if (_stricmp("install", argv[i]+1) == 0)
95 lpszInstall = argv[i++];
97 else if (_stricmp("remove", argv[i]+1) == 0)
100 lpszRemove = argv[i++];
102 else if (_stricmp("stdout", argv[i]+1) == 0)
105 lpszStdout = argv[i++];
106 freopen(lpszStdout, "a+", stdout);
109 else if (_stricmp("stderr", argv[i]+1) == 0)
112 lpszStderr = argv[i++];
113 freopen(lpszStderr, "a+", stderr);
116 else if (_stricmp( "console", argv[i]+1) == 0)
121 else if (_stricmp( "check", argv[i]+1) == 0)
127 else if (_stricmp( "config", argv[i]+1) == 0)
130 shar_config = argv[i++];
132 else if (_stricmp( "prefix", argv[i]+1) == 0)
135 shar_prefix = argv[i++];
137 else if (_stricmp( "catalogs", argv[i]+1) == 0)
140 shar_schemadir = argv[i++];
150 // Install break handler, then run the C routine twice, once to setup, once to start running.
151 SetConsoleCtrlHandler(&BreakHandler,TRUE);
152 if ((i=real_main(1))!=0)
154 LogEvent(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
159 else if (lpszInstall)
161 CmdInstallService(lpszInstall);
166 CmdRemoveService(lpszRemove);
171 // if it doesn't match any of the above parameters
172 // the service control manager may be starting the service
173 // so we must call StartServiceCtrlDispatcher
175 // this is just to be friendly
176 printf("%s -install <name> to install the named service\n", argv[0]);
177 printf("%s -remove <name> to remove the named service\n", argv[0]);
178 printf("%s -console to run as a console app for debugging\n", argv[0]);
179 printf("%s -check to run as a console app and check configuration\n", argv[0]);
180 printf("\t-stdout <path> to redirect stdout stream\n");
181 printf("\t-stderr <path> to redirect stderr stream\n");
182 printf("\t-prefix <dir> to specify the installation directory\n");
183 printf("\t-config <file> to specify the config file to use\n");
184 printf("\t-catalogs <catalog1:catalog2> to specify schema catalogs\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(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "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(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "shibd startup failed, check shibd.log for further details");
213 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7700, nullptr, "shibd started successfully.");
215 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
223 // FUNCTION: ServiceStop
225 // PURPOSE: Stops the service
230 LogEvent(nullptr, EVENTLOG_INFORMATION_TYPE, 7701, nullptr, "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(nullptr, EVENTLOG_ERROR_TYPE, 2100, nullptr, "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;
375 if ( GetModuleFileName( nullptr, szPath, 256 ) == 0 )
377 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
381 string dispName = string("Shibboleth 2 Daemon (") + name + ")";
382 string realName = string("shibd_") + name;
385 cmd = cmd + " -prefix " + shar_prefix;
387 cmd = cmd + " -config " + shar_config;
389 cmd = cmd + " -schemadir " + shar_schemadir;
391 cmd = cmd + " -stdout " + lpszStdout;
393 cmd = cmd + " -stderr " + lpszStderr;
395 schSCManager = OpenSCManager(
396 nullptr, // machine (nullptr == local)
397 nullptr, // database (nullptr == default)
398 SC_MANAGER_ALL_ACCESS // access required
404 schService = CreateService(
405 schSCManager, // SCManager database
406 realName.c_str(), // name of service
407 dispName.c_str(), // 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.c_str(), // service's command line
413 nullptr, // no load ordering group
414 nullptr, // no tag identifier
415 nullptr, // dependencies
416 nullptr, // LocalSystem account
417 nullptr); // no password
421 printf("%s installed.\n", realName.c_str());
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 _snprintf(realName,sizeof(realName),"shibd_%s",name);
443 schSCManager = OpenSCManager(
444 nullptr, // machine (nullptr == local)
445 nullptr, // database (nullptr == 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 = nullptr;
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, nullptr};
548 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
549 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, nullptr);
550 return (DeregisterEventSource(hElog) && res);