1// Copyright (c) 2010 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 "chrome/browser/policy/configuration_policy_provider_delegate_win.h"
6
7#include "base/string_number_conversions.h"
8#include "base/utf_string_conversions.h"
9#include "base/win/registry.h"
10#include "policy/policy_constants.h"
11
12using base::win::RegKey;
13
14namespace {
15
16bool ReadRegistryStringValue(RegKey* key, const string16& name,
17                             string16* result) {
18  DWORD value_size = 0;
19  DWORD key_type = 0;
20  scoped_array<uint8> buffer;
21
22  if (key->ReadValue(name.c_str(), 0, &value_size, &key_type) != ERROR_SUCCESS)
23    return false;
24  if (key_type != REG_SZ)
25    return false;
26
27  // According to the Microsoft documentation, the string
28  // buffer may not be explicitly 0-terminated. Allocate a
29  // slightly larger buffer and pre-fill to zeros to guarantee
30  // the 0-termination.
31  buffer.reset(new uint8[value_size + 2]);
32  memset(buffer.get(), 0, value_size + 2);
33  key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
34  result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
35  return true;
36}
37
38}  // namespace
39
40namespace policy {
41
42ConfigurationPolicyProviderDelegateWin::ConfigurationPolicyProviderDelegateWin(
43    const ConfigurationPolicyProvider::PolicyDefinitionList*
44        policy_definition_list)
45    : policy_definition_list_(policy_definition_list) {
46}
47
48DictionaryValue* ConfigurationPolicyProviderDelegateWin::Load() {
49  DictionaryValue* result = new DictionaryValue();
50  const ConfigurationPolicyProvider::PolicyDefinitionList::Entry* current;
51  for (current = policy_definition_list_->begin;
52       current != policy_definition_list_->end;
53       ++current) {
54    const string16 name(ASCIIToUTF16(current->name));
55    switch (current->value_type) {
56      case Value::TYPE_STRING: {
57        string16 string_value;
58        if (GetRegistryPolicyString(name, &string_value)) {
59          result->SetString(current->name, string_value);
60        }
61        break;
62      }
63      case Value::TYPE_LIST: {
64        scoped_ptr<ListValue> list_value(new ListValue);
65        if (GetRegistryPolicyStringList(name, list_value.get()))
66          result->Set(current->name, list_value.release());
67        break;
68      }
69      case Value::TYPE_BOOLEAN: {
70        bool bool_value;
71        if (GetRegistryPolicyBoolean(name, &bool_value)) {
72          result->SetBoolean(current->name, bool_value);
73        }
74        break;
75      }
76      case Value::TYPE_INTEGER: {
77        uint32 int_value;
78        if (GetRegistryPolicyInteger(name, &int_value)) {
79          result->SetInteger(current->name, int_value);
80        }
81        break;
82      }
83      default:
84        NOTREACHED();
85    }
86  }
87  return result;
88}
89
90bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyString(
91    const string16& name, string16* result) const {
92  RegKey policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
93  // First try the global policy.
94  if (ReadRegistryStringValue(&policy_key, name, result))
95    return true;
96
97  // Fall back on user-specific policy.
98  if (policy_key.Open(HKEY_CURRENT_USER, kRegistrySubKey,
99                      KEY_READ) != ERROR_SUCCESS)
100    return false;
101  return ReadRegistryStringValue(&policy_key, name, result);
102}
103
104bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyStringList(
105    const string16& key, ListValue* result) const {
106  string16 path = string16(kRegistrySubKey);
107  path += ASCIIToUTF16("\\") + key;
108  RegKey policy_key;
109  if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ) !=
110      ERROR_SUCCESS) {
111    // Fall back on user-specific policy.
112    if (policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ) !=
113        ERROR_SUCCESS)
114      return false;
115  }
116  string16 policy_string;
117  int index = 0;
118  while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index),
119                                 &policy_string)) {
120    result->Append(Value::CreateStringValue(policy_string));
121  }
122  return true;
123}
124
125bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyBoolean(
126    const string16& value_name, bool* result) const {
127  uint32 local_result = 0;
128  bool ret = GetRegistryPolicyInteger(value_name, &local_result);
129  if (ret)
130    *result = local_result != 0;
131  return ret;
132}
133
134bool ConfigurationPolicyProviderDelegateWin::GetRegistryPolicyInteger(
135    const string16& value_name, uint32* result) const {
136  DWORD value = 0;
137  RegKey policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
138  if (policy_key.ReadValueDW(value_name.c_str(), &value) == ERROR_SUCCESS) {
139    *result = value;
140    return true;
141  }
142
143  if (policy_key.Open(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ) ==
144      ERROR_SUCCESS) {
145    if (policy_key.ReadValueDW(value_name.c_str(), &value) == ERROR_SUCCESS) {
146      *result = value;
147      return true;
148    }
149  }
150  return false;
151}
152
153}  // namespace policy
154