{"record":{"id":"db0703982dda7ae9","repo":"puppetlabs/puppet","slug":"os-x-10-7-requires-a-salted-sha512-hash-password-o","errorCode":null,"errorMessage":"OS X 10.7 requires a Salted SHA512 hash password of 136 characters.  Please check your password and try again.","messagePattern":"OS X 10\\.7 requires a Salted SHA512 hash password of 136 characters\\.  Please check your password and try again\\.","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/provider/user/directoryservice.rb","lineNumber":357,"sourceCode":"      merge_attribute_with_dscl('Groups', group, 'GroupMembership', @resource.name)\n      merge_attribute_with_dscl('Groups', group, 'GroupMembers', guid)\n    end\n  end\n\n  # If you thought GETTING a password was bad, try SETTING it. This method\n  # makes me want to cry. A thousand tears...\n  #\n  # I've been unsuccessful in tracking down a way to set the password for\n  # a user using dscl that DOESN'T require passing it as plaintext. We were\n  # also unable to get dsimport to work like this. Due to these downfalls,\n  # the sanest method requires opening the user's plist, dropping in the\n  # password hash, and serializing it back to disk. The problems with THIS\n  # method revolve around dscl. Any time you directly modify a user's plist,\n  # you need to flush the cache that dscl maintains.\n  def password=(value)\n    if self.class.get_os_version == '10.7'\n      if value.length != 136\n        raise Puppet::Error, \"OS X 10.7 requires a Salted SHA512 hash password of 136 characters.  Please check your password and try again.\"\n      end\n    else\n      if value.length != 256\n        raise Puppet::Error, \"OS X versions > 10.7 require a Salted SHA512 PBKDF2 password hash of 256 characters. Please check your password and try again.\"\n      end\n\n      assert_full_pbkdf2_password\n    end\n\n    # Methods around setting the password on OS X are the ONLY methods that\n    # cannot use dscl (because the only way to set it via dscl is by passing\n    # a plaintext password - which is bad). Because of this, we have to change\n    # the user's plist directly. DSCL has its own caching mechanism, which\n    # means that every time we call dscl in this provider we're not directly\n    # changing values on disk (instead, those calls are cached and written\n    # to disk according to Apple's prioritization algorithms). When Puppet\n    # needs to set the password property on OS X > 10.6, the provider has to\n    # tell dscl to write its cache to disk before modifying the user's","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/provider/user/directoryservice.rb#L339-L375","documentation":"Raised by Puppet's macOS DirectoryService user provider on OS X 10.7 when the `password` property value is not exactly 136 characters — the length of a salted SHA-512 hash as Apple stores it in the 10.7 ShadowHashData plist. The provider validates length before writing the plist, because it cannot set passwords via dscl without plaintext.","triggerScenarios":"Managing `password` on an OS X 10.7 user and supplying a plaintext password, a SHA-512 hex digest without salt (128 chars), or the newer 256-char PBKDF2 hash instead of the required 136-char salted SHA-512 form.","commonSituations":"Manifests written for 10.8+ (PBKDF2) reused on 10.7; Linux-style crypt strings passed through; salt/format omitted when generating the hash with OpenSSL.","solutions":["Generate a correct salted SHA-512: salt (up to 8 chars) + SHA-512(salt+password) hex — verify total length is 136 characters.","Do not pass plaintext; the provider writes the hash directly into the user's plist.","Keep OS-version-specific password data in Hiera keyed by os.major, or gate the password property with an `if` on the OS version.","If you cannot produce a 10.7-format hash, manage the password outside Puppet (e.g., MDM) on those hosts."],"exampleFix":"# before (10.7 node)\nuser { 'alice': ensure => present, password => 'plaintext-or-128-char-hash' }\n# after - 136-char salted SHA512 (salt 'abcdefgh' + 128-hex digest)\nuser { 'alice': ensure => present, password => 'abcdefgh<128 hex chars...>' }","handlingStrategy":"type-guard","validationCode":"raise 'expected 136 chars' unless hash.length == 136","typeGuard":"def valid_salted_sha512_10_7?(hash)\n  hash.is_a?(String) && hash.length == 136 && hash.match?(/\\A[0-9a-fA-F]+\\z/)\nend","tryCatchPattern":null,"preventionTips":["Generate the salted SHA-512 programmatically and assert 136 length in CI.","Key password data by OS version in Hiera.","Never pass plaintext to `password` on the directoryservice provider."],"tags":["macos","user-management","password-hash","puppet"],"backgroundTag":"password-hash-format-invalid","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}