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/lib/rlz_lib.h"
14 #include "base/basictypes.h"
15 #include "base/win/registry.h"
16 #include "rlz/lib/assert.h"
17 #include "rlz/lib/rlz_value_store.h"
18 #include "rlz/win/lib/machine_deal.h"
19 #include "rlz/win/lib/rlz_value_store_registry.h"
23 // OEM Deal confirmation storage functions.
26 class typed_buffer_ptr
{
27 scoped_ptr
<char[]> buffer_
;
33 explicit typed_buffer_ptr(size_t size
) : buffer_(new char[size
]) {
36 void reset(size_t size
) {
37 buffer_
.reset(new char[size
]);
41 return reinterpret_cast<T
*>(buffer_
.get());
45 // Check if this SID has the desired access by scanning the ACEs in the DACL.
46 // This function is part of the rlz_lib namespace so that it can be called from
47 // unit tests. Non-unit test code should not call this function.
48 bool HasAccess(PSID sid
, ACCESS_MASK access_mask
, ACL
* dacl
) {
52 ACL_SIZE_INFORMATION info
;
53 if (!GetAclInformation(dacl
, &info
, sizeof(info
), AclSizeInformation
))
56 GENERIC_MAPPING generic_mapping
= {KEY_READ
, KEY_WRITE
, KEY_EXECUTE
,
58 MapGenericMask(&access_mask
, &generic_mapping
);
60 for (DWORD i
= 0; i
< info
.AceCount
; ++i
) {
61 ACCESS_ALLOWED_ACE
* ace
;
62 if (GetAce(dacl
, i
, reinterpret_cast<void**>(&ace
))) {
63 if ((ace
->Header
.AceFlags
& INHERIT_ONLY_ACE
) == INHERIT_ONLY_ACE
)
66 PSID existing_sid
= reinterpret_cast<PSID
>(&ace
->SidStart
);
67 DWORD mask
= ace
->Mask
;
68 MapGenericMask(&mask
, &generic_mapping
);
70 if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
&&
71 (mask
& access_mask
) == access_mask
&& EqualSid(existing_sid
, sid
))
74 if (ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
&&
75 (mask
& access_mask
) != 0 && EqualSid(existing_sid
, sid
))
83 bool CreateMachineState() {
88 base::win::RegKey hklm_key
;
89 if (hklm_key
.Create(HKEY_LOCAL_MACHINE
,
90 RlzValueStoreRegistry::GetWideLibKeyName().c_str(),
91 KEY_ALL_ACCESS
| KEY_WOW64_32KEY
) != ERROR_SUCCESS
) {
92 ASSERT_STRING("rlz_lib::CreateMachineState: "
93 "Unable to create / open machine key.");
97 // Create a SID that represents ALL USERS.
98 DWORD users_sid_size
= SECURITY_MAX_SID_SIZE
;
99 typed_buffer_ptr
<SID
> users_sid(users_sid_size
);
100 CreateWellKnownSid(WinBuiltinUsersSid
, NULL
, users_sid
, &users_sid_size
);
102 // Get the security descriptor for the registry key.
103 DWORD original_sd_size
= 0;
104 ::RegGetKeySecurity(hklm_key
.Handle(), DACL_SECURITY_INFORMATION
, NULL
,
106 typed_buffer_ptr
<SECURITY_DESCRIPTOR
> original_sd(original_sd_size
);
108 LONG result
= ::RegGetKeySecurity(hklm_key
.Handle(),
109 DACL_SECURITY_INFORMATION
, original_sd
, &original_sd_size
);
110 if (result
!= ERROR_SUCCESS
) {
111 ASSERT_STRING("rlz_lib::CreateMachineState: "
112 "Unable to create / open machine key.");
116 // Make a copy of the security descriptor so we can modify it. The one
117 // returned by RegGetKeySecurity() is self-relative, so we need to make it
119 DWORD new_sd_size
= 0;
122 DWORD owner_size
= 0;
123 DWORD group_size
= 0;
124 ::MakeAbsoluteSD(original_sd
, NULL
, &new_sd_size
, NULL
, &dacl_size
,
125 NULL
, &sacl_size
, NULL
, &owner_size
,
128 typed_buffer_ptr
<SECURITY_DESCRIPTOR
> new_sd(new_sd_size
);
129 // Make sure the DACL is big enough to add one more ACE.
130 typed_buffer_ptr
<ACL
> dacl(dacl_size
+ SECURITY_MAX_SID_SIZE
);
131 typed_buffer_ptr
<ACL
> sacl(sacl_size
);
132 typed_buffer_ptr
<SID
> owner(owner_size
);
133 typed_buffer_ptr
<SID
> group(group_size
);
135 if (!::MakeAbsoluteSD(original_sd
, new_sd
, &new_sd_size
, dacl
, &dacl_size
,
136 sacl
, &sacl_size
, owner
, &owner_size
,
137 group
, &group_size
)) {
138 ASSERT_STRING("rlz_lib::CreateMachineState: MakeAbsoluteSD failed");
142 // If all users already have read/write access to the registry key, then
143 // nothing to do. Otherwise change the security descriptor of the key to
144 // give everyone access.
145 if (HasAccess(users_sid
, KEY_ALL_ACCESS
, dacl
)) {
149 // Add ALL-USERS ALL-ACCESS ACL.
151 ZeroMemory(&ea
, sizeof(EXPLICIT_ACCESS
));
152 ea
.grfAccessPermissions
= GENERIC_ALL
| KEY_ALL_ACCESS
;
153 ea
.grfAccessMode
= GRANT_ACCESS
;
154 ea
.grfInheritance
= SUB_CONTAINERS_AND_OBJECTS_INHERIT
;
155 ea
.Trustee
.TrusteeForm
= TRUSTEE_IS_NAME
;
156 ea
.Trustee
.ptstrName
= const_cast<wchar_t*>(L
"Everyone");
158 ACL
* new_dacl
= NULL
;
159 result
= SetEntriesInAcl(1, &ea
, dacl
, &new_dacl
);
160 if (result
!= ERROR_SUCCESS
) {
161 ASSERT_STRING("rlz_lib::CreateMachineState: SetEntriesInAcl failed");
165 BOOL ok
= SetSecurityDescriptorDacl(new_sd
, TRUE
, new_dacl
, FALSE
);
167 ASSERT_STRING("rlz_lib::CreateMachineState: "
168 "SetSecurityDescriptorOwner failed");
173 result
= ::RegSetKeySecurity(hklm_key
.Handle(),
174 DACL_SECURITY_INFORMATION
,
176 // Note that the new DACL cannot be freed until after the call to
177 // RegSetKeySecurity().
181 if (result
!= ERROR_SUCCESS
) {
182 ASSERT_STRING("rlz_lib::CreateMachineState: "
183 "Unable to create / open machine key.");
191 bool SetMachineDealCode(const char* dcc
) {
192 return MachineDealCode::Set(dcc
);
195 bool GetMachineDealCodeAsCgi(char* cgi
, size_t cgi_size
) {
196 return MachineDealCode::GetAsCgi(cgi
, cgi_size
);
199 bool GetMachineDealCode(char* dcc
, size_t dcc_size
) {
200 return MachineDealCode::Get(dcc
, dcc_size
);
203 // Combined functions.
205 bool SetMachineDealCodeFromPingResponse(const char* response
) {
206 return MachineDealCode::SetFromPingResponse(response
);
209 } // namespace rlz_lib