Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async getgrsid
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 "../libcli/security/security.h"
24 : #include "lib/dbwrap/dbwrap_rbt.h"
25 : #include "lib/dbwrap/dbwrap.h"
26 :
27 : struct wb_getgrsid_state {
28 : struct tevent_context *ev;
29 : struct dom_sid sid;
30 : int max_nesting;
31 : const char *domname;
32 : const char *name;
33 : enum lsa_SidType type;
34 : gid_t gid;
35 : struct db_context *members;
36 : uint32_t num_sids;
37 : struct dom_sid *sids;
38 : };
39 :
40 : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq);
41 : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq);
42 : static void wb_getgrsid_got_members(struct tevent_req *subreq);
43 : static void wb_getgrsid_got_alias_members(struct tevent_req *subreq);
44 :
45 5720 : struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
46 : struct tevent_context *ev,
47 : const struct dom_sid *group_sid,
48 : int max_nesting)
49 : {
50 0 : struct tevent_req *req, *subreq;
51 0 : struct wb_getgrsid_state *state;
52 0 : struct dom_sid_buf buf;
53 :
54 5720 : req = tevent_req_create(mem_ctx, &state, struct wb_getgrsid_state);
55 5720 : if (req == NULL) {
56 0 : return NULL;
57 : }
58 :
59 5720 : D_INFO("WB command getgrsid start.\nLooking up group SID %s.\n", dom_sid_str_buf(group_sid, &buf));
60 :
61 5720 : sid_copy(&state->sid, group_sid);
62 5720 : state->ev = ev;
63 5720 : state->max_nesting = max_nesting;
64 :
65 5720 : if (dom_sid_in_domain(&global_sid_Unix_Groups, group_sid)) {
66 : /* unmapped Unix groups must be resolved locally */
67 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
68 0 : return tevent_req_post(req, ev);
69 : }
70 :
71 5720 : subreq = wb_lookupsid_send(state, ev, &state->sid);
72 5720 : if (tevent_req_nomem(subreq, req)) {
73 0 : return tevent_req_post(req, ev);
74 : }
75 5720 : tevent_req_set_callback(subreq, wb_getgrsid_lookupsid_done, req);
76 5720 : return req;
77 : }
78 :
79 5720 : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq)
80 : {
81 5720 : struct tevent_req *req = tevent_req_callback_data(
82 : subreq, struct tevent_req);
83 5720 : struct wb_getgrsid_state *state = tevent_req_data(
84 : req, struct wb_getgrsid_state);
85 0 : NTSTATUS status;
86 :
87 5720 : status = wb_lookupsid_recv(subreq, state, &state->type,
88 : &state->domname, &state->name);
89 5720 : TALLOC_FREE(subreq);
90 5720 : if (tevent_req_nterror(req, status)) {
91 0 : return;
92 : }
93 :
94 5720 : switch (state->type) {
95 5720 : case SID_NAME_DOM_GRP:
96 : case SID_NAME_ALIAS:
97 : case SID_NAME_WKN_GRP:
98 : /*
99 : * also treat user-type SIDS (they might map to ID_TYPE_BOTH)
100 : */
101 : case SID_NAME_USER:
102 : case SID_NAME_COMPUTER:
103 5720 : break;
104 0 : default:
105 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
106 0 : return;
107 : }
108 :
109 5720 : subreq = wb_sids2xids_send(state, state->ev, &state->sid, 1);
110 5720 : if (tevent_req_nomem(subreq, req)) {
111 0 : return;
112 : }
113 5720 : tevent_req_set_callback(subreq, wb_getgrsid_sid2gid_done, req);
114 : }
115 :
116 5720 : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
117 : {
118 5720 : struct tevent_req *req = tevent_req_callback_data(
119 : subreq, struct tevent_req);
120 5720 : struct wb_getgrsid_state *state = tevent_req_data(
121 : req, struct wb_getgrsid_state);
122 0 : NTSTATUS status;
123 0 : struct unixid xids[1];
124 :
125 5720 : status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
126 5720 : TALLOC_FREE(subreq);
127 5720 : if (tevent_req_nterror(req, status)) {
128 78 : return;
129 : }
130 :
131 : /*
132 : * We are filtering further down in sids2xids, but that filtering
133 : * depends on the actual type of the sid handed in (as determined
134 : * by lookupsids). Here we need to filter for the type of object
135 : * actually requested, in this case uid.
136 : */
137 5720 : if (!(xids[0].type == ID_TYPE_GID || xids[0].type == ID_TYPE_BOTH)) {
138 0 : tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
139 0 : return;
140 : }
141 :
142 5720 : state->gid = (gid_t)xids[0].id;
143 :
144 5720 : switch (state->type) {
145 8 : case SID_NAME_USER:
146 : case SID_NAME_COMPUTER: {
147 : /*
148 : * special treatment for a user sid that is
149 : * mapped to ID_TYPE_BOTH:
150 : * create a group with the sid/xid as only member
151 : */
152 0 : const char *name;
153 :
154 8 : if (xids[0].type != ID_TYPE_BOTH) {
155 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
156 0 : return;
157 : }
158 :
159 8 : state->members = db_open_rbt(state);
160 8 : if (tevent_req_nomem(state->members, req)) {
161 0 : return;
162 : }
163 :
164 8 : name = fill_domain_username_talloc(talloc_tos(),
165 : state->domname,
166 : state->name,
167 : true /* can_assume */);
168 8 : if (tevent_req_nomem(name, req)) {
169 0 : return;
170 : }
171 :
172 8 : status = add_member_to_db(state->members, &state->sid, name);
173 8 : if (!NT_STATUS_IS_OK(status)) {
174 0 : tevent_req_nterror(req, status);
175 0 : return;
176 : }
177 :
178 8 : tevent_req_done(req);
179 8 : return;
180 : }
181 640 : case SID_NAME_ALIAS:
182 640 : subreq = wb_alias_members_send(state,
183 : state->ev,
184 640 : &state->sid,
185 : state->type,
186 : state->max_nesting);
187 640 : if (tevent_req_nomem(subreq, req)) {
188 0 : return;
189 : }
190 : /* Decrement the depth based on 'winbind expand groups' */
191 640 : state->max_nesting--;
192 640 : tevent_req_set_callback(subreq,
193 : wb_getgrsid_got_alias_members,
194 : req);
195 5642 : break;
196 5002 : case SID_NAME_DOM_GRP:
197 5002 : subreq = wb_group_members_send(state,
198 : state->ev,
199 5002 : &state->sid,
200 : 1,
201 : &state->type,
202 : state->max_nesting);
203 5002 : if (tevent_req_nomem(subreq, req)) {
204 0 : return;
205 : }
206 5002 : tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
207 5002 : break;
208 70 : case SID_NAME_WKN_GRP:
209 70 : state->members = db_open_rbt(state);
210 70 : if (tevent_req_nomem(state->members, req)) {
211 0 : return;
212 : }
213 70 : tevent_req_done(req);
214 70 : return;
215 0 : default:
216 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
217 0 : break;
218 : }
219 : }
220 :
221 640 : static void wb_getgrsid_got_alias_members_names(struct tevent_req *subreq)
222 : {
223 0 : struct tevent_req *req =
224 640 : tevent_req_callback_data(subreq, struct tevent_req);
225 0 : struct wb_getgrsid_state *state =
226 640 : tevent_req_data(req, struct wb_getgrsid_state);
227 640 : struct lsa_RefDomainList *domains = NULL;
228 640 : struct lsa_TransNameArray *names = NULL;
229 0 : NTSTATUS status;
230 0 : uint32_t li;
231 640 : uint32_t num_sids = 0;
232 640 : struct dom_sid *sids = NULL;
233 640 : enum lsa_SidType *types = NULL;
234 :
235 640 : status = wb_lookupsids_recv(subreq, state, &domains, &names);
236 :
237 640 : TALLOC_FREE(subreq);
238 640 : if (tevent_req_nterror(req, status)) {
239 0 : D_WARNING("Failed with %s.\n", nt_errstr(status));
240 638 : return;
241 : }
242 :
243 640 : if (domains == NULL) {
244 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
245 0 : D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
246 0 : return;
247 : }
248 :
249 640 : if (names == NULL) {
250 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
251 0 : D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
252 0 : return;
253 : }
254 :
255 640 : state->members = db_open_rbt(state);
256 640 : if (tevent_req_nomem(state->members, req)) {
257 0 : return;
258 : }
259 :
260 650 : for (li = 0; li < state->num_sids; li++) {
261 10 : struct lsa_TranslatedName *n = &names->names[li];
262 :
263 10 : if (n->sid_type == SID_NAME_USER ||
264 10 : n->sid_type == SID_NAME_COMPUTER) {
265 4 : const char *name = fill_domain_username_talloc(
266 : talloc_tos(),
267 4 : domains->domains[n->sid_index].name.string,
268 : n->name.string,
269 : false /* can_assume */);
270 4 : if (tevent_req_nomem(name, req)) {
271 0 : return;
272 : }
273 :
274 4 : status = add_member_to_db(state->members,
275 4 : &state->sids[li],
276 : name);
277 4 : if (!NT_STATUS_IS_OK(status)) {
278 0 : tevent_req_nterror(req, status);
279 0 : return;
280 : }
281 6 : } else if (n->sid_type == SID_NAME_DOM_GRP) {
282 6 : sids = talloc_realloc(talloc_tos(),
283 : sids,
284 : struct dom_sid,
285 : num_sids + 1);
286 6 : if (tevent_req_nomem(sids, req)) {
287 0 : return;
288 : }
289 6 : sids[num_sids] = state->sids[li];
290 6 : types = talloc_realloc(talloc_tos(),
291 : types,
292 : enum lsa_SidType,
293 : num_sids + 1);
294 6 : if (tevent_req_nomem(types, req)) {
295 0 : return;
296 : }
297 6 : types[num_sids] = n->sid_type;
298 6 : num_sids++;
299 : } else {
300 0 : struct dom_sid_buf buf;
301 0 : D_DEBUG("SID %s with sid_type=%d is ignored!\n",
302 : dom_sid_str_buf(&state->sids[li], &buf),
303 : n->sid_type);
304 : }
305 : }
306 :
307 640 : TALLOC_FREE(names);
308 640 : TALLOC_FREE(domains);
309 :
310 640 : if (num_sids == 0) {
311 638 : tevent_req_done(req);
312 638 : return;
313 : }
314 2 : subreq = wb_group_members_send(state,
315 : state->ev,
316 : sids,
317 : num_sids,
318 : types,
319 : state->max_nesting);
320 2 : if (tevent_req_nomem(subreq, req)) {
321 0 : return;
322 : }
323 2 : tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
324 : }
325 :
326 640 : static void wb_getgrsid_got_alias_members(struct tevent_req *subreq)
327 : {
328 0 : struct tevent_req *req =
329 640 : tevent_req_callback_data(subreq, struct tevent_req);
330 0 : struct wb_getgrsid_state *state =
331 640 : tevent_req_data(req, struct wb_getgrsid_state);
332 0 : NTSTATUS status;
333 :
334 640 : status = wb_alias_members_recv(subreq,
335 : state,
336 : &state->num_sids,
337 : &state->sids);
338 640 : TALLOC_FREE(subreq);
339 640 : if (tevent_req_nterror(req, status)) {
340 0 : return;
341 : }
342 :
343 640 : subreq = wb_lookupsids_send(state,
344 : state->ev,
345 : state->sids,
346 : state->num_sids);
347 640 : if (tevent_req_nomem(subreq, req)) {
348 0 : return;
349 : }
350 640 : tevent_req_set_callback(subreq,
351 : wb_getgrsid_got_alias_members_names,
352 : req);
353 : }
354 :
355 5004 : static void wb_getgrsid_got_members(struct tevent_req *subreq)
356 : {
357 5004 : struct tevent_req *req = tevent_req_callback_data(
358 : subreq, struct tevent_req);
359 5004 : struct wb_getgrsid_state *state = tevent_req_data(
360 : req, struct wb_getgrsid_state);
361 0 : NTSTATUS status;
362 5004 : struct db_context *members_prev = state->members;
363 :
364 5004 : status = wb_group_members_recv(subreq, state, &state->members);
365 5004 : TALLOC_FREE(subreq);
366 5004 : if (tevent_req_nterror(req, status)) {
367 0 : return;
368 : }
369 : /*
370 : * If we have called wb_alias_members_send(), members_prev
371 : * might already contain users that are direct members of alias,
372 : * add to them the users from nested groups.
373 : */
374 5004 : if (members_prev != NULL) {
375 2 : status = dbwrap_merge_dbs(state->members,
376 : members_prev,
377 : TDB_REPLACE);
378 2 : if (tevent_req_nterror(req, status)) {
379 0 : return;
380 : }
381 : }
382 5004 : tevent_req_done(req);
383 : }
384 :
385 5720 : NTSTATUS wb_getgrsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
386 : const char **domname, const char **name, gid_t *gid,
387 : struct db_context **members)
388 : {
389 5720 : struct wb_getgrsid_state *state = tevent_req_data(
390 : req, struct wb_getgrsid_state);
391 0 : NTSTATUS status;
392 :
393 5720 : D_INFO("WB command getgrsid end.\n");
394 5720 : if (tevent_req_is_nterror(req, &status)) {
395 0 : D_WARNING("Failed with %s.\n", nt_errstr(status));
396 0 : return status;
397 : }
398 5720 : *domname = talloc_move(mem_ctx, &state->domname);
399 5720 : *name = talloc_move(mem_ctx, &state->name);
400 5720 : *gid = state->gid;
401 5720 : *members = talloc_move(mem_ctx, &state->members);
402 5720 : return NT_STATUS_OK;
403 : }
|