1
require 'puppet/provider/parsedfile'
4
Puppet::Type.type(:ssh_authorized_key).provide(
6
:parent => Puppet::Provider::ParsedFile,
11
desc "Parse and generate authorized_keys files for SSH."
13
text_line :comment, :match => /^#/
14
text_line :blank, :match => /^\s+/
17
:fields => %w{options type key name},
18
:optional => %w{options},
20
:match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/,
21
:post_parse => proc { |h|
22
h[:name] = "" if h[:name] == :absent
23
h[:options] ||= [:absent]
24
h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
26
:pre_gen => proc { |h|
27
h[:options] = [] if h[:options].include?(:absent)
28
h[:options] = h[:options].join(',')
32
:fields => %w{options bits exponent modulus name},
33
:optional => %w{options},
35
:match => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/
46
@resource.should(:target) || File.expand_path("~#{@resource.should(:user)}/.ssh/authorized_keys")
48
raise Puppet::Error, "Target not defined and/or specified user does not exist yet"
52
uid = File.stat(target).uid
53
Etc.getpwuid(uid).name
57
raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
58
raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
59
unless File.exist?(dir = File.dirname(target))
60
Puppet.debug "Creating #{dir}"
61
Dir.mkdir(dir, dir_perm)
62
File.chown(uid, nil, dir)
65
# ParsedFile usually calls backup_target much later in the flush process,
66
# but our SUID makes that fail to open filebucket files for writing.
67
# Fortunately, there's already logic to make sure it only ever happens once,
68
# so calling it here supresses the later attempt by our superclass's flush method.
69
self.class.backup_target(target)
71
Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
72
File.chown(uid, nil, target)
73
File.chmod(file_perm, target)
76
# parse sshv2 option strings, wich is a comma separated list of
77
# either key="values" elements or bare-word elements
78
def self.parse_options(options)
80
scanner = StringScanner.new(options)
82
scanner.skip(/[ \t]*/)
84
if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
87
# found an unscannable token, let's abort
91
scanner.skip(/[ \t]*,[ \t]*/)