From 7da166afb824e00be2819267b7ffc3537754c680 Mon Sep 17 00:00:00 2001 From: Michael Merideth Date: Thu, 14 Jan 2016 14:28:39 -0700 Subject: [PATCH 1/5] mitigate client bugs CVE-2016-0777 and CVE-2016-0778 --- manifests/init.pp | 1 + templates/ssh_config.erb | 3 +++ 2 files changed, 4 insertions(+) diff --git a/manifests/init.pp b/manifests/init.pp index b06219f..9381d6f 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -22,6 +22,7 @@ class ssh ( $ssh_config_sendenv_xmodifiers = false, $ssh_config_ciphers = undef, $ssh_config_macs = undef, + $ssh_config_use_roaming = 'no', $ssh_config_template = 'ssh/ssh_config.erb', $ssh_sendenv = 'USE_DEFAULTS', $ssh_gssapiauthentication = 'yes', diff --git a/templates/ssh_config.erb b/templates/ssh_config.erb index cb8a086..61959ef 100644 --- a/templates/ssh_config.erb +++ b/templates/ssh_config.erb @@ -72,6 +72,9 @@ GSSAPIDelegateCredentials <%= @ssh_gssapidelegatecredentials %> <% if @ssh_config_forward_x11 != nil -%> ForwardX11 <%= @ssh_config_forward_x11 %> <% end -%> +<% if @ssh_config_use_roaming != nil -%> + UseRoaming <%= @ssh_config_use_roaming %> +<% end -%> <% if @ssh_config_server_alive_interval != nil -%> ServerAliveInterval <%= @ssh_config_server_alive_interval %> <% end -%> From 38260e68c47435c132b789e53dc66fbbcce8cf5e Mon Sep 17 00:00:00 2001 From: Phil Friderici Date: Fri, 15 Jan 2016 15:16:09 +0100 Subject: [PATCH 2/5] Set UseRoaming parameter only on Linux clients - add variable validation - add tests --- README.md | 6 ++++ manifests/init.pp | 15 ++++++++- spec/classes/init_spec.rb | 69 +++++++++++++++++++++++++++++++++++++++ templates/ssh_config.erb | 4 +-- 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7b6f5ab..a27f81f 100644 --- a/README.md +++ b/README.md @@ -340,6 +340,12 @@ This module sets this option to 'yes' on Linux and undef on Solaris. - *Default*: 'USE_DEFAULTS' +ssh_config_use_roaming +---------------------- +String to enable or disable UseRoaming in client configuration ssh_config. Valid values are 'yes', 'no' and 'unset'. Using 'unset' will not use (print) this configuration parameter at all. Default is set to 'no' on Linux and 'unset' on Solaris. + +- *Default*: 'USE_DEFAULTS' + sshd_client_alive_interval -------------------------- ClientAliveInterval in sshd_config. diff --git a/manifests/init.pp b/manifests/init.pp index 9381d6f..5028296 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -22,7 +22,7 @@ class ssh ( $ssh_config_sendenv_xmodifiers = false, $ssh_config_ciphers = undef, $ssh_config_macs = undef, - $ssh_config_use_roaming = 'no', + $ssh_config_use_roaming = 'USE_DEFAULTS', $ssh_config_template = 'ssh/ssh_config.erb', $ssh_sendenv = 'USE_DEFAULTS', $ssh_gssapiauthentication = 'yes', @@ -108,6 +108,7 @@ class ssh ( $default_ssh_package_source = undef $default_ssh_package_adminfile = undef $default_ssh_sendenv = true + $default_ssh_config_use_roaming = 'no' $default_sshd_config_subsystem_sftp = '/usr/libexec/openssh/sftp-server' $default_sshd_config_mode = '0600' $default_sshd_config_use_dns = 'yes' @@ -128,6 +129,7 @@ class ssh ( $default_ssh_package_source = undef $default_ssh_package_adminfile = undef $default_ssh_sendenv = true + $default_ssh_config_use_roaming = 'no' $default_ssh_config_forward_x11_trusted = 'yes' $default_sshd_config_mode = '0600' $default_sshd_config_use_dns = 'yes' @@ -165,6 +167,7 @@ class ssh ( $default_ssh_package_source = undef $default_ssh_package_adminfile = undef $default_ssh_sendenv = true + $default_ssh_config_use_roaming = 'no' $default_sshd_config_subsystem_sftp = '/usr/lib/openssh/sftp-server' $default_sshd_config_mode = '0600' $default_sshd_config_use_dns = 'yes' @@ -182,6 +185,7 @@ class ssh ( $default_ssh_config_hash_known_hosts = undef $default_ssh_sendenv = false $default_ssh_config_forward_x11_trusted = undef + $default_ssh_config_use_roaming = 'unset' $default_sshd_config_subsystem_sftp = '/usr/lib/ssh/sftp-server' $default_sshd_config_mode = '0644' $default_sshd_config_use_dns = undef @@ -338,6 +342,12 @@ class ssh ( $sshd_gssapicleanupcredentials_real = $sshd_gssapicleanupcredentials } + if $ssh_config_use_roaming == 'USE_DEFAULTS' { + $ssh_config_use_roaming_real = $default_ssh_config_use_roaming + } else { + $ssh_config_use_roaming_real = $ssh_config_use_roaming + } + if $ssh_sendenv == 'USE_DEFAULTS' { $ssh_sendenv_real = $default_ssh_sendenv } else { @@ -434,6 +444,9 @@ class ssh ( if $sshd_config_serverkeybits_real != undef { if is_integer($sshd_config_serverkeybits_real) == false { fail("ssh::sshd_config_serverkeybits must be an integer and is set to <${sshd_config_serverkeybits}>.") } } + if $ssh_config_use_roaming_real != undef { + validate_re($ssh_config_use_roaming_real, '^(yes|no|unset)$', "ssh::ssh_config_use_roaming may be either 'yes', 'no' or 'unset' and is set to <${$ssh_config_use_roaming}>.") + } if is_integer($sshd_client_alive_interval) == false { fail("ssh::sshd_client_alive_interval must be an integer and is set to <${sshd_client_alive_interval}>.") } if is_integer($sshd_client_alive_count_max) == false { fail("ssh::sshd_client_alive_count_max must be an integer and is set to <${sshd_client_alive_count_max}>.") } diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index b523bd1..2082fc3 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -59,6 +59,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { @@ -204,6 +205,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } @@ -326,6 +328,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } @@ -446,6 +449,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } @@ -567,6 +571,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } it { should contain_file('ssh_config').without_content(/^\s*MACs/) } @@ -695,6 +700,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } it { should contain_file('ssh_config').without_content(/^\s*MACs/) } @@ -825,6 +831,7 @@ describe 'ssh' do it { should contain_file('ssh_config').without_content(/^\s*ForwardAgent$/) } it { should contain_file('ssh_config').without_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) } it { should contain_file('ssh_config').without_content(/^\s*ServerAliveInterval$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } it { should contain_file('ssh_config').without_content(/^\s*MACs/) } @@ -953,6 +960,7 @@ describe 'ssh' do it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) } it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } it { should contain_file('ssh_config').without_content(/^\s*MACs/) } @@ -1062,6 +1070,7 @@ describe 'ssh' do :ssh_config_hash_known_hosts => 'yes', :ssh_config_forward_agent => 'yes', :ssh_config_forward_x11 => 'yes', + :ssh_config_use_roaming => 'yes', :ssh_config_server_alive_interval => '300', :ssh_config_sendenv_xmodifiers => true, :ssh_config_ciphers => [ 'aes128-cbc', @@ -1099,6 +1108,7 @@ describe 'ssh' do it { should contain_file('ssh_config').with_content(/^ ForwardAgent yes$/) } it { should contain_file('ssh_config').with_content(/^ ForwardX11 yes$/) } it { should contain_file('ssh_config').with_content(/^\s*GSSAPIAuthentication yes$/) } + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming yes$/) } it { should contain_file('ssh_config').with_content(/^ ServerAliveInterval 300$/) } it { should contain_file('ssh_config').with_content(/^ SendEnv XMODIFIERS$/) } it { should contain_file('ssh_config').with_content(/^\s*Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc$/) } @@ -3440,4 +3450,63 @@ describe 'ssh' do end end end + + describe 'with parameter ssh_config_use_roaming' do + let(:facts) { { :osfamily => 'RedHat' } } + + ['yes','no','unset'].each do |value| + context "set to valid value #{value}" do + let(:params) { { :ssh_config_use_roaming => value } } + if value == 'unset' + it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) } + else + it { should contain_file('ssh_config').with_content(/^\s*UseRoaming #{value}$/) } + end + end + end + end + + describe 'variable type and content validations' do + # set needed custom facts and variables + let(:facts) do + { + :osfamily => 'RedHat', + } + end + let(:mandatory_params) do + { + #:param => 'value', + } + end + + validations = { + 'regex (yes|no|unset)' => { + :name => %w(ssh_config_use_roaming), + :valid => ['yes', 'no', 'unset'], + :invalid => ['string', %w(array), { 'ha' => 'sh' }, 3, 2.42, true, false, nil], + :message => 'may be either \'yes\', \'no\' or \'unset\'', + }, + } + + validations.sort.each do |type, var| + var[:name].each do |var_name| + var[:params] = {} if var[:params].nil? + var[:valid].each do |valid| + context "when #{var_name} (#{type}) is set to valid #{valid} (as #{valid.class})" do + let(:params) { [mandatory_params, var[:params], { :"#{var_name}" => valid, }].reduce(:merge) } + it { should compile } + end + end + + var[:invalid].each do |invalid| + context "when #{var_name} (#{type}) is set to invalid #{invalid} (as #{invalid.class})" do + let(:params) { [mandatory_params, var[:params], { :"#{var_name}" => invalid, }].reduce(:merge) } + it 'should fail' do + expect { should contain_class(subject) }.to raise_error(Puppet::Error, /#{var[:message]}/) + end + end + end + end # var[:name].each + end # validations.sort.each + end # describe 'variable type and content validations' end diff --git a/templates/ssh_config.erb b/templates/ssh_config.erb index 61959ef..f34f435 100644 --- a/templates/ssh_config.erb +++ b/templates/ssh_config.erb @@ -72,8 +72,8 @@ GSSAPIDelegateCredentials <%= @ssh_gssapidelegatecredentials %> <% if @ssh_config_forward_x11 != nil -%> ForwardX11 <%= @ssh_config_forward_x11 %> <% end -%> -<% if @ssh_config_use_roaming != nil -%> - UseRoaming <%= @ssh_config_use_roaming %> +<% if (@ssh_config_use_roaming_real == 'yes') or (@ssh_config_use_roaming_real == 'no') -%> + UseRoaming <%= @ssh_config_use_roaming_real %> <% end -%> <% if @ssh_config_server_alive_interval != nil -%> ServerAliveInterval <%= @ssh_config_server_alive_interval %> From dd970dbaa54620609df5d95263a5b79b6551d07d Mon Sep 17 00:00:00 2001 From: Garrett Honeycutt Date: Sun, 17 Jan 2016 13:12:26 -0500 Subject: [PATCH 3/5] Add CVE-2016-0777 and CVE-2016-0778 information to README --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a27f81f..189a8c8 100644 --- a/README.md +++ b/README.md @@ -342,7 +342,11 @@ This module sets this option to 'yes' on Linux and undef on Solaris. ssh_config_use_roaming ---------------------- -String to enable or disable UseRoaming in client configuration ssh_config. Valid values are 'yes', 'no' and 'unset'. Using 'unset' will not use (print) this configuration parameter at all. Default is set to 'no' on Linux and 'unset' on Solaris. +String to enable or disable UseRoaming in client configuration ssh_config. +Valid values are 'yes', 'no' and 'unset'. Using 'unset' will not use (print) +this configuration parameter at all. Default is set to 'no' on Linux and +'unset' on Solaris. If you have OpenSSH >= version 5.4, this should be set to +'no' to mitigate CVE-2016-0777 and CVE-2016-0778. - *Default*: 'USE_DEFAULTS' From a76ec2fd3855bba4a772f9470c90451413aab466 Mon Sep 17 00:00:00 2001 From: Garrett Honeycutt Date: Sun, 17 Jan 2016 13:15:58 -0500 Subject: [PATCH 4/5] Use puppet-lint from git as rubygems is not updated --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index d25efe1..ddc9a29 100644 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,9 @@ end gem 'metadata-json-lint' gem 'puppetlabs_spec_helper', '>= 0.1.0' -gem 'puppet-lint', '>= 1.0.0' gem 'facter', '>= 1.7.0' gem 'rspec-puppet', '~> 2.0' +gem 'puppet-lint', :git => 'https://github.com/rodjek/puppet-lint.git' gem 'puppet-lint-absolute_classname-check' gem 'puppet-lint-alias-check' gem 'puppet-lint-empty_string-check' From 0f6a0df26b4ca4292731b57f65f84327074f6016 Mon Sep 17 00:00:00 2001 From: Garrett Honeycutt Date: Sun, 17 Jan 2016 13:16:48 -0500 Subject: [PATCH 5/5] Allow rspec > v2 on platforms that support it --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index ddc9a29..3cf09bb 100644 --- a/Gemfile +++ b/Gemfile @@ -9,7 +9,7 @@ end gem 'metadata-json-lint' gem 'puppetlabs_spec_helper', '>= 0.1.0' gem 'facter', '>= 1.7.0' -gem 'rspec-puppet', '~> 2.0' +gem 'rspec-puppet' gem 'puppet-lint', :git => 'https://github.com/rodjek/puppet-lint.git' gem 'puppet-lint-absolute_classname-check' gem 'puppet-lint-alias-check'