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;
+}