security/sandbox/chromium/base/win/registry.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/sandbox/chromium/base/win/registry.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,483 @@
     1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +#include "base/win/registry.h"
     1.9 +
    1.10 +#include <shlwapi.h>
    1.11 +#include <algorithm>
    1.12 +
    1.13 +#include "base/logging.h"
    1.14 +#include "base/strings/string_util.h"
    1.15 +#include "base/threading/thread_restrictions.h"
    1.16 +
    1.17 +#pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey
    1.18 +
    1.19 +namespace base {
    1.20 +namespace win {
    1.21 +
    1.22 +namespace {
    1.23 +
    1.24 +// RegEnumValue() reports the number of characters from the name that were
    1.25 +// written to the buffer, not how many there are. This constant is the maximum
    1.26 +// name size, such that a buffer with this size should read any name.
    1.27 +const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
    1.28 +
    1.29 +// Registry values are read as BYTE* but can have wchar_t* data whose last
    1.30 +// wchar_t is truncated. This function converts the reported |byte_size| to
    1.31 +// a size in wchar_t that can store a truncated wchar_t if necessary.
    1.32 +inline DWORD to_wchar_size(DWORD byte_size) {
    1.33 +  return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
    1.34 +}
    1.35 +
    1.36 +}  // namespace
    1.37 +
    1.38 +// RegKey ----------------------------------------------------------------------
    1.39 +
    1.40 +RegKey::RegKey()
    1.41 +    : key_(NULL),
    1.42 +      watch_event_(0) {
    1.43 +}
    1.44 +
    1.45 +RegKey::RegKey(HKEY key)
    1.46 +    : key_(key),
    1.47 +      watch_event_(0) {
    1.48 +}
    1.49 +
    1.50 +RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
    1.51 +    : key_(NULL),
    1.52 +      watch_event_(0) {
    1.53 +  if (rootkey) {
    1.54 +    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
    1.55 +      Create(rootkey, subkey, access);
    1.56 +    else
    1.57 +      Open(rootkey, subkey, access);
    1.58 +  } else {
    1.59 +    DCHECK(!subkey);
    1.60 +  }
    1.61 +}
    1.62 +
    1.63 +RegKey::~RegKey() {
    1.64 +  Close();
    1.65 +}
    1.66 +
    1.67 +LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
    1.68 +  DWORD disposition_value;
    1.69 +  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
    1.70 +}
    1.71 +
    1.72 +LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
    1.73 +                                   DWORD* disposition, REGSAM access) {
    1.74 +  DCHECK(rootkey && subkey && access && disposition);
    1.75 +  Close();
    1.76 +
    1.77 +  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
    1.78 +                               REG_OPTION_NON_VOLATILE, access, NULL, &key_,
    1.79 +                               disposition);
    1.80 +  return result;
    1.81 +}
    1.82 +
    1.83 +LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
    1.84 +  DCHECK(name && access);
    1.85 +  HKEY subkey = NULL;
    1.86 +  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
    1.87 +                               access, NULL, &subkey, NULL);
    1.88 +  Close();
    1.89 +
    1.90 +  key_ = subkey;
    1.91 +  return result;
    1.92 +}
    1.93 +
    1.94 +LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
    1.95 +  DCHECK(rootkey && subkey && access);
    1.96 +  Close();
    1.97 +
    1.98 +  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
    1.99 +  return result;
   1.100 +}
   1.101 +
   1.102 +LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
   1.103 +  DCHECK(relative_key_name && access);
   1.104 +  HKEY subkey = NULL;
   1.105 +  LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
   1.106 +
   1.107 +  // We have to close the current opened key before replacing it with the new
   1.108 +  // one.
   1.109 +  Close();
   1.110 +
   1.111 +  key_ = subkey;
   1.112 +  return result;
   1.113 +}
   1.114 +
   1.115 +void RegKey::Close() {
   1.116 +  StopWatching();
   1.117 +  if (key_) {
   1.118 +    ::RegCloseKey(key_);
   1.119 +    key_ = NULL;
   1.120 +  }
   1.121 +}
   1.122 +
   1.123 +void RegKey::Set(HKEY key) {
   1.124 +  if (key_ != key) {
   1.125 +    Close();
   1.126 +    key_ = key;
   1.127 +  }
   1.128 +}
   1.129 +
   1.130 +HKEY RegKey::Take() {
   1.131 +  StopWatching();
   1.132 +  HKEY key = key_;
   1.133 +  key_ = NULL;
   1.134 +  return key;
   1.135 +}
   1.136 +
   1.137 +bool RegKey::HasValue(const wchar_t* name) const {
   1.138 +  return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
   1.139 +}
   1.140 +
   1.141 +DWORD RegKey::GetValueCount() const {
   1.142 +  DWORD count = 0;
   1.143 +  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
   1.144 +                                NULL, NULL, NULL, NULL);
   1.145 +  return (result == ERROR_SUCCESS) ? count : 0;
   1.146 +}
   1.147 +
   1.148 +LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
   1.149 +  wchar_t buf[256];
   1.150 +  DWORD bufsize = arraysize(buf);
   1.151 +  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
   1.152 +  if (r == ERROR_SUCCESS)
   1.153 +    *name = buf;
   1.154 +
   1.155 +  return r;
   1.156 +}
   1.157 +
   1.158 +LONG RegKey::DeleteKey(const wchar_t* name) {
   1.159 +  DCHECK(key_);
   1.160 +  DCHECK(name);
   1.161 +  LONG result = SHDeleteKey(key_, name);
   1.162 +  return result;
   1.163 +}
   1.164 +
   1.165 +LONG RegKey::DeleteValue(const wchar_t* value_name) {
   1.166 +  DCHECK(key_);
   1.167 +  LONG result = RegDeleteValue(key_, value_name);
   1.168 +  return result;
   1.169 +}
   1.170 +
   1.171 +LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
   1.172 +  DCHECK(out_value);
   1.173 +  DWORD type = REG_DWORD;
   1.174 +  DWORD size = sizeof(DWORD);
   1.175 +  DWORD local_value = 0;
   1.176 +  LONG result = ReadValue(name, &local_value, &size, &type);
   1.177 +  if (result == ERROR_SUCCESS) {
   1.178 +    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
   1.179 +      *out_value = local_value;
   1.180 +    else
   1.181 +      result = ERROR_CANTREAD;
   1.182 +  }
   1.183 +
   1.184 +  return result;
   1.185 +}
   1.186 +
   1.187 +LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
   1.188 +  DCHECK(out_value);
   1.189 +  DWORD type = REG_QWORD;
   1.190 +  int64 local_value = 0;
   1.191 +  DWORD size = sizeof(local_value);
   1.192 +  LONG result = ReadValue(name, &local_value, &size, &type);
   1.193 +  if (result == ERROR_SUCCESS) {
   1.194 +    if ((type == REG_QWORD || type == REG_BINARY) &&
   1.195 +        size == sizeof(local_value))
   1.196 +      *out_value = local_value;
   1.197 +    else
   1.198 +      result = ERROR_CANTREAD;
   1.199 +  }
   1.200 +
   1.201 +  return result;
   1.202 +}
   1.203 +
   1.204 +LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
   1.205 +  DCHECK(out_value);
   1.206 +  const size_t kMaxStringLength = 1024;  // This is after expansion.
   1.207 +  // Use the one of the other forms of ReadValue if 1024 is too small for you.
   1.208 +  wchar_t raw_value[kMaxStringLength];
   1.209 +  DWORD type = REG_SZ, size = sizeof(raw_value);
   1.210 +  LONG result = ReadValue(name, raw_value, &size, &type);
   1.211 +  if (result == ERROR_SUCCESS) {
   1.212 +    if (type == REG_SZ) {
   1.213 +      *out_value = raw_value;
   1.214 +    } else if (type == REG_EXPAND_SZ) {
   1.215 +      wchar_t expanded[kMaxStringLength];
   1.216 +      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
   1.217 +      // Success: returns the number of wchar_t's copied
   1.218 +      // Fail: buffer too small, returns the size required
   1.219 +      // Fail: other, returns 0
   1.220 +      if (size == 0 || size > kMaxStringLength) {
   1.221 +        result = ERROR_MORE_DATA;
   1.222 +      } else {
   1.223 +        *out_value = expanded;
   1.224 +      }
   1.225 +    } else {
   1.226 +      // Not a string. Oops.
   1.227 +      result = ERROR_CANTREAD;
   1.228 +    }
   1.229 +  }
   1.230 +
   1.231 +  return result;
   1.232 +}
   1.233 +
   1.234 +LONG RegKey::ReadValue(const wchar_t* name,
   1.235 +                       void* data,
   1.236 +                       DWORD* dsize,
   1.237 +                       DWORD* dtype) const {
   1.238 +  LONG result = RegQueryValueEx(key_, name, 0, dtype,
   1.239 +                                reinterpret_cast<LPBYTE>(data), dsize);
   1.240 +  return result;
   1.241 +}
   1.242 +
   1.243 +LONG RegKey::ReadValues(const wchar_t* name,
   1.244 +                        std::vector<std::wstring>* values) {
   1.245 +  values->clear();
   1.246 +
   1.247 +  DWORD type = REG_MULTI_SZ;
   1.248 +  DWORD size = 0;
   1.249 +  LONG result = ReadValue(name, NULL, &size, &type);
   1.250 +  if (FAILED(result) || size == 0)
   1.251 +    return result;
   1.252 +
   1.253 +  if (type != REG_MULTI_SZ)
   1.254 +    return ERROR_CANTREAD;
   1.255 +
   1.256 +  std::vector<wchar_t> buffer(size / sizeof(wchar_t));
   1.257 +  result = ReadValue(name, &buffer[0], &size, NULL);
   1.258 +  if (FAILED(result) || size == 0)
   1.259 +    return result;
   1.260 +
   1.261 +  // Parse the double-null-terminated list of strings.
   1.262 +  // Note: This code is paranoid to not read outside of |buf|, in the case where
   1.263 +  // it may not be properly terminated.
   1.264 +  const wchar_t* entry = &buffer[0];
   1.265 +  const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
   1.266 +  while (entry < buffer_end && entry[0] != '\0') {
   1.267 +    const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
   1.268 +    values->push_back(std::wstring(entry, entry_end));
   1.269 +    entry = entry_end + 1;
   1.270 +  }
   1.271 +  return 0;
   1.272 +}
   1.273 +
   1.274 +LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
   1.275 +  return WriteValue(
   1.276 +      name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
   1.277 +}
   1.278 +
   1.279 +LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
   1.280 +  return WriteValue(name, in_value,
   1.281 +      static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
   1.282 +}
   1.283 +
   1.284 +LONG RegKey::WriteValue(const wchar_t* name,
   1.285 +                        const void* data,
   1.286 +                        DWORD dsize,
   1.287 +                        DWORD dtype) {
   1.288 +  DCHECK(data || !dsize);
   1.289 +
   1.290 +  LONG result = RegSetValueEx(key_, name, 0, dtype,
   1.291 +      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
   1.292 +  return result;
   1.293 +}
   1.294 +
   1.295 +LONG RegKey::StartWatching() {
   1.296 +  DCHECK(key_);
   1.297 +  if (!watch_event_)
   1.298 +    watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
   1.299 +
   1.300 +  DWORD filter = REG_NOTIFY_CHANGE_NAME |
   1.301 +                 REG_NOTIFY_CHANGE_ATTRIBUTES |
   1.302 +                 REG_NOTIFY_CHANGE_LAST_SET |
   1.303 +                 REG_NOTIFY_CHANGE_SECURITY;
   1.304 +
   1.305 +  // Watch the registry key for a change of value.
   1.306 +  LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE);
   1.307 +  if (result != ERROR_SUCCESS) {
   1.308 +    CloseHandle(watch_event_);
   1.309 +    watch_event_ = 0;
   1.310 +  }
   1.311 +
   1.312 +  return result;
   1.313 +}
   1.314 +
   1.315 +bool RegKey::HasChanged() {
   1.316 +  if (watch_event_) {
   1.317 +    if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
   1.318 +      StartWatching();
   1.319 +      return true;
   1.320 +    }
   1.321 +  }
   1.322 +  return false;
   1.323 +}
   1.324 +
   1.325 +LONG RegKey::StopWatching() {
   1.326 +  LONG result = ERROR_INVALID_HANDLE;
   1.327 +  if (watch_event_) {
   1.328 +    CloseHandle(watch_event_);
   1.329 +    watch_event_ = 0;
   1.330 +    result = ERROR_SUCCESS;
   1.331 +  }
   1.332 +  return result;
   1.333 +}
   1.334 +
   1.335 +// RegistryValueIterator ------------------------------------------------------
   1.336 +
   1.337 +RegistryValueIterator::RegistryValueIterator(HKEY root_key,
   1.338 +                                             const wchar_t* folder_key)
   1.339 +    : name_(MAX_PATH, L'\0'),
   1.340 +      value_(MAX_PATH, L'\0') {
   1.341 +  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
   1.342 +  if (result != ERROR_SUCCESS) {
   1.343 +    key_ = NULL;
   1.344 +  } else {
   1.345 +    DWORD count = 0;
   1.346 +    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
   1.347 +                               NULL, NULL, NULL, NULL);
   1.348 +
   1.349 +    if (result != ERROR_SUCCESS) {
   1.350 +      ::RegCloseKey(key_);
   1.351 +      key_ = NULL;
   1.352 +    } else {
   1.353 +      index_ = count - 1;
   1.354 +    }
   1.355 +  }
   1.356 +
   1.357 +  Read();
   1.358 +}
   1.359 +
   1.360 +RegistryValueIterator::~RegistryValueIterator() {
   1.361 +  if (key_)
   1.362 +    ::RegCloseKey(key_);
   1.363 +}
   1.364 +
   1.365 +DWORD RegistryValueIterator::ValueCount() const {
   1.366 +  DWORD count = 0;
   1.367 +  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
   1.368 +                                  &count, NULL, NULL, NULL, NULL);
   1.369 +  if (result != ERROR_SUCCESS)
   1.370 +    return 0;
   1.371 +
   1.372 +  return count;
   1.373 +}
   1.374 +
   1.375 +bool RegistryValueIterator::Valid() const {
   1.376 +  return key_ != NULL && index_ >= 0;
   1.377 +}
   1.378 +
   1.379 +void RegistryValueIterator::operator++() {
   1.380 +  --index_;
   1.381 +  Read();
   1.382 +}
   1.383 +
   1.384 +bool RegistryValueIterator::Read() {
   1.385 +  if (Valid()) {
   1.386 +    DWORD capacity = static_cast<DWORD>(name_.capacity());
   1.387 +    DWORD name_size = capacity;
   1.388 +    // |value_size_| is in bytes. Reserve the last character for a NUL.
   1.389 +    value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
   1.390 +    LONG result = ::RegEnumValue(
   1.391 +        key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
   1.392 +        reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
   1.393 +
   1.394 +    if (result == ERROR_MORE_DATA) {
   1.395 +      // Registry key names are limited to 255 characters and fit within
   1.396 +      // MAX_PATH (which is 260) but registry value names can use up to 16,383
   1.397 +      // characters and the value itself is not limited
   1.398 +      // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
   1.399 +      // ms724872(v=vs.85).aspx).
   1.400 +      // Resize the buffers and retry if their size caused the failure.
   1.401 +      DWORD value_size_in_wchars = to_wchar_size(value_size_);
   1.402 +      if (value_size_in_wchars + 1 > value_.size())
   1.403 +        value_.resize(value_size_in_wchars + 1, L'\0');
   1.404 +      value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
   1.405 +      name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
   1.406 +      result = ::RegEnumValue(
   1.407 +          key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
   1.408 +          reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
   1.409 +    }
   1.410 +
   1.411 +    if (result == ERROR_SUCCESS) {
   1.412 +      DCHECK_LT(to_wchar_size(value_size_), value_.size());
   1.413 +      value_[to_wchar_size(value_size_)] = L'\0';
   1.414 +      return true;
   1.415 +    }
   1.416 +  }
   1.417 +
   1.418 +  name_[0] = L'\0';
   1.419 +  value_[0] = L'\0';
   1.420 +  value_size_ = 0;
   1.421 +  return false;
   1.422 +}
   1.423 +
   1.424 +// RegistryKeyIterator --------------------------------------------------------
   1.425 +
   1.426 +RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
   1.427 +                                         const wchar_t* folder_key) {
   1.428 +  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
   1.429 +  if (result != ERROR_SUCCESS) {
   1.430 +    key_ = NULL;
   1.431 +  } else {
   1.432 +    DWORD count = 0;
   1.433 +    LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
   1.434 +                                    NULL, NULL, NULL, NULL, NULL);
   1.435 +
   1.436 +    if (result != ERROR_SUCCESS) {
   1.437 +      ::RegCloseKey(key_);
   1.438 +      key_ = NULL;
   1.439 +    } else {
   1.440 +      index_ = count - 1;
   1.441 +    }
   1.442 +  }
   1.443 +
   1.444 +  Read();
   1.445 +}
   1.446 +
   1.447 +RegistryKeyIterator::~RegistryKeyIterator() {
   1.448 +  if (key_)
   1.449 +    ::RegCloseKey(key_);
   1.450 +}
   1.451 +
   1.452 +DWORD RegistryKeyIterator::SubkeyCount() const {
   1.453 +  DWORD count = 0;
   1.454 +  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
   1.455 +                                  NULL, NULL, NULL, NULL, NULL);
   1.456 +  if (result != ERROR_SUCCESS)
   1.457 +    return 0;
   1.458 +
   1.459 +  return count;
   1.460 +}
   1.461 +
   1.462 +bool RegistryKeyIterator::Valid() const {
   1.463 +  return key_ != NULL && index_ >= 0;
   1.464 +}
   1.465 +
   1.466 +void RegistryKeyIterator::operator++() {
   1.467 +  --index_;
   1.468 +  Read();
   1.469 +}
   1.470 +
   1.471 +bool RegistryKeyIterator::Read() {
   1.472 +  if (Valid()) {
   1.473 +    DWORD ncount = arraysize(name_);
   1.474 +    FILETIME written;
   1.475 +    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
   1.476 +                            NULL, &written);
   1.477 +    if (ERROR_SUCCESS == r)
   1.478 +      return true;
   1.479 +  }
   1.480 +
   1.481 +  name_[0] = '\0';
   1.482 +  return false;
   1.483 +}
   1.484 +
   1.485 +}  // namespace win
   1.486 +}  // namespace base

mercurial