this looks like it checks the permissions as we'd expect

This commit is contained in:
Mike Griese 2021-09-09 14:00:51 -05:00
parent 7854abe0a3
commit 6265f4f1d7
6 changed files with 93 additions and 19 deletions

View file

@ -47,7 +47,7 @@ winrt::hstring BaseApplicationState::FilePath() const noexcept
void BaseApplicationState::_read() const noexcept
try
{
const auto data = ReadUTF8FileIfExists(_path).value_or(std::string{});
const auto data = _readFileContents().value_or(std::string{});
if (data.empty())
{
return;
@ -80,3 +80,13 @@ try
WriteUTF8FileAtomic(_path, content);
}
CATCH_LOG()
std::optional<std::string> BaseApplicationState::_readFileContents() const
{
return ReadUTF8FileIfExists(_path);
}
void BaseApplicationState::_writeFileContents(const std::string_view content) const
{
WriteUTF8FileAtomic(_path, content);
}

View file

@ -25,7 +25,10 @@ struct BaseApplicationState
virtual Json::Value ToJson() const noexcept = 0;
protected:
virtual void _write() const noexcept;
virtual std::optional<std::string> _readFileContents() const;
virtual void _writeFileContents(const std::string_view content) const;
void _write() const noexcept;
void _read() const noexcept;
std::filesystem::path _path;

View file

@ -113,20 +113,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
MTSM_ELEVATED_STATE_FIELDS(MTSM_ELEVATED_STATE_GEN)
#undef MTSM_ELEVATED_STATE_GEN
// Serialized this ApplicationState (in `context`) into the state.json at _path.
// * Errors are only logged.
// * _state->_writeScheduled is set to false, signaling our
// setters that _synchronize() needs to be called again.
void ElevatedState::_write() const noexcept
try
void ElevatedState::_writeFileContents(const std::string_view content) const
{
Json::Value root{ this->ToJson() };
Json::StreamWriterBuilder wbuilder;
const auto content = Json::writeString(wbuilder, root);
// WriteUTF8FileAtomic(_path, content, true);
WriteUTF8File(_path, content, true);
}
CATCH_LOG()
std::optional<std::string> ElevatedState::_readFileContents() const
{
return ReadUTF8FileIfExists(_path, true);
}
}

View file

@ -48,7 +48,9 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
#undef MTSM_ELEVATED_STATE_GEN
};
til::shared_mutex<state_t> _state;
virtual void _write() const noexcept override;
virtual std::optional<std::string> _readFileContents() const override;
virtual void _writeFileContents(const std::string_view content) const override;
};
}

View file

@ -43,8 +43,73 @@ namespace Microsoft::Terminal::Settings::Model
// Tries to read a file somewhat atomically without locking it.
// Strips the UTF8 BOM if it exists.
std::string ReadUTF8File(const std::filesystem::path& path)
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly)
{
if (elevatedOnly)
{
// If we want to only open the file if it's elevated, check the
// permissions on this file. We want to make sure that:
// * Everyone has permission to read
// * admins can do anything
// * no one else can do anything.
PACL pAcl{ nullptr };
PSECURITY_DESCRIPTOR pSD{ nullptr };
auto status = GetNamedSecurityInfo(path.c_str(),
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
nullptr,
nullptr,
&pAcl,
nullptr,
&pSD);
THROW_IF_WIN32_ERROR(status);
pSD;
pAcl;
PEXPLICIT_ACCESS pEA{ nullptr };
DWORD count = 0;
status = GetExplicitEntriesFromAcl(pAcl, &count, &pEA);
THROW_IF_WIN32_ERROR(status);
THROW_HR_IF(E_FAIL, count != 2);
PSID pEveryoneSid = nullptr;
PSID pAdminGroupSid = nullptr;
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
// Create a SID for the BUILTIN\Administrators group.
THROW_IF_WIN32_BOOL_FALSE(AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminGroupSid));
// Create a well-known SID for the Everyone group.
THROW_IF_WIN32_BOOL_FALSE(AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSid));
THROW_HR_IF(E_FAIL, pEA[0].grfAccessPermissions != GENERIC_ALL);
THROW_HR_IF(E_FAIL, pEA[0].grfInheritance != NO_INHERITANCE);
THROW_HR_IF(E_FAIL, pEA[0].Trustee.TrusteeForm != TRUSTEE_IS_SID);
THROW_HR_IF(E_FAIL, pEA[0].Trustee.TrusteeType != TRUSTEE_IS_WELL_KNOWN_GROUP);
THROW_HR_IF(E_FAIL, pEA[0].Trustee.ptstrName != pAdminGroupSid);
THROW_HR_IF(E_FAIL, pEA[1].grfAccessPermissions != GENERIC_READ);
THROW_HR_IF(E_FAIL, pEA[1].grfInheritance != NO_INHERITANCE);
THROW_HR_IF(E_FAIL, pEA[1].Trustee.TrusteeForm != TRUSTEE_IS_SID);
THROW_HR_IF(E_FAIL, pEA[1].Trustee.TrusteeType != TRUSTEE_IS_WELL_KNOWN_GROUP);
THROW_HR_IF(E_FAIL, pEA[1].Trustee.ptstrName != pEveryoneSid);
// // Grant Admins all permissions on this file
// ea[0].grfAccessPermissions = GENERIC_ALL;
// ea[0].grfAccessMode = SET_ACCESS;
// ea[0].grfInheritance = NO_INHERITANCE;
// ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
// ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
// ea[0].Trustee.ptstrName = (LPTSTR)pAdminGroupSid;
// ea[1].grfAccessPermissions = GENERIC_READ;
// ea[1].grfAccessMode = SET_ACCESS;
// ea[1].grfInheritance = NO_INHERITANCE;
// ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
// ea[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
// ea[1].Trustee.ptstrName = (LPTSTR)pEveryoneSid;
}
// From some casual observations we can determine that:
// * ReadFile() always returns the requested amount of data (unless the file is smaller)
// * It's unlikely that the file was changed between GetFileSize() and ReadFile()
@ -91,11 +156,11 @@ namespace Microsoft::Terminal::Settings::Model
}
// Same as ReadUTF8File, but returns an empty optional, if the file couldn't be opened.
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path)
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly)
{
try
{
return { ReadUTF8File(path) };
return { ReadUTF8File(path, elevatedOnly) };
}
catch (const wil::ResultException& exception)
{

View file

@ -4,8 +4,8 @@
namespace Microsoft::Terminal::Settings::Model
{
std::filesystem::path GetBaseSettingsPath();
std::string ReadUTF8File(const std::filesystem::path& path);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path);
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false);
std::optional<std::string> ReadUTF8FileIfExists(const std::filesystem::path& path, const bool elevatedOnly = false);
void WriteUTF8File(const std::filesystem::path& path, const std::string_view content, const bool elevatedOnly = false);
void WriteUTF8FileAtomic(const std::filesystem::path& path, const std::string_view content);
}