summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-09-11 23:33:23 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-09-11 23:33:23 -0400
commit09f98576e882a5fef68cdefdff939834a8782eaa (patch)
treeb3094bf7e84d5479b2e6806b0c5103788cf871d5 /src
parent9c59c739d4ef9a4479ac849badc998b200fddb13 (diff)
added env::getFileSecurity()
Environment gets stuff on demand
Diffstat (limited to 'src')
-rw-r--r--src/env.cpp31
-rw-r--r--src/env.h21
-rw-r--r--src/envsecurity.cpp332
-rw-r--r--src/envsecurity.h17
4 files changed, 388 insertions, 13 deletions
diff --git a/src/env.cpp b/src/env.cpp
index 411443c5..e2b85560 100644
--- a/src/env.cpp
+++ b/src/env.cpp
@@ -57,10 +57,7 @@ Console::~Console()
Environment::Environment()
- : m_windows(new WindowsInfo), m_metrics(new Metrics)
{
- m_modules = getLoadedModules();
- m_security = getSecurityProducts();
}
// anchor
@@ -68,48 +65,64 @@ Environment::~Environment() = default;
const std::vector<Module>& Environment::loadedModules() const
{
+ if (m_modules.empty()){
+ m_modules = getLoadedModules();
+ }
+
return m_modules;
}
const WindowsInfo& Environment::windowsInfo() const
{
+ if (!m_windows) {
+ m_windows.reset(new WindowsInfo);
+ }
+
return *m_windows;
}
const std::vector<SecurityProduct>& Environment::securityProducts() const
{
+ if (m_security.empty()) {
+ m_security = getSecurityProducts();
+ }
+
return m_security;
}
const Metrics& Environment::metrics() const
{
+ if (!m_metrics) {
+ m_metrics.reset(new Metrics);
+ }
+
return *m_metrics;
}
void Environment::dump(const Settings& s) const
{
- log::debug("windows: {}", m_windows->toString());
+ log::debug("windows: {}", windowsInfo().toString());
- if (m_windows->compatibilityMode()) {
+ if (windowsInfo().compatibilityMode()) {
log::warn("MO seems to be running in compatibility mode");
}
log::debug("security products:");
- for (const auto& sp : m_security) {
+ for (const auto& sp : securityProducts()) {
log::debug(" . {}", sp.toString());
}
log::debug("modules loaded in process:");
- for (const auto& m : m_modules) {
+ for (const auto& m : loadedModules()) {
log::debug(" . {}", m.toString());
}
log::debug("displays:");
- for (const auto& d : m_metrics->displays()) {
+ for (const auto& d : metrics().displays()) {
log::debug(" . {}", d.toString());
}
- const auto r = m_metrics->desktopGeometry();
+ const auto r = metrics().desktopGeometry();
log::debug(
"desktop geometry: ({},{})-({},{})",
r.left(), r.top(), r.right(), r.bottom());
diff --git a/src/env.h b/src/env.h
index 1f146a08..46095ca3 100644
--- a/src/env.h
+++ b/src/env.h
@@ -79,6 +79,19 @@ template <class T>
using COMPtr = std::unique_ptr<T, COMReleaser>;
+// used by MallocPtr, calls std::free() as the deleter
+//
+struct MallocFreer
+{
+ void operator()(void* p)
+ {
+ std::free(p);
+ }
+};
+
+template <class T>
+using MallocPtr = std::unique_ptr<T, MallocFreer>;
+
// creates a console in the constructor and destroys it in the destructor,
// also redirects standard streams
//
@@ -133,10 +146,10 @@ public:
void dump(const Settings& s) const;
private:
- std::vector<Module> m_modules;
- std::unique_ptr<WindowsInfo> m_windows;
- std::vector<SecurityProduct> m_security;
- std::unique_ptr<Metrics> m_metrics;
+ mutable std::vector<Module> m_modules;
+ mutable std::unique_ptr<WindowsInfo> m_windows;
+ mutable std::vector<SecurityProduct> m_security;
+ mutable std::unique_ptr<Metrics> m_metrics;
// dumps all the disks involved in the settings
//
diff --git a/src/envsecurity.cpp b/src/envsecurity.cpp
index 376be4df..6e3fadbe 100644
--- a/src/envsecurity.cpp
+++ b/src/envsecurity.cpp
@@ -9,6 +9,11 @@
#include <netfw.h>
#pragma comment(lib, "Wbemuuid.lib")
+#include <accctrl.h>
+#include <aclapi.h>
+#include <sddl.h>
+#pragma comment(lib, "advapi32.lib")
+
namespace env
{
@@ -397,4 +402,331 @@ std::vector<SecurityProduct> getSecurityProducts()
return v;
}
+
+class failed
+{
+public:
+ failed(DWORD e, QString what)
+ : m_what(what + ", " + QString::fromStdWString(formatSystemMessage(e)))
+ {
+ }
+
+ QString what() const
+ {
+ return m_what;
+ }
+
+private:
+ QString m_what;
+};
+
+
+MallocPtr<SECURITY_DESCRIPTOR> getSecurityDescriptor(const QString& path)
+{
+ const auto wpath = path.toStdWString();
+ BOOL ret = FALSE;
+
+ DWORD length = 0;
+ ret = ::GetFileSecurityW(
+ wpath.c_str(), DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
+ nullptr, 0, &length);
+
+ if (!ret || length == 0) {
+ const auto e = GetLastError();
+
+ if (e != ERROR_INSUFFICIENT_BUFFER) {
+ if (e == ERROR_ACCESS_DENIED) {
+ // if this fails, the user doesn't even have permissions to get the
+ // security descriptor, which probably means they're not the owner and
+ // their effective access is none
+ throw failed(e, "cannot get security descriptor");
+ } else {
+ // other error
+ throw failed(e, "GetFileSecurity() for length failed");
+ }
+ }
+ }
+
+ MallocPtr<SECURITY_DESCRIPTOR> sd(
+ static_cast<SECURITY_DESCRIPTOR*>(std::malloc(length)));
+
+ std::memset(sd.get(), 0, length);
+
+ ret = ::GetFileSecurityW(
+ wpath.c_str(), DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
+ sd.get(), length, &length);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "GetFileSecurity()");
+ }
+
+ return sd;
+}
+
+PACL getDacl(SECURITY_DESCRIPTOR* sd)
+{
+ BOOL present = FALSE;
+ BOOL daclDefaulted = FALSE;
+ PACL acl = nullptr;
+
+ BOOL ret = ::GetSecurityDescriptorDacl(sd, &present, &acl, &daclDefaulted);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "GetSecurityDescriptorDacl()");
+ }
+
+ if (!present) {
+ return nullptr;
+ }
+
+ return acl;
+}
+
+PSID getFileOwner(SECURITY_DESCRIPTOR* sd)
+{
+ BOOL ownerDefaulted = FALSE;
+ PSID owner;
+
+ BOOL ret = ::GetSecurityDescriptorOwner(sd, &owner, &ownerDefaulted);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "GetSecurityDescriptionOwner()");
+ }
+
+ return owner;
+}
+
+MallocPtr<void> getCurrentUser()
+{
+ HANDLE hnd = ::GetCurrentProcess();
+ HANDLE rawToken = 0;
+
+ BOOL ret = ::OpenProcessToken(hnd, TOKEN_QUERY, &rawToken);
+ if (!ret) {
+ const auto e = GetLastError();
+ throw(e, "OpenProcessToken()");
+ }
+
+ HandlePtr token(rawToken);
+
+ DWORD retsize = 0;
+ ret = ::GetTokenInformation(token.get(), TokenUser, 0, 0, &retsize);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ if (e != ERROR_INSUFFICIENT_BUFFER) {
+ throw failed(e, "GetTokenInformation() for length");
+ }
+ }
+
+ MallocPtr<void> tokenBuffer(std::malloc(retsize));
+ ret = ::GetTokenInformation(
+ token.get(), TokenUser, tokenBuffer.get(), retsize, &retsize);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "GetTokenInformation()");
+ }
+
+ PSID tokenSid = ((PTOKEN_USER)(tokenBuffer.get()))->User.Sid;
+ DWORD sidLen = ::GetLengthSid(tokenSid);
+ MallocPtr<void> currentUserSID((SID*)(malloc(sidLen)));
+
+ ret = ::CopySid(sidLen, currentUserSID.get(), tokenSid);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "CopySid()");
+ }
+
+ return currentUserSID;
+}
+
+ACCESS_MASK getEffectiveRights(ACL* dacl, PSID sid)
+{
+ TRUSTEEW trustee = {};
+ BuildTrusteeWithSid(&trustee, sid);
+
+ ACCESS_MASK access = 0;
+ DWORD ret = ::GetEffectiveRightsFromAclW(dacl, &trustee, &access);
+
+ if (ret != ERROR_SUCCESS) {
+ throw failed(ret, "GetEffectiveRightsFromAclW()");
+ }
+
+ return access;
+}
+
+QString getUsername(PSID owner)
+{
+ DWORD nameSize=0, domainSize=0;
+ auto use = SidTypeUnknown;
+
+ BOOL ret = LookupAccountSidW(
+ nullptr, owner, nullptr, &nameSize, nullptr, &domainSize, &use);
+
+ if (!ret) {
+ const auto e = GetLastError();
+
+ if (e != ERROR_INSUFFICIENT_BUFFER) {
+ throw failed(e, "LookupAccountSid() for sizes");
+ }
+ }
+
+ auto wsName = std::make_unique<wchar_t[]>(nameSize);
+ auto wsDomain = std::make_unique<wchar_t[]>(domainSize);
+
+ ret = LookupAccountSidW(
+ nullptr, owner, wsName.get(), &nameSize, wsDomain.get(), &domainSize, &use);
+
+ if (!ret) {
+ const auto e = GetLastError();
+ throw failed(e, "LookupAccountSid()");
+ }
+
+ const QString name = QString::fromWCharArray(wsName.get(), nameSize);
+ const QString domain = QString::fromWCharArray(wsDomain.get(), domainSize);
+
+ if (!name.isEmpty() && !domain.isEmpty()) {
+ return domain + "\\" + name;
+ } else {
+ // either or both are empty
+ return name + domain;
+ }
+}
+
+FileRights makeFileRights(ACCESS_MASK m)
+{
+ FileRights fr;
+
+ if (m & FILE_GENERIC_READ) {
+ fr.list.push_back("file_generic_read");
+ } else {
+ if (m & READ_CONTROL) {
+ fr.list.push_back("read_ctrl");
+ }
+
+ if (m & FILE_READ_DATA) {
+ fr.list.push_back("read_data");
+ }
+
+ if (m & FILE_READ_ATTRIBUTES) {
+ fr.list.push_back("read_atts");
+ }
+
+ if (m & FILE_READ_EA) {
+ fr.list.push_back("read_ex_atts");
+ }
+
+ if (m & SYNCHRONIZE) {
+ fr.list.push_back("sync");
+ }
+ }
+
+ if (m & FILE_GENERIC_WRITE) {
+ fr.list.push_back("file_generic_write");
+ } else {
+ // READ_CONTROL handled above
+
+ if (m & FILE_WRITE_DATA) {
+ fr.list.push_back("write_data");
+ }
+
+ if (m & FILE_WRITE_ATTRIBUTES) {
+ fr.list.push_back("write_atts");
+ }
+
+ if (m & FILE_WRITE_EA) {
+ fr.list.push_back("write_ex_atts");
+ }
+
+ if (m & FILE_APPEND_DATA) {
+ fr.list.push_back("append_data");
+ }
+
+ // SYNCHRONIZE handled above
+ }
+
+ if (m & FILE_GENERIC_EXECUTE) {
+ fr.list.push_back("file_generic_execute");
+ fr.hasExecute = true;
+ } else {
+ // READ_CONTROL handled above
+ // FILE_READ_ATTRIBUTES handled above
+
+ if (m & FILE_EXECUTE) {
+ fr.list.push_back("execute");
+ fr.hasExecute = true;
+ }
+
+ // SYNCHRONIZE handled above
+ }
+
+ if (m & DELETE) {
+ fr.list.push_back("delete");
+ }
+
+ if (m & WRITE_DAC) {
+ fr.list.push_back("write_dac");
+ }
+
+ if (m & WRITE_OWNER) {
+ fr.list.push_back("write_owner");
+ }
+
+ if (m & GENERIC_ALL) {
+ fr.list.push_back("generic_all");
+ }
+
+ if (m & GENERIC_WRITE) {
+ fr.list.push_back("generic_write");
+ }
+
+ if (m & GENERIC_READ) {
+ fr.list.push_back("generic_read");
+ }
+
+ // 0x001f01ff
+ const auto normalRights =
+ STANDARD_RIGHTS_ALL |
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE |
+ FILE_DELETE_CHILD;
+
+ if (m == normalRights) {
+ fr.normalRights = true;
+ }
+
+ return fr;
+}
+
+FileSecurity getFileSecurity(const QString& path)
+{
+ FileSecurity fs;
+
+ try
+ {
+ auto sd = getSecurityDescriptor(path);
+ auto dacl = getDacl(sd.get());
+ auto currentUser = getCurrentUser();
+ auto owner = getFileOwner(sd.get());
+ auto access = getEffectiveRights(dacl, currentUser.get());
+
+ fs.rights = makeFileRights(access);
+
+ if (EqualSid(owner, currentUser.get())) {
+ fs.owner = "(this user)";
+ } else {
+ fs.owner = getUsername(owner);
+ }
+ }
+ catch(failed& f)
+ {
+ fs.error = f.what();
+ }
+
+ return fs;
+}
} // namespace
diff --git a/src/envsecurity.h b/src/envsecurity.h
index bc63c4a2..436103b7 100644
--- a/src/envsecurity.h
+++ b/src/envsecurity.h
@@ -49,6 +49,23 @@ private:
std::vector<SecurityProduct> getSecurityProducts();
+
+struct FileRights
+{
+ QStringList list;
+ bool hasExecute = false;
+ bool normalRights = false;
+};
+
+struct FileSecurity
+{
+ QString owner;
+ FileRights rights;
+ QString error;
+};
+
+FileSecurity getFileSecurity(const QString& file);
+
} // namespace env
#endif // ENV_SECURITY_H