ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
835 stars 1.53k forks source link

authselect config breaks pamd module #5850

Open kvothe19 opened 1 year ago

kvothe19 commented 1 year ago

Summary

If i try to customize system-auth config in a custom authselect profile, which is based on the default profile sssd in RHEL 8 like distros, with community.general.pamd the module fails with "AttributeError: 'NoneType' object has no attribute 'group'". The reason for this issue is the first line in file '{imply "with-smartcard" if "with-smartcard-required"}'

Issue Type

Bug Report

Component Name

community.general.pamd

Ansible Version

$ ansible --version
ansible [core 2.14.1]
  config file = /home/vagrant/.ansible.cfg
  configured module search path = ['/home/vagrant/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.11/site-packages/ansible
  ansible collection location = /home/vagrant/ansible-galaxy-collections
  executable location = /usr/bin/ansible
  python version = 3.11.1 (main, Dec  7 2022, 00:00:00) [GCC 12.2.1 20221121 (Red Hat 12.2.1-4)] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general

# /usr/lib/python3.11/site-packages/ansible_collections
Collection        Version
----------------- -------
community.general 6.1.0

# /home/vagrant/ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 6.2.0

Configuration

$ ansible-config dump --only-changed

OS / Environment

RHEL 8, Rocky Linux 8

Steps to Reproduce

Create a new authselect profile based on the sssd default profile

authselect create-profile test -b sssd

Following system-auth file is going to be created:

cat -nA /etc/authselect/custom/test/system-auth

     1  {imply "with-smartcard" if "with-smartcard-required"}$                                                                                                                                
     2  auth        required                                     pam_env.so$                                                                                                                  
     3  auth        required                                     pam_faildelay.so delay=2000000$                                                                                              
     4  auth        required                                     pam_faillock.so preauth silent                         {include if "with-faillock"}$                                         
     5  auth        [success=1 default=ignore]                   pam_succeed_if.so service notin login:gdm:xdm:kdm:kde:xscreensaver:gnome-screensaver:kscreensaver quiet use_uid {include if "
with-smartcard-required"}$                                                                                                                                                                    
     6  auth        [success=done ignore=ignore default=die]     pam_sss.so require_cert_auth ignore_authinfo_unavail   {include if "with-smartcard-required"}$                               
     7  auth        sufficient                                   pam_fprintd.so                                         {include if "with-fingerprint"}$                                      
     8  auth        sufficient                                   pam_u2f.so cue                                         {include if "with-pam-u2f"}$                                          
     9  auth        required                                     pam_u2f.so cue {if not "without-pam-u2f-nouserok":nouserok} {include if "with-pam-u2f-2fa"}$                                 
    10  auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular$                                                                                                   
    11  auth        [default=1 ignore=ignore success=ok]         pam_localuser.so                                       {exclude if "with-smartcard"}$                                        
    12  auth        [default=2 ignore=ignore success=ok]         pam_localuser.so                                       {include if "with-smartcard"}$                                        
    13  auth        [success=done authinfo_unavail=ignore user_unknown=ignore ignore=ignore default=die] pam_sss.so try_cert_auth {include if "with-smartcard"}$
    14  auth        sufficient                                   pam_unix.so {if not "without-nullok":nullok}$
    15  auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular                              {include if "with-gssapi"}$
    16  auth        sufficient                                   pam_sss_gss.so                                         {include if "with-gssapi"}$
    17  auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular$
    18  auth        sufficient                                   pam_sss.so forward_pass$
    19  auth        required                                     pam_faillock.so authfail                               {include if "with-faillock"}$
    20  auth        optional                                     pam_gnome_keyring.so only_if=login auto_start          {include if "with-pam-gnome-keyring"}$
    21  auth        required                                     pam_deny.so$
    22  $
    23  account     required                                     pam_access.so                                          {include if "with-pamaccess"}$
    24  account     required                                     pam_faillock.so                                        {include if "with-faillock"}$
    25  account     required                                     pam_unix.so$
    26  account     sufficient                                   pam_localuser.so                                       {exclude if "with-files-access-provider"}$
    27  account     sufficient                                   pam_usertype.so issystem$
    28  account     [default=bad success=ok user_unknown=ignore] pam_sss.so$
    29  account     required                                     pam_permit.so$
   30  $
    31  password    requisite                                    pam_pwquality.so local_users_only$
    32  password    sufficient                                   pam_unix.so yescrypt shadow {if not "without-nullok":nullok} use_authtok$
    33  password    sufficient                                   pam_sss.so use_authtok$
    34  password    required                                     pam_deny.so$
    35  $
    36  session     optional                                     pam_keyinit.so revoke$
    37  session     required                                     pam_limits.so$
    38  -session    optional                                     pam_systemd.so$
    39  session     optional                                     pam_oddjob_mkhomedir.so                               {include if "with-mkhomedir"}$
    40  session     [success=1 default=ignore]                   pam_succeed_if.so service in crond quiet use_uid$
    41  session     required                                     pam_unix.so$
    42  session     optional                                     pam_sss.so$
    43  session     optional                                     pam_gnome_keyring.so only_if=login auto_start          {include if "with-pam-gnome-keyring"}$

The issue is on line 1.

- name: Update pam
  community.general.pamd:
      path: /etc/authselect/custom/test
      name: system-auth
      type: password
      control: sufficient
      module_path: pam_unix.so
      module_arguments: sha512
      state: args_present

Expected Results

I expected line 32 to change from password sufficient pam_unix.so yescrypt shadow {if not "without-nullok":nullok} use_authtok$ to password sufficient pam_unix.so yescrypt shadow {if not "without-nullok":nullok} use_authtok sha512$

Actual Results

Traceback (most recent call last):                                                                                                                                                        
  File "/home/vagrant/.ansible/tmp/ansible-tmp-1673967229.709315-1209279-206495393597740/AnsiballZ_pamd.py", line 107, in <module>                                                        
    _ansiballz_main()                                                                                                                                                                     
  File "/home/vagrant/.ansible/tmp/ansible-tmp-1673967229.709315-1209279-206495393597740/AnsiballZ_pamd.py", line 99, in _ansiballz_main                                                  
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)                                                                                                                                
  File "/home/vagrant/.ansible/tmp/ansible-tmp-1673967229.709315-1209279-206495393597740/AnsiballZ_pamd.py", line 48, in invoke_module                                                    
    run_name='__main__', alter_sys=True)                                                                                                                                                  
  File "/usr/lib64/python3.6/runpy.py", line 205, in run_module                                                                                                                           
    return _run_module_code(code, init_globals, run_name, mod_spec)                                                                                                                       
  File "/usr/lib64/python3.6/runpy.py", line 96, in _run_module_code                                                                                                                      
    mod_name, mod_spec, pkg_name, script_name)                                                                                                                                            
  File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code                                                                                                                             
    exec(code, run_globals)                                                                                                                                                               
  File "/tmp/ansible_community.general.pamd_payload_0k32ymn2/ansible_community.general.pamd_payload.zip/ansible_collections/community/general/plugins/modules/pamd.py", line 845, in <modu le>                                                                                                                                                                                           
    File "/tmp/ansible_community.general.pamd_payload_0k32ymn2/ansible_community.general.pamd_payload.zip/ansible_collections/community/general/plugins/modules/pamd.py", line 783, in main 
    File "/tmp/ansible_community.general.pamd_payload_0k32ymn2/ansible_community.general.pamd_payload.zip/ansible_collections/community/general/plugins/modules/pamd.py", line 426, in __init__                                                                                                                                                                                           
    File "/tmp/ansible_community.general.pamd_payload_0k32ymn2/ansible_community.general.pamd_payload.zip/ansible_collections/community/general/plugins/modules/pamd.py", line 339, in rule_
from_string                                                                                                                                                                                   
  AttributeError: 'NoneType' object has no attribute 'group'
msg: |-
  MODULE FAILURE
  See stdout/stderr for the exact error
rc: 1

Issue is happening because line '1 {imply "with-smartcard" if "with-smartcard-required"}$' is analyzed with method PamdRule.rule_from_string(line) in line 427 in plugins/modules/pamd.py and no groups are found in rule_match.

RULE_REGEX = re.compile(r"""(?P<rule_type>-?(?:auth|account|session|password))\s+
                        (?P<control>\[.*\]|\S*)\s+
                        (?P<path>\S*)\s*
                        (?P<args>.*)\s*""", re.X)
RULE_ARG_REGEX = re.compile(r"(\[.*\]|\S*)")
...
...
@classmethod
def rule_from_string(cls, line):
    rule_match = RULE_REGEX.search(line)
    rule_args = parse_module_arguments(rule_match.group('args'))
    return cls(rule_match.group('rule_type'), rule_match.group('control'), rule_match.group('path'), rule_args)

Additional handling is required for these type of lines. https://www.mankier.com/5/authselect-profiles#Profile_Files-Example

Code of Conduct

ansibullbot commented 1 year ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 1 year ago

cc @kevensen click here for bot help