Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support modifying sudoers Defaults #282

Merged
merged 10 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ sudo::configs:
'template' : "mymodule/bill.erb"
```

##### Override sudoers defaults

You can modify `Default_Entry` lines by passing a `Hash` to `sudo::defaults`, where the key is `Defaults` parameter name (see `man 5 sudoers` for more details):

```yaml
sudo::defaults:
lecture:
value: always
badpass_message:
value: "Password is wrong, please try again"
passwd_tries:
value: 5
insults:
mailto:
value: [email protected]
```

##### Set a custom name for the sudoers file

In some edge cases, the automatically generated sudoers file name is insufficient. For example, when an application generates a sudoers file with a fixed file name, using this class with the purge option enabled will always delete the custom file and adding it manually will generate a file with the right content, but the wrong name. To solve this, you can use the ```sudo_file_name``` option to manually set the desired file name.
Expand Down
56 changes: 56 additions & 0 deletions lib/puppet/functions/sudo/defaults.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: false

# Formats sudoers defaults config see https://linux.die.net/man/5/sudoers
#
# Default_Type ::= 'Defaults' |
# 'Defaults' '@' Host_List |
# 'Defaults' ':' User_List |
# 'Defaults' '!' Cmnd_List |
# 'Defaults' '>' Runas_List
#
# Default_Entry ::= Default_Type Parameter_List
#
# Parameter_List ::= Parameter |
# Parameter ',' Parameter_List
#
# Parameter ::= Parameter '=' Value |
# Parameter '+=' Value |
# Parameter '-=' Value |
# '!'* Parameter
#
# The function is passed an Array of Tuples
# e.g. [["env_reset", nil]]
# [["mailto", {"value" => root}]]
Puppet::Functions.create_function(:'sudo::defaults') do
def defaults(*args)
res = ''
raise "Unsupported number of arguments #{args.size}: #{args.inspect}" if args.nil?

args.each do |tuple|
raise "Unsupported number of arguments #{args.size}: #{args.inspect}" unless tuple.size == 2

res.concat(defaults_entry(tuple[0], tuple[1]))
end

res
end

def defaults_entry(key, config)
entry = "Defaults\t#{key}"

unless config.nil?
entry.concat((config['list']).to_s) if config.key? 'list'

operator = '='
operator = config['operator'] if config.key? 'operator'

if config.key? 'value'
val = config['value'].is_a?(String) ? "\"#{config['value']}\"" : config['value']

entry.concat("#{operator}#{val}")
end
end

entry.concat("\n")
end
end
1 change: 1 addition & 0 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
Enum['absent','password','nopassword'] $wheel_config = $sudo::params::wheel_config,
Optional[Array[String[1]]] $sudoreplay_discard = undef,
Hash $configs = {},
Sudo::Defaults $defaults = $sudo::params::defaults,
) inherits sudo::params {
case $enable {
true: {
Expand Down
20 changes: 20 additions & 0 deletions manifests/params.pp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {
'env_reset' => undef,
'mail_badpass' => undef,
}
}
'RedHat': {
$package = 'sudo'
Expand Down Expand Up @@ -84,6 +88,9 @@
$config_file_group = 'root'
$config_dir_keepme = false
$package_provider = undef
$defaults = {
'env_reset' => undef,
}
}
'Suse': {
$package = 'sudo'
Expand All @@ -99,6 +106,7 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
'Solaris': {
case $facts['os']['name'] {
Expand Down Expand Up @@ -170,6 +178,9 @@
}
}
}
$defaults = {
'env_reset' => undef,
}
}
'FreeBSD': {
$package = 'security/sudo'
Expand All @@ -185,6 +196,7 @@
$config_dir_keepme = true
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
'OpenBSD': {
if (versioncmp($facts['kernelversion'], '5.8') < 0) {
Expand All @@ -203,6 +215,7 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
'AIX': {
$package = 'sudo'
Expand All @@ -218,6 +231,7 @@
$config_dir_keepme = false
$package_provider = 'rpm'
$wheel_config = 'absent'
$defaults = {}
}
'Darwin': {
$package = undef
Expand All @@ -233,6 +247,9 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {
'env_reset' => undef,
}
}
default: {
case $facts['os']['name'] {
Expand All @@ -250,6 +267,7 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
/^(Arch|Manjaro)(.{0}|linux)$/: {
$package = 'sudo'
Expand All @@ -265,6 +283,7 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
'Amazon': {
$package = 'sudo'
Expand Down Expand Up @@ -292,6 +311,7 @@
$config_dir_keepme = false
$package_provider = undef
$wheel_config = 'absent'
$defaults = {}
}
default: {
fail("Unsupported platform: ${facts['os']['family']}/${facts['os']['name']}")
Expand Down
63 changes: 62 additions & 1 deletion spec/classes/sudo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
}
end

it { is_expected.to contain_file('/etc/sudoers').with_content(%r{.*Defaults\s+env_reset.*}) }
it { is_expected.to contain_file('/etc/sudoers').with_content(%r{.*#\s+Host\s+alias\s+specification.*}) }
end

unless os =~ %r{^(debian|ubuntu)}
Expand Down Expand Up @@ -103,6 +103,67 @@
it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^%wheel\s+ALL=\(ALL\)\s+NOPASSWD:\s+ALL$}) }
end
end

unless os =~ %r{^(gentoo|archlinux-rolling)}
context 'env_reset default is set' do
it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+env_reset$}) }
end
end

if os =~ %r{^(debian|ubuntu)}
context 'mail_badpass default is set' do
it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+mail_badpass$}) }
end
end

if os =~ %r{^(redhat)}
context '!visiblepw default is set' do
it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+!visiblepw$}) }
end
end

context 'Modify passwd_tries default' do
let :params do
{
defaults: {
passwd_tries: {
value: 5,
}
}
}
end

it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+passwd_tries=5$}) }
end

context 'Modify env_keep default' do
let :params do
{
defaults: {
env_keep: {
operator: '+=',
value: 'SOME_VAR',
}
}
}
end

it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+env_keep\+="SOME_VAR"$}) }
end

context 'Escape strings' do
let :params do
{
defaults: {
badpass_message: {
value: 'Password is wrong, please try again',
}
}
}
end

it { is_expected.to contain_file('/etc/sudoers').with_content(%r{^Defaults\s+badpass_message="Password is wrong, please try again"$}) }
end
end
end

Expand Down
15 changes: 15 additions & 0 deletions spec/functions/defaults_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'sudo::defaults' do
it {
is_expected.to run.with_params(['mailto', { 'value' => 'root' }]).and_return("Defaults\tmailto=\"root\"\n")
}

it {
is_expected.to run.with_params(['env_reset', nil]).and_return("Defaults\tenv_reset\n")
}

it { is_expected.to run.with_params(nil).and_raise_error(StandardError) }
end
1 change: 1 addition & 0 deletions templates/sudoers.aix.erb
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
1 change: 1 addition & 0 deletions templates/sudoers.archlinux.erb
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
3 changes: 2 additions & 1 deletion templates/sudoers.darwin.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# Cmnd alias specification

# Defaults specification
Defaults env_reset
Defaults env_keep += "BLOCKSIZE"
Defaults env_keep += "COLORFGBG COLORTERM"
Defaults env_keep += "__CF_USER_TEXT_ENCODING"
Expand All @@ -30,6 +29,7 @@ Defaults env_keep += "DISPLAY XAUTHORIZATION XAUTHORITY"
Defaults env_keep += "EDITOR VISUAL"
Defaults env_keep += "HOME MAIL"


<% if @use_sudoreplay %>
Defaults log_output
Defaults!/usr/bin/sudoreplay !log_output
Expand Down Expand Up @@ -61,3 +61,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
4 changes: 1 addition & 3 deletions templates/sudoers.debian.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# file managed by puppet (unless config_file_replace=false)
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="<%= @secure_path %>"

<% if @use_sudoreplay %>
Expand All @@ -28,4 +26,4 @@ root ALL=(ALL:ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>

<%= scope.call_function('sudo::defaults', @defaults) -%>
1 change: 1 addition & 0 deletions templates/sudoers.freebsd.erb
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
1 change: 1 addition & 0 deletions templates/sudoers.gentoo.erb
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
2 changes: 2 additions & 0 deletions templates/sudoers.olddebian.erb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH"
# Defaults!/usr/bin/sudoreplay !log_output
# Defaults!/usr/local/bin/sudoreplay !log_output
# Defaults!/sbin/reboot !log_output

<% if @use_sudoreplay %>
Defaults log_output
Defaults!/usr/bin/sudoreplay !log_output
Expand Down Expand Up @@ -105,3 +106,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
1 change: 1 addition & 0 deletions templates/sudoers.omnios.erb
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
1 change: 1 addition & 0 deletions templates/sudoers.openbsd.erb
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ root ALL=(ALL) SETENV: ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
2 changes: 1 addition & 1 deletion templates/sudoers.rhel5.erb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
#
Defaults !visiblepw

Defaults env_reset
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR \
LS_COLORS MAIL PS1 PS2 QTDIR USERNAME \
LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION \
Expand Down Expand Up @@ -98,3 +97,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
3 changes: 2 additions & 1 deletion templates/sudoers.rhel6.erb
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ Defaults !visiblepw
# Preserving HOME has security implications since many programs
# use it when searching for configuration files.
#

Defaults always_set_home

Defaults env_reset
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Expand Down Expand Up @@ -123,3 +123,4 @@ root ALL=(ALL) ALL
<% @extra_include_dirs.each do |include_dir| -%>
#includedir <%= include_dir %>
<% end if @extra_include_dirs -%>
<%= scope.call_function('sudo::defaults', @defaults) -%>
Loading