samba-tool group: Add --special parameter to add predefined special group
[Samba.git] / source3 / winbindd / wb_xids2sids.c
blobc68939b2bcd3833ebf3ace18aa68ae831e6a772e
1 /*
2 * Unix SMB/CIFS implementation.
3 * async xids2sids
4 * Copyright (C) Volker Lendecke 2015
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.
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.
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/>.
20 #include "includes.h"
21 #include "winbindd.h"
22 #include "../libcli/security/security.h"
23 #include "idmap_cache.h"
24 #include "librpc/gen_ndr/ndr_winbind_c.h"
25 #include "librpc/gen_ndr/ndr_netlogon.h"
26 #include "passdb/lookup_sid.h"
28 struct wb_xids2sids_dom_state {
29 struct tevent_context *ev;
30 struct unixid *all_xids;
31 const bool *cached;
32 size_t num_all_xids;
33 struct dom_sid *all_sids;
34 const struct wb_parent_idmap_config_dom *dom_map;
35 bool tried_dclookup;
37 size_t num_dom_xids;
38 struct unixid *dom_xids;
39 struct dom_sid *dom_sids;
42 static void wb_xids2sids_dom_done(struct tevent_req *subreq);
43 static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq);
45 static struct tevent_req *wb_xids2sids_dom_send(
46 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
47 const struct wb_parent_idmap_config_dom *dom_map,
48 struct unixid *xids,
49 const bool *cached,
50 size_t num_xids,
51 struct dom_sid *sids)
53 struct tevent_req *req, *subreq;
54 struct wb_xids2sids_dom_state *state;
55 struct dcerpc_binding_handle *child_binding_handle = NULL;
56 size_t i;
58 req = tevent_req_create(mem_ctx, &state,
59 struct wb_xids2sids_dom_state);
60 if (req == NULL) {
61 return NULL;
63 state->ev = ev;
64 state->all_xids = xids;
65 state->cached = cached;
66 state->num_all_xids = num_xids;
67 state->all_sids = sids;
68 state->dom_map = dom_map;
70 state->dom_xids = talloc_array(state, struct unixid, num_xids);
71 if (tevent_req_nomem(state->dom_xids, req)) {
72 return tevent_req_post(req, ev);
74 state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
75 if (tevent_req_nomem(state->dom_sids, req)) {
76 return tevent_req_post(req, ev);
79 for (i=0; i<num_xids; i++) {
80 struct unixid id = state->all_xids[i];
82 if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
83 /* out of range */
84 continue;
86 if (state->cached[i]) {
87 /* already found in cache */
88 continue;
90 if (!is_null_sid(&state->all_sids[i])) {
91 /* already mapped in a previously asked domain */
92 continue;
94 state->dom_xids[state->num_dom_xids++] = id;
97 if (state->num_dom_xids == 0) {
98 tevent_req_done(req);
99 return tevent_req_post(req, ev);
102 child_binding_handle = idmap_child_handle();
103 subreq = dcerpc_wbint_UnixIDs2Sids_send(
104 state, ev, child_binding_handle, dom_map->name, dom_map->sid,
105 state->num_dom_xids, state->dom_xids, state->dom_sids);
106 if (tevent_req_nomem(subreq, req)) {
107 return tevent_req_post(req, ev);
109 tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
110 return req;
113 static void wb_xids2sids_dom_done(struct tevent_req *subreq)
115 struct tevent_req *req = tevent_req_callback_data(
116 subreq, struct tevent_req);
117 struct wb_xids2sids_dom_state *state = tevent_req_data(
118 req, struct wb_xids2sids_dom_state);
119 const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
120 NTSTATUS status, result;
121 size_t i;
122 size_t dom_sid_idx;
124 status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
125 TALLOC_FREE(subreq);
126 if (tevent_req_nterror(req, status)) {
127 return;
130 if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
131 !state->tried_dclookup) {
133 subreq = wb_dsgetdcname_send(
134 state, state->ev, state->dom_map->name, NULL, NULL,
135 DS_RETURN_DNS_NAME);
136 if (tevent_req_nomem(subreq, req)) {
137 return;
139 tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
140 return;
143 if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
144 tevent_req_nterror(req, result)) {
145 return;
148 dom_sid_idx = 0;
150 for (i=0; i<state->num_all_xids; i++) {
151 struct unixid *id = &state->all_xids[i];
153 if ((id->id < dom_map->low_id) || (id->id > dom_map->high_id)) {
154 /* out of range */
155 continue;
157 if (state->cached[i]) {
158 /* already found in cache */
159 continue;
161 if (!is_null_sid(&state->all_sids[i])) {
162 /* already mapped in a previously asked domain */
163 continue;
166 sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
167 *id = state->dom_xids[dom_sid_idx];
169 dom_sid_idx += 1;
172 tevent_req_done(req);
175 static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
177 struct tevent_req *req = tevent_req_callback_data(
178 subreq, struct tevent_req);
179 struct wb_xids2sids_dom_state *state = tevent_req_data(
180 req, struct wb_xids2sids_dom_state);
181 struct dcerpc_binding_handle *child_binding_handle = NULL;
182 struct netr_DsRGetDCNameInfo *dcinfo;
183 NTSTATUS status;
185 status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
186 TALLOC_FREE(subreq);
187 if (tevent_req_nterror(req, status)) {
188 return;
191 state->tried_dclookup = true;
193 status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
194 if (tevent_req_nterror(req, status)) {
195 return;
198 child_binding_handle = idmap_child_handle();
199 subreq = dcerpc_wbint_UnixIDs2Sids_send(
200 state, state->ev, child_binding_handle, state->dom_map->name,
201 state->dom_map->sid, state->num_dom_xids,
202 state->dom_xids, state->dom_sids);
203 if (tevent_req_nomem(subreq, req)) {
204 return;
206 tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
209 static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
211 return tevent_req_simple_recv_ntstatus(req);
214 struct wb_xids2sids_state {
215 struct tevent_context *ev;
216 struct unixid *xids;
217 size_t num_xids;
218 struct dom_sid *sids;
219 bool *cached;
221 size_t dom_idx;
222 const struct wb_parent_idmap_config *cfg;
225 static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
226 static void wb_xids2sids_done(struct tevent_req *subreq);
228 struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
229 struct tevent_context *ev,
230 const struct unixid *xids,
231 uint32_t num_xids)
233 struct tevent_req *req, *subreq;
234 struct wb_xids2sids_state *state;
236 req = tevent_req_create(mem_ctx, &state,
237 struct wb_xids2sids_state);
238 if (req == NULL) {
239 return NULL;
241 state->ev = ev;
242 state->num_xids = num_xids;
244 state->xids = talloc_array(state, struct unixid, num_xids);
245 if (tevent_req_nomem(state->xids, req)) {
246 return tevent_req_post(req, ev);
248 memcpy(state->xids, xids, num_xids * sizeof(struct unixid));
250 state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
251 if (tevent_req_nomem(state->sids, req)) {
252 return tevent_req_post(req, ev);
255 state->cached = talloc_zero_array(state, bool, num_xids);
256 if (tevent_req_nomem(state->cached, req)) {
257 return tevent_req_post(req, ev);
260 if (winbindd_use_idmap_cache()) {
261 uint32_t i;
263 for (i=0; i<num_xids; i++) {
264 struct dom_sid sid = {0};
265 bool ok, expired = true;
267 ok = idmap_cache_find_xid2sid(
268 &xids[i], &sid, &expired);
269 if (ok && !expired) {
270 struct dom_sid_buf buf;
271 DBG_DEBUG("Found %cID in cache: %s\n",
272 xids[i].type == ID_TYPE_UID?'U':'G',
273 dom_sid_str_buf(&sid, &buf));
275 sid_copy(&state->sids[i], &sid);
276 state->cached[i] = true;
281 subreq = wb_parent_idmap_setup_send(state, state->ev);
282 if (tevent_req_nomem(subreq, req)) {
283 return tevent_req_post(req, ev);
285 tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
286 return req;
289 static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
291 struct tevent_req *req = tevent_req_callback_data(
292 subreq, struct tevent_req);
293 struct wb_xids2sids_state *state = tevent_req_data(
294 req, struct wb_xids2sids_state);
295 NTSTATUS status;
297 status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
298 TALLOC_FREE(subreq);
299 if (tevent_req_nterror(req, status)) {
300 return;
302 SMB_ASSERT(state->cfg->num_doms > 0);
304 subreq = wb_xids2sids_dom_send(
305 state, state->ev,
306 &state->cfg->doms[state->dom_idx],
307 state->xids, state->cached, state->num_xids, state->sids);
308 if (tevent_req_nomem(subreq, req)) {
309 return;
311 tevent_req_set_callback(subreq, wb_xids2sids_done, req);
312 return;
315 static void wb_xids2sids_done(struct tevent_req *subreq)
317 struct tevent_req *req = tevent_req_callback_data(
318 subreq, struct tevent_req);
319 struct wb_xids2sids_state *state = tevent_req_data(
320 req, struct wb_xids2sids_state);
321 size_t i;
322 NTSTATUS status;
324 status = wb_xids2sids_dom_recv(subreq);
325 TALLOC_FREE(subreq);
326 if (tevent_req_nterror(req, status)) {
327 return;
330 state->dom_idx += 1;
332 if (state->dom_idx < state->cfg->num_doms) {
333 const struct wb_parent_idmap_config_dom *dom_map =
334 &state->cfg->doms[state->dom_idx];
336 subreq = wb_xids2sids_dom_send(state,
337 state->ev,
338 dom_map,
339 state->xids,
340 state->cached,
341 state->num_xids,
342 state->sids);
343 if (tevent_req_nomem(subreq, req)) {
344 return;
346 tevent_req_set_callback(subreq, wb_xids2sids_done, req);
347 return;
351 for (i = 0; i < state->num_xids; i++) {
353 * Prime the cache after an xid2sid call. It's important that we
354 * use the xid value returned from the backend for the xid value
355 * passed to idmap_cache_set_sid2unixid(), not the input to
356 * wb_xids2sids_send: the input carries what was asked for,
357 * e.g. a ID_TYPE_UID. The result from the backend something the
358 * idmap child possibly changed to ID_TYPE_BOTH.
360 * And of course If the value was from the cache don't update
361 * the cache.
364 if (state->cached[i]) {
365 continue;
368 idmap_cache_set_sid2unixid(&state->sids[i], &state->xids[i]);
371 tevent_req_done(req);
372 return;
375 NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
376 struct dom_sid **sids)
378 struct wb_xids2sids_state *state = tevent_req_data(
379 req, struct wb_xids2sids_state);
380 NTSTATUS status;
382 if (tevent_req_is_nterror(req, &status)) {
383 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status)));
384 return status;
387 *sids = talloc_move(mem_ctx, &state->sids);
388 return NT_STATUS_OK;