2 * Unix SMB/CIFS implementation.
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/>.
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
;
33 struct dom_sid
*all_sids
;
34 const struct wb_parent_idmap_config_dom
*dom_map
;
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
,
53 struct tevent_req
*req
, *subreq
;
54 struct wb_xids2sids_dom_state
*state
;
55 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
58 req
= tevent_req_create(mem_ctx
, &state
,
59 struct wb_xids2sids_dom_state
);
64 D_DEBUG("Searching for %zu xid(s) in domain %s.\n",
69 state
->all_xids
= xids
;
70 state
->cached
= cached
;
71 state
->num_all_xids
= num_xids
;
72 state
->all_sids
= sids
;
73 state
->dom_map
= dom_map
;
75 state
->dom_xids
= talloc_array(state
, struct unixid
, num_xids
);
76 if (tevent_req_nomem(state
->dom_xids
, req
)) {
77 return tevent_req_post(req
, ev
);
79 state
->dom_sids
= talloc_array(state
, struct dom_sid
, num_xids
);
80 if (tevent_req_nomem(state
->dom_sids
, req
)) {
81 return tevent_req_post(req
, ev
);
84 for (i
=0; i
<num_xids
; i
++) {
85 struct unixid id
= state
->all_xids
[i
];
87 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
89 D_DEBUG("%zu: XID %"PRIu32
" is out of range.\n",
93 if (state
->cached
[i
]) {
94 /* already found in cache */
95 D_DEBUG("%zu: XID %"PRIu32
" is already found in cache.\n",
99 if (!is_null_sid(&state
->all_sids
[i
])) {
100 /* already mapped in a previously asked domain */
101 D_DEBUG("%zu: XID %"PRIu32
" is already mapped in a previously asked domain.\n",
105 D_DEBUG("%zu: XID %"PRIu32
" will be looked up via dcerpc_wbint_UnixIDs2Sids_send().\n",
107 state
->dom_xids
[state
->num_dom_xids
++] = id
;
110 if (state
->num_dom_xids
== 0) {
111 tevent_req_done(req
);
112 return tevent_req_post(req
, ev
);
115 child_binding_handle
= idmap_child_handle();
116 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
117 state
, ev
, child_binding_handle
, dom_map
->name
, dom_map
->sid
,
118 state
->num_dom_xids
, state
->dom_xids
, state
->dom_sids
);
119 if (tevent_req_nomem(subreq
, req
)) {
120 return tevent_req_post(req
, ev
);
122 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
126 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
)
128 struct tevent_req
*req
= tevent_req_callback_data(
129 subreq
, struct tevent_req
);
130 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
131 req
, struct wb_xids2sids_dom_state
);
132 const struct wb_parent_idmap_config_dom
*dom_map
= state
->dom_map
;
133 NTSTATUS status
, result
;
137 status
= dcerpc_wbint_UnixIDs2Sids_recv(subreq
, state
, &result
);
139 if (tevent_req_nterror(req
, status
)) {
143 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
144 !state
->tried_dclookup
) {
146 subreq
= wb_dsgetdcname_send(
147 state
, state
->ev
, state
->dom_map
->name
, NULL
, NULL
,
149 if (tevent_req_nomem(subreq
, req
)) {
152 tevent_req_set_callback(subreq
, wb_xids2sids_dom_gotdc
, req
);
156 if (!NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
) &&
157 tevent_req_nterror(req
, result
)) {
163 D_DEBUG("Processing response for %zu xid(s).\n", state
->num_all_xids
);
164 for (i
=0; i
<state
->num_all_xids
; i
++) {
165 struct unixid
*id
= &state
->all_xids
[i
];
166 struct dom_sid_buf buf
;
168 if ((id
->id
< dom_map
->low_id
) || (id
->id
> dom_map
->high_id
)) {
172 if (state
->cached
[i
]) {
173 /* already found in cache */
176 if (!is_null_sid(&state
->all_sids
[i
])) {
177 /* already mapped in a previously asked domain */
181 sid_copy(&state
->all_sids
[i
], &state
->dom_sids
[dom_sid_idx
]);
182 *id
= state
->dom_xids
[dom_sid_idx
];
183 D_DEBUG("%zu: XID %"PRIu32
" mapped to SID %s.\n",
186 dom_sid_str_buf(&state
->all_sids
[i
], &buf
));
191 tevent_req_done(req
);
194 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
)
196 struct tevent_req
*req
= tevent_req_callback_data(
197 subreq
, struct tevent_req
);
198 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
199 req
, struct wb_xids2sids_dom_state
);
200 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
201 struct netr_DsRGetDCNameInfo
*dcinfo
;
204 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
206 if (tevent_req_nterror(req
, status
)) {
210 state
->tried_dclookup
= true;
212 status
= wb_dsgetdcname_gencache_set(state
->dom_map
->name
, dcinfo
);
213 if (tevent_req_nterror(req
, status
)) {
217 child_binding_handle
= idmap_child_handle();
218 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
219 state
, state
->ev
, child_binding_handle
, state
->dom_map
->name
,
220 state
->dom_map
->sid
, state
->num_dom_xids
,
221 state
->dom_xids
, state
->dom_sids
);
222 if (tevent_req_nomem(subreq
, req
)) {
225 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
228 static NTSTATUS
wb_xids2sids_dom_recv(struct tevent_req
*req
)
230 return tevent_req_simple_recv_ntstatus(req
);
233 struct wb_xids2sids_state
{
234 struct tevent_context
*ev
;
237 struct dom_sid
*sids
;
241 const struct wb_parent_idmap_config
*cfg
;
244 static void wb_xids2sids_idmap_setup_done(struct tevent_req
*subreq
);
245 static void wb_xids2sids_done(struct tevent_req
*subreq
);
247 struct tevent_req
*wb_xids2sids_send(TALLOC_CTX
*mem_ctx
,
248 struct tevent_context
*ev
,
249 const struct unixid
*xids
,
252 struct tevent_req
*req
, *subreq
;
253 struct wb_xids2sids_state
*state
;
255 req
= tevent_req_create(mem_ctx
, &state
,
256 struct wb_xids2sids_state
);
261 D_INFO("WB command xids2sids start.\nLooking up %"PRIu32
" XID(s).\n",
265 state
->num_xids
= num_xids
;
267 state
->xids
= talloc_array(state
, struct unixid
, num_xids
);
268 if (tevent_req_nomem(state
->xids
, req
)) {
269 return tevent_req_post(req
, ev
);
271 memcpy(state
->xids
, xids
, num_xids
* sizeof(struct unixid
));
273 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_xids
);
274 if (tevent_req_nomem(state
->sids
, req
)) {
275 return tevent_req_post(req
, ev
);
278 state
->cached
= talloc_zero_array(state
, bool, num_xids
);
279 if (tevent_req_nomem(state
->cached
, req
)) {
280 return tevent_req_post(req
, ev
);
283 if (winbindd_use_idmap_cache()) {
286 for (i
=0; i
<num_xids
; i
++) {
287 struct dom_sid sid
= {0};
288 bool ok
, expired
= true;
290 ok
= idmap_cache_find_xid2sid(
291 &xids
[i
], &sid
, &expired
);
292 if (ok
&& !expired
) {
293 struct dom_sid_buf buf
;
294 DBG_DEBUG("Found %cID in cache: %s\n",
295 xids
[i
].type
== ID_TYPE_UID
?'U':'G',
296 dom_sid_str_buf(&sid
, &buf
));
298 sid_copy(&state
->sids
[i
], &sid
);
299 state
->cached
[i
] = true;
304 subreq
= wb_parent_idmap_setup_send(state
, state
->ev
);
305 if (tevent_req_nomem(subreq
, req
)) {
306 return tevent_req_post(req
, ev
);
308 tevent_req_set_callback(subreq
, wb_xids2sids_idmap_setup_done
, req
);
312 static void wb_xids2sids_idmap_setup_done(struct tevent_req
*subreq
)
314 struct tevent_req
*req
= tevent_req_callback_data(
315 subreq
, struct tevent_req
);
316 struct wb_xids2sids_state
*state
= tevent_req_data(
317 req
, struct wb_xids2sids_state
);
320 status
= wb_parent_idmap_setup_recv(subreq
, &state
->cfg
);
322 if (tevent_req_nterror(req
, status
)) {
325 SMB_ASSERT(state
->cfg
->num_doms
> 0);
327 subreq
= wb_xids2sids_dom_send(
329 &state
->cfg
->doms
[state
->dom_idx
],
330 state
->xids
, state
->cached
, state
->num_xids
, state
->sids
);
331 if (tevent_req_nomem(subreq
, req
)) {
334 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
338 static void wb_xids2sids_done(struct tevent_req
*subreq
)
340 struct tevent_req
*req
= tevent_req_callback_data(
341 subreq
, struct tevent_req
);
342 struct wb_xids2sids_state
*state
= tevent_req_data(
343 req
, struct wb_xids2sids_state
);
347 status
= wb_xids2sids_dom_recv(subreq
);
349 if (tevent_req_nterror(req
, status
)) {
354 if (state
->dom_idx
< state
->cfg
->num_doms
) {
355 const struct wb_parent_idmap_config_dom
*dom_map
=
356 &state
->cfg
->doms
[state
->dom_idx
];
358 subreq
= wb_xids2sids_dom_send(state
,
365 if (tevent_req_nomem(subreq
, req
)) {
368 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
373 for (i
= 0; i
< state
->num_xids
; i
++) {
375 * Prime the cache after an xid2sid call. It's important that we
376 * use the xid value returned from the backend for the xid value
377 * passed to idmap_cache_set_sid2unixid(), not the input to
378 * wb_xids2sids_send: the input carries what was asked for,
379 * e.g. a ID_TYPE_UID. The result from the backend something the
380 * idmap child possibly changed to ID_TYPE_BOTH.
382 * And of course If the value was from the cache don't update
386 if (state
->cached
[i
]) {
390 idmap_cache_set_sid2unixid(&state
->sids
[i
], &state
->xids
[i
]);
393 tevent_req_done(req
);
397 NTSTATUS
wb_xids2sids_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
398 struct dom_sid
**sids
)
400 struct wb_xids2sids_state
*state
= tevent_req_data(
401 req
, struct wb_xids2sids_state
);
405 D_INFO("WB command xids2sids end.\n");
406 if (tevent_req_is_nterror(req
, &status
)) {
407 D_WARNING("wb_sids_to_xids failed: %s\n", nt_errstr(status
));
411 *sids
= talloc_move(mem_ctx
, &state
->sids
);
412 if (CHECK_DEBUGLVL(DBGLVL_INFO
)) {
413 for (i
= 0; i
< state
->num_xids
; i
++) {
414 struct dom_sid_buf buf
;
415 D_INFO("%zu: XID %"PRIu32
" mapped to SID %s\n",
418 dom_sid_str_buf(&((*sids
)[i
]), &buf
));