Take version out of service name string.
[shibboleth/cpp-sp.git] / shibd / shibd_win32.cpp
index 20eb442..7069a91 100644 (file)
-/*\r
- *  Copyright 2001-2007 Internet2\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/*\r
- * shar_win32.cpp -- the SHAR "main" code on Win32\r
- *\r
- * Created By: Scott Cantor (cantor.2@osu.edu)\r
- *\r
- * $Id: shar_win32.cpp 2150 2007-02-02 04:06:15 +0000 (Fri, 02 Feb 2007) cantor $\r
- */\r
-\r
-#include "config_win32.h"\r
-\r
-#define _CRT_NONSTDC_NO_DEPRECATE 1\r
-#define _CRT_SECURE_NO_DEPRECATE 1\r
-\r
-#include <shibsp/base.h>\r
-#include <windows.h>\r
-\r
-extern bool shibd_shutdown;                    // signals shutdown to Unix side\r
-extern const char* shar_schemadir;\r
-extern const char* shar_config;\r
-extern bool shar_checkonly;\r
-\r
-// internal variables\r
-SERVICE_STATUS          ssStatus;       // current status of the service\r
-SERVICE_STATUS_HANDLE   sshStatusHandle;\r
-DWORD                   dwErr = 0;\r
-BOOL                    bConsole = FALSE;\r
-char                    szErr[256];\r
-LPCSTR                  lpszInstall = NULL;\r
-LPCSTR                  lpszRemove = NULL;\r
-\r
-// internal function prototypes\r
-VOID WINAPI service_ctrl(DWORD dwCtrlCode);\r
-VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);\r
-VOID CmdInstallService(LPCSTR);\r
-VOID CmdRemoveService(LPCSTR);\r
-LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );\r
-\r
-BOOL LogEvent(\r
-    LPCTSTR  lpUNCServerName,\r
-    WORD  wType,\r
-    DWORD  dwEventID,\r
-    PSID  lpUserSid,\r
-    LPCTSTR  message);\r
-\r
-VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);\r
-VOID ServiceStop();\r
-BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);\r
-void AddToMessageLog(LPSTR lpszMsg);\r
-\r
-BOOL WINAPI BreakHandler(DWORD dwCtrlType)\r
-{\r
-   switch(dwCtrlType)\r
-    {\r
-        case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate\r
-        case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in console mode\r
-            ServiceStop();\r
-            return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-\r
-int real_main(int);  // The revised two-phase main() in shar.cpp\r
-\r
-int main(int argc, char *argv[])\r
-{\r
-    int i=1;\r
-    while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))\r
-    {\r
-        if (_stricmp("install", argv[i]+1) == 0)\r
-        {\r
-            if (argc > ++i)\r
-                lpszInstall = argv[i++];\r
-        }\r
-        else if (_stricmp("remove", argv[i]+1) == 0)\r
-        {\r
-            if (argc > ++i)\r
-                lpszRemove = argv[i++];\r
-        }\r
-        else if (_stricmp( "console", argv[i]+1) == 0)\r
-        {\r
-            i++;\r
-            bConsole = TRUE;\r
-        }\r
-        else if (_stricmp( "check", argv[i]+1) == 0)\r
-        {\r
-            i++;\r
-            bConsole = TRUE;\r
-            shar_checkonly=true;\r
-        }\r
-        else if (_stricmp( "config", argv[i]+1) == 0)\r
-        {\r
-            if (argc > ++i)\r
-                shar_config = argv[i++];\r
-        }\r
-        else if (_stricmp( "catalogs", argv[i]+1) == 0)\r
-        {\r
-            if (argc > ++i)\r
-                shar_schemadir = argv[i++];\r
-        }\r
-        else\r
-        {\r
-            goto dispatch;\r
-        }\r
-    }\r
-    \r
-    if (bConsole)\r
-    {\r
-        // Install break handler, then run the C routine twice, once to setup, once to start running.\r
-        SetConsoleCtrlHandler(&BreakHandler,TRUE);\r
-        if ((i=real_main(1))!=0)\r
-        {\r
-            LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");\r
-            return i;\r
-        }\r
-        return real_main(0);\r
-    }\r
-    else if (lpszInstall)\r
-    {\r
-        CmdInstallService(lpszInstall);\r
-        return 0;\r
-    }\r
-    else if (lpszRemove)\r
-    {\r
-        CmdRemoveService(lpszRemove);\r
-        return 0;\r
-    }\r
-    \r
-\r
-    // if it doesn't match any of the above parameters\r
-    // the service control manager may be starting the service\r
-    // so we must call StartServiceCtrlDispatcher\r
-    dispatch:\r
-        // this is just to be friendly\r
-        printf("%s -install <name>   to install the named service\n", argv[0]);\r
-        printf("%s -remove <name>    to remove the named service\n", argv[0]);\r
-        printf("%s -console          to run as a console app for debugging\n", argv[0]);\r
-        printf("%s -check            to run as a console app and check configuration\n", argv[0]);\r
-        printf("\t-config <file> to specify the config file to use\n");\r
-        printf("\t-catalogs <dir> to specify schema catalogs\n");\r
-        printf("\nService starting.\nThis may take several seconds. Please wait.\n" );\r
-\r
-    SERVICE_TABLE_ENTRY dispatchTable[] =\r
-    {\r
-        { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },\r
-        { NULL, NULL }\r
-    };\r
-\r
-    if (!StartServiceCtrlDispatcher(dispatchTable))\r
-        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "StartServiceCtrlDispatcher failed.");\r
-    return 0;\r
-}\r
-\r
-//\r
-//  FUNCTION: ServiceStart\r
-//\r
-//  PURPOSE: Actual code of the service\r
-//          that does the work.\r
-//\r
-VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)\r
-{\r
-\r
-    if (real_main(1)!=0)\r
-    {\r
-        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");\r
-        return;\r
-    }\r
-\r
-    LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7700, NULL, "shibd started successfully.");\r
-\r
-    if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))\r
-        return;\r
-\r
-    real_main(0);\r
-}\r
-\r
-\r
-//\r
-//  FUNCTION: ServiceStop\r
-//\r
-//   PURPOSE: Stops the service\r
-//\r
-VOID ServiceStop()\r
-{\r
-    if (!bConsole)\r
-        LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7701, NULL, "shibd stopping...");\r
-    shibd_shutdown=true;\r
-}\r
-\r
-\r
-void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)\r
-{\r
-\r
-    // register our service control handler:\r
-    sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);\r
-    if (!sshStatusHandle)\r
-        goto cleanup;\r
-\r
-    // SERVICE_STATUS members that don't change in example\r
-    ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
-    ssStatus.dwServiceSpecificExitCode = 0;\r
-\r
-\r
-    // report the status to the service control manager.\r
-    if (!ReportStatusToSCMgr(\r
-        SERVICE_START_PENDING, // service state\r
-        NO_ERROR,              // exit code\r
-        3000))                 // wait hint\r
-        goto cleanup;\r
-\r
-\r
-    ServiceStart(dwArgc, lpszArgv);\r
-\r
-cleanup:\r
-\r
-    // try to report the stopped status to the service control manager.\r
-    //\r
-    if (sshStatusHandle)\r
-        (VOID)ReportStatusToSCMgr(\r
-                            SERVICE_STOPPED,\r
-                            dwErr,\r
-                            0);\r
-\r
-    return;\r
-}\r
-\r
-\r
-//\r
-//  FUNCTION: service_ctrl\r
-//\r
-//  PURPOSE: This function is called by the SCM whenever\r
-//           ControlService() is called on this service.\r
-//\r
-//  PARAMETERS:\r
-//    dwCtrlCode - type of control requested\r
-//\r
-//  RETURN VALUE:\r
-//    none\r
-//\r
-VOID WINAPI service_ctrl(DWORD dwCtrlCode)\r
-{\r
-    // Handle the requested control code.\r
-    //\r
-    switch(dwCtrlCode)\r
-    {\r
-        // Stop the service.\r
-        //\r
-        case SERVICE_CONTROL_STOP:\r
-            ssStatus.dwCurrentState = SERVICE_STOP_PENDING;\r
-            ServiceStop();\r
-            break;\r
-\r
-        // Update the service status.\r
-        //\r
-        case SERVICE_CONTROL_INTERROGATE:\r
-            break;\r
-\r
-        // invalid control code\r
-        //\r
-        default:\r
-            break;\r
-\r
-    }\r
-\r
-    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);\r
-}\r
-\r
-\r
-//\r
-//  FUNCTION: ReportStatusToSCMgr()\r
-//\r
-//  PURPOSE: Sets the current status of the service and\r
-//           reports it to the Service Control Manager\r
-//\r
-//  PARAMETERS:\r
-//    dwCurrentState - the state of the service\r
-//    dwWin32ExitCode - error code to report\r
-//    dwWaitHint - worst case estimate to next checkpoint\r
-//\r
-//  RETURN VALUE:\r
-//    TRUE  - success\r
-//    FALSE - failure\r
-//\r
-BOOL ReportStatusToSCMgr(DWORD dwCurrentState,\r
-                         DWORD dwWin32ExitCode,\r
-                         DWORD dwWaitHint)\r
-{\r
-    static DWORD dwCheckPoint = 1;\r
-    BOOL fResult = TRUE;\r
-\r
-\r
-    if (!bConsole) // when console we don't report to the SCM\r
-    {\r
-        if (dwCurrentState == SERVICE_START_PENDING)\r
-            ssStatus.dwControlsAccepted = 0;\r
-        else\r
-            ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;\r
-\r
-        ssStatus.dwCurrentState = dwCurrentState;\r
-        ssStatus.dwWin32ExitCode = dwWin32ExitCode;\r
-        ssStatus.dwWaitHint = dwWaitHint;\r
-\r
-        if ( ( dwCurrentState == SERVICE_RUNNING ) ||\r
-             ( dwCurrentState == SERVICE_STOPPED ) )\r
-            ssStatus.dwCheckPoint = 0;\r
-        else\r
-            ssStatus.dwCheckPoint = dwCheckPoint++;\r
-\r
-\r
-        // Report the status of the service to the service control manager.\r
-        //\r
-        if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))\r
-            LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "SetServiceStatus failed.");\r
-    }\r
-    return fResult;\r
-}\r
-\r
-\r
-///////////////////////////////////////////////////////////////////\r
-//\r
-//  The following code handles service installation and removal\r
-//\r
-//\r
-void CmdInstallService(LPCSTR name)\r
-{\r
-    SC_HANDLE   schService;\r
-    SC_HANDLE   schSCManager;\r
-\r
-    char szPath[256];\r
-    char dispName[512];\r
-    char realName[512];\r
-    char cmd[2048];\r
-\r
-    if ( GetModuleFileName( NULL, szPath, 256 ) == 0 )\r
-    {\r
-        printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));\r
-        return;\r
-    }\r
-    \r
-    sprintf(dispName,"Shibboleth %s Daemon (%s)",PACKAGE_VERSION,name);\r
-    sprintf(realName,"shibd_%s",name);\r
-    if (shar_config && shar_schemadir)\r
-        sprintf(cmd,"%s -config %s -schemadir %s",szPath,shar_config,shar_schemadir);\r
-    else if (shar_config)\r
-        sprintf(cmd,"%s -config %s",szPath,shar_config);\r
-    else if (shar_schemadir)\r
-        sprintf(cmd,"%s -schemadir %s",szPath,shar_schemadir);\r
-    else\r
-        sprintf(cmd,"%s",szPath);\r
-\r
-    schSCManager = OpenSCManager(\r
-                        NULL,                   // machine (NULL == local)\r
-                        NULL,                   // database (NULL == default)\r
-                        SC_MANAGER_ALL_ACCESS   // access required\r
-                        );\r
-    \r
-    \r
-    if ( schSCManager )\r
-    {\r
-        schService = CreateService(\r
-            schSCManager,               // SCManager database\r
-            realName,                   // name of service\r
-            dispName,                   // name to display\r
-            SERVICE_ALL_ACCESS,         // desired access\r
-            SERVICE_WIN32_OWN_PROCESS,  // service type\r
-            SERVICE_AUTO_START,         // start type\r
-            SERVICE_ERROR_NORMAL,       // error control type\r
-            cmd,                        // service's command line\r
-            NULL,                       // no load ordering group\r
-            NULL,                       // no tag identifier\r
-            NULL,                       // dependencies\r
-            NULL,                       // LocalSystem account\r
-            NULL);                      // no password\r
-\r
-        if ( schService )\r
-        {\r
-            printf("%s installed.\n",realName);\r
-            CloseServiceHandle(schService);\r
-        }\r
-        else\r
-        {\r
-            printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));\r
-        }\r
-\r
-        CloseServiceHandle(schSCManager);\r
-    }\r
-    else\r
-        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));\r
-}\r
-\r
-void CmdRemoveService(LPCSTR name)\r
-{\r
-    SC_HANDLE   schService;\r
-    SC_HANDLE   schSCManager;\r
-    char        realName[512];\r
-\r
-    sprintf(realName,"shibd_%s",name);\r
-\r
-    schSCManager = OpenSCManager(\r
-                        NULL,                   // machine (NULL == local)\r
-                        NULL,                   // database (NULL == default)\r
-                        SC_MANAGER_ALL_ACCESS   // access required\r
-                        );\r
-    if ( schSCManager )\r
-    {\r
-        schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);\r
-\r
-        if (schService)\r
-        {\r
-            // try to stop the service\r
-            if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )\r
-            {\r
-                printf("Stopping shibd (%s).", name);\r
-                Sleep( 1000 );\r
-\r
-                while( QueryServiceStatus( schService, &ssStatus ) )\r
-                {\r
-                    if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )\r
-                    {\r
-                        printf(".");\r
-                        Sleep( 1000 );\r
-                    }\r
-                    else\r
-                        break;\r
-                }\r
-\r
-                if ( ssStatus.dwCurrentState == SERVICE_STOPPED )\r
-                    printf("\n%s stopped.\n", realName);\r
-                else\r
-                    printf("\n%s failed to stop.\n", realName);\r
-\r
-            }\r
-\r
-            // now remove the service\r
-            if( DeleteService(schService) )\r
-                printf("%s removed.\n", realName);\r
-            else\r
-                printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));\r
-\r
-\r
-            CloseServiceHandle(schService);\r
-        }\r
-        else\r
-            printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));\r
-\r
-        CloseServiceHandle(schSCManager);\r
-    }\r
-    else\r
-        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));\r
-}\r
-\r
-\r
-//\r
-//  FUNCTION: GetLastErrorText\r
-//\r
-//  PURPOSE: copies error message text to string\r
-//\r
-//  PARAMETERS:\r
-//    lpszBuf - destination buffer\r
-//    dwSize - size of buffer\r
-//\r
-//  RETURN VALUE:\r
-//    destination buffer\r
-//\r
-//  COMMENTS:\r
-//\r
-LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )\r
-{\r
-    DWORD dwRet;\r
-    LPSTR lpszTemp = NULL;\r
-\r
-    dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,\r
-                           NULL,\r
-                           GetLastError(),\r
-                           LANG_NEUTRAL,\r
-                           (LPSTR)&lpszTemp,\r
-                           0,\r
-                           NULL );\r
-\r
-    // supplied buffer is not long enough\r
-    if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )\r
-        lpszBuf[0] = '\0';\r
-    else\r
-    {\r
-        lpszTemp[lstrlen(lpszTemp)-2] = '\0';  //remove cr and newline character\r
-        sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );\r
-    }\r
-\r
-    if ( lpszTemp )\r
-        LocalFree((HLOCAL) lpszTemp );\r
-\r
-    return lpszBuf;\r
-}\r
-\r
-BOOL LogEvent(\r
-    LPCSTR  lpUNCServerName,\r
-    WORD  wType,\r
-    DWORD  dwEventID,\r
-    PSID  lpUserSid,\r
-    LPCSTR  message)\r
-{\r
-    LPCSTR  messages[] = {message, NULL};\r
-    \r
-    HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");\r
-    BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);\r
-    return (DeregisterEventSource(hElog) && res);\r
-}\r
+/*
+ *  Copyright 2001-2007 Internet2
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * shar_win32.cpp -- the SHAR "main" code on Win32
+ *
+ * Created By: Scott Cantor (cantor.2@osu.edu)
+ *
+ * $Id: shar_win32.cpp 2150 2007-02-02 04:06:15 +0000 (Fri, 02 Feb 2007) cantor $
+ */
+
+#include "config_win32.h"
+
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+
+#include <shibsp/base.h>
+#include <string>
+#include <windows.h>
+
+using namespace std;
+
+extern bool shibd_shutdown;                    // signals shutdown to Unix side
+extern const char* shar_schemadir;
+extern const char* shar_config;
+extern const char* shar_prefix;
+extern bool shar_checkonly;
+
+// internal variables
+SERVICE_STATUS          ssStatus;       // current status of the service
+SERVICE_STATUS_HANDLE   sshStatusHandle;
+DWORD                   dwErr = 0;
+BOOL                    bConsole = FALSE;
+char                    szErr[256];
+LPCSTR                  lpszInstall = NULL;
+LPCSTR                  lpszRemove = NULL;
+
+// internal function prototypes
+VOID WINAPI service_ctrl(DWORD dwCtrlCode);
+VOID WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv);
+VOID CmdInstallService(LPCSTR);
+VOID CmdRemoveService(LPCSTR);
+LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize );
+
+BOOL LogEvent(
+    LPCTSTR  lpUNCServerName,
+    WORD  wType,
+    DWORD  dwEventID,
+    PSID  lpUserSid,
+    LPCTSTR  message);
+
+VOID ServiceStart(DWORD dwArgc, LPSTR *lpszArgv);
+VOID ServiceStop();
+BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
+void AddToMessageLog(LPSTR lpszMsg);
+
+BOOL WINAPI BreakHandler(DWORD dwCtrlType)
+{
+   switch(dwCtrlType)
+    {
+        case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate
+        case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in console mode
+            ServiceStop();
+            return TRUE;
+    }
+    return FALSE;
+}
+
+
+int real_main(int);  // The revised two-phase main() in shar.cpp
+
+int main(int argc, char *argv[])
+{
+    int i=1;
+    while ((argc > i) && ((*argv[i] == '-') || (*argv[i] == '/')))
+    {
+        if (_stricmp("install", argv[i]+1) == 0)
+        {
+            if (argc > ++i)
+                lpszInstall = argv[i++];
+        }
+        else if (_stricmp("remove", argv[i]+1) == 0)
+        {
+            if (argc > ++i)
+                lpszRemove = argv[i++];
+        }
+        else if (_stricmp( "console", argv[i]+1) == 0)
+        {
+            i++;
+            bConsole = TRUE;
+        }
+        else if (_stricmp( "check", argv[i]+1) == 0)
+        {
+            i++;
+            bConsole = TRUE;
+            shar_checkonly=true;
+        }
+        else if (_stricmp( "config", argv[i]+1) == 0)
+        {
+            if (argc > ++i)
+                shar_config = argv[i++];
+        }
+        else if (_stricmp( "prefix", argv[i]+1) == 0)
+        {
+            if (argc > ++i)
+                shar_prefix = argv[i++];
+        }
+        else if (_stricmp( "catalogs", argv[i]+1) == 0)
+        {
+            if (argc > ++i)
+                shar_schemadir = argv[i++];
+        }
+        else
+        {
+            goto dispatch;
+        }
+    }
+    
+    if (bConsole)
+    {
+        // Install break handler, then run the C routine twice, once to setup, once to start running.
+        SetConsoleCtrlHandler(&BreakHandler,TRUE);
+        if ((i=real_main(1))!=0)
+        {
+            LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
+            return i;
+        }
+        return real_main(0);
+    }
+    else if (lpszInstall)
+    {
+        CmdInstallService(lpszInstall);
+        return 0;
+    }
+    else if (lpszRemove)
+    {
+        CmdRemoveService(lpszRemove);
+        return 0;
+    }
+    
+
+    // if it doesn't match any of the above parameters
+    // the service control manager may be starting the service
+    // so we must call StartServiceCtrlDispatcher
+    dispatch:
+        // this is just to be friendly
+        printf("%s -install <name>   to install the named service\n", argv[0]);
+        printf("%s -remove <name>    to remove the named service\n", argv[0]);
+        printf("%s -console          to run as a console app for debugging\n", argv[0]);
+        printf("%s -check            to run as a console app and check configuration\n", argv[0]);
+        printf("\t-prefix <dir> to specify the installation directory\n");
+        printf("\t-config <file> to specify the config file to use\n");
+        printf("\t-catalogs <catalog1:catalog2> to specify schema catalogs\n");
+        printf("\nService starting.\nThis may take several seconds. Please wait.\n" );
+
+    SERVICE_TABLE_ENTRY dispatchTable[] =
+    {
+        { "SHIBD", (LPSERVICE_MAIN_FUNCTION)service_main },
+        { NULL, NULL }
+    };
+
+    if (!StartServiceCtrlDispatcher(dispatchTable))
+        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "StartServiceCtrlDispatcher failed.");
+    return 0;
+}
+
+//
+//  FUNCTION: ServiceStart
+//
+//  PURPOSE: Actual code of the service
+//          that does the work.
+//
+VOID ServiceStart (DWORD dwArgc, LPSTR *lpszArgv)
+{
+
+    if (real_main(1)!=0)
+    {
+        LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "shibd startup failed, check shibd.log for further details");
+        return;
+    }
+
+    LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7700, NULL, "shibd started successfully.");
+
+    if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
+        return;
+
+    real_main(0);
+}
+
+
+//
+//  FUNCTION: ServiceStop
+//
+//   PURPOSE: Stops the service
+//
+VOID ServiceStop()
+{
+    if (!bConsole)
+        LogEvent(NULL, EVENTLOG_INFORMATION_TYPE, 7701, NULL, "shibd stopping...");
+    shibd_shutdown=true;
+}
+
+
+void WINAPI service_main(DWORD dwArgc, LPSTR *lpszArgv)
+{
+
+    // register our service control handler:
+    sshStatusHandle=RegisterServiceCtrlHandler(lpszArgv[0], service_ctrl);
+    if (!sshStatusHandle)
+        goto cleanup;
+
+    // SERVICE_STATUS members that don't change in example
+    ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    ssStatus.dwServiceSpecificExitCode = 0;
+
+
+    // report the status to the service control manager.
+    if (!ReportStatusToSCMgr(
+        SERVICE_START_PENDING, // service state
+        NO_ERROR,              // exit code
+        3000))                 // wait hint
+        goto cleanup;
+
+
+    ServiceStart(dwArgc, lpszArgv);
+
+cleanup:
+
+    // try to report the stopped status to the service control manager.
+    //
+    if (sshStatusHandle)
+        (VOID)ReportStatusToSCMgr(
+                            SERVICE_STOPPED,
+                            dwErr,
+                            0);
+
+    return;
+}
+
+
+//
+//  FUNCTION: service_ctrl
+//
+//  PURPOSE: This function is called by the SCM whenever
+//           ControlService() is called on this service.
+//
+//  PARAMETERS:
+//    dwCtrlCode - type of control requested
+//
+//  RETURN VALUE:
+//    none
+//
+VOID WINAPI service_ctrl(DWORD dwCtrlCode)
+{
+    // Handle the requested control code.
+    //
+    switch(dwCtrlCode)
+    {
+        // Stop the service.
+        //
+        case SERVICE_CONTROL_STOP:
+            ssStatus.dwCurrentState = SERVICE_STOP_PENDING;
+            ServiceStop();
+            break;
+
+        // Update the service status.
+        //
+        case SERVICE_CONTROL_INTERROGATE:
+            break;
+
+        // invalid control code
+        //
+        default:
+            break;
+
+    }
+
+    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
+}
+
+
+//
+//  FUNCTION: ReportStatusToSCMgr()
+//
+//  PURPOSE: Sets the current status of the service and
+//           reports it to the Service Control Manager
+//
+//  PARAMETERS:
+//    dwCurrentState - the state of the service
+//    dwWin32ExitCode - error code to report
+//    dwWaitHint - worst case estimate to next checkpoint
+//
+//  RETURN VALUE:
+//    TRUE  - success
+//    FALSE - failure
+//
+BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
+                         DWORD dwWin32ExitCode,
+                         DWORD dwWaitHint)
+{
+    static DWORD dwCheckPoint = 1;
+    BOOL fResult = TRUE;
+
+
+    if (!bConsole) // when console we don't report to the SCM
+    {
+        if (dwCurrentState == SERVICE_START_PENDING)
+            ssStatus.dwControlsAccepted = 0;
+        else
+            ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+        ssStatus.dwCurrentState = dwCurrentState;
+        ssStatus.dwWin32ExitCode = dwWin32ExitCode;
+        ssStatus.dwWaitHint = dwWaitHint;
+
+        if ( ( dwCurrentState == SERVICE_RUNNING ) ||
+             ( dwCurrentState == SERVICE_STOPPED ) )
+            ssStatus.dwCheckPoint = 0;
+        else
+            ssStatus.dwCheckPoint = dwCheckPoint++;
+
+
+        // Report the status of the service to the service control manager.
+        //
+        if (!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus)))
+            LogEvent(NULL, EVENTLOG_ERROR_TYPE, 2100, NULL, "SetServiceStatus failed.");
+    }
+    return fResult;
+}
+
+
+///////////////////////////////////////////////////////////////////
+//
+//  The following code handles service installation and removal
+//
+//
+void CmdInstallService(LPCSTR name)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+
+    char szPath[256];
+
+    if ( GetModuleFileName( NULL, szPath, 256 ) == 0 )
+    {
+        printf("Unable to install %s - %s\n", name, GetLastErrorText(szErr, 256));
+        return;
+    }
+    
+    string dispName = string("Shibboleth 2 Daemon (") + name + ")";
+    string realName = string("shibd_") + name;
+    string cmd(szPath);
+    if (shar_prefix)
+        cmd = cmd + " -prefix " + shar_prefix;
+    if (shar_config)
+        cmd = cmd + " -config " + shar_config;
+    if (shar_schemadir)
+        cmd = cmd + " -schemadir " + shar_schemadir;
+
+    schSCManager = OpenSCManager(
+                        NULL,                   // machine (NULL == local)
+                        NULL,                   // database (NULL == default)
+                        SC_MANAGER_ALL_ACCESS   // access required
+                        );
+    
+    
+    if ( schSCManager )
+    {
+        schService = CreateService(
+            schSCManager,               // SCManager database
+            realName.c_str(),           // name of service
+            dispName.c_str(),           // name to display
+            SERVICE_ALL_ACCESS,         // desired access
+            SERVICE_WIN32_OWN_PROCESS,  // service type
+            SERVICE_AUTO_START,         // start type
+            SERVICE_ERROR_NORMAL,       // error control type
+            cmd.c_str(),                // service's command line
+            NULL,                       // no load ordering group
+            NULL,                       // no tag identifier
+            NULL,                       // dependencies
+            NULL,                       // LocalSystem account
+            NULL);                      // no password
+
+        if ( schService )
+        {
+            printf("%s installed.\n", realName.c_str());
+            CloseServiceHandle(schService);
+        }
+        else
+        {
+            printf("CreateService failed - %s\n", GetLastErrorText(szErr, 256));
+        }
+
+        CloseServiceHandle(schSCManager);
+    }
+    else
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
+}
+
+void CmdRemoveService(LPCSTR name)
+{
+    SC_HANDLE   schService;
+    SC_HANDLE   schSCManager;
+    char        realName[512];
+
+    _snprintf(realName,sizeof(realName),"shibd_%s",name);
+
+    schSCManager = OpenSCManager(
+                        NULL,                   // machine (NULL == local)
+                        NULL,                   // database (NULL == default)
+                        SC_MANAGER_ALL_ACCESS   // access required
+                        );
+    if ( schSCManager )
+    {
+        schService = OpenService(schSCManager, realName, SERVICE_ALL_ACCESS);
+
+        if (schService)
+        {
+            // try to stop the service
+            if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
+            {
+                printf("Stopping shibd (%s).", name);
+                Sleep( 1000 );
+
+                while( QueryServiceStatus( schService, &ssStatus ) )
+                {
+                    if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
+                    {
+                        printf(".");
+                        Sleep( 1000 );
+                    }
+                    else
+                        break;
+                }
+
+                if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
+                    printf("\n%s stopped.\n", realName);
+                else
+                    printf("\n%s failed to stop.\n", realName);
+
+            }
+
+            // now remove the service
+            if( DeleteService(schService) )
+                printf("%s removed.\n", realName);
+            else
+                printf("DeleteService failed - %s\n", GetLastErrorText(szErr,256));
+
+
+            CloseServiceHandle(schService);
+        }
+        else
+            printf("OpenService failed - %s\n", GetLastErrorText(szErr,256));
+
+        CloseServiceHandle(schSCManager);
+    }
+    else
+        printf("OpenSCManager failed - %s\n", GetLastErrorText(szErr,256));
+}
+
+
+//
+//  FUNCTION: GetLastErrorText
+//
+//  PURPOSE: copies error message text to string
+//
+//  PARAMETERS:
+//    lpszBuf - destination buffer
+//    dwSize - size of buffer
+//
+//  RETURN VALUE:
+//    destination buffer
+//
+//  COMMENTS:
+//
+LPTSTR GetLastErrorText( LPSTR lpszBuf, DWORD dwSize )
+{
+    DWORD dwRet;
+    LPSTR lpszTemp = NULL;
+
+    dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
+                           NULL,
+                           GetLastError(),
+                           LANG_NEUTRAL,
+                           (LPSTR)&lpszTemp,
+                           0,
+                           NULL );
+
+    // supplied buffer is not long enough
+    if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
+        lpszBuf[0] = '\0';
+    else
+    {
+        lpszTemp[lstrlen(lpszTemp)-2] = '\0';  //remove cr and newline character
+        sprintf( lpszBuf, "%s (0x%x)", lpszTemp, GetLastError() );
+    }
+
+    if ( lpszTemp )
+        LocalFree((HLOCAL) lpszTemp );
+
+    return lpszBuf;
+}
+
+BOOL LogEvent(
+    LPCSTR  lpUNCServerName,
+    WORD  wType,
+    DWORD  dwEventID,
+    PSID  lpUserSid,
+    LPCSTR  message)
+{
+    LPCSTR  messages[] = {message, NULL};
+    
+    HANDLE hElog = RegisterEventSource(lpUNCServerName, "Shibboleth Daemon");
+    BOOL res = ReportEvent(hElog, wType, 0, dwEventID, lpUserSid, 1, 0, messages, NULL);
+    return (DeregisterEventSource(hElog) && res);
+}