puppet 2.6.10 → 2.6.11
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +7 -0
- data/conf/redhat/puppet.spec +5 -2
- data/lib/puppet.rb +1 -1
- data/lib/puppet/application/resource.rb +17 -10
- data/lib/puppet/provider/ssh_authorized_key/parsed.rb +10 -9
- data/lib/puppet/type/k5login.rb +3 -1
- data/spec/unit/indirector/terminus_spec.rb +3 -3
- data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +8 -8
- metadata +4 -6
- data/lib/puppet/indirector/file.rb +0 -79
- data/spec/unit/indirector/file_spec.rb +0 -181
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
2.6.11
|
2
|
+
===
|
3
|
+
e158b26 (#9793) "secure" indirector file backed terminus base class.
|
4
|
+
343c7bd (#9792) Predictable temporary filename in ralsh.
|
5
|
+
88512e8 Drop privileges before creating and chmodding SSH keys.
|
6
|
+
2775c21 (#9794) k5login can overwrite arbitrary files as root
|
7
|
+
|
1
8
|
2.6.10
|
2
9
|
===
|
3
10
|
ec5a32a Update spec and lib/puppet.rb for 2.6.10 release
|
data/conf/redhat/puppet.spec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
%global confdir conf/redhat
|
6
6
|
|
7
7
|
Name: puppet
|
8
|
-
Version: 2.6.
|
8
|
+
Version: 2.6.11
|
9
9
|
Release: 1%{?dist}
|
10
10
|
Summary: A network tool for managing many disparate systems
|
11
11
|
License: GPLv2
|
@@ -253,11 +253,14 @@ fi
|
|
253
253
|
rm -rf %{buildroot}
|
254
254
|
|
255
255
|
%changelog
|
256
|
+
* Fri Sep 30 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.6.11-1
|
257
|
+
- CVE-2011-3869, 3870, 3871
|
258
|
+
|
256
259
|
* Wed Sep 28 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.6.10-1
|
257
260
|
- Fix for CVE-2011-3484
|
258
261
|
|
259
262
|
* Tue Jun 21 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.6.9-1
|
260
|
-
- Release of 2.6.9
|
263
|
+
- Release of 2.6.9
|
261
264
|
|
262
265
|
* Wed Jun 15 2011 Todd Zullinger <tmz@pobox.com> - 2.6.9-0.1.rc1
|
263
266
|
- Update rc versioning to ensure 2.6.9 final is newer to rpm
|
data/lib/puppet.rb
CHANGED
@@ -85,18 +85,25 @@ class Puppet::Application::Resource < Puppet::Application
|
|
85
85
|
end.map(&format).join("\n")
|
86
86
|
|
87
87
|
if options[:edit]
|
88
|
-
|
88
|
+
require 'tempfile'
|
89
|
+
# Prefer the current directory, which is more likely to be secure
|
90
|
+
# and, in the case of interactive use, accessible to the user.
|
91
|
+
tmpfile = Tempfile.new('x2puppet', Dir.pwd)
|
89
92
|
begin
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
system("
|
93
|
+
# sync write, so nothing buffers before we invoke the editor.
|
94
|
+
tmpfile.sync = true
|
95
|
+
tmpfile.puts text
|
96
|
+
|
97
|
+
# edit the content
|
98
|
+
system(ENV["EDITOR"] || 'vi', tmpfile.path)
|
99
|
+
|
100
|
+
# ...and, now, pass that file to puppet to apply. Because
|
101
|
+
# many editors rename or replace the original file we need to
|
102
|
+
# feed the pathname, not the file content itself, to puppet.
|
103
|
+
system('puppet -v ' + tmpfile.path)
|
96
104
|
ensure
|
97
|
-
#
|
98
|
-
|
99
|
-
#end
|
105
|
+
# The temporary file will be safely removed.
|
106
|
+
tmpfile.close(true)
|
100
107
|
end
|
101
108
|
else
|
102
109
|
puts text
|
@@ -56,21 +56,22 @@ require 'puppet/provider/parsedfile'
|
|
56
56
|
def flush
|
57
57
|
raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
|
58
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)
|
63
|
-
end
|
64
|
-
|
65
59
|
# ParsedFile usually calls backup_target much later in the flush process,
|
66
60
|
# but our SUID makes that fail to open filebucket files for writing.
|
67
61
|
# Fortunately, there's already logic to make sure it only ever happens once,
|
68
62
|
# so calling it here supresses the later attempt by our superclass's flush method.
|
69
63
|
self.class.backup_target(target)
|
70
64
|
|
71
|
-
Puppet::Util::SUIDManager.asuser(@resource.should(:user))
|
72
|
-
|
73
|
-
|
65
|
+
Puppet::Util::SUIDManager.asuser(@resource.should(:user)) do
|
66
|
+
unless File.exist?(dir = File.dirname(target))
|
67
|
+
Puppet.debug "Creating #{dir}"
|
68
|
+
Dir.mkdir(dir, dir_perm)
|
69
|
+
end
|
70
|
+
|
71
|
+
super
|
72
|
+
|
73
|
+
File.chmod(file_perm, target)
|
74
|
+
end
|
74
75
|
end
|
75
76
|
|
76
77
|
# parse sshv2 option strings, wich is a comma separated list of
|
data/lib/puppet/type/k5login.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
4
4
|
require 'puppet/defaults'
|
5
5
|
require 'puppet/indirector'
|
6
|
-
require 'puppet/indirector/
|
6
|
+
require 'puppet/indirector/memory'
|
7
7
|
|
8
8
|
describe Puppet::Indirector::Terminus do
|
9
9
|
before :each do
|
@@ -202,14 +202,14 @@ describe Puppet::Indirector::Terminus, " when parsing class constants for indire
|
|
202
202
|
@subclass.expects(:indirection=).with(:test_ind)
|
203
203
|
@subclass.stubs(:name=)
|
204
204
|
@subclass.stubs(:terminus_type=)
|
205
|
-
Puppet::Indirector::
|
205
|
+
Puppet::Indirector::Memory.inherited(@subclass)
|
206
206
|
end
|
207
207
|
|
208
208
|
it "should convert the indirection name to a downcased symbol" do
|
209
209
|
@subclass.expects(:indirection=).with(:test_ind)
|
210
210
|
@subclass.stubs(:name=)
|
211
211
|
@subclass.stubs(:terminus_type=)
|
212
|
-
Puppet::Indirector::
|
212
|
+
Puppet::Indirector::Memory.inherited(@subclass)
|
213
213
|
end
|
214
214
|
|
215
215
|
it "should convert camel case to lower case with underscores as word separators" do
|
@@ -133,15 +133,15 @@ describe provider_class do
|
|
133
133
|
@provider.flush
|
134
134
|
end
|
135
135
|
|
136
|
-
it "should chown the directory to the user" do
|
136
|
+
it "should absolutely not chown the directory to the user" do
|
137
137
|
uid = Puppet::Util.uid("random_bob")
|
138
|
-
File.expects(:chown).
|
138
|
+
File.expects(:chown).never
|
139
139
|
@provider.flush
|
140
140
|
end
|
141
141
|
|
142
|
-
it "should chown the key file to the user" do
|
142
|
+
it "should absolutely not chown the key file to the user" do
|
143
143
|
uid = Puppet::Util.uid("random_bob")
|
144
|
-
File.expects(:chown).
|
144
|
+
File.expects(:chown).never
|
145
145
|
@provider.flush
|
146
146
|
end
|
147
147
|
|
@@ -177,11 +177,11 @@ describe provider_class do
|
|
177
177
|
@provider.flush
|
178
178
|
end
|
179
179
|
|
180
|
-
it "should chown the directory to the user if it creates it" do
|
180
|
+
it "should absolutely not chown the directory to the user if it creates it" do
|
181
181
|
File.stubs(:exist?).with(@dir).returns false
|
182
182
|
Dir.stubs(:mkdir).with(@dir,0700)
|
183
183
|
uid = Puppet::Util.uid("nobody")
|
184
|
-
File.expects(:chown).
|
184
|
+
File.expects(:chown).never
|
185
185
|
@provider.flush
|
186
186
|
end
|
187
187
|
|
@@ -192,9 +192,9 @@ describe provider_class do
|
|
192
192
|
@provider.flush
|
193
193
|
end
|
194
194
|
|
195
|
-
it "should chown the key file to the user" do
|
195
|
+
it "should absolutely not chown the key file to the user" do
|
196
196
|
uid = Puppet::Util.uid("nobody")
|
197
|
-
File.expects(:chown).
|
197
|
+
File.expects(:chown).never
|
198
198
|
@provider.flush
|
199
199
|
end
|
200
200
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 2.6.
|
9
|
+
- 11
|
10
|
+
version: 2.6.11
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Puppet Labs
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-09-
|
18
|
+
date: 2011-09-30 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: facter
|
@@ -159,7 +159,6 @@ files:
|
|
159
159
|
- lib/puppet/indirector/facts/memory.rb
|
160
160
|
- lib/puppet/indirector/facts/rest.rb
|
161
161
|
- lib/puppet/indirector/facts/yaml.rb
|
162
|
-
- lib/puppet/indirector/file.rb
|
163
162
|
- lib/puppet/indirector/file_bucket_file/file.rb
|
164
163
|
- lib/puppet/indirector/file_bucket_file/rest.rb
|
165
164
|
- lib/puppet/indirector/file_content/file.rb
|
@@ -1091,7 +1090,6 @@ files:
|
|
1091
1090
|
- spec/unit/indirector/file_metadata/file_spec.rb
|
1092
1091
|
- spec/unit/indirector/file_metadata/rest_spec.rb
|
1093
1092
|
- spec/unit/indirector/file_server_spec.rb
|
1094
|
-
- spec/unit/indirector/file_spec.rb
|
1095
1093
|
- spec/unit/indirector/indirection_spec.rb
|
1096
1094
|
- spec/unit/indirector/key/ca_spec.rb
|
1097
1095
|
- spec/unit/indirector/key/file_spec.rb
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'puppet/indirector/terminus'
|
2
|
-
|
3
|
-
# Store instances as files, usually serialized using some format.
|
4
|
-
class Puppet::Indirector::File < Puppet::Indirector::Terminus
|
5
|
-
# Where do we store our data?
|
6
|
-
def data_directory
|
7
|
-
name = Puppet.run_mode.master? ? :server_datadir : :client_datadir
|
8
|
-
|
9
|
-
File.join(Puppet.settings[name], self.class.indirection_name.to_s)
|
10
|
-
end
|
11
|
-
|
12
|
-
def file_format(path)
|
13
|
-
path =~ /\.(\w+)$/ and return $1
|
14
|
-
end
|
15
|
-
|
16
|
-
def file_path(request)
|
17
|
-
File.join(data_directory, request.key + ".#{serialization_format}")
|
18
|
-
end
|
19
|
-
|
20
|
-
def latest_path(request)
|
21
|
-
files = Dir.glob(File.join(data_directory, request.key + ".*"))
|
22
|
-
return nil if files.empty?
|
23
|
-
|
24
|
-
# Return the newest file.
|
25
|
-
files.sort { |a, b| File.stat(b).mtime <=> File.stat(a).mtime }[0]
|
26
|
-
end
|
27
|
-
|
28
|
-
def serialization_format
|
29
|
-
model.default_format
|
30
|
-
end
|
31
|
-
|
32
|
-
# Remove files on disk.
|
33
|
-
def destroy(request)
|
34
|
-
begin
|
35
|
-
removed = false
|
36
|
-
Dir.glob(File.join(data_directory, request.key.to_s + ".*")).each do |file|
|
37
|
-
removed = true
|
38
|
-
File.unlink(file)
|
39
|
-
end
|
40
|
-
rescue => detail
|
41
|
-
raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
|
42
|
-
end
|
43
|
-
|
44
|
-
raise Puppet::Error, "Could not find files for #{request.key} to remove" unless removed
|
45
|
-
end
|
46
|
-
|
47
|
-
# Return a model instance for a given file on disk.
|
48
|
-
def find(request)
|
49
|
-
return nil unless path = latest_path(request)
|
50
|
-
format = file_format(path)
|
51
|
-
|
52
|
-
raise ArgumentError, "File format #{format} is not supported by #{self.class.indirection_name}" unless model.support_format?(format)
|
53
|
-
|
54
|
-
begin
|
55
|
-
return model.convert_from(format, File.read(path))
|
56
|
-
rescue => detail
|
57
|
-
raise Puppet::Error, "Could not convert path #{path} into a #{self.class.indirection_name}: #{detail}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Save a new file to disk.
|
62
|
-
def save(request)
|
63
|
-
path = file_path(request)
|
64
|
-
|
65
|
-
dir = File.dirname(path)
|
66
|
-
|
67
|
-
raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless File.directory?(dir)
|
68
|
-
|
69
|
-
begin
|
70
|
-
File.open(path, "w") { |f| f.print request.instance.render(serialization_format) }
|
71
|
-
rescue => detail
|
72
|
-
raise Puppet::Error, "Could not write #{request.key}: #{detail}" % [request.key, detail]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def path(key)
|
77
|
-
key
|
78
|
-
end
|
79
|
-
end
|
@@ -1,181 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.dirname(__FILE__) + '/../../spec_helper'
|
4
|
-
require 'puppet/indirector/file'
|
5
|
-
|
6
|
-
|
7
|
-
describe Puppet::Indirector::File do
|
8
|
-
before :each do
|
9
|
-
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
|
10
|
-
@model = mock 'model'
|
11
|
-
@indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
|
12
|
-
Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
|
13
|
-
|
14
|
-
@file_class = Class.new(Puppet::Indirector::File) do
|
15
|
-
def self.to_s
|
16
|
-
"Testing::Mytype"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
@searcher = @file_class.new
|
21
|
-
|
22
|
-
@path = "/my/file"
|
23
|
-
@dir = "/my"
|
24
|
-
|
25
|
-
@request = stub 'request', :key => @path
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "when finding files" do
|
29
|
-
it "should provide a method to return file contents at a specified path" do
|
30
|
-
@searcher.should respond_to(:find)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should use the server data directory plus the indirection name if the run_mode is master" do
|
34
|
-
Puppet.run_mode.expects(:master?).returns true
|
35
|
-
Puppet.settings.expects(:value).with(:server_datadir).returns "/my/dir"
|
36
|
-
|
37
|
-
@searcher.data_directory.should == File.join("/my/dir", "mystuff")
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should use the client data directory plus the indirection name if the run_mode is not master" do
|
41
|
-
Puppet.run_mode.expects(:master?).returns false
|
42
|
-
Puppet.settings.expects(:value).with(:client_datadir).returns "/my/dir"
|
43
|
-
|
44
|
-
@searcher.data_directory.should == File.join("/my/dir", "mystuff")
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should use the newest file in the data directory matching the indirection key without extension" do
|
48
|
-
@searcher.expects(:data_directory).returns "/data/dir"
|
49
|
-
@request.stubs(:key).returns "foo"
|
50
|
-
Dir.expects(:glob).with("/data/dir/foo.*").returns %w{/data1.stuff /data2.stuff}
|
51
|
-
|
52
|
-
stat1 = stub 'data1', :mtime => (Time.now - 5)
|
53
|
-
stat2 = stub 'data2', :mtime => Time.now
|
54
|
-
File.expects(:stat).with("/data1.stuff").returns stat1
|
55
|
-
File.expects(:stat).with("/data2.stuff").returns stat2
|
56
|
-
|
57
|
-
@searcher.latest_path(@request).should == "/data2.stuff"
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should return nil when no files are found" do
|
61
|
-
@searcher.stubs(:latest_path).returns nil
|
62
|
-
|
63
|
-
@searcher.find(@request).should be_nil
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should determine the file format from the file extension" do
|
67
|
-
@searcher.file_format("/data2.pson").should == "pson"
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should fail if the model does not support the file format" do
|
71
|
-
@searcher.stubs(:latest_path).returns "/my/file.pson"
|
72
|
-
|
73
|
-
@model.expects(:support_format?).with("pson").returns false
|
74
|
-
|
75
|
-
lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "when saving files" do
|
80
|
-
before do
|
81
|
-
@content = "my content"
|
82
|
-
@file = stub 'file', :content => @content, :path => @path, :name => @path, :render => "mydata"
|
83
|
-
@request.stubs(:instance).returns @file
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should provide a method to save file contents at a specified path" do
|
87
|
-
@searcher.should respond_to(:save)
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should choose the file extension based on the default format of the model" do
|
91
|
-
@model.expects(:default_format).returns "pson"
|
92
|
-
|
93
|
-
@searcher.serialization_format.should == "pson"
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should place the file in the data directory, named after the indirection, key, and format" do
|
97
|
-
@searcher.stubs(:data_directory).returns "/my/dir"
|
98
|
-
@searcher.stubs(:serialization_format).returns "pson"
|
99
|
-
|
100
|
-
@request.stubs(:key).returns "foo"
|
101
|
-
@searcher.file_path(@request).should == File.join("/my/dir", "foo.pson")
|
102
|
-
end
|
103
|
-
|
104
|
-
it "should fail intelligently if the file's parent directory does not exist" do
|
105
|
-
@searcher.stubs(:file_path).returns "/my/dir/file.pson"
|
106
|
-
@searcher.stubs(:serialization_format).returns "pson"
|
107
|
-
|
108
|
-
@request.stubs(:key).returns "foo"
|
109
|
-
File.expects(:directory?).with(File.join("/my/dir")).returns(false)
|
110
|
-
|
111
|
-
proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should render the instance using the file format and print it to the file path" do
|
115
|
-
@searcher.stubs(:file_path).returns "/my/file.pson"
|
116
|
-
@searcher.stubs(:serialization_format).returns "pson"
|
117
|
-
|
118
|
-
File.stubs(:directory?).returns true
|
119
|
-
|
120
|
-
@request.instance.expects(:render).with("pson").returns "data"
|
121
|
-
|
122
|
-
fh = mock 'filehandle'
|
123
|
-
File.expects(:open).with("/my/file.pson", "w").yields fh
|
124
|
-
fh.expects(:print).with("data")
|
125
|
-
|
126
|
-
@searcher.save(@request)
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should fail intelligently if a file cannot be written" do
|
130
|
-
filehandle = mock 'file'
|
131
|
-
File.stubs(:directory?).returns(true)
|
132
|
-
File.stubs(:open).yields(filehandle)
|
133
|
-
filehandle.expects(:print).raises(ArgumentError)
|
134
|
-
|
135
|
-
@searcher.stubs(:file_path).returns "/my/file.pson"
|
136
|
-
@model.stubs(:default_format).returns "pson"
|
137
|
-
|
138
|
-
@instance.stubs(:render).returns "stuff"
|
139
|
-
|
140
|
-
proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
describe "when removing files" do
|
145
|
-
it "should provide a method to remove files" do
|
146
|
-
@searcher.should respond_to(:destroy)
|
147
|
-
end
|
148
|
-
|
149
|
-
it "should remove files in all formats found in the data directory that match the request key" do
|
150
|
-
@searcher.stubs(:data_directory).returns "/my/dir"
|
151
|
-
@request.stubs(:key).returns "me"
|
152
|
-
|
153
|
-
Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one /two}
|
154
|
-
|
155
|
-
File.expects(:unlink).with("/one")
|
156
|
-
File.expects(:unlink).with("/two")
|
157
|
-
|
158
|
-
@searcher.destroy(@request)
|
159
|
-
end
|
160
|
-
|
161
|
-
it "should throw an exception if no file is found" do
|
162
|
-
@searcher.stubs(:data_directory).returns "/my/dir"
|
163
|
-
@request.stubs(:key).returns "me"
|
164
|
-
|
165
|
-
Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns []
|
166
|
-
|
167
|
-
proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
|
168
|
-
end
|
169
|
-
|
170
|
-
it "should fail intelligently if a file cannot be removed" do
|
171
|
-
@searcher.stubs(:data_directory).returns "/my/dir"
|
172
|
-
@request.stubs(:key).returns "me"
|
173
|
-
|
174
|
-
Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one}
|
175
|
-
|
176
|
-
File.expects(:unlink).with("/one").raises ArgumentError
|
177
|
-
|
178
|
-
proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|