s3:winbind: Convert WINBINDD_LIST_GROUPS to the new API
authorVolker Lendecke <vl@samba.org>
Sat, 29 Aug 2009 15:17:47 +0000 (17:17 +0200)
committerVolker Lendecke <vl@samba.org>
Sat, 29 Aug 2009 17:53:46 +0000 (19:53 +0200)
source3/Makefile.in
source3/winbindd/winbindd.c
source3/winbindd/winbindd_async.c
source3/winbindd/winbindd_domain.c
source3/winbindd/winbindd_group.c
source3/winbindd/winbindd_list_groups.c [new file with mode: 0644]
source3/winbindd/winbindd_misc.c
source3/winbindd/winbindd_proto.h

index 91534026fa4d55a28b7159935a6a4d6187ff8cc6..ebf602492333adc7b5cf12c559228cf88db7e952 100644 (file)
@@ -1210,6 +1210,7 @@ WINBINDD_OBJ1 = \
                winbindd/winbindd_dsgetdcname.o \
                winbindd/winbindd_getdcname.o \
                winbindd/winbindd_list_users.o \
+               winbindd/winbindd_list_groups.o \
                auth/token_util.o \
                ../nsswitch/libwbclient/wb_reqtrans.o \
                smbd/connection.o
index 1d3762f5b95b568efb9154c3b0d81e1ae7901c3c..e583dae4a9b2b8ec199cd24dba85931e77a2e952 100644 (file)
@@ -435,7 +435,6 @@ static struct winbindd_dispatch_table {
 
        /* Enumeration functions */
 
-       { WINBINDD_LIST_GROUPS, winbindd_list_groups, "LIST_GROUPS" },
        { WINBINDD_LIST_TRUSTDOM, winbindd_list_trusted_domains,
          "LIST_TRUSTDOM" },
 
@@ -538,6 +537,8 @@ static struct winbindd_async_dispatch_table async_nonpriv_table[] = {
          winbindd_endgrent_send, winbindd_endgrent_recv },
        { WINBINDD_LIST_USERS, "LIST_USERS",
          winbindd_list_users_send, winbindd_list_users_recv },
+       { WINBINDD_LIST_GROUPS, "LIST_GROUPS",
+         winbindd_list_groups_send, winbindd_list_groups_recv },
 
        { 0, NULL, NULL, NULL }
 };
index 1e63ed1fec82d449d80f6b5f5b2d641b7383cfce..6c5d92e71b9de507b2aebe9dcf0617d1d9f2e692 100644 (file)
@@ -454,163 +454,6 @@ enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
        return WINBINDD_OK;
 }
 
-/* This is the first callback after enumerating users/groups from a domain */
-static void listent_recv(TALLOC_CTX *mem_ctx, bool success,
-                           struct winbindd_response *response,
-                           void *c, void *private_data)
-{
-       void (*cont)(void *priv, bool succ, fstring dom_name, char *data) =
-               (void (*)(void *, bool, fstring, char*))c;
-
-       if (!success || response->result != WINBINDD_OK) {
-               DEBUG(5, ("list_ent() failed!\n"));
-               cont(private_data, False, response->data.name.dom_name, NULL);
-               return;
-       }
-
-       cont(private_data, True, response->data.name.dom_name,
-            (char *)response->extra_data.data);
-}
-
-/* Request the name of all users/groups in a single domain */
-void winbindd_listent_async(TALLOC_CTX *mem_ctx,
-                              struct winbindd_domain *domain,
-                              void (*cont)(void *private_data, bool success,
-                                    fstring dom_name, char* extra_data),
-                              void *private_data, enum ent_type type)
-{
-       struct winbindd_request request;
-
-       ZERO_STRUCT(request);
-       if (type == LIST_USERS)
-               request.cmd = WINBINDD_LIST_USERS;
-       else if (type == LIST_GROUPS)
-               request.cmd = WINBINDD_LIST_GROUPS;
-
-       do_async_domain(mem_ctx, domain, &request, listent_recv,
-                       (void *)cont, private_data);
-}
-
-enum winbindd_result winbindd_dual_list_users(struct winbindd_domain *domain,
-                                              struct winbindd_cli_state *state)
-{
-       struct wbint_userinfo *info;
-       NTSTATUS status;
-       struct winbindd_methods *methods;
-       uint32 num_entries = 0;
-       char *extra_data;
-       uint32_t extra_data_len = 0, i;
-
-       /* Must copy domain into response first for debugging in parent */
-       fstrcpy(state->response->data.name.dom_name, domain->name);
-
-       /* Query user info */
-       methods = domain->methods;
-       status = methods->query_user_list(domain, state->mem_ctx, 
-                                         &num_entries, &info);
-
-       if (!NT_STATUS_IS_OK(status))
-               return WINBINDD_ERROR;
-
-       if (num_entries == 0)
-               return WINBINDD_OK;
-
-       /* Allocate some memory for extra data.  Note that we limit
-          account names to sizeof(fstring) = 256 characters.           
-          +1 for the ',' between group names */
-       extra_data = talloc_array(state->mem_ctx, char,
-                                 (sizeof(fstring) + 1) * num_entries);
-
-       if (!extra_data) {
-               DEBUG(0,("failed to enlarge buffer!\n"));
-               return WINBINDD_ERROR;
-       }
-
-       /* Pack user list into extra data fields */
-       for (i = 0; i < num_entries; i++) {
-               fstring acct_name, name;
-
-               if (info[i].acct_name == NULL)
-                       fstrcpy(acct_name, "");
-               else
-                       fstrcpy(acct_name, info[i].acct_name);
-
-               fill_domain_username(name, domain->name, acct_name, True);
-               /* Append to extra data */
-               memcpy(&extra_data[extra_data_len], name, strlen(name));
-               extra_data_len += strlen(name);
-               extra_data[extra_data_len++] = ',';
-       }   
-
-       /* Assign extra_data fields in response structure */
-       if (extra_data) {
-               /* remove trailing ',' */
-               extra_data[extra_data_len - 1] = '\0';
-               state->response->extra_data.data = extra_data;
-               state->response->length += extra_data_len;
-       }
-
-       return WINBINDD_OK;
-}
-
-enum winbindd_result winbindd_dual_list_groups(struct winbindd_domain *domain,
-                                               struct winbindd_cli_state *state)
-{
-       struct getent_state groups;
-       char *extra_data;
-       uint32_t extra_data_len = 0, i;
-
-       ZERO_STRUCT(groups);
-
-       /* Must copy domain into response first for debugging in parent */
-       fstrcpy(state->response->data.name.dom_name, domain->name);
-       fstrcpy(groups.domain_name, domain->name);
-
-       /* Get list of sam groups */
-       if (!get_sam_group_entries(&groups)) {
-               /* this domain is empty or in an error state */
-               return WINBINDD_ERROR;
-       }
-
-       /* Allocate some memory for extra data.  Note that we limit
-          account names to sizeof(fstring) = 256 characters.
-          +1 for the ',' between group names */
-       extra_data = talloc_array(
-               state->mem_ctx, char,
-               (sizeof(fstring) + 1) * groups.num_sam_entries);
-
-       if (!extra_data) {
-               DEBUG(0,("failed to enlarge buffer!\n"));
-               SAFE_FREE(groups.sam_entries);
-               return WINBINDD_ERROR;
-       }
-
-       /* Pack group list into extra data fields */
-       for (i = 0; i < groups.num_sam_entries; i++) {
-               char *group_name = ((struct acct_info *)
-                                   groups.sam_entries)[i].acct_name;
-               fstring name;
-
-               fill_domain_username(name, domain->name, group_name, True);
-               /* Append to extra data */
-               memcpy(&extra_data[extra_data_len], name, strlen(name));
-               extra_data_len += strlen(name);
-               extra_data[extra_data_len++] = ',';
-       }
-
-       SAFE_FREE(groups.sam_entries);
-
-       /* Assign extra_data fields in response structure */
-       if (extra_data) {
-               /* remove trailing ',' */
-               extra_data[extra_data_len - 1] = '\0';
-               state->response->extra_data.data = extra_data;
-               state->response->length += extra_data_len;
-       }
-
-       return WINBINDD_OK;
-}
-
 bool print_sidlist(TALLOC_CTX *mem_ctx, const DOM_SID *sids,
                   size_t num_sids, char **result, ssize_t *len)
 {
@@ -671,29 +514,6 @@ bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
        return True;
 }
 
-static bool parse_ridlist(TALLOC_CTX *mem_ctx, char *ridstr,
-                         uint32 **rids, size_t *num_rids)
-{
-       char *p;
-
-       p = ridstr;
-       if (p == NULL)
-               return False;
-
-       while (p[0] != '\0') {
-               uint32 rid;
-               char *q;
-               rid = strtoul(p, &q, 10);
-               if (*q != '\n') {
-                       DEBUG(0, ("Got invalid ridstr: %s\n", p));
-                       return False;
-               }
-               p = q+1;
-               ADD_TO_ARRAY(mem_ctx, uint32, rid, rids, num_rids);
-       }
-       return True;
-}
-
 static void getsidaliases_recv(TALLOC_CTX *mem_ctx, bool success,
                               struct winbindd_response *response,
                               void *c, void *private_data)
index 14376c62bf0725329c0d812fcef7eca25da747d0..107c83ac80866082f5f0a2ab9672878f3e9cbba7 100644 (file)
@@ -49,14 +49,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = {
                .name           = "LOOKUPNAME",
                .struct_cmd     = WINBINDD_LOOKUPNAME,
                .struct_fn      = winbindd_dual_lookupname,
-       },{
-               .name           = "LIST_USERS",
-               .struct_cmd     = WINBINDD_LIST_USERS,
-               .struct_fn      = winbindd_dual_list_users,
-       },{
-               .name           = "LIST_GROUPS",
-               .struct_cmd     = WINBINDD_LIST_GROUPS,
-               .struct_fn      = winbindd_dual_list_groups,
        },{
                .name           = "LIST_TRUSTDOM",
                .struct_cmd     = WINBINDD_LIST_TRUSTDOM,
index 8a76071265ffe806f5e367b2fba6a98361f3e678..eab5c26df4fc2e16f1f176c1f45241d170671743 100644 (file)
@@ -201,12 +201,6 @@ bool get_sam_group_entries(struct getent_state *ent)
        return result;
 }
 
-/* List domain groups without mapping to unix ids */
-void winbindd_list_groups(struct winbindd_cli_state *state)
-{
-       winbindd_list_ent(state, LIST_GROUPS);
-}
-
 /* Get user supplementary groups.  This is much quicker than trying to
    invert the groups database.  We merge the groups from the gids and
    other_sids info3 fields as trusted domain, universal group
diff --git a/source3/winbindd/winbindd_list_groups.c b/source3/winbindd/winbindd_list_groups.c
new file mode 100644 (file)
index 0000000..3795045
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+   Unix SMB/CIFS implementation.
+   async implementation of WINBINDD_LIST_GROUPS
+   Copyright (C) Volker Lendecke 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "winbindd.h"
+#include "librpc/gen_ndr/cli_wbint.h"
+
+struct winbindd_list_groups_domstate {
+       struct tevent_req *subreq;
+       struct winbindd_domain *domain;
+       struct wbint_Principals groups;
+};
+
+struct winbindd_list_groups_state {
+       int num_received;
+       /* All domains */
+       int num_domains;
+       struct winbindd_list_groups_domstate *domains;
+};
+
+static void winbindd_list_groups_done(struct tevent_req *subreq);
+
+struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct winbindd_cli_state *cli,
+                                            struct winbindd_request *request)
+{
+       struct tevent_req *req;
+       struct winbindd_list_groups_state *state;
+       struct winbindd_domain *domain;
+       int i;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct winbindd_list_groups_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       /* Ensure null termination */
+       request->domain_name[sizeof(request->domain_name)-1]='\0';
+
+       DEBUG(3, ("list_groups %s\n", request->domain_name));
+
+       if (request->domain_name[0] != '\0') {
+               state->num_domains = 1;
+       } else {
+               state->num_domains = 0;
+               for (domain = domain_list(); domain; domain = domain->next) {
+                       state->num_domains += 1;
+               }
+       }
+
+       state->domains = talloc_array(state,
+                                     struct winbindd_list_groups_domstate,
+                                     state->num_domains);
+       if (tevent_req_nomem(state->domains, req)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (request->domain_name[0] != '\0') {
+               state->domains[0].domain = find_domain_from_name_noinit(
+                       request->domain_name);
+               if (state->domains[0].domain == NULL) {
+                       tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
+                       return tevent_req_post(req, ev);
+               }
+       } else {
+               i = 0;
+               for (domain = domain_list(); domain; domain = domain->next) {
+                       state->domains[i++].domain = domain;
+               }
+       }
+
+       for (i=0; i<state->num_domains; i++) {
+               struct winbindd_list_groups_domstate *d = &state->domains[i];
+
+               d->subreq = rpccli_wbint_QueryGroupList_send(
+                       state->domains, ev, d->domain->child.rpccli,
+                       &d->groups);
+               if (tevent_req_nomem(d->subreq, req)) {
+                       TALLOC_FREE(state->domains);
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(d->subreq, winbindd_list_groups_done,
+                                       req);
+       }
+       state->num_received = 0;
+       return req;
+}
+
+static void winbindd_list_groups_done(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct winbindd_list_groups_state *state = tevent_req_data(
+               req, struct winbindd_list_groups_state);
+       NTSTATUS status, result;
+       int i;
+
+       status = rpccli_wbint_QueryGroupList_recv(subreq, state->domains,
+                                                 &result);
+
+       for (i=0; i<state->num_domains; i++) {
+               if (subreq == state->domains[i].subreq) {
+                       break;
+               }
+       }
+       if (i < state->num_domains) {
+               struct winbindd_list_groups_domstate *d = &state->domains[i];
+
+               DEBUG(10, ("Domain %s returned %d users\n", d->domain->name,
+                          d->groups.num_principals));
+
+               d->subreq = NULL;
+
+               if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(result)) {
+                       DEBUG(10, ("list_groups for domain %s failed\n",
+                                  d->domain->name));
+                       d->groups.num_principals = 0;
+               }
+       }
+
+       TALLOC_FREE(subreq);
+
+       state->num_received += 1;
+
+       if (state->num_received >= state->num_domains) {
+               tevent_req_done(req);
+       }
+}
+
+NTSTATUS winbindd_list_groups_recv(struct tevent_req *req,
+                                  struct winbindd_response *response)
+{
+       struct winbindd_list_groups_state *state = tevent_req_data(
+               req, struct winbindd_list_groups_state);
+       NTSTATUS status;
+       char *result;
+       int i;
+       uint32_t j;
+       size_t len;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+
+       len = 0;
+       for (i=0; i<state->num_domains; i++) {
+               struct winbindd_list_groups_domstate *d = &state->domains[i];
+
+               for (j=0; j<d->groups.num_principals; j++) {
+                       fstring name;
+                       fill_domain_username(name, d->domain->name,
+                                            d->groups.principals[j].name,
+                                            True);
+                       len += strlen(name)+1;
+               }
+       }
+
+       result = talloc_array(response, char, len+1);
+       if (result == 0) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       len = 0;
+       for (i=0; i<state->num_domains; i++) {
+               struct winbindd_list_groups_domstate *d = &state->domains[i];
+
+               for (j=0; j<d->groups.num_principals; j++) {
+                       fstring name;
+                       size_t this_len;
+                       fill_domain_username(name, d->domain->name,
+                                            d->groups.principals[j].name,
+                                            True);
+                       this_len = strlen(name);
+                       memcpy(result+len, name, this_len);
+                       len += this_len;
+                       result[len] = ',';
+                       len += 1;
+               }
+       }
+       result[len-1] = '\0';
+
+       response->extra_data.data = result;
+       response->length += len;
+
+       return NT_STATUS_OK;
+}
index beaf450743fb79719654f8ecc2be42474f890696..b9673909664372e4b044ef9310c479192efc480e 100644 (file)
@@ -94,128 +94,6 @@ enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *do
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
 
-/* Helpers for listing user and group names */
-
-const char *ent_type_strings[] = {"users", 
-                                 "groups"};
-
-static const char *get_ent_type_string(enum ent_type type)
-{
-       return ent_type_strings[type];
-}
-
-struct listent_state {
-       TALLOC_CTX *mem_ctx;
-       struct winbindd_cli_state *cli_state;
-       enum ent_type type;
-       int domain_count;
-       char *extra_data;
-       uint32_t extra_data_len;
-};
-
-static void listent_recv(void *private_data, bool success, fstring dom_name,
-                        char *extra_data);
-
-/* List domain users/groups without mapping to unix ids */
-void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type)
-{
-       struct winbindd_domain *domain;
-       const char *which_domain;
-       struct listent_state *ent_state;
-
-       DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid, 
-             get_ent_type_string(type)));
-
-       /* Ensure null termination */
-       state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
-       which_domain = state->request->domain_name;
-       
-       /* Initialize listent_state */
-       ent_state = TALLOC_P(state->mem_ctx, struct listent_state);
-       if (ent_state == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               request_error(state);
-               return;
-       }
-
-       ent_state->mem_ctx = state->mem_ctx;
-       ent_state->cli_state = state;
-       ent_state->type = type;
-       ent_state->domain_count = 0;
-       ent_state->extra_data = NULL;
-       ent_state->extra_data_len = 0;
-
-       /* Must count the full list of expected domains before we request data
-        * from any of them.  Otherwise it's possible for a connection to the
-        * first domain to fail, call listent_recv(), and return to the
-        * client without checking any other domains. */
-       for (domain = domain_list(); domain; domain = domain->next) {
-               /* if we have a domain name restricting the request and this
-                  one in the list doesn't match, then just bypass the remainder
-                  of the loop */
-               if ( *which_domain && !strequal(which_domain, domain->name) )
-                       continue;
-
-               ent_state->domain_count++;
-       }
-
-       /* Make sure we're enumerating at least one domain */
-       if (!ent_state->domain_count) {
-               request_ok(state);
-               return;
-       }
-
-       /* Enumerate list of trusted domains and request user/group list from
-        * each */
-       for (domain = domain_list(); domain; domain = domain->next) {
-               if ( *which_domain && !strequal(which_domain, domain->name) )
-                       continue;
-
-               winbindd_listent_async(state->mem_ctx, domain, 
-                                         listent_recv, ent_state, type);
-       }
-}
-
-static void listent_recv(void *private_data, bool success, fstring dom_name,
-                        char *extra_data)
-{
-       /* extra_data comes to us as a '\0' terminated string of comma
-          separated users or groups */
-       struct listent_state *state = talloc_get_type_abort(
-               private_data, struct listent_state);
-
-       /* Append users/groups from one domain onto the whole list */
-       if (extra_data) {
-               DEBUG(5, ("listent_recv: %s returned %s.\n", 
-                     dom_name, get_ent_type_string(state->type)));
-                if (!state->extra_data)
-                        state->extra_data = talloc_asprintf(state->mem_ctx,
-                                                            "%s", extra_data);
-                else
-                        state->extra_data = talloc_asprintf_append(
-                                                            state->extra_data,
-                                                            ",%s", extra_data);
-                /* Add one for the '\0' and each additional ',' */
-                state->extra_data_len += strlen(extra_data) + 1;
-       }
-       else {
-               DEBUG(5, ("listent_recv: %s returned no %s.\n", 
-                     dom_name, get_ent_type_string(state->type)));
-       }
-
-       if (--state->domain_count)
-               /* Still waiting for some child domains to return */
-               return;
-
-       /* Return list of all users/groups to the client */
-       if (state->extra_data) {
-               state->cli_state->response->extra_data.data = state->extra_data;
-               state->cli_state->response->length += state->extra_data_len;
-       }
-
-       request_ok(state->cli_state);
-}      
-
 /* Constants and helper functions for determining domain trust types */
 
 enum trust_type {
index 9894602523b705a87ed0fd17e40b6edf37d088a0..b59d11b78ff50c7713d015be16bfd90a41be6c56 100644 (file)
@@ -950,4 +950,12 @@ struct tevent_req *winbindd_list_users_send(TALLOC_CTX *mem_ctx,
 NTSTATUS winbindd_list_users_recv(struct tevent_req *req,
                                  struct winbindd_response *response);
 
+struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct winbindd_cli_state *cli,
+                                            struct winbindd_request *request);
+NTSTATUS winbindd_list_groups_recv(struct tevent_req *req,
+                                  struct winbindd_response *response);
+
+
 #endif /*  _WINBINDD_PROTO_H_  */