{"record":{"id":"c5633d338c4da008","repo":"puppetlabs/puppet","slug":"could-not-read-password-hash-file-at-password-ha","errorCode":null,"errorMessage":"Could not read password hash file at #{password_hash_file}","messagePattern":"Could not read password hash file at #(.+?)","errorType":"exception","errorClass":"Puppet::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/provider/user/directoryservice.rb","lineNumber":237,"sourceCode":"      if value.nil?\n        raise Puppet::Error, \"Invalid #{field} given for user #{user_name}\"\n      end\n\n      value.unpack1('H*')\n    when 'iterations'\n      Integer(embedded_binary_plist['SALTED-SHA512-PBKDF2'][field])\n    else\n      raise Puppet::Error, \"Puppet has tried to read an incorrect value from the user #{user_name} in the SALTED-SHA512-PBKDF2 hash. Acceptable fields are 'salt', 'entropy', or 'iterations'.\"\n    end\n  end\n\n  # In versions 10.5 and 10.6 of OS X, the password hash is stored in a file\n  # in the /var/db/shadow/hash directory that matches the GUID of the user.\n  def self.get_sha1(guid)\n    password_hash = nil\n    password_hash_file = \"#{password_hash_dir}/#{guid}\"\n    if Puppet::FileSystem.exist?(password_hash_file) and File.file?(password_hash_file)\n      raise Puppet::Error, \"Could not read password hash file at #{password_hash_file}\" unless File.readable?(password_hash_file)\n\n      f = File.new(password_hash_file)\n      password_hash = f.read\n      f.close\n    end\n    password_hash\n  end\n\n  ##                   ##\n  ## Ensurable Methods ##\n  ##                   ##\n\n  def exists?\n    begin\n      dscl '.', 'read', \"/Users/#{@resource.name}\"\n    rescue Puppet::ExecutionFailure => e\n      Puppet.debug(\"User was not found, dscl returned: #{e.inspect}\")\n      return false","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/provider/user/directoryservice.rb#L219-L255","documentation":"Raised by Puppet's macOS DirectoryService user provider when the OS X 10.5/10.6 password hash file (/var/db/shadow/hash/<GUID>) exists and is a regular file, but File.readable? returns false — the process lacks read permission on it. get_sha1 then refuses to read and raises instead of silently returning nil.","triggerScenarios":"Reading/inspecting a 10.5–10.6 user's password hash when the agent runs as a non-root user, or the file's mode/ACL was tightened (these shadow files are normally root-only), or filesystem damage changed ownership.","commonSituations":"Puppet agent accidentally running as non-root; security hardening scripts that chmod 000 /var/db/shadow/hash/*; migrated volumes with wrong ownership.","solutions":["Run the Puppet agent as root (macOS password management requires it).","Check and restore expected ownership/permissions: `ls -l /var/db/shadow/hash/` — files are typically 0400 root:wheel.","Verify readability as root: `sudo head -c 4 /var/db/shadow/hash/<GUID>`.","If the hardening change was intentional, exclude these paths or stop managing passwords on those legacy systems."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"file = '/var/db/shadow/hash/<GUID>'\nif File.exist?(file)\n  File.readable?(file) or raise 'not readable - run agent as root'\nend","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run the Puppet agent as root on macOS.","Do not harden /var/db/shadow/hash to exclude root; keep root:wheel 0400-style ownership.","On modern macOS (10.7+), this path is legacy — avoid password inspection flows that hit it."],"tags":["macos","file-permissions","password-hash","puppet"],"backgroundTag":"file-read-permission-denied","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}