Skip to content

Instantly share code, notes, and snippets.

@glarizza
Created August 15, 2012 20:54
Show Gist options
  • Save glarizza/3363581 to your computer and use it in GitHub Desktop.
Save glarizza/3363581 to your computer and use it in GitHub Desktop.
Setting the password in 10.7 by editing the plist
require 'puppet'
require 'facter/util/plist'
require 'stringio'
require 'base64'
def convert_xml_to_binary(plist_data)
# This method will accept a hash that has been returned from Plist::parse_xml
# and convert it to a binary plist (string value).
Puppet.debug('Converting XML plist to binary')
Puppet.debug('Executing: \'plutil -convert binary1 -o - -\'')
IO.popen('plutil -convert binary1 -o - -', mode='r+') do |io|
io.write Plist::Emit.dump(plist_data)
io.close_write
@converted_plist = io.read
end
@converted_plist
end
def convert_binary_to_xml(plist_data)
# This method will accept a binary plist (as a string) and convert it to a
# hash via Plist::parse_xml.
Puppet.debug('Converting binary plist to XML')
Puppet.debug('Executing: \'plutil -convert xml1 -o - -\'')
IO.popen('plutil -convert xml1 -o - -', mode='r+') do |io|
io.write plist_data
io.close_write
@converted_plist = io.read
end
Puppet.debug('Converting XML values to a hash.')
@plist_hash = Plist::parse_xml(@converted_plist)
@plist_hash
end
def write_password_to_users_plist(users_plist, value)
shadow_hash_data = get_shadow_hash_data(users_plist)
set_salted_sha512(users_plist, shadow_hash_data, value)
end
def get_shadow_hash_data(users_plist)
if users_plist['ShadowHashData']
password_hash_plist = users_plist['ShadowHashData'][0].string
convert_binary_to_xml(password_hash_plist)
else
false
end
end
def set_salted_sha512(users_plist, shadow_hash_data, value)
shadow_hash_data = Hash.new unless shadow_hash_data
shadow_hash_data['SALTED-SHA512'].string = Base64.decode64([[value].pack("H*")].pack("m").strip)
binary_plist = convert_xml_to_binary(shadow_hash_data)
users_plist['ShadowHashData'][0].string = binary_plist
write_users_plist_to_disk(users_plist)
end
def users_plist_dir
'/var/db/dslocal/nodes/Default/users'
end
def write_users_plist_to_disk(users_plist)
puts users_plist
puts "#{users_plist_dir}/#{@resource}.plist"
Plist::Emit.save_plist(users_plist, "#{users_plist_dir}/#{@resource}.plist")
`/usr/bin/plutil -convert binary1 "#{users_plist_dir}/#{@resource}.plist`
# Restart directoryservices or opendirectoryd
# OR dscacheutil -cachedump
# OR sleep 5
end
def get_attribute_from_dscl(path, keyname)
# Perform a dscl lookup at the path specified for the specific keyname
# value. The value returned is the first item within the array returned
# from dscl
puts "/usr/bin/dscl -plist . read /#{path}/#{@resource} #{keyname}"
Plist.parse_xml(`/usr/bin/dscl -plist . read /#{path}/#{@resource} #{keyname}`)
end
def get_embedded_binary_plist(shadow_hash_data)
# The plist embedded in the ShadowHashData key is a binary plist. The
# facter/util/plist library doesn't read binary plists, so we need to
# extract the binary plist, convert it to XML, and return it.
embedded_binary_plist = Array(shadow_hash_data['dsAttrTypeNative:ShadowHashData'][0].delete(' ')).pack('H*')
convert_binary_to_xml(embedded_binary_plist)
end
def get_salted_sha512(embedded_binary_plist)
# The salted-SHA512 password hash in 10.7 is stored in the 'SALTED-SHA512'
# key as binary data. That data is extracted and converted to a hex string.
embedded_binary_plist['SALTED-SHA512'].string.unpack("H*")[0]
end
@resource = 'jeff'
value = "7ea7d592131f57b2c8f8bdbcec8d9df12128a386393a4f00c7619bac2622a44d451419d11da512d5915ab98e39718ac94083fe2efd6bf710a54d477f8ff735b12587192d"
## Get the password
shadow_hash_data = get_attribute_from_dscl('Users', 'ShadowHashData')
embedded_binary_plist = get_embedded_binary_plist(shadow_hash_data)
the_password = get_salted_sha512(embedded_binary_plist)
## Set the password
users_plist = Plist::parse_xml(`plutil -convert xml1 -o /dev/stdout /var/db/dslocal/nodes/Default/users/jeff.plist`)
write_password_to_users_plist(users_plist, value)
## Get the password again
shadow_hash_data = get_attribute_from_dscl('Users', 'ShadowHashData')
embedded_binary_plist = get_embedded_binary_plist(shadow_hash_data)
the_password = get_salted_sha512(embedded_binary_plist)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment