Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
5f4b39c
Fix ensure_logrotate_activated to work with /etc configuration
teacup-on-rockingchair Apr 27, 2026
d254f32
Use drop-ins file in /etc/login.defs.d/
teacup-on-rockingchair Feb 23, 2026
5a16b0c
Use new ansible macro ansible_copy_distro_defaults to create default …
teacup-on-rockingchair Apr 6, 2026
bb588bb
Use new bash macro bash_copy_distro_defaults to create default config…
teacup-on-rockingchair Apr 6, 2026
6a35f2c
Use macro to check if external variable is set to value in a config file
teacup-on-rockingchair Apr 6, 2026
0e88997
Add tests for the new functionality
teacup-on-rockingchair Apr 6, 2026
0b7392a
Add missing definition of login_defs_defaults_path and login_defs_dro…
teacup-on-rockingchair Apr 6, 2026
3d77773
Add variables to product_stability
teacup-on-rockingchair Apr 7, 2026
027d7d8
Make sure that both min and max rounds are set in either defs or drop…
teacup-on-rockingchair Apr 15, 2026
c3e5b74
make sure configuration is checked both in defs file and in drop-in f…
teacup-on-rockingchair Apr 15, 2026
4d02fc1
Minor patches to the new ansible macros
teacup-on-rockingchair Apr 15, 2026
e6cef0b
Update shared/macros/10-oval.jinja
teacup-on-rockingchair Apr 28, 2026
406362e
Update linux_os/guide/system/accounts/accounts-pam/set_password_hashi…
teacup-on-rockingchair Apr 28, 2026
b354563
Fix spacing in jinja macro
teacup-on-rockingchair Apr 28, 2026
de9c02c
Code review fixes
teacup-on-rockingchair Apr 29, 2026
16676bc
Update linux_os/guide/system/accounts/accounts-pam/set_password_hashi…
teacup-on-rockingchair May 1, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,22 @@

{{{ ansible_instantiate_variables("var_password_hashing_algorithm") }}}

{{% if product in [ 'slmicro6', 'sle16' ] %}}
{{% set cce_cce_identifier = cce_identifiers['cce'] %}}
{{{
ansible_login_defs(
parameter='ENCRYPT_METHOD',
value='{{ var_password_hashing_algorithm.split("|")[0] }}',
rule_title=rule_title,
cce=cce_cce_identifier
)
}}}
{{% else %}}
- name: Set Password Hashing Algorithm in {{{ login_defs_path }}}
ansible.builtin.lineinfile:
dest: {{{ login_defs_path }}}
regexp: ^#?ENCRYPT_METHOD
line: ENCRYPT_METHOD {{ var_password_hashing_algorithm.split('|')[0] }}
state: present
create: yes
{{% endif %}}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
#
var_password_hashing_algorithm="$(echo $var_password_hashing_algorithm | cut -d \| -f 1)"

{{% if product in [ 'slmicro6', 'sle16' ] %}}
{{{ bash_login_defs("ENCRYPT_METHOD", "$var_password_hashing_algorithm", cce_identifiers=cce_identifiers) }}}
{{% else %}}
{{{ bash_replace_or_append(login_defs_path, '^ENCRYPT_METHOD', "$var_password_hashing_algorithm", '%s %s', cce_identifiers=cce_identifiers) }}}
{{% endif %}}
Original file line number Diff line number Diff line change
@@ -1,53 +1,64 @@
<def-group>
<definition class="compliance" id="{{{ rule_id }}}" version="2">
{{{ oval_metadata("The password hashing algorithm should be set correctly in /usr/etc/login.defs.", rule_title=rule_title) }}}
{{{ oval_metadata("The password hashing algorithm should be set correctly in " + login_defs_path + ".", rule_title=rule_title) }}}
{{% if product in [ 'slmicro6', 'sle16' ] %}}
<criteria operator="OR">
<criteria operator="AND">
<criterion comment="Check ENCRYPT_METHOD in {{{ login_defs_drop_in_path }}} is not set"
test_ref="test_password_hashing_algorithm_drop_in_path_not_set"/>
<criterion comment="Check ENCRYPT_METHOD should be set appropriately in {{{ login_defs_path }}}"
test_ref="test_password_hashing_algorithm_logindefs"/>
</criteria>
<criteria operator="AND">
<criterion comment="Check ENCRYPT_METHOD should be set appropriately in {{{ login_defs_drop_in_path }}}"
test_ref="test_password_hashing_algorithm_logindefs_drop_in_path"/>
</criteria>
</criteria>
{{% else %}}
<criteria operator="AND">
<criterion test_ref="test_set_password_hashing_algorithm_logindefs"/>
<criterion test_ref="test_password_hashing_algorithm_logindefs"/>
</criteria>
{{% endif %}}
</definition>

<ind:variable_test id="test_set_password_hashing_algorithm_logindefs" version="1"
check="all" comment="The value of ENCRYPT_METHOD should be set appropriately in {{{ login_defs_path }}}">
<ind:object object_ref="object_set_password_hashing_algorithm_logindefs"/>
<ind:state state_ref="state_set_password_hashing_algorithm_logindefs"/>
</ind:variable_test>

<ind:textfilecontent54_object id="object_last_encrypt_method_from_etc_login_defs" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last ENCRYPT_METHOD directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>{{{ login_defs_path }}}</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of ENCRYPT_METHOD directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(ENCRYPT_METHOD\s+\w+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>

<!-- Capture the actual ENCRYPT_METHOD string value from the previously retrieved last instance -->
<local_variable id="variable_last_encrypt_method_instance_value" version="1"
datatype="string" comment="The value of last ENCRYPT_METHOD directive in {{{ login_defs_path }}}">
<regex_capture pattern="ENCRYPT_METHOD\s+(\w+)">
<object_component item_field="subexpression" object_ref="object_last_encrypt_method_from_etc_login_defs"/>
</regex_capture>
</local_variable>

<!-- Construct OVAL object from this local variable so we can use it in variable test above -->
<ind:variable_object id="object_set_password_hashing_algorithm_logindefs" version="1">
<ind:var_ref>variable_last_encrypt_method_instance_value</ind:var_ref>
</ind:variable_object>
{{{
oval_param_in_file_variable_test(
filepath=login_defs_path,
parameter="ENCRYPT_METHOD",
pattern="^[\s]*(?i)(ENCRYPT_METHOD[\s]+\w+)[\s]*(?:#.*)?$",
regex_capture="ENCRYPT_METHOD\s+(\w+)",
operation="pattern match",
type="string",
test_id="test_password_hashing_algorithm_logindefs",
variable="var_password_hashing_algorithm"
)
}}}
{{% set login_defs_drop_in_config_dir = "/".join(login_defs_drop_in_path.split("/")[:-1]) %}}
{{{
oval_param_in_file_variable_test(
filepath=login_defs_drop_in_config_dir,
filename_regex=".*\.defs$",
parameter="ENCRYPT_METHOD",
pattern="^[\s]*(?i)(ENCRYPT_METHOD[\s]+\w+)[\s]*(?:#.*)?$",
regex_capture="ENCRYPT_METHOD\s+(\w+)",
operation="pattern match",
type="string",
test_id="test_password_hashing_algorithm_logindefs_drop_in_path",
variable="var_password_hashing_algorithm"
)
}}}

<!-- Define corresponding variable state (the requirement) for the variable object -->
<!-- The check should PASS if retrieved last ENCRYPT_METHOD value is equal to the requirement -->
<ind:variable_state id="state_set_password_hashing_algorithm_logindefs" version="1">
<ind:value operation="pattern match" datatype="string" var_ref="var_password_hashing_algorithm_regex"/>
</ind:variable_state>
<ind:textfilecontent54_test check="all" check_existence="none_exist" version="1"
comment="Check ENCRYPT_METHOD in {{{ login_defs_drop_in_path }}} is not set"
id="test_password_hashing_algorithm_drop_in_path_not_set">
<ind:object object_ref="object_password_hashing_algorithm_drop_in_path_not_set" />
</ind:textfilecontent54_test>

<local_variable datatype="string" id="var_password_hashing_algorithm_regex" version="1" comment="Limit regex">
<concat>
<literal_component>^</literal_component>
<variable_component var_ref="var_password_hashing_algorithm"/>
<literal_component>$</literal_component>
</concat>
</local_variable>
<ind:textfilecontent54_object id="object_password_hashing_algorithm_drop_in_path_not_set" version="1">
<ind:path>{{{ login_defs_drop_in_config_dir }}}</ind:path>
<ind:filename operation="pattern match">.*\.defs$</ind:filename>
<ind:pattern operation="pattern match">^\s*ENCRYPT_METHOD\s*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>

<external_variable id="var_password_hashing_algorithm" version="1"
datatype="string" comment="hashing algorithm for {{{ login_defs_path }}}"/>
</def-group>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
# platform = SUSE Linux Enterprise 16
# variables = var_password_hashing_algorithm=SHA512

if [ -e {{{ login_defs_drop_in_path }}} ] ; then
rm {{{ login_defs_drop_in_path }}}
fi
{{{ bash_copy_distro_defaults(login_defs_defaults_path, login_defs_path) }}}

if grep -q "^ENCRYPT_METHOD" {{{ login_defs_path }}} ; then
sed -i "s/ENCRYPT_METHOD.*/ENCRYPT_METHOD MD5/g" {{{ login_defs_path }}}
else
echo "ENCRYPT_METHOD MD5" >> {{{ login_defs_path }}}
fi
echo "ENCRYPT_METHOD SHA512" >> {{{ login_defs_drop_in_path }}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# platform = SUSE Linux Enterprise 16
# variables = var_password_hashing_algorithm=SHA512

if [ -e {{{ login_defs_drop_in_path }}} ] ; then
rm {{{ login_defs_drop_in_path }}}
fi
{{{ bash_copy_distro_defaults(login_defs_defaults_path, login_defs_path) }}}
if grep -q "^ENCRYPT_METHOD" {{{ login_defs_path }}} ; then
sed -i "s/ENCRYPT_METHOD.*/ENCRYPT_METHOD SHA512/g" {{{ login_defs_path }}}
else
echo "ENCRYPT_METHOD SHA512" >> {{{ login_defs_path }}}
fi
echo "ENCRYPT_METHOD MD5" >> "/etc/login.defs.d/user.dropin.defs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# platform = SUSE Linux Enterprise 16
# variables = var_password_hashing_algorithm=SHA512

if [ -e {{{ login_defs_drop_in_path }}} ] ; then
rm {{{ login_defs_drop_in_path }}}
fi
{{{ bash_copy_distro_defaults(login_defs_defaults_path, login_defs_path) }}}
if grep -q "^ENCRYPT_METHOD" {{{ login_defs_path }}} ; then
sed -i "s/ENCRYPT_METHOD.*/ENCRYPT_METHOD SHA512/g" {{{ login_defs_path }}}
else
echo "ENCRYPT_METHOD SHA512" >> {{{ login_defs_path }}}
fi
echo "ENCRYPT_METHOD MD5" >> {{{ login_defs_drop_in_path }}}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@

{{{ ansible_instantiate_variables("var_password_hashing_min_rounds_login_defs") }}}

{{% if product in [ 'sle16', 'slmicro6' ] %}}
{{% set cce_cce_identifier = cce_identifiers['cce'] %}}
{{{
ansible_login_defs(
parameter='SHA_CRYPT_MIN_ROUNDS',
value='{{ var_password_hashing_min_rounds_login_defs }}',
rule_title=rule_title,
cce=cce_cce_identifier
)
}}}
{{{
ansible_login_defs(
parameter='SHA_CRYPT_MAX_ROUNDS',
value='{{ var_password_hashing_min_rounds_login_defs }}',
rule_title=rule_title,
cce=cce_cce_identifier
)
}}}
{{% else %}}
- name: "{{{ rule_title }}} - extract contents of the file {{{ login_defs_path }}}"
ansible.builtin.slurp:
src: {{{ login_defs_path }}}
Expand Down Expand Up @@ -48,3 +67,4 @@
path: {{{ login_defs_path }}}
state: present
when: etc_login_defs_sha_crypt_max_rounds | length == 0
{{% endif %}}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@

{{{ bash_instantiate_variables("var_password_hashing_min_rounds_login_defs") }}}

{{% if product == [ 'sle16', 'slmicro6' ] %}}
{{% set login_defs_d_config_dir = "/".join(login_defs_drop_in_path.split("/")[:-1]) ~ "/*.defs" %}}

min_rounds_login_defs=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' {{{ login_defs_d_config_dir }}})
if [[ -z "$min_rounds_login_defs" ]]; then
min_rounds_login_defs=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' {{{ login_defs_path }}})
fi
if [[ -z "$min_rounds_login_defs" || "$min_rounds_login_defs" -le "$var_password_hashing_min_rounds_login_defs" ]]; then
{{{ bash_login_defs("SHA_CRYPT_MIN_ROUNDS", "$var_password_hashing_min_rounds_login_defs", cce_identifiers=cce_identifiers) }}}
fi

max_rounds_login_defs=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' {{{ login_defs_d_config_dir }}})
if [[ -z "$max_rounds_login_defs" ]]; then
max_rounds_login_defs=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' {{{ login_defs_path }}})
fi
if [[ -z "$max_rounds_login_defs" || "$max_rounds_login_defs" -le "$var_password_hashing_min_rounds_login_defs" ]]; then
{{{ bash_login_defs("SHA_CRYPT_MAX_ROUNDS", "$var_password_hashing_min_rounds_login_defs", cce_identifiers=cce_identifiers) }}}
fi

{{% else %}}

config_file={{{ login_defs_path }}}
current_min_rounds=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' "$config_file")
current_max_rounds=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' "$config_file")
Expand All @@ -21,3 +42,4 @@ if [[ -n "$current_max_rounds" && "$current_max_rounds" -le "$var_password_hashi
separator=" ",
separator_regex="\s*", rule_id=rule_id) | indent(4) }}}
fi
{{% endif %}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<def-group>
<definition class="compliance" id="set_password_hashing_min_rounds_logindefs" version="3">
{{{ oval_metadata("The password hashing minimum rounds should be set correctly.", rule_title=rule_title) }}}
<criteria operator="OR">
<criteria operator="AND">
<criterion
comment="Check SHA_CRYPT_MIN_ROUNDS in {{{ login_defs_drop_in_path }}} is not set"
test_ref="test_sha_crypt_min_rounds_logindefs_drop_in_path_not_set"/>
<criterion
comment="Check SHA_CRYPT_MIN_ROUNDS should be set appropriately in {{{ login_defs_path }}}"
test_ref="test_sha_crypt_min_rounds_logindefs"/>

<criterion
comment="Check SHA_CRYPT_MAX_ROUNDS in {{{ login_defs_drop_in_path }}} is not set"
test_ref="test_sha_crypt_max_rounds_logindefs_drop_in_path_not_set"/>
<criterion
comment="Check SHA_CRYPT_MAX_ROUNDS should be set appropriately in {{{ login_defs_path }}}"
test_ref="test_sha_crypt_max_rounds_logindefs"/>
</criteria>
<criteria operator="AND">
<criterion comment="Check SHA_CRYPT_MIN_ROUNDS should be set appropriately in {{{ login_defs_drop_in_path }}}"
test_ref="test_sha_crypt_min_rounds_logindefs_drop_in_path"/>
<criterion comment="Check SHA_CRYPT_MAX_ROUNDS should be set appropriately in {{{ login_defs_drop_in_path }}}"
test_ref="test_sha_crypt_max_rounds_logindefs_drop_in_path"/>
</criteria>
</criteria>
</definition>

{{{
oval_param_in_file_variable_test(
filepath=login_defs_path,
parameter="SHA_CRYPT_MIN_ROUNDS",
pattern="^[\s]*(?i)(SHA_CRYPT_MIN_ROUNDS[\s]+\d+)[\s]*(?:#.*)?$",
regex_capture="SHA_CRYPT_MIN_ROUNDS\s+(\d+)",
operation="greater than or equal",
type="int",
variable="var_password_hashing_min_rounds_login_defs",
test_id="test_sha_crypt_min_rounds_logindefs"
)
}}}

{{{
oval_param_in_file_variable_test(
filepath=login_defs_path,
parameter="SHA_CRYPT_MAX_ROUNDS",
pattern="^[\s]*(?i)(SHA_CRYPT_MAX_ROUNDS[\s]+\d+)[\s]*(?:#.*)?$",
regex_capture="SHA_CRYPT_MAX_ROUNDS\s+(\d+)",
operation="greater than or equal",
type="int",
variable="var_password_hashing_min_rounds_login_defs",
test_id="test_sha_crypt_max_rounds_logindefs"
)
}}}

{{% set login_defs_drop_in_config_dir = "/".join(login_defs_drop_in_path.split("/")[:-1]) %}}
{{{
oval_param_in_file_variable_test(
filepath=login_defs_drop_in_config_dir,
filename_regex=".*\.defs$",
parameter="SHA_CRYPT_MIN_ROUNDS",
pattern="^[\s]*(?i)(SHA_CRYPT_MIN_ROUNDS[\s]+\d+)[\s]*(?:#.*)?$",
regex_capture="SHA_CRYPT_MIN_ROUNDS\s+(\d+)",
operation="greater than or equal",
type="int",
variable="var_password_hashing_min_rounds_login_defs",
test_id="test_sha_crypt_min_rounds_logindefs_drop_in_path"
)
}}}

{{{
oval_param_in_file_variable_test(
filepath=login_defs_drop_in_config_dir,
filename_regex=".*\.defs$",
parameter="SHA_CRYPT_MAX_ROUNDS",
pattern="^[\s]*(?i)(SHA_CRYPT_MAX_ROUNDS[\s]+\d+)[\s]*(?:#.*)?$",
regex_capture="SHA_CRYPT_MAX_ROUNDS\s+(\d+)",
operation="greater than or equal",
type="int",
variable="var_password_hashing_min_rounds_login_defs",
test_id="test_sha_crypt_max_rounds_logindefs_drop_in_path"
)
}}}

<ind:textfilecontent54_test check="all" check_existence="none_exist" version="1"
comment="Check SHA_CRYPT_MIN_ROUNDS in {{{ login_defs_drop_in_path }}} is not set"
id="test_sha_crypt_min_rounds_logindefs_drop_in_path_not_set">
<ind:object object_ref="object_sha_crypt_min_rounds_logindefs_drop_in_path_not_set" />
</ind:textfilecontent54_test>

<ind:textfilecontent54_object id="object_sha_crypt_min_rounds_logindefs_drop_in_path_not_set" version="1">
<ind:path>{{{ login_defs_drop_in_config_dir }}}</ind:path>
<ind:filename operation="pattern match">.*\.defs$</ind:filename>
<ind:pattern operation="pattern match">^\s*SHA_CRYPT_MIN_ROUNDS\s*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>

<ind:textfilecontent54_test check="all" check_existence="none_exist" version="1"
comment="Check SHA_CRYPT_MAX_ROUNDS in {{{ login_defs_drop_in_path }}} is not set"
id="test_sha_crypt_max_rounds_logindefs_drop_in_path_not_set">
<ind:object object_ref="object_sha_crypt_max_rounds_logindefs_drop_in_path_not_set" />
</ind:textfilecontent54_test>

<ind:textfilecontent54_object id="object_sha_crypt_max_rounds_logindefs_drop_in_path_not_set" version="1">
<ind:path>{{{ login_defs_drop_in_config_dir }}}</ind:path>
<ind:filename operation="pattern match">.*\.defs$</ind:filename>
<ind:pattern operation="pattern match">^\s*SHA_CRYPT_MAX_ROUNDS\s*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
</def-group>
Loading
Loading