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
31 #include <windows.h>
\r
33 extern bool shibd_shutdown; // signals shutdown to Unix side
\r
34 extern const char* shar_schemadir;
\r
35 extern const char* shar_config;
\r
36 extern bool shar_checkonly;
\r
38 // internal variables
\r
39 SERVICE_STATUS ssStatus; // current status of the service
\r
40 SERVICE_STATUS_HANDLE sshStatusHandle;
\r
42 BOOL bConsole = FALSE;
\r
44 LPCSTR lpszInstall = NULL;
\r
45 LPCSTR lpszRemove = NULL;
\r
47 // internal function prototypes
\r
48 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
\r
49 VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
\r
50 VOID CmdInstallService(LPCSTR);
\r
51 VOID CmdRemoveService(LPCSTR);
\r
52 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
\r
55 LPCTSTR lpUNCServerName,
\r
61 VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
\r
63 BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
\r
64 void AddToMessageLog(LPSTR lpszMsg);
\r
66 BOOL WINAPI BreakHandler(DWORD dwCtrlType)
\r
70 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
\r
71 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in console mode
\r
79 int real_main(int); // The revised two-phase main() in shar.cpp
\r
81 int main(int argc, char *argv[])
\r
84 while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
\r
86 if (_stricmp("install", argv[i]+1) == 0)
\r
89 lpszInstall = argv[i++];
\r
91 else if (_stricmp("remove", argv[i]+1) == 0)
\r
94 lpszRemove = argv[i++];
\r
96 else if (_stricmp( "console", argv[i]+1) == 0)
\r
101 else if (_stricmp( "check", argv[i]+1) == 0)
\r
105 shar_checkonly=true;
\r
107 else if (_stricmp( "config", argv[i]+1) == 0)
\r
110 shar_config = argv[i++];
\r
112 else if (_stricmp( "catalogs", argv[i]+1) == 0)
\r
115 shar_schemadir = argv[i++];
\r
125 // Install break handler, then run the C routine twice, once to setup, once to start running.
\r
126 SetConsoleCtrlHandler(&BreakHandler,TRUE);
\r
127 if ((i=real_main(1))!=0)
\r
129 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
\r
132 return real_main(0);
\r
134 else if (lpszInstall)
\r
136 CmdInstallService(lpszInstall);
\r
139 else if (lpszRemove)
\r
141 CmdRemoveService(lpszRemove);
\r
146 // if it doesn't match any of the above parameters
\r
147 // the service control manager may be starting the service
\r
148 // so we must call StartServiceCtrlDispatcher
\r
150 // this is just to be friendly
\r
151 printf("%s -install <name> to install the named service\n", argv[0]);
\r
152 printf("%s -remove <name> to remove the named service\n", argv[0]);
\r
153 printf("%s -console to run as a console app for debugging\n", argv[0]);
\r
154 printf("%s -check to run as a console app and check configuration\n", argv[0]);
\r
155 printf("\t-config <file> to specify the config file to use\n");
\r
156 printf("\t-catalogs <dir> to specify schema catalogs\n");
\r
157 printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
\r
159 SERVICE_TABLE_ENTRY dispatchTable[] =
\r
161 { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
\r
165 if (!StartServiceCtrlDispatcher(dispatchTable))
\r
166 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "StartServiceCtrlDispatcher failed.");
\r
171 // FUNCTION: ServiceStart
\r
173 // PURPOSE: Actual code of the service
\r
174 // that does the work.
\r
176 VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
\r
179 if (real_main(1)!=0)
\r
181 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
\r
185 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7700, NULL, "shibd started successfully.");
\r
187 if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
\r
195 // FUNCTION: ServiceStop
\r
197 // PURPOSE: Stops the service
\r
202 LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7701, NULL, "shibd stopping...");
\r
203 shibd_shutdown=true;
\r
207 void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
\r
210 // register our service control handler:
\r
211 sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
\r
212 if (!sshStatusHandle)
\r
215 // SERVICE_STATUS members that don't change in example
\r
216 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
\r
217 ssStatus.dwServiceSpecificExitCode = 0;
\r
220 // report the status to the service control manager.
\r
221 if (!ReportStatusToSCMgr(
\r
222 SERVICE_START_PENDING, // service state
\r
223 NO_ERROR, // exit code
\r
224 3000)) // wait hint
\r
228 ServiceStart(dwArgc, lpszArgv);
\r
232 // try to report the stopped status to the service control manager.
\r
234 if (sshStatusHandle)
\r
235 (VOID)ReportStatusToSCMgr(
\r
245 // FUNCTION: service_ctrl
\r
247 // PURPOSE: This function is called by the SCM whenever
\r
248 // ControlService() is called on this service.
\r
251 // dwCtrlCode - type of control requested
\r
256 VOID WINAPI service_ctrl(DWORD dwCtrlCode)
\r
258 // Handle the requested control code.
\r
262 // Stop the service.
\r
264 case SERVICE_CONTROL_STOP:
\r
265 ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
\r
269 // Update the service status.
\r
271 case SERVICE_CONTROL_INTERROGATE:
\r
274 // invalid control code
\r
281 ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
\r
286 // FUNCTION: ReportStatusToSCMgr()
\r
288 // PURPOSE: Sets the current status of the service and
\r
289 // reports it to the Service Control Manager
\r
292 // dwCurrentState - the state of the service
\r
293 // dwWin32ExitCode - error code to report
\r
294 // dwWaitHint - worst case estimate to next checkpoint
\r
300 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
\r
301 DWORD dwWin32ExitCode,
\r
304 static DWORD dwCheckPoint = 1;
\r
305 BOOL fResult = TRUE;
\r
308 if (!bConsole) // when console we don't report to the SCM
\r
310 if (dwCurrentState == SERVICE_START_PENDING)
\r
311 ssStatus.dwControlsAccepted = 0;
\r
313 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
\r
315 ssStatus.dwCurrentState = dwCurrentState;
\r
316 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
\r
317 ssStatus.dwWaitHint = dwWaitHint;
\r
319 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
\r
320 ( dwCurrentState == SERVICE_STOPPED ) )
\r
321 ssStatus.dwCheckPoint = 0;
\r
323 ssStatus.dwCheckPoint = dwCheckPoint++;
\r
326 // Report the status of the service to the service control manager.
\r
328 if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
\r
329 LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "SetServiceStatus failed.");
\r
335 ///////////////////////////////////////////////////////////////////
\r
337 // The following code handles service installation and removal
\r
340 void CmdInstallService(LPCSTR name)
\r
342 SC_HANDLE schService;
\r
343 SC_HANDLE schSCManager;
\r
346 char dispName[512];
\r
347 char realName[512];
\r
350 if ( GetModuleFileName( NULL, szPath, 256 ) == 0 )
\r
352 printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
\r
356 sprintf(dispName,"Shibboleth %s Daemon (%s)",PACKAGE_VERSION,name);
\r
357 sprintf(realName,"shibd_%s",name);
\r
358 if (shar_config && shar_schemadir)
\r
359 sprintf(cmd,"%s -config %s -schemadir %s",szPath,shar_config,shar_schemadir);
\r
360 else if (shar_config)
\r
361 sprintf(cmd,"%s -config %s",szPath,shar_config);
\r
362 else if (shar_schemadir)
\r
363 sprintf(cmd,"%s -schemadir %s",szPath,shar_schemadir);
\r
365 sprintf(cmd,"%s",szPath);
\r
367 schSCManager = OpenSCManager(
\r
368 NULL, // machine (NULL == local)
\r
369 NULL, // database (NULL == default)
\r
370 SC_MANAGER_ALL_ACCESS // access required
\r
374 if ( schSCManager )
\r
376 schService = CreateService(
\r
377 schSCManager, // SCManager database
\r
378 realName, // name of service
\r
379 dispName, // name to display
\r
380 SERVICE_ALL_ACCESS, // desired access
\r
381 SERVICE_WIN32_OWN_PROCESS, // service type
\r
382 SERVICE_AUTO_START, // start type
\r
383 SERVICE_ERROR_NORMAL, // error control type
\r
384 cmd, // service's command line
\r
385 NULL, // no load ordering group
\r
386 NULL, // no tag identifier
\r
387 NULL, // dependencies
\r
388 NULL, // LocalSystem account
\r
389 NULL); // no password
\r
393 printf("%s installed.\n",realName);
\r
394 CloseServiceHandle(schService);
\r
398 printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
\r
401 CloseServiceHandle(schSCManager);
\r
404 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
\r
407 void CmdRemoveService(LPCSTR name)
\r
409 SC_HANDLE schService;
\r
410 SC_HANDLE schSCManager;
\r
411 char realName[512];
\r
413 sprintf(realName,"shibd_%s",name);
\r
415 schSCManager = OpenSCManager(
\r
416 NULL, // machine (NULL == local)
\r
417 NULL, // database (NULL == default)
\r
418 SC_MANAGER_ALL_ACCESS // access required
\r
420 if ( schSCManager )
\r
422 schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
\r
426 // try to stop the service
\r
427 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
\r
429 printf("Stopping shibd (%s).", name);
\r
432 while( QueryServiceStatus( schService, &ssStatus ) )
\r
434 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
\r
443 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
\r
444 printf("\n%s stopped.\n", realName);
\r
446 printf("\n%s failed to stop.\n", realName);
\r
450 // now remove the service
\r
451 if( DeleteService(schService) )
\r
452 printf("%s removed.\n", realName);
\r
454 printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
\r
457 CloseServiceHandle(schService);
\r
460 printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
\r
462 CloseServiceHandle(schSCManager);
\r
465 printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
\r
470 // FUNCTION: GetLastErrorText
\r
472 // PURPOSE: copies error message text to string
\r
475 // lpszBuf - destination buffer
\r
476 // dwSize - size of buffer
\r
479 // destination buffer
\r
483 LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
\r
486 LPSTR lpszTemp = NULL;
\r
488 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
\r
496 // supplied buffer is not long enough
\r
497 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
\r
501 lpszTemp[lstrlen(lpszTemp)-2] = '\0'; //remove cr and newline character
\r
502 sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
\r
506 LocalFree((HLOCAL) lpszTemp );
\r
512 LPCSTR lpUNCServerName,
\r
518 LPCSTR messages[] = {message, NULL};
\r
520 HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
\r
521 BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);
\r
522 return (DeregisterEventSource(hElog) && res);
\r