Skip to content
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
13 changes: 9 additions & 4 deletions library/scan_sudoers.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,22 @@
comment_re = re.compile(r"^#+")
include_re = re.compile(r"^#include")
defaults_re = re.compile(r"^(Defaults)+\s+(.*$)")
# NOTE: The spec https://www.sudo.ws/docs/man/1.9.17/sudoers.man/ says
# NAME ::= A-Z*
# A NAME is a string of uppercase letters, numbers, and underscore characters ('_').
# A NAME must start with an uppercase letter.
# I'm assuming these are ASCII - so the pattern used for NAME is ([A-Z][A-Z0-9_]*)
cmnd_alias_re = re.compile(
r"(^Cmnd_Alias)+\s+(\S+)+\s*\={1}\s*((\S+,{1}\s*)+\S+|\S+)\s*(\:)*(.*)*$"
r"(^Cmnd_Alias)+\s+([A-Z][A-Z0-9_]*)\s*\=\s*((\S+,\s*)+\S+|\S+)\s*(\:)*(.*)*$"

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Cmnd_Alias A=' and containing many repetitions of '!,'.

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Cmnd_Alias A=!' and containing many repetitions of 'a'.
)
host_alias_re = re.compile(
r"(^Host_Alias)+\s+(\S+)+\s*\={1}\s*((\S+,{1}\s*)+\S+|\S+)\s*(\:)*(.*)*$"
r"(^Host_Alias)+\s+([A-Z][A-Z0-9_]*)\s*\=\s*((\S+,\s*)+\S+|\S+)\s*(\:)*(.*)*$"

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Host_Alias A=' and containing many repetitions of '!,'.

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Host_Alias A=!' and containing many repetitions of 'a'.
)
runas_alias_re = re.compile(
r"(^Runas_Alias)+\s+(\S+)+\s*\={1}\s*((\S+,{1}\s*)+\S+|\S+)\s*(\:)*(.*)*$"
r"(^Runas_Alias)+\s+([A-Z][A-Z0-9_]*)\s*\=\s*((\S+,\s*)+\S+|\S+)\s*(\:)*(.*)*$"

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Runas_Alias A=' and containing many repetitions of '!,'.

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'Runas_Alias A=!' and containing many repetitions of 'a'.
)
user_alias_re = re.compile(
r"(^User_Alias)+\s+(\S+)+\s*\={1}\s*((\S+,{1}\s*)+\S+|\S+)\s*(\:)*(.*)*$"
r"(^User_Alias)+\s+([A-Z][A-Z0-9_]*)\s*\=\s*((\S+,\s*)+\S+|\S+)\s*(\:)*(.*)*$"

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'User_Alias A=' and containing many repetitions of '!,'.

Check failure

Code scanning / CodeQL

Inefficient regular expression High

This part of the regular expression may cause exponential backtracking on strings starting with 'User_Alias A=!' and containing many repetitions of 'a'.
)

# Defaults Parsing vars
Expand Down
101 changes: 101 additions & 0 deletions tests/tests_scan_sudoers.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# SPDX-License-Identifier: MIT
---
- name: Ensure that the role can parse existing sudoers
hosts: all
gather_facts: false # test that role works in this case
vars:
alias_values:
Cmnd_Alias:
- name: MY_CMND_NO_SPACES
commands:
- /usr/local/bin/my_cmd_alias.sh
- name: MY_CMND_SPACES
commands:
- /usr/local/bin/my_cmd_alias.sh
Host_Alias:
- name: MY_HOST_NO_SPACES
hosts:
- myhostalias.example.com
- name: MY_HOST_SPACES
hosts:
- myhostalias.example.com
User_Alias:
- name: MY_USER_NO_SPACES
users:
- myuser
- name: MY_USER_SPACES
users:
- myuser
Runas_Alias:
- name: MY_RUNAS_NO_SPACES
users:
- myrunasuser
- name: MY_RUNAS_SPACES
users:
- myrunasuser
alias_keys: "{{ alias_values.keys() | list }}"
alias_names: "{{ alias_keys | zip(alias_keys) | flatten | list }}"
alias_vals: "{{ alias_values.values() | flatten | list }}"
names_vals: "{{ alias_names | zip(alias_vals) | list }}"
tasks:
- name: Run tests
block:
- name: Test setup
include_tasks: tasks/setup.yml

- name: Try with no spaces in alias definitions
copy:
dest: /etc/sudoers
content: |
{% for alias in names_vals %}
{% set itemvals = alias.1.values() | list %}
{% set space = ("NO_SPACES" in itemvals.0) | ternary("", " ") %}
{{ alias.0 }} {{ itemvals.0 }}{{ space }}={{ space }}{{ itemvals.1 | join("") }}
{% endfor %}
mode: preserve

- name: Run the role
include_role:
name: linux-system-roles.sudo
vars:
sudo_rewrite_default_sudoers_file: true
sudo_remove_unauthorized_included_files: true
sudo_sudoers_files:
- path: /etc/sudoers
aliases: "{{ aliases }}"
aliases: "{{ dict(keys | zip(vals)) }}"
keys: "{{ alias_values | dict2items | map(attribute='key') | map('lower') | list }}"
vals: "{{ alias_values | dict2items | map(attribute='value') | list }}"

- name: Get sudoers
slurp:
path: /etc/sudoers
register: __check_sudoers

- name: Check that lines are properly formatted
debug:
msg: expected {{ expected }} in actual {{ actual }}
loop: "{{ names_vals }}"
vars:
expected: "{{ item.0 }} {{ vals.0 }} = {{ vals.1.0 }}"
vals: "{{ item.1.values() | list }}"
actual: "{{ __check_sudoers.content | b64decode }}"

- name: Check that lines are properly formatted
assert:
that: expected in actual
loop: "{{ names_vals }}"
vars:
expected: "{{ item.0 }} {{ vals.0 }} = {{ vals.1.0 }}"
vals: "{{ item.1.values() | list }}"
actual: "{{ __check_sudoers.content | b64decode }}"

- name: Check header for ansible_managed, fingerprint
include_tasks: tasks/check_present_header.yml
vars:
__file: /etc/sudoers
__fingerprint: system_role:sudo

always:
- name: Test cleanup
include_tasks: tasks/cleanup.yml
Loading