/** * Opens the service control manager. * * When this fails, an error message will be displayed. * * @returns Valid handle on success. * NULL on failure, will display an error message. * * @param pszAction The action which is requesting access to SCM. * @param dwAccess The desired access. */ static SC_HANDLE supSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess) { SC_HANDLE hSCM = OpenSCManager(NULL /* lpMachineName*/, NULL /* lpDatabaseName */, dwAccess); if (hSCM == NULL) { DWORD err = GetLastError(); switch (err) { case ERROR_ACCESS_DENIED: supSvcDisplayError("%s - OpenSCManager failure: access denied\n", pszAction); break; default: supSvcDisplayError("%s - OpenSCManager failure: %d\n", pszAction, err); break; } } return hSCM; }
/** * Opens the service. * * Last error is preserved on failure and set to 0 on success. * * @returns Valid service handle on success. * NULL on failure, will display an error message unless it's ignored. * * @param pszAction The action which is requesting access to the service. * @param dwSCMAccess The service control manager access. * @param dwSVCAccess The desired service access. * @param cIgnoredErrors The number of ignored errors. * @param ... Errors codes that should not cause a message to be displayed. */ static SC_HANDLE supSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess, unsigned cIgnoredErrors, ...) { SC_HANDLE hSCM = supSvcWinOpenSCManager(pszAction, dwSCMAccess); if (!hSCM) return NULL; SC_HANDLE hSvc = OpenService(hSCM, SUPSVC_SERVICE_NAME, dwSVCAccess); if (hSvc) { CloseServiceHandle(hSCM); SetLastError(0); } else { DWORD err = GetLastError(); bool fIgnored = false; va_list va; va_start(va, cIgnoredErrors); while (!fIgnored && cIgnoredErrors-- > 0) fIgnored = va_arg(va, long) == err; va_end(va); if (!fIgnored) { switch (err) { case ERROR_ACCESS_DENIED: supSvcDisplayError("%s - OpenService failure: access denied\n", pszAction); break; case ERROR_SERVICE_DOES_NOT_EXIST: supSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction); break; default: supSvcDisplayError("%s - OpenService failure: %d\n", pszAction, err); break; } } CloseServiceHandle(hSCM); SetLastError(err); } return hSvc; }
/** * Handle the 'create' action. * * @returns 0 or 1. * @param argc The action argument count. * @param argv The action argument vector. */ static int supSvcWinRunIt(int argc, char **argv) { LogFlowFuncEnter(); /* * Initialize release logging. */ /** @todo release logging of the system-wide service. */ /* * Parse the arguments. */ static const RTOPTIONDEF s_aOptions[] = { { "--dummy", 'd', RTGETOPT_REQ_NOTHING } }; int iArg = 0; int ch; RTGETOPTUNION Value; while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value))) switch (ch) { default: return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value); } if (iArg != argc) return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg); /* * Register the service with the service control manager * and start dispatching requests from it (all done by the API). */ static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] = { { SUPSVC_SERVICE_NAME, supSvcWinServiceMain }, { NULL, NULL} }; if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0])) { LogFlowFuncLeave(); return 0; /* told to quit, so quit. */ } DWORD err = GetLastError(); switch (err) { case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n"); break; default: supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err); break; } return 1; }
/** * Handle the 'delete' action. * * @returns 0 or 1. * @param argc The action argument count. * @param argv The action argument vector. */ static int supSvcWinDelete(int argc, char **argv) { /* * Parse the arguments. */ bool fVerbose = false; static const RTGETOPTDEF s_aOptions[] = { { "--verbose", 'v', RTGETOPT_REQ_NOTHING } }; int ch; RTGETOPTUNION Value; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS); while ((ch = RTGetOpt(&GetState, &Value))) switch (ch) { case 'v': fVerbose = true; break; case VINF_GETOPT_NOT_OPTION: return supSvcDisplayTooManyArgsError("delete", argc, argv, iArg); default: return supSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value); } /* * Create the service. */ int rc = 1; SC_HANDLE hSvc = supSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE, 1, ERROR_SERVICE_DOES_NOT_EXIST); if (hSvc) { if (DeleteService(hSvc)) { RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME); rc = 0; } else supSvcDisplayError("delete - DeleteService failed, err=%d.\n", GetLastError()); CloseServiceHandle(hSvc); } else if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { if (fVerbose) RTPrintf("The service %s was not installed, nothing to be done.", SUPSVC_SERVICE_NAME); else RTPrintf("Successfully deleted the %s service.\n", SUPSVC_SERVICE_NAME); rc = 0; } return rc; }
/** * Bitch about too many arguments (after RTGetOpt stops). * * @returns 1 * @param pszAction The action name. * @param argc The argument count. * @param argv The argument vector. * @param iArg The argument index. */ int supSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg) { Assert(iArg < argc); supSvcDisplayError("%s - Too many arguments: %s\n", pszAction, argv[iArg]); return 1; }
/** * Deals with RTGetOpt failure. * * @returns 1 * @param pszAction The action name. * @param rc The RTGetOpt return value. * @param argc The argument count. * @param argv The argument vector. * @param iArg The argument index. * @param pValue The value returned by RTGetOpt. */ int supSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue) { supSvcDisplayError("%s - RTGetOpt failure, %Rrc (%d): %s\n", pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>"); return 1; }
/** * Handle the 'create' action. * * @returns 0 or 1. * @param argc The action argument count. * @param argv The action argument vector. */ static int supSvcWinCreate(int argc, char **argv) { /* * Parse the arguments. */ bool fVerbose = false; static const RTOPTIONDEF s_aOptions[] = { { "--verbose", 'v', RTGETOPT_REQ_NOTHING } }; int iArg = 0; int ch; RTGETOPTUNION Value; while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value))) switch (ch) { case 'v': fVerbose = true; break; default: return supSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value); } if (iArg != argc) return supSvcDisplayTooManyArgsError("create", argc, argv, iArg); /* * Create the service. */ int rc = 1; SC_HANDLE hSCM = supSvcWinOpenSCManager("create", SC_MANAGER_CREATE_SERVICE); /*SC_MANAGER_ALL_ACCESS*/ if (hSCM) { char szExecPath[MAX_PATH]; if (GetModuleFileName(NULL /* the executable */, szExecPath, sizeof(szExecPath))) { if (fVerbose) RTPrintf("Creating the %s service, binary \"%s\"...\n", SUPSVC_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */ SC_HANDLE hSvc = CreateService(hSCM, /* hSCManager */ SUPSVC_SERVICE_NAME, /* lpServiceName */ SUPSVC_SERVICE_DISPLAY_NAME, /* lpDisplayName */ SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */ SERVICE_WIN32_OWN_PROCESS, /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */ SERVICE_DEMAND_START/*_AUTO*/, /* dwStartType */ SERVICE_ERROR_NORMAL, /* dwErrorControl */ szExecPath, /* lpBinaryPathName */ NULL, /* lpLoadOrderGroup */ NULL, /* lpdwTagId */ NULL, /* lpDependencies */ NULL, /* lpServiceStartName (=> LocalSystem) */ NULL); /* lpPassword */ if (hSvc) { RTPrintf("Successfully created the %s service.\n", SUPSVC_SERVICE_NAME); /** @todo Set the service description or it'll look weird in the vista service manager. * Anything else that should be configured? Start access or something? */ rc = 0; CloseServiceHandle(hSvc); } else { DWORD err = GetLastError(); switch (err) { case ERROR_SERVICE_EXISTS: supSvcDisplayError("create - The service already exists.\n"); break; default: supSvcDisplayError("create - CreateService failed, err=%d.\n", GetLastError()); break; } } CloseServiceHandle(hSvc); } else supSvcDisplayError("create - Failed to obtain the executable path: %d\n", GetLastError()); } return rc; }