diff options
Diffstat (limited to 'lib/chef/provider/user/dscl.rb')
-rw-r--r-- | lib/chef/provider/user/dscl.rb | 328 |
1 files changed, 127 insertions, 201 deletions
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb index 821fa8e8a7..cd10403e4a 100644 --- a/lib/chef/provider/user/dscl.rb +++ b/lib/chef/provider/user/dscl.rb @@ -1,6 +1,6 @@ # # Author:: Dreamcat4 (<dreamcat4@gmail.com>) -# Copyright:: Copyright 2009-2016, Chef Software Inc. +# Copyright:: Copyright (c) Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,18 +16,19 @@ # limitations under the License. # -require "mixlib/shellout" -require "chef/provider/user" -require "openssl" -require "plist" -require "chef/util/path_helper" +require_relative "../../mixin/shell_out" +require_relative "../user" +require_relative "../../resource/user/dscl_user" +autoload :OpenSSL, "openssl" +autoload :Plist, "plist" +require_relative "../../util/path_helper" class Chef class Provider class User # # The most tricky bit of this provider is the way it deals with user passwords. - # Mac OS X has different password shadow calculations based on the version. + # macOS has different password shadow calculations based on the version. # < 10.7 => password shadow calculation format SALTED-SHA1 # => stored in: /var/db/shadow/hash/#{guid} # => shadow binary length 68 bytes @@ -41,7 +42,7 @@ class Chef # => shadow binary length 128 bytes # => Salt / Iterations are stored separately in the same file # - # This provider only supports Mac OSX versions 10.7 and above + # This provider only supports macOS versions 10.7 to 10.13 class Dscl < Chef::Provider::User attr_accessor :user_info @@ -49,29 +50,29 @@ class Chef attr_accessor :password_shadow_conversion_algorithm provides :dscl_user - provides :user, os: "darwin" + provides :user, os: "darwin", platform_version: "<= 10.13" + + # Just-in-case a recipe calls the user dscl provider without specifying + # a gid property. Avoids chown issues in move_home when the manage_home + # property is in use. #5393 + STAFF_GROUP_ID = 20 def define_resource_requirements super requirements.assert(:all_actions) do |a| - a.assertion { mac_osx_version_less_than_10_7? == false } - a.failure_message(Chef::Exceptions::User, "Chef::Provider::User::Dscl only supports Mac OS X versions 10.7 and above.") - end - - requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/dscl") } + a.assertion { ::File.exist?("/usr/bin/dscl") } a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{new_resource}!") end requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/plutil") } + a.assertion { ::File.exist?("/usr/bin/plutil") } a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{new_resource}!") end requirements.assert(:create, :modify, :manage) do |a| a.assertion do - if new_resource.password && mac_osx_version_greater_than_10_7? + if new_resource.password # SALTED-SHA512 password shadow hashes are not supported on 10.8 and above. !salted_sha512?(new_resource.password) else @@ -85,7 +86,7 @@ in 'password', with the associated 'salt' and 'iterations'.") requirements.assert(:create, :modify, :manage) do |a| a.assertion do - if new_resource.password && mac_osx_version_greater_than_10_7? && salted_sha512_pbkdf2?(new_resource.password) + if new_resource.password && salted_sha512_pbkdf2?(new_resource.password) # salt and iterations should be specified when # SALTED-SHA512-PBKDF2 password shadow hash is given !new_resource.salt.nil? && !new_resource.iterations.nil? @@ -96,24 +97,10 @@ in 'password', with the associated 'salt' and 'iterations'.") a.failure_message(Chef::Exceptions::User, "SALTED-SHA512-PBKDF2 shadow hash is given without associated \ 'salt' and 'iterations'. Please specify 'salt' and 'iterations' in order to set the user password using shadow hash.") end - - requirements.assert(:create, :modify, :manage) do |a| - a.assertion do - if new_resource.password && !mac_osx_version_greater_than_10_7? - # On 10.7 SALTED-SHA512-PBKDF2 is not supported - !salted_sha512_pbkdf2?(new_resource.password) - else - true - end - end - a.failure_message(Chef::Exceptions::User, "SALTED-SHA512-PBKDF2 shadow hashes are not supported on \ -Mac OS X version 10.7. Please specify a SALTED-SHA512 shadow hash in 'password' attribute to set the \ -user password using shadow hash.") - end end def load_current_resource - @current_resource = Chef::Resource::User.new(new_resource.username) + @current_resource = Chef::Resource::User::DsclUser.new(new_resource.username) current_resource.username(new_resource.username) @user_info = read_user_info @@ -131,13 +118,9 @@ user password using shadow hash.") # Calling shell_out directly since we want to give an input stream shadow_hash_xml = convert_binary_plist_to_xml(shadow_hash_binary.string) - shadow_hash = Plist.parse_xml(shadow_hash_xml) + shadow_hash = ::Plist.parse_xml(shadow_hash_xml) - if shadow_hash["SALTED-SHA512"] - # Convert the shadow value from Base64 encoding to hex before consuming them - @password_shadow_conversion_algorithm = "SALTED-SHA512" - current_resource.password(shadow_hash["SALTED-SHA512"].string.unpack("H*").first) - elsif shadow_hash["SALTED-SHA512-PBKDF2"] + if shadow_hash["SALTED-SHA512-PBKDF2"] # 10.7+ contains this, but we retain the check in case it goes away in the future @password_shadow_conversion_algorithm = "SALTED-SHA512-PBKDF2" # Convert the entropy from Base64 encoding to hex before consuming them current_resource.password(shadow_hash["SALTED-SHA512-PBKDF2"]["entropy"].string.unpack("H*").first) @@ -145,14 +128,14 @@ user password using shadow hash.") # Convert the salt from Base64 encoding to hex before consuming them current_resource.salt(shadow_hash["SALTED-SHA512-PBKDF2"]["salt"].string.unpack("H*").first) else - raise(Chef::Exceptions::User, "Unknown shadow_hash format: #{shadow_hash.keys.join(' ')}") + raise(Chef::Exceptions::User, "Unknown shadow_hash format: #{shadow_hash.keys.join(" ")}") end end convert_group_name if new_resource.gid else @user_exists = false - Chef::Log.debug("#{new_resource} user does not exist") + logger.trace("#{new_resource} user does not exist") end current_resource @@ -194,7 +177,7 @@ user password using shadow hash.") # Create a user using dscl # def dscl_create_user - run_dscl("create /Users/#{new_resource.username}") + run_dscl("create", "/Users/#{new_resource.username}") end # @@ -203,13 +186,13 @@ user password using shadow hash.") # def dscl_create_comment comment = new_resource.comment || new_resource.username - run_dscl("create /Users/#{new_resource.username} RealName '#{comment}'") + run_dscl("create", "/Users/#{new_resource.username}", "RealName", comment) end # # Sets the user id for the user using dscl. # If a `uid` is not specified, it finds the next available one starting - # from 200 if `system` is set, 500 otherwise. + # from 200 if `system` is set, 501 otherwise. # def dscl_set_uid # XXX: mutates the new resource @@ -219,27 +202,27 @@ user password using shadow hash.") raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{new_resource.uid} is already in use") end - run_dscl("create /Users/#{new_resource.username} UniqueID #{new_resource.uid}") + run_dscl("create", "/Users/#{new_resource.username}", "UniqueID", new_resource.uid) end # # Find the next available uid on the system. starting with 200 if `system` is set, - # 500 otherwise. + # 501 otherwise. # def get_free_uid(search_limit = 1000) uid = nil - base_uid = new_resource.system ? 200 : 500 + base_uid = new_resource.system ? 200 : 501 next_uid_guess = base_uid - users_uids = run_dscl("list /Users 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") + if users_uids&.match?(Regexp.new("#{Regexp.escape(next_uid_guess.to_s)}\n")) next_uid_guess += 1 else uid = next_uid_guess break end end - return uid || raise("uid not found. Exhausted. Searched #{search_limit} times") + uid || raise("uid not found. Exhausted. Searched #{search_limit} times") end # @@ -247,39 +230,40 @@ user password using shadow hash.") # def uid_used?(uid) return false unless uid - users_uids = run_dscl("list /Users uid").split("\n") - uid_map = users_uids.inject({}) do |tmap, tuid| + + users_uids = run_dscl("list", "/Users", "uid").split("\n") + uid_map = users_uids.each_with_object({}) do |tuid, tmap| x = tuid.split tmap[x[1]] = x[0] tmap end if uid_map[uid.to_s] - unless uid_map[uid.to_s] == new_resource.username.to_s + unless uid_map[uid.to_s] == new_resource.username return true end end - return false + false end # # Sets the group id for the user using dscl. Fails if a group doesn't # exist on the system with given group id. If `gid` is not specified, it - # sets a default Mac user group "staff", with id 20. + # sets a default Mac user group "staff", with id 20 using the CONSTANT # def dscl_set_gid if new_resource.gid.nil? # XXX: mutates the new resource - new_resource.gid(20) + new_resource.gid(STAFF_GROUP_ID) elsif !new_resource.gid.to_s.match(/^\d+$/) begin - possible_gid = run_dscl("read /Groups/#{new_resource.gid} PrimaryGroupID").split(" ").last - rescue Chef::Exceptions::DsclCommandFailed => e - raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{new_resource.gid} when creating user #{new_resource.username}") + possible_gid = run_dscl("read", "/Groups/#{new_resource.gid}", "PrimaryGroupID").split(" ").last + rescue Chef::Exceptions::DsclCommandFailed + raise Chef::Exceptions::GroupIDNotFound, "Group not found for #{new_resource.gid} when creating user #{new_resource.username}" end # XXX: mutates the new resource new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/) end - run_dscl("create /Users/#{new_resource.username} PrimaryGroupID '#{new_resource.gid}'") + run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", new_resource.gid) end # @@ -288,11 +272,11 @@ user password using shadow hash.") # def dscl_set_home if new_resource.home.nil? || new_resource.home.empty? - run_dscl("delete /Users/#{new_resource.username} NFSHomeDirectory") + run_dscl("delete", "/Users/#{new_resource.username}", "NFSHomeDirectory") return end - if new_resource.supports[:manage_home] + if new_resource.manage_home validate_home_dir_specification! if (current_resource.home == new_resource.home) && !new_home_exists? @@ -303,37 +287,34 @@ user password using shadow hash.") move_home end end - run_dscl("create /Users/#{new_resource.username} NFSHomeDirectory '#{new_resource.home}'") + run_dscl("create", "/Users/#{new_resource.username}", "NFSHomeDirectory", new_resource.home) end def validate_home_dir_specification! - unless new_resource.home =~ /^\// + unless %r{^/}.match?(new_resource.home) raise(Chef::Exceptions::InvalidHomeDirectory, "invalid path spec for User: '#{new_resource.username}', home directory: '#{new_resource.home}'") end end def current_home_exists? - ::File.exist?("#{current_resource.home}") + !!current_resource.home && ::File.exist?(current_resource.home) end def new_home_exists? - ::File.exist?("#{new_resource.home}") + ::File.exist?(new_resource.home) end def ditto_home - skel = "/System/Library/User Template/English.lproj" - raise(Chef::Exceptions::User, "can't find skel at: #{skel}") unless ::File.exists?(skel) - shell_out! "ditto '#{skel}' '#{new_resource.home}'" - ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home) + shell_out!("/usr/sbin/createhomedir", "-c", "-u", (new_resource.username).to_s) end def move_home - Chef::Log.debug("#{new_resource} moving #{self} home from #{current_resource.home} to #{new_resource.home}") - + logger.trace("#{new_resource} moving #{self} home from #{current_resource.home} to #{new_resource.home}") + new_resource.gid(STAFF_GROUP_ID) if new_resource.gid.nil? src = current_resource.home FileUtils.mkdir_p(new_resource.home) files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob_dir(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.", "#{src}/.."] - ::FileUtils.mv(files, new_resource.home, :force => true) + ::FileUtils.mv(files, new_resource.home, force: true) ::FileUtils.rmdir(src) ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home) end @@ -342,10 +323,10 @@ user password using shadow hash.") # Sets the shell for the user using dscl. # def dscl_set_shell - if new_resource.shell || ::File.exists?("#{new_resource.shell}") - run_dscl("create /Users/#{new_resource.username} UserShell '#{new_resource.shell}'") + if new_resource.shell + run_dscl("create", "/Users/#{new_resource.username}", "UserShell", new_resource.shell) else - run_dscl("create /Users/#{new_resource.username} UserShell '/usr/bin/false'") + run_dscl("create", "/Users/#{new_resource.username}", "UserShell", "/usr/bin/false") end end @@ -362,9 +343,8 @@ user password using shadow hash.") # Shadow info is saved as binary plist. Convert the info to binary plist. shadow_info_binary = StringIO.new - command = Mixlib::ShellOut.new("plutil -convert binary1 -o - -", - :input => shadow_info.to_plist, :live_stream => shadow_info_binary) - command.run_command + shell_out("plutil", "-convert", "binary1", "-o", "-", "-", + input: shadow_info.to_plist, live_stream: shadow_info_binary) if user_info.nil? # User is just created. read_user_info() will read the fresh information @@ -389,47 +369,31 @@ user password using shadow hash.") salt = nil iterations = nil - if mac_osx_version_10_7? - hash_value = if salted_sha512?(new_resource.password) - new_resource.password - else - # Create a random 4 byte salt - salt = OpenSSL::Random.random_bytes(4) - encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password) - hash_value = salt.unpack("H*").first + encoded_password - end - - shadow_info["SALTED-SHA512"] = StringIO.new - shadow_info["SALTED-SHA512"].string = convert_to_binary(hash_value) - shadow_info + if salted_sha512_pbkdf2?(new_resource.password) + entropy = convert_to_binary(new_resource.password) + salt = convert_to_binary(new_resource.salt) + iterations = new_resource.iterations else - if salted_sha512_pbkdf2?(new_resource.password) - entropy = convert_to_binary(new_resource.password) - salt = convert_to_binary(new_resource.salt) - iterations = new_resource.iterations - else - salt = OpenSSL::Random.random_bytes(32) - iterations = new_resource.iterations # Use the default if not specified by the user - - entropy = OpenSSL::PKCS5.pbkdf2_hmac( - new_resource.password, - salt, - iterations, - 128, - OpenSSL::Digest::SHA512.new - ) - end - - pbkdf_info = {} - pbkdf_info["entropy"] = StringIO.new - pbkdf_info["entropy"].string = entropy - pbkdf_info["salt"] = StringIO.new - pbkdf_info["salt"].string = salt - pbkdf_info["iterations"] = iterations - - shadow_info["SALTED-SHA512-PBKDF2"] = pbkdf_info + salt = OpenSSL::Random.random_bytes(32) + iterations = new_resource.iterations # Use the default if not specified by the user + + entropy = OpenSSL::PKCS5.pbkdf2_hmac( + new_resource.password, + salt, + iterations, + 128, + OpenSSL::Digest.new("SHA512") + ) end + pbkdf_info = {} + pbkdf_info["entropy"] = StringIO.new + pbkdf_info["entropy"].string = entropy + pbkdf_info["salt"] = StringIO.new + pbkdf_info["salt"].string = salt + pbkdf_info["iterations"] = iterations + + shadow_info["SALTED-SHA512-PBKDF2"] = pbkdf_info shadow_info end @@ -438,27 +402,27 @@ user password using shadow hash.") # and deleting home directory if needed. # def remove_user - if new_resource.supports[:manage_home] + if new_resource.manage_home # Remove home directory FileUtils.rm_rf(current_resource.home) end # Remove the user from its groups - run_dscl("list /Groups").each_line do |group| + run_dscl("list", "/Groups").each_line do |group| if member_of_group?(group.chomp) - run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{new_resource.username}'") + run_dscl("delete", "/Groups/#{group.chomp}", "GroupMembership", new_resource.username) end end # Remove user account - run_dscl("delete /Users/#{new_resource.username}") + run_dscl("delete", "/Users/#{new_resource.username}") end # # Locks the user. # def lock_user - run_dscl("append /Users/#{new_resource.username} AuthenticationAuthority ';DisabledUser;'") + run_dscl("append", "/Users/#{new_resource.username}", "AuthenticationAuthority", ";DisabledUser;") end # @@ -466,7 +430,7 @@ user password using shadow hash.") # def unlock_user auth_string = authentication_authority.gsub(/AuthenticationAuthority: /, "").gsub(/;DisabledUser;/, "").strip - run_dscl("create /Users/#{new_resource.username} AuthenticationAuthority '#{auth_string}'") + run_dscl("create", "/Users/#{new_resource.username}", "AuthenticationAuthority", auth_string) end # @@ -474,7 +438,7 @@ user password using shadow hash.") # def locked? if authentication_authority - !!(authentication_authority =~ /DisabledUser/ ) + !!(authentication_authority.include?("DisabledUser")) else false end @@ -484,7 +448,7 @@ user password using shadow hash.") # This is the interface base User provider requires to provide idempotency. # def check_lock - return @locked = locked? + @locked = locked? end # @@ -496,11 +460,11 @@ user password using shadow hash.") # given attribute. # def diverged?(parameter) - parameter_updated?(parameter) && (not new_resource.send(parameter).nil?) + parameter_updated?(parameter) && !new_resource.send(parameter).nil? end def parameter_updated?(parameter) - not (new_resource.send(parameter) == current_resource.send(parameter)) + !(new_resource.send(parameter) == current_resource.send(parameter)) end # @@ -514,29 +478,16 @@ user password using shadow hash.") return false if new_resource.password.nil? # Dscl provider supports both plain text passwords and shadow hashes. - if mac_osx_version_10_7? - if salted_sha512?(new_resource.password) - diverged?(:password) - else - !salted_sha512_password_match? - end + # + # Some system users don't have salts; this can happen if the system is + # upgraded and the user hasn't logged in yet. In this case, we will force + # the password to be updated. + return true if current_resource.salt.nil? + + if salted_sha512_pbkdf2?(new_resource.password) + diverged?(:password) || diverged?(:salt) || diverged?(:iterations) else - # When a system is upgraded to a version 10.7+ shadow hashes of the users - # will be updated when the user logs in. So it's possible that we will have - # SALTED-SHA512 password in the current_resource. In that case we will force - # password to be updated. - return true if salted_sha512?(current_resource.password) - - # Some system users don't have salts; this can happen if the system is - # upgraded and the user hasn't logged in yet. In this case, we will force - # the password to be updated. - return true if current_resource.salt.nil? - - if salted_sha512_pbkdf2?(new_resource.password) - diverged?(:password) || diverged?(:salt) || diverged?(:iterations) - else - !salted_sha512_pbkdf2_password_match? - end + !salted_sha512_pbkdf2_password_match? end end @@ -546,7 +497,7 @@ user password using shadow hash.") def member_of_group?(group_name) membership_info = "" begin - membership_info = run_dscl("read /Groups/#{group_name}") + membership_info = run_dscl("read", "/Groups/#{group_name}") rescue Chef::Exceptions::DsclCommandFailed # Raised if the group doesn't contain any members end @@ -563,14 +514,14 @@ user password using shadow hash.") # A simple map of Chef's terms to DSCL's terms. DSCL_PROPERTY_MAP = { - :uid => "uid", - :gid => "gid", - :home => "home", - :shell => "shell", - :comment => "realname", - :password => "passwd", - :auth_authority => "authentication_authority", - :shadow_hash => "ShadowHashData", + uid: "uid", + gid: "gid", + home: "home", + shell: "shell", + comment: "realname", + password: "passwd", + auth_authority: "authentication_authority", + shadow_hash: "ShadowHashData", }.freeze # Directory where the user plist files are stored for versions 10.7 and above @@ -585,12 +536,12 @@ user password using shadow hash.") # We flush the cache here in order to make sure that we read fresh information # for the user. - shell_out("dscacheutil '-flushcache'") + shell_out("dscacheutil", "-flushcache") # FIXME: this is macOS version dependent begin user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist" - user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}") - user_info = Plist.parse_xml(user_plist_info) + user_plist_info = run_plutil("convert", "xml1", "-o", "-", user_plist_file) + user_info = ::Plist.parse_xml(user_plist_info) rescue Chef::Exceptions::PlistUtilCommandFailed end @@ -603,15 +554,16 @@ user password using shadow hash.") # def save_user_info(user_info) user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist" - Plist::Emit.save_plist(user_info, user_plist_file) - run_plutil("convert binary1 #{user_plist_file}") + ::Plist::Emit.save_plist(user_info, user_plist_file) + run_plutil("convert", "binary1", user_plist_file) end # # Sets a value in user information hash using Chef attributes as keys. # def dscl_set(user_hash, key, value) - raise "Unknown dscl key #{key}" unless DSCL_PROPERTY_MAP.keys.include?(key) + raise "Unknown dscl key #{key}" unless DSCL_PROPERTY_MAP.key?(key) + user_hash[DSCL_PROPERTY_MAP[key]] = [ value ] user_hash end @@ -620,58 +572,39 @@ user password using shadow hash.") # Gets a value from user information hash using Chef attributes as keys. # def dscl_get(user_hash, key) - raise "Unknown dscl key #{key}" unless DSCL_PROPERTY_MAP.keys.include?(key) + raise "Unknown dscl key #{key}" unless DSCL_PROPERTY_MAP.key?(key) + # DSCL values are set as arrays value = user_hash[DSCL_PROPERTY_MAP[key]] value.nil? ? value : value.first end # - # System Helpets + # System Helpers # - def mac_osx_version - # This provider will only be invoked on node[:platform] == "mac_os_x" - # We do not check or assert that here. - node[:platform_version] - end - - def mac_osx_version_10_7? - mac_osx_version.start_with?("10.7.") - end - - def mac_osx_version_less_than_10_7? - versions = mac_osx_version.split(".") - # Make integer comparison in order not to report 10.10 less than 10.7 - (versions[0].to_i <= 10 && versions[1].to_i < 7) - end - - def mac_osx_version_greater_than_10_7? - versions = mac_osx_version.split(".") - # Make integer comparison in order not to report 10.10 less than 10.7 - (versions[0].to_i >= 10 && versions[1].to_i > 7) - end - def run_dscl(*args) - result = shell_out("dscl . -#{args.join(' ')}") + result = shell_out("dscl", ".", "-#{args[0]}", args[1..]) return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 ) raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") unless result.exitstatus == 0 - raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout =~ /No such key: / + raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout.include?("No such key: ") + result.stdout end def run_plutil(*args) - result = shell_out("plutil -#{args.join(' ')}") + result = shell_out("plutil", "-#{args[0]}", args[1..]) raise(Chef::Exceptions::PlistUtilCommandFailed, "plutil error: #{result.inspect}") unless result.exitstatus == 0 + if result.stdout.encoding == Encoding::ASCII_8BIT - result.stdout.encode("utf-8", "binary", :undef => :replace, :invalid => :replace, :replace => "?") + result.stdout.encode("utf-8", "binary", undef: :replace, invalid: :replace, replace: "?") else result.stdout end end def convert_binary_plist_to_xml(binary_plist_string) - Mixlib::ShellOut.new("plutil -convert xml1 -o - -", :input => binary_plist_string).run_command.stdout + shell_out("plutil", "-convert", "xml1", "-o", "-", "-", input: binary_plist_string).stdout end def convert_to_binary(string) @@ -682,13 +615,6 @@ user password using shadow hash.") !!(string =~ /^[[:xdigit:]]{136}$/) end - def salted_sha512_password_match? - # Salt is included in the first 4 bytes of shadow data - salt = current_resource.password.slice(0, 8) - shadow = OpenSSL::Digest::SHA512.hexdigest(convert_to_binary(salt) + new_resource.password) - current_resource.password == salt + shadow - end - def salted_sha512_pbkdf2?(string) !!(string =~ /^[[:xdigit:]]{256}$/) end @@ -701,7 +627,7 @@ user password using shadow hash.") salt, current_resource.iterations, 128, - OpenSSL::Digest::SHA512.new + OpenSSL::Digest.new("SHA512") ).unpack("H*").first == current_resource.password end |