blob: fa3d28c75e910ce760bd28b1c284bf999172df6b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/chrome_cleaner/interfaces/typemaps/windows_handle_mojom_traits.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace mojo {
using chrome_cleaner::mojom::SpecialWindowsHandle;
using chrome_cleaner::mojom::WindowsHandleDataView;
namespace {
bool ToSpecialHandle(HANDLE handle, SpecialWindowsHandle* out_special_handle) {
DCHECK(out_special_handle);
if (handle == nullptr) {
*out_special_handle = SpecialWindowsHandle::NULL_HANDLE;
return true;
}
if (handle == INVALID_HANDLE_VALUE) {
*out_special_handle = SpecialWindowsHandle::INVALID_HANDLE;
return true;
}
if (handle == HKEY_CLASSES_ROOT) {
*out_special_handle = SpecialWindowsHandle::CLASSES_ROOT;
return true;
}
if (handle == HKEY_CURRENT_CONFIG) {
*out_special_handle = SpecialWindowsHandle::CURRENT_CONFIG;
return true;
}
if (handle == HKEY_CURRENT_USER) {
*out_special_handle = SpecialWindowsHandle::CURRENT_USER;
return true;
}
if (handle == HKEY_LOCAL_MACHINE) {
*out_special_handle = SpecialWindowsHandle::LOCAL_MACHINE;
return true;
}
if (handle == HKEY_USERS) {
*out_special_handle = SpecialWindowsHandle::USERS;
return true;
}
return false;
}
bool IsSpecialHandle(HANDLE handle) {
SpecialWindowsHandle unused;
return ToSpecialHandle(handle, &unused);
}
bool FromSpecialHandle(SpecialWindowsHandle special_handle,
HANDLE* out_handle) {
DCHECK(out_handle);
switch (special_handle) {
case SpecialWindowsHandle::NULL_HANDLE:
*out_handle = nullptr;
return true;
case SpecialWindowsHandle::INVALID_HANDLE:
*out_handle = INVALID_HANDLE_VALUE;
return true;
case SpecialWindowsHandle::CLASSES_ROOT:
*out_handle = HKEY_CLASSES_ROOT;
return true;
case SpecialWindowsHandle::CURRENT_CONFIG:
*out_handle = HKEY_CURRENT_CONFIG;
return true;
case SpecialWindowsHandle::CURRENT_USER:
*out_handle = HKEY_CURRENT_USER;
return true;
case SpecialWindowsHandle::LOCAL_MACHINE:
*out_handle = HKEY_LOCAL_MACHINE;
return true;
case SpecialWindowsHandle::USERS:
*out_handle = HKEY_USERS;
return true;
default:
return false;
}
}
// Duplicates a handle in the current process. Returns INVALID_HANDLE_VALUE on
// error.
HANDLE DuplicateWindowsHandle(HANDLE source_handle) {
const HANDLE current_process = ::GetCurrentProcess();
HANDLE new_handle = INVALID_HANDLE_VALUE;
if (::DuplicateHandle(current_process, source_handle, current_process,
&new_handle, 0, FALSE, DUPLICATE_SAME_ACCESS) == 0) {
PLOG(ERROR) << "Error duplicating handle " << source_handle;
return INVALID_HANDLE_VALUE;
}
return new_handle;
}
} // namespace
// static
mojo::ScopedHandle UnionTraits<WindowsHandleDataView, HANDLE>::raw_handle(
HANDLE handle) {
DCHECK_EQ(WindowsHandleDataView::Tag::RAW_HANDLE, GetTag(handle));
if (IsSpecialHandle(handle)) {
CHECK(false) << "Accessor raw_handle() should only be called when the "
"union's tag is RAW_HANDLE.";
return mojo::ScopedHandle();
}
HANDLE duplicate_handle = DuplicateWindowsHandle(handle);
return WrapPlatformFile(duplicate_handle);
}
// static
SpecialWindowsHandle UnionTraits<WindowsHandleDataView, HANDLE>::special_handle(
HANDLE handle) {
DCHECK_EQ(WindowsHandleDataView::Tag::SPECIAL_HANDLE, GetTag(handle));
SpecialWindowsHandle special_handle;
if (ToSpecialHandle(handle, &special_handle))
return special_handle;
CHECK(false) << "Accessor special_handle() should only be called when the "
"union's tag is SPECIAL_HANDLE.";
return SpecialWindowsHandle::INVALID_HANDLE;
}
// static
WindowsHandleDataView::Tag UnionTraits<WindowsHandleDataView, HANDLE>::GetTag(
HANDLE handle) {
return IsSpecialHandle(handle) ? WindowsHandleDataView::Tag::SPECIAL_HANDLE
: WindowsHandleDataView::Tag::RAW_HANDLE;
}
// static
bool UnionTraits<WindowsHandleDataView, HANDLE>::Read(
WindowsHandleDataView windows_handle_view,
HANDLE* out) {
if (windows_handle_view.is_raw_handle()) {
HANDLE handle;
MojoResult mojo_result =
UnwrapPlatformFile(windows_handle_view.TakeRawHandle(), &handle);
if (mojo_result != MOJO_RESULT_OK) {
*out = INVALID_HANDLE_VALUE;
return false;
}
*out = handle;
return true;
}
HANDLE special_handle;
if (FromSpecialHandle(windows_handle_view.special_handle(),
&special_handle)) {
*out = special_handle;
return true;
}
return false;
}
} // namespace mojo