Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async implementation of WINBINDD_LIST_USERS
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 : #include "lib/util/strv.h"
24 :
25 : struct winbindd_list_users_domstate {
26 : struct tevent_req *subreq;
27 : struct winbindd_domain *domain;
28 : char *users;
29 : };
30 :
31 : struct winbindd_list_users_state {
32 : size_t num_received;
33 : /* All domains */
34 : size_t num_domains;
35 : struct winbindd_list_users_domstate *domains;
36 : };
37 :
38 : static void winbindd_list_users_done(struct tevent_req *subreq);
39 :
40 13 : struct tevent_req *winbindd_list_users_send(TALLOC_CTX *mem_ctx,
41 : struct tevent_context *ev,
42 : struct winbindd_cli_state *cli,
43 : struct winbindd_request *request)
44 : {
45 : struct tevent_req *req;
46 : struct winbindd_list_users_state *state;
47 : struct winbindd_domain *domain;
48 : size_t i;
49 :
50 13 : req = tevent_req_create(mem_ctx, &state,
51 : struct winbindd_list_users_state);
52 13 : if (req == NULL) {
53 0 : return NULL;
54 : }
55 13 : D_NOTICE("[%s (%u)] Winbind external command LIST_USERS start.\n"
56 : "WBFLAG_FROM_NSS is %s, winbind enum users is %d.\n",
57 : cli->client_name,
58 : (unsigned int)cli->pid,
59 : request->wb_flags & WBFLAG_FROM_NSS ? "Set" : "Unset",
60 : lp_winbind_enum_users());
61 :
62 13 : if (request->wb_flags & WBFLAG_FROM_NSS && !lp_winbind_enum_users()) {
63 0 : tevent_req_done(req);
64 0 : return tevent_req_post(req, ev);
65 : }
66 :
67 : /* Ensure null termination */
68 13 : request->domain_name[sizeof(request->domain_name)-1]='\0';
69 :
70 13 : D_NOTICE("Listing users for domain %s\n", request->domain_name);
71 13 : if (request->domain_name[0] != '\0') {
72 9 : state->num_domains = 1;
73 : } else {
74 4 : state->num_domains = 0;
75 24 : for (domain = domain_list(); domain; domain = domain->next) {
76 20 : state->num_domains += 1;
77 : }
78 : }
79 :
80 13 : state->domains = talloc_array(state,
81 : struct winbindd_list_users_domstate,
82 : state->num_domains);
83 13 : if (tevent_req_nomem(state->domains, req)) {
84 0 : return tevent_req_post(req, ev);
85 : }
86 :
87 13 : if (request->domain_name[0] != '\0') {
88 11 : state->domains[0].domain = find_domain_from_name_noinit(
89 9 : request->domain_name);
90 9 : if (state->domains[0].domain == NULL) {
91 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_DOMAIN);
92 0 : return tevent_req_post(req, ev);
93 : }
94 : } else {
95 4 : i = 0;
96 24 : for (domain = domain_list(); domain; domain = domain->next) {
97 20 : state->domains[i++].domain = domain;
98 : }
99 : }
100 :
101 42 : for (i=0; i<state->num_domains; i++) {
102 29 : struct winbindd_list_users_domstate *d = &state->domains[i];
103 :
104 58 : d->subreq = wb_query_user_list_send(
105 29 : state->domains, ev, d->domain);
106 29 : if (tevent_req_nomem(d->subreq, req)) {
107 0 : TALLOC_FREE(state->domains);
108 0 : return tevent_req_post(req, ev);
109 : }
110 29 : tevent_req_set_callback(d->subreq, winbindd_list_users_done,
111 : req);
112 : }
113 13 : state->num_received = 0;
114 13 : return req;
115 : }
116 :
117 29 : static void winbindd_list_users_done(struct tevent_req *subreq)
118 : {
119 29 : struct tevent_req *req = tevent_req_callback_data(
120 : subreq, struct tevent_req);
121 29 : struct winbindd_list_users_state *state = tevent_req_data(
122 : req, struct winbindd_list_users_state);
123 : struct winbindd_list_users_domstate *d;
124 : NTSTATUS status;
125 : size_t i;
126 :
127 69 : for (i=0; i<state->num_domains; i++) {
128 69 : if (subreq == state->domains[i].subreq) {
129 29 : break;
130 : }
131 : }
132 29 : if (i == state->num_domains) {
133 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
134 0 : return;
135 : }
136 :
137 29 : d = &state->domains[i];
138 :
139 29 : status = wb_query_user_list_recv(subreq, state->domains,
140 : &d->users);
141 29 : TALLOC_FREE(subreq);
142 29 : if (!NT_STATUS_IS_OK(status)) {
143 : /*
144 : * Just skip this domain
145 : */
146 0 : d->users = NULL;
147 : }
148 :
149 29 : state->num_received += 1;
150 :
151 29 : if (state->num_received >= state->num_domains) {
152 13 : tevent_req_done(req);
153 : }
154 : }
155 :
156 13 : NTSTATUS winbindd_list_users_recv(struct tevent_req *req,
157 : struct winbindd_response *response)
158 : {
159 13 : struct winbindd_list_users_state *state = tevent_req_data(
160 : req, struct winbindd_list_users_state);
161 : NTSTATUS status;
162 : char *result;
163 : size_t i, len;
164 :
165 13 : D_NOTICE("Winbind external command LIST_USERS end.\n");
166 13 : if (tevent_req_is_nterror(req, &status)) {
167 0 : D_WARNING("Failed with %s.\n", nt_errstr(status));
168 0 : return status;
169 : }
170 :
171 13 : result = NULL;
172 :
173 42 : for (i=0; i<state->num_domains; i++) {
174 29 : struct winbindd_list_users_domstate *d = &state->domains[i];
175 : int ret;
176 :
177 29 : if (d->users == NULL) {
178 12 : continue;
179 : }
180 :
181 17 : ret = strv_append(state, &result, d->users);
182 17 : if (ret != 0) {
183 0 : return map_nt_error_from_unix(ret);
184 : }
185 : }
186 :
187 13 : len = talloc_get_size(result);
188 :
189 13 : response->extra_data.data = talloc_steal(response, result);
190 13 : response->length += len;
191 13 : response->data.num_entries = 0;
192 :
193 13 : if (result != NULL && len >= 1) {
194 13 : len -= 1;
195 13 : response->data.num_entries = 1;
196 :
197 4402 : for (i=0; i<len; i++) {
198 4389 : if (result[i] == '\0') {
199 203 : result[i] = ',';
200 203 : response->data.num_entries += 1;
201 : }
202 : }
203 : }
204 :
205 13 : D_NOTICE("Got %"PRIu32" user(s):\n%s\n",
206 : response->data.num_entries,
207 : result);
208 :
209 13 : return NT_STATUS_OK;
210 : }
|