puppet 2.7.4 → 2.7.5

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,13 @@
1
+ 2.7.5
2
+ ===
3
+ a36f39d Updating version numbers for 2.7.5
4
+ de51f3d (#9832) 2.7.4 StoreConfigs regression with PostgreSQL.
5
+ 1aa9be5 (#9793) "secure" indirector file backed terminus base class.
6
+ d76c309 (#9792) Predictable temporary filename in ralsh. (CVE-2011-3871)
7
+ b29b178 Drop privileges before creating and chmodding SSH keys.(CVE-2011-3870)
8
+ 7d4c169 (#9794) k5login can overwrite arbitrary files as root (CVE-2011-3869)
9
+
10
+
1
11
  2.7.4
2
12
  ===
3
13
  47135fb Resist directory traversal attacks through indirections. (CVE-2011-3484)
@@ -5,8 +5,8 @@
5
5
  %global confdir conf/redhat
6
6
 
7
7
  Name: puppet
8
- Version: 2.7.2
9
- Release: 0.2.rc1%{?dist}
8
+ Version: 2.7.5
9
+ Release: 1%{?dist}
10
10
  Summary: A network tool for managing many disparate systems
11
11
  License: ASL 2.0
12
12
  URL: http://puppetlabs.com
@@ -282,6 +282,12 @@ fi
282
282
  rm -rf %{buildroot}
283
283
 
284
284
  %changelog
285
+ * Fri Sep 30 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.5-1
286
+ - Fixes for CVE-2011-3869, 3870, 3871
287
+
288
+ * Wed Sep 28 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.4-1
289
+ - Fix for CVE-2011-3484
290
+
285
291
  * Wed Jul 06 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.2-0.2.rc1
286
292
  - Clean up rpmlint errors
287
293
  - Put man pages in correct package
@@ -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.7.4'
27
+ PUPPETVERSION = '2.7.5'
28
28
 
29
29
  def Puppet.version
30
30
  PUPPETVERSION
@@ -190,18 +190,25 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
190
190
  end.map(&format).join("\n")
191
191
 
192
192
  if options[:edit]
193
- file = "/tmp/x2puppet-#{Process.pid}.pp"
193
+ require 'tempfile'
194
+ # Prefer the current directory, which is more likely to be secure
195
+ # and, in the case of interactive use, accessible to the user.
196
+ tmpfile = Tempfile.new('x2puppet', Dir.pwd)
194
197
  begin
195
- File.open(file, "w") do |f|
196
- f.puts text
197
- end
198
- ENV["EDITOR"] ||= "vi"
199
- system(ENV["EDITOR"], file)
200
- system("puppet -v #{file}")
198
+ # sync write, so nothing buffers before we invoke the editor.
199
+ tmpfile.sync = true
200
+ tmpfile.puts text
201
+
202
+ # edit the content
203
+ system(ENV["EDITOR"] || 'vi', tmpfile.path)
204
+
205
+ # ...and, now, pass that file to puppet to apply. Because
206
+ # many editors rename or replace the original file we need to
207
+ # feed the pathname, not the file content itself, to puppet.
208
+ system('puppet -v ' + tmpfile.path)
201
209
  ensure
202
- #if FileTest.exists? file
203
- # File.unlink(file)
204
- #end
210
+ # The temporary file will be safely removed.
211
+ tmpfile.close(true)
205
212
  end
206
213
  else
207
214
  puts text
@@ -62,7 +62,10 @@ class Puppet::Resource::ActiveRecord < Puppet::Indirector::ActiveRecord
62
62
  # Some versions of ActiveRecord just to_s a symbol, which our type is, but
63
63
  # others preserve the symbol-nature, which causes our storage (string) and
64
64
  # query (symbol) to mismatch. So, manually stringify. --daniel 2011-09-08
65
- arguments = [true, type.to_s]
65
+ #
66
+ # Also, PostgreSQL is case sensitive; we need to make sure our type name
67
+ # here matches what we inject. --daniel 2011-09-30
68
+ arguments = [true, type.to_s.capitalize]
66
69
 
67
70
  if filter then
68
71
  sql, values = filter_to_active_record(filter)
@@ -50,21 +50,22 @@ require 'puppet/provider/parsedfile'
50
50
  def flush
51
51
  raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
52
52
  raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
53
- unless File.exist?(dir = File.dirname(target))
54
- Puppet.debug "Creating #{dir}"
55
- Dir.mkdir(dir, dir_perm)
56
- File.chown(uid, nil, dir)
57
- end
58
-
59
53
  # ParsedFile usually calls backup_target much later in the flush process,
60
54
  # but our SUID makes that fail to open filebucket files for writing.
61
55
  # Fortunately, there's already logic to make sure it only ever happens once,
62
56
  # so calling it here supresses the later attempt by our superclass's flush method.
63
57
  self.class.backup_target(target)
64
58
 
65
- Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
66
- File.chown(uid, nil, target)
67
- File.chmod(file_perm, target)
59
+ Puppet::Util::SUIDManager.asuser(@resource.should(:user)) do
60
+ unless File.exist?(dir = File.dirname(target))
61
+ Puppet.debug "Creating #{dir}"
62
+ Dir.mkdir(dir, dir_perm)
63
+ end
64
+
65
+ super
66
+
67
+ File.chmod(file_perm, target)
68
+ end
68
69
  end
69
70
 
70
71
  # 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
@@ -70,7 +70,7 @@ describe "Puppet::Resource::ActiveRecord", :if => (Puppet.features.rails? and de
70
70
  host = Puppet::Rails::Host.create!(:name => 'one.local')
71
71
  Puppet::Rails::Resource.
72
72
  create!(:host => host,
73
- :restype => 'exec', :title => 'whammo',
73
+ :restype => 'Exec', :title => 'whammo',
74
74
  :exported => true)
75
75
 
76
76
  end
@@ -80,12 +80,12 @@ describe "Puppet::Resource::ActiveRecord", :if => (Puppet.features.rails? and de
80
80
  found.length.should == 1
81
81
  found.map do |item|
82
82
  item.should respond_to :to_resource
83
- item.restype.should == "exec"
83
+ item.restype.should == "Exec"
84
84
  end
85
85
  end
86
86
 
87
87
  it "should not filter resources that have been found before" do
88
- search("exec").should == search("exec")
88
+ search("Exec").should == search("Exec")
89
89
  end
90
90
  end
91
91
  end
@@ -137,7 +137,12 @@ describe "Puppet::Resource::ActiveRecord", :if => (Puppet.features.rails? and de
137
137
  got.keys.should =~ [:conditions]
138
138
  got[:conditions][0].should be_include "(exported=? AND restype=?)"
139
139
  got[:conditions][1].should == true
140
- got[:conditions][2].should == type.to_s
140
+ got[:conditions][2].should == type.to_s.capitalize
141
+ end
142
+
143
+ it "should capitalize the type, since PGSQL is case sensitive" do
144
+ got = query(type, 'whatever')
145
+ got[:conditions][2].should == 'Notify'
141
146
  end
142
147
  end
143
148
 
@@ -2,7 +2,7 @@
2
2
  require 'spec_helper'
3
3
  require 'puppet/defaults'
4
4
  require 'puppet/indirector'
5
- require 'puppet/indirector/file'
5
+ require 'puppet/indirector/memory'
6
6
 
7
7
  describe Puppet::Indirector::Terminus, :'fails_on_ruby_1.9.2' => true do
8
8
  before :each do
@@ -201,14 +201,14 @@ describe Puppet::Indirector::Terminus, " when parsing class constants for indire
201
201
  @subclass.expects(:indirection=).with(:test_ind)
202
202
  @subclass.stubs(:name=)
203
203
  @subclass.stubs(:terminus_type=)
204
- Puppet::Indirector::File.inherited(@subclass)
204
+ Puppet::Indirector::Memory.inherited(@subclass)
205
205
  end
206
206
 
207
207
  it "should convert the indirection name to a downcased symbol" do
208
208
  @subclass.expects(:indirection=).with(:test_ind)
209
209
  @subclass.stubs(:name=)
210
210
  @subclass.stubs(:terminus_type=)
211
- Puppet::Indirector::File.inherited(@subclass)
211
+ Puppet::Indirector::Memory.inherited(@subclass)
212
212
  end
213
213
 
214
214
  it "should convert camel case to lower case with underscores as word separators" do
@@ -110,15 +110,15 @@ describe provider_class, :unless => Puppet.features.microsoft_windows? do
110
110
  @provider.flush
111
111
  end
112
112
 
113
- it "should chown the directory to the user" do
113
+ it "should absolutely not chown the directory to the user" do
114
114
  uid = Puppet::Util.uid("random_bob")
115
- File.expects(:chown).with(uid, nil, "/tmp/.ssh_dir")
115
+ File.expects(:chown).never
116
116
  @provider.flush
117
117
  end
118
118
 
119
- it "should chown the key file to the user" do
119
+ it "should absolutely not chown the key file to the user" do
120
120
  uid = Puppet::Util.uid("random_bob")
121
- File.expects(:chown).with(uid, nil, "/tmp/.ssh_dir/place_to_put_authorized_keys")
121
+ File.expects(:chown).never
122
122
  @provider.flush
123
123
  end
124
124
 
@@ -153,11 +153,11 @@ describe provider_class, :unless => Puppet.features.microsoft_windows? do
153
153
  @provider.flush
154
154
  end
155
155
 
156
- it "should chown the directory to the user if it creates it" do
156
+ it "should absolutely not chown the directory to the user if it creates it" do
157
157
  File.stubs(:exist?).with(@dir).returns false
158
158
  Dir.stubs(:mkdir).with(@dir,0700)
159
159
  uid = Puppet::Util.uid("nobody")
160
- File.expects(:chown).with(uid, nil, @dir)
160
+ File.expects(:chown).never
161
161
  @provider.flush
162
162
  end
163
163
 
@@ -168,9 +168,9 @@ describe provider_class, :unless => Puppet.features.microsoft_windows? do
168
168
  @provider.flush
169
169
  end
170
170
 
171
- it "should chown the key file to the user" do
171
+ it "should absolutely not chown the key file to the user" do
172
172
  uid = Puppet::Util.uid("nobody")
173
- File.expects(:chown).with(uid, nil, File.expand_path("~nobody/.ssh/authorized_keys"))
173
+ File.expects(:chown).never
174
174
  @provider.flush
175
175
  end
176
176
 
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: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
8
  - 7
9
- - 4
10
- version: 2.7.4
9
+ - 5
10
+ version: 2.7.5
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
@@ -215,7 +215,6 @@ files:
215
215
  - lib/puppet/indirector/facts/rest.rb
216
216
  - lib/puppet/indirector/facts/store_configs.rb
217
217
  - lib/puppet/indirector/facts/yaml.rb
218
- - lib/puppet/indirector/file.rb
219
218
  - lib/puppet/indirector/file_bucket_file/file.rb
220
219
  - lib/puppet/indirector/file_bucket_file/rest.rb
221
220
  - lib/puppet/indirector/file_content/file.rb
@@ -1332,7 +1331,6 @@ files:
1332
1331
  - spec/unit/indirector/file_metadata/file_spec.rb
1333
1332
  - spec/unit/indirector/file_metadata/rest_spec.rb
1334
1333
  - spec/unit/indirector/file_server_spec.rb
1335
- - spec/unit/indirector/file_spec.rb
1336
1334
  - spec/unit/indirector/indirection_spec.rb
1337
1335
  - spec/unit/indirector/inventory/yaml_spec.rb
1338
1336
  - spec/unit/indirector/key/ca_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,179 +0,0 @@
1
- #!/usr/bin/env rspec
2
- require 'spec_helper'
3
- require 'puppet/indirector/file'
4
-
5
-
6
- describe Puppet::Indirector::File do
7
- before :all do
8
- Puppet::Indirector::Terminus.stubs(:register_terminus_class)
9
- @model = mock 'model'
10
- @indirection = stub 'indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model
11
- Puppet::Indirector::Indirection.stubs(:instance).returns(@indirection)
12
-
13
- module Testing; end
14
- @file_class = class Testing::MyFile < Puppet::Indirector::File
15
- self
16
- end
17
-
18
- @searcher = @file_class.new
19
-
20
- @path = "/my/file"
21
- @dir = "/my"
22
-
23
- @request = stub 'request', :key => @path
24
- end
25
-
26
- describe "when finding files" do
27
- it "should provide a method to return file contents at a specified path" do
28
- @searcher.should respond_to(:find)
29
- end
30
-
31
- it "should use the server data directory plus the indirection name if the run_mode is master" do
32
- Puppet.run_mode.expects(:master?).returns true
33
- Puppet.settings.expects(:value).with(:server_datadir).returns "/my/dir"
34
-
35
- @searcher.data_directory.should == File.join("/my/dir", "mystuff")
36
- end
37
-
38
- it "should use the client data directory plus the indirection name if the run_mode is not master" do
39
- Puppet.run_mode.expects(:master?).returns false
40
- Puppet.settings.expects(:value).with(:client_datadir).returns "/my/dir"
41
-
42
- @searcher.data_directory.should == File.join("/my/dir", "mystuff")
43
- end
44
-
45
- it "should use the newest file in the data directory matching the indirection key without extension" do
46
- @searcher.expects(:data_directory).returns "/data/dir"
47
- @request.stubs(:key).returns "foo"
48
- Dir.expects(:glob).with("/data/dir/foo.*").returns %w{/data1.stuff /data2.stuff}
49
-
50
- stat1 = stub 'data1', :mtime => (Time.now - 5)
51
- stat2 = stub 'data2', :mtime => Time.now
52
- File.expects(:stat).with("/data1.stuff").returns stat1
53
- File.expects(:stat).with("/data2.stuff").returns stat2
54
-
55
- @searcher.latest_path(@request).should == "/data2.stuff"
56
- end
57
-
58
- it "should return nil when no files are found" do
59
- @searcher.stubs(:latest_path).returns nil
60
-
61
- @searcher.find(@request).should be_nil
62
- end
63
-
64
- it "should determine the file format from the file extension" do
65
- @searcher.file_format("/data2.pson").should == "pson"
66
- end
67
-
68
- it "should fail if the model does not support the file format" do
69
- @searcher.stubs(:latest_path).returns "/my/file.pson"
70
-
71
- @model.expects(:support_format?).with("pson").returns false
72
-
73
- lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
74
- end
75
- end
76
-
77
- describe "when saving files" do
78
- before do
79
- @content = "my content"
80
- @file = stub 'file', :content => @content, :path => @path, :name => @path, :render => "mydata"
81
- @request.stubs(:instance).returns @file
82
- end
83
-
84
- it "should provide a method to save file contents at a specified path" do
85
- @searcher.should respond_to(:save)
86
- end
87
-
88
- it "should choose the file extension based on the default format of the model" do
89
- @model.expects(:default_format).returns "pson"
90
-
91
- @searcher.serialization_format.should == "pson"
92
- end
93
-
94
- it "should place the file in the data directory, named after the indirection, key, and format" do
95
- @searcher.stubs(:data_directory).returns "/my/dir"
96
- @searcher.stubs(:serialization_format).returns "pson"
97
-
98
- @request.stubs(:key).returns "foo"
99
- @searcher.file_path(@request).should == File.join("/my/dir", "foo.pson")
100
- end
101
-
102
- it "should fail intelligently if the file's parent directory does not exist" do
103
- @searcher.stubs(:file_path).returns "/my/dir/file.pson"
104
- @searcher.stubs(:serialization_format).returns "pson"
105
-
106
- @request.stubs(:key).returns "foo"
107
- File.expects(:directory?).with(File.join("/my/dir")).returns(false)
108
-
109
- proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
110
- end
111
-
112
- it "should render the instance using the file format and print it to the file path" do
113
- @searcher.stubs(:file_path).returns "/my/file.pson"
114
- @searcher.stubs(:serialization_format).returns "pson"
115
-
116
- File.stubs(:directory?).returns true
117
-
118
- @request.instance.expects(:render).with("pson").returns "data"
119
-
120
- fh = mock 'filehandle'
121
- File.expects(:open).with("/my/file.pson", "w").yields fh
122
- fh.expects(:print).with("data")
123
-
124
- @searcher.save(@request)
125
- end
126
-
127
- it "should fail intelligently if a file cannot be written" do
128
- filehandle = mock 'file'
129
- File.stubs(:directory?).returns(true)
130
- File.stubs(:open).yields(filehandle)
131
- filehandle.expects(:print).raises(ArgumentError)
132
-
133
- @searcher.stubs(:file_path).returns "/my/file.pson"
134
- @model.stubs(:default_format).returns "pson"
135
-
136
- @instance.stubs(:render).returns "stuff"
137
-
138
- proc { @searcher.save(@request) }.should raise_error(Puppet::Error)
139
- end
140
- end
141
-
142
- describe "when removing files" do
143
- it "should provide a method to remove files" do
144
- @searcher.should respond_to(:destroy)
145
- end
146
-
147
- it "should remove files in all formats found in the data directory that match the request key" do
148
- @searcher.stubs(:data_directory).returns "/my/dir"
149
- @request.stubs(:key).returns "me"
150
-
151
- Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one /two}
152
-
153
- File.expects(:unlink).with("/one")
154
- File.expects(:unlink).with("/two")
155
-
156
- @searcher.destroy(@request)
157
- end
158
-
159
- it "should throw an exception if no file is found" do
160
- @searcher.stubs(:data_directory).returns "/my/dir"
161
- @request.stubs(:key).returns "me"
162
-
163
- Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns []
164
-
165
- proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
166
- end
167
-
168
- it "should fail intelligently if a file cannot be removed" do
169
- @searcher.stubs(:data_directory).returns "/my/dir"
170
- @request.stubs(:key).returns "me"
171
-
172
- Dir.expects(:glob).with(File.join("/my/dir", "me.*")).returns %w{/one}
173
-
174
- File.expects(:unlink).with("/one").raises ArgumentError
175
-
176
- proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error)
177
- end
178
- end
179
- end