 Issue 11756012:
  Enhanced Protected Mode support  (Closed)
    
  
    Issue 11756012:
  Enhanced Protected Mode support  (Closed) 
  | Left: | ||
| Right: | 
| OLD | NEW | 
|---|---|
| 1 #include <Windows.h> | 1 #include <Windows.h> | 
| 2 #include <Lmcons.h> | 2 #include <Lmcons.h> | 
| 3 #include <Sddl.h> | 3 #include <Sddl.h> | 
| 4 #include <aclapi.h> | |
| 4 | 5 | 
| 5 #include "Communication.h" | 6 #include "Communication.h" | 
| 6 #include "Utils.h" | 7 #include "Utils.h" | 
| 8 #include <strsafe.h> | |
| 
Wladimir Palant
2013/09/16 13:45:07
Please move that up, to the built-in include files
 | |
| 9 | |
| 10 #ifndef SECURITY_APP_PACKAGE_AUTHORITY | |
| 11 #define SECURITY_APP_PACKAGE_AUTHORITY {0,0,0,0,0,15} | |
| 12 #endif | |
| 13 | |
| 14 std::wstring Communication::browserSID; | |
| 7 | 15 | 
| 8 namespace | 16 namespace | 
| 9 { | 17 { | 
| 10 const int bufferSize = 1024; | 18 const int bufferSize = 1024; | 
| 11 | 19 | 
| 12 std::string AppendErrorCode(const std::string& message) | 20 std::string AppendErrorCode(const std::string& message) | 
| 13 { | 21 { | 
| 14 std::stringstream stream; | 22 std::stringstream stream; | 
| 15 stream << message << " (Error code: " << GetLastError() << ")"; | 23 stream << message << " (Error code: " << GetLastError() << ")"; | 
| 16 return stream.str(); | 24 return stream.str(); | 
| 17 } | 25 } | 
| 18 | 26 | 
| 19 std::wstring GetUserName() | 27 std::wstring GetUserName() | 
| 20 { | 28 { | 
| 21 const DWORD maxLength = UNLEN + 1; | 29 const DWORD maxLength = UNLEN + 1; | 
| 22 std::auto_ptr<wchar_t> buffer(new wchar_t[maxLength]); | 30 std::auto_ptr<wchar_t> buffer(new wchar_t[maxLength]); | 
| 23 DWORD length = maxLength; | 31 DWORD length = maxLength; | 
| 24 if (!::GetUserNameW(buffer.get(), &length)) | 32 if (!::GetUserNameW(buffer.get(), &length)) | 
| 25 throw std::runtime_error(AppendErrorCode("Failed to get the current user's name")); | 33 throw std::runtime_error(AppendErrorCode("Failed to get the current user's name")); | 
| 26 return std::wstring(buffer.get(), length); | 34 return std::wstring(buffer.get(), length); | 
| 27 } | 35 } | 
| 36 | |
| 37 // See http://msdn.microsoft.com/en-us/library/windows/desktop/hh448493(v=vs.8 5).aspx | |
| 38 bool GetLogonSid (HANDLE hToken, PSID *ppsid) | |
| 
Felix Dahlke
2013/09/16 16:30:12
Nit: No space after GetLogonSid?
 | |
| 39 { | |
| 40 DWORD dwLength = 0; | |
| 41 PTOKEN_GROUPS ptg = NULL; | |
| 42 | |
| 43 // Verify the parameter passed in is not NULL. | |
| 
Felix Dahlke
2013/09/16 16:30:12
I do think this is kinda obvious from the conditio
 | |
| 44 if (NULL == ppsid) | |
| 
Felix Dahlke
2013/09/16 16:30:12
We normally don't use Yoda conditions :D But it's
 | |
| 45 return false; | |
| 46 | |
| 47 // Get required buffer size and allocate the TOKEN_GROUPS buffer. | |
| 48 if (!GetTokenInformation(hToken, TokenLogonSid, (LPVOID) ptg, 0, &dwLength)) | |
| 
Felix Dahlke
2013/09/16 16:30:12
This code looks very similar to what's in AdblockP
 | |
| 49 { | |
| 50 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) | |
| 51 return false; | |
| 52 | |
| 53 ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLengt h); | |
| 54 | |
| 55 if (ptg == NULL) | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 // Get the token group information from the access token. | |
| 60 if (!GetTokenInformation(hToken, TokenLogonSid, (LPVOID) ptg, dwLength, &dwL ength) || ptg->GroupCount != 1) | |
| 61 { | |
| 62 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); | |
| 63 return false; | |
| 64 } | |
| 65 | |
| 66 // Found the logon SID; make a copy of it. | |
| 67 dwLength = GetLengthSid(ptg->Groups[0].Sid); | |
| 68 *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); | |
| 69 if (*ppsid == NULL) | |
| 70 { | |
| 71 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); | |
| 72 return false; | |
| 73 } | |
| 74 if (!CopySid(dwLength, *ppsid, ptg->Groups[0].Sid)) | |
| 75 { | |
| 76 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); | |
| 77 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); | |
| 78 return false; | |
| 79 } | |
| 80 | |
| 81 HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); | |
| 82 return true; | |
| 83 } | |
| 84 | |
| 85 bool CreateObjectSecurityDescriptor(PSID pLogonSid, PSECURITY_DESCRIPTOR* ppSD ) | |
| 86 { | |
| 87 BOOL bSuccess = FALSE; | |
| 
Felix Dahlke
2013/09/16 16:30:12
I'd rather have these declarations closer to their
 | |
| 88 DWORD dwRes; | |
| 89 PSID pBrowserSID = NULL; | |
| 90 PACL pACL = NULL; | |
| 91 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 92 EXPLICIT_ACCESS ea[2]; | |
| 93 SID_IDENTIFIER_AUTHORITY ApplicationAuthority = SECURITY_APP_PACKAGE_AUTHORI TY; | |
| 94 | |
| 95 ConvertStringSidToSid(Communication::browserSID.c_str(), &pBrowserSID); | |
| 96 | |
| 97 // Initialize an EXPLICIT_ACCESS structure for an ACE. | |
| 98 // The ACE will allow LogonSid generic all access | |
| 99 ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS)); | |
| 100 ea[0].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL; | |
| 101 ea[0].grfAccessMode = SET_ACCESS; | |
| 102 ea[0].grfInheritance= NO_INHERITANCE; | |
| 103 ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; | |
| 104 ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER; | |
| 105 ea[0].Trustee.ptstrName = (LPTSTR) pLogonSid; | |
| 106 | |
| 107 // Initialize an EXPLICIT_ACCESS structure for an ACE. | |
| 108 // The ACE will give the browser SID all permissions | |
| 109 ea[1].grfAccessPermissions = STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL; | |
| 110 ea[1].grfAccessMode = SET_ACCESS; | |
| 111 ea[1].grfInheritance= NO_INHERITANCE; | |
| 112 ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; | |
| 113 ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; | |
| 114 ea[1].Trustee.ptstrName = (LPTSTR) pBrowserSID; | |
| 115 | |
| 116 // Create a new ACL that contains the new ACEs. | |
| 117 dwRes = SetEntriesInAcl(2, ea, NULL, &pACL); | |
| 118 if (ERROR_SUCCESS != dwRes) | |
| 119 { | |
| 120 FreeSid(pBrowserSID); | |
| 121 return false; | |
| 122 } | |
| 123 | |
| 124 // Initialize a security descriptor. | |
| 125 pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH ); | |
| 126 if (NULL == pSD) | |
| 127 { | |
| 128 FreeSid(pBrowserSID); | |
| 129 LocalFree(pACL); | |
| 130 return false;; | |
| 131 } | |
| 132 | |
| 133 if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) | |
| 134 { | |
| 135 FreeSid(pBrowserSID); | |
| 136 LocalFree(pACL); | |
| 137 LocalFree((LPVOID)pSD); | |
| 138 return false; | |
| 139 } | |
| 140 | |
| 141 // Add the ACL to the security descriptor. | |
| 142 if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) // not a default D ACL | |
| 143 { | |
| 144 FreeSid(pBrowserSID); | |
| 145 LocalFree(pACL); | |
| 146 LocalFree((LPVOID)pSD); | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 *ppSD = pSD; | |
| 151 pSD = NULL; | |
| 152 | |
| 153 if (pBrowserSID) | |
| 154 FreeSid(pBrowserSID); | |
| 155 if (pACL) | |
| 156 LocalFree(pACL); | |
| 157 | |
| 158 return true; | |
| 159 } | |
| 160 | |
| 161 | |
| 28 } | 162 } | 
| 29 | 163 | 
| 30 const std::wstring Communication::pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName(); | 164 const std::wstring Communication::pipeName = L"\\\\.\\pipe\\adblockplusengine_" + GetUserName(); | 
| 31 | 165 | 
| 32 void Communication::InputBuffer::CheckType(Communication::ValueType expectedType ) | 166 void Communication::InputBuffer::CheckType(Communication::ValueType expectedType ) | 
| 33 { | 167 { | 
| 34 if (!hasType) | 168 if (!hasType) | 
| 35 ReadBinary(currentType); | 169 ReadBinary(currentType); | 
| 36 | 170 | 
| 37 if (currentType != expectedType) | 171 if (currentType != expectedType) | 
| (...skipping 22 matching lines...) Expand all Loading... | |
| 60 | 194 | 
| 61 Communication::PipeBusyError::PipeBusyError() | 195 Communication::PipeBusyError::PipeBusyError() | 
| 62 : std::runtime_error("Timeout while trying to connect to a named pipe, pipe is busy") | 196 : std::runtime_error("Timeout while trying to connect to a named pipe, pipe is busy") | 
| 63 { | 197 { | 
| 64 } | 198 } | 
| 65 | 199 | 
| 66 Communication::PipeDisconnectedError::PipeDisconnectedError() | 200 Communication::PipeDisconnectedError::PipeDisconnectedError() | 
| 67 : std::runtime_error("Pipe disconnected") | 201 : std::runtime_error("Pipe disconnected") | 
| 68 { | 202 { | 
| 69 } | 203 } | 
| 70 | |
| 71 Communication::Pipe::Pipe(const std::wstring& pipeName, Communication::Pipe::Mod e mode) | 204 Communication::Pipe::Pipe(const std::wstring& pipeName, Communication::Pipe::Mod e mode) | 
| 
Wladimir Palant
2013/09/16 13:45:07
Nit: Please keep an empty line before this one.
 | |
| 72 { | 205 { | 
| 73 pipe = INVALID_HANDLE_VALUE; | 206 pipe = INVALID_HANDLE_VALUE; | 
| 74 if (mode == MODE_CREATE) | 207 if (mode == MODE_CREATE) | 
| 75 { | 208 { | 
| 76 SECURITY_ATTRIBUTES sa; | 209 SECURITY_ATTRIBUTES sa; | 
| 77 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); | 210 memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); | 
| 78 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 211 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | 
| 79 | 212 | 
| 80 PSECURITY_DESCRIPTOR securitydescriptor; | 213 HANDLE hToken = NULL; | 
| 81 if (IsWindowsVistaOrLater()) | 214 OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken); | 
| 215 | |
| 216 if (browserSID.empty()) | |
| 82 { | 217 { | 
| 83 // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb6259 58.aspx | 218 if (IsWindowsVistaOrLater()) | 
| 84 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; | 219 { | 
| 85 ConvertStringSecurityDescriptorToSecurityDescriptorW(accessControlEntry, S DDL_REVISION_1, &securitydescriptor, 0); | 220 // Low mandatory label. See http://msdn.microsoft.com/en-us/library/bb62 5958.aspx | 
| 86 sa.lpSecurityDescriptor = securitydescriptor; | 221 LPCWSTR accessControlEntry = L"S:(ML;;NW;;;LW)"; | 
| 222 ConvertStringSecurityDescriptorToSecurityDescriptorW(accessControlEntry, SDDL_REVISION_1, &securitydescriptor, 0); | |
| 223 sa.lpSecurityDescriptor = securitydescriptor; | |
| 224 } | |
| 225 | |
| 226 sa.bInheritHandle = TRUE; | |
| 87 } | 227 } | 
| 88 | 228 else // IE is in AppContainer | 
| 89 sa.bInheritHandle = TRUE; | |
| 90 | |
| 91 pipe = CreateNamedPipeW (pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MES SAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | |
| 92 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSi ze, 0, &sa); | |
| 93 if (IsWindowsVistaOrLater() && securitydescriptor) | |
| 94 { | 229 { | 
| 95 LocalFree(securitydescriptor); | 230 PSID pLogonSid = NULL; | 
| 231 //Allowing LogonSid and IE's appcontainer. | |
| 232 if (GetLogonSid(hToken, &pLogonSid) && CreateObjectSecurityDescriptor(pLog onSid, &securitydescriptor) ) | |
| 
Wladimir Palant
2013/09/16 13:45:07
Why do we need to allow the logon sid? Is it for t
 
Oleksandr
2013/09/17 08:27:19
Our plugin is unable to access the named pipe if w
 | |
| 233 { | |
| 234 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | |
| 235 sa.bInheritHandle = TRUE; | |
| 
Wladimir Palant
2013/09/16 13:45:07
I think that we still want to set this in any case
 | |
| 236 sa.lpSecurityDescriptor = securitydescriptor; | |
| 237 } | |
| 96 } | 238 } | 
| 97 } | 239 pipe = CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESS AGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, | 
| 
Wladimir Palant
2013/09/16 13:45:07
Please use CreateNamedPipeW explicitly, as we had
 | |
| 240 PIPE_UNLIMITED_INSTANCES, bufferSize, bufferSize, 0, &sa); | |
| 241 } | |
| 
Wladimir Palant
2013/09/16 13:45:07
Bad indentation?
 | |
| 98 else | 242 else | 
| 99 { | 243 { | 
| 100 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPE N_EXISTING, 0, 0); | 244 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPE N_EXISTING, 0, 0); | 
| 101 if (pipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) | 245 if (pipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) | 
| 102 { | 246 { | 
| 103 if (!WaitNamedPipeW(pipeName.c_str(), 10000)) | 247 if (!WaitNamedPipeW(pipeName.c_str(), 10000)) | 
| 104 throw PipeBusyError(); | 248 throw PipeBusyError(); | 
| 105 | 249 | 
| 106 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, O PEN_EXISTING, 0, 0); | 250 pipe = CreateFileW(pipeName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, O PEN_EXISTING, 0, 0); | 
| 107 } | 251 } | 
| 108 } | 252 } | 
| 109 | 253 | 
| 110 if (pipe == INVALID_HANDLE_VALUE) | 254 if (pipe == INVALID_HANDLE_VALUE) | 
| 111 throw PipeConnectionError(); | 255 throw PipeConnectionError(); | 
| 112 | 256 | 
| 113 DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; | 257 DWORD pipeMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; | 
| 114 if (!SetNamedPipeHandleState(pipe, &pipeMode, 0, 0)) | 258 if (!SetNamedPipeHandleState(pipe, &pipeMode, 0, 0)) | 
| 115 throw std::runtime_error("SetNamedPipeHandleState failed: error " + GetLastE rror()); | 259 throw std::runtime_error("SetNamedPipeHandleState failed: error " + GetLastE rror()); | 
| 116 | 260 | 
| 117 if (mode == MODE_CREATE && !ConnectNamedPipe(pipe, 0)) | 261 if (mode == MODE_CREATE && !ConnectNamedPipe(pipe, 0)) | 
| 118 throw std::runtime_error("Client failed to connect: error " + GetLastError() ); | 262 throw std::runtime_error("Client failed to connect: error " + GetLastError() ); | 
| 119 } | 263 } | 
| 120 | 264 | 
| 121 Communication::Pipe::~Pipe() | 265 Communication::Pipe::~Pipe() | 
| 122 { | 266 { | 
| 123 CloseHandle(pipe); | 267 CloseHandle(pipe); | 
| 268 if (securitydescriptor) | |
| 269 LocalFree(securitydescriptor); | |
| 270 | |
| 124 } | 271 } | 
| 125 | 272 | 
| 126 Communication::InputBuffer Communication::Pipe::ReadMessage() | 273 Communication::InputBuffer Communication::Pipe::ReadMessage() | 
| 127 { | 274 { | 
| 128 std::stringstream stream; | 275 std::stringstream stream; | 
| 129 std::auto_ptr<char> buffer(new char[bufferSize]); | 276 std::auto_ptr<char> buffer(new char[bufferSize]); | 
| 130 bool doneReading = false; | 277 bool doneReading = false; | 
| 131 while (!doneReading) | 278 while (!doneReading) | 
| 132 { | 279 { | 
| 133 DWORD bytesRead; | 280 DWORD bytesRead; | 
| (...skipping 19 matching lines...) Expand all Loading... | |
| 153 return Communication::InputBuffer(stream.str()); | 300 return Communication::InputBuffer(stream.str()); | 
| 154 } | 301 } | 
| 155 | 302 | 
| 156 void Communication::Pipe::WriteMessage(Communication::OutputBuffer& message) | 303 void Communication::Pipe::WriteMessage(Communication::OutputBuffer& message) | 
| 157 { | 304 { | 
| 158 DWORD bytesWritten; | 305 DWORD bytesWritten; | 
| 159 std::string data = message.Get(); | 306 std::string data = message.Get(); | 
| 160 if (!WriteFile(pipe, data.c_str(), static_cast<DWORD>(data.length()), &bytesWr itten, 0)) | 307 if (!WriteFile(pipe, data.c_str(), static_cast<DWORD>(data.length()), &bytesWr itten, 0)) | 
| 161 throw std::runtime_error("Failed to write to pipe"); | 308 throw std::runtime_error("Failed to write to pipe"); | 
| 162 } | 309 } | 
| OLD | NEW |