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