]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
winbind:varlink: Implement membership by group and user names
authorSamuel Cabrero <scabrero@samba.org>
Mon, 6 Feb 2023 18:06:43 +0000 (19:06 +0100)
committerAndreas Schneider <asn@cryptomilk.org>
Thu, 20 Feb 2025 08:07:32 +0000 (08:07 +0000)
$> varlink call -m unix:/run/systemd/userdb/org.samba.winbind/io.systemd.UserDatabase.GetMemberships "{\"service\":\"org.samba.winbind\",\"groupName\":\"AFOREST+domain users\",\"userName\":\"AFOREST+user1\"}"
{
  "groupName": "AFOREST+domain users",
  "userName": "AFOREST+user1"
}

Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
source3/winbindd/winbindd_varlink.c
source3/winbindd/winbindd_varlink.h
source3/winbindd/winbindd_varlink_getmemberships.c

index e17427e7d4db93b4e346f81ce1bdaa8fc0fc5f94..857ea5f14d60d241f805c4e6ab79bc4299a48907 100644 (file)
@@ -416,6 +416,15 @@ static long io_systemd_getmemberships(VarlinkService *service,
                                                    flags,
                                                    parm_service,
                                                    parm_groupname);
+       } else if (parm_username != NULL && parm_groupname != NULL) {
+               /* Check membership */
+               status = wb_vl_membership_check(state,
+                                               state->ev_ctx,
+                                               call,
+                                               flags,
+                                               parm_service,
+                                               parm_username,
+                                               parm_groupname);
        }
 
        if (NT_STATUS_IS_ERR(status)) {
index 497542a5f11bc7779e288e471b66a580197db8a7..0508bc689ff7773d76a7ccd93f2f25fff3aa332b 100644 (file)
@@ -111,6 +111,13 @@ NTSTATUS wb_vl_memberships_by_group(TALLOC_CTX *mem_ctx,
                                    uint64_t flags,
                                    const char *service,
                                    const char *group_name);
+NTSTATUS wb_vl_membership_check(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev_ctx,
+                               VarlinkCall *call,
+                               uint64_t flags,
+                               const char *service,
+                               const char *user_name,
+                               const char *group_name);
 
 bool winbind_setup_varlink(TALLOC_CTX *mem_ctx, struct tevent_context *ev_ctx);
 
index 2351f8a1c4fd0ccca37486f470de56c2ca0e19fd..13ca838ef7a181312a8f017e76492ba7fc269994 100644 (file)
@@ -785,3 +785,185 @@ fail:
        TALLOC_FREE(s);
        return status;
 }
+
+/******************************************************************************
+ * Check membership
+ *****************************************************************************/
+
+struct membership_check_state {
+       struct tevent_context *ev_ctx;
+       struct winbindd_request *fake_req;
+       struct winbindd_cli_state *fake_cli;
+       const char *username;
+       const char *groupname;
+       VarlinkCall *call;
+};
+
+static int membership_check_state_destructor(struct membership_check_state *s)
+{
+       if (s->call != NULL) {
+               s->call = varlink_call_unref(s->call);
+       }
+
+       return 0;
+}
+
+static void membership_check_getgrnam_done(struct tevent_req *req)
+{
+       struct membership_check_state *s =
+               tevent_req_callback_data(req, struct membership_check_state);
+       struct winbindd_response *response = NULL;
+       struct winbindd_gr *gr = NULL;
+       char *gr_members = NULL;
+       char *name = NULL;
+       char *p = NULL;
+       uint32_t i;
+       NTSTATUS status;
+
+       /* winbindd_*_recv functions expect a talloc-allocated response */
+       response = talloc_zero(s, struct winbindd_response);
+       if (response == NULL) {
+               DBG_ERR("No memory\n");
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                       NULL);
+               goto out;
+       }
+
+       status = winbindd_getgrnam_recv(req, response);
+       TALLOC_FREE(req);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+               varlink_call_reply_error(s->call,
+                                        WB_VL_REPLY_ERROR_NO_RECORD_FOUND,
+                                        NULL);
+               goto out;
+       } else if (NT_STATUS_IS_ERR(status)) {
+               DBG_ERR("winbindd_getgrnam failed: %s\n", nt_errstr(status));
+               varlink_call_reply_error(
+                       s->call,
+                       WB_VL_REPLY_ERROR_SERVICE_NOT_AVAILABLE,
+                       NULL);
+               goto out;
+       }
+
+       gr = &response->data.gr;
+       gr_members = (char *)response->extra_data.data;
+
+       if (gr->num_gr_mem == 0 || gr_members == NULL) {
+               varlink_call_reply_error(s->call,
+                                        WB_VL_REPLY_ERROR_NO_RECORD_FOUND,
+                                        NULL);
+               goto out;
+       }
+
+       for ((name = strtok_r(gr_members, ",", &p)), i = 0; name != NULL;
+            name = strtok_r(NULL, ",", &p), i++) {
+               if (i == gr->num_gr_mem) {
+                       break;
+               }
+               if (strequal(name, s->username)) {
+                       membership_reply(s->call,
+                                        s->username,
+                                        s->groupname,
+                                        false);
+                       return;
+               }
+       }
+
+       varlink_call_reply_error(s->call,
+                                WB_VL_REPLY_ERROR_NO_RECORD_FOUND,
+                                NULL);
+out:
+       TALLOC_FREE(s);
+}
+
+NTSTATUS wb_vl_membership_check(TALLOC_CTX *mem_ctx,
+                               struct tevent_context *ev_ctx,
+                               VarlinkCall *call,
+                               uint64_t flags,
+                               const char *service,
+                               const char *user_name,
+                               const char *group_name)
+{
+       struct membership_check_state *s = NULL;
+       struct tevent_req *req = NULL;
+       NTSTATUS status;
+
+       /* Check if group expansion is enabled */
+       if (!lp_winbind_expand_groups()) {
+               varlink_call_reply_error(
+                       call,
+                       WB_VL_REPLY_ERROR_ENUMERATION_NOT_SUPPORTED,
+                       NULL);
+               return NT_STATUS_OK;
+       }
+
+       /* Check more flag is set */
+       if (!(flags & VARLINK_CALL_MORE)) {
+               DBG_WARNING("Request without more flag set\n");
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       s = talloc_zero(mem_ctx, struct membership_check_state);
+       if (s == NULL) {
+               DBG_ERR("No memory\n");
+               return NT_STATUS_NO_MEMORY;
+       }
+       talloc_set_destructor(s, membership_check_state_destructor);
+
+       s->fake_cli = talloc_zero(s, struct winbindd_cli_state);
+       if (s->fake_cli == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->fake_req = talloc_zero(s, struct winbindd_request);
+       if (s->fake_req == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->username = talloc_strdup(s, user_name);
+       if (s->username == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->groupname = talloc_strdup(s, group_name);
+       if (s->groupname == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+
+       s->ev_ctx = ev_ctx;
+       s->call = varlink_call_ref(call);
+
+       status = wb_vl_fake_cli_state(call, service, s->fake_cli);
+       if (NT_STATUS_IS_ERR(status)) {
+               DBG_ERR("Failed to create fake winbindd_cli_state: %s\n",
+                       nt_errstr(status));
+               goto fail;
+       }
+
+       s->fake_req->cmd = WINBINDD_GETGRNAM;
+       fstrcpy(s->fake_req->data.username, group_name);
+
+       req = winbindd_getgrnam_send(s, s->ev_ctx, s->fake_cli, s->fake_req);
+       if (req == NULL) {
+               DBG_ERR("No memory\n");
+               status = NT_STATUS_NO_MEMORY;
+               goto fail;
+       }
+       tevent_req_set_callback(req, membership_check_getgrnam_done, s);
+
+       return NT_STATUS_OK;
+fail:
+       TALLOC_FREE(s);
+       return status;
+}