| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "WindowsSecurity.h" |
| |
|
| | #include <array> |
| |
|
| | #include "DebugClient.h" |
| | #include "OsModule.h" |
| | #include "OwnedHandle.h" |
| | #include "StringBuilder.h" |
| | #include "WindowsVersion.h" |
| | #include "WinptyAssert.h" |
| | #include "WinptyException.h" |
| |
|
| | namespace { |
| |
|
| | struct LocalFreer { |
| | void operator()(void *ptr) { |
| | if (ptr != nullptr) { |
| | LocalFree(reinterpret_cast<HLOCAL>(ptr)); |
| | } |
| | } |
| | }; |
| |
|
| | typedef std::unique_ptr<void, LocalFreer> PointerLocal; |
| |
|
| | template <typename T> |
| | SecurityItem<T> localItem(typename T::type v) { |
| | typedef typename T::type P; |
| | struct Impl : SecurityItem<T>::Impl { |
| | P m_v; |
| | Impl(P v) : m_v(v) {} |
| | virtual ~Impl() { |
| | LocalFree(reinterpret_cast<HLOCAL>(m_v)); |
| | } |
| | }; |
| | return SecurityItem<T>(v, std::unique_ptr<Impl>(new Impl { v })); |
| | } |
| |
|
| | Sid allocatedSid(PSID v) { |
| | struct Impl : Sid::Impl { |
| | PSID m_v; |
| | Impl(PSID v) : m_v(v) {} |
| | virtual ~Impl() { |
| | if (m_v != nullptr) { |
| | FreeSid(m_v); |
| | } |
| | } |
| | }; |
| | return Sid(v, std::unique_ptr<Impl>(new Impl { v })); |
| | } |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| | static OwnedHandle openSecurityTokenForQuery() { |
| | HANDLE token = nullptr; |
| | |
| | |
| | if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, |
| | FALSE, &token)) { |
| | if (GetLastError() != ERROR_NO_TOKEN) { |
| | throwWindowsError(L"OpenThreadToken failed"); |
| | } |
| | if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { |
| | throwWindowsError(L"OpenProcessToken failed"); |
| | } |
| | } |
| | ASSERT(token != nullptr && |
| | "OpenThreadToken/OpenProcessToken token is NULL"); |
| | return OwnedHandle(token); |
| | } |
| |
|
| | |
| | Sid getOwnerSid() { |
| | struct Impl : Sid::Impl { |
| | std::unique_ptr<char[]> buffer; |
| | }; |
| |
|
| | OwnedHandle token = openSecurityTokenForQuery(); |
| | DWORD actual = 0; |
| | BOOL success; |
| | success = GetTokenInformation(token.get(), TokenOwner, |
| | nullptr, 0, &actual); |
| | if (success) { |
| | throwWinptyException(L"getOwnerSid: GetTokenInformation: " |
| | L"expected ERROR_INSUFFICIENT_BUFFER"); |
| | } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
| | throwWindowsError(L"getOwnerSid: GetTokenInformation: " |
| | L"expected ERROR_INSUFFICIENT_BUFFER"); |
| | } |
| | std::unique_ptr<Impl> impl(new Impl); |
| | impl->buffer = std::unique_ptr<char[]>(new char[actual]); |
| | success = GetTokenInformation(token.get(), TokenOwner, |
| | impl->buffer.get(), actual, &actual); |
| | if (!success) { |
| | throwWindowsError(L"getOwnerSid: GetTokenInformation"); |
| | } |
| | TOKEN_OWNER tmp; |
| | ASSERT(actual >= sizeof(tmp)); |
| | std::copy( |
| | impl->buffer.get(), |
| | impl->buffer.get() + sizeof(tmp), |
| | reinterpret_cast<char*>(&tmp)); |
| | return Sid(tmp.Owner, std::move(impl)); |
| | } |
| |
|
| | Sid wellKnownSid( |
| | const wchar_t *debuggingName, |
| | SID_IDENTIFIER_AUTHORITY authority, |
| | BYTE authorityCount, |
| | DWORD subAuthority0, |
| | DWORD subAuthority1) { |
| | PSID psid = nullptr; |
| | if (!AllocateAndInitializeSid(&authority, authorityCount, |
| | subAuthority0, |
| | subAuthority1, |
| | 0, 0, 0, 0, 0, 0, |
| | &psid)) { |
| | const auto err = GetLastError(); |
| | const auto msg = |
| | std::wstring(L"wellKnownSid: error getting ") + |
| | debuggingName + L" SID"; |
| | throwWindowsError(msg.c_str(), err); |
| | } |
| | return allocatedSid(psid); |
| | } |
| |
|
| | Sid builtinAdminsSid() { |
| | |
| | SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; |
| | return wellKnownSid(L"BUILTIN\\Administrators group", |
| | authority, 2, |
| | SECURITY_BUILTIN_DOMAIN_RID, |
| | DOMAIN_ALIAS_RID_ADMINS); |
| | } |
| |
|
| | Sid localSystemSid() { |
| | |
| | SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; |
| | return wellKnownSid(L"LocalSystem account", |
| | authority, 1, |
| | SECURITY_LOCAL_SYSTEM_RID); |
| | } |
| |
|
| | Sid everyoneSid() { |
| | |
| | SID_IDENTIFIER_AUTHORITY authority = { SECURITY_WORLD_SID_AUTHORITY }; |
| | return wellKnownSid(L"Everyone account", |
| | authority, 1, |
| | SECURITY_WORLD_RID); |
| | } |
| |
|
| | static SecurityDescriptor finishSecurityDescriptor( |
| | size_t daclEntryCount, |
| | EXPLICIT_ACCESSW *daclEntries, |
| | Acl &outAcl) { |
| | { |
| | PACL aclRaw = nullptr; |
| | DWORD aclError = |
| | SetEntriesInAclW(daclEntryCount, |
| | daclEntries, |
| | nullptr, &aclRaw); |
| | if (aclError != ERROR_SUCCESS) { |
| | WStringBuilder sb(64); |
| | sb << L"finishSecurityDescriptor: " |
| | << L"SetEntriesInAcl failed: " << aclError; |
| | throwWinptyException(sb.c_str()); |
| | } |
| | outAcl = localItem<AclTag>(aclRaw); |
| | } |
| |
|
| | const PSECURITY_DESCRIPTOR sdRaw = |
| | reinterpret_cast<PSECURITY_DESCRIPTOR>( |
| | LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH)); |
| | if (sdRaw == nullptr) { |
| | throwWinptyException(L"finishSecurityDescriptor: LocalAlloc failed"); |
| | } |
| | SecurityDescriptor sd = localItem<SecurityDescriptorTag>(sdRaw); |
| | if (!InitializeSecurityDescriptor(sdRaw, SECURITY_DESCRIPTOR_REVISION)) { |
| | throwWindowsError( |
| | L"finishSecurityDescriptor: InitializeSecurityDescriptor"); |
| | } |
| | if (!SetSecurityDescriptorDacl(sdRaw, TRUE, outAcl.get(), FALSE)) { |
| | throwWindowsError( |
| | L"finishSecurityDescriptor: SetSecurityDescriptorDacl"); |
| | } |
| |
|
| | return std::move(sd); |
| | } |
| |
|
| | |
| | |
| | SecurityDescriptor |
| | createPipeSecurityDescriptorOwnerFullControl() { |
| |
|
| | struct Impl : SecurityDescriptor::Impl { |
| | Sid localSystem; |
| | Sid builtinAdmins; |
| | Sid owner; |
| | std::array<EXPLICIT_ACCESSW, 3> daclEntries = {}; |
| | Acl dacl; |
| | SecurityDescriptor value; |
| | }; |
| |
|
| | std::unique_ptr<Impl> impl(new Impl); |
| | impl->localSystem = localSystemSid(); |
| | impl->builtinAdmins = builtinAdminsSid(); |
| | impl->owner = getOwnerSid(); |
| |
|
| | for (auto &ea : impl->daclEntries) { |
| | ea.grfAccessPermissions = GENERIC_ALL; |
| | ea.grfAccessMode = SET_ACCESS; |
| | ea.grfInheritance = NO_INHERITANCE; |
| | ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| | } |
| | impl->daclEntries[0].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->localSystem.get()); |
| | impl->daclEntries[1].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->builtinAdmins.get()); |
| | impl->daclEntries[2].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->owner.get()); |
| |
|
| | impl->value = finishSecurityDescriptor( |
| | impl->daclEntries.size(), |
| | impl->daclEntries.data(), |
| | impl->dacl); |
| |
|
| | const auto retValue = impl->value.get(); |
| | return SecurityDescriptor(retValue, std::move(impl)); |
| | } |
| |
|
| | SecurityDescriptor |
| | createPipeSecurityDescriptorOwnerFullControlEveryoneWrite() { |
| |
|
| | struct Impl : SecurityDescriptor::Impl { |
| | Sid localSystem; |
| | Sid builtinAdmins; |
| | Sid owner; |
| | Sid everyone; |
| | std::array<EXPLICIT_ACCESSW, 4> daclEntries = {}; |
| | Acl dacl; |
| | SecurityDescriptor value; |
| | }; |
| |
|
| | std::unique_ptr<Impl> impl(new Impl); |
| | impl->localSystem = localSystemSid(); |
| | impl->builtinAdmins = builtinAdminsSid(); |
| | impl->owner = getOwnerSid(); |
| | impl->everyone = everyoneSid(); |
| |
|
| | for (auto &ea : impl->daclEntries) { |
| | ea.grfAccessPermissions = GENERIC_ALL; |
| | ea.grfAccessMode = SET_ACCESS; |
| | ea.grfInheritance = NO_INHERITANCE; |
| | ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; |
| | } |
| | impl->daclEntries[0].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->localSystem.get()); |
| | impl->daclEntries[1].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->builtinAdmins.get()); |
| | impl->daclEntries[2].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->owner.get()); |
| | impl->daclEntries[3].Trustee.ptstrName = |
| | reinterpret_cast<LPWSTR>(impl->everyone.get()); |
| | |
| | |
| | |
| | impl->daclEntries[3].grfAccessPermissions = |
| | FILE_GENERIC_READ | |
| | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA | |
| | STANDARD_RIGHTS_WRITE | SYNCHRONIZE; |
| |
|
| | impl->value = finishSecurityDescriptor( |
| | impl->daclEntries.size(), |
| | impl->daclEntries.data(), |
| | impl->dacl); |
| |
|
| | const auto retValue = impl->value.get(); |
| | return SecurityDescriptor(retValue, std::move(impl)); |
| | } |
| |
|
| | SecurityDescriptor getObjectSecurityDescriptor(HANDLE handle) { |
| | PACL dacl = nullptr; |
| | PSECURITY_DESCRIPTOR sd = nullptr; |
| | const DWORD errCode = GetSecurityInfo(handle, SE_KERNEL_OBJECT, |
| | OWNER_SECURITY_INFORMATION | |
| | GROUP_SECURITY_INFORMATION | |
| | DACL_SECURITY_INFORMATION, |
| | nullptr, nullptr, &dacl, nullptr, &sd); |
| | if (errCode != ERROR_SUCCESS) { |
| | throwWindowsError(L"GetSecurityInfo failed"); |
| | } |
| | return localItem<SecurityDescriptorTag>(sd); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | typedef BOOL WINAPI ConvertStringSidToSidW_t( |
| | LPCWSTR StringSid, |
| | PSID *Sid); |
| |
|
| | typedef BOOL WINAPI ConvertSidToStringSidW_t( |
| | PSID Sid, |
| | LPWSTR *StringSid); |
| |
|
| | typedef BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW_t( |
| | LPCWSTR StringSecurityDescriptor, |
| | DWORD StringSDRevision, |
| | PSECURITY_DESCRIPTOR *SecurityDescriptor, |
| | PULONG SecurityDescriptorSize); |
| |
|
| | typedef BOOL WINAPI ConvertSecurityDescriptorToStringSecurityDescriptorW_t( |
| | PSECURITY_DESCRIPTOR SecurityDescriptor, |
| | DWORD RequestedStringSDRevision, |
| | SECURITY_INFORMATION SecurityInformation, |
| | LPWSTR *StringSecurityDescriptor, |
| | PULONG StringSecurityDescriptorLen); |
| |
|
| | #define GET_MODULE_PROC(mod, funcName) \ |
| | const auto p##funcName = \ |
| | reinterpret_cast<funcName##_t*>( \ |
| | mod.proc(#funcName)); \ |
| | if (p##funcName == nullptr) { \ |
| | throwWinptyException( \ |
| | L"" L ## #funcName L" API is missing from ADVAPI32.DLL"); \ |
| | } |
| |
|
| | const DWORD kSDDL_REVISION_1 = 1; |
| |
|
| | std::wstring sidToString(PSID sid) { |
| | OsModule advapi32(L"advapi32.dll"); |
| | GET_MODULE_PROC(advapi32, ConvertSidToStringSidW); |
| | wchar_t *sidString = NULL; |
| | BOOL success = pConvertSidToStringSidW(sid, &sidString); |
| | if (!success) { |
| | throwWindowsError(L"ConvertSidToStringSidW failed"); |
| | } |
| | PointerLocal freer(sidString); |
| | return std::wstring(sidString); |
| | } |
| |
|
| | Sid stringToSid(const std::wstring &str) { |
| | |
| | |
| | |
| | |
| | OsModule advapi32(L"advapi32.dll"); |
| | GET_MODULE_PROC(advapi32, ConvertStringSidToSidW); |
| | PSID psid = nullptr; |
| | BOOL success = pConvertStringSidToSidW(const_cast<LPWSTR>(str.c_str()), |
| | &psid); |
| | if (!success) { |
| | const auto err = GetLastError(); |
| | throwWindowsError( |
| | (std::wstring(L"ConvertStringSidToSidW failed on \"") + |
| | str + L'"').c_str(), |
| | err); |
| | } |
| | return localItem<SidTag>(psid); |
| | } |
| |
|
| | SecurityDescriptor stringToSd(const std::wstring &str) { |
| | OsModule advapi32(L"advapi32.dll"); |
| | GET_MODULE_PROC(advapi32, ConvertStringSecurityDescriptorToSecurityDescriptorW); |
| | PSECURITY_DESCRIPTOR desc = nullptr; |
| | if (!pConvertStringSecurityDescriptorToSecurityDescriptorW( |
| | str.c_str(), kSDDL_REVISION_1, &desc, nullptr)) { |
| | const auto err = GetLastError(); |
| | throwWindowsError( |
| | (std::wstring(L"ConvertStringSecurityDescriptorToSecurityDescriptorW failed on \"") + |
| | str + L'"').c_str(), |
| | err); |
| | } |
| | return localItem<SecurityDescriptorTag>(desc); |
| | } |
| |
|
| | std::wstring sdToString(PSECURITY_DESCRIPTOR sd) { |
| | OsModule advapi32(L"advapi32.dll"); |
| | GET_MODULE_PROC(advapi32, ConvertSecurityDescriptorToStringSecurityDescriptorW); |
| | wchar_t *sdString = nullptr; |
| | if (!pConvertSecurityDescriptorToStringSecurityDescriptorW( |
| | sd, |
| | kSDDL_REVISION_1, |
| | OWNER_SECURITY_INFORMATION | |
| | GROUP_SECURITY_INFORMATION | |
| | DACL_SECURITY_INFORMATION, |
| | &sdString, |
| | nullptr)) { |
| | throwWindowsError( |
| | L"ConvertSecurityDescriptorToStringSecurityDescriptor failed"); |
| | } |
| | PointerLocal freer(sdString); |
| | return std::wstring(sdString); |
| | } |
| |
|
| | |
| | |
| | |
| | DWORD rejectRemoteClientsPipeFlag() { |
| | if (isAtLeastWindowsVista()) { |
| | |
| | const DWORD kPIPE_REJECT_REMOTE_CLIENTS = 8; |
| | return kPIPE_REJECT_REMOTE_CLIENTS; |
| | } else { |
| | trace("Omitting PIPE_REJECT_REMOTE_CLIENTS on pre-Vista OS"); |
| | return 0; |
| | } |
| | } |
| |
|
| | typedef BOOL WINAPI GetNamedPipeClientProcessId_t( |
| | HANDLE Pipe, |
| | PULONG ClientProcessId); |
| |
|
| | std::tuple<GetNamedPipeClientProcessId_Result, DWORD, DWORD> |
| | getNamedPipeClientProcessId(HANDLE serverPipe) { |
| | OsModule kernel32(L"kernel32.dll"); |
| | const auto pGetNamedPipeClientProcessId = |
| | reinterpret_cast<GetNamedPipeClientProcessId_t*>( |
| | kernel32.proc("GetNamedPipeClientProcessId")); |
| | if (pGetNamedPipeClientProcessId == nullptr) { |
| | return std::make_tuple( |
| | GetNamedPipeClientProcessId_Result::UnsupportedOs, 0, 0); |
| | } |
| | ULONG pid = 0; |
| | if (!pGetNamedPipeClientProcessId(serverPipe, &pid)) { |
| | return std::make_tuple( |
| | GetNamedPipeClientProcessId_Result::Failure, 0, GetLastError()); |
| | } |
| | return std::make_tuple( |
| | GetNamedPipeClientProcessId_Result::Success, |
| | static_cast<DWORD>(pid), |
| | 0); |
| | } |
| |
|