Index | Thread | Search

From:
Klemens Nanni <kn@openbsd.org>
Subject:
puppet: user resource: fix changing passwords
To:
ports <ports@openbsd.org>, Sebastian Reitenbach <sebastia@openbsd.org>
Date:
Thu, 28 Aug 2025 22:37:31 +0000

Download raw body.

Thread
  • Klemens Nanni:

    puppet: user resource: fix changing passwords

The problem:

	$ cat test.pp
	user { 'test':
		# echo secret | encrypt
		password => '$2b$08$ZN1ywlySByQ79VoNNzHT5.riIraLxU/LVfXonHuPimCIyIAcNMArO';
	}

	# puppet apply ./test.pp
	Warning: Facter: Unable to getenv for pid 1, 'uninitialized constant Facter::Util::Linux'
	Notice: Compiled catalog for atar in environment production in 0.02 seconds
	Error: Could not set password on user[test]: No command chpasswd defined for provider openbsd
	Error: /Stage[main]/Main/User[test]/password: change from [redacted] to [redacted] failed: Could not set password on 	user[test]: No command chpasswd defined for provider openbsd
	Notice: Applied catalog in 0.01 seconds


We don't have chpasswd, so nothing is executed to change the password.

Current code expects a new value on stdin, so they create a tempfile, etc.

Our usermod(8) -p takes it as argument and, as confimed by ktrace, Puppet
executes the command directly without shell, so use that instead:

	# make update
	# puppet apply ./test.pp
	Warning: Facter: Unable to getenv for pid 1, 'uninitialized constant Facter::Util::Linux'
	Notice: Compiled catalog for atar in environment production in 0.02 seconds
	Notice: /Stage[main]/Main/User[test]/password: changed [redacted] to [redacted]
	Notice: Applied catalog in 0.05 seconds

master.passwd(5) now gets updated correctly.

Puppet 7 has the same issue, but is EOL since 2025, so I'd rather remove it.

Feedback? OK?


Index: Makefile
===================================================================
RCS file: /cvs/ports/sysutils/ruby-puppet/8/Makefile,v
diff -u -p -r1.6 Makefile
--- Makefile	28 Jun 2025 00:36:32 -0000	1.6
+++ Makefile	27 Aug 2025 20:33:30 -0000
@@ -1,7 +1,7 @@
 PORTROACH=		limit:^8
 
 VERSION=		8.10.0
-REVISION=		0
+REVISION=		1
 
 RUN_DEPENDS+=		converters/ruby-multi_json,${MODRUBY_FLAVOR}>=1.13,<2 \
 			devel/ruby-concurrent-ruby,${MODRUBY_FLAVOR}>=1,<2 \
Index: patches/patch-lib_puppet_provider_user_useradd_rb
===================================================================
RCS file: patches/patch-lib_puppet_provider_user_useradd_rb
diff -N patches/patch-lib_puppet_provider_user_useradd_rb
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ patches/patch-lib_puppet_provider_user_useradd_rb	28 Aug 2025 22:07:49 -0000
@@ -0,0 +1,41 @@
+Use usermod(8) -p to update to fix changing a user's password.
+
+Index: lib/puppet/provider/user/useradd.rb
+--- lib/puppet/provider/user/useradd.rb.orig
++++ lib/puppet/provider/user/useradd.rb
+@@ -14,7 +14,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => 
+     To use the `forcelocal` parameter, you need to install the `libuser` package (providing
+     `/usr/sbin/lgroupadd` and `/usr/sbin/luseradd`)."
+ 
+-  commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "chage", :chpasswd => "chpasswd"
++  commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "chage", :chpasswd => "usermod"
+ 
+   options :home, :flag => "-d", :method => :dir
+   options :comment, :method => :gecos
+@@ -189,25 +189,14 @@ Puppet::Type.type(:user).provide :useradd, :parent => 
+     user = @resource[:name]
+     tempfile = Tempfile.new('puppet', :encoding => Encoding::UTF_8)
+     begin
+-      # Puppet execute does not support strings as input, only files.
+-      # The password is expected to be in an encrypted format given -e is specified:
+-      tempfile << "#{user}:#{value}\n"
+-      tempfile.flush
+-
+-      # Options '-e' use encrypted password
+-      # Must receive "user:enc_password" as input
+-      # command, arguments = {:failonfail => true, :combine => true}
+-      cmd = [command(:chpasswd), '-e']
++      cmd = [command(:chpasswd), '-p', value, user]
+       execute_options = {
+         :failonfail => false,
+         :combine => true,
+-        :stdinfile => tempfile.path,
+         :sensitive => has_sensitive_data?
+       }
+       output = execute(cmd, execute_options)
+     rescue => detail
+-      tempfile.close
+-      tempfile.delete
+       raise Puppet::Error, "Could not set password on #{@resource.class.name}[#{@resource.name}]: #{detail}", detail.backtrace
+     end
+