URL: https://github.com/SSSD/sssd/pull/5608
Author: sumit-bose
 Title: #5608: nss: fix getsidbyname for IPA user-private-groups
Action: opened

PR body:
"""
Currently the getsidbyname request does not work properly for IPA users
due to the way IPA user-private-groups are handled by SSSD. With this
patch two different cases, the default automatic user-private-groups
where the group is a managed object and manual creation of a user and a
groups with UID and GIDs so that the group is a user-private group, are
covered.

Resolves: https://github.com/SSSD/sssd/issues/5607

:fixes: Fix getsidbyname issues with IPA users with a user-private-group
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/5608/head:pr5608
git checkout pr5608
From 0adfd7827196eaea44279344eed85289db2ffa31 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Tue, 27 Apr 2021 10:48:04 +0200
Subject: [PATCH] nss: fix getsidbyname for IPA user-private-groups

Currently the getsidbyname request does not work properly for IPA users
due to the way IPA user-private-groups are handled by SSSD. With this
patch two different cases, the default automatic user-private-groups
where the group is a managed object and manual creation of a user and a
groups with UID and GIDs so that the group is a user-private group, are
covered.

Resolves: https://github.com/SSSD/sssd/issues/5607

:fixes: Fix getsidbyname issues with IPA users with a user-private-group
---
 src/db/sysdb_ops.c                            |   2 +-
 .../plugins/cache_req_object_by_name.c        |   2 +-
 src/responder/nss/nss_cmd.c                   |   5 +-
 src/responder/nss/nss_protocol_sid.c          | 119 ++++++++++++++++--
 src/tests/cmocka/test_nss_srv.c               | 101 +++++++++++++++
 5 files changed, 218 insertions(+), 11 deletions(-)

diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c
index 585708abec..a874ae6df6 100644
--- a/src/db/sysdb_ops.c
+++ b/src/db/sysdb_ops.c
@@ -5259,7 +5259,7 @@ errno_t sysdb_search_object_by_name(TALLOC_CTX *mem_ctx,
         goto done;
     }
 
-    ret = sysdb_search_object_attr(mem_ctx, domain, filter, attrs, true, res);
+    ret = sysdb_search_object_attr(mem_ctx, domain, filter, attrs, false, res);
 
 done:
     talloc_free(tmp_ctx);
diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
index 83d00f7750..907f1f3d50 100644
--- a/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
+++ b/src/responder/common/cache_req/plugins/cache_req_object_by_name.c
@@ -190,7 +190,7 @@ const struct cache_req_plugin cache_req_object_by_name = {
     .parse_name = true,
     .ignore_default_domain = false,
     .bypass_cache = false,
-    .only_one_result = true,
+    .only_one_result = false,
     .search_all_domains = false,
     .require_enumeration = false,
     .allow_missing_fqn = false,
diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
index 4698e751c9..a487e1c248 100644
--- a/src/responder/nss/nss_cmd.c
+++ b/src/responder/nss/nss_cmd.c
@@ -1121,7 +1121,10 @@ static errno_t nss_cmd_endservent(struct cli_ctx *cli_ctx)
 
 static errno_t nss_cmd_getsidbyname(struct cli_ctx *cli_ctx)
 {
-    const char *attrs[] = { SYSDB_SID_STR, NULL };
+    /* The attributes besides SYSDB_SID_STR are needed to handle some corner
+     * cases with respect to user-private-groups */
+    const char *attrs[] = { SYSDB_SID_STR, SYSDB_UIDNUM, SYSDB_GIDNUM,
+                            SYSDB_OBJECTCATEGORY, NULL };
 
     return nss_getby_name(cli_ctx, false, CACHE_REQ_OBJECT_BY_NAME, attrs,
                           SSS_MC_NONE, nss_protocol_fill_sid);
diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c
index 96cb8617bc..0fd8d48dad 100644
--- a/src/responder/nss/nss_protocol_sid.c
+++ b/src/responder/nss/nss_protocol_sid.c
@@ -87,13 +87,115 @@ nss_get_id_type(struct nss_cmd_ctx *cmd_ctx,
     return EOK;
 }
 
+static errno_t
+nss_get_sid_id_type(struct nss_cmd_ctx *cmd_ctx,
+                    struct cache_req_result *result,
+                    const char **_sid,
+                    enum sss_id_type *_type)
+{
+    errno_t ret;
+    size_t c;
+    const char *tmp;
+    const char *user_sid = NULL;
+    const char *group_sid = NULL;
+    uint64_t user_uid = 0;
+    uint64_t user_gid = 0;
+    uint64_t group_gid = 0;
+    enum sss_id_type ltype;
+
+    if (result->count == 1) {
+        *_sid = ldb_msg_find_attr_as_string(result->msgs[0],
+                                            SYSDB_SID_STR, NULL);
+        if (*_sid == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "Missing SID.\n");
+            return EINVAL;
+        }
+        return nss_get_id_type(cmd_ctx, result, _type);
+    }
+
+    for (c = 0; c < result->count; c++) {
+        ret = find_sss_id_type(result->msgs[c],
+                               false /* we are only interested in the type
+                                      * of the object, so mpg setting can
+                                      * be ignored */,
+                               &ltype);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Unable to find ID type, ignored [%d][%s].\n",
+                  ret, sss_strerror(ret));
+            continue;
+        }
+
+        if (ltype == SSS_ID_TYPE_GID) {
+            tmp = ldb_msg_find_attr_as_string(result->msgs[c],
+                                               SYSDB_SID_STR, NULL);
+            if (tmp == NULL) {
+                continue;
+            }
+            if (tmp != NULL && group_sid != NULL) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "Search for SID found multiple users with a SID, "
+                      "request failed.\n");
+                return EINVAL;
+            }
+            group_sid = tmp;
+            group_gid = ldb_msg_find_attr_as_uint64(result->msgs[c],
+                                                    SYSDB_GIDNUM, 0);
+        } else {
+            tmp = ldb_msg_find_attr_as_string(result->msgs[c],
+                                              SYSDB_SID_STR, NULL);
+            if (tmp == NULL) {
+                continue;
+            }
+            if (tmp != NULL && user_sid != NULL) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "Search for SID found multiple users with a SID, "
+                      "request failed.\n");
+                return EINVAL;
+            }
+            user_sid = tmp;
+            user_uid = ldb_msg_find_attr_as_uint64(result->msgs[c],
+                                                   SYSDB_UIDNUM, 0);
+            user_gid = ldb_msg_find_attr_as_uint64(result->msgs[c],
+                                                   SYSDB_GIDNUM, 0);
+        }
+    }
+
+    if (user_sid == NULL && group_sid == NULL) {
+        /* No SID in the results */
+        return ENOENT;
+    } else if (user_sid != NULL && group_sid == NULL) {
+        /* There is only one user with a SID in the results */
+        *_sid = user_sid;
+        *_type = SSS_ID_TYPE_UID;
+    } else if (user_sid == NULL && group_sid != NULL) {
+        /* There is only one group with a SID in the results */
+        *_sid = group_sid;
+        *_type = SSS_ID_TYPE_GID;
+    } else if (user_sid != NULL && group_sid != NULL && user_uid != 0
+                    && user_uid == user_gid && user_gid == group_gid) {
+        /* Manually created user-private-group */
+        *_sid = user_sid;
+        *_type = SSS_ID_TYPE_UID;
+    } else {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Found user with SID [%s] and group with SID [%s] during a "
+              "single request, cannot handle this case.\n",
+              user_sid, group_sid);
+        /* Unrelated user and group both with SIDs are returned, we cannot
+         * handle this case. */
+        return EINVAL;
+    }
+
+    return EOK;
+}
+
 errno_t
 nss_protocol_fill_sid(struct nss_ctx *nss_ctx,
                       struct nss_cmd_ctx *cmd_ctx,
                       struct sss_packet *packet,
                       struct cache_req_result *result)
 {
-    struct ldb_message *msg = result->msgs[0];
     struct sized_string sz_sid;
     enum sss_id_type id_type;
     const char *sid;
@@ -102,17 +204,11 @@ nss_protocol_fill_sid(struct nss_ctx *nss_ctx,
     uint8_t *body;
     errno_t ret;
 
-    ret = nss_get_id_type(cmd_ctx, result, &id_type);
+    ret = nss_get_sid_id_type(cmd_ctx, result, &sid, &id_type);
     if (ret != EOK) {
         return ret;
     }
 
-    sid = ldb_msg_find_attr_as_string(msg, SYSDB_SID_STR, NULL);
-    if (sid == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "Missing SID.\n");
-        return EINVAL;
-    }
-
     to_sized_string(&sz_sid, sid);
 
     ret = sss_packet_grow(packet, sz_sid.len + 3 * sizeof(uint32_t));
@@ -242,6 +338,13 @@ nss_protocol_fill_orig(struct nss_ctx *nss_ctx,
                                  SYSDB_ORIG_MEMBEROF,
                                  NULL };
 
+    if (result->count != 1) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Unexpected number of results [%u], expected [1].\n",
+              result->count);
+        return EINVAL;
+    }
+
     tmp_ctx = talloc_new(NULL);
     if (tmp_ctx == NULL) {
         return ENOMEM;
diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c
index 2b6b8ca280..5f5a383a58 100644
--- a/src/tests/cmocka/test_nss_srv.c
+++ b/src/tests/cmocka/test_nss_srv.c
@@ -4109,6 +4109,21 @@ struct passwd sid_user = {
     .pw_passwd = discard_const("*"),
 };
 
+struct passwd sid_user_upg = {
+    .pw_name = discard_const("testusersidupg"),
+    .pw_uid = 5678,
+    .pw_gid = 5678,
+    .pw_dir = discard_const("/home/testusersidupg"),
+    .pw_gecos = discard_const("test user upg"),
+    .pw_shell = discard_const("/bin/sh"),
+    .pw_passwd = discard_const("*"),
+};
+
+struct group sid_user_group = {
+    .gr_name = discard_const("testusersidupg"),
+    .gr_gid = 5678,
+};
+
 static int test_nss_getsidbyname_check(uint32_t status,
                                        uint8_t *body,
                                        size_t blen)
@@ -4168,6 +4183,88 @@ void test_nss_getsidbyname(void **state)
     assert_int_equal(ret, EOK);
 }
 
+void test_nss_getsidbyname_ipa_upg(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *attrs;
+    const char *testuser_sid = "S-1-2-3-4";
+
+    attrs = sysdb_new_attrs(nss_test_ctx);
+    assert_non_null(attrs);
+
+    ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, testuser_sid);
+    assert_int_equal(ret, EOK);
+
+    ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
+                     &sid_user_upg, attrs, 0);
+    assert_int_equal(ret, EOK);
+
+    ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom,
+                      &sid_user_group, NULL, 0);
+    assert_int_equal(ret, EOK);
+
+    mock_input_user_or_group("testusersid");
+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+    will_return(test_nss_getsidbyname_check, testuser_sid);
+
+    /* Query for that user, call a callback when command finishes */
+    set_cmd_cb(test_nss_getsidbyname_check);
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with EOK */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, EOK);
+}
+
+void test_nss_getsidbyname_ipa_upg_manual(void **state)
+{
+    errno_t ret;
+    struct sysdb_attrs *attrs;
+    const char *testuser_sid = "S-1-2-3-4";
+    const char *testgroup_sid = "S-1-2-3-5";
+
+    attrs = sysdb_new_attrs(nss_test_ctx);
+    assert_non_null(attrs);
+
+    ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, testuser_sid);
+    assert_int_equal(ret, EOK);
+
+    ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom,
+                     &sid_user_upg, attrs, 0);
+    assert_int_equal(ret, EOK);
+
+    talloc_free(attrs);
+    attrs = sysdb_new_attrs(nss_test_ctx);
+    assert_non_null(attrs);
+
+    ret = sysdb_attrs_add_string(attrs, SYSDB_SID_STR, testgroup_sid);
+    assert_int_equal(ret, EOK);
+
+    ret = store_group(nss_test_ctx, nss_test_ctx->tctx->dom,
+                      &sid_user_group, attrs, 0);
+    assert_int_equal(ret, EOK);
+
+    mock_input_user_or_group("testusersid");
+    will_return(__wrap_sss_packet_get_cmd, SSS_NSS_GETSIDBYNAME);
+    will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
+
+    will_return(test_nss_getsidbyname_check, testuser_sid);
+
+    /* Query for that user, call a callback when command finishes */
+    set_cmd_cb(test_nss_getsidbyname_check);
+    ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETSIDBYNAME,
+                          nss_test_ctx->nss_cmds);
+    assert_int_equal(ret, EOK);
+
+    /* Wait until the test finishes with EOK */
+    ret = test_ev_loop(nss_test_ctx->tctx);
+    assert_int_equal(ret, EOK);
+}
+
 void test_nss_getsidbyid(void **state)
 {
     errno_t ret;
@@ -5667,6 +5764,8 @@ int main(int argc, const char *argv[])
                                         nss_subdom_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getsidbyname,
                                         nss_test_setup, nss_test_teardown),
+        cmocka_unit_test_setup_teardown(test_nss_getsidbyname_ipa_upg,
+                                        nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getsidbyid,
                                         nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getsidbyuid,
@@ -5685,6 +5784,8 @@ int main(int argc, const char *argv[])
                                         nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getsidbyname_neg,
                                         nss_test_setup, nss_test_teardown),
+        cmocka_unit_test_setup_teardown(test_nss_getsidbyname_ipa_upg_manual,
+                                        nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getpwnam_ex,
                                         nss_test_setup, nss_test_teardown),
         cmocka_unit_test_setup_teardown(test_nss_getpwuid_ex,
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/sssd-devel@lists.fedorahosted.org
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to