Created
August 14, 2012 23:59
-
-
Save glarizza/3354042 to your computer and use it in GitHub Desktop.
Setting the password with dsimport
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | |
| ## Setting the Password with dsimport | |
| @resource = 'jeff' | |
| value = "7ea7d592131f57b2c8f8bdbcec8d9df12128a386393a4f00c7619bac2622a44d451419d11da512d5915ab98e39718ac94083fe2efd6bf710a54d477f8ff735b12587192d" | |
| binary_password_value = Base64.decode64([[value].pack("H*")].pack("m").strip) | |
| archive_hash = Hash.new | |
| archive_hash = { 'SALTED-SHA512' => StringIO.new } | |
| archive_hash['SALTED-SHA512'].string = binary_password_value | |
| binary_archive_hash = convert_xml_to_binary(archive_hash) | |
| tmpdir = Dir.mktmpdir | |
| password_file = File.join(tmpdir, 'binary_password') | |
| cached_source = File.join(tmpdir, 'dsimportfile') | |
| #junk = Marshal.dump(binary_archive_hash) | |
| File.open(password_file, 'w') { |file| file.write(binary_archive_hash) } | |
| File.open(cached_source, 'w') { |file| file.write("0x0A 0x5C 0x3A 0x2C dsRecTypeStandard:Users 2 dsAttrTypeStandard:RecordName externalbinary:dsAttrTypeStandard:ShadowHashData \n#{@resource}:#{password_file}") } | |
| `/usr/bin/dsimport #{cached_source} /Local/Default O` | |
| ## Get the password from disk using dscl | |
| shadow_hash_data = Plist.parse_xml(`/usr/bin/dscl -plist . read /Users/jeff ShadowHashData`) | |
| binary_plist = Array(shadow_hash_data['dsAttrTypeNative:ShadowHashData'][0].delete(' ')).pack('H*') | |
| embedded_binary_plist = convert_binary_to_xml(binary_plist) | |
| key_from_disk = embedded_binary_plist['SALTED-SHA512'].string.unpack("H*")[0] | |
| ## Back out the data we calculated in the first block | |
| backed_out_plist = convert_binary_to_xml(binary_archive_hash) | |
| key_from_backup = backed_out_plist['SALTED-SHA512'].string.unpack("H*")[0] | |
| ## They don't match | |
| puts 'THEY MATCH' if key_from_backup == key_from_disk | |
| ## Read the data we JUST wrote to disk and compare the keys: | |
| ## Read from disk | |
| data_from_disk = File.open(password_file, "rb").read | |
| converted_plist = convert_binary_to_xml(data_from_disk) | |
| key_from_file = converted_plist['SALTED-SHA512'].string.unpack("H*")[0] | |
| ## Yes, this is a match | |
| puts "Sure are!" if key_from_file == value | |
| ## Okay, so let's try just modifying the user's plist | |
| users_plist = Plist::parse_xml(`plutil -convert xml1 -o /dev/stdout /var/db/dslocal/nodes/Default/users/jeff.plist`) | |
| password_hash_plist = users_plist['ShadowHashData'][0].string | |
| converted_hash_plist = convert_binary_to_xml(password_hash_plist) | |
| #converted_hash_plist['SALTED-SHA512'].string = value.unpack('a2'*(value.size/2)).collect { |i| i.hex.chr }.join | |
| converted_hash_plist['SALTED-SHA512'].string = Base64.decode64([[value].pack("H*")].pack("m").strip) | |
| changed_plist = convert_xml_to_binary(converted_hash_plist) | |
| users_plist['ShadowHashData'][0].string = changed_plist | |
| Plist::Emit.save_plist(users_plist, '/var/db/dslocal/nodes/Default/users/jeff.plist') | |
| `plutil -convert binary1 /var/db/dslocal/nodes/Default/users/jeff.plist` | |
| ## Great, now read directly from the plist | |
| get_plist = Plist::parse_xml(`plutil -convert xml1 -o /dev/stdout /var/db/dslocal/nodes/Default/users/jeff.plist`) | |
| get_password_hash_plist = get_plist['ShadowHashData'][0].string | |
| get_converted_hash_plist = convert_binary_to_xml(get_password_hash_plist) | |
| get_password_hash = get_converted_hash_plist['SALTED-SHA512'].string.unpack("H*")[0] | |
| ## Do they match? Yes they do. | |
| puts "THEY MATCH" if value == get_password_hash | |
| ## Now, let's read from DSCL again... | |
| shadow_hash_data = Plist.parse_xml(`/usr/bin/dscl -plist . read /Users/jeff ShadowHashData`) | |
| binary_plist = Array(shadow_hash_data['dsAttrTypeNative:ShadowHashData'][0].delete(' ')).pack('H*') | |
| embedded_binary_plist = convert_binary_to_xml(binary_plist) | |
| key_from_disk = embedded_binary_plist['SALTED-SHA512'].string.unpack("H*")[0] | |
| ## Do they match? Yes they do. | |
| puts "THEY MATCH" if value == key_from_disk | |
| ## In summary, we're setting incorrectly with dsimport | |
| ## Reading from dscl the correct value: | |
| #62706c69 73743030 d101025d 53414c54 45442d53 48413531 324f1044 7ea7d592 131f57b2 c8f8bdbc ec8d9df1 2128a386 393a4f00 c7619bac 2622a44d 451419d1 #1da512d5 915ab98e 39718ac9 4083fe2e fd6bf710 a54d477f 8ff735b1 2587192d 080b1900 00000000 00010100 00000000 00000300 00000000 00000000 00000000 000060 | |
| ## Reading from dscl with the INCORRECT value: | |
| #62706c69 73743030 d101025d 53414c54 45442d53 48413531 324f1044 4ebb58ad e6e87d16 2a410d01 685acbe0 2a8ba79a 4791327b ca153a67 86578057 6df98883 #37b33eca ede269f5 77c81d6b e96456df cf9f34d6 a6f1d919 03f46052 0e878346 080b1900 00000000 00010100 00000000 00000300 00000000 00000000 00000000 000060 | |
| delete this gist | |
| Comments are parsed with GitHub Flavored Markdown | |
| Write |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment