1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
require 'puppet/provider/parsedfile'
Puppet::Type.type(:ssh_authorized_key).provide(
:parsed,
:parent => Puppet::Provider::ParsedFile,
:filetype => :flat,
:default_target => ''
) do
desc "Parse and generate authorized_keys files for SSH."
text_line :comment, :match => /^#/
text_line :blank, :match => /^\s+/
record_line :parsed,
:fields => %w{options type key name},
:optional => %w{options},
:rts => /^\s+/,
:match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/,
:post_parse => proc { |h|
h[:name] = "" if h[:name] == :absent
h[:options] ||= [:absent]
h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
},
:pre_gen => proc { |h|
h[:options] = [] if h[:options].include?(:absent)
h[:options] = h[:options].join(',')
}
record_line :key_v1,
:fields => %w{options bits exponent modulus name},
:optional => %w{options},
:rts => /^\s+/,
:match => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/
def dir_perm
0700
end
def file_perm
0600
end
def target
begin
@resource.should(:target) || File.expand_path("~#{@resource.should(:user)}/.ssh/authorized_keys")
rescue
raise Puppet::Error, "Target not defined and/or specified user does not exist yet"
end
end
def user
uid = File.stat(target).uid
Etc.getpwuid(uid).name
end
def flush
raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
unless File.exist?(dir = File.dirname(target))
Puppet.debug "Creating #{dir}"
Dir.mkdir(dir, dir_perm)
File.chown(uid, nil, dir)
end
Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
File.chown(uid, nil, target)
File.chmod(file_perm, target)
end
# parse sshv2 option strings, wich is a comma separated list of
# either key="values" elements or bare-word elements
def self.parse_options(options)
result = []
scanner = StringScanner.new(options)
while !scanner.eos?
scanner.skip(/[ \t]*/)
# scan a long option
if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
result << out
else
# found an unscannable token, let's abort
break
end
# eat a comma
scanner.skip(/[ \t]*,[ \t]*/)
end
result
end
end
|