15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/policy_loader_mac.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
97dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/callback.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/foundation_util.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/mac/scoped_cftyperef.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/sequenced_task_runner.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/sys_string_conversions.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/external_data_fetcher.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/policy/core/common/mac_util.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_bundle.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/policy_load_status.h"
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_map.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/preferences_mac.h"
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "components/policy/core/common/schema.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/schema_map.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing base::ScopedCFTypeRef;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)PolicyLoaderMac::PolicyLoaderMac(
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    scoped_refptr<base::SequencedTaskRunner> task_runner,
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    const base::FilePath& managed_policy_path,
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    MacPreferences* preferences)
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : AsyncPolicyLoader(task_runner),
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      preferences_(preferences),
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      managed_policy_path_(managed_policy_path) {}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PolicyLoaderMac::~PolicyLoaderMac() {}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void PolicyLoaderMac::InitOnBackgroundThread() {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!managed_policy_path_.empty()) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    watcher_.Watch(
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        managed_policy_path_, false,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&PolicyLoaderMac::OnFileUpdated, base::Unretained(this)));
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<PolicyBundle> PolicyLoaderMac::Load() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  preferences_->AppSynchronize(kCFPreferencesCurrentApplication);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PolicyBundle> bundle(new PolicyBundle());
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Load Chrome's policy.
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PolicyMap& chrome_policy =
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  PolicyLoadStatusSample status;
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool policy_present = false;
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const Schema* schema =
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      schema_map()->GetSchema(PolicyNamespace(POLICY_DOMAIN_CHROME, ""));
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (Schema::Iterator it = schema->GetPropertiesIterator();
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       !it.IsAtEnd(); it.Advance()) {
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ScopedCFTypeRef<CFStringRef> name(
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        base::SysUTF8ToCFStringRef(it.key()));
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ScopedCFTypeRef<CFPropertyListRef> value(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        preferences_->CopyAppValue(name, kCFPreferencesCurrentApplication));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!value.get())
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    policy_present = true;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool forced =
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        preferences_->AppValueIsForced(name, kCFPreferencesCurrentApplication);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY :
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 POLICY_LEVEL_RECOMMENDED;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(joaodasilva): figure the policy scope.
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<base::Value> policy = PropertyToValue(value);
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (policy) {
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      chrome_policy.Set(
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          it.key(), level, POLICY_SCOPE_USER, policy.release(), NULL);
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      status.Add(POLICY_LOAD_STATUS_PARSE_ERROR);
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!policy_present)
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    status.Add(POLICY_LOAD_STATUS_NO_POLICY);
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Load policy for the registered components.
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  LoadPolicyForDomain(POLICY_DOMAIN_EXTENSIONS, "extensions", bundle.get());
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bundle.Pass();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time PolicyLoaderMac::LastModificationTime() {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::File::Info file_info;
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!base::GetFileInfo(managed_policy_path_, &file_info) ||
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_info.is_directory) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return base::Time();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_info.last_modified;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void PolicyLoaderMac::LoadPolicyForDomain(
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PolicyDomain domain,
10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& domain_name,
10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PolicyBundle* bundle) {
10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::string id_prefix(base::mac::BaseBundleID());
10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  id_prefix.append(".").append(domain_name).append(".");
10890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const ComponentMap* components = schema_map()->GetComponents(domain);
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!components)
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (ComponentMap::const_iterator it = components->begin();
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       it != components->end(); ++it) {
11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PolicyMap policy;
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    LoadPolicyForComponent(id_prefix + it->first, it->second, &policy);
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!policy.empty())
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      bundle->Get(PolicyNamespace(domain, it->first)).Swap(&policy);
11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void PolicyLoaderMac::LoadPolicyForComponent(
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const std::string& bundle_id_string,
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const Schema& schema,
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PolicyMap* policy) {
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TODO(joaodasilva): Extensions may be registered in a ComponentMap
12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // without a schema, to allow a graceful update of the Legacy Browser Support
12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // extension on Windows. Remove this check once that support is removed.
12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!schema.valid())
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return;
13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ScopedCFTypeRef<CFStringRef> bundle_id(
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      base::SysUTF8ToCFStringRef(bundle_id_string));
13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  preferences_->AppSynchronize(bundle_id);
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  for (Schema::Iterator it = schema.GetPropertiesIterator();
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)       !it.IsAtEnd(); it.Advance()) {
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ScopedCFTypeRef<CFStringRef> pref_name(
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        base::SysUTF8ToCFStringRef(it.key()));
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    base::ScopedCFTypeRef<CFPropertyListRef> value(
14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        preferences_->CopyAppValue(pref_name, bundle_id));
14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!value.get())
14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      continue;
14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    bool forced =
14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        preferences_->AppValueIsForced(pref_name, bundle_id);
14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    PolicyLevel level = forced ? POLICY_LEVEL_MANDATORY :
14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                 POLICY_LEVEL_RECOMMENDED;
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<base::Value> policy_value = PropertyToValue(value);
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (policy_value) {
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      policy->Set(it.key(), level, POLICY_SCOPE_USER,
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                  policy_value.release(), NULL);
15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PolicyLoaderMac::OnFileUpdated(const base::FilePath& path, bool error) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!error)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Reload(false);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
162