Line data Source code
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 "util/debug.h"
22 : #include "winbindd.h"
23 : #include "librpc/gen_ndr/ndr_winbind_c.h"
24 :
25 : struct winbindd_list_groups_domstate {
26 : struct tevent_req *subreq;
27 : struct winbindd_domain *domain;
28 : struct wbint_Principals groups;
29 : };
30 :
31 : struct winbindd_list_groups_state {
32 : uint32_t num_received;
33 : /* All domains */
34 : uint32_t num_domains;
35 : struct winbindd_list_groups_domstate *domains;
36 : };
37 :
38 : static void winbindd_list_groups_done(struct tevent_req *subreq);
39 :
40 18 : struct tevent_req *winbindd_list_groups_send(TALLOC_CTX *mem_ctx,
41 : struct tevent_context *ev,
42 : struct winbindd_cli_state *cli,
43 : struct winbindd_request *request)
44 : {
45 0 : struct tevent_req *req;
46 0 : struct winbindd_list_groups_state *state;
47 0 : struct winbindd_domain *domain;
48 0 : uint32_t i;
49 :
50 18 : req = tevent_req_create(mem_ctx, &state,
51 : struct winbindd_list_groups_state);
52 18 : if (req == NULL) {
53 0 : return NULL;
54 : }
55 :
56 18 : D_NOTICE("[%s (%u)] Winbind external command LIST_GROUPS start.\n"
57 : "WBFLAG_FROM_NSS is %s, winbind enum groups is %d.\n",
58 : cli->client_name,
59 : (unsigned int)cli->pid,
60 : request->wb_flags & WBFLAG_FROM_NSS ? "Set" : "Unset",
61 : lp_winbind_enum_groups());
62 :
63 18 : if (request->wb_flags & WBFLAG_FROM_NSS && !lp_winbind_enum_groups()) {
64 0 : tevent_req_done(req);
65 0 : return tevent_req_post(req, ev);
66 : }
67 :
68 : /* Ensure null termination */
69 18 : request->domain_name[sizeof(request->domain_name)-1]='\0';
70 :
71 18 : if (request->domain_name[0] != '\0') {
72 10 : state->num_domains = 1;
73 10 : D_DEBUG("List groups for domain %s.\n", request->domain_name);
74 : } else {
75 8 : state->num_domains = 0;
76 40 : for (domain = domain_list(); domain; domain = domain->next) {
77 32 : state->num_domains += 1;
78 : }
79 8 : D_DEBUG("List groups for %"PRIu32" domain(s).\n", state->num_domains);
80 : }
81 :
82 18 : state->domains = talloc_array(state,
83 : struct winbindd_list_groups_domstate,
84 : state->num_domains);
85 18 : if (tevent_req_nomem(state->domains, req)) {
86 0 : return tevent_req_post(req, ev);
87 : }
88 :
89 18 : if (request->domain_name[0] != '\0') {
90 10 : ZERO_STRUCT(state->domains[0].groups);
91 :
92 20 : state->domains[0].domain = find_domain_from_name_noinit(
93 10 : request->domain_name);
94 10 : if (state->domains[0].domain == NULL) {
95 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
96 0 : return tevent_req_post(req, ev);
97 : }
98 : } else {
99 8 : i = 0;
100 40 : for (domain = domain_list(); domain; domain = domain->next) {
101 32 : ZERO_STRUCT(state->domains[i].groups);
102 :
103 32 : state->domains[i].domain = domain;
104 32 : i++;
105 : }
106 : }
107 :
108 60 : for (i=0; i<state->num_domains; i++) {
109 42 : struct winbindd_list_groups_domstate *d = &state->domains[i];
110 :
111 42 : d->subreq = dcerpc_wbint_QueryGroupList_send(
112 42 : state->domains, ev, dom_child_handle(d->domain),
113 : &d->groups);
114 42 : if (tevent_req_nomem(d->subreq, req)) {
115 0 : TALLOC_FREE(state->domains);
116 0 : return tevent_req_post(req, ev);
117 : }
118 42 : tevent_req_set_callback(d->subreq, winbindd_list_groups_done,
119 : req);
120 : }
121 18 : state->num_received = 0;
122 18 : return req;
123 : }
124 :
125 42 : static void winbindd_list_groups_done(struct tevent_req *subreq)
126 : {
127 42 : struct tevent_req *req = tevent_req_callback_data(
128 : subreq, struct tevent_req);
129 42 : struct winbindd_list_groups_state *state = tevent_req_data(
130 : req, struct winbindd_list_groups_state);
131 0 : NTSTATUS status, result;
132 0 : uint32_t i;
133 :
134 42 : status = dcerpc_wbint_QueryGroupList_recv(subreq, state->domains,
135 : &result);
136 :
137 94 : for (i=0; i<state->num_domains; i++) {
138 94 : if (subreq == state->domains[i].subreq) {
139 42 : break;
140 : }
141 : }
142 42 : if (i < state->num_domains) {
143 42 : struct winbindd_list_groups_domstate *d = &state->domains[i];
144 :
145 42 : D_DEBUG("Domain %s returned %"PRIu32" groups\n", d->domain->name,
146 : d->groups.num_principals);
147 :
148 42 : d->subreq = NULL;
149 :
150 42 : if (!NT_STATUS_IS_OK(status) || !NT_STATUS_IS_OK(result)) {
151 8 : D_WARNING("list_groups for domain %s failed\n",
152 : d->domain->name);
153 8 : d->groups.num_principals = 0;
154 : }
155 : }
156 :
157 42 : TALLOC_FREE(subreq);
158 :
159 42 : state->num_received += 1;
160 :
161 42 : if (state->num_received >= state->num_domains) {
162 18 : tevent_req_done(req);
163 : }
164 42 : }
165 :
166 18 : NTSTATUS winbindd_list_groups_recv(struct tevent_req *req,
167 : struct winbindd_response *response)
168 : {
169 18 : struct winbindd_list_groups_state *state = tevent_req_data(
170 : req, struct winbindd_list_groups_state);
171 0 : NTSTATUS status;
172 0 : char *result;
173 18 : uint32_t i, j, num_entries = 0;
174 0 : size_t len;
175 :
176 18 : D_NOTICE("Winbind external command LIST_GROUPS end.\n");
177 18 : if (tevent_req_is_nterror(req, &status)) {
178 0 : D_WARNING("Failed with %s.\n", nt_errstr(status));
179 0 : return status;
180 : }
181 :
182 18 : len = 0;
183 18 : response->data.num_entries = 0;
184 60 : for (i=0; i<state->num_domains; i++) {
185 42 : struct winbindd_list_groups_domstate *d = &state->domains[i];
186 :
187 1730 : for (j=0; j<d->groups.num_principals; j++) {
188 0 : const char *name;
189 1688 : name = fill_domain_username_talloc(response, d->domain->name,
190 1688 : d->groups.principals[j].name,
191 : True);
192 1688 : if (name == NULL) {
193 0 : return NT_STATUS_NO_MEMORY;
194 : }
195 1688 : len += strlen(name)+1;
196 : }
197 42 : response->data.num_entries += d->groups.num_principals;
198 : }
199 :
200 18 : result = talloc_array(response, char, len+1);
201 18 : if (result == 0) {
202 0 : return NT_STATUS_NO_MEMORY;
203 : }
204 :
205 18 : len = 0;
206 60 : for (i=0; i<state->num_domains; i++) {
207 42 : struct winbindd_list_groups_domstate *d = &state->domains[i];
208 :
209 1730 : for (j=0; j<d->groups.num_principals; j++) {
210 0 : const char *name;
211 0 : size_t this_len;
212 1688 : name = fill_domain_username_talloc(response, d->domain->name,
213 1688 : d->groups.principals[j].name,
214 : True);
215 1688 : if (name == NULL) {
216 0 : return NT_STATUS_NO_MEMORY;
217 : }
218 1688 : this_len = strlen(name);
219 1688 : memcpy(result+len, name, this_len);
220 1688 : len += this_len;
221 1688 : result[len] = ',';
222 1688 : len += 1;
223 1688 : num_entries++;
224 : }
225 : }
226 18 : result[len-1] = '\0';
227 :
228 18 : response->data.num_entries = num_entries;
229 18 : response->extra_data.data = result;
230 18 : response->length += len;
231 :
232 18 : return NT_STATUS_OK;
233 : }
|