mirror of https://github.com/Icinga/icinga2.git
Merge pull request #5602 from Icinga/fix/config-validation-fails-on-windows-with-unprivileged-account-5515
Add windows process elevation and log message if user does not have privileges to read/write files
This commit is contained in:
commit
9d68ae9f1f
|
@ -40,6 +40,11 @@
|
|||
# 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;
|
||||
|
@ -233,6 +238,74 @@ int Main(void)
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
char username[UNLEN + 1];
|
||||
DWORD usernameLen = UNLEN + 1;
|
||||
GetUserName(username, &usernameLen);
|
||||
|
||||
std::ifstream userFile;
|
||||
userFile.open(Application::GetSysconfDir() + "/icinga2/user");
|
||||
|
||||
if (userFile && command && !Application::IsProcessElevated()) {
|
||||
std::string userLine;
|
||||
if (std::getline(userFile, userLine)) {
|
||||
userFile.close();
|
||||
|
||||
std::vector<std::string> strs;
|
||||
boost::split(strs, userLine, boost::is_any_of("\\"));
|
||||
|
||||
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")) {
|
||||
Console::SetType(std::cout, Console_VT100);
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
#include <sys/prctl.h>
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif /* _win32 */
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_TYPE(Application);
|
||||
|
@ -780,6 +784,40 @@ BOOL WINAPI Application::CtrlHandler(DWORD type)
|
|||
SetConsoleCtrlHandler(NULL, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool Application::IsProcessElevated(void) {
|
||||
BOOL fIsElevated = FALSE;
|
||||
DWORD dwError = ERROR_SUCCESS;
|
||||
HANDLE hToken = NULL;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
||||
dwError = GetLastError();
|
||||
else {
|
||||
TOKEN_ELEVATION elevation;
|
||||
DWORD dwSize;
|
||||
|
||||
if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize))
|
||||
dwError = GetLastError();
|
||||
else
|
||||
fIsElevated = elevation.TokenIsElevated;
|
||||
}
|
||||
|
||||
if (hToken) {
|
||||
CloseHandle(hToken);
|
||||
hToken = NULL;
|
||||
}
|
||||
|
||||
if (ERROR_SUCCESS != dwError) {
|
||||
LPSTR mBuf = NULL;
|
||||
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), mBuf, 0, NULL))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to format error message, last error was: " + dwError));
|
||||
else
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(mBuf));
|
||||
}
|
||||
|
||||
return fIsElevated;
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
/**
|
||||
|
|
|
@ -126,6 +126,10 @@ public:
|
|||
static String GetRunAsGroup(void);
|
||||
static void DeclareRunAsGroup(const String& group);
|
||||
|
||||
#ifdef _WIN32
|
||||
static bool IsProcessElevated(void);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
static int GetRLimitFiles(void);
|
||||
static int GetDefaultRLimitFiles(void);
|
||||
static void DeclareRLimitFiles(int limit);
|
||||
|
|
|
@ -106,11 +106,16 @@ bool DaemonUtility::ValidateConfigFiles(const std::vector<std::string>& configs,
|
|||
|
||||
if (!configs.empty()) {
|
||||
for (const String& configPath : configs) {
|
||||
Expression *expression = ConfigCompiler::CompileFile(configPath, String(), "_etc");
|
||||
success = ExecuteExpression(expression);
|
||||
delete expression;
|
||||
if (!success)
|
||||
return false;
|
||||
try {
|
||||
Expression *expression = ConfigCompiler::CompileFile(configPath, String(), "_etc");
|
||||
success = ExecuteExpression(expression);
|
||||
delete expression;
|
||||
if (!success)
|
||||
return false;
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogCritical, "cli", "Could not compile config files: " + DiagnosticInformation(ex, false));
|
||||
Application::Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +183,13 @@ bool DaemonUtility::LoadConfigFiles(const std::vector<std::string>& configs,
|
|||
}
|
||||
|
||||
ConfigCompilerContext::GetInstance()->FinishObjectsFile();
|
||||
ScriptGlobal::WriteToFile(varsfile);
|
||||
|
||||
try {
|
||||
ScriptGlobal::WriteToFile(varsfile);
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogCritical, "cli", "Could not write vars file: " + DiagnosticInformation(ex, false));
|
||||
Application::Exit(1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "base/json.hpp"
|
||||
#include "base/netstring.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/application.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
|
@ -39,7 +40,12 @@ void ConfigCompilerContext::OpenObjectsFile(const String& filename)
|
|||
m_ObjectsPath = filename;
|
||||
|
||||
std::fstream *fp = new std::fstream();
|
||||
m_ObjectsTempFile = Utility::CreateTempFile(filename + ".XXXXXX", 0600, *fp);
|
||||
try {
|
||||
m_ObjectsTempFile = Utility::CreateTempFile(filename + ".XXXXXX", 0600, *fp);
|
||||
} catch (const std::exception& ex) {
|
||||
Log(LogCritical, "cli", "Could not create temporary objects file: " + DiagnosticInformation(ex, false));
|
||||
Application::Exit(1);
|
||||
}
|
||||
|
||||
if (!*fp)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + m_ObjectsTempFile + "' file"));
|
||||
|
|
Loading…
Reference in New Issue