From: Samuel Cabrero Date: Mon, 6 Feb 2023 18:06:43 +0000 (+0100) Subject: winbind:varlink: Implement membership by group and user names X-Git-Tag: tevent-0.17.0~733 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32d2a783b0c9b060d3f2f330e98c62b7b165aee3;p=thirdparty%2Fsamba.git winbind:varlink: Implement membership by group and user names $> 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 Reviewed-by: Andreas Schneider --- diff --git a/source3/winbindd/winbindd_varlink.c b/source3/winbindd/winbindd_varlink.c index e17427e7d4d..857ea5f14d6 100644 --- a/source3/winbindd/winbindd_varlink.c +++ b/source3/winbindd/winbindd_varlink.c @@ -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)) { diff --git a/source3/winbindd/winbindd_varlink.h b/source3/winbindd/winbindd_varlink.h index 497542a5f11..0508bc689ff 100644 --- a/source3/winbindd/winbindd_varlink.h +++ b/source3/winbindd/winbindd_varlink.h @@ -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); diff --git a/source3/winbindd/winbindd_varlink_getmemberships.c b/source3/winbindd/winbindd_varlink_getmemberships.c index 2351f8a1c4f..13ca838ef7a 100644 --- a/source3/winbindd/winbindd_varlink_getmemberships.c +++ b/source3/winbindd/winbindd_varlink_getmemberships.c @@ -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; +}