261 lines
10 KiB
C
261 lines
10 KiB
C
|
|
// Copyright 2022 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#ifndef BASE_WIN_SECURITY_DESCRIPTOR_H_
|
||
|
|
#define BASE_WIN_SECURITY_DESCRIPTOR_H_
|
||
|
|
|
||
|
|
#include <stdint.h>
|
||
|
|
|
||
|
|
#include <string>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "base/base_export.h"
|
||
|
|
#include "base/files/file_path.h"
|
||
|
|
#include "base/win/access_control_list.h"
|
||
|
|
#include "base/win/access_token.h"
|
||
|
|
#include "base/win/sid.h"
|
||
|
|
#include "base/win/windows_types.h"
|
||
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||
|
|
|
||
|
|
namespace base::win {
|
||
|
|
|
||
|
|
// Represents the type of Windows kernel object for reading/writing the security
|
||
|
|
// descriptor.
|
||
|
|
enum class SecurityObjectType {
|
||
|
|
kFile,
|
||
|
|
kRegistry,
|
||
|
|
kWindowStation,
|
||
|
|
kDesktop,
|
||
|
|
kKernel
|
||
|
|
};
|
||
|
|
|
||
|
|
// Results from the access check.
|
||
|
|
struct AccessCheckResult {
|
||
|
|
// The granted access from the check.
|
||
|
|
ACCESS_MASK granted_access;
|
||
|
|
// The access status. Set to true if the access check was successful.
|
||
|
|
bool access_status;
|
||
|
|
};
|
||
|
|
|
||
|
|
// This class is used to hold and modify a Windows security descriptor.
|
||
|
|
class BASE_EXPORT SecurityDescriptor {
|
||
|
|
public:
|
||
|
|
class BASE_EXPORT SelfRelative {
|
||
|
|
public:
|
||
|
|
friend SecurityDescriptor;
|
||
|
|
|
||
|
|
SelfRelative(const SelfRelative&);
|
||
|
|
~SelfRelative();
|
||
|
|
|
||
|
|
size_t size() const { return sd_.size(); }
|
||
|
|
PSECURITY_DESCRIPTOR get() const {
|
||
|
|
return const_cast<uint8_t*>(sd_.data());
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
explicit SelfRelative(std::vector<uint8_t>&& sd);
|
||
|
|
|
||
|
|
std::vector<uint8_t> sd_;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Create from an existing security descriptor pointer.
|
||
|
|
// |security_descriptor| The pointer to a self-relative or absolute security
|
||
|
|
// descriptor. This method will copy all security descriptor data.
|
||
|
|
static absl::optional<SecurityDescriptor> FromPointer(
|
||
|
|
PSECURITY_DESCRIPTOR security_descriptor);
|
||
|
|
|
||
|
|
// Create from the security descriptor of an existing file.
|
||
|
|
// |path| the path to the file.
|
||
|
|
// |security_info| indicates what parts to read.
|
||
|
|
static absl::optional<SecurityDescriptor> FromFile(
|
||
|
|
const base::FilePath& path,
|
||
|
|
SECURITY_INFORMATION security_info);
|
||
|
|
|
||
|
|
// Create from the security descriptor of a named Windows object.
|
||
|
|
// |name| the name of the object using the format specified for the
|
||
|
|
// GetNamedSecurityInfo API.
|
||
|
|
// |object_type| specifies the type of object the name represents.
|
||
|
|
// |security_info| indicates what parts to read.
|
||
|
|
static absl::optional<SecurityDescriptor> FromName(
|
||
|
|
const std::wstring& name,
|
||
|
|
SecurityObjectType object_type,
|
||
|
|
SECURITY_INFORMATION security_info);
|
||
|
|
|
||
|
|
// Create from the security descriptor of a kernel object.
|
||
|
|
// |handle| the object handle. It must have READ_CONTROL access.
|
||
|
|
// |object_type| specifies the type of object the handle represents.
|
||
|
|
// |security_info| indicates what parts to read.
|
||
|
|
static absl::optional<SecurityDescriptor> FromHandle(
|
||
|
|
HANDLE handle,
|
||
|
|
SecurityObjectType object_type,
|
||
|
|
SECURITY_INFORMATION security_info);
|
||
|
|
|
||
|
|
// Create from a string representation of a security descriptor.
|
||
|
|
// |sddl| the security descriptor in SDDL format.
|
||
|
|
static absl::optional<SecurityDescriptor> FromSddl(const std::wstring& sddl);
|
||
|
|
|
||
|
|
SecurityDescriptor();
|
||
|
|
SecurityDescriptor(const SecurityDescriptor&) = delete;
|
||
|
|
SecurityDescriptor& operator=(const SecurityDescriptor&) = delete;
|
||
|
|
SecurityDescriptor(SecurityDescriptor&&);
|
||
|
|
SecurityDescriptor& operator=(SecurityDescriptor&&);
|
||
|
|
~SecurityDescriptor();
|
||
|
|
|
||
|
|
// Write the security descriptor to a file.
|
||
|
|
// |path| specifies the path to the file.
|
||
|
|
// |security_info| indicates what parts to write.
|
||
|
|
bool WriteToFile(const base::FilePath& path,
|
||
|
|
SECURITY_INFORMATION security_info) const;
|
||
|
|
|
||
|
|
// Write the security descriptor to a named kernel object.
|
||
|
|
// |name| the name of the object using the format specified for the
|
||
|
|
// SetNamedSecurityInfo API.
|
||
|
|
// |object_type| specifies the type of object name represents.
|
||
|
|
// |security_info| indicates what parts to write.
|
||
|
|
bool WriteToName(const std::wstring& name,
|
||
|
|
SecurityObjectType object_type,
|
||
|
|
SECURITY_INFORMATION security_info) const;
|
||
|
|
|
||
|
|
// Write the SecurityDescriptor to a kernel object.
|
||
|
|
// |handle| the handle to the object. Must have WRITE_DAC and/or WRITE_OWNER
|
||
|
|
// access depending of the parts specified with |security_info|. |object_type|
|
||
|
|
// specifies the type of object the handle represents. Use kKernel for
|
||
|
|
// undefined types. |security_info| indicates what parts to write.
|
||
|
|
bool WriteToHandle(HANDLE handle,
|
||
|
|
SecurityObjectType object_type,
|
||
|
|
SECURITY_INFORMATION security_info) const;
|
||
|
|
|
||
|
|
// Convert the SecurityDescriptor to an SDDL string.
|
||
|
|
// |security_info| determines what parts are included in the string.
|
||
|
|
absl::optional<std::wstring> ToSddl(SECURITY_INFORMATION security_info) const;
|
||
|
|
|
||
|
|
// Create an reference to the absolute security descriptor of this instance.
|
||
|
|
// |sd| the SECURITY_DESCRIPTOR structure to populate. This is is only valid
|
||
|
|
// as long as this object is in scope and not modified.
|
||
|
|
void ToAbsolute(SECURITY_DESCRIPTOR& sd) const;
|
||
|
|
|
||
|
|
// Create a self-relative security descriptor in a single buffer.
|
||
|
|
absl::optional<SelfRelative> ToSelfRelative() const;
|
||
|
|
|
||
|
|
// Make a clone of the current security descriptor object.
|
||
|
|
SecurityDescriptor Clone() const;
|
||
|
|
|
||
|
|
// Set the mandatory label in the security descriptor. Note that calling
|
||
|
|
// this will completely replace the SACL.
|
||
|
|
// |integrity_level| is the integrity level for the label.
|
||
|
|
// |inheritance| specify the flags for inheritance.
|
||
|
|
// |mandatory_policy| is the policy, e.g. SYSTEM_MANDATORY_LABEL_NO_WRITE_UP.
|
||
|
|
bool SetMandatoryLabel(DWORD integrity_level,
|
||
|
|
DWORD inheritance,
|
||
|
|
DWORD mandatory_policy);
|
||
|
|
|
||
|
|
// Set one or more entry in the DACL.
|
||
|
|
// |entries| the list of entries to set in the ACL.
|
||
|
|
// Returns true if successful, false on error, with the Win32 last error set.
|
||
|
|
// If DACL is not present a NULL ACL will be added first.
|
||
|
|
bool SetDaclEntries(const std::vector<ExplicitAccessEntry>& entries);
|
||
|
|
|
||
|
|
// Set one entry in the DACL.
|
||
|
|
// |sid| the SID for the entry.
|
||
|
|
// |mode| the operation to perform on the ACL, e.g. grant access.
|
||
|
|
// |access_mask| the entries access mask.
|
||
|
|
// |inheritance| inheritance flags.
|
||
|
|
// Returns true if successful, false on
|
||
|
|
// error, with the Win32 last error set.
|
||
|
|
// If DACL is not present a NULL ACL will be added first.
|
||
|
|
bool SetDaclEntry(const Sid& sid,
|
||
|
|
SecurityAccessMode mode,
|
||
|
|
DWORD access_mask,
|
||
|
|
DWORD inheritance);
|
||
|
|
|
||
|
|
// Set one entry in the DACL.
|
||
|
|
// |known_sid| the known SID for the entry.
|
||
|
|
// |mode| the operation to perform on the ACL, e.g. grant access.
|
||
|
|
// |access_mask| the entries access mask.
|
||
|
|
// |inheritance| inheritance flags.
|
||
|
|
// Returns true if successful, false on
|
||
|
|
// error, with the Win32 last error set.
|
||
|
|
// If DACL is not present a NULL ACL will be added first.
|
||
|
|
bool SetDaclEntry(WellKnownSid known_sid,
|
||
|
|
SecurityAccessMode mode,
|
||
|
|
DWORD access_mask,
|
||
|
|
DWORD inheritance);
|
||
|
|
|
||
|
|
// Perform an access check for this security descriptor.
|
||
|
|
// |token| specify the impersonation token to check against.
|
||
|
|
// |desired_access| the access desired for the check.
|
||
|
|
// |generic_mapping| the generic mapping for the access check.
|
||
|
|
// Returns the result of the access check. If an empty result is returned the
|
||
|
|
// call to the AccessCheck API failed.
|
||
|
|
absl::optional<AccessCheckResult> AccessCheck(
|
||
|
|
const AccessToken& token,
|
||
|
|
ACCESS_MASK desired_access,
|
||
|
|
const GENERIC_MAPPING& generic_mapping);
|
||
|
|
|
||
|
|
// Perform an access check for this security descriptor.
|
||
|
|
// |token| specify the impersonation token to check against.
|
||
|
|
// |desired_access| the access desired for the check.
|
||
|
|
// |object_type| the object type to determine how to map generic rights. Note
|
||
|
|
// that you can't use kKernel as that doesn't reflect a specific kernel object
|
||
|
|
// type, an empty return will be return if this is used. If you need to access
|
||
|
|
// check an unsupported type use the overload which accepts a manually
|
||
|
|
// configured GENERIC_MAPPING.
|
||
|
|
// Returns the result of the access check. If an empty result is returned the
|
||
|
|
// call to the AccessCheck API failed.
|
||
|
|
absl::optional<AccessCheckResult> AccessCheck(const AccessToken& token,
|
||
|
|
ACCESS_MASK desired_access,
|
||
|
|
SecurityObjectType object_type);
|
||
|
|
|
||
|
|
// Get, set and clear owner member.
|
||
|
|
const absl::optional<Sid>& owner() const { return owner_; }
|
||
|
|
void set_owner(const Sid& owner) { owner_ = owner.Clone(); }
|
||
|
|
void clear_owner() { owner_ = absl::nullopt; }
|
||
|
|
|
||
|
|
// Get, set and clear group member.
|
||
|
|
const absl::optional<Sid>& group() const { return group_; }
|
||
|
|
void set_group(const Sid& group) { group_ = group.Clone(); }
|
||
|
|
void clear_group() { group_ = absl::nullopt; }
|
||
|
|
|
||
|
|
// Get, set and clear dacl member.
|
||
|
|
const absl::optional<AccessControlList>& dacl() const { return dacl_; }
|
||
|
|
void set_dacl(const AccessControlList& dacl) { dacl_ = dacl.Clone(); }
|
||
|
|
void clear_dacl() { dacl_ = absl::nullopt; }
|
||
|
|
|
||
|
|
// Get and set dacl_protected member.
|
||
|
|
bool dacl_protected() const { return dacl_protected_; }
|
||
|
|
void set_dacl_protected(bool dacl_protected) {
|
||
|
|
dacl_protected_ = dacl_protected;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get, set and clear sacl member.
|
||
|
|
const absl::optional<AccessControlList>& sacl() const { return sacl_; }
|
||
|
|
void set_sacl(const AccessControlList& sacl) { sacl_ = sacl.Clone(); }
|
||
|
|
void clear_sacl() { sacl_ = absl::nullopt; }
|
||
|
|
|
||
|
|
// Get and set sacl_protected member.
|
||
|
|
bool sacl_protected() const { return sacl_protected_; }
|
||
|
|
void set_sacl_protected(bool sacl_protected) {
|
||
|
|
sacl_protected_ = sacl_protected;
|
||
|
|
}
|
||
|
|
|
||
|
|
private:
|
||
|
|
SecurityDescriptor(absl::optional<Sid>&& owner,
|
||
|
|
absl::optional<Sid>&& group,
|
||
|
|
absl::optional<AccessControlList>&& dacl,
|
||
|
|
bool dacl_protected,
|
||
|
|
absl::optional<AccessControlList>&& sacl,
|
||
|
|
bool sacl_protected);
|
||
|
|
|
||
|
|
absl::optional<Sid> owner_;
|
||
|
|
absl::optional<Sid> group_;
|
||
|
|
absl::optional<AccessControlList> dacl_;
|
||
|
|
bool dacl_protected_ = false;
|
||
|
|
absl::optional<AccessControlList> sacl_;
|
||
|
|
bool sacl_protected_ = false;
|
||
|
|
};
|
||
|
|
|
||
|
|
} // namespace base::win
|
||
|
|
|
||
|
|
#endif // BASE_WIN_SECURITY_DESCRIPTOR_H_
|