URL: https://github.com/SSSD/sssd/pull/136 Author: spbnick Title: #136: Tlog integration WIP Action: opened
PR body: """ @lslebodn, @pbrezina, this is the work-in-progress tlog integration patchset I'd like to work on with you. This is not for merging as it is. We can go over it when we meet :) """ To pull the PR as Git branch: git remote add ghsssd https://github.com/SSSD/sssd git fetch ghsssd pull/136/head:pr136 git checkout pr136
From 50a5ef8822e8573136f3e1a4841adc6f4a4fa566 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Tue, 20 Dec 2016 10:16:47 +0200 Subject: [PATCH 01/11] config: Add session_recording section Add information on "session_recording" config section, having three options: "scope", "users", and "groups". The section is intended for disabling session recording ("scope = none", default), enabling session recording for all users ("scope = all"), and enabling it for some specific users and/or groups ("scope = some", "users = <users>", "groups = <groups>"). --- src/confdb/confdb.h | 6 ++++++ src/config/SSSDConfigTest.py | 6 ++++-- src/config/etc/sssd.api.conf | 6 ++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index 9055048..0794451 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -159,6 +159,12 @@ #define CONFDB_IFP_USER_ATTR_LIST "user_attributes" #define CONFDB_IFP_WILDCARD_LIMIT "wildcard_limit" +/* Session Recording */ +#define CONFDB_SESSION_RECORDING_CONF_ENTRY "config/session_recording" +#define CONFDB_SESSION_RECORDING_SCOPE "scope" +#define CONFDB_SESSION_RECORDING_USERS "users" +#define CONFDB_SESSION_RECORDING_GROUPS "groups" + /* Domains */ #define CONFDB_DOMAIN_PATH_TMPL "config/domain/%s" #define CONFDB_DOMAIN_BASEDN "cn=domain,cn=config" diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py index 0da5d63..c4dc65a 100755 --- a/src/config/SSSDConfigTest.py +++ b/src/config/SSSDConfigTest.py @@ -1354,7 +1354,8 @@ def testNewConfig(self): 'ssh', 'pac', 'ifp', - 'secrets'] + 'secrets', + 'session_recording'] for section in control_list: self.assertTrue(sssdconfig.has_section(section), "Section [%s] missing" % @@ -1448,7 +1449,8 @@ def testListServices(self): 'ssh', 'pac', 'ifp', - 'secrets'] + 'secrets', + 'session_recording'] service_list = sssdconfig.list_services() for service in control_list: self.assertTrue(service in service_list, diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf index 5654006..7fea58c 100644 --- a/src/config/etc/sssd.api.conf +++ b/src/config/etc/sssd.api.conf @@ -111,6 +111,12 @@ forward_headers = list, None, false username = str, None, false password = str, None, false +[session_recording] +# Session recording service +scope = str, None, false +users = list, str, false +groups = list, str, false + [provider] #Available provider types id_provider = str, None, true From 08a412dcdd332311cd59e6138563f088de86d7f8 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 11 Aug 2016 14:15:55 +0300 Subject: [PATCH 02/11] BUILD: Support configuring session recording shell Add support for specifying the shell used for recording user sessions, at configure time. --- configure.ac | 1 + src/conf_macros.m4 | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/configure.ac b/configure.ac index 2915046..b9ed9e6 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,7 @@ WITH_SEMANAGE WITH_AD_GPO_DEFAULT WITH_GPO_CACHE_PATH WITH_NOLOGIN_SHELL +WITH_SESSION_RECORDING_SHELL WITH_APP_LIBS WITH_SUDO WITH_SUDO_LIB_PATH diff --git a/src/conf_macros.m4 b/src/conf_macros.m4 index 427b0e0..5422a57 100644 --- a/src/conf_macros.m4 +++ b/src/conf_macros.m4 @@ -592,6 +592,22 @@ AC_DEFUN([WITH_NOLOGIN_SHELL], AC_DEFINE_UNQUOTED(NOLOGIN_SHELL, "$nologin_shell", [The shell used to deny access to users]) ]) +AC_DEFUN([WITH_SESSION_RECORDING_SHELL], + [ AC_ARG_WITH([session-recording-shell], + [AC_HELP_STRING([--with-session-recording-shell=PATH], + [The shell used to record user sessions [/usr/bin/tlog-rec]] + ) + ] + ) + session_recording_shell="/usr/bin/tlog-rec" + if test x"$with_session_recording_shell" != x; then + nologin_shell=$with_session_recording_shell + fi + AC_SUBST(session_recording_shell) + AC_DEFINE_UNQUOTED(SESSION_RECORDING_SHELL, "$session_recording_shell", + [The shell used to record user sessions]) + ]) + AC_ARG_ENABLE([all-experimental-features], [AS_HELP_STRING([--enable-all-experimental-features], [build all experimental features])], From aa1203c7ae6b5b0a030d2cf94df8fcb8f7bb2831 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 18:42:46 +0200 Subject: [PATCH 03/11] Fix func names in sysdb_views.c error messages --- src/db/sysdb_views.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c index 9dc48f5..2d2fac8 100644 --- a/src/db/sysdb_views.c +++ b/src/db/sysdb_views.c @@ -298,7 +298,7 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) ret = ldb_search(sysdb->ldb, tmp_ctx, &res, base_dn, LDB_SCOPE_SUBTREE, NULL, "%s", SYSDB_GC); if (ret != LDB_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "ldb_search failed.\n"); ret = sysdb_error_to_errno(ret); goto done; } @@ -353,19 +353,23 @@ add_name_and_aliases_for_name_override(struct sss_domain_info *domain, ret = sysdb_attrs_add_string(attrs, SYSDB_DEFAULT_OVERRIDE_NAME, name_override); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); return ret; } } if (!domain->case_sensitive) { ret = sysdb_attrs_add_lc_name_alias(attrs, name_override); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n"); + return ret; + } } else { ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, name_override); - } - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_lc_name_alias failed.\n"); - return ret; + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); + return ret; + } } return EOK; @@ -692,7 +696,7 @@ static errno_t safe_original_attributes(struct sss_domain_info *domain, ret = sysdb_attrs_add_val_safe(attrs, SYSDB_NAME_ALIAS, &el->values[c]); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_val_safe failed.\n"); goto done; } } @@ -1332,7 +1336,7 @@ errno_t sysdb_add_overrides_to_object(struct sss_domain_info *domain, ret = ldb_msg_add_steal_value(obj, attr_map[c].new_attr, &tmp_el->values[d]); if (ret != LDB_SUCCESS) { - DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_value failed.\n"); + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_steal_value failed.\n"); ret = sysdb_error_to_errno(ret); goto done; } From 6d94a80492a98e33cf9b8b425f6361c710a85d4a Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 18:46:36 +0200 Subject: [PATCH 04/11] Rename nss_get_name_from_msg to sysdb_get_name_from_msg Move nss_get_name_from_msg function from nss_utils.c to sysdb_views.c, and rename it to sysdb_get_name_from_msg to make it available to all responder, in anticipation of implementing session recording support. --- src/db/sysdb.h | 3 +++ src/db/sysdb_views.c | 27 +++++++++++++++++++++++++++ src/responder/nss/nss_private.h | 4 ---- src/responder/nss/nss_protocol_grent.c | 2 +- src/responder/nss/nss_protocol_pwent.c | 2 +- src/responder/nss/nss_utils.c | 27 --------------------------- 6 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 8a363d0..21f8188 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -617,6 +617,9 @@ uint64_t sss_view_ldb_msg_find_attr_as_uint64(struct sss_domain_info *dom, const char *attr_name, uint64_t default_value); +const char *sysdb_get_name_from_msg(const struct sss_domain_info *domain, + const struct ldb_message *msg); + /* Sysdb initialization. * call this function *only* once to initialize the database and get * the sysdb ctx */ diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c index 2d2fac8..2198bb1 100644 --- a/src/db/sysdb_views.c +++ b/src/db/sysdb_views.c @@ -1644,3 +1644,30 @@ const char *sss_view_ldb_msg_find_attr_as_string(struct sss_domain_info *dom, talloc_free(tmp_ctx); return val; } + +const char * +sysdb_get_name_from_msg(const struct sss_domain_info *domain, + const struct ldb_message *msg) +{ + const char *name; + + /* If domain has a view associated we return overridden name + * if possible. */ + if (DOM_HAS_VIEWS(domain)) { + name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, + NULL); + if (name != NULL) { + return name; + } + } + + /* Otherwise we try to return name override from + * Default Truest View for trusted users. */ + name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); + if (name != NULL) { + return name; + } + + /* If no override is found we return the original name. */ + return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); +} diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h index e63fbab..6086230 100644 --- a/src/responder/nss/nss_private.h +++ b/src/responder/nss/nss_private.h @@ -136,10 +136,6 @@ nss_setnetgrent_recv(struct tevent_req *req); /* Utils. */ -const char * -nss_get_name_from_msg(struct sss_domain_info *domain, - struct ldb_message *msg); - int sized_output_name(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, const char *orig_name, diff --git a/src/responder/nss/nss_protocol_grent.c b/src/responder/nss/nss_protocol_grent.c index 7409e04..de7b4bc 100644 --- a/src/responder/nss/nss_protocol_grent.c +++ b/src/responder/nss/nss_protocol_grent.c @@ -41,7 +41,7 @@ nss_get_grent(TALLOC_CTX *mem_ctx, } /* Get fields. */ - name = nss_get_name_from_msg(domain, msg); + name = sysdb_get_name_from_msg(domain, msg); gid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_GIDNUM, 0); if (name == NULL || gid == 0) { diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c index 783b06a..0d1b1f9 100644 --- a/src/responder/nss/nss_protocol_pwent.c +++ b/src/responder/nss/nss_protocol_pwent.c @@ -225,7 +225,7 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, /* Get fields. */ upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL); - name = nss_get_name_from_msg(domain, msg); + name = sysdb_get_name_from_msg(domain, msg); gid = nss_get_gid(domain, msg); uid = sss_view_ldb_msg_find_attr_as_uint64(domain, msg, SYSDB_UIDNUM, 0); diff --git a/src/responder/nss/nss_utils.c b/src/responder/nss/nss_utils.c index 41081c9..75f0eb6 100644 --- a/src/responder/nss/nss_utils.c +++ b/src/responder/nss/nss_utils.c @@ -25,33 +25,6 @@ #include "confdb/confdb.h" #include "responder/common/responder.h" -const char * -nss_get_name_from_msg(struct sss_domain_info *domain, - struct ldb_message *msg) -{ - const char *name; - - /* If domain has a view associated we return overridden name - * if possible. */ - if (DOM_HAS_VIEWS(domain)) { - name = ldb_msg_find_attr_as_string(msg, OVERRIDE_PREFIX SYSDB_NAME, - NULL); - if (name != NULL) { - return name; - } - } - - /* Otherwise we try to return name override from - * Default Truest View for trusted users. */ - name = ldb_msg_find_attr_as_string(msg, SYSDB_DEFAULT_OVERRIDE_NAME, NULL); - if (name != NULL) { - return name; - } - - /* If no override is found we return the original name. */ - return ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL); -} - int sized_output_name(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx, const char *orig_name, From 0a4f32b271d45860c6c7fe5059470584148e4a3e Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 18:51:13 +0200 Subject: [PATCH 05/11] Move enum cache_req_type to a separate header Move the definition of enum cache_req_type from cache_req.h to a separate header cache_req_type.h to avoid include loop, and allow including it into the session recording interface to be used by the cache_req module itself. --- Makefile.am | 1 + src/responder/common/cache_req/cache_req.h | 31 +------------- src/responder/common/cache_req/cache_req_type.h | 54 +++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 src/responder/common/cache_req/cache_req_type.h diff --git a/Makefile.am b/Makefile.am index 661e944..8f1495a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -639,6 +639,7 @@ dist_noinst_HEADERS = \ src/responder/common/responder_packet.h \ src/responder/common/responder_sbus.h \ src/responder/common/cache_req/cache_req.h \ + src/responder/common/cache_req/cache_req_type.h \ src/responder/common/cache_req/cache_req_plugin.h \ src/responder/common/cache_req/cache_req_private.h \ src/responder/common/data_provider/rdp.h \ diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h index 7700091..fd3055b 100644 --- a/src/responder/common/cache_req/cache_req.h +++ b/src/responder/common/cache_req/cache_req.h @@ -24,36 +24,7 @@ #include "util/util.h" #include "confdb/confdb.h" #include "responder/common/negcache.h" - -enum cache_req_type { - CACHE_REQ_USER_BY_NAME, - CACHE_REQ_USER_BY_UPN, - CACHE_REQ_USER_BY_ID, - CACHE_REQ_USER_BY_CERT, - CACHE_REQ_USER_BY_FILTER, - - CACHE_REQ_GROUP_BY_NAME, - CACHE_REQ_GROUP_BY_ID, - CACHE_REQ_GROUP_BY_FILTER, - - CACHE_REQ_INITGROUPS, - CACHE_REQ_INITGROUPS_BY_UPN, - - CACHE_REQ_OBJECT_BY_SID, - CACHE_REQ_OBJECT_BY_NAME, - CACHE_REQ_OBJECT_BY_ID, - - CACHE_REQ_ENUM_USERS, - CACHE_REQ_ENUM_GROUPS, - CACHE_REQ_ENUM_SVC, - - CACHE_REQ_SVC_BY_NAME, - CACHE_REQ_SVC_BY_PORT, - - CACHE_REQ_NETGROUP_BY_NAME, - - CACHE_REQ_SENTINEL -}; +#include "responder/common/cache_req/cache_req_type.h" /* Input data. */ diff --git a/src/responder/common/cache_req/cache_req_type.h b/src/responder/common/cache_req/cache_req_type.h new file mode 100644 index 0000000..43f0744 --- /dev/null +++ b/src/responder/common/cache_req/cache_req_type.h @@ -0,0 +1,54 @@ +/* + Authors: + Pavel Březina <pbrez...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CACHE_REQ_TYPE_H_ +#define _CACHE_REQ_TYPE_H_ + +enum cache_req_type { + CACHE_REQ_USER_BY_NAME, + CACHE_REQ_USER_BY_UPN, + CACHE_REQ_USER_BY_ID, + CACHE_REQ_USER_BY_CERT, + CACHE_REQ_USER_BY_FILTER, + + CACHE_REQ_GROUP_BY_NAME, + CACHE_REQ_GROUP_BY_ID, + CACHE_REQ_GROUP_BY_FILTER, + + CACHE_REQ_INITGROUPS, + CACHE_REQ_INITGROUPS_BY_UPN, + + CACHE_REQ_OBJECT_BY_SID, + CACHE_REQ_OBJECT_BY_NAME, + CACHE_REQ_OBJECT_BY_ID, + + CACHE_REQ_ENUM_USERS, + CACHE_REQ_ENUM_GROUPS, + CACHE_REQ_ENUM_SVC, + + CACHE_REQ_SVC_BY_NAME, + CACHE_REQ_SVC_BY_PORT, + + CACHE_REQ_NETGROUP_BY_NAME, + + CACHE_REQ_SENTINEL +}; + +#endif /* _CACHE_REQ_TYPE_H_ */ From fecd87786ba215279df6fcab0d6d4c67d5325f6c Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Tue, 17 Jan 2017 09:18:00 +0200 Subject: [PATCH 06/11] Move struct cache_req_result to a separate header Move the definition of struct cache_req_result from cache_req.h to a separate header cache_req_result.h to avoid include loop, and allow including it into the session recording interface to be used by the cache_req module itself. --- Makefile.am | 1 + src/responder/common/cache_req/cache_req.h | 39 +------------- src/responder/common/cache_req/cache_req_result.h | 62 +++++++++++++++++++++++ 3 files changed, 64 insertions(+), 38 deletions(-) create mode 100644 src/responder/common/cache_req/cache_req_result.h diff --git a/Makefile.am b/Makefile.am index 8f1495a..e5e91e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -639,6 +639,7 @@ dist_noinst_HEADERS = \ src/responder/common/responder_packet.h \ src/responder/common/responder_sbus.h \ src/responder/common/cache_req/cache_req.h \ + src/responder/common/cache_req/cache_req_result.h \ src/responder/common/cache_req/cache_req_type.h \ src/responder/common/cache_req/cache_req_plugin.h \ src/responder/common/cache_req/cache_req_private.h \ diff --git a/src/responder/common/cache_req/cache_req.h b/src/responder/common/cache_req/cache_req.h index fd3055b..7a95cdb 100644 --- a/src/responder/common/cache_req/cache_req.h +++ b/src/responder/common/cache_req/cache_req.h @@ -25,6 +25,7 @@ #include "confdb/confdb.h" #include "responder/common/negcache.h" #include "responder/common/cache_req/cache_req_type.h" +#include "responder/common/cache_req/cache_req_result.h" /* Input data. */ @@ -76,44 +77,6 @@ cache_req_data_svc(TALLOC_CTX *mem_ctx, /* Output data. */ -struct cache_req_result { - /** - * SSSD domain where the result was obtained. - */ - struct sss_domain_info *domain; - - /** - * Result from ldb lookup. - */ - struct ldb_result *ldb_result; - - /** - * Shortcuts into ldb_result. This shortens the code a little since - * callers usually don't don't need to work with ldb_result directly. - */ - unsigned int count; - struct ldb_message **msgs; - - /** - * If name was used as a lookup parameter, @lookup_name contains name - * normalized to @domain rules. - */ - const char *lookup_name; - - /** - * If true the result contain attributes of a well known object. - * Since this result is manually created it may not contain all - * requested attributes, depending on the plug-in. - */ - bool well_known_object; - - /* If this is a well known object, it may not be part of any particular - * SSSD domain, but still may be associated with a well known domain - * name such as "BUILTIN", or "LOCAL AUTHORITY". - */ - const char *well_known_domain; -}; - /** * Shallow copy of cache request result, limiting the result to a maximum * numbers of records. diff --git a/src/responder/common/cache_req/cache_req_result.h b/src/responder/common/cache_req/cache_req_result.h new file mode 100644 index 0000000..d5908c8 --- /dev/null +++ b/src/responder/common/cache_req/cache_req_result.h @@ -0,0 +1,62 @@ +/* + Authors: + Pavel Březina <pbrez...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CACHE_REQ_RESULT_H_ +#define _CACHE_REQ_RESULT_H_ + +struct cache_req_result { + /** + * SSSD domain where the result was obtained. + */ + struct sss_domain_info *domain; + + /** + * Result from ldb lookup. + */ + struct ldb_result *ldb_result; + + /** + * Shortcuts into ldb_result. This shortens the code a little since + * callers usually don't don't need to work with ldb_result directly. + */ + unsigned int count; + struct ldb_message **msgs; + + /** + * If name was used as a lookup parameter, @lookup_name contains name + * normalized to @domain rules. + */ + const char *lookup_name; + + /** + * If true the result contain attributes of a well known object. + * Since this result is manually created it may not contain all + * requested attributes, depending on the plug-in. + */ + bool well_known_object; + + /* If this is a well known object, it may not be part of any particular + * SSSD domain, but still may be associated with a well known domain + * name such as "BUILTIN", or "LOCAL AUTHORITY". + */ + const char *well_known_domain; +}; + +#endif /* _CACHE_REQ_RESULT_H_ */ From 24b78bd758c8ba8f3ece7f7735345bdfb31d9201 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Tue, 17 Jan 2017 09:35:37 +0200 Subject: [PATCH 07/11] Move searched domain name to struct cache_req_state Instead of passing around the name of the domain being searched as argument in cache_req.c, move it to struct cache_req_state to simplify adding another request to the chain, which doesn't deal with domain names. --- src/responder/common/cache_req/cache_req.c | 46 ++++++++++++++++++------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c index f546e61..20f4263 100644 --- a/src/responder/common/cache_req/cache_req.c +++ b/src/responder/common/cache_req/cache_req.c @@ -312,6 +312,7 @@ struct cache_req_state { struct cache_req *cr; /* work data */ + char *domain_name; struct sss_domain_info *domain; struct sss_domain_info *selected_domain; struct cache_req_result **results; @@ -325,13 +326,11 @@ static errno_t cache_req_add_result(struct cache_req_state *state, static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, struct tevent_req *req, - struct cache_req *cr, - const char *domain); + struct cache_req *cr); static void cache_req_input_parsed(struct tevent_req *subreq); -static errno_t cache_req_select_domains(struct tevent_req *req, - const char *domain); +static errno_t cache_req_select_domains(struct tevent_req *req); static errno_t cache_req_next_domain(struct tevent_req *req); @@ -359,6 +358,15 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->dp_success = true; + if (domain == NULL) { + state->domain_name = NULL; + } else { + state->domain_name = talloc_strdup(state, domain); + if (state->domain_name == NULL) { + ret = ENOMEM; + goto done; + } + } state->cr = cr = cache_req_create(state, rctx, data, ncache, midpoint); if (state->cr == NULL) { ret = ENOMEM; @@ -375,12 +383,12 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, goto done; } - ret = cache_req_process_input(state, req, cr, domain); + ret = cache_req_process_input(state, req, cr); if (ret != EOK) { goto done; } - ret = cache_req_select_domains(req, domain); + ret = cache_req_select_domains(req); done: if (ret == EOK) { @@ -396,17 +404,19 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, struct tevent_req *req, - struct cache_req *cr, - const char *domain) + struct cache_req *cr) { + struct cache_req_state *state; struct tevent_req *subreq; + state = tevent_req_data(req, struct cache_req_state); + if (cr->data->name.input == NULL) { /* Input was not name, there is no need to process it further. */ return EOK; } - if (cr->plugin->parse_name == false || domain != NULL) { + if (cr->plugin->parse_name == false || state->domain_name != NULL) { /* We do not want to parse the name. */ return cache_req_set_name(cr, cr->data->name.input); } @@ -431,14 +441,13 @@ static void cache_req_input_parsed(struct tevent_req *subreq) struct tevent_req *req; struct cache_req_state *state; char *name; - char *domain; bool maybe_upn; errno_t ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct cache_req_state); - ret = sss_parse_inp_recv(subreq, state, &name, &domain); + ret = sss_parse_inp_recv(subreq, state, &name, &state->domain_name); switch (ret) { case EOK: ret = cache_req_set_name(state->cr, name); @@ -454,32 +463,32 @@ static void cache_req_input_parsed(struct tevent_req *subreq) return; } - domain = NULL; + state->domain_name = NULL; break; default: tevent_req_error(req, ret); return; } - ret = cache_req_select_domains(req, domain); + ret = cache_req_select_domains(req); if (ret != EAGAIN) { tevent_req_error(req, ret); return; } } -static errno_t cache_req_select_domains(struct tevent_req *req, - const char *domain) +static errno_t cache_req_select_domains(struct tevent_req *req) { struct cache_req_state *state = NULL; state = tevent_req_data(req, struct cache_req_state); - if (domain != NULL) { + if (state->domain_name != NULL) { CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, state->cr, "Performing a single domain search\n"); - state->domain = responder_get_domain(state->cr->rctx, domain); + state->domain = responder_get_domain(state->cr->rctx, + state->domain_name); if (state->domain == NULL) { return ERR_DOMAIN_NOT_FOUND; } @@ -673,7 +682,8 @@ static void cache_req_done(struct tevent_req *subreq) if (cache_req_assume_upn(state->cr)) { /* Try UPN now. */ - ret = cache_req_select_domains(req, NULL); + state->domain_name = NULL; + ret = cache_req_select_domains(req); goto done; } From cc0c2f9e81bc0b62ad52049ee9bf1133eb2940ba Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 18:58:08 +0200 Subject: [PATCH 08/11] Simplify next_domain_flag reference in cache_req.c --- src/responder/common/cache_req/cache_req.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c index 20f4263..7941c72 100644 --- a/src/responder/common/cache_req/cache_req.c +++ b/src/responder/common/cache_req/cache_req.c @@ -558,8 +558,7 @@ static errno_t cache_req_next_domain(struct tevent_req *req) /* we will continue with the following domain the next time */ if (state->check_next) { - state->domain = get_next_domain(state->domain, - cr->plugin->get_next_domain_flags); + state->domain = get_next_domain(state->domain, next_domain_flag); } return EAGAIN; From 8b8ee0ff34246c65a1eaddf867e15b315214ddab Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 19:10:25 +0200 Subject: [PATCH 09/11] Add session recording conf loading to responder --- Makefile.am | 4 ++ src/responder/common/responder.h | 3 ++ src/responder/common/responder_common.c | 9 ++++ src/responder/common/session_recording_conf.c | 72 +++++++++++++++++++++++++ src/responder/common/session_recording_conf.h | 76 +++++++++++++++++++++++++++ src/tests/cwrap/Makefile.am | 2 + 6 files changed, 166 insertions(+) create mode 100644 src/responder/common/session_recording_conf.c create mode 100644 src/responder/common/session_recording_conf.h diff --git a/Makefile.am b/Makefile.am index e5e91e9..cce022b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -524,6 +524,7 @@ SSSD_RESPONDER_OBJ = \ src/responder/common/responder_packet.c \ src/responder/common/responder_get_domains.c \ src/responder/common/responder_utils.c \ + src/responder/common/session_recording_conf.c \ src/responder/common/data_provider/rdp_message.c \ src/responder/common/data_provider/rdp_client.c \ src/monitor/monitor_iface_generated.c \ @@ -643,6 +644,7 @@ dist_noinst_HEADERS = \ src/responder/common/cache_req/cache_req_type.h \ src/responder/common/cache_req/cache_req_plugin.h \ src/responder/common/cache_req/cache_req_private.h \ + src/responder/common/session_recording_conf.h \ src/responder/common/data_provider/rdp.h \ src/responder/pam/pamsrv.h \ src/responder/pam/pam_helpers.h \ @@ -2037,6 +2039,7 @@ responder_socket_access_tests_SOURCES = \ src/responder/common/responder_common.c \ src/responder/common/responder_packet.c \ src/responder/common/responder_cmd.c \ + src/responder/common/session_recording_conf.c \ src/responder/common/data_provider/rdp_message.c \ src/responder/common/data_provider/rdp_client.c responder_socket_access_tests_CFLAGS = \ @@ -2121,6 +2124,7 @@ TEST_MOCK_RESP_OBJ = \ src/responder/common/negcache_files.c \ src/responder/common/negcache.c \ src/responder/common/responder_common.c \ + src/responder/common/session_recording_conf.c \ src/responder/common/data_provider/rdp_message.c \ src/responder/common/data_provider/rdp_client.c \ src/responder/common/responder_utils.c \ diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h index d1fa532..46b78c2 100644 --- a/src/responder/common/responder.h +++ b/src/responder/common/responder.h @@ -36,6 +36,7 @@ #include "data_provider/rdp.h" #include "sbus/sssd_dbus.h" #include "responder/common/negcache.h" +#include "responder/common/session_recording_conf.h" #include "sss_client/sss_cli.h" extern hash_table_t *dp_requests; @@ -126,6 +127,8 @@ struct resp_ctx { char *default_domain; char override_space; + struct session_recording_conf sr_conf; + uint32_t cache_req_num; void *pvt_ctx; diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c index 67922bf..7c54d91 100644 --- a/src/responder/common/responder_common.c +++ b/src/responder/common/responder_common.c @@ -1171,6 +1171,15 @@ int sss_process_init(TALLOC_CTX *mem_ctx, rctx->override_space = tmp[0]; } + /* Read session_recording section */ + ret = session_recording_conf_load(rctx, rctx->cdb, &rctx->sr_conf); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed loading session recording configuration: %s\n", + strerror(ret)); + goto fail; + } + ret = sss_monitor_init(rctx, rctx->ev, monitor_intf, svc_name, svc_version, MT_SVC_SERVICE, rctx, &rctx->last_request_time, diff --git a/src/responder/common/session_recording_conf.c b/src/responder/common/session_recording_conf.c new file mode 100644 index 0000000..3966833 --- /dev/null +++ b/src/responder/common/session_recording_conf.c @@ -0,0 +1,72 @@ +/* + SSSD + + Responder session recording configuration management + + Authors: + Nikolai Kondrashov <nikolai.kondras...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "responder/common/session_recording_conf.h" +#include "util/debug.h" +#include <string.h> +#include <errno.h> + +errno_t session_recording_conf_load(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + struct session_recording_conf *pconf) +{ + int ret; + char *str; + + /* Read session_recording/scope option */ + ret = confdb_get_string(cdb, mem_ctx, CONFDB_SESSION_RECORDING_CONF_ENTRY, + CONFDB_SESSION_RECORDING_SCOPE, "none", &str); + if (ret != EOK) goto done; + if (strcasecmp(str, "none") == 0) { + pconf->scope = SESSION_RECORDING_CONF_SCOPE_NONE; + } else if (strcasecmp(str, "some") == 0) { + pconf->scope = SESSION_RECORDING_CONF_SCOPE_SOME; + } else if (strcasecmp(str, "all") == 0) { + pconf->scope = SESSION_RECORDING_CONF_SCOPE_ALL; + } else { + DEBUG(SSSDBG_OP_FAILURE, + "Unknown value for session recording scope: %s\n", + str); + ret = EINVAL; + goto done; + } + + /* Read session_recording/users option */ + ret = confdb_get_string_as_list(cdb, mem_ctx, + CONFDB_SESSION_RECORDING_CONF_ENTRY, + CONFDB_SESSION_RECORDING_USERS, + &pconf->users); + if (ret != EOK && ret != ENOENT) goto done; + + /* Read session_recording/groups option */ + ret = confdb_get_string_as_list(cdb, mem_ctx, + CONFDB_SESSION_RECORDING_CONF_ENTRY, + CONFDB_SESSION_RECORDING_GROUPS, + &pconf->groups); + if (ret != EOK && ret != ENOENT) goto done; + + ret = EOK; +done: + return ret; +} diff --git a/src/responder/common/session_recording_conf.h b/src/responder/common/session_recording_conf.h new file mode 100644 index 0000000..4f658f8 --- /dev/null +++ b/src/responder/common/session_recording_conf.h @@ -0,0 +1,76 @@ +/* + SSSD + + Responder session recording configuration management + + Authors: + Nikolai Kondrashov <nikolai.kondras...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __SSS_RESPONDER_SESSION_RECORDING_CONF_H__ +#define __SSS_RESPONDER_SESSION_RECORDING_CONF_H__ + +#include "confdb/confdb.h" +#include "util/util_errors.h" + +/** Scope of users whose session should be recorded */ +enum session_recording_conf_scope { + SESSION_RECORDING_CONF_SCOPE_NONE, /**< None, no users */ + SESSION_RECORDING_CONF_SCOPE_SOME, /**< Some users specified elsewhere */ + SESSION_RECORDING_CONF_SCOPE_ALL /**< All users */ +}; + +/** Session recording configuration (from "session_recording" section) */ +struct session_recording_conf { + /** + * Session recording scope: + * whether to record nobody, everyone, or some users/groups + */ + enum session_recording_conf_scope scope; + /** + * NULL-terminated list of users whose session should be recorded. + * Can be NULL, meaning empty list. Only applicable if scope is "some". + */ + char **users; + /** + * NULL-terminated list of groups, members of which should have their + * sessions recorded. Can be NULL, meaning empty list. Only applicable if + * scope is "some" + */ + char **groups; +}; + +/** + * Load session recording configuration from configuration database. + * + * @param mem_ctx Memory context to allocate data with. + * @param cdb The configuration database connection object to retrieve + * data from. + * @param pconf Location for the loaded session configuration. + * + * @return Status code: + * ENOMEM - memory allocation failed, + * EINVAL - configuration was invalid, + * EIO - an I/O error occurred while communicating with the ConfDB. + */ +extern errno_t session_recording_conf_load( + TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + struct session_recording_conf *pconf); + +#endif /* __SSS_RESPONDER_SESSION_RECORDING_CONF_H__ */ diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am index 8ca0026..85ae224 100644 --- a/src/tests/cwrap/Makefile.am +++ b/src/tests/cwrap/Makefile.am @@ -71,6 +71,7 @@ SSSD_RESPONDER_OBJ = \ ../../../src/responder/common/responder_packet.c \ ../../../src/responder/common/responder_get_domains.c \ ../../../src/responder/common/responder_utils.c \ + ../../../src/responder/common/session_recording_conf.c \ ../../../src/responder/common/data_provider/rdp_message.c \ ../../../src/responder/common/data_provider/rdp_client.c \ ../../../src/monitor/monitor_iface_generated.c \ @@ -163,6 +164,7 @@ responder_common_tests_SOURCES =\ ../../../src/responder/common/responder_common.c \ ../../../src/responder/common/responder_packet.c \ ../../../src/responder/common/responder_cmd.c \ + ../../../src/responder/common/session_recording_conf.c \ $(NULL) responder_common_tests_CFLAGS = \ $(AM_CFLAGS) \ From 2d3b07262eab57766b95e176a96df77e42d08e9a Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 12 Jan 2017 19:21:38 +0200 Subject: [PATCH 10/11] Add basic session recording shell substitution --- Makefile.am | 3 + src/db/sysdb.h | 2 + src/responder/common/cache_req/cache_req.c | 104 ++++++++- src/responder/common/session_recording.c | 315 ++++++++++++++++++++++++++ src/responder/common/session_recording.h | 85 +++++++ src/responder/common/session_recording_conf.h | 2 +- src/responder/nss/nss_protocol_pwent.c | 8 +- src/tests/cwrap/Makefile.am | 2 + 8 files changed, 518 insertions(+), 3 deletions(-) create mode 100644 src/responder/common/session_recording.c create mode 100644 src/responder/common/session_recording.h diff --git a/Makefile.am b/Makefile.am index cce022b..7c37b5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -524,6 +524,7 @@ SSSD_RESPONDER_OBJ = \ src/responder/common/responder_packet.c \ src/responder/common/responder_get_domains.c \ src/responder/common/responder_utils.c \ + src/responder/common/session_recording.c \ src/responder/common/session_recording_conf.c \ src/responder/common/data_provider/rdp_message.c \ src/responder/common/data_provider/rdp_client.c \ @@ -644,6 +645,7 @@ dist_noinst_HEADERS = \ src/responder/common/cache_req/cache_req_type.h \ src/responder/common/cache_req/cache_req_plugin.h \ src/responder/common/cache_req/cache_req_private.h \ + src/responder/common/session_recording.h \ src/responder/common/session_recording_conf.h \ src/responder/common/data_provider/rdp.h \ src/responder/pam/pamsrv.h \ @@ -2124,6 +2126,7 @@ TEST_MOCK_RESP_OBJ = \ src/responder/common/negcache_files.c \ src/responder/common/negcache.c \ src/responder/common/responder_common.c \ + src/responder/common/session_recording.c \ src/responder/common/session_recording_conf.c \ src/responder/common/data_provider/rdp_message.c \ src/responder/common/data_provider/rdp_client.c \ diff --git a/src/db/sysdb.h b/src/db/sysdb.h index 21f8188..8142119 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -174,6 +174,7 @@ #define SYSDB_OVERRIDE_GROUP_CLASS "groupOverride" #define SYSDB_OVERRIDE_DN "overrideDN" #define SYSDB_OVERRIDE_OBJECT_DN "overrideObjectDN" +#define SYSDB_SESSION_RECORDING "sessionRecording" #define SYSDB_NEXTID_FILTER "("SYSDB_NEXTID"=*)" @@ -226,6 +227,7 @@ SYSDB_OVERRIDE_DN, \ SYSDB_OVERRIDE_OBJECT_DN, \ SYSDB_DEFAULT_OVERRIDE_NAME, \ + SYSDB_SESSION_RECORDING, \ SYSDB_UUID, \ SYSDB_ORIG_DN, \ NULL} diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c index 7941c72..a335b89 100644 --- a/src/responder/common/cache_req/cache_req.c +++ b/src/responder/common/cache_req/cache_req.c @@ -24,6 +24,7 @@ #include <errno.h> #include "util/util.h" +#include "responder/common/session_recording.h" #include "responder/common/cache_req/cache_req_private.h" #include "responder/common/cache_req/cache_req_plugin.h" @@ -319,6 +320,10 @@ struct cache_req_state { size_t num_results; bool check_next; bool dp_success; + + /* NULL-terminated list of results of looking up + * groups for which session recording is enabled */ + struct cache_req_result **sr_groups; }; static errno_t cache_req_add_result(struct cache_req_state *state, @@ -330,6 +335,10 @@ static errno_t cache_req_process_input(TALLOC_CTX *mem_ctx, static void cache_req_input_parsed(struct tevent_req *subreq); +static errno_t cache_req_sr_get_groups(struct tevent_req *req); + +static void cache_req_sr_get_groups_done(struct tevent_req *subreq); + static errno_t cache_req_select_domains(struct tevent_req *req); static errno_t cache_req_next_domain(struct tevent_req *req); @@ -388,6 +397,11 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx, goto done; } + ret = cache_req_sr_get_groups(req); + if (ret != EOK) { + goto done; + } + ret = cache_req_select_domains(req); done: @@ -470,6 +484,82 @@ static void cache_req_input_parsed(struct tevent_req *subreq) return; } + ret = cache_req_sr_get_groups(req); + if (ret == EAGAIN) { + return; + } else if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + + ret = cache_req_select_domains(req); + if (ret != EAGAIN) { + tevent_req_error(req, ret); + return; + } +} + +static errno_t cache_req_sr_get_groups(struct tevent_req *req) +{ + struct cache_req_state *state; + struct cache_req *cr; + struct resp_ctx *rctx; + struct session_recording_conf *sr_conf; + struct tevent_req *subreq; + + state = tevent_req_data(req, struct cache_req_state); + cr = state->cr; + rctx = cr->rctx; + sr_conf = &rctx->sr_conf; + + /* Don't do anything if session recording is not group-selective */ + if (sr_conf->scope != SESSION_RECORDING_CONF_SCOPE_SOME || + sr_conf->groups == NULL || *sr_conf->groups == NULL) { + return EOK; + } + + /* Only handle requests for users */ + switch (cr->data->type) { + case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: + case CACHE_REQ_USER_BY_ID: + case CACHE_REQ_USER_BY_CERT: + case CACHE_REQ_USER_BY_FILTER: + case CACHE_REQ_ENUM_USERS: + break; + default: + return EOK; + } + + /* Create request for groups with session recording enabled */ + subreq = session_recording_get_groups_send(state, rctx, + &state->sr_groups); + if (subreq == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Failed creating request for groups " + "with session recording enabled!\n"); + return ENOMEM; + } + + tevent_req_set_callback(subreq, cache_req_sr_get_groups_done, req); + + return EAGAIN; +} + +static void cache_req_sr_get_groups_done(struct tevent_req *subreq) +{ + struct tevent_req *req; + errno_t ret; + + req = tevent_req_callback_data(subreq, struct tevent_req); + + ret = session_recording_get_groups_recv(subreq); + talloc_free(subreq); + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + ret = cache_req_select_domains(req); if (ret != EAGAIN) { tevent_req_error(req, ret); @@ -657,7 +747,19 @@ static void cache_req_done(struct tevent_req *subreq) switch (ret) { case EOK: - /* We got some data from this search. Save it. */ + /* We got some data from this search */ + + /* Overlay it with session recording info */ + ret = session_recording_overlay(state->cr->rctx, + state->cr->data->type, + state->selected_domain, + state->sr_groups, + result); + if (ret != EOK) { + goto done; + } + + /* Save it. */ ret = cache_req_create_and_add_result(state, state->selected_domain, result, state->cr->data->name.lookup); diff --git a/src/responder/common/session_recording.c b/src/responder/common/session_recording.c new file mode 100644 index 0000000..0689f97 --- /dev/null +++ b/src/responder/common/session_recording.c @@ -0,0 +1,315 @@ +/* + SSSD + + Responder session recording functions + + Authors: + Nikolai Kondrashov <nikolai.kondras...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "responder/common/session_recording.h" +#include "responder/common/cache_req/cache_req.h" +#include "responder/nss/nss_private.h" + +/** + * Internal state of the asynchronous request to retrieve information on + * groups for which session recording is enabled. + */ +struct session_recording_get_groups_state { + /** Memory context to allocate results with */ + TALLOC_CTX *mem_ctx; + /** Responder context to work within */ + struct resp_ctx *rctx; + /** Pointer to name of the next group to retrieve info about */ + char **pname; + /** Next location to store retrieved result pointer in */ + struct cache_req_result **presult; +}; + +/** + * Handle a result of a group info request and submit another one, if there's + * any. + * + * @param subreq The completed group info request. + */ +static void session_recording_get_groups_step(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, + struct tevent_req); + struct session_recording_get_groups_state *state = + tevent_req_data(req, struct session_recording_get_groups_state); + struct resp_ctx *rctx = state->rctx; + + /* Get the lookup result, move onto next array element if we got one */ + ret = cache_req_group_by_name_recv(state->mem_ctx, subreq, + state->presult); + talloc_zfree(subreq); + if (ret == EOK) { + state->presult++; + } else if (ret != ENOENT) { + goto done; + } + + /* Move onto the next group name */ + state->pname++; + + /* If there are no more names */ + if (*state->pname == NULL) { + tevent_req_done(req); + ret = EOK; + goto done; + } + + /* Lookup next name */ + /* TODO: Figure out proper caching parameters */ + subreq = cache_req_group_by_name_send(state->mem_ctx, rctx->ev, rctx, + rctx->ncache, 0, NULL, + *state->pname); + if (subreq == NULL) { + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, + session_recording_get_groups_step, req); + return; + +done: + tevent_req_error(req, ret); +} + +struct tevent_req *session_recording_get_groups_send( + TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct cache_req_result ***presult_list) +{ + errno_t ret; + struct tevent_req *req; + struct tevent_req *subreq; + struct session_recording_get_groups_state *state; + char **pname; + size_t num; + + /* Create the tracking "request" */ + req = tevent_req_create(mem_ctx, &state, + struct session_recording_get_groups_state); + if (req == NULL) { + return NULL; + } + + /* Count groups to request */ + num = 0; + pname = rctx->sr_conf.groups; + if (pname != NULL) { + for (; *pname != NULL; pname++, num++); + } + + /* Allocate array for lookup results, include terminating NULL */ + *presult_list = talloc_zero_array(mem_ctx, + struct cache_req_result *, num + 1); + if (*presult_list == NULL) { + ret = ENOMEM; + goto error; + } + + /* TODO Handle zero groups */ + + /* Fill state */ + state->mem_ctx = mem_ctx; + state->rctx = rctx; + state->pname = rctx->sr_conf.groups; + state->presult = *presult_list; + + /* Start first group lookup */ + subreq = cache_req_group_by_name_send(mem_ctx, rctx->ev, rctx, + rctx->ncache, 0, NULL, + *state->pname); + if (subreq == NULL) { + ret = ENOMEM; + goto error; + } + tevent_req_set_callback(subreq, + session_recording_get_groups_step, req); + + return req; + +error: + tevent_req_error(req, ret); + tevent_req_post(req, rctx->ev); + return req; +} + +errno_t session_recording_get_groups_recv(struct tevent_req *req) +{ + TEVENT_REQ_RETURN_ON_ERROR(req); + + return EOK; +} + +errno_t session_recording_overlay(struct resp_ctx *rctx, + enum cache_req_type req_type, + struct sss_domain_info *domain, + struct cache_req_result **group_results, + struct ldb_result *result) +{ + errno_t ret; + size_t i; + struct ldb_message *msg; + const char *orig_name; + char **pname; + bool enabled; + TALLOC_CTX *tmp_ctx = NULL; + struct sysdb_attrs *attrs; + + if (rctx == NULL || domain == NULL || result == NULL) { + return EINVAL; + } + + /* Don't do anything if session recording is not selective */ + if (rctx->sr_conf.scope != SESSION_RECORDING_CONF_SCOPE_SOME) { + return EOK; + } + + /* Only handle requests for users */ + switch (req_type) { + case CACHE_REQ_USER_BY_NAME: + case CACHE_REQ_USER_BY_UPN: + case CACHE_REQ_USER_BY_ID: + case CACHE_REQ_USER_BY_CERT: + case CACHE_REQ_USER_BY_FILTER: + case CACHE_REQ_ENUM_USERS: + break; + default: + return EOK; + } + + /* For each result message */ + for (i = 0; i < result->count; i++) { + msg = result->msgs[i]; + + /* Skip messages with present session recording attribute */ + if (ldb_msg_find_element(msg, SYSDB_SESSION_RECORDING) != NULL) { + continue; + } + + /* Get the entry user name */ + orig_name = sysdb_get_name_from_msg(domain, msg); + /* If the entry has no name */ + if (orig_name == NULL) { + continue; + } + + /* Create temporary memory context for just this message */ + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + /* Start with the assumption recording is disabled */ + enabled = false; + + /* If we have a list of users to match against */ + if (rctx->sr_conf.users != NULL) { + char *output_name; + /* Get the user name in output shape to match against */ + output_name = sss_output_name(tmp_ctx, orig_name, + domain->case_preserve, + rctx->override_space); + if (output_name == NULL) { + ret = ENOMEM; + goto done; + } + for (pname = rctx->sr_conf.users; + *pname != NULL; + pname++) { + if (strcmp(output_name, *pname) == 0) { + enabled = true; + break; + } + } + } + + /* If we have a list of groups to match against */ + if (group_results != NULL) { + struct cache_req_result **pgroup_result = group_results; + struct cache_req_result *group_result; + struct ldb_result *user_result; + size_t j; + size_t k; + + /* Retrieve groups the user is member of */ + ret = sysdb_initgroups_with_views(tmp_ctx, domain, + orig_name, &user_result); + if (ret != EOK) { + goto done; + } + /* + * For each result of a session recording-enabled group lookup + */ + do { + group_result = *pgroup_result; + /* For each message (match) in the result */ + for (j = 0; !enabled && j < group_result->count; j++) { + /* For each user's group */ + for (k = 1; !enabled && k < user_result->count; k++) { + /* If their DN's match */ + if (ldb_dn_compare( + group_result->msgs[j]->dn, + user_result->msgs[k]->dn) == 0) { + enabled = true; + } + } + } + } while (!enabled && *++pgroup_result != NULL); + } + + /* Store the attribute in the cache */ + attrs = sysdb_new_attrs(tmp_ctx); + if (attrs == NULL) { + ret = ENOMEM; + goto done; + } + ret = sysdb_attrs_add_bool(attrs, SYSDB_SESSION_RECORDING, enabled); + if (ret != EOK) { + goto done; + } + ret = sysdb_set_entry_attr(domain->sysdb, msg->dn, attrs, SYSDB_MOD_ADD); + if (ret != EOK) { + goto done; + } + + /* Store the attribute in the result */ + ret = ldb_msg_add_string(msg, SYSDB_SESSION_RECORDING, + enabled ? "TRUE" : "FALSE"); + if (ret != LDB_SUCCESS) { + ret = sysdb_error_to_errno(ret); + goto done; + } + + /* Free the messages's temporary memory context */ + talloc_free(tmp_ctx); + tmp_ctx = NULL; + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} diff --git a/src/responder/common/session_recording.h b/src/responder/common/session_recording.h new file mode 100644 index 0000000..03d590a --- /dev/null +++ b/src/responder/common/session_recording.h @@ -0,0 +1,85 @@ +/* + SSSD + + Responder session recording functions + + Authors: + Nikolai Kondrashov <nikolai.kondras...@redhat.com> + + Copyright (C) 2016 Red Hat + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __SSS_RESPONDER_SESSION_RECORDING_H__ +#define __SSS_RESPONDER_SESSION_RECORDING_H__ + +#include "confdb/confdb.h" +#include "responder/common/responder.h" +#include "responder/common/cache_req/cache_req_type.h" +#include "responder/common/cache_req/cache_req_result.h" +#include "responder/common/session_recording_conf.h" + +/** + * Start an asynchronous request to retrieve groups for which session + * recording is enabled, for an abstract responder context. + * + * @param mem_ctx The memory context to allocate results and request + * state with. + * @param rctx Abstract responder context to operate within. + * @param presult_list Location for the pointer to a NULL-terminated array of + * pointers to retrieved group results, allocated with + * mem_ctx. + * + * @return The created asynchronous request, or NULL, if failed to allocate + * memory for it. + */ +extern struct tevent_req *session_recording_get_groups_send( + TALLOC_CTX *mem_ctx, + struct resp_ctx *rctx, + struct cache_req_result ***presult_list); + +/** + * Retrieve status code for a finished request to retrieve groups for which + * session recording is enabled. + * + * @return Status code. + */ +extern errno_t session_recording_get_groups_recv(struct tevent_req *req); + +/** + * Overlay an LDB result and corresponding LDB contents for a specific cache + * request with session recording information, according to configuration. If + * session recording is disabled, or the request is not for a user, no changes + * are done. + * + * @param rctx Responder context to work within. + * @param req_type The type of request that produced the supplied result. + * @param domain The domain the result was retrieved from. + * @param group_results A NULL-terminated list of results for groups with + * session recording enabled. Only valid if scope is + * "some". Can be NULL. + * @param result The result to modify, and to use to locate and modify + * the original entry in the LDB. + * + * @return Status code. + */ +extern errno_t session_recording_overlay( + struct resp_ctx *rctx, + enum cache_req_type req_type, + struct sss_domain_info *domain, + struct cache_req_result **group_results, + struct ldb_result *result); + +#endif /* __SSS_RESPONDER_SESSION_RECORDING_H__ */ diff --git a/src/responder/common/session_recording_conf.h b/src/responder/common/session_recording_conf.h index 4f658f8..55dee8d 100644 --- a/src/responder/common/session_recording_conf.h +++ b/src/responder/common/session_recording_conf.h @@ -70,7 +70,7 @@ struct session_recording_conf { */ extern errno_t session_recording_conf_load( TALLOC_CTX *mem_ctx, - struct confdb_ctx *cdb, + struct confdb_ctx *cdb, struct session_recording_conf *pconf); #endif /* __SSS_RESPONDER_SESSION_RECORDING_CONF_H__ */ diff --git a/src/responder/nss/nss_protocol_pwent.c b/src/responder/nss/nss_protocol_pwent.c index 0d1b1f9..b49e825 100644 --- a/src/responder/nss/nss_protocol_pwent.c +++ b/src/responder/nss/nss_protocol_pwent.c @@ -239,7 +239,13 @@ nss_get_pwent(TALLOC_CTX *mem_ctx, gecos = sss_view_ldb_msg_find_attr_as_string(domain, msg, SYSDB_GECOS, NULL); homedir = nss_get_homedir(mem_ctx, nss_ctx, domain, msg, name, upn, uid); - shell = nss_get_shell_override(msg, nss_ctx, domain); + if (nss_ctx->rctx->sr_conf.scope == SESSION_RECORDING_CONF_SCOPE_ALL || + (nss_ctx->rctx->sr_conf.scope == SESSION_RECORDING_CONF_SCOPE_SOME && + ldb_msg_find_attr_as_bool(msg, SYSDB_SESSION_RECORDING, false))) { + shell = SESSION_RECORDING_SHELL; + } else { + shell = nss_get_shell_override(msg, nss_ctx, domain); + } /* Convert to sized strings. */ ret = sized_output_name(mem_ctx, nss_ctx->rctx, name, domain, _name); diff --git a/src/tests/cwrap/Makefile.am b/src/tests/cwrap/Makefile.am index 85ae224..4d4b0af 100644 --- a/src/tests/cwrap/Makefile.am +++ b/src/tests/cwrap/Makefile.am @@ -71,6 +71,7 @@ SSSD_RESPONDER_OBJ = \ ../../../src/responder/common/responder_packet.c \ ../../../src/responder/common/responder_get_domains.c \ ../../../src/responder/common/responder_utils.c \ + ../../../src/responder/common/session_recording.c \ ../../../src/responder/common/session_recording_conf.c \ ../../../src/responder/common/data_provider/rdp_message.c \ ../../../src/responder/common/data_provider/rdp_client.c \ @@ -164,6 +165,7 @@ responder_common_tests_SOURCES =\ ../../../src/responder/common/responder_common.c \ ../../../src/responder/common/responder_packet.c \ ../../../src/responder/common/responder_cmd.c \ + ../../../src/responder/common/session_recording.c \ ../../../src/responder/common/session_recording_conf.c \ $(NULL) responder_common_tests_CFLAGS = \ From 5a58ff84570e2b843a1cb3bf2c0bb18ba367d5f1 Mon Sep 17 00:00:00 2001 From: Nikolai Kondrashov <nikolai.kondras...@redhat.com> Date: Thu, 11 Aug 2016 14:18:38 +0300 Subject: [PATCH 11/11] intg: Add session recording tests --- src/tests/intg/Makefile.am | 1 + src/tests/intg/config.py.m4 | 27 ++-- src/tests/intg/test_enumeration.py | 251 +++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 13 deletions(-) diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am index e81e5ee..9b68275 100644 --- a/src/tests/intg/Makefile.am +++ b/src/tests/intg/Makefile.am @@ -31,6 +31,7 @@ config.py: config.py.m4 -D "secdbpath=\`$(secdbpath)'" \ -D "libexecpath=\`$(libexecdir)'" \ -D "runstatedir=\`$(runstatedir)'" \ + -D "session_recording_shell=\`$(session_recording_shell)'" \ $< > $@ root: diff --git a/src/tests/intg/config.py.m4 b/src/tests/intg/config.py.m4 index 65e17e5..9aa14dc 100644 --- a/src/tests/intg/config.py.m4 +++ b/src/tests/intg/config.py.m4 @@ -2,16 +2,17 @@ Build configuration variables. """ -PREFIX = "prefix" -SYSCONFDIR = "sysconfdir" -NSS_MODULE_DIR = PREFIX + "/lib" -SSSDCONFDIR = SYSCONFDIR + "/sssd" -CONF_PATH = SSSDCONFDIR + "/sssd.conf" -DB_PATH = "dbpath" -PID_PATH = "pidpath" -PIDFILE_PATH = PID_PATH + "/sssd.pid" -LOG_PATH = "logpath" -MCACHE_PATH = "mcpath" -SECDB_PATH = "secdbpath" -LIBEXEC_PATH = "libexecpath" -RUNSTATEDIR = "runstatedir" +PREFIX = "prefix" +SYSCONFDIR = "sysconfdir" +NSS_MODULE_DIR = PREFIX + "/lib" +SSSDCONFDIR = SYSCONFDIR + "/sssd" +CONF_PATH = SSSDCONFDIR + "/sssd.conf" +DB_PATH = "dbpath" +PID_PATH = "pidpath" +PIDFILE_PATH = PID_PATH + "/sssd.pid" +LOG_PATH = "logpath" +MCACHE_PATH = "mcpath" +SECDB_PATH = "secdbpath" +LIBEXEC_PATH = "libexecpath" +RUNSTATEDIR = "runstatedir" +SESSION_RECORDING_SHELL = "session_recording_shell" diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py index 5cb6c3e..b8c8010 100644 --- a/src/tests/intg/test_enumeration.py +++ b/src/tests/intg/test_enumeration.py @@ -687,3 +687,254 @@ def test_vetoed_shells(vetoed_shells): shell="/bin/default") ) ) + + +@pytest.fixture +def session_recording_ldap(request, ldap_conn): + ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) + ent_list.add_user("user1", 1001, 2001, loginShell="/bin/sh1") + ent_list.add_user("user2", 1002, 2002, loginShell="/bin/sh2") + ent_list.add_user("user3", 1003, 2003, loginShell="/bin/sh3") + ent_list.add_group("group1", 2001) + ent_list.add_group("group2", 2002) + ent_list.add_group("group3", 2003) + ent_list.add_group("empty_group", 2010) + ent_list.add_group("one_user_group", 2011, ["user1"]) + ent_list.add_group("two_user_group", 2012, ["user1", "user2"]) + ent_list.add_group("three_user_group", 2013, ["user1", "user2", "user3"]) + create_ldap_fixture(request, ldap_conn, ent_list) + + +@pytest.fixture +def session_recording_none(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = none + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_none(session_recording_none): + """Test session recording "none" scope""" + ent.assert_passwd( + 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"), + ) + ) + + +@pytest.fixture +def session_recording_all(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = all + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_all_nam(session_recording_all): + """Test session recording "all" scope with 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=config.SESSION_RECORDING_SHELL), + )) + # Request a second time to verify positive caching + 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=config.SESSION_RECORDING_SHELL), + )) + + +def test_session_recording_all_uid(session_recording_all): + """Test session recording "all" scope with 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=config.SESSION_RECORDING_SHELL), + }) + # Request a second time to verify positive caching + 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=config.SESSION_RECORDING_SHELL), + }) + + +def test_session_recording_all_ent(session_recording_all): + """Test session recording "all" scope with 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=config.SESSION_RECORDING_SHELL), + ) + ) + + +@pytest.fixture +def session_recording_some_empty(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = some + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_some_empty(session_recording_some_empty): + """Test session recording "some" scope with no users or groups""" + ent.assert_passwd( + 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"), + ) + ) + + +@pytest.fixture +def session_recording_some_users(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = some + users = user1, user2 + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_some_users_nam(session_recording_some_users): + """Test session recording "some" scope with user 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"), + )) + + +def test_session_recording_some_users_uid(session_recording_some_users): + """Test session recording "some" scope with user 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"), + }) + + +def test_session_recording_some_users_ent(session_recording_some_users): + """Test session recording "some" scope with user 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"), + ) + ) + + +@pytest.fixture +def session_recording_some_groups(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = some + groups = one_user_group, two_user_group + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_some_groups_nam(session_recording_some_groups): + """Test session recording "some" scope with group 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"), + )) + + +def test_session_recording_some_groups_uid(session_recording_some_groups): + """Test session recording "some" scope with group 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"), + }) + + +def test_session_recording_some_groups_ent(session_recording_some_groups): + """Test session recording "some" scope with 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"), + ) + ) + + +@pytest.fixture +def session_recording_some_users_and_groups(request, ldap_conn, session_recording_ldap): + conf = \ + format_basic_conf(ldap_conn, SCHEMA_RFC2307) + \ + unindent("""\ + [session_recording] + scope = some + users = user3 + groups = one_user_group + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) + + +def test_session_recording_some_users_and_groups_nam( + session_recording_some_users_and_groups): + """ + Test session recording "some" scope with user and group lists 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="/bin/sh2"), + user3=dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), + )) + + +def test_session_recording_some_users_and_groups_uid( + session_recording_some_users_and_groups): + """ + Test session recording "some" scope with user and group lists 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="/bin/sh2"), + 1003:dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), + }) + + +def test_session_recording_some_users_and_groups_ent( + session_recording_some_users_and_groups): + """ + Test session recording "some" scope with user and group lists 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="/bin/sh2"), + dict(name="user3", uid=1003, shell=config.SESSION_RECORDING_SHELL), + ) + )
_______________________________________________ sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org