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 #include "components/policy/core/common/policy_loader_mac.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/callback.h" 10 #include "base/files/file_util.h" 11 #include "base/mac/foundation_util.h" 12 #include "base/mac/scoped_cftyperef.h" 13 #include "base/path_service.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" 25 26 using base::ScopedCFTypeRef; 27 28 namespace policy { 29 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 38 PolicyLoaderMac::~PolicyLoaderMac() {} 39 40 void PolicyLoaderMac::InitOnBackgroundThread() { 41 if (!managed_policy_path_.empty()) { 42 watcher_.Watch( 43 managed_policy_path_, false, 44 base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this))); 45 } 46 } 47 48 scoped_ptr<PolicyBundle> PolicyLoaderMac::Load() { 49 preferences_->AppSynchronize(kCFPreferencesCurrentApplication); 50 scoped_ptr<PolicyBundle> bundle(new PolicyBundle()); 51 52 // Load Chrome's policy. 53 PolicyMap& chrome_policy = 54 bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())); 55 56 PolicyLoadStatusSample status; 57 bool policy_present = false; 58 const Schema* schema = 59 schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, "")); 60 for (Schema::Iterator it = schema->GetPropertiesIterator(); 61 !it.IsAtEnd(); it.Advance()) { 62 base::ScopedCFTypeRef<CFStringRef> name( 63 base::SysUTF8ToCFStringRef(it.key())); 64 base::ScopedCFTypeRef<CFPropertyListRef> value( 65 preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication)); 66 if (!value.get()) 67 continue; 68 policy_present = true; 69 bool forced = 70 preferences_->AppValueIsForced(name, kCFPreferencesCurrentApplication); 71 PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY : 72 POLICY_LEVEL_RECOMMENDED; 73 // TODO(joaodasilva): figure the policy scope. 74 scoped_ptr<base::Value> policy = PropertyToValue(value); 75 if (policy) { 76 chrome_policy.Set( 77 it.key(), level, POLICY_SCOPE_USER, policy.release(), NULL); 78 } else { 79 status.Add(POLICY_LOAD_STATUS_PARSE_ERROR); 80 } 81 } 82 83 if (!policy_present) 84 status.Add(POLICY_LOAD_STATUS_NO_POLICY); 85 86 // Load policy for the registered components. 87 LoadPolicyForDomain(POLICY_DOMAIN_EXTENSIONS, "extensions", bundle.get()); 88 89 return bundle.Pass(); 90 } 91 92 base::Time PolicyLoaderMac::LastModificationTime() { 93 base::File::Info file_info; 94 if (!base::GetFileInfo(managed_policy_path_, &file_info) || 95 file_info.is_directory) { 96 return base::Time(); 97 } 98 99 return file_info.last_modified; 100 } 101 102 void PolicyLoaderMac::LoadPolicyForDomain( 103 PolicyDomain domain, 104 const std::string& domain_name, 105 PolicyBundle* bundle) { 106 std::string id_prefix(base::mac::BaseBundleID()); 107 id_prefix.append(".").append(domain_name).append("."); 108 109 const ComponentMap* components = schema_map()->GetComponents(domain); 110 if (!components) 111 return; 112 113 for (ComponentMap::const_iterator it = components->begin(); 114 it != components->end(); ++it) { 115 PolicyMap policy; 116 LoadPolicyForComponent(id_prefix + it->first, it->second, &policy); 117 if (!policy.empty()) 118 bundle->Get(PolicyNamespace(domain, it->first)).Swap(&policy); 119 } 120 } 121 122 void PolicyLoaderMac::LoadPolicyForComponent( 123 const std::string& bundle_id_string, 124 const Schema& schema, 125 PolicyMap* policy) { 126 // TODO(joaodasilva): Extensions may be registered in a ComponentMap 127 // without a schema, to allow a graceful update of the Legacy Browser Support 128 // extension on Windows. Remove this check once that support is removed. 129 if (!schema.valid()) 130 return; 131 132 base::ScopedCFTypeRef<CFStringRef> bundle_id( 133 base::SysUTF8ToCFStringRef(bundle_id_string)); 134 preferences_->AppSynchronize(bundle_id); 135 136 for (Schema::Iterator it = schema.GetPropertiesIterator(); 137 !it.IsAtEnd(); it.Advance()) { 138 base::ScopedCFTypeRef<CFStringRef> pref_name( 139 base::SysUTF8ToCFStringRef(it.key())); 140 base::ScopedCFTypeRef<CFPropertyListRef> value( 141 preferences_->CopyAppValue(pref_name, bundle_id)); 142 if (!value.get()) 143 continue; 144 bool forced = 145 preferences_->AppValueIsForced(pref_name, bundle_id); 146 PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY : 147 POLICY_LEVEL_RECOMMENDED; 148 scoped_ptr<base::Value> policy_value = PropertyToValue(value); 149 if (policy_value) { 150 policy->Set(it.key(), level, POLICY_SCOPE_USER, 151 policy_value.release(), NULL); 152 } 153 } 154 } 155 156 void PolicyLoaderMac::OnFileUpdated(const base::FilePath& path, bool error) { 157 if (!error) 158 Reload(false); 159 } 160 161 } // namespace policy 162