diff --git a/lib/puppet/provider/gpgkey/gpgme.rb b/lib/puppet/provider/gpgkey/gpgme.rb index 4e50828..4b71da4 100644 --- a/lib/puppet/provider/gpgkey/gpgme.rb +++ b/lib/puppet/provider/gpgkey/gpgme.rb @@ -1,36 +1,85 @@ Puppet::Type.type(:gpgkey).provide(:gpgme) do + # This provider uses the new API of the gpgme-2.0.0 gem. require 'gpgme' + def exists? - ! GPGME::Key.find(:secret, keyname()).empty? + run_as_user do + Process.exit!(GPGME::Key.find(:secret, keyname()).empty? ? 1 : 0) + end == 0 end def create - ctx = GPGME::Ctx.new - keydata = "\n" - keydata += "Key-Type: " +@resource.value(:keytype)+"\n" - keydata += "Key-Length: " +@resource.value(:keylength)+"\n" - keydata += "Subkey-Type: " +@resource.value(:subkeytype)+"\n" - keydata += "Subkey-Length: " +@resource.value(:subkeylength)+"\n" - keydata += "Name-Real: " +@resource.value(:name)+"\n" - keydata += "Name-Comment: " +keyname()+"\n" - keydata += "Name-Email: " +@resource.value(:email)+"\n" - keydata += "Expire-Date: " +@resource.value(:expire)+"\n" - keydata += "Passphrase: " +@resource.value(:password)+"\n" - keydata += "\n" - - ctx.genkey(keydata, nil, nil) + run_as_user do + GPGME::Ctx.new do |ctx| + keydata = "\n" + keydata += "Key-Type: " +@resource.value(:keytype)+"\n" + keydata += "Key-Length: " +@resource.value(:keylength)+"\n" + keydata += "Subkey-Type: " +@resource.value(:subkeytype)+"\n" + keydata += "Subkey-Length: " +@resource.value(:subkeylength)+"\n" + keydata += "Name-Real: " +@resource.value(:name)+"\n" + keydata += "Name-Comment: " +keyname()+"\n" + keydata += "Name-Email: " +@resource.value(:email)+"\n" + keydata += "Expire-Date: " +@resource.value(:expire)+"\n" + # This parameter requires a value when present. Default is to + # not use a passphrase. + unless @resource.value(:password).empty? + keydata += "Passphrase: " +@resource.value(:password)+"\n" + end + keydata += "\n" + + ctx.genkey(keydata, nil, nil) + end + end end def destroy - GPGME::Key.find(:secret, keyname()).each do |key| - key.delete!(true) + run_as_user do + GPGME::Key.find(:secret, keyname()).each do |key| + key.delete!(true) + end end end private + def keyname keyname = 'puppet#' + @resource.value(:name) + '#' return keyname end + def run_as_user(&block) + if (pid = Process.fork).nil? + Puppet::Util::SUIDManager.change_privileges(@resource.value(:user), nil, true) + with_env(&block) + Process.exit! + else + Process.waitpid(pid) + $?.exitstatus + end + end + + def with_env(&block) + env_vars = %w{HOME GNUPGHOME} + old_env = env_vars.map { |var| ENV[var] } + + begin + ENV['HOME'] = Etc.getpwuid(Process.uid).dir + + if @resource.value(:gnupghome) + ENV['GNUPGHOME'] = @resource.value(:gnupghome) + else + ENV.delete('GNUPGHOME') + end + + Dir.chdir(ENV['HOME']) do + yield + end + ensure + old_env.each_with_index { |val, i| + var = env_vars[i] + val.nil? ? ENV.delete(var) : (ENV[var] = val) + } + end + end + end diff --git a/lib/puppet/type/gpgkey.rb b/lib/puppet/type/gpgkey.rb index 85eafaf..64799fd 100644 --- a/lib/puppet/type/gpgkey.rb +++ b/lib/puppet/type/gpgkey.rb @@ -42,4 +42,23 @@ defaultto true end + newparam(:user) do + desc <<-EOT + The user account in which the key should be managed. + The resource will automatically depend on this user. + EOT + end + + newparam(:gnupghome) do + desc <<-EOT + The GnuPG data directory in which the key should be managed. + If this is not set, GnuPG selects the directory by itself. + EOT + end + + # Autorequire the owner of the ~/.gnupg directory. + autorequire(:user) do + self[:user] + end + end diff --git a/manifests/init.pp b/manifests/init.pp index 4847fc2..44578a1 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -36,7 +36,7 @@ } package { 'gpgme': - ensure => 'instaled', + ensure => 'installed', provider => $gpgme_provider, require => Package['gnupg'] }