Home | History | Annotate | Download | only in common
      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