OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 // | |
5 // A library to manage RLZ information for access-points shared | |
6 // across different client applications. | |
7 | |
8 #include "rlz/win/lib/rlz_lib.h" | |
9 | |
10 #include <windows.h> | |
11 #include <aclapi.h> | |
12 #include <winerror.h> | |
13 | |
14 #include "base/basictypes.h" | |
15 #include "base/win/registry.h" | |
16 #include "base/win/windows_version.h" | |
17 #include "rlz/lib/assert.h" | |
18 #include "rlz/lib/rlz_value_store.h" | |
19 #include "rlz/win/lib/machine_deal.h" | |
20 #include "rlz/win/lib/rlz_value_store_registry.h" | |
21 | |
22 namespace { | |
23 | |
24 // Path to recursively copy into the replacemment hives. These are needed | |
25 // to make sure certain win32 APIs continue to run correctly once the real | |
26 // hives are replaced. | |
27 const wchar_t* kHKLMAccessProviders = | |
28 L"System\\CurrentControlSet\\Control\\Lsa\\AccessProviders"; | |
29 | |
30 // Helper functions | |
31 | |
32 void CopyRegistryTree(const base::win::RegKey& src, base::win::RegKey* dest) { | |
33 // First copy values. | |
34 for (base::win::RegistryValueIterator i(src.Handle(), L""); | |
35 i.Valid(); ++i) { | |
36 dest->WriteValue(i.Name(), reinterpret_cast<const void*>(i.Value()), | |
37 i.ValueSize(), i.Type()); | |
38 } | |
39 | |
40 // Next copy subkeys recursively. | |
41 for (base::win::RegistryKeyIterator i(src.Handle(), L""); | |
42 i.Valid(); ++i) { | |
43 base::win::RegKey subkey(dest->Handle(), i.Name(), KEY_ALL_ACCESS); | |
44 CopyRegistryTree(base::win::RegKey(src.Handle(), i.Name(), KEY_READ), | |
45 &subkey); | |
46 } | |
47 } | |
48 | |
49 } // namespace anonymous | |
50 | |
51 | |
52 namespace rlz_lib { | |
53 | |
54 // OEM Deal confirmation storage functions. | |
55 | |
56 template<class T> | |
57 class typed_buffer_ptr { | |
58 scoped_array<char> buffer_; | |
59 | |
60 public: | |
61 typed_buffer_ptr() { | |
62 } | |
63 | |
64 explicit typed_buffer_ptr(size_t size) : buffer_(new char[size]) { | |
65 } | |
66 | |
67 void reset(size_t size) { | |
68 buffer_.reset(new char[size]); | |
69 } | |
70 | |
71 operator T*() { | |
72 return reinterpret_cast<T*>(buffer_.get()); | |
73 } | |
74 }; | |
75 | |
76 // Check if this SID has the desired access by scanning the ACEs in the DACL. | |
77 // This function is part of the rlz_lib namespace so that it can be called from | |
78 // unit tests. Non-unit test code should not call this function. | |
79 bool HasAccess(PSID sid, ACCESS_MASK access_mask, ACL* dacl) { | |
80 if (dacl == NULL) | |
81 return false; | |
82 | |
83 ACL_SIZE_INFORMATION info; | |
84 if (!GetAclInformation(dacl, &info, sizeof(info), AclSizeInformation)) | |
85 return false; | |
86 | |
87 GENERIC_MAPPING generic_mapping = {KEY_READ, KEY_WRITE, KEY_EXECUTE, | |
88 KEY_ALL_ACCESS}; | |
89 MapGenericMask(&access_mask, &generic_mapping); | |
90 | |
91 for (DWORD i = 0; i < info.AceCount; ++i) { | |
92 ACCESS_ALLOWED_ACE* ace; | |
93 if (GetAce(dacl, i, reinterpret_cast<void**>(&ace))) { | |
94 if ((ace->Header.AceFlags & INHERIT_ONLY_ACE) == INHERIT_ONLY_ACE) | |
95 continue; | |
96 | |
97 PSID existing_sid = reinterpret_cast<PSID>(&ace->SidStart); | |
98 DWORD mask = ace->Mask; | |
99 MapGenericMask(&mask, &generic_mapping); | |
100 | |
101 if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && | |
102 (mask & access_mask) == access_mask && EqualSid(existing_sid, sid)) | |
103 return true; | |
104 | |
105 if (ace->Header.AceType == ACCESS_DENIED_ACE_TYPE && | |
106 (mask & access_mask) != 0 && EqualSid(existing_sid, sid)) | |
107 return false; | |
108 } | |
109 } | |
110 | |
111 return false; | |
112 } | |
113 | |
114 bool CreateMachineState() { | |
115 LibMutex lock; | |
116 if (lock.failed()) | |
117 return false; | |
118 | |
119 base::win::RegKey hklm_key; | |
120 if (hklm_key.Create(HKEY_LOCAL_MACHINE, | |
121 RlzValueStoreRegistry::GetWideLibKeyName().c_str(), | |
122 KEY_ALL_ACCESS | KEY_WOW64_32KEY) != ERROR_SUCCESS) { | |
123 ASSERT_STRING("rlz_lib::CreateMachineState: " | |
124 "Unable to create / open machine key."); | |
125 return false; | |
126 } | |
127 | |
128 // Create a SID that represents ALL USERS. | |
129 DWORD users_sid_size = SECURITY_MAX_SID_SIZE; | |
130 typed_buffer_ptr<SID> users_sid(users_sid_size); | |
131 CreateWellKnownSid(WinBuiltinUsersSid, NULL, users_sid, &users_sid_size); | |
132 | |
133 // Get the security descriptor for the registry key. | |
134 DWORD original_sd_size = 0; | |
135 ::RegGetKeySecurity(hklm_key.Handle(), DACL_SECURITY_INFORMATION, NULL, | |
136 &original_sd_size); | |
137 typed_buffer_ptr<SECURITY_DESCRIPTOR> original_sd(original_sd_size); | |
138 | |
139 LONG result = ::RegGetKeySecurity(hklm_key.Handle(), | |
140 DACL_SECURITY_INFORMATION, original_sd, &original_sd_size); | |
141 if (result != ERROR_SUCCESS) { | |
142 ASSERT_STRING("rlz_lib::CreateMachineState: " | |
143 "Unable to create / open machine key."); | |
144 return false; | |
145 } | |
146 | |
147 // Make a copy of the security descriptor so we can modify it. The one | |
148 // returned by RegGetKeySecurity() is self-relative, so we need to make it | |
149 // absolute. | |
150 DWORD new_sd_size = 0; | |
151 DWORD dacl_size = 0; | |
152 DWORD sacl_size = 0; | |
153 DWORD owner_size = 0; | |
154 DWORD group_size = 0; | |
155 ::MakeAbsoluteSD(original_sd, NULL, &new_sd_size, NULL, &dacl_size, | |
156 NULL, &sacl_size, NULL, &owner_size, | |
157 NULL, &group_size); | |
158 | |
159 typed_buffer_ptr<SECURITY_DESCRIPTOR> new_sd(new_sd_size); | |
160 // Make sure the DACL is big enough to add one more ACE. | |
161 typed_buffer_ptr<ACL> dacl(dacl_size + SECURITY_MAX_SID_SIZE); | |
162 typed_buffer_ptr<ACL> sacl(sacl_size); | |
163 typed_buffer_ptr<SID> owner(owner_size); | |
164 typed_buffer_ptr<SID> group(group_size); | |
165 | |
166 if (!::MakeAbsoluteSD(original_sd, new_sd, &new_sd_size, dacl, &dacl_size, | |
167 sacl, &sacl_size, owner, &owner_size, | |
168 group, &group_size)) { | |
169 ASSERT_STRING("rlz_lib::CreateMachineState: MakeAbsoluteSD failed"); | |
170 return false; | |
171 } | |
172 | |
173 // If all users already have read/write access to the registry key, then | |
174 // nothing to do. Otherwise change the security descriptor of the key to | |
175 // give everyone access. | |
176 if (HasAccess(users_sid, KEY_ALL_ACCESS, dacl)) { | |
177 return false; | |
178 } | |
179 | |
180 // Add ALL-USERS ALL-ACCESS ACL. | |
181 EXPLICIT_ACCESS ea; | |
182 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); | |
183 ea.grfAccessPermissions = GENERIC_ALL | KEY_ALL_ACCESS; | |
184 ea.grfAccessMode = GRANT_ACCESS; | |
185 ea.grfInheritance= SUB_CONTAINERS_AND_OBJECTS_INHERIT; | |
186 ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; | |
187 ea.Trustee.ptstrName = L"Everyone"; | |
188 | |
189 ACL* new_dacl = NULL; | |
190 result = SetEntriesInAcl(1, &ea, dacl, &new_dacl); | |
191 if (result != ERROR_SUCCESS) { | |
192 ASSERT_STRING("rlz_lib::CreateMachineState: SetEntriesInAcl failed"); | |
193 return false; | |
194 } | |
195 | |
196 BOOL ok = SetSecurityDescriptorDacl(new_sd, TRUE, new_dacl, FALSE); | |
197 if (!ok) { | |
198 ASSERT_STRING("rlz_lib::CreateMachineState: " | |
199 "SetSecurityDescriptorOwner failed"); | |
200 LocalFree(new_dacl); | |
201 return false; | |
202 } | |
203 | |
204 result = ::RegSetKeySecurity(hklm_key.Handle(), | |
205 DACL_SECURITY_INFORMATION, | |
206 new_sd); | |
207 // Note that the new DACL cannot be freed until after the call to | |
208 // RegSetKeySecurity(). | |
209 LocalFree(new_dacl); | |
210 | |
211 bool success = true; | |
212 if (result != ERROR_SUCCESS) { | |
213 ASSERT_STRING("rlz_lib::CreateMachineState: " | |
214 "Unable to create / open machine key."); | |
215 success = false; | |
216 } | |
217 | |
218 | |
219 return success; | |
220 } | |
221 | |
222 bool SetMachineDealCode(const char* dcc) { | |
223 return MachineDealCode::Set(dcc); | |
224 } | |
225 | |
226 bool GetMachineDealCodeAsCgi(char* cgi, size_t cgi_size) { | |
227 return MachineDealCode::GetAsCgi(cgi, cgi_size); | |
228 } | |
229 | |
230 bool GetMachineDealCode(char* dcc, size_t dcc_size) { | |
231 return MachineDealCode::Get(dcc, dcc_size); | |
232 } | |
233 | |
234 // Combined functions. | |
235 | |
236 bool SetMachineDealCodeFromPingResponse(const char* response) { | |
237 return MachineDealCode::SetFromPingResponse(response); | |
238 } | |
239 | |
240 void InitializeTempHivesForTesting(const base::win::RegKey& temp_hklm_key, | |
241 const base::win::RegKey& temp_hkcu_key) { | |
242 // For the moment, the HKCU hive requires no initialization. | |
243 | |
244 if (base::win::GetVersion() >= base::win::VERSION_WIN7) { | |
245 // Copy the following HKLM subtrees to the temporary location so that the | |
246 // win32 APIs used by the tests continue to work: | |
247 // | |
248 // HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders | |
249 // | |
250 // This seems to be required since Win7. | |
251 base::win::RegKey dest(temp_hklm_key.Handle(), kHKLMAccessProviders, | |
252 KEY_ALL_ACCESS); | |
253 CopyRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE, | |
254 kHKLMAccessProviders, | |
255 KEY_READ), | |
256 &dest); | |
257 } | |
258 } | |
259 | |
260 } // namespace rlz_lib | |
OLD | NEW |