From c25c4bc816782930f5497732dab4ce6d15e9e97e Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 10:25:43 -0400
Subject: [PATCH 1/8] CONFIG: Add SR exclude_users exclude_groups options

Add options to allow explicitly excluding users and groups from
enforcing session recording. These options are recognized only
when the SR configuration defines 'scope=all'.
---
 src/confdb/confdb.h                  | 2 ++
 src/config/SSSDConfig/sssdoptions.py | 3 +++
 src/config/cfg_rules.ini             | 2 ++
 src/config/etc/sssd.api.conf         | 2 ++
 4 files changed, 9 insertions(+)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index c96896da5d..1f134945e6 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -190,6 +190,8 @@
 #define CONFDB_SESSION_RECORDING_SCOPE "scope"
 #define CONFDB_SESSION_RECORDING_USERS "users"
 #define CONFDB_SESSION_RECORDING_GROUPS "groups"
+#define CONFDB_SESSION_RECORDING_EXCLUDE_USERS "exclude_users"
+#define CONFDB_SESSION_RECORDING_EXCLUDE_GROUPS "exclude_groups"
 
 /* Domains */
 #define CONFDB_DOMAIN_ENABLED "enabled"
diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py
index f57ad4b41a..b833b661ce 100644
--- a/src/config/SSSDConfig/sssdoptions.py
+++ b/src/config/SSSDConfig/sssdoptions.py
@@ -162,6 +162,9 @@ def __init__(self):
         'groups': _('A comma-separated list of groups, members of which should have session recording enabled. '
                     'Matches group names as returned by NSS. I.e. after the possible space replacement, case changes, '
                     'etc.'),
+        'exclude_users': _('A comma-separated list of users to be excluded from recording, only when scope=all'),
+        'exclude_groups': _('A comma-separated list of groups, members of which should be excluded from recording, '
+                            ' only when scope=all. '),
 
         # [provider]
         'id_provider': _('Identity provider'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 2874ea048b..0663829d6b 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -331,6 +331,8 @@ section_re = ^session_recording$
 option = scope
 option = users
 option = groups
+option = exclude_users
+option = exclude_groups
 
 [rule/allowed_domain_options]
 validator = ini_allowed_options
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index 035c33cad8..099ebbfe6b 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -136,6 +136,8 @@ key = str, None, false
 scope = str, None, false
 users = list, str, false
 groups = list, str, false
+exclude_users = list, str, false
+exclude_groups = list, str, false
 
 [provider]
 #Available provider types

From b2732c2ffaebd950c633da4e33eec677524389fb Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 10:51:55 -0400
Subject: [PATCH 2/8] UTIL: Add support for SR exclude_users exclude_groups

Read the exclude_* option values to be applied elsewhere when
'scope=all'.
---
 src/util/session_recording.c | 14 ++++++++++++++
 src/util/session_recording.h | 11 +++++++++++
 2 files changed, 25 insertions(+)

diff --git a/src/util/session_recording.c b/src/util/session_recording.c
index fa480c4788..743f42f92b 100644
--- a/src/util/session_recording.c
+++ b/src/util/session_recording.c
@@ -107,6 +107,20 @@ errno_t session_recording_conf_load(TALLOC_CTX *mem_ctx,
                                     &pconf->groups);
     if (ret != EOK && ret != ENOENT) goto done;
 
+    /* Read session_recording/exclude users option */
+    ret = confdb_get_string_as_list(cdb, mem_ctx,
+                                    CONFDB_SESSION_RECORDING_CONF_ENTRY,
+                                    CONFDB_SESSION_RECORDING_EXCLUDE_USERS,
+                                    &pconf->exclude_users);
+    if (ret != EOK && ret != ENOENT) goto done;
+
+    /* Read session_recording/exclude groups option */
+    ret = confdb_get_string_as_list(cdb, mem_ctx,
+                                    CONFDB_SESSION_RECORDING_CONF_ENTRY,
+                                    CONFDB_SESSION_RECORDING_EXCLUDE_GROUPS,
+                                    &pconf->exclude_groups);
+    if (ret != EOK && ret != ENOENT) goto done;
+
     ret = EOK;
 done:
     return ret;
diff --git a/src/util/session_recording.h b/src/util/session_recording.h
index 69fb1a8bc4..2b77b445b9 100644
--- a/src/util/session_recording.h
+++ b/src/util/session_recording.h
@@ -53,6 +53,17 @@ struct session_recording_conf {
      * scope is "some"
      */
     char                          **groups;
+    /**
+     * NULL-terminated list of users to be excluded from recording.
+     * Can be NULL, meaning empty list. Only applicable if scope is "all".
+     */
+    char                          **exclude_users;
+    /**
+     * NULL-terminated list of groups, members of which should be excluded
+     * from recording. Can be NULL, meaning empty list. Only applicable if
+     * scope is "all"
+     */
+    char                          **exclude_groups;
 };
 
 /**

From ea11223354bc1debe462aa23e41db92e60c5c187 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 11:11:57 -0400
Subject: [PATCH 3/8] NSS: Rely on sessionRecording attribute

Don't force the tlog-rec-session shell when 'scope=all' is set,
instead read the sessionRecording attribute allowing
exclude_* options to work properly.
---
 src/responder/nss/nss_protocol_pwent.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c
index f9f3f0cf05..c9926cdc99 100644
--- a/src/responder/nss/nss_protocol_pwent.c
+++ b/src/responder/nss/nss_protocol_pwent.c
@@ -134,10 +134,7 @@ nss_get_shell(struct nss_ctx *nss_ctx,
 {
     const char *shell = NULL;
 
-    if (nss_ctx->rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) {
-        shell = SESSION_RECORDING_SHELL;
-    } else if (nss_ctx->rctx->sr_conf.scope ==
-               SESSION_RECORDING_SCOPE_SOME) {
+    if (nss_ctx->rctx->sr_conf.scope != SESSION_RECORDING_SCOPE_NONE) {
         const char *sr_enabled;
         sr_enabled = ldb_msg_find_attr_as_string(
                                     msg, SYSDB_SESSION_RECORDING, NULL);

From 14df25de24c5b504696c815bd5552263f078b06e Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 11:16:49 -0400
Subject: [PATCH 4/8] PAM: Rely on sessionRecording attribute

Don't force the tlog-rec-session shell when 'scope=all' is set,
instead read the sessionRecording attribute allowing
exclude_* options to work properly.
---
 src/responder/pam/pamsrv_cmd.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index 666131cb77..d76ade943a 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -752,9 +752,6 @@ static int pam_reply_sr_export_shell(struct pam_auth_req *preq,
     if (preq->cctx->rctx->sr_conf.scope ==
             SESSION_RECORDING_SCOPE_NONE) {
         enabled = false;
-    } else if (preq->cctx->rctx->sr_conf.scope ==
-            SESSION_RECORDING_SCOPE_ALL) {
-        enabled = true;
     } else {
         enabled_str = ldb_msg_find_attr_as_string(preq->user_obj,
                                                   SYSDB_SESSION_RECORDING, NULL);

From a5f343b719fb2b0432701262f112d5a2dccfd611 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 15:52:43 -0400
Subject: [PATCH 5/8] DP: Support SR excludes in initgroups postprocessing

When 'scope=all' is configured, set the user sessionRecording attribute
to false if a match is found with 'exclude_users' and 'exclude_groups'
values, and true otherwise, when no exclude match is found.
---
 src/providers/data_provider/dp_target_id.c | 61 ++++++++++++++++++----
 1 file changed, 51 insertions(+), 10 deletions(-)

diff --git a/src/providers/data_provider/dp_target_id.c b/src/providers/data_provider/dp_target_id.c
index 28c5928251..a6f407fcd8 100644
--- a/src/providers/data_provider/dp_target_id.c
+++ b/src/providers/data_provider/dp_target_id.c
@@ -177,6 +177,8 @@ static void dp_req_initgr_pp_sr_overlay(struct data_provider *provider,
     char *output_name;
     char **conf_user;
     char **conf_group;
+    char **conf_exclude_user;
+    char **conf_exclude_group;
     size_t i;
     TALLOC_CTX *tmp_ctx = NULL;
     errno_t ret;
@@ -184,11 +186,14 @@ static void dp_req_initgr_pp_sr_overlay(struct data_provider *provider,
     struct sysdb_attrs del_attrs = { 1, &el };
     struct sysdb_attrs *add_attrs;
 
-    /* If selective session recording is not enabled */
-    if (be->sr_conf.scope != SESSION_RECORDING_SCOPE_SOME) {
+    /* Only proceed if scope is applicable: 'some' or 'all' */
+    if (be->sr_conf.scope == SESSION_RECORDING_SCOPE_NONE) {
         goto done;
     }
 
+    /* Default to enabled when scope is 'all' */
+    enabled = be->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL ? true : false;
+
     /* Allocate temporary talloc context */
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
@@ -240,12 +245,29 @@ static void dp_req_initgr_pp_sr_overlay(struct data_provider *provider,
         }
     }
 
+    /* For each exclude user name in session recording config */
+    conf_exclude_user = be->sr_conf.exclude_users;
+    if (conf_exclude_user != NULL &&
+            be->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) {
+        for (; *conf_exclude_user != NULL && enabled; conf_exclude_user++) {
+            if (strcmp(*conf_exclude_user, output_name) == 0) {
+                enabled = false;
+            }
+        }
+    }
+
     /* If we have groups in config and are not yet enabled */
-    if (be->sr_conf.groups != NULL &&
+    if ((be->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME &&
+        be->sr_conf.groups != NULL &&
         be->sr_conf.groups[0] != NULL &&
-        !enabled) {
+        !enabled) ||
+        /* Or if we have exclude_groups in config and are enabled */
+        (be->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL &&
+        be->sr_conf.exclude_groups != NULL &&
+        be->sr_conf.exclude_groups[0] != NULL &&
+        enabled)) {
         /* For each group in response */
-        for (i = 0; i < res->count && !enabled; i++) {
+        for (i = 0; i < res->count; i++) {
             /* Get the group msg */
             if (i == 0) {
                 gid_t gid;
@@ -289,13 +311,32 @@ static void dp_req_initgr_pp_sr_overlay(struct data_provider *provider,
                 goto done;
             }
             /* For each group in configuration */
-            for (conf_group = be->sr_conf.groups;
-                 *conf_group != NULL && !enabled;
-                 conf_group++) {
-                if (strcmp(*conf_group, output_name) == 0) {
-                    enabled = true;
+            if (be->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME) {
+                for (conf_group = be->sr_conf.groups;
+                     *conf_group != NULL && !enabled;
+                     conf_group++) {
+                    if (strcmp(*conf_group, output_name) == 0) {
+                        enabled = true;
+                    }
+                }
+            /* For each exclude group in configuration */
+            } else if (be->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) {
+                for (conf_exclude_group = be->sr_conf.exclude_groups;
+                     *conf_exclude_group != NULL && enabled;
+                     conf_exclude_group++) {
+                    if (strcmp(*conf_exclude_group, output_name) == 0) {
+                        enabled = false;
+                    }
                 }
             }
+
+            /* Found a matched group */
+            if ((be->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME
+                && enabled) ||
+                (be->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL
+                && !enabled)) {
+                break;
+            }
         }
     }
 

From 0a1a9227b4fdeb2d0a2c694c041eced987c0088a Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Wed, 15 Jul 2020 16:11:58 -0400
Subject: [PATCH 6/8] CACHE_REQ: Support SR exclude options

When 'scope=all' is configured, set the user sessionRecording
attribute to false if a match is found with 'exclude_users' and
'exclude_groups' values, and true otherwise, when no exclude match is found.
---
 .../common/cache_req/cache_req_sr_overlay.c   | 36 ++++++++++++++-----
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/responder/common/cache_req/cache_req_sr_overlay.c b/src/responder/common/cache_req/cache_req_sr_overlay.c
index b06a80a774..8deb06a603 100644
--- a/src/responder/common/cache_req/cache_req_sr_overlay.c
+++ b/src/responder/common/cache_req/cache_req_sr_overlay.c
@@ -70,7 +70,7 @@ struct tevent_req *cache_req_sr_overlay_send(
     state->num_results = num_results;
 
     /* If session recording is selective */
-    if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME) {
+    if (rctx->sr_conf.scope != SESSION_RECORDING_SCOPE_NONE) {
         /* If it's a request for a user/users */
         switch (cr->data->type) {
         case CACHE_REQ_USER_BY_NAME:
@@ -78,8 +78,10 @@ struct tevent_req *cache_req_sr_overlay_send(
         case CACHE_REQ_USER_BY_ID:
         case CACHE_REQ_ENUM_USERS:
             /* If we have group names to match against */
-            if (rctx->sr_conf.groups != NULL &&
-                rctx->sr_conf.groups[0] != NULL) {
+            if ((rctx->sr_conf.groups != NULL &&
+                 rctx->sr_conf.groups[0] != NULL) ||
+                (rctx->sr_conf.exclude_groups != NULL &&
+                 rctx->sr_conf.exclude_groups[0] != NULL)) {
                 /* Pull and match group and user names for each user entry */
                 subreq = cache_req_sr_overlay_match_all_step_send(state);
                 if (subreq == NULL) {
@@ -128,6 +130,7 @@ static errno_t cache_req_sr_overlay_match_users(
     const char *name;
     char *output_name;
     char **conf_user;
+    char **conf_exclude_user;
     bool enabled;
     char *enabled_str;
 
@@ -170,12 +173,27 @@ static errno_t cache_req_sr_overlay_match_users(
             /* For each user name in session recording config */
             enabled = false;
             conf_user = rctx->sr_conf.users;
-            if (conf_user != NULL) {
-                for (; *conf_user != NULL; conf_user++) {
-                    /* If it matches the requested user name */
-                    if (strcmp(*conf_user, output_name) == 0) {
-                        enabled = true;
-                        break;
+            if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_SOME) {
+                if (conf_user != NULL) {
+                    for (; *conf_user != NULL; conf_user++) {
+                        /* If it matches the requested user name */
+                        if (strcmp(*conf_user, output_name) == 0) {
+                            enabled = true;
+                            break;
+                        }
+                    }
+                }
+            /* For each exclude user name in session recording config */
+            } else if (rctx->sr_conf.scope == SESSION_RECORDING_SCOPE_ALL) {
+                enabled = true;
+                conf_exclude_user = rctx->sr_conf.exclude_users;
+                if (conf_exclude_user != NULL) {
+                    for (; *conf_exclude_user != NULL; conf_exclude_user++) {
+                        /* If it matches the requested user name */
+                        if (strcmp(*conf_exclude_user, output_name) == 0) {
+                            enabled = false;
+                            break;
+                        }
                     }
                 }
             }

From 26c67b09969ffe3afaecf2997893e6ed3d585aa6 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Thu, 16 Jul 2020 13:41:18 -0400
Subject: [PATCH 7/8] INTG: Add session recording exclude tests

Add basic tests for exclude_users and exclude_groups options.
---
 src/tests/intg/test_session_recording.py | 162 +++++++++++++++++++++++
 1 file changed, 162 insertions(+)

diff --git a/src/tests/intg/test_session_recording.py b/src/tests/intg/test_session_recording.py
index 91cd93bfcb..34a586e4a2 100644
--- a/src/tests/intg/test_session_recording.py
+++ b/src/tests/intg/test_session_recording.py
@@ -1000,3 +1000,165 @@ def test_some_users_and_groups_ent(some_users_and_groups):
             dict(name="user4", uid=1004, shell="/bin/sh4"),
         )
     )
+
+
+@pytest.fixture
+def all_exclude_users(request, ldap_conn, users_and_groups):
+    """
+    Test "all" scope with a simple excludes user list
+    """
+    conf = \
+        format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \
+        unindent("""\
+            [session_recording]
+            scope = all
+            exclude_users = user1, user3
+        """).format(**locals())
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+
+
+def test_all_exclude_users_nam(all_exclude_users):
+    """Test "all" scope with exclude users list and getpwnam"""
+    ent.assert_each_passwd_by_name(dict(
+        user1=dict(name="user1", uid=1001, shell="/bin/sh1"),
+        user2=dict(name="user2", uid=1002,
+                   shell=config.SESSION_RECORDING_SHELL),
+        user3=dict(name="user3", uid=1003, shell="/bin/sh3"),
+        user4=dict(name="user4", uid=1004,
+                   shell=config.SESSION_RECORDING_SHELL),
+    ))
+
+
+def test_all_exclude_users_uid(all_exclude_users):
+    """Test "all" scope with exclude users list and getpwuid"""
+    ent.assert_each_passwd_by_uid({
+        1001: dict(name="user1", uid=1001, shell="/bin/sh1"),
+        1002: dict(name="user2", uid=1002,
+                   shell=config.SESSION_RECORDING_SHELL),
+        1003: dict(name="user3", uid=1003, shell="/bin/sh3"),
+        1004: dict(name="user4", uid=1004,
+                   shell=config.SESSION_RECORDING_SHELL),
+    })
+
+
+def test_all_exclude_users_ent(all_exclude_users):
+    """Test "all" scope with exclude users list and getpwent"""
+    ent.assert_passwd_list(
+        ent.contains_only(
+            dict(name="user1", uid=1001, shell="/bin/sh1"),
+            dict(name="user2", uid=1002, shell=config.SESSION_RECORDING_SHELL),
+            dict(name="user3", uid=1003, shell="/bin/sh3"),
+            dict(name="user4", uid=1004, shell=config.SESSION_RECORDING_SHELL),
+        )
+    )
+
+
+@pytest.fixture
+def all_exclude_groups(request, ldap_conn, users_and_groups):
+    """
+    Fixture with scope "all", specifying two primary exclude
+    groups and one supplementary exclude group.
+    """
+    conf = \
+        format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \
+        unindent("""\
+            [session_recording]
+            scope = all
+            exclude_groups = group1, group3, two_user_group
+        """).format(**locals())
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+
+
+def test_all_exclude_groups_nam(all_exclude_groups):
+    """Test "all" scope with exclude groups list and getpwnam"""
+    ent.assert_each_passwd_by_name(dict(
+        user1=dict(name="user1", uid=1001, shell="/bin/sh1"),
+        user2=dict(name="user2", uid=1002, shell="/bin/sh2"),
+        user3=dict(name="user3", uid=1003, shell="/bin/sh3"),
+        user4=dict(name="user4", uid=1004,
+                   shell=config.SESSION_RECORDING_SHELL),
+    ))
+
+
+def test_all_exclude_groups_uid(all_exclude_groups):
+    """Test "all" scope with group list and getpwuid"""
+    ent.assert_each_passwd_by_uid({
+        1001: dict(name="user1", uid=1001, shell="/bin/sh1"),
+        1002: dict(name="user2", uid=1002, shell="/bin/sh2"),
+        1003: dict(name="user3", uid=1003, shell="/bin/sh3"),
+        1004: dict(name="user4", uid=1004,
+                   shell=config.SESSION_RECORDING_SHELL),
+    })
+
+
+def test_all_exclude_groups_ent(all_exclude_groups):
+    """Test "all" scope with group list and getpwent"""
+    ent.assert_passwd_list(
+        ent.contains_only(
+            dict(name="user1", uid=1001, shell="/bin/sh1"),
+            dict(name="user2", uid=1002, shell="/bin/sh2"),
+            dict(name="user3", uid=1003, shell="/bin/sh3"),
+            dict(name="user4", uid=1004,
+                 shell=config.SESSION_RECORDING_SHELL),
+        )
+    )
+
+
+@pytest.fixture
+def some_users_and_exclude_groups(request, ldap_conn, users_and_groups):
+    """
+    Fixture with scope "some" containing users to
+    enable recording, and exclude_* options to be ignored
+    intentionally
+    """
+    conf = \
+        format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \
+        unindent("""\
+            [session_recording]
+            scope = some
+            users = user1, user2
+            exclude_users = user1, user2, user3
+            exclude_groups = group1, group3, two_user_group
+        """).format(**locals())
+    create_conf_fixture(request, conf)
+    create_sssd_fixture(request)
+
+
+def test_some_users_and_exclude_groups_nam(some_users_and_exclude_groups):
+    """Test "some" scope with exclude users and groups list and getpwnam"""
+    ent.assert_each_passwd_by_name(dict(
+        user1=dict(name="user1", uid=1001,
+                   shell=config.SESSION_RECORDING_SHELL),
+        user2=dict(name="user2", uid=1002,
+                   shell=config.SESSION_RECORDING_SHELL),
+        user3=dict(name="user3", uid=1003, shell="/bin/sh3"),
+        user4=dict(name="user4", uid=1004, shell="/bin/sh4"),
+    ))
+
+
+def test_some_users_and_exclude_groups_uid(some_users_and_exclude_groups):
+    """Test "some" scope with exclude users and groups list and getpwuid"""
+    ent.assert_each_passwd_by_uid({
+        1001: dict(name="user1", uid=1001,
+                   shell=config.SESSION_RECORDING_SHELL),
+        1002: dict(name="user2", uid=1002,
+                   shell=config.SESSION_RECORDING_SHELL),
+        1003: dict(name="user3", uid=1003, shell="/bin/sh3"),
+        1004: dict(name="user4", uid=1004, shell="/bin/sh4"),
+    })
+
+
+def test_some_users_and_exclude_groups_ent(some_users_and_exclude_groups):
+    """Test "some" scope with exclude users and group list and getpwent"""
+    ent.assert_passwd_list(
+        ent.contains_only(
+            dict(name="user1", uid=1001,
+                 shell=config.SESSION_RECORDING_SHELL),
+            dict(name="user2", uid=1002,
+                 shell=config.SESSION_RECORDING_SHELL),
+            dict(name="user3", uid=1003, shell="/bin/sh3"),
+            dict(name="user4", uid=1004, shell="/bin/sh4"),
+        )
+    )

From f787a76278b383a918b26597c66b2fa5ac9bdf33 Mon Sep 17 00:00:00 2001
From: Justin Stephenson <jstephen@redhat.com>
Date: Thu, 16 Jul 2020 14:11:03 -0400
Subject: [PATCH 8/8] MAN: Add SR exclude_users and exclude_groups options

---
 src/man/sssd-session-recording.5.xml | 32 ++++++++++++++++++++++++++++
 src/man/sssd.conf.5.xml              | 32 ++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/src/man/sssd-session-recording.5.xml b/src/man/sssd-session-recording.5.xml
index c4b6d7a03c..6eeebdd61f 100644
--- a/src/man/sssd-session-recording.5.xml
+++ b/src/man/sssd-session-recording.5.xml
@@ -137,6 +137,38 @@
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>exclude_users (string)</term>
+                    <listitem>
+                        <para>
+                            A comma-separated list of users to be excluded from
+                            recording, only applicable with 'scope=all'.
+                        </para>
+                        <para>
+                            Default: Empty. No users excluded.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>exclude_groups (string)</term>
+                    <listitem>
+                        <para>
+                            A comma-separated list of groups, members of which
+                            should be excluded from recording. Only applicable
+                            with 'scope=all'.
+                        </para>
+                        <para>
+                            NOTE: using this option (having it set to
+                            anything) has a considerable performance cost,
+                            because each uncached request for a user requires
+                            retrieving and matching the groups the user is
+                            member of.
+                        </para>
+                        <para>
+                            Default: Empty. No groups excluded.
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
     </refsect1>
 
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index 874a09c494..0a5125be14 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -2093,6 +2093,38 @@ p11_uri = library-description=OpenSC%20smartcard%20framework;slot-id=2
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>exclude_users (string)</term>
+                    <listitem>
+                        <para>
+                            A comma-separated list of users to be excluded from
+                            recording, only applicable with 'scope=all'.
+                        </para>
+                        <para>
+                            Default: Empty. No users excluded.
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>exclude_groups (string)</term>
+                    <listitem>
+                        <para>
+                            A comma-separated list of groups, members of which
+                            should be excluded from recording. Only applicable
+                            with 'scope=all'.
+                        </para>
+                        <para>
+                            NOTE: using this option (having it set to
+                            anything) has a considerable performance cost,
+                            because each uncached request for a user requires
+                            retrieving and matching the groups the user is
+                            member of.
+                        </para>
+                        <para>
+                            Default: Empty. No groups excluded.
+                        </para>
+                    </listitem>
+                </varlistentry>
             </variablelist>
         </refsect2>
 
