From 09f98576e882a5fef68cdefdff939834a8782eaa Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Wed, 11 Sep 2019 23:33:23 -0400 Subject: added env::getFileSecurity() Environment gets stuff on demand --- src/env.cpp | 31 +++-- src/env.h | 21 +++- src/envsecurity.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/envsecurity.h | 17 +++ 4 files changed, 388 insertions(+), 13 deletions(-) (limited to 'src') 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& 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& 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 using COMPtr = std::unique_ptr; +// used by MallocPtr, calls std::free() as the deleter +// +struct MallocFreer +{ + void operator()(void* p) + { + std::free(p); + } +}; + +template +using MallocPtr = std::unique_ptr; + // 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 m_modules; - std::unique_ptr m_windows; - std::vector m_security; - std::unique_ptr m_metrics; + mutable std::vector m_modules; + mutable std::unique_ptr m_windows; + mutable std::vector m_security; + mutable std::unique_ptr 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 #pragma comment(lib, "Wbemuuid.lib") +#include +#include +#include +#pragma comment(lib, "advapi32.lib") + namespace env { @@ -397,4 +402,331 @@ std::vector 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 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 sd( + static_cast(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 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 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 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(nameSize); + auto wsDomain = std::make_unique(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 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 -- cgit v1.3.1