1 // Copyright (c) 2015 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 #include "components/policy/core/common/policy_loader_mac.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/sequenced_task_runner.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/values.h"
17 #include "components/policy/core/common/external_data_fetcher.h"
18 #include "components/policy/core/common/mac_util.h"
19 #include "components/policy/core/common/policy_bundle.h"
20 #include "components/policy/core/common/policy_load_status.h"
21 #include "components/policy/core/common/policy_map.h"
22 #include "components/policy/core/common/preferences_mac.h"
23 #include "components/policy/core/common/schema.h"
24 #include "components/policy/core/common/schema_map.h"
26 using base::ScopedCFTypeRef;
30 PolicyLoaderMac::PolicyLoaderMac(
31 scoped_refptr<base::SequencedTaskRunner> task_runner,
32 const base::FilePath& managed_policy_path,
33 MacPreferences* preferences)
34 : AsyncPolicyLoader(task_runner),
35 preferences_(preferences),
36 managed_policy_path_(managed_policy_path),
37 application_id_(kCFPreferencesCurrentApplication) {
40 PolicyLoaderMac::PolicyLoaderMac(
41 scoped_refptr<base::SequencedTaskRunner> task_runner,
42 const base::FilePath& managed_policy_path,
43 MacPreferences* preferences,
44 CFStringRef application_id)
45 : AsyncPolicyLoader(task_runner),
46 preferences_(preferences),
47 managed_policy_path_(managed_policy_path),
48 application_id_(application_id) {
51 PolicyLoaderMac::~PolicyLoaderMac() {
54 void PolicyLoaderMac::InitOnBackgroundThread() {
55 if (!managed_policy_path_.empty()) {
57 managed_policy_path_, false,
58 base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this)));
62 scoped_ptr<PolicyBundle> PolicyLoaderMac::Load() {
63 preferences_->AppSynchronize(application_id_);
64 scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
66 // Load Chrome's policy.
67 PolicyMap& chrome_policy =
68 bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
70 PolicyLoadStatusSample status;
71 bool policy_present = false;
72 const Schema* schema =
73 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
74 for (Schema::Iterator it = schema->GetPropertiesIterator(); !it.IsAtEnd();
76 base::ScopedCFTypeRef<CFStringRef> name(
77 base::SysUTF8ToCFStringRef(it.key()));
78 base::ScopedCFTypeRef<CFPropertyListRef> value(
79 preferences_->CopyAppValue(name, application_id_));
82 policy_present = true;
83 bool forced = preferences_->AppValueIsForced(name, application_id_);
85 forced ? POLICY_LEVEL_MANDATORY : POLICY_LEVEL_RECOMMENDED;
86 // TODO(joaodasilva): figure the policy scope.
87 scoped_ptr<base::Value> policy = PropertyToValue(value);
89 chrome_policy.Set(it.key(), level, POLICY_SCOPE_USER, policy.release(),
92 status.Add(POLICY_LOAD_STATUS_PARSE_ERROR);
97 status.Add(POLICY_LOAD_STATUS_NO_POLICY);
99 // Load policy for the registered components.
100 LoadPolicyForDomain(POLICY_DOMAIN_EXTENSIONS, "extensions", bundle.get());
102 return bundle.Pass();
105 base::Time PolicyLoaderMac::LastModificationTime() {
106 base::File::Info file_info;
107 if (!base::GetFileInfo(managed_policy_path_, &file_info) ||
108 file_info.is_directory) {
112 return file_info.last_modified;
115 #if defined(OS_MACOSX) && !defined(OS_IOS)
117 base::FilePath PolicyLoaderMac::GetManagedPolicyPath(CFStringRef bundle_id) {
118 // This constructs the path to the plist file in which Mac OS X stores the
119 // managed preference for the application. This is undocumented and therefore
120 // fragile, but if it doesn't work out, AsyncPolicyLoader has a task that
121 // polls periodically in order to reload managed preferences later even if we
122 // missed the change.
125 if (!base::mac::GetLocalDirectory(NSLibraryDirectory, &path))
126 return base::FilePath();
127 path = path.Append(FILE_PATH_LITERAL("Managed Preferences"));
128 char* login = getlogin();
130 return base::FilePath();
131 path = path.AppendASCII(login);
132 return path.Append(base::SysCFStringRefToUTF8(bundle_id) + ".plist");
137 void PolicyLoaderMac::LoadPolicyForDomain(PolicyDomain domain,
138 const std::string& domain_name,
139 PolicyBundle* bundle) {
140 std::string id_prefix(base::mac::BaseBundleID());
141 id_prefix.append(".").append(domain_name).append(".");
143 const ComponentMap* components = schema_map()->GetComponents(domain);
147 for (ComponentMap::const_iterator it = components->begin();
148 it != components->end(); ++it) {
150 LoadPolicyForComponent(id_prefix + it->first, it->second, &policy);
152 bundle->Get(PolicyNamespace(domain, it->first)).Swap(&policy);
156 void PolicyLoaderMac::LoadPolicyForComponent(
157 const std::string& bundle_id_string,
158 const Schema& schema,
160 // TODO(joaodasilva): Extensions may be registered in a ComponentMap
161 // without a schema, to allow a graceful update of the Legacy Browser Support
162 // extension on Windows. Remove this check once that support is removed.
166 base::ScopedCFTypeRef<CFStringRef> bundle_id(
167 base::SysUTF8ToCFStringRef(bundle_id_string));
168 preferences_->AppSynchronize(bundle_id);
170 for (Schema::Iterator it = schema.GetPropertiesIterator(); !it.IsAtEnd();
172 base::ScopedCFTypeRef<CFStringRef> pref_name(
173 base::SysUTF8ToCFStringRef(it.key()));
174 base::ScopedCFTypeRef<CFPropertyListRef> value(
175 preferences_->CopyAppValue(pref_name, bundle_id));
178 bool forced = preferences_->AppValueIsForced(pref_name, bundle_id);
180 forced ? POLICY_LEVEL_MANDATORY : POLICY_LEVEL_RECOMMENDED;
181 scoped_ptr<base::Value> policy_value = PropertyToValue(value);
183 policy->Set(it.key(), level, POLICY_SCOPE_USER, policy_value.release(),
189 void PolicyLoaderMac::OnFileUpdated(const base::FilePath& path, bool error) {
194 } // namespace policy