]> granicus.if.org Git - icinga2/blobdiff - icinga-app/icinga.cpp
Make a few functions static
[icinga2] / icinga-app / icinga.cpp
index d67df4690273a658a3602aab67b9f3da1ba76d39..8a36a9cbd11c8d0115c7323062493a4905349631 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * Icinga 2                                                                   *
- * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/)  *
+ * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/)  *
  *                                                                            *
  * This program is free software; you can redistribute it and/or              *
  * modify it under the terms of the GNU General Public License                *
 #include "base/scriptglobal.hpp"
 #include "base/context.hpp"
 #include "base/console.hpp"
+#include "base/process.hpp"
 #include "config.h"
 #include <boost/program_options.hpp>
 #include <boost/tuple/tuple.hpp>
-#include <boost/foreach.hpp>
+#include <thread>
 
 #ifndef _WIN32
 #      include <sys/types.h>
 #      include <pwd.h>
 #      include <grp.h>
-#else /* _WIN32 */
-#      include <msi.h>
+#else
+#      include <windows.h>
+#      include <Lmcons.h>
+#      include <Shellapi.h>
+#      include <tchar.h>
 #endif /* _WIN32 */
 
 using namespace icinga;
@@ -90,7 +94,7 @@ static std::vector<String> GlobalArgumentCompletion(const String& argument, cons
                return std::vector<String>();
 }
 
-int Main(void)
+static int Main(void)
 {
        int argc = Application::GetArgC();
        char **argv = Application::GetArgV();
@@ -115,9 +119,6 @@ int Main(void)
 
        Application::SetStartTime(Utility::GetTime());
 
-       if (!autocomplete)
-               Application::SetResourceLimits();
-
        /* Set thread title. */
        Utility::SetThreadName("Main Thread", false);
 
@@ -127,37 +128,16 @@ int Main(void)
 #ifdef _WIN32
        bool builtinPaths = true;
 
-       String prefix;
-
-       char szProduct[39];
-       bool foundMsi = false;
-
-       for (int i = 0; MsiEnumProducts(i, szProduct) == ERROR_SUCCESS; i++) {
-               char szName[128];
-               DWORD cbName = sizeof(szName);
-               if (MsiGetProductInfo(szProduct, INSTALLPROPERTY_INSTALLEDPRODUCTNAME, szName, &cbName) != ERROR_SUCCESS)
-                       continue;
-
-               if (strcmp(szName, "Icinga 2") != 0)
-                       continue;
-
-               char szLocation[1024];
-               DWORD cbLocation = sizeof(szLocation);
-               if (MsiGetProductInfo(szProduct, INSTALLPROPERTY_INSTALLLOCATION, szLocation, &cbLocation) == ERROR_SUCCESS) {
-                       builtinPaths = false;
-                       prefix = szLocation;
-                       foundMsi = true;
-                       break;
-               }
-       }
+       String binaryPrefix = Utility::GetIcingaInstallPath();
+       String dataPrefix = Utility::GetIcingaDataPath();
 
-       if (!builtinPaths) {
-               Application::DeclarePrefixDir(prefix);
-               Application::DeclareSysconfDir(prefix + "\\etc");
-               Application::DeclareRunDir(prefix + "\\var\\run");
-               Application::DeclareLocalStateDir(prefix + "\\var");
-               Application::DeclarePkgDataDir(prefix + "\\share\\icinga2");
-               Application::DeclareIncludeConfDir(prefix + "\\share\\icinga2\\include");
+       if (!binaryPrefix.IsEmpty() && !dataPrefix.IsEmpty()) {
+               Application::DeclarePrefixDir(binaryPrefix);
+               Application::DeclareSysconfDir(dataPrefix + "\\etc");
+               Application::DeclareRunDir(dataPrefix + "\\var\\run");
+               Application::DeclareLocalStateDir(dataPrefix + "\\var");
+               Application::DeclarePkgDataDir(binaryPrefix + "\\share\\icinga2");
+               Application::DeclareIncludeConfDir(binaryPrefix + "\\share\\icinga2\\include");
        } else {
                Log(LogWarning, "icinga-app", "Registry key could not be read. Falling back to built-in paths.");
 
@@ -175,14 +155,12 @@ int Main(void)
        Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d");
        Application::DeclareRunAsUser(ICINGA_USER);
        Application::DeclareRunAsGroup(ICINGA_GROUP);
-       Application::DeclareConcurrency(boost::thread::hardware_concurrency());
-
-       if (!ScriptGlobal::Exists("UseVfork"))
-#ifdef __APPLE__
-               ScriptGlobal::Set("UseVfork", false);
-#else /* __APPLE__ */
-               ScriptGlobal::Set("UseVfork", true);
-#endif /* __APPLE__ */
+#ifdef __linux__
+       Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles());
+       Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses());
+       Application::DeclareRLimitStack(Application::GetDefaultRLimitStack());
+#endif /* __linux__ */
+       Application::DeclareConcurrency(std::thread::hardware_concurrency());
 
        ScriptGlobal::Set("AttachDebugger", false);
 
@@ -192,6 +170,32 @@ int Main(void)
        ScriptGlobal::Set("PlatformVersion", Utility::GetPlatformVersion());
        ScriptGlobal::Set("PlatformArchitecture", Utility::GetPlatformArchitecture());
 
+       ScriptGlobal::Set("BuildHostName", ICINGA_BUILD_HOST_NAME);
+       ScriptGlobal::Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME);
+       ScriptGlobal::Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION);
+
+       String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";
+
+       if (Utility::PathExists(initconfig)) {
+               Expression *expression;
+               try {
+                       expression = ConfigCompiler::CompileFile(initconfig);
+
+                       ScriptFrame frame;
+                       expression->Evaluate(frame);
+               } catch (const std::exception& ex) {
+                       delete expression;
+
+                       Log(LogCritical, "config", DiagnosticInformation(ex));
+                       return EXIT_FAILURE;
+               }
+
+               delete expression;
+       }
+
+       if (!autocomplete)
+               Application::SetResourceLimits();
+
        LogSeverity logLevel = Logger::GetConsoleLogSeverity();
        Logger::SetConsoleLogSeverity(LogWarning);
 
@@ -235,24 +239,73 @@ int Main(void)
                return EXIT_FAILURE;
        }
 
-       String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf";
+#ifdef _WIN32
+       char username[UNLEN + 1];
+       DWORD usernameLen = UNLEN + 1;
+       GetUserName(username, &usernameLen);
 
-       if (Utility::PathExists(initconfig)) {
-               Expression *expression;
-               try {
-                       expression = ConfigCompiler::CompileFile(initconfig);
+       std::ifstream userFile;
+       userFile.open(Application::GetSysconfDir() + "/icinga2/user");
 
-                       ScriptFrame frame;
-                       expression->Evaluate(frame);
-               } catch (const std::exception& ex) {
-                       delete expression;
+       if (userFile && command && !Application::IsProcessElevated()) {
+               std::string userLine;
+               if (std::getline(userFile, userLine)) {
+                       userFile.close();
 
-                       Log(LogCritical, "config", DiagnosticInformation(ex));
-                       return EXIT_FAILURE;
-               }
+                       std::vector<std::string> strs;
+                       boost::split(strs, userLine, boost::is_any_of("\\"));
 
-               delete expression;
+                       if (username != strs[1] && command->GetImpersonationLevel() == ImpersonationLevel::ImpersonateIcinga
+                               || command->GetImpersonationLevel() == ImpersonationLevel::ImpersonateRoot) {
+                               TCHAR szPath[MAX_PATH];
+
+                               if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) { 
+                                       SHELLEXECUTEINFO sei = { sizeof(sei) };
+                                       sei.lpVerb = _T("runas");
+                                       sei.lpFile = "cmd.exe";
+                                       sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI;
+                                       sei.nShow = SW_SHOW;
+
+                                       std::stringstream parameters;
+
+                                       parameters << "/C " << "\"" << szPath << "\"" << " ";
+
+                                       for (int i = 1; i < argc; i++) {
+                                               if (i != 1)
+                                                       parameters << " ";
+                                               parameters << argv[i];
+                                       }
+
+                                       parameters << " & SET exitcode=%errorlevel%";
+                                       parameters << " & pause";
+                                       parameters << " & EXIT /B %exitcode%";
+
+                                       std::string str = parameters.str();
+                                       LPCSTR cstr = str.c_str();
+
+                                       sei.lpParameters = cstr;
+
+                                       if (!ShellExecuteEx(&sei)) {
+                                               DWORD dwError = GetLastError();
+                                               if (dwError == ERROR_CANCELLED)
+                                                       Application::Exit(0);
+                                       } else {
+                                               WaitForSingleObject(sei.hProcess, INFINITE);
+
+                                               DWORD exitCode;
+                                               GetExitCodeProcess(sei.hProcess, &exitCode);
+
+                                               CloseHandle(sei.hProcess);
+
+                                               Application::Exit(exitCode);
+                                       }
+                               }
+                       }
+               } else {
+                       userFile.close();
+               }
        }
+#endif /* _WIN32 */
 
 #ifndef _WIN32
        if (vm.count("color")) {
@@ -262,7 +315,7 @@ int Main(void)
 #endif /* _WIN32 */
 
        if (vm.count("define")) {
-               BOOST_FOREACH(const String& define, vm["define"].as<std::vector<std::string> >()) {
+               for (const String& define : vm["define"].as<std::vector<std::string> >()) {
                        String key, value;
                        size_t pos = define.FindFirstOf('=');
                        if (pos != String::NPos) {
@@ -288,7 +341,7 @@ int Main(void)
        ConfigCompiler::AddIncludeSearchDir(Application::GetIncludeConfDir());
 
        if (!autocomplete && vm.count("include")) {
-               BOOST_FOREACH(const String& includePath, vm["include"].as<std::vector<std::string> >()) {
+               for (const String& includePath : vm["include"].as<std::vector<std::string> >()) {
                        ConfigCompiler::AddIncludeSearchDir(includePath);
                }
        }
@@ -312,7 +365,7 @@ int Main(void)
                }
 
                if (vm.count("library")) {
-                       BOOST_FOREACH(const String& libraryName, vm["library"].as<std::vector<std::string> >()) {
+                       for (const String& libraryName : vm["library"].as<std::vector<std::string> >()) {
                                try {
                                        (void) Loader::LoadExtensionLibrary(libraryName);
                                } catch (const std::exception& ex) {
@@ -347,7 +400,7 @@ int Main(void)
 
                        if ((!command || vm.count("help")) && !vm.count("version")) {
                                std::cout << "Usage:" << std::endl
-                                   << "  " << argv[0] << " ";
+                                   << "  " << Utility::BaseName(argv[0]) << " ";
 
                                if (cmdname.IsEmpty())
                                        std::cout << "<command>";
@@ -363,7 +416,7 @@ int Main(void)
                        }
 
                        if (vm.count("version")) {
-                               std::cout << "Copyright (c) 2012-2016 Icinga Development Team (https://www.icinga.org/)" << std::endl
+                               std::cout << "Copyright (c) 2012-2017 Icinga Development Team (https://www.icinga.com/)" << std::endl
                                        << "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl2.html>" << std::endl
                                        << "This is free software: you are free to change and redistribute it." << std::endl
                                        << "There is NO WARRANTY, to the extent permitted by law.";
@@ -385,8 +438,8 @@ int Main(void)
                                CLICommand::ShowCommands(argc, argv, NULL);
 
                        std::cout << visibleDesc << std::endl
-                               << "Report bugs at <https://dev.icinga.org/>" << std::endl
-                               << "Icinga home page: <https://www.icinga.org/>" << std::endl;
+                               << "Report bugs at <https://github.com/Icinga/icinga2>" << std::endl
+                               << "Icinga home page: <https://www.icinga.com/>" << std::endl;
                        return EXIT_SUCCESS;
                }
        }
@@ -474,20 +527,22 @@ int Main(void)
                                }
                        }
                }
+
+               Process::InitializeSpawnHelper();
 #endif /* _WIN32 */
 
                std::vector<std::string> args;
                if (vm.count("arg"))
                        args = vm["arg"].as<std::vector<std::string> >();
 
-               if (args.size() < command->GetMinArguments()) {
+               if (static_cast<int>(args.size()) < command->GetMinArguments()) {
                        Log(LogCritical, "cli")
                            << "Too few arguments. Command needs at least " << command->GetMinArguments()
                            << " argument" << (command->GetMinArguments() != 1 ? "s" : "") << ".";
                        return EXIT_FAILURE;
                }
 
-               if (command->GetMaxArguments() >= 0 && args.size() > command->GetMaxArguments()) {
+               if (command->GetMaxArguments() >= 0 && static_cast<int>(args.size()) > command->GetMaxArguments()) {
                        Log(LogCritical, "cli")
                            << "Too many arguments. At most " << command->GetMaxArguments()
                            << " argument" << (command->GetMaxArguments() != 1 ? "s" : "") << " may be specified.";
@@ -533,8 +588,20 @@ static int SetupService(bool install, int argc, char **argv)
        String szArgs;
        szArgs = Utility::EscapeShellArg(szPath) + " --scm";
 
-       for (int i = 0; i < argc; i++)
-               szArgs += " " + Utility::EscapeShellArg(argv[i]);
+       std::string scmUser = "NT AUTHORITY\\NetworkService";
+       std::ifstream initf(Utility::GetIcingaDataPath() + "\\etc\\icinga2\\user");
+       if (initf.good()) {
+               std::getline(initf, scmUser);
+       }
+       initf.close();
+
+       for (int i = 0; i < argc; i++) {
+               if (!strcmp(argv[i], "--scm-user") && i + 1 < argc) {
+                       scmUser = argv[i + 1];
+                       i++;
+               } else
+                       szArgs += " " + Utility::EscapeShellArg(argv[i]);
+       }
 
        SC_HANDLE schService = OpenService(schSCManager, "icinga2", SERVICE_ALL_ACCESS);
 
@@ -571,14 +638,14 @@ static int SetupService(bool install, int argc, char **argv)
                        NULL,
                        NULL,
                        NULL,
-                       "NT AUTHORITY\\NetworkService",
+                       scmUser.c_str(),
                        NULL);
 
                if (schService == NULL) {
                        printf("CreateService failed (%d)\n", GetLastError());
                        CloseServiceHandle(schSCManager);
                        return 1;
-               }       
+               }
        } else {
                printf("Service isn't installed.\n");
                CloseServiceHandle(schSCManager);
@@ -595,11 +662,21 @@ static int SetupService(bool install, int argc, char **argv)
 
                printf("Service uninstalled successfully\n");
        } else {
-               ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_AUTO_START,
-                   SERVICE_ERROR_NORMAL, szArgs.CStr(), NULL, NULL, NULL, NULL, NULL, NULL);
+               if (!ChangeServiceConfig(schService, SERVICE_NO_CHANGE, SERVICE_AUTO_START,
+                       SERVICE_ERROR_NORMAL, szArgs.CStr(), NULL, NULL, NULL, scmUser.c_str(), NULL, NULL)) {
+                       printf("ChangeServiceConfig failed (%d)\n", GetLastError());
+                       CloseServiceHandle(schService);
+                       CloseServiceHandle(schSCManager);
+                       return 1;
+               }
 
                SERVICE_DESCRIPTION sdDescription = { "The Icinga 2 monitoring application" };
-               ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription);
+               if(!ChangeServiceConfig2(schService, SERVICE_CONFIG_DESCRIPTION, &sdDescription)) {
+                       printf("ChangeServiceConfig2 failed (%d)\n", GetLastError());
+                       CloseServiceHandle(schService);
+                       CloseServiceHandle(schSCManager);
+                       return 1;
+               }
 
                if (!StartService(schService, 0, NULL)) {
                        printf("StartService failed (%d)\n", GetLastError());
@@ -608,7 +685,14 @@ static int SetupService(bool install, int argc, char **argv)
                        return 1;
                }
 
-               printf("Service installed successfully\n");
+               printf("Service successfully installed for user '%s'\n", scmUser);
+
+               std::ofstream fuser(Utility::GetIcingaDataPath() + "\\etc\\icinga2\\user", std::ios::out | std::ios::trunc);
+               if (fuser)
+                       fuser << scmUser;
+               else
+                       printf("Could not write user to %s\\etc\\icinga2\\user", Utility::GetIcingaDataPath());
+               fuser.close();
        }
 
        CloseServiceHandle(schService);
@@ -617,7 +701,7 @@ static int SetupService(bool install, int argc, char **argv)
        return 0;
 }
 
-VOID ReportSvcStatus(DWORD dwCurrentState,
+static VOID ReportSvcStatus(DWORD dwCurrentState,
        DWORD dwWin32ExitCode,
        DWORD dwWaitHint)
 {
@@ -641,7 +725,7 @@ VOID ReportSvcStatus(DWORD dwCurrentState,
        SetServiceStatus(l_SvcStatusHandle, &l_SvcStatus);
 }
 
-VOID WINAPI ServiceControlHandler(DWORD dwCtrl)
+static VOID WINAPI ServiceControlHandler(DWORD dwCtrl)
 {
        if (dwCtrl == SERVICE_CONTROL_STOP) {
                ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
@@ -649,7 +733,7 @@ VOID WINAPI ServiceControlHandler(DWORD dwCtrl)
        }
 }
 
-VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
+static VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
 {
        l_SvcStatusHandle = RegisterServiceCtrlHandler(
                "icinga2",
@@ -659,7 +743,6 @@ VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
        l_SvcStatus.dwServiceSpecificExitCode = 0;
 
        ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
-
        l_Job = CreateJobObject(NULL, NULL);
 
        for (;;) {
@@ -725,20 +808,22 @@ VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
 int main(int argc, char **argv)
 {
 #ifndef _WIN32
-       rlimit rl;
-       if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
-               rlim_t maxfds = rl.rlim_max;
+       if (!getenv("ICINGA2_KEEP_FDS")) {
+               rlimit rl;
+               if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
+                       rlim_t maxfds = rl.rlim_max;
 
-               if (maxfds == RLIM_INFINITY)
-                       maxfds = 65536;
+                       if (maxfds == RLIM_INFINITY)
+                               maxfds = 65536;
 
-               for (rlim_t i = 3; i < maxfds; i++) {
-                       int rc = close(i);
+                       for (rlim_t i = 3; i < maxfds; i++) {
+                               int rc = close(i);
 
 #ifdef I2_DEBUG
-                       if (rc >= 0)
-                               std::cerr << "Closed FD " << i << " which we inherited from our parent process." << std::endl;
+                               if (rc >= 0)
+                                       std::cerr << "Closed FD " << i << " which we inherited from our parent process." << std::endl;
 #endif /* I2_DEBUG */
+                       }
                }
        }
 #endif /* _WIN32 */