Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mac_user: fixing gid and system properties, and adding hidden property #9275

Merged
merged 6 commits into from Feb 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 53 additions & 9 deletions lib/chef/provider/user/mac.rb
Expand Up @@ -52,6 +52,10 @@ def load_current_resource
current_resource.shell(user_plist[:shell][0])
current_resource.comment(user_plist[:comment][0])

if user_plist[:is_hidden]
current_resource.hidden(user_plist[:is_hidden][0] == "1" ? true : false)
end

shadow_hash = user_plist[:shadow_hash]
if shadow_hash
current_resource.password(shadow_hash[0]["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*")[0])
Expand Down Expand Up @@ -137,7 +141,7 @@ def reload_user_plist
def create_user
cmd = [-"-addUser", new_resource.username]
cmd += ["-fullName", new_resource.comment] if prop_is_set?(:comment)
cmd += ["-UID", new_resource.uid] if prop_is_set?(:uid)
cmd += ["-UID", prop_is_set?(:uid) ? new_resource.uid : get_free_uid]
cmd += ["-shell", new_resource.shell]
cmd += ["-home", new_resource.home]
cmd += ["-admin"] if new_resource.admin
Expand Down Expand Up @@ -165,6 +169,10 @@ def create_user
reload_user_plist
reload_admin_group_plist

if prop_is_set?(:hidden)
set_hidden
end

if prop_is_set?(:password)
converge_by("set password") { set_password }
end
Expand Down Expand Up @@ -196,7 +204,7 @@ def create_user
end.run_action(group_action)

converge_by("create primary group ID") do
run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", new_resource.gid)
run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", group_id)
end
end

Expand All @@ -208,7 +216,7 @@ def create_user
end

def compare_user
%i{comment shell uid gid salt password admin secure_token}.any? { |m| diverged?(m) }
%i{comment shell uid gid salt password admin secure_token hidden}.any? { |m| diverged?(m) }
end

def manage_user
Expand Down Expand Up @@ -272,7 +280,13 @@ def manage_user

if diverged?(:gid)
converge_by("alter group membership") do
run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", new_resource.gid)
run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", group_id)
end
end

if diverged?(:hidden)
converge_by("alter hidden") do
set_hidden
end
end

Expand Down Expand Up @@ -336,13 +350,33 @@ def diverged?(prop)
user_group_diverged?
when :secure_token
secure_token_diverged?
when :hidden
hidden_diverged?
else
# Other fields are have been set on current resource so just compare
# them.
!new_resource.send(prop).nil? && (new_resource.send(prop) != current_resource.send(prop))
end
end

# Find the next available uid on the system.
# Starting with 200 if `system` is set, 501 otherwise.
def get_free_uid(search_limit = 1000)
uid = nil
base_uid = new_resource.system ? 200 : 501
next_uid_guess = base_uid
users_uids = run_dscl("list", "/Users", "uid")
while next_uid_guess < search_limit + base_uid
if users_uids =~ Regexp.new("#{Regexp.escape(next_uid_guess.to_s)}\n")
next_uid_guess += 1
else
uid = next_uid_guess
break
end
end
uid || raise("uid not found. Exhausted. Searched #{search_limit} times")
end

# Attempt to resolve the group name, gid, and the action required for
# associated group resource. If a group exists we'll modify it, otherwise
# create it.
Expand Down Expand Up @@ -410,12 +444,21 @@ def user_group_diverged?
return false unless prop_is_set?(:gid)

group_name, group_id = user_group_info
current_resource.gid != group_id.to_i
end

if current_resource.gid.is_a?(String)
current_resource.gid != group_name
else
current_resource.gid != group_id.to_i
end
def hidden_diverged?
return false unless prop_is_set?(:hidden)

(current_resource.hidden ? 1 : 0) != hidden_value.to_i
end

def set_hidden
run_dscl("create", "/Users/#{new_resource.username}", "IsHidden", hidden_value.to_i)
end

def hidden_value
new_resource.hidden ? 1 : 0
end

def password_diverged?
Expand Down Expand Up @@ -593,6 +636,7 @@ class Plist
auth_authority: "dsAttrTypeStandard:AuthenticationAuthority",
shadow_hash: "dsAttrTypeNative:ShadowHashData",
group_members: "dsAttrTypeStandard:GroupMembers",
is_hidden: "dsAttrTypeNative:IsHidden",
}.freeze

attr_accessor :plist_hash, :property_map
Expand Down
3 changes: 3 additions & 0 deletions lib/chef/resource/user/mac_user.rb
Expand Up @@ -100,6 +100,9 @@ class MacUser < Chef::Resource::User

property :admin, [TrueClass, FalseClass], description: "Create the user as an admin", default: false

# Hide a user account in the macOS login window
property :hidden, [TrueClass, FalseClass, nil], description: "Hide account from loginwindow and system preferences", default: nil

# TCC on macOS >= 10.14 requires admin credentials of an Admin user that
# has SecureToken enabled in order to toggle SecureToken.
property :admin_username, String, description: "Admin username for superuser actions"
Expand Down