{"record":{"id":"b17c0dc507de829e","repo":"puppetlabs/puppet","slug":"failed-to-adjust-process-privileges","errorCode":null,"errorMessage":"Failed to adjust process privileges","messagePattern":"Failed to adjust process privileges","errorType":"exception","errorClass":"Puppet::Util::Windows::Error","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/windows/security.rb","lineNumber":572,"sourceCode":"    Puppet::Util::Windows::Process.with_process_token(TOKEN_ADJUST_PRIVILEGES) do |token|\n      Puppet::Util::Windows::Process.lookup_privilege_value(privilege) do |luid|\n        FFI::MemoryPointer.new(Puppet::Util::Windows::Process::LUID_AND_ATTRIBUTES.size) do |luid_and_attributes_ptr|\n          # allocate unmanaged memory for structs that we clean up afterwards\n          luid_and_attributes = Puppet::Util::Windows::Process::LUID_AND_ATTRIBUTES.new(luid_and_attributes_ptr)\n          luid_and_attributes[:Luid] = luid\n          luid_and_attributes[:Attributes] = enable ? SE_PRIVILEGE_ENABLED : 0\n\n          FFI::MemoryPointer.new(Puppet::Util::Windows::Process::TOKEN_PRIVILEGES.size) do |token_privileges_ptr|\n            token_privileges = Puppet::Util::Windows::Process::TOKEN_PRIVILEGES.new(token_privileges_ptr)\n            token_privileges[:PrivilegeCount] = 1\n            token_privileges[:Privileges][0] = luid_and_attributes\n\n            # size is correct given we only have 1 LUID, otherwise would be:\n            # [:PrivilegeCount].size + [:PrivilegeCount] * LUID_AND_ATTRIBUTES.size\n            if AdjustTokenPrivileges(token, FFI::WIN32_FALSE,\n                                     token_privileges, token_privileges.size,\n                                     FFI::MemoryPointer::NULL, FFI::MemoryPointer::NULL) == FFI::WIN32_FALSE\n              raise Puppet::Util::Windows::Error, _(\"Failed to adjust process privileges\")\n            end\n          end\n        end\n      end\n    end\n\n    # token / luid structs freed by this point, so return true as nothing raised\n    true\n  end\n\n  def get_security_descriptor(path)\n    sd = nil\n\n    with_privilege(SE_BACKUP_NAME) do\n      open_file(path, READ_CONTROL) do |handle|\n        FFI::MemoryPointer.new(:pointer, 1) do |owner_sid_ptr_ptr|\n          FFI::MemoryPointer.new(:pointer, 1) do |group_sid_ptr_ptr|\n            FFI::MemoryPointer.new(:pointer, 1) do |dacl_ptr_ptr|","sourceCodeStart":554,"sourceCodeEnd":590,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/windows/security.rb#L554-L590","documentation":"Raised when AdjustTokenPrivileges returns FALSE while with_privilege tries to enable SE_BACKUP_NAME or SE_RESTORE_NAME in the process token. The function only returns FALSE for hard failures (invalid handle, invalid LUID); note the classic trap that it can also 'succeed' while not assigning the privilege, which this check does not catch. It fires whenever Puppet needs backup/restore privileges to read or write security descriptors.","triggerScenarios":"Any set_security_descriptor / get_security_descriptor path that calls with_privilege, when OpenProcessToken or LookupPrivilegeValue produced an unusable handle/LUID, or the FFI call itself fails. Most often seen when the process token simply does not possess SeBackupPrivilege/SeRestorePrivilege in a degraded token.","commonSituations":"Running Puppet or custom Ruby code from a non-elevated shell on UAC systems (filtered token lacks the privileges); running as a service account without the required user rights; scripts that drop privileges before managing ACLs.","solutions":["Run the process elevated as local Administrator (whoami /priv should list SeBackupPrivilege and SeRestorePrivilege)","If a service account is used, grant it the 'Back up files and directories' and 'Restore files and directories' user rights via Local Security Policy","Check e.code on the error for the concrete Win32 reason","Verify privileges at startup with whoami /priv before attempting ACL work"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  Puppet::Util::Windows::Security.set_security_descriptor(path, sd)\nrescue Puppet::Util::Windows::Error => e\n  if e.message.include?('Failed to adjust process privileges')\n    raise Puppet::Error, 'ACL write needs an elevated token with SeBackupPrivilege/SeRestorePrivilege'\n  end\n  raise\nend","preventionTips":["Verify required privileges at startup: whoami /priv must list SeBackupPrivilege and SeRestorePrivilege","Run ACL work from an elevated process; UAC-filtered tokens lack the privileges","Grant service accounts 'Back up files and directories' / 'Restore files and directories' rights explicitly"],"tags":["windows","privileges","security","win32","elevation"],"backgroundTag":"windows-privilege-not-held","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}