URL: https://github.com/SSSD/sssd/pull/5784
Author: ikerexxe
 Title: #5784: proxy: allow removing group members
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/5784/head:pr5784
git checkout pr5784
From 9f2cf6abddc352ca894e63c6ebe66687d3dd6abb Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedr...@redhat.com>
Date: Tue, 14 Sep 2021 12:35:09 +0200
Subject: [PATCH] proxy: allow removing group members

The proxy provider doesn't allow to remove group members once they have
been added. This patch allows to do it by looping the member list from
the cache and comparing it with the actual membership list. If a member
is missing then it's removed from the cache.

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

Signed-off-by: Iker Pedrosa <ipedr...@redhat.com>
---
 src/providers/proxy/proxy_id.c | 166 ++++++++++++++++++++++++++++++++-
 1 file changed, 164 insertions(+), 2 deletions(-)

diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index 25daea585d..f7cfe5cf65 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -915,7 +915,9 @@ handle_getgr_result(enum nss_status status, struct group *grp,
 
     case NSS_STATUS_NOTFOUND:
         DEBUG(SSSDBG_MINOR_FAILURE, "Group not found.\n");
-        *delete_group = true;
+        if (delete_group) {
+            *delete_group = true;
+        }
         break;
 
     case NSS_STATUS_SUCCESS:
@@ -927,7 +929,9 @@ handle_getgr_result(enum nss_status status, struct group *grp,
         if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) {
             DEBUG(SSSDBG_MINOR_FAILURE,
                   "Group filtered out! (id out of range)\n");
-            *delete_group = true;
+            if (delete_group) {
+                *delete_group = true;
+            }
             break;
         }
         break;
@@ -1488,6 +1492,153 @@ static int get_initgr(TALLOC_CTX *mem_ctx,
     return ret;
 }
 
+static int remove_group_members(struct proxy_id_ctx *ctx,
+                                struct sss_domain_info *dom,
+                                const struct passwd *pwd,
+                                long int num_gids,
+                                const gid_t *gids,
+                                long int num_cached_gids,
+                                const gid_t *cached_gids)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    int i = 0, j = 0;
+    int ret = EOK;
+    size_t buflen = 0;
+    char *buffer = NULL;
+    char *groupname = NULL;
+    const char *username = NULL;
+    enum nss_status status;
+    struct group *grp = NULL;
+    bool group_found = false;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        goto done;
+    }
+
+    username = sss_create_internal_fqname(tmp_ctx, pwd->pw_name, dom->name);
+    if (username == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n", pwd->pw_name);
+        ret = ENOMEM;
+        goto done;
+    }
+
+    grp = talloc(tmp_ctx, struct group);
+    if (!grp) {
+        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc() failed\n");
+        goto done;
+    }
+
+    for (i = 0; i < num_cached_gids; i++) {
+        group_found = false;
+        // group 0 is the primary group so it can be skipped
+        for (j = 1; j < num_gids; j++) {
+            if (cached_gids[i] == gids[j]) {
+                group_found = true;
+                break;
+            }
+        }
+
+        if (!group_found) {
+            do {
+                /* always zero out the grp structure */
+                memset(grp, 0, sizeof(struct group));
+                buffer = grow_group_buffer(tmp_ctx, &buffer, &buflen);
+                if (!buffer) {
+                    ret = ENOMEM;
+                    break;
+                }
+
+                status = ctx->ops.getgrgid_r(cached_gids[i], grp, buffer, buflen, &ret);
+
+                ret = handle_getgr_result(status, grp, dom, NULL);
+            } while (ret == EAGAIN);
+
+            if (ret != EOK) {
+                DEBUG(SSSDBG_OP_FAILURE,
+                      "getgrgid failed [%d]: %s\n", ret, strerror(ret));
+                continue;
+            }
+
+            groupname = sss_create_internal_fqname(tmp_ctx, grp->gr_name, dom->name);
+            if (groupname == NULL) {
+                DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n",
+                      grp->gr_name);
+                ret = ENOMEM;
+                continue;
+            }
+
+            ret = sysdb_remove_group_member(dom, groupname,
+                                            username,
+                                            SYSDB_MEMBER_USER, false);
+
+            if (ret != EOK) {
+                DEBUG(SSSDBG_CRIT_FAILURE,
+                      "Could not remove member [%s] from group [%s]\n",
+                      username, groupname);
+                continue;
+            }
+        }
+    }
+
+done:
+    return ret;
+}
+
+static int get_cached_user_members(struct sysdb_ctx *sysdb,
+                                   struct sss_domain_info *dom,
+                                   const struct passwd *pwd,
+                                   unsigned int *_num_cached_gids,
+                                   gid_t **_cached_gids)
+{
+    TALLOC_CTX *tmp_ctx = NULL;
+    int ret = EOK;
+    int i = 0, j = 0;
+    gid_t gid = 0;
+    gid_t *cached_gids = NULL;
+    const char *username = NULL;
+    struct ldb_result *res = NULL;
+    unsigned int num_cached_gids = 0;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) {
+        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
+        goto done;
+    }
+
+    username = sss_create_internal_fqname(tmp_ctx, pwd->pw_name, dom->name);
+    if (username == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, "Failed to create fqdn '%s'\n", pwd->pw_name);
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ret = sysdb_initgroups(tmp_ctx, dom, username, &res);
+    if (res->count > 1) {
+        num_cached_gids = res->count - 1;
+
+        cached_gids = talloc_array(tmp_ctx, gid_t, num_cached_gids);
+
+        for (i = 1; i < res->count; i++) {
+            gid = ldb_msg_find_attr_as_uint(res->msgs[i], SYSDB_GIDNUM, 0);
+            cached_gids[j] = gid;
+            j++;
+        }
+    }
+
+    *_num_cached_gids = num_cached_gids;
+    *_cached_gids = talloc_steal(sysdb, cached_gids);
+
+done:
+    talloc_zfree(tmp_ctx);
+
+    return ret;
+}
+
 static int get_initgr_groups_process(TALLOC_CTX *memctx,
                                      struct proxy_id_ctx *ctx,
                                      struct sysdb_ctx *sysdb,
@@ -1503,6 +1654,8 @@ static int get_initgr_groups_process(TALLOC_CTX *memctx,
     int ret;
     int i;
     time_t now;
+    gid_t *cached_gids = NULL;
+    unsigned int num_cached_gids = 0;
 
     num_gids = 0;
     limit = 4096;
@@ -1553,6 +1706,15 @@ static int get_initgr_groups_process(TALLOC_CTX *memctx,
         DEBUG(SSSDBG_CONF_SETTINGS, "User [%s] appears to be member of %lu "
               "groups\n", pwd->pw_name, num_gids);
 
+        ret = get_cached_user_members(sysdb, dom, pwd, &num_cached_gids, &cached_gids);
+        if (ret) {
+            return ret;
+        }
+        ret = remove_group_members(ctx, dom, pwd, num_gids, gids, num_cached_gids, cached_gids);
+        if (ret) {
+            return ret;
+        }
+
         now = time(NULL);
         for (i = 0; i < num_gids; i++) {
             ret = get_gr_gid(memctx, ctx, sysdb, dom, gids[i], now);
_______________________________________________
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