Project

General

Profile

« Previous | Next » 

Revision 30280bea

Added by Nicolas CHARLES almost 7 years ago

Fixes #9347: sudo management isn't update-safe

View differences:

techniques/systemSettings/userManagement/sudoParameters/3.1/sudoParameters.st
#####################################################################################
##########################################################################
# Sudo configuration PT #
# Sudo configuration Technique #
# ---------------------------------------------------------------------- #
# Objective : Configure /etc/sudoers according to the given parameters #
##########################################################################
......
&SUDO_NAME:{name |"sudo_entity_name[&i&]" string => "&name&";
}&
&SUDO_DESCRIPTION:{description |"sudo_entity_description[&i&]" string => "&description&";
}&
&SUDO_NOPASSWD:{nopasswd |"sudo_entity_nopasswd[&i&]" string => "&nopasswd&";
}&
......
pass1.!visudo_use_strict_mode::
"strict_mode" string => "";
classes:
pass1::
"entity[${sudo_index}]"
string => "%${sudo_entity_name[${sudo_index}]}",
ifvarclass => "sudo_${sudo_index}_isgroup";
"entity[${sudo_index}]"
string => "${sudo_entity_name[${sudo_index}]}",
ifvarclass => "sudo_${sudo_index}_isuser";
# used for reporting conditions
"csection_name[${sudo_index}]"
string => canonify("# begin_section_${entity[${sudo_index}]}");
classes:
"sudoconfiguration_sudoers_present" expression => fileexists("/etc/sudoers");
# Check the version of visudo; if before 1.7 (so 1.6 or less), we need to use strict mode
......
# visudo -V can returns several lines, so we need to keep only the visudo version line
"visudo_use_strict_mode" expression => returnszero("/usr/sbin/visudo -V | grep 'visudo version' | /bin/sed -e 's/visudo version \([0-9]\+\)\.\([0-9]\+\)\..*/\1 \2/p' | /usr/bin/awk '{ if(($1<1)||($1==1 \&\& $2<=6)) { exit 0 }; exit 1 }'", "useshell");
# Is it a group ?
"sudo_${sudo_index}_isgroup" expression => strcmp("${sudo_entity_type[${sudo_index}]}","group");
# Is it a user ?
"sudo_${sudo_index}_isuser" expression => strcmp("${sudo_entity_type[${sudo_index}]}","user");
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
......
comment => "Remove temporary copy of /etc/sudoers that Rudder keeps in /etc/sudoers.rudder";
((sudoconfiguration_sudoers_tmp_copy_kept|sudoconfiguration_sudoers_tmp_copy_repaired).(!sudoconfiguration_sudoers_tmp_copy_error))::
"/etc/sudoers.rudder"
edit_line => sudo_add_line("check_sudo_parameters.sudo_entity_type", "check_sudo_parameters.sudo_entity_name", "check_sudo_parameters.sudo_entity_nopasswd", "check_sudo_parameters.sudo_entity_all", "check_sudo_parameters.sudo_entity_command", "check_sudo_parameters.sudo_directive_id", "${sudo_force_content}"),
create => "true",
edit_defaults => noempty_backup,
perms => mog("0440", "root", "0"),
classes => kept_if_else("sudoconfiguration_sudoers_tmp_edit_kept", "sudoconfiguration_sudoers_tmp_edit_repair", "sudoconfiguration_sudoers_tmp_edit_error"),
comment => "Editing temporary sudoers file";
sudoconfiguration_sudoers_valid::
"/etc/sudoers"
......
methods:
"any"
usebundle => check_sudo_installation("${sudo_directive_id[${sudo_index}]}");
# Edit sudoers.rudder file if it's been copied or purged
((sudoconfiguration_sudoers_tmp_copy_kept|sudoconfiguration_sudoers_tmp_copy_repaired).(!sudoconfiguration_sudoers_tmp_copy_error))::
"any"
usebundle => sudo_parameter_edit_sudoers("/etc/sudoers.rudder", "check_sudo_parameters.entity", "check_sudo_parameters.sudo_entity_nopasswd", "check_sudo_parameters.sudo_entity_all", "check_sudo_parameters.sudo_entity_command");
pass3.(sudoconfiguration_sudoers_copy_kept.!sudoconfiguration_sudoers_copy_repaired)::
"any" usebundle => rudder_common_report("sudoParameters", "result_success", "${sudo_directive_id[${sudo_index}]}", "sudoersFile", "None", "The sudoers file did not require any modification");
......
pass3.sudoconfiguration_sudoers_invalid::
"any" usebundle => rudder_common_report("sudoParameters", "result_error", "${sudo_directive_id[${sudo_index}]}", "sudoersFile", "None", "The generated sudoers file is invalid. Not updating /etc/sudoers. This should not happen.");
pass3.sudo_all_lines_defined::
pass3::
"any" usebundle => rudder_common_report("sudoParameters", "log_warn", "${sudo_directive_id[${sudo_index}]}", "Permissions", "${sudo_entity_name[${sudo_index}]}", "Entry for ${sudo_entity_type[${sudo_index}]} ${sudo_entity_name[${sudo_index}]} is invalid (no command given), and has been ignored"),
ifvarclass => "!sudo_${sudo_index}_command_notempty.!sudo_${sudo_index}_alldo";
"any" usebundle => rudder_common_report("sudoParameters", "result_repaired", "${sudo_directive_id[${sudo_index}]}", "Permissions", "${sudo_entity_name[${sudo_index}]}", "The ${sudo_entity_type[${sudo_index}]} ${sudo_entity_name[${sudo_index}]} has been handled"),
ifvarclass => canonify("line_${sudo_index}_added");
ifvarclass => "sudo_parameter_edited_section_${csection_name[${sudo_index}]}_repaired.!sudo_parameter_edited_section_${csection_name[${sudo_index}]}_error";
"any" usebundle => rudder_common_report("sudoParameters", "result_success", "${sudo_directive_id[${sudo_index}]}", "Permissions", "${sudo_entity_name[${sudo_index}]}", "The ${sudo_entity_type[${sudo_index}]} ${sudo_entity_name[${sudo_index}]} is already present"),
ifvarclass => canonify("line_${sudo_index}_kept");
ifvarclass => "sudo_parameter_edited_section_${csection_name[${sudo_index}]}_kept.!sudo_parameter_edited_section_${csection_name[${sudo_index}]}_repaired.!sudo_parameter_edited_section_${csection_name[${sudo_index}]}_error";
"any" usebundle => rudder_common_report("sudoParameters", "result_error", "${sudo_directive_id[${sudo_index}]}", "Permissions", "${sudo_entity_name[${sudo_index}]}", "The ${sudo_entity_type[${sudo_index}]} ${sudo_entity_name[${sudo_index}]} could not be handled"),
ifvarclass => canonify("line_${sudo_index}_add_failed");
pass3.sudo_all_lines_defined.force.sudo_all_lines_deleted::
"any" usebundle => rudder_common_report("sudoParameters", "result_repaired", "sudoersFile", "None", "None", "Some lines were deleted from the sudoers file. This implies either a manual edition or an intrusion attempt");
ifvarclass => "sudo_parameter_edited_section_${csection_name[${sudo_index}]}_error";
commands:
(sudoconfiguration_sudoers_tmp_edit_repair|sudoconfiguration_sudoers_tmp_edit_kept).pass2::
sudoparameters_sudoers_tmp_file_ok::
"/usr/sbin/visudo"
args => "-c ${strict_mode} -f /etc/sudoers.rudder",
......
}
bundle edit_line sudo_add_line(type, name, nopasswd, alldo, command, directiveId, force)
bundle agent sudo_parameter_edit_sudoers(filename, entity, nopasswd, alldo, command)
{
vars:
"index" slist => getindices("${type}");
check_sudo_parameters_sudo_add_line_classes_defined::
"lines[${index}]"
string => "%${${name}[${index}]} ALL=(ALL) NOPASSWD:ALL",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_alldo.sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"index" slist => getindices("${entity}");
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) ALL",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_alldo.!sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
pass1::
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) NOPASSWD:${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isgroup.sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"command_all[${index}]" string => "ALL=(ALL) NOPASSWD:ALL",
ifvarclass => "(sudo_${index}_alldo.sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "%${${name}[${index}]} ALL=(ALL) ${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isgroup.!sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"command_all[${index}]" string => "ALL=(ALL) ALL",
ifvarclass => "(sudo_${index}_alldo.!sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"command_all[${index}]" string => "ALL=(ALL) NOPASSWD:${${command}[${index}]}",
ifvarclass => "(sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) NOPASSWD:ALL",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_alldo.sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"command_all[${index}]" string => "ALL=(ALL) ${${command}[${index}]}",
ifvarclass => "(!sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) ALL",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_alldo.!sudo_${index}_nopasswd).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) NOPASSWD:${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isuser.sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"lines[${index}]" string => "${${name}[${index}]} ALL=(ALL) ${${command}[${index}]}",
ifvarclass => "(sudo_${index}_isuser.!sudo_${index}_nopasswd.!sudo_${index}_alldo).(sudo_${index}_command_notempty|sudo_${index}_alldo)";
"all_lines" slist => getvalues("lines");
classes:
# some classes are used by reporting from parent bundle (scope namespace)
# sudoParameters is declared as unique so this bundle can be called only once
"sudo_force_content" expression => strcmp("true", "${force}");
# Is it a group ?
"sudo_${index}_isgroup" expression => strcmp("${${type}[${index}]}","group");
# Is it a user ?
"sudo_${index}_isuser" expression => strcmp("${${type}[${index}]}","user");
# Disable password asking ?
"sudo_${index}_nopasswd" expression => strcmp("${${nopasswd}[${index}]}","true");
......
# Should we enable ALL as command ?
"sudo_${index}_alldo" expression => strcmp("${${alldo}[${index}]}","true"),
scope => "namespace";
pass2::
# Is command empty ?
"sudo_${index}_command_notempty" not => strcmp("${${command}[${index}]}",""),
scope => "namespace";
"check_sudo_parameters_sudo_add_line_classes_defined" expression => "any";
# detect if file has been changed by edition
"sudoparameters_sudoers_tmp_file_ok"
not => classmatch("sudo_parameter_edited_section_.*_error"),
scope => "namespace";
"check_sudo_parameters_sudo_add_line_vars_defined" expression => isvariable("lines[${index}]");
"sudoparameters_sudoers_tmp_file_error"
expression => classmatch("sudo_parameter_edited_section_.*_error"),
scope => "namespace";
any::
"pass3" expression => "pass2";
"pass2" expression => "pass1";
"pass1" expression => "any";
"sudo_all_lines_defined" expression => isvariable("all_lines"),
scope => "namespace";
files:
"${filename}"
create => "true",
edit_defaults => noempty_backup,
perms => mog("0440", "root", "0"),
comment => "Sanitize environment",
edit_line => sudo_parameter_sanitize_env;
delete_lines:
sudo_all_lines_defined.force::
methods:
pass2::
"edit_file" usebundle => sudo_parameter_ensure_block_section("${filename}", "${${entity}[${index}]}", "${command_all[${index}]}", "# begin_section_${${entity}[${index}]}", "# end_section_${${entity}[${index}]}");
".*"
delete_select => sudo_select_nomatch("${all_lines}"),
classes => if_repaired("sudo_all_lines_deleted");
}
# Sanitize the environement
bundle edit_line sudo_parameter_sanitize_env
{
insert_lines:
replace_attempted_env_reset::
"Defaults env_reset";
check_sudo_parameters_sudo_add_line_vars_defined::
"${lines[${index}]}"
classes => kept_if_else("line_${index}_kept", "line_${index}_added", "line_${index}_add_failed");
replace_patterns:
"^(?!Defaults env_reset$)Defaults\s+env_reset$"
comment => "Normalize env_reset setting",
......
}
bundle agent sudo_parameter_ensure_block_section(filename, entity, command, begin, end) {
vars:
"escaped_entity" string => escape("${entity}");
"escaped_command" string => escape("${command}");
"escaped_begin" string => escape("${begin}");
"canonified_begin" string => canonify("${begin}");
# Edit the file using ncf_ensure_section_content_and_purge_type
# It will remove all lines starting by entity in the file, and ensure content of block begin-entity command-end
files:
"${filename}"
create => "true",
edit_defaults => noempty_backup,
perms => mog("0440", "root", "0"),
edit_line => ncf_ensure_section_content_and_purge_type("${begin}", "${end}", "${entity} ${command}", "preserve_block", "${escaped_entity}"),
classes => classes_generic("sudo_parameter_edited_section_${canonified_begin}");
}
bundle agent check_sudo_installation(directiveId)
{

Also available in: Unified diff