Merge branch 'dev/jweyer/remote_management_updates' into release/6.0.0

This commit is contained in:
Jared Weyer 2023-06-20 11:38:08 -07:00
Родитель 2be28656eb cca16fce1d
Коммит f022984b98
9 изменённых файлов: 1237 добавлений и 147 удалений

Просмотреть файл

@ -5,6 +5,15 @@
### Removed
- Removed the `plist` resource
### Fixed
- Fixed issues with ARD not working on macOS Monterey.
### Added
- Added additional functionality to the [remote_management](resources/remote_management.rb) resource.
- You can now specify the users to whose privileges will be configured.
- You can now specify the privileges to bestow upon the given users.
- You can now set the computer info fields; this is helpful for stratifying computers within ARD.
## [5.0.4] - 2023-01-31
### Added

Просмотреть файл

@ -1,50 +1,63 @@
remote_management
===
Use the **remote_management** resource to manage the "Remote Management" settings, found in System
Preferences > Sharing > Remote Management. Under the hood, the [**remote_management**](https://github.com/Microsoft/macos-cookbook/blob/master/resources/remote_management.rb) resource
executes the `kickstart` command, located in ARDAgent.app (one of macOS' "core services").
Use the **remote_management** resource to manage the "Remote Management" settings in System Preferences > Sharing > Remote Management. Under the hood, the [remote_management](../resources/remote_management.rb) resource utilizes the [kickstart](https://ss64.com/osx/kickstart.html) script.
Syntax
------
The **remote_management** resource block declares a basic description of the command configuration
and an action executed. For example:
```ruby
remote_management 'enable remote management' do
action :enable
remote_management 'configure remote management' do
users [String, Array]
privileges [String, Array]
computer_info [String, Array]
end
```
where
Properties
-------
- `:enable` activates remote management and configures full privileges for all users on the system.
- `:disable` deactivates the remote management agent and prevents it from activating at boot time.
The default `:enable` action is equivalent to configuring the following
**System Preferences > Sharing** settings:
![Sharing Preferences](sharing_preferences.png)
The full syntax for all of the properties that are available to the **remote_management**
resource is:
```ruby
remote_management 'description' do
action Symbol # defaults to [:enable] if not specified
end
```
* `users`
* **Description:** the user(s) whoose ARD privileges will be configured.
* **Usage:** a single user can be specified in the form of a string, or multiple users can be specified as an array of strings. Specifying 'all' is a special case; all local users will be configured.
* **Default:** `'all'`
* Privileges will be configured for all local users.
* **Constraints:** specified users must exist on the system.
<br></br>
* `privileges`
* **Description:** the desired privileges to bestow upon the given user(s).
**Usage:** a single privilege can be specified in the form of a string, or multiple privileges can be specified as an array of strings.
* **Default:** `'all'`
* **Constraints:** the list of optional privileges bellow
* `all` → grant all privileges (default)
* `none` → disable all privileges for the specified user
* `DeleteFiles` → delete files
* `TextMessages` → send a text message
* `OpenQuitApp` → open and quit applications
* `GenerateReport` → generate reports
* `RestartShutDown` → restart *and/or* shutdown
* `SendFile` → send *and/or* retrieve files
* `ChangeSetting` → change system settings
* `ShowObserve` → show the client when being observed or controlled
* `ControlObserve` → control AND observe (unless ObserveOnly is also specified)
* `ObserveOnly` → modify ControlObserve option to allow Observe mode only
<br></br>
* `computer_info`
* **Description:** Info fields; helpful for stratifying computers in the ARD client app.
* **Usage** a single info field can be added as a string, or multiple info fields can be added as an array of strings.
* **Default:** `[]`
* No info fields will be added.
* **Constraints:** there is a maximum of four info fields allowed.
Actions
-------
This resource has the following actions:
* `enable`
* **Description:** activate remote management and configure full privileges for all users on the system.
* **GUI Equivalent:** activating with the privileges property set to 'all' is equivalent to the following:
![Sharing Preferences](sharing_preferences.png)
`:enable`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Activate remote management and configure full privileges for all users on the system.
`:disable`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Deactivate the remote management agent and prevent it from activating at boot time.
* `disable`
* **Description:** deactivate the remote management agent and prevent it from activating at boot time.

Просмотреть файл

@ -1,35 +1,361 @@
include Chef::Mixin::ShellOut
module MacOS
class RemoteManagement
class << self
def current_mask(users)
using_global_privileges? ? Privileges::Value.new(value: global_settings_privilege_value).to_mask : current_user_masks(users).first
end
def current_user_masks(users)
users = all_local_users if users.include?('all')
users.flatten.map { |user| Privileges::Mask.new(mask: individual_settings.fetch(user)) }
end
def current_users_have_identical_masks?(users)
return true if using_global_privileges?
current_user_masks(users).map(&:to_i).uniq.one?
end
def current_users_configured?(users)
return true if using_global_privileges?
users = all_local_users if users.include?('all')
(users - individual_settings.keys).empty?
end
def current_computer_info
computer_info_hash.select { |k, _v| k.match?(Regexp.new('Text')) }.values.reject(&:empty?)
end
def activated?
::File.exist? '/Library/Application Support/Apple/Remote Desktop/RemoteManagement.launchd'
if Chef::Version.new(Chef.node['platform_version']) >= Chef::Version.new('12.0.0')
agent_running? && TCC::State.enabled?
else
agent_running?
end
end
def configured_for_all_users_and_privileges?
RemoteManagement.plist_content.include?('ARD_AllLocalUsers = true') &&
RemoteManagement.plist_content.include?(full_privileges)
def kickstart
'/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart'
end
def plist_content
shell_out('/usr/libexec/PlistBuddy -c Print /Library/Preferences/com.apple.RemoteManagement.plist').stdout
private
def agent_running?
::File.exist?('/Library/Application Support/Apple/Remote Desktop/RemoteManagement.launchd')
end
def full_privileges
text_messages = 1 << 0
control_observe = 1 << 1
send_files = 1 << 2
delete_files = 1 << 3
generate_reports = 1 << 4
open_quit_apps = 1 << 5
change_settings = 1 << 6
restart_shutdown = 1 << 7
show_observe = 1 << 30
def using_global_privileges?
using_global_settings? && !global_settings_privilege_value.nil?
end
(text_messages | control_observe | send_files |
delete_files | generate_reports | open_quit_apps |
change_settings | restart_shutdown | show_observe).to_s
def using_global_settings?
global_settings['ARD_AllLocalUsers'] || false
end
def global_settings_privilege_value
global_settings['ARD_AllLocalUsersPrivs']
end
def global_settings
::Plist.parse_xml(global_settings_xml) || {}
end
def global_settings_xml
shell_out!('/usr/bin/plutil -convert xml1 /Library/Preferences/com.apple.RemoteManagement.plist -o -').stdout
rescue Mixlib::ShellOut::ShellCommandFailed => e
e.message.match?(Regexp.new('file does not exist')) ? '' : raise
end
def individual_settings
dscl_naprivs.scan(/(?<user>^\S+)\s+(?<mask>-\d+)/).to_h.transform_values(&:to_i)
end
def dscl_naprivs
shell_out!('/usr/bin/dscl . -list /Users dsAttrTypeNative:naprivs').stdout
end
def computer_info_xml
shell_out!('/usr/bin/plutil -convert xml1 /Library/Preferences/com.apple.RemoteDesktop.plist -o -').stdout
rescue Mixlib::ShellOut::ShellCommandFailed => e
e.message.match?(Regexp.new('file does not exist')) ? '' : raise
end
def computer_info_hash
::Plist.parse_xml(computer_info_xml) || {}
end
def all_local_users
system_users = %w(root nobody daemon unknown smmsp www mysql sshd lp sendmail postfix eppc qtss cyrus mailman)
(all_users.reject { |user| user.match?(/^_\w+$/) } - system_users)
end
def all_users
shell_out!('/usr/bin/dscl . -list /Users').stdout.split
end
end
module TCC
module State
class << self
def enabled?
post_event_service_enabled? && screencapture_service_enabled?
end
def post_event_service_enabled?
hash['postEvent'] || false
end
def screencapture_service_enabled?
hash['screenCapture'] || false
end
private
def hash
::Plist.parse_xml(xml) || {}
end
def xml
shell_out!('sudo', '/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Support/tccstate').stdout
end
end
end
module DB
class << self
def correct_privileges?
screensharing_client_authorized_for_post_event_service? && screensharing_client_authorized_for_screencapture_service?
end
def screensharing_client_authorized_for_post_event_service?
screensharing_client_auth_value_for_post_event_service == 2
end
def screensharing_client_authorized_for_screencapture_service?
screensharing_client_auth_value_for_screencapture_service == 2
end
private
def path
'/Library/Application Support/com.apple.TCC/TCC.db'
end
def screensharing_client_auth_value_for_post_event_service
shell_out!('/usr/bin/sqlite3', path, "SELECT auth_value FROM access WHERE service='kTCCServicePostEvent' AND client='com.apple.screensharing.agent';").stdout.chomp.to_i
end
def screensharing_client_auth_value_for_screencapture_service
shell_out!('/usr/bin/sqlite3', path, "SELECT auth_value FROM access WHERE service='kTCCServiceScreenCapture' AND client='com.apple.screensharing.agent';").stdout.chomp.to_i
end
end
end
module SIP
class << self
def disabled?
system_profiler_software_info.match?(Regexp.new('System Integrity Protection: Disabled'))
end
private
def system_profiler_software_info
shell_out!('/usr/sbin/system_profiler', 'SPSoftwareDataType').stdout
end
end
end
end
module Privileges
class << self
def valid?(*privileges)
list_invalid([privileges].flatten).empty?
end
def validate!(*privileges)
raise(Exceptions::Privileges::ValidationError, list_invalid(privileges)) unless valid?(privileges)
rescue Exceptions::Privileges::ValidationError => e # raise property validation error if called from property coercion block
called_by_chef_property_coerce? ? raise(Chef::Exceptions::ValidationFailed, e.message) : raise
end
def format(*privileges)
[privileges].flatten.map do |privilege|
privilege.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
.gsub(/([a-z])([A-Z])/, '\1_\2')
.gsub(/(\s|-|_{2,})/, '_')
.upcase.to_sym
end
end
private
def called_by_chef_property_coerce?
caller_locations.any? { |backtrace_location| ::File.basename(backtrace_location.path, '.rb') == 'property' && backtrace_location.label == 'coerce' }
end
def list_invalid(privileges)
privileges - BitMask.constants(false)
end
end
class Value
extend Forwardable
def_delegators :@value, :to_i, :zero?, :==, :+, :-, :|, :&, :^
def initialize(value: nil, privileges: nil)
if value
raise(Exceptions::Privileges::Value::ValidationError, value) unless valid?(value)
@value = value
elsif privileges
privileges = Privileges.format(privileges)
Privileges.validate!(privileges)
@value = from_privileges(privileges)
else
raise(Exceptions::Privileges::Value::InvalidArgument, value, privileges)
end
end
def valid?(value)
return true if value == BitMask::NONE
(~(BitMask::ALL | BitMask::OBSERVE_ONLY) & value).zero?
end
def from_privileges(privileges)
return BitMask::ALL if privileges.include?(:ALL)
return 0 if privileges.include?(:NONE)
privileges.map { |priv| BitMask.const_get(priv.upcase) }.reduce(&:|)
end
def to_mask
Mask.new(mask: (@value - BitMask::NONE))
end
def to_a
return ['none'] if @value.zero?
return ['all'] if @value == BitMask::ALL
unformated_priv_strings = BitMask.constants(false).reject { |const| (BitMask.const_get(const) & @value).zero? || const == :ALL }.map(&:to_s).map(&:downcase)
unformated_priv_strings.map { |priv| priv.to_s.split('_').map(&:capitalize).join }
end
end
class Mask
extend Forwardable
def_delegators :@mask, :to_i, :zero?, :==, :+, :-, :|, :&, :^
def initialize(mask: nil, privileges: nil)
if mask
raise(Exceptions::Privileges::Value::ValidationError, mask) unless valid?(mask)
@mask = mask
elsif privileges
privileges = Privileges.format(privileges)
Privileges.validate!(privileges)
@mask = from_privileges(privileges)
else
raise(Exceptions::Privileges::Value::InvalidArgument, mask, privileges)
end
end
def valid?(mask)
return true if mask.zero?
(~(BitMask::ALL | BitMask::OBSERVE_ONLY) & (mask + BitMask::NONE)).zero?
end
def from_privileges(privileges)
return -BitMask::NONE if privileges.include?(:NONE)
return (BitMask::ALL - BitMask::NONE) if privileges.include?(:ALL)
(privileges.map { |priv| BitMask.const_get(priv.upcase) }.reduce(&:|) - BitMask::NONE)
end
def to_value
Value.new(value: (@mask + BitMask::NONE))
end
def to_a
return ['none'] if (@mask + BitMask::NONE).zero?
return ['all'] if @mask + BitMask::NONE == BitMask::ALL
unformated_priv_strings = BitMask.constants(false).reject { |const| (BitMask.const_get(const) & (@mask + BitMask::NONE)).zero? || const == :ALL }
unformated_priv_strings.map { |priv| priv.to_s.split('_').map(&:capitalize).join }
end
# For Chef logging
# Chef logs without this overide -> 'set privileges to MacOS::RemoteManagement::Privileges::Mask:0x00007fe032914c08 @mask=-2147483641> (was #<MacOS::RemoteManagement::Privileges::Mask:0x00007fe0329d7f78 @mask=-2147483645>)'
# Chef logs with this override -> 'set privileges to ["TextMessages", "ControlObserve"] (was ["TextMessages", "ControlObserve", "SendFiles"])'
def inspect
to_a.to_s
end
end
end
module BitMask
TEXT_MESSAGES = 0b00000000000000000000000000000001
CONTROL_OBSERVE = 0b00000000000000000000000000000010
SEND_FILES = 0b00000000000000000000000000000100
DELETE_FILES = 0b00000000000000000000000000001000
GENERATE_REPORTS = 0b00000000000000000000000000010000
OPEN_QUIT_APPS = 0b00000000000000000000000000100000
CHANGE_SETTINGS = 0b00000000000000000000000001000000
RESTART_SHUT_DOWN = 0b00000000000000000000000010000000
OBSERVE_ONLY = 0b00000000000000000000000100000000
SHOW_OBSERVE = 0b01000000000000000000000000000000
ALL = 0b01000000000000000000000011111111
NONE = 0b10000000000000000000000000000000
end
module Exceptions
class TCCError < RuntimeError
def initialize
super(message)
end
def message
String.new.tap do |message|
message << "TCC does not have the correct authorizations for ARD to work!\n"
message << "\t* Screensharing client not authorized for post event service\n" unless RemoteManagement::TCC::DB.screensharing_client_authorized_for_post_event_service?
message << "\t* Screensharing client not authorized for screencapture service\n" unless RemoteManagement::TCC::DB.screensharing_client_authorized_for_screencapture_service?
end
end
end
class SIPEnabled < RuntimeError
def initialize
super('SIP is enabled! Please disable before using this resource')
end
end
module Privileges
class ValidationError < ArgumentError
def initialize(invalid_privileges)
super("#{invalid_privileges.map(&:to_s).map(&:downcase)} are invalid privilege(s)! Valid privileges include: #{RemoteManagement::BitMask.constants(false).map(&:downcase).map(&:to_s)}")
end
end
module Value
class ValidationError < ArgumentError
def initialize(value)
super("#{value.inspect} is an invalid value!")
end
end
class InvalidArgument < ArgumentError
def initialize(*args)
super("wrong number of arguments (given #{args.compact.size} expected 1)")
end
end
end
module Mask
class ValidationError < ArgumentError
def initialize(mask)
super("#{mask.inspect} is an invalid mask!")
end
class InvalidArgument < ArgumentError
def initialize(*args)
super("wrong number of arguments (given #{args.compact.size} expected 1)")
end
end
end
end
end
end
end

Просмотреть файл

@ -3,24 +3,85 @@ unified_mode true
provides :remote_management
default_action :enable
kickstart = '/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart'
property :users,
[String, Array],
default: 'all',
description: 'The user(s) whose ARD privileges will be configured.',
coerce: ->(p) { [p].flatten }
property :privileges,
[String, Array, RemoteManagement::Privileges::Mask],
default: 'all',
description: 'The desired privileges to bestow upon the given users.',
coerce: ->(p) { p.is_a?(RemoteManagement::Privileges::Mask) ? p : RemoteManagement::Privileges::Mask.new(privileges: p) }
property :computer_info,
[String, Array],
default: [],
description: 'Info fields; helpful for stratifying computers in ARD client app.',
coerce: ->(p) { p.is_a?(Array) ? p.compact.map(&:to_s) : [p] },
callbacks: { 'has too many elements; computer info excepts up to four info fields' => ->(p) { (p.is_a?(Array) && p.size < 4) } }
load_current_value do |desired|
current_value_does_not_exist! unless RemoteManagement.activated? && RemoteManagement.current_users_configured?(desired.users) && RemoteManagement.current_users_have_identical_masks?(desired.users)
privileges RemoteManagement.current_mask(desired.users)
computer_info RemoteManagement.current_computer_info
end
# TODO; the enable action should be decoupled from configuration; configure action should be added; default action should be [:configure, :enable]
action :enable do
execute "#{kickstart} -activate" do
not_if { RemoteManagement.activated? }
end
converge_if_changed(:privileges, :computer_info) do
raise(RemoteManagement::Exceptions::SIPEnabled) unless RemoteManagement::TCC::SIP.disabled?
raise(RemoteManagement::Exceptions::TCCError) unless RemoteManagement::TCC::DB.correct_privileges?
execute "#{kickstart} -configure -allowAccessFor -allUsers -access -on -privs -all" do
not_if { RemoteManagement.configured_for_all_users_and_privileges? }
execute 'restart the TCC daemon' do
command 'sudo pkill -9 tccd'
only_if { platform_version >= Chef::Version.new('12.0.0') }
not_if { RemoteManagement::TCC::State.enabled? }
end
converge_if_changed(:privileges) do
if new_resource.users.include?('all')
converge_by('setting privileges for all users') do
privs_array = new_resource.privileges.to_a.map { |priv| priv.prepend('-') }
execute 'set privileges for all users' do
command [RemoteManagement.kickstart, '-configure', '-allowAccessFor', '-allUsers', '-access', '-on', '-privs', privs_array].flatten
end
end
else
converge_by("setting privileges for #{new_resource.users.join(', ')}") do
privs_array = new_resource.privileges.to_a.map { |priv| priv.prepend('-') }
execute 'set up Remote Management to only grant access to users with privileges' do
command [RemoteManagement.kickstart, '-configure', '-allowAccessFor', '-specifiedUsers']
end
execute "set privileges for #{new_resource.users.join(', ')}" do
command [RemoteManagement.kickstart, '-configure', '-access', '-on', '-privs', privs_array, '-users', new_resource.users].flatten
end
end
end
end
converge_if_changed(:computer_info) do
new_resource.computer_info.each_with_index do |info, i|
execute "set computer info field #{i + 1}" do
command [RemoteManagement.kickstart, '-configure', '-computerinfo', "-set#{i + 1}", "-#{i + 1}", info]
end
end
end
execute 'activate the Remote Management service and restart the agent' do
command [RemoteManagement.kickstart, '-activate', '-restart', '-agent']
end
end
end
action :disable do
execute "#{kickstart} -deactivate" do
only_if { RemoteManagement.activated? }
end
execute "#{kickstart} -stop" do
execute 'stop the Remote Management service and deactivate it so it will not start after the next restart' do
command [RemoteManagement.kickstart, '-deactivate', '-stop']
only_if { RemoteManagement.activated? }
end
end

Просмотреть файл

@ -0,0 +1,83 @@
unified_mode true
provides :remote_management
default_action :enable
property :users,
[String, Array],
default: 'all',
description: 'The user(s) whoose ARD privileges will be configured.',
coerce: ->(p) { [p].flatten }
property :privileges,
[String, Array, Integer],
default: 'all',
description: 'The desired privileges to bestow upon the given users.',
coerce: ->(p) { p.is_a?(Integer) ? p : RemoteManagement::BitMask.mask_from_privileges(p) },
callbacks: { 'is invalid. See https://ss64.com/osx/kickstart.html for valid privileges' => ->(p) { RemoteManagement::BitMask.valid_mask?(p) } }
property :computer_info,
[String, Array],
default: [],
description: 'Info fields; helpful for stratifing computers in ARD client app.',
coerce: ->(p) { p.compact.map(&:to_s) },
callbacks: { 'has too many elements; computer info excepts up to four info fields' => ->(p) { (p.is_a?(Array) && p.size < 4) } }
load_current_value do |desired|
current_value_does_not_exist! unless RemoteManagement.activated?
privileges RemoteManagement.current_mask(desired.users)
computer_info RemoteManagement.current_computer_info
end
# TODO; the enable action should be decoupled from configuration; configure action should be added; default action should be [:configure, :enable]
action :enable do
converge_if_changed(:privileges, :computer_info) do
raise(RemoteManagement::Exceptions::TCCError) unless RemoteManagement::TCC::DB.correct_privileges?
execute 'restart the TCC daemon' do
command 'sudo pkill -9 tccd'
only_if { platform_version >= Chef::Version.new('12.0.0') }
not_if { RemoteManagement::TCC::State.enabled? }
end
converge_if_changed(:privileges) do
if new_resource.users.include?('all')
converge_by('setting privileges for all users') do
execute 'set privileges for all users' do
command [RemoteManagement.kickstart, '-configure', '-allowAccessFor', '-allUsers', '-access', '-on', '-privs', '-mask', new_resource.privileges]
end
end
else
converge_by('setting privileges for specified users') do
execute 'set up Remote Management to only grant access to users with privileges' do
command [RemoteManagement.kickstart, '-configure', '-allowAccessFor', '-specifiedUsers']
end
execute "set privileges for #{new_resource.users.join(', ')}" do
command [RemoteManagement.kickstart, '-configure', '-access', '-on', '-privs', '-mask', new_resource.privileges, '-users', new_resource.users.join(',')]
end
end
end
end
converge_if_changed(:computer_info) do
new_resource.computer_info.each_with_index do |info, i|
execute "set computer info field #{i + 1}" do
command [RemoteManagement.kickstart, '-configure', '-computerinfo', "-set#{i + 1}", "-#{i + 1}", info]
end
end
end
execute 'activate the Remote Management service and restart the agent' do
command [RemoteManagement.kickstart, '-activate', '-restart', '-agent']
end
end
end
action :disable do
execute 'stop the Remote Management service and deactivate it so it will not start after the next restart' do
command [RemoteManagement.kickstart, '-deactivate', '-stop']
only_if { RemoteManagement.activated? }
end
end

Просмотреть файл

@ -0,0 +1,307 @@
require_relative '../../spec_helper'
describe MacOS::RemoteManagement do
let(:shellout) { double(stdout: nil, stderr: nil) }
describe '.current_mask' do
context 'when ARD is currently configured to use global privileges' do
let(:global_settings_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ARD_AllLocalUsers</key>
<true/>
<key>ARD_AllLocalUsersPrivs</key>
<integer>3</integer>
<key>allowInsecureDH</key>
<true/>
</dict>
</plist>
XML
end
it 'should retrieve the privilege value from global settings plist and return the equivalent mask' do
allow(described_class).to receive(:global_settings_xml).and_return global_settings_xml
expect(described_class.current_mask('bilbo')).to eq(-2147483645) # priv value: 3 -> priv mask: -2147483645
end
end
context 'when ARD is currently configured to use individual privileges' do
let(:dscl_naprivs) do
<<~STDOUT
bilbo -2147483644
gandalf -2147483644
STDOUT
end
it 'should return the mask retrieved from `dscl`' do
allow(described_class).to receive(:using_global_privileges?).and_return false
allow(shellout).to receive(:stdout).and_return dscl_naprivs
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_mask(['bilbo', 'gandalf'])).to eq(-2147483644)
end
end
end
describe '.current_users_configured?' do
context 'when using global settings' do
let(:global_settings_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ARD_AllLocalUsers</key>
<true/>
<key>ARD_AllLocalUsersPrivs</key>
<integer>3</integer>
<key>allowInsecureDH</key>
<true/>
</dict>
</plist>
XML
end
it 'should return true when global privilege value exists' do
allow(shellout).to receive(:stdout).and_return global_settings_xml
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_users_configured?(['bilbo'])).to be true
end
end
context 'when using individual settings' do
context 'when all desired users are configured' do
it 'should return true' do
allow(described_class).to receive(:using_global_privileges?).and_return false
allow(described_class).to receive(:individual_settings).and_return({ 'bilbo' => 1 })
expect(described_class.current_users_configured?(['bilbo'])).to be true
end
end
context 'when desired users are not configured' do
it 'should return false' do
allow(described_class).to receive(:using_global_privileges?).and_return false
allow(described_class).to receive(:individual_settings).and_return({ 'bilbo' => 1 })
expect(described_class.current_users_configured?(['bilbo', 'frodo'])).to be false
end
end
end
describe '.users_have_identical_masks?' do
before(:each) { allow(described_class).to receive(:using_global_privileges?).and_return false }
context 'when the users have different privilege masks' do
let(:dscl_naprivs) do
<<~STDOUT
bilbo -2147483644
gandalf -2147483648
STDOUT
end
it 'should return false' do
allow(shellout).to receive(:stdout).and_return dscl_naprivs
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_users_have_identical_masks?(['bilbo', 'gandalf'])).to be false
end
end
context 'when the users have the same privilege masks' do
let(:dscl_naprivs) do
<<~STDOUT
bilbo -2147483644
ganalf -2147483644
STDOUT
end
it 'should return true' do
allow(shellout).to receive(:stdout).and_return dscl_naprivs
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_users_have_identical_masks?(['bilbo', 'ganalf'])).to be true
end
end
end
describe '.current_computer_info' do
context 'when there is no computer info' do
let(:computer_info_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DOCAllowRemoteConnections</key>
<false/>
</dict>
</plist>
XML
end
it 'should return an empty array' do
allow(shellout).to receive(:stdout).and_return computer_info_xml
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_computer_info).to eq []
end
end
context 'when there is computer info' do
let(:computer_info_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DOCAllowRemoteConnections</key>
<false/>
<key>Text1</key>
<string>bilbo</string>
<key>Text2</key>
<string>baggins</string>
<key>Text3</key>
<string></string>
<key>Text4</key>
<string></string>
</dict>
</plist>
XML
end
it 'should return an empty array' do
allow(shellout).to receive(:stdout).and_return computer_info_xml
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.current_computer_info).to eq ['bilbo', 'baggins']
end
end
end
end
describe '.activated?' do
context 'when the Remote Management launchd file does not exit' do
it 'should return false' do
allow(Chef).to receive(:node).and_return({'platform_version' => '12.6.3' })
allow(RemoteManagement::TCC::State).to receive(:enabled?).and_return true
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).and_return false
expect(described_class.activated?).to be false
end
end
context 'when the tcc state is not enabled' do
let(:tccstate_stdout) do
<<~XML
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<dict>
<key>postEvent</key>
<false/>
<key>screenCapture</key>
<false/>
</dict>
</plist>
XML
end
it 'should return false' do
allow(Chef).to receive(:node).and_return({'platform_version' => '12.6.3' })
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).and_return false
allow(shellout).to receive(:stdout).and_return tccstate_stdout
allow_any_instance_of(Chef::Mixin::ShellOut).to receive(:shell_out!).and_return shellout
expect(described_class.activated?).to be false
end
end
end
end
describe MacOS::RemoteManagement::Privileges do
describe '.format_privileges' do
it 'should strings to capitalized snakecase' do
expect(described_class.format('OneRINGToRuleThemAll')).to eq [:ONE_RING_TO_RULE_THEM_ALL]
expect(described_class.format('one__RING__to__find__them')).to eq [:ONE_RING_TO_FIND_THEM]
expect(described_class.format('one RING to bring them all')).to eq [:ONE_RING_TO_BRING_THEM_ALL]
expect(described_class.format('and-in-the-darkness-bind-them')).to eq [:AND_IN_THE_DARKNESS_BIND_THEM]
end
end
describe '.valid?' do
context 'when the privileges are valid' do
it 'should return true' do
expect(described_class.valid?(:TEXT_MESSAGES)).to be true
expect(described_class.valid?([:SEND_FILES, :CHANGE_SETTINGS])).to be true
end
end
context 'when the privileges are invalid' do
it 'should return true' do
expect(described_class.valid?(:NASGUL)).to be false
expect(described_class.valid?([:goblin, :orc])).to be false
expect(described_class.valid?([:SMAUG])).to be false
end
end
end
end
describe MacOS::RemoteManagement::Privileges::Mask do
describe '.valid?' do
subject { described_class.new(mask: -2147483645) }
context 'when the mask is valid' do
it 'should return true' do
expect(subject.valid?(-2147483645)).to be true
expect(subject.valid?(-2147483552)).to be true
expect(subject.valid?(-2147483508)).to be true
expect(subject.valid?(-1073741569)).to be true
expect(subject.valid?(-2147483648)).to be true
expect(subject.valid?(-2147483392)).to be true
expect(subject.valid?(-2147483391)).to be true
end
end
context 'when the mask is invalid' do
it 'should return false' do
expect(subject.valid?(-1073725185)).to be false
expect(subject.valid?(-2145386496)).to be false
expect(subject.valid?(-2143813632)).to be false
expect(subject.valid?(-2143813629)).to be false
end
end
end
describe '.to_a' do
it 'should return an array of privilege strings coresponding to the privilege mask' do
expect(described_class.new(mask: -2147483645).to_a).to contain_exactly('TextMessages', 'ControlObserve')
expect(described_class.new(mask: -2147483552).to_a).to contain_exactly('OpenQuitApps', 'ChangeSettings')
expect(described_class.new(mask: -2147483508).to_a).to contain_exactly('SendFiles', 'RestartShutDown', 'DeleteFiles')
expect(described_class.new(mask: -1073741569).to_a).to contain_exactly('all')
expect(described_class.new(mask: -2147483648).to_a).to contain_exactly('none')
end
end
end
describe MacOS::RemoteManagement::Privileges::Value do
describe '.valid?' do
subject { described_class.new(value: 0) }
context 'when the value is valid' do
it 'should return true' do
expect(subject.valid?(3)).to be true
expect(subject.valid?(96)).to be true
expect(subject.valid?(140)).to be true
expect(subject.valid?(0)).to be true
expect(subject.valid?(1073742079)).to be true
end
end
context 'when the mask is invalid' do
it 'should return false' do
expect(subject.valid?(512)).to be false
expect(subject.valid?(888)).to be false
expect(subject.valid?(1024)).to be false
expect(subject.valid?(666)).to be false
end
end
end
describe '.to_a' do
it 'should return an array of privilege strings coresponding to the privilege value' do
expect(described_class.new(value: 3).to_a).to contain_exactly('TextMessages', 'ControlObserve')
expect(described_class.new(value: 96).to_a).to contain_exactly('OpenQuitApps', 'ChangeSettings')
expect(described_class.new(value: 140).to_a).to contain_exactly('SendFiles', 'RestartShutDown', 'DeleteFiles')
expect(described_class.new(value: 1073742079).to_a).to contain_exactly('all')
expect(described_class.new(value: 0).to_a).to contain_exactly('none')
end
end
end

Просмотреть файл

@ -1,102 +1,383 @@
require 'spec_helper'
require_relative '../../spec_helper'
shared_context 'with remote management enabled' do
step_into :remote_management
platform 'mac_os_x'
shared_context 'remote management enabled' do
before { allow(RemoteManagement).to receive(:activated?).and_return true }
end
shared_context 'remote management disabled' do
before { allow(RemoteManagement).to receive(:activated?).and_return false }
end
shared_context 'users current mask is -2147483648 (no privileges)' do
let(:current_mask) { RemoteManagement::Privileges::Mask.new(mask: -2147483648) }
before { allow(RemoteManagement).to receive(:current_users_configured?).and_return true }
before { allow(RemoteManagement).to receive(:current_users_have_identical_masks?).and_return true }
before { allow(RemoteManagement).to receive(:current_mask).and_return(current_mask) }
end
shared_context 'users current mask is -1073741569 (all privileges)' do
let(:current_mask) { RemoteManagement::Privileges::Mask.new(mask: -1073741569) }
before { allow(RemoteManagement).to receive(:current_users_configured?).and_return true }
before { allow(RemoteManagement).to receive(:current_users_have_identical_masks?).and_return true }
before { allow(RemoteManagement).to receive(:current_mask).and_return(current_mask) }
end
shared_context 'no current computer info' do
before { allow(RemoteManagement).to receive(:current_computer_info).and_return [] }
end
shared_context 'SIP is disabled' do
before { allow(RemoteManagement::TCC::SIP).to receive(:disabled?).and_return true }
end
shared_context 'correct tccstate' do
before { allow(RemoteManagement::TCC::State).to receive(:enabled?).and_return true }
end
shared_context 'incorrect tccstate' do
before { allow(RemoteManagement::TCC::State).to receive(:enabled?).and_return false }
end
shared_context 'correct TCC database privileges' do
before do
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?)
.with('/Library/Application Support/Apple/Remote Desktop/RemoteManagement.launchd')
.and_return(true)
allow(RemoteManagement).to receive(:plist_content)
.and_return 'Dict { ARD_AllLocalUsersPrivs = 1073742079
ARD_AllLocalUsers = true }'
allow(RemoteManagement::TCC::DB).to receive(:correct_privileges?).and_return true
end
end
shared_context 'with remote management disabled' do
step_into :remote_management
platform 'mac_os_x'
shared_context 'incorrect TCC database privileges' do
before do
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?)
.with('/Library/Application Support/Apple/Remote Desktop/RemoteManagement.launchd')
.and_return(false)
allow(RemoteManagement).to receive(:plist_content)
.and_return ''
allow(RemoteManagement::TCC::DB).to receive(:correct_privileges?).and_return false
allow(RemoteManagement::TCC::DB).to receive(:screensharing_client_authorized_for_post_event_service?).and_return false
allow(RemoteManagement::TCC::DB).to receive(:screensharing_client_authorized_for_screencapture_service?).and_return false
end
end
shared_examples 'kickstart activating and configuring the ARD agent' do
it { is_expected.to run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate') }
it { is_expected.to run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -allowAccessFor -allUsers -access -on -privs -all') }
shared_examples 'activating the ARD agent' do
it {
is_expected.to run_execute('activate the Remote Management service and restart the agent')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-activate', '-restart', '-agent'])
}
end
shared_examples 'kickstart deactivating and stopping the ARD agent' do
it { is_expected.to run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -deactivate') }
it { is_expected.to run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -stop') }
shared_examples 'not activating the ARD agent' do
it { is_expected.to_not run_execute('activate the Remote Management service and restart the agent') }
end
shared_examples 'kickstart not activating or configuring the ARD agent' do
it { is_expected.to_not run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate') }
it { is_expected.to_not run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -allowAccessFor -allUsers -access -on -privs -all') }
shared_examples 'configuring the ARD agent for all users' do
it {
is_expected.to run_execute('set privileges for all users')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-configure', '-allowAccessFor', '-allUsers', '-access', '-on', '-privs', '-all'])
}
end
shared_examples 'kickstart not deactivating or stopping the ARD agent' do
it { is_expected.to_not run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -deactivate') }
it { is_expected.to_not run_execute('/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -stop') }
shared_examples 'not configuring the ARD agent for all users' do
it { is_expected.to_not run_execute('set privileges for all users') }
end
describe 'enabling when already disabled' do
include_context 'with remote management disabled'
shared_examples 'configuring the ARD agent for specified users' do
it {
is_expected.to run_execute('set up Remote Management to only grant access to users with privileges')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-configure', '-allowAccessFor', '-specifiedUsers'])
}
it {
is_expected.to run_execute('set privileges for bilbo')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-configure', '-access', '-on', '-privs', '-all', '-users', 'bilbo'])
}
end
shared_examples 'not configuring the ARD agent for specified users' do
it { is_expected.to_not run_execute('set up Remote Management to only grant access to users with privileges') }
it { is_expected.to_not run_execute('set privileges for bilbo') }
end
shared_examples 'restarting the TCC daemon' do
it {
is_expected.to run_execute('restart the TCC daemon')
.with(command: 'sudo pkill -9 tccd')
}
end
shared_examples 'not restarting the TCC daemon' do
it { is_expected.to_not run_execute('restart the TCC daemon') }
end
shared_examples 'deactivating and stopping the ARD agent' do
it {
is_expected.to run_execute('stop the Remote Management service and deactivate it so it will not start after the next restart')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-deactivate', '-stop'])
}
end
shared_examples 'not deactivating or stopping the ARD agent' do
it { is_expected.to_not run_execute('stop the Remote Management service and deactivate it so it will not start after the next restart') }
end
shared_examples 'setting the computer info' do
it {
is_expected.to run_execute('set computer info field 1')
.with(command: ['/System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart', '-configure', '-computerinfo', '-set1', '-1', 'Arkenstone'])
}
end
shared_examples 'not setting the computer info' do
it { is_expected.to_not run_execute('set computer info 1') }
end
describe 'enabling for all users when currently disabled' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'incorrect tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'enabled' do
remote_management 'enable the ARD agent, giving all users all privileges' do
users 'all'
privileges 'all'
computer_info []
action :enable
end
end
it_behaves_like 'kickstart activating and configuring the ARD agent'
it_behaves_like 'kickstart not deactivating or stopping the ARD agent'
it_behaves_like 'configuring the ARD agent for all users'
it_behaves_like 'restarting the TCC daemon'
it_behaves_like 'activating the ARD agent'
it_behaves_like 'not configuring the ARD agent for specified users'
it_behaves_like 'not setting the computer info'
end
describe 'enabling when already enabled' do
include_context 'with remote management enabled'
describe 'enabling for specified users when currently disabled' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'correct tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'enabled' do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'all'
computer_info []
action :enable
end
end
it_behaves_like 'kickstart not activating or configuring the ARD agent'
it_behaves_like 'kickstart not deactivating or stopping the ARD agent'
it_behaves_like 'configuring the ARD agent for specified users'
it_behaves_like 'not restarting the TCC daemon'
it_behaves_like 'activating the ARD agent'
it_behaves_like 'not configuring the ARD agent for all users'
it_behaves_like 'not setting the computer info'
end
describe 'disabling when already disabled' do
include_context 'with remote management disabled'
describe 'enabling for specified users when currently enabled and current privileges are different than the desired privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management enabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'incorrect tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'disabled' do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'all'
computer_info []
action :enable
end
end
it_behaves_like 'configuring the ARD agent for specified users'
it_behaves_like 'restarting the TCC daemon'
it_behaves_like 'activating the ARD agent'
it_behaves_like 'not configuring the ARD agent for all users'
it_behaves_like 'not setting the computer info'
end
describe 'enabling when the current computer info differs from the desired computer info' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management enabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'incorrect tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'all'
computer_info 'Arkenstone'
action :enable
end
end
it_behaves_like 'setting the computer info'
end
describe 'enabling for specified users when currently enabled and current privileges are the same as the desired privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management enabled'
include_context 'users current mask is -1073741569 (all privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'incorrect tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'all'
computer_info []
action :enable
end
end
it_behaves_like 'not configuring the ARD agent for specified users'
it_behaves_like 'not configuring the ARD agent for all users'
it_behaves_like 'not restarting the TCC daemon'
it_behaves_like 'not activating the ARD agent'
it_behaves_like 'not setting the computer info'
end
describe 'trying to enable when TCC does not have the correct privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'incorrect TCC database privileges'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'all'
computer_info []
action :enable
end
end
it { expect { subject }.to raise_error(RemoteManagement::Exceptions::TCCError) }
end
describe 'trying to enable with invalid privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'incorrect TCC database privileges'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges 'smaug'
computer_info []
action :enable
end
end
it { expect { subject }.to raise_error(Chef::Exceptions::ValidationFailed) }
end
describe 'trying to enable with invalid privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'incorrect TCC database privileges'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges ['nazgûl', 'smèagol']
computer_info []
action :enable
end
end
it { expect { subject }.to raise_error(Chef::Exceptions::ValidationFailed) }
end
describe 'enable with abnormally formatted privileges' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'no current computer info'
include_context 'correct TCC database privileges'
include_context 'incorrect tccstate'
include_context 'SIP is disabled'
recipe do
remote_management 'enable the ARD agent' do
users 'bilbo'
privileges ['DeleteFiles', 'text messages', 'SEND__FILES', 'restart-shut-down']
computer_info []
action :enable
end
end
it { expect { subject }.to_not raise_error }
end
describe 'disabling when currently disabled' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management disabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'SIP is disabled'
recipe do
remote_management 'disable the ARD agent' do
action :disable
end
end
it_behaves_like 'kickstart not activating or configuring the ARD agent'
it_behaves_like 'kickstart not deactivating or stopping the ARD agent'
it_behaves_like 'not deactivating or stopping the ARD agent'
end
describe 'disabling when already enabled' do
include_context 'with remote management enabled'
describe 'disabling when currently enabled' do
platform 'mac_os_x', '12'
step_into :remote_management
include_context 'remote management enabled'
include_context 'users current mask is -2147483648 (no privileges)'
include_context 'SIP is disabled'
recipe do
remote_management 'disabled' do
remote_management 'disable the ARD agent' do
action :disable
end
end
it_behaves_like 'kickstart not activating or configuring the ARD agent'
it_behaves_like 'kickstart deactivating and stopping the ARD agent'
it_behaves_like 'deactivating and stopping the ARD agent'
end

Просмотреть файл

@ -1,4 +1,22 @@
remote_management 'activate and configure remote management for all users' do
action :enable
not_if { node['platform_version'] >= '11.0' } # remove prior to Big Sur public release
# TODO; do we want to add the TCC logic to the resource?
tcc_db_path = '/Library/Application Support/com.apple.TCC/TCC.db'
execute 'authorize screensharing client to utilize the kTCCServicePostEvent service' do
command ['/usr/bin/sqlite3', tcc_db_path, "INSERT OR REPLACE INTO access VALUES('kTCCServicePostEvent','com.apple.screensharing.agent',0,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1639743960);" ]
not_if { RemoteManagement::TCC::DB.correct_privileges? }
only_if { shell_out('/usr/sbin/system_profiler', 'SPSoftwareDataType').stdout.match?(Regexp.new('System Integrity Protection: Disabled')) }
end
execute 'authorize screensharing client to utilize the kTCCServiceScreenCapture service' do
command ['/usr/bin/sqlite3', tcc_db_path, "INSERT OR REPLACE INTO access VALUES ('kTCCServiceScreenCapture','com.apple.screensharing.agent',0,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1639743960);" ]
not_if { RemoteManagement::TCC::DB.correct_privileges? }
only_if { shell_out('/usr/sbin/system_profiler', 'SPSoftwareDataType').stdout.match?(Regexp.new('System Integrity Protection: Disabled')) }
end
remote_management 'activate and configure remote management for all users' do
users 'all'
privileges %w(text__messages ControlObserve send_files)
computer_info ['Arkenstone', 'Gold']
only_if { shell_out('/usr/sbin/system_profiler', 'SPSoftwareDataType').stdout.match?(Regexp.new('System Integrity Protection: Disabled')) }
end

Просмотреть файл

@ -1,31 +1,23 @@
title 'remote access'
# user_has_access = 1 << 31
text_messages = 1 << 0
control_observe = 1 << 1
send_files = 1 << 2
delete_files = 1 << 3
generate_reports = 1 << 4
open_quit_apps = 1 << 5
change_settings = 1 << 6
restart_shutdown = 1 << 7
# observe_only = 1 << 8
show_observe = 1 << 30
all_privileges = text_messages | control_observe | send_files |
delete_files | generate_reports | open_quit_apps |
change_settings | restart_shutdown | show_observe
control 'remote-control' do
title 'ensure that remote access and control will function'
desc "ensure that the Remote Management plist grants local users access, that
all privileges are granted based on the mask #{all_privileges}, and that
remote control is enabled"
only_if { os.release < '20' } # remove prior to Big Sur public release
title 'ensure the correct configuration of ARD'
desc 'ensure that the ARD is enabled and configured to grant the correct privileges to the correct users'
describe command('/usr/libexec/PlistBuddy -c Print /Library/Preferences/com.apple.RemoteManagement.plist') do
its('stdout') { should match 'ARD_AllLocalUsers = true' }
its('stdout') { should match /#{all_privileges}/ }
describe command('/usr/bin/defaults read /Library/Preferences/com.apple.RemoteManagement') do
its('stdout') { should match /"ARD_AllLocalUsers" = 1/ }
end
describe command('/usr/bin/defaults read /Library/Preferences/com.apple.RemoteDesktop') do
its('stdout') { should match /Text1 = \w+/ }
its('stdout') { should match /Text2 = \w+/ }
its('stdout') { should match /Text3 = ""/ }
its('stdout') { should match /Text4 = ""/ }
end
if Chef::Version.new(os.release) >= Chef::Version.new('21.0.0')
describe command('sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Support/tccstate') do
its('stdout') { should match Regexp.new('<key>postEvent<\/key>.\s+<true\/>', Regexp::MULTILINE) }
its('stdout') { should match Regexp.new('<key>screenCapture<\/key>.\s+<true\/>', Regexp::MULTILINE) }
end
end
describe file('/Library/Application Support/Apple/Remote Desktop/RemoteManagement.launchd') do