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.
5 // A library to manage RLZ information for access-points shared
6 // across different client applications.
8 #include "rlz/win/lib/rlz_lib.h"
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"
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";
32 void CopyRegistryTree(const base::win::RegKey
& src
, base::win::RegKey
* dest
) {
34 for (base::win::RegistryValueIterator
i(src
.Handle(), L
"");
36 dest
->WriteValue(i
.Name(), reinterpret_cast<const void*>(i
.Value()),
37 i
.ValueSize(), i
.Type());
40 // Next copy subkeys recursively.
41 for (base::win::RegistryKeyIterator
i(src
.Handle(), L
"");
43 base::win::RegKey
subkey(dest
->Handle(), i
.Name(), KEY_ALL_ACCESS
);
44 CopyRegistryTree(base::win::RegKey(src
.Handle(), i
.Name(), KEY_READ
),
49 } // namespace anonymous
54 // OEM Deal confirmation storage functions.
57 class typed_buffer_ptr
{
58 scoped_ptr
<char[]> buffer_
;
64 explicit typed_buffer_ptr(size_t size
) : buffer_(new char[size
]) {
67 void reset(size_t size
) {
68 buffer_
.reset(new char[size
]);
72 return reinterpret_cast<T
*>(buffer_
.get());
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
) {
83 ACL_SIZE_INFORMATION info
;
84 if (!GetAclInformation(dacl
, &info
, sizeof(info
), AclSizeInformation
))
87 GENERIC_MAPPING generic_mapping
= {KEY_READ
, KEY_WRITE
, KEY_EXECUTE
,
89 MapGenericMask(&access_mask
, &generic_mapping
);
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
)
97 PSID existing_sid
= reinterpret_cast<PSID
>(&ace
->SidStart
);
98 DWORD mask
= ace
->Mask
;
99 MapGenericMask(&mask
, &generic_mapping
);
101 if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
&&
102 (mask
& access_mask
) == access_mask
&& EqualSid(existing_sid
, sid
))
105 if (ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
&&
106 (mask
& access_mask
) != 0 && EqualSid(existing_sid
, sid
))
114 bool CreateMachineState() {
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.");
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
);
133 // Get the security descriptor for the registry key.
134 DWORD original_sd_size
= 0;
135 ::RegGetKeySecurity(hklm_key
.Handle(), DACL_SECURITY_INFORMATION
, NULL
,
137 typed_buffer_ptr
<SECURITY_DESCRIPTOR
> original_sd(original_sd_size
);
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.");
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
150 DWORD new_sd_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
,
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
);
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");
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
)) {
180 // Add ALL-USERS ALL-ACCESS ACL.
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";
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");
196 BOOL ok
= SetSecurityDescriptorDacl(new_sd
, TRUE
, new_dacl
, FALSE
);
198 ASSERT_STRING("rlz_lib::CreateMachineState: "
199 "SetSecurityDescriptorOwner failed");
204 result
= ::RegSetKeySecurity(hklm_key
.Handle(),
205 DACL_SECURITY_INFORMATION
,
207 // Note that the new DACL cannot be freed until after the call to
208 // RegSetKeySecurity().
212 if (result
!= ERROR_SUCCESS
) {
213 ASSERT_STRING("rlz_lib::CreateMachineState: "
214 "Unable to create / open machine key.");
222 bool SetMachineDealCode(const char* dcc
) {
223 return MachineDealCode::Set(dcc
);
226 bool GetMachineDealCodeAsCgi(char* cgi
, size_t cgi_size
) {
227 return MachineDealCode::GetAsCgi(cgi
, cgi_size
);
230 bool GetMachineDealCode(char* dcc
, size_t dcc_size
) {
231 return MachineDealCode::Get(dcc
, dcc_size
);
234 // Combined functions.
236 bool SetMachineDealCodeFromPingResponse(const char* response
) {
237 return MachineDealCode::SetFromPingResponse(response
);
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.
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:
248 // HKLM\System\CurrentControlSet\Control\Lsa\AccessProviders
250 // This seems to be required since Win7.
251 base::win::RegKey
dest(temp_hklm_key
.Handle(), kHKLMAccessProviders
,
253 CopyRegistryTree(base::win::RegKey(HKEY_LOCAL_MACHINE
,
254 kHKLMAccessProviders
,
260 } // namespace rlz_lib