SUDO Responder Cache Behaviour

Before we go into the caching its better to know some useful information about sudo schema.

  1. As the document at http://www.gratisoft.us/sudo/man/1.8.1/sudoers.ldap.man.html indicates the sudo rules are contained in a ldap server inside the SUDOers container.

  2. The SUDOers container contains the sudoRole objects. Where each object indicates a a sudorule.

  3. Each sudoRole object supports following attributes:

    sudoUser - A user name, uid (prefixed with ‘#’), UNIX group (prefixed with a ‘%’) or user netgroup (prefixed with a ‘+’).
    sudoHost - A host name, IP address, IP network, or host netgroup (prefixed with a ‘+’). The special value ALL will match any host.
    sudoCommand - A UNIX command with optional command line arguments and wild chars.
    sudoOption – Specifies options to be enabled or disabled as in the sudoers file.
    sudoRunAsUser - A user name or uid (prefixed with ‘#’) that commands may be run as or a UNIX group (prefixed with a ‘%’) or user netgroup (prefixed with a ‘+’) that contains a list of users that commands may be run as. The special value ALL will match any user.
    sudoRunAsGroup - A UNIX group or gid (prefixed with ‘#’) that commands may be run as. The special value ALL will match any group.
    sudoNotBefore - A time-stamp in the form yyyymmddHHMMZ that can be used to provide a start date/time for when the sudoRole will be valid. If multiplesudoNotBefore entries are present, the earliest is used. Note that timestamps must be in Coordinated Universal Time (UTC), not the local timezone.
    sudoNotAfter - A time stamp in the form yyyymmddHHMMZ that indicates an expiration date/time,after which the sudoRole will no longer be valid. If multiplesudoNotBefore entries are present, the last one is used. Note that time-stamps must be in Coordinated Universal Time (UTC), not the local timezone

    *To use SudoNotBefore and SudoNotAfter the user should enable the SUDOERS_TIMED option in the config file.*

    sudoOrder - The sudoRole entries retrieved from the LDAP directory have no inherent order. The sudoOrder attribute is an integer (or floating point value for LDAP servers that support it) that is used to sort the matching entries. This allows LDAP-based sudoers entries to more closely mimic the behaviour of the sudoers file, where the of the entries influences the result. If multiple entries match, the entry with the highest sudoOrder attribute is chosen.

    *A sudoRole must contain at least one sudoUser, sudoHost and sudoCommand.*

  4. The sudoRole that have '''cn=Defaults''' will be applied (if specified) over all the rules before applying any other rules. This mimics the default statements in the sudoers file.

Now we have the necessary information to move on.

Q1). What should we cache for offline sudo authentication???

The anatomy of sudo is as follows:

when you type ‘sudo cmd’ sudo is going to lookup in ldap to try and find the user POSIX groups and the user/host Nisnetgroup where the user is a member. Then it is going to do an ldap search in the ou=SUDOers container looking for any rule that matches that user or his usergroups. when it matches some rules, it goes down that list to see if the hostname OR a netgroup that the host is a member of is in that same rule, then finally it determines if the command ‘less’ is allowed.

This is how it works in a ldap server client. But in order to incorporate the netgroups we have to do some hack in the order of this anatomy.

For the successful validation we need to know the nisnetgroups and POSIX groups that a user/host is a member of. So that we need to cache the host/user-> nisgroup and user->posixgroups along with all sudoRole objects inside the SUDOers container that references to the specified command.

The simple solution for this problem is to enumerate all groups and netgroup information and check it with sudorules. But this approach less efficient and costly. Instead of enumerating all the rules, the procedure goes like this.

  • First we need to find the groups and user/host netgroups in which the user is a member of. That is the first step. We can do the search in DN: cn=accounts,dc=example,dc=com. Here we can use memberof plugin to resolve the user groups and the host groups. This step is already implemented inside the sssd. In order to include the support for NIS net groups we can add one more filter to the query that searches for the user groups. The query is

    (|
       (nisNetgroupTriple=\28*,username,*\29)
       (nisNetgroupTriple=\28hostname,*,*\29)
    )
    

    This will give you the netgroup that the user/host is a member of.

  • In the second phase we apply the search to filter the rules that applies to the user/host POSIX groups and netgroups found in step1. Search returns

    (\|(sudoBaseCommand=cmd)(sudoCommand=ALL)) where the
    sudoBaseCommand is JUST the command (not including args).
    

    The skeleton of the filter will be:

    (&
        (objectClass=sudoRole)
        (|
            (sudoUser=username)
            (sudoUser=#uid)
            (sudoUser=%usergroup1)
            (sudoUser=%usergroupN)
            (sudoUser=+userNetgroup1)
            (sudoUser=+userNetgroupN)
            (sudoUser=ALL)
        )
        (|
            (sudoHost=ipa.example.com)
            (sudoHost=+sample_host_group)
            (sudoHost=ALL)
        )
        (|
            (sudoBaseCommand=!cmd*)
            (sudoCommand=ALL)
        )
     )
    
  • From these rules the evaluation is done.

Performance Considerations

  1. Within a sudoRole, The sudoCommand attribute with an command negation is executed first, then sudoCommand with exact command is evaluated, at last the sudoCommands with ‘all’ is evaluated.
  2. To incorporate the sudoOrder attribute we can do the sorting AFTER our search filter. So we’ll limit the number of rules to sort first.
Q2) How to store cached data?
The cached data is in the LDAP format. So that the simple option available is to store it in the ldb file.