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 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
@@ -5,7 +5,7 @@
5
5
  %global confdir conf/redhat
6
6
 
7
7
  Name: puppet
8
- Version: 2.6.10
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
@@ -24,7 +24,7 @@ require 'puppet/util/run_mode'
24
24
  # it's also a place to find top-level commands like 'debug'
25
25
 
26
26
  module Puppet
27
- PUPPETVERSION = '2.6.10'
27
+ PUPPETVERSION = '2.6.11'
28
28
 
29
29
  def Puppet.version
30
30
  PUPPETVERSION
@@ -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
- file = "/tmp/x2puppet-#{Process.pid}.pp"
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
- File.open(file, "w") do |f|
91
- f.puts text
92
- end
93
- ENV["EDITOR"] ||= "vi"
94
- system(ENV["EDITOR"], file)
95
- system("puppet -v #{file}")
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
- #if FileTest.exists? file
98
- # File.unlink(file)
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)) { super }
72
- File.chown(uid, nil, target)
73
- File.chmod(file_perm, target)
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
@@ -79,7 +79,9 @@ Puppet::Type.newtype(:k5login) do
79
79
 
80
80
  private
81
81
  def write(value)
82
- File.open(@resource[:name], "w") { |f| f.puts value.join("\n") }
82
+ Puppet::Util.secure_open(@resource[:name], "w") do |f|
83
+ f.puts value.join("\n")
84
+ end
83
85
  end
84
86
  end
85
87
  end
@@ -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/file'
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::File.inherited(@subclass)
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::File.inherited(@subclass)
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).with(uid, nil, "/tmp/.ssh_dir")
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).with(uid, nil, "/tmp/.ssh_dir/place_to_put_authorized_keys")
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).with(uid, nil, @dir)
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).with(uid, nil, File.expand_path("~nobody/.ssh/authorized_keys"))
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: 3
4
+ hash: 1
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 6
9
- - 10
10
- version: 2.6.10
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-28 00:00:00 Z
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