Revision 30280bea
Added by Nicolas CHARLES almost 7 years ago
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
Fixes #9347: sudo management isn't update-safe