puppetlabs/puppet · error · Puppet::Error

OS X versions > 10.7 require a Salted SHA512 PBKDF2 password

Error message

OS X versions > 10.7 require a Salted SHA512 PBKDF2 password hash of 256 characters. Please check your password and try again.

What it means

Raised by Puppet's macOS DirectoryService user provider on OS X newer than 10.7 when the `password` property value is not exactly 256 characters — the combined length of a Salted SHA-512 PBKDF2 hash (salt + entropy hex + iterations segments as the provider concatenates them). After the length check, assert_full_pbkdf2_password additionally verifies all three components are present.

Source

Thrown at lib/puppet/provider/user/directoryservice.rb:361

  # If you thought GETTING a password was bad, try SETTING it. This method
  # makes me want to cry. A thousand tears...
  #
  # I've been unsuccessful in tracking down a way to set the password for
  # a user using dscl that DOESN'T require passing it as plaintext. We were
  # also unable to get dsimport to work like this. Due to these downfalls,
  # the sanest method requires opening the user's plist, dropping in the
  # password hash, and serializing it back to disk. The problems with THIS
  # method revolve around dscl. Any time you directly modify a user's plist,
  # you need to flush the cache that dscl maintains.
  def password=(value)
    if self.class.get_os_version == '10.7'
      if value.length != 136
        raise Puppet::Error, "OS X 10.7 requires a Salted SHA512 hash password of 136 characters.  Please check your password and try again."
      end
    else
      if value.length != 256
        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."
      end

      assert_full_pbkdf2_password
    end

    # Methods around setting the password on OS X are the ONLY methods that
    # cannot use dscl (because the only way to set it via dscl is by passing
    # a plaintext password - which is bad). Because of this, we have to change
    # the user's plist directly. DSCL has its own caching mechanism, which
    # means that every time we call dscl in this provider we're not directly
    # changing values on disk (instead, those calls are cached and written
    # to disk according to Apple's prioritization algorithms). When Puppet
    # needs to set the password property on OS X > 10.6, the provider has to
    # tell dscl to write its cache to disk before modifying the user's
    # plist. The 'dscacheutil -flushcache' command does this. Another issue
    # is how fast Puppet makes calls to dscl and how long it takes dscl to
    # enter those calls into its cache. We have to sleep for 2 seconds before
    # flushing the dscl cache to allow all dscl calls to get INTO the cache

View on GitHub (pinned to e227c27540)

Solutions

  1. Generate the full PBKDF2 form: iterations + 64-hex-char salt + 128-hex-char entropy, concatenated to exactly 256 characters.
  2. Extract a working example from an existing user: `dscl . -read /Users/<name> ShadowHashData` and hex-decode to confirm the layout.
  3. Version your password data in Hiera by OS version so 10.7 and 10.8+ hosts get the right format.
  4. Ensure assert_full_pbkdf2_password passes by including all three parts, not just the digest.

Example fix

# before (macOS 10.8+)
user { 'alice': ensure => present, password => 'abcdefgh<128 hex chars>' }  # 136 chars, 10.7 format
# after - 256 chars: iterations(3) + salt(64 hex) + entropy(128 hex) ... total 256
user { 'alice': ensure => present, password => lookup('users::alice::pbkdf2_hash', Sensitive) }
Defensive patterns

Strategy: type-guard

Validate before calling

raise 'expected 256 chars' unless hash.length == 256
parts = hash.partition_valid_pbkdf2  # salt(64) + entropy(128) + iterations present

Type guard

def valid_pbkdf2_256?(hash)
  hash.is_a?(String) && hash.length == 256 && hash.match?(/\A[0-9a-fA-F]+\z/)
end

Prevention

When it happens

Trigger: Managing `password` on macOS >= 10.8 with a 136-char 10.7-style salted SHA-512 hash, a plaintext string, or a PBKDF2 value missing a component so the concatenated form is the wrong length.

Common situations: Old manifests from 10.7 carried forward after an OS upgrade; hashes generated with wrong output length (e.g., truncated entropy); omitting the iterations segment.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/665f68cc35168e3c. Report an issue: GitHub.