winbindd: Initialize the domain groups member
[samba.git] / source3 / winbindd / winbindd_list_groups.c
1 /*
2    Unix SMB/CIFS implementation.
3    async implementation of WINBINDD_LIST_GROUPS
4    Copyright (C) Volker Lendecke 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "librpc/gen_ndr/ndr_winbind_c.h"
23
24 struct winbindd_list_groups_domstate {
25         struct tevent_req *subreq;
26         struct winbindd_domain *domain;
27         struct wbint_Principals groups;
28 };
29
30 struct winbindd_list_groups_state {
31         int num_received;
32         /* All domains */
33         int num_domains;
34         struct winbindd_list_groups_domstate *domains;
35 };
36
37 static void winbindd_list_groups_done(struct tevent_req *subreq);
38
39 struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx,
40                                              struct tevent_context *ev,
41                                              struct winbindd_cli_state *cli,
42                                              struct winbindd_request *request)
43 {
44         struct tevent_req *req;
45         struct winbindd_list_groups_state *state;
46         struct winbindd_domain *domain;
47         int i;
48
49         req = tevent_req_create(mem_ctx, &state,
50                                 struct winbindd_list_groups_state);
51         if (req == NULL) {
52                 return NULL;
53         }
54
55         /* Ensure null termination */
56         request->domain_name[sizeof(request->domain_name)-1]='\0';
57
58         DEBUG(3, ("list_groups %s\n", request->domain_name));
59
60         if (request->domain_name[0] != '\0') {
61                 state->num_domains = 1;
62         } else {
63                 state->num_domains = 0;
64                 for (domain = domain_list(); domain; domain = domain->next) {
65                         state->num_domains += 1;
66                 }
67         }
68
69         state->domains = talloc_array(state,
70                                       struct winbindd_list_groups_domstate,
71                                       state->num_domains);
72         if (tevent_req_nomem(state->domains, req)) {
73                 return tevent_req_post(req, ev);
74         }
75
76         if (request->domain_name[0] != '\0') {
77                 ZERO_STRUCT(state->domains[0].groups);
78
79                 state->domains[0].domain = find_domain_from_name_noinit(
80                         request->domain_name);
81                 if (state->domains[0].domain == NULL) {
82                         tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
83                         return tevent_req_post(req, ev);
84                 }
85         } else {
86                 i = 0;
87                 for (domain = domain_list(); domain; domain = domain->next) {
88                         ZERO_STRUCT(state->domains[i].groups);
89
90                         state->domains[i].domain = domain;
91                         i++;
92                 }
93         }
94
95         for (i=0; i<state->num_domains; i++) {
96                 struct winbindd_list_groups_domstate *d = &state->domains[i];
97
98                 d->subreq = dcerpc_wbint_QueryGroupList_send(
99                         state->domains, ev, dom_child_handle(d->domain),
100                         &d->groups);
101                 if (tevent_req_nomem(d->subreq, req)) {
102                         TALLOC_FREE(state->domains);
103                         return tevent_req_post(req, ev);
104                 }
105                 tevent_req_set_callback(d->subreq, winbindd_list_groups_done,
106                                         req);
107         }
108         state->num_received = 0;
109         return req;
110 }
111
112 static void winbindd_list_groups_done(struct tevent_req *subreq)
113 {
114         struct tevent_req *req = tevent_req_callback_data(
115                 subreq, struct tevent_req);
116         struct winbindd_list_groups_state *state = tevent_req_data(
117                 req, struct winbindd_list_groups_state);
118         NTSTATUS status, result;
119         int i;
120
121         status = dcerpc_wbint_QueryGroupList_recv(subreq, state->domains,
122                                                   &result);
123
124         for (i=0; i<state->num_domains; i++) {
125                 if (subreq == state->domains[i].subreq) {
126                         break;
127                 }
128         }
129         if (i < state->num_domains) {
130                 struct winbindd_list_groups_domstate *d = &state->domains[i];
131
132                 DEBUG(10, ("Domain %s returned %d groups\n", d->domain->name,
133                            d->groups.num_principals));
134
135                 d->subreq = NULL;
136
137                 if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(result)) {
138                         DEBUG(10, ("list_groups for domain %s failed\n",
139                                    d->domain->name));
140                         d->groups.num_principals = 0;
141                 }
142         }
143
144         TALLOC_FREE(subreq);
145
146         state->num_received += 1;
147
148         if (state->num_received >= state->num_domains) {
149                 tevent_req_done(req);
150         }
151 }
152
153 NTSTATUS winbindd_list_groups_recv(struct tevent_req *req,
154                                    struct winbindd_response *response)
155 {
156         struct winbindd_list_groups_state *state = tevent_req_data(
157                 req, struct winbindd_list_groups_state);
158         NTSTATUS status;
159         char *result;
160         int i;
161         uint32_t j, num_entries = 0;
162         size_t len;
163
164         if (tevent_req_is_nterror(req, &status)) {
165                 return status;
166         }
167
168         len = 0;
169         response->data.num_entries = 0;
170         for (i=0; i<state->num_domains; i++) {
171                 struct winbindd_list_groups_domstate *d = &state->domains[i];
172
173                 for (j=0; j<d->groups.num_principals; j++) {
174                         fstring name;
175                         fill_domain_username(name, d->domain->name,
176                                              d->groups.principals[j].name,
177                                              True);
178                         len += strlen(name)+1;
179                 }
180                 response->data.num_entries += d->groups.num_principals;
181         }
182
183         result = talloc_array(response, char, len+1);
184         if (result == 0) {
185                 return NT_STATUS_NO_MEMORY;
186         }
187
188         len = 0;
189         for (i=0; i<state->num_domains; i++) {
190                 struct winbindd_list_groups_domstate *d = &state->domains[i];
191
192                 for (j=0; j<d->groups.num_principals; j++) {
193                         fstring name;
194                         size_t this_len;
195                         fill_domain_username(name, d->domain->name,
196                                              d->groups.principals[j].name,
197                                              True);
198                         this_len = strlen(name);
199                         memcpy(result+len, name, this_len);
200                         len += this_len;
201                         result[len] = ',';
202                         len += 1;
203                         num_entries++;
204                 }
205         }
206         result[len-1] = '\0';
207
208         response->data.num_entries = num_entries;
209         response->extra_data.data = result;
210         response->length += len;
211
212         return NT_STATUS_OK;
213 }