/******************************************************************************
* 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
+# include <windows.h>
+# include <Lmcons.h>
+# include <Shellapi.h>
+# include <tchar.h>
#endif /* _WIN32 */
using namespace icinga;
return std::vector<String>();
}
-int Main(void)
+static int Main(void)
{
int argc = Application::GetArgC();
char **argv = Application::GetArgV();
Application::SetStartTime(Utility::GetTime());
- if (!autocomplete)
- Application::SetResourceLimits();
-
/* Set thread title. */
Utility::SetThreadName("Main Thread", false);
#ifdef _WIN32
bool builtinPaths = true;
- HKEY hKey;
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Icinga Development Team\\ICINGA2", 0,
- KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) {
- BYTE pvData[MAX_PATH];
- DWORD cbData = sizeof(pvData)-1;
- DWORD lType;
- if (RegQueryValueEx(hKey, NULL, NULL, &lType, pvData, &cbData) == ERROR_SUCCESS && lType == REG_SZ) {
- pvData[cbData] = '\0';
-
- String prefix = (char *)pvData;
- 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");
-
- builtinPaths = false;
- }
-
- RegCloseKey(hKey);
- }
+ String binaryPrefix = Utility::GetIcingaInstallPath();
+ String dataPrefix = Utility::GetIcingaDataPath();
- if (builtinPaths) {
+ 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.");
#endif /* _WIN32 */
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);
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);
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")) {
#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) {
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);
}
}
}
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) {
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>";
}
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.";
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;
}
}
}
}
}
+
+ 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.";
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);
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);
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());
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);
return 0;
}
-VOID ReportSvcStatus(DWORD dwCurrentState,
+static VOID ReportSvcStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
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);
}
}
-VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
+static VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
l_SvcStatusHandle = RegisterServiceCtrlHandler(
"icinga2",
l_SvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
-
l_Job = CreateJobObject(NULL, NULL);
for (;;) {
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 */