this looks like it checks the permissions as we'd expect
This commit is contained in:
parent
7854abe0a3
commit
6265f4f1d7
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue