]> granicus.if.org Git - icinga2/commitdiff
Add process elevation & log message if user does not have enough privileges 5602/head
authorNoah Hilverling <noah.hilverling@icinga.com>
Tue, 22 Aug 2017 08:26:23 +0000 (10:26 +0200)
committerNoah Hilverling <noah.hilverling@icinga.com>
Fri, 22 Sep 2017 08:25:17 +0000 (10:25 +0200)
refs #5515

icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.hpp
lib/cli/daemonutility.cpp
lib/config/configcompilercontext.cpp

index 2007e8c589a663889ebdd1bf7137a7010562bc15..f5665c9830d9f969206ef169560caef33fd213a5 100644 (file)
 #      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);
index c1c2692c82160a74b22f5ddebe7f15261cb87140..ce4982e2a570ac52e185f6df068cde06b75000f7 100644 (file)
 #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 */
 
 /**
index 5c1469e12ab4974bb201dcb0a030b2488d7e2331..bd04bbd02a975d841a9f09fca363715028b2af60 100644 (file)
@@ -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);
index e89b40a9ac7e6dfefbdb1cf4720a679fbbd326eb..c6748947ec13ab8337d253aebbacf7ba5ac4418a 100644 (file)
@@ -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;
 }
index 25135412647fdb2f58793cc303f26bc3adba2389..fcb9c13d50f5c77613f773e0d740fd90a37fbf59 100644 (file)
@@ -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"));