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 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
)) {
86 if (state
->cached
[i
]) {
87 /* already found in cache */
90 if (!is_null_sid(&state
->all_sids
[i
])) {
91 /* already mapped in a previously asked domain */
94 state
->dom_xids
[state
->num_dom_xids
++] = id
;
97 if (state
->num_dom_xids
== 0) {
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
);
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
;
124 status
= dcerpc_wbint_UnixIDs2Sids_recv(subreq
, state
, &result
);
126 if (tevent_req_nterror(req
, status
)) {
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
,
136 if (tevent_req_nomem(subreq
, req
)) {
139 tevent_req_set_callback(subreq
, wb_xids2sids_dom_gotdc
, req
);
143 if (!NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
) &&
144 tevent_req_nterror(req
, result
)) {
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
)) {
157 if (state
->cached
[i
]) {
158 /* already found in cache */
161 if (!is_null_sid(&state
->all_sids
[i
])) {
162 /* already mapped in a previously asked domain */
166 sid_copy(&state
->all_sids
[i
], &state
->dom_sids
[dom_sid_idx
]);
167 *id
= state
->dom_xids
[dom_sid_idx
];
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
;
185 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
187 if (tevent_req_nterror(req
, status
)) {
191 state
->tried_dclookup
= true;
193 status
= wb_dsgetdcname_gencache_set(state
->dom_map
->name
, dcinfo
);
194 if (tevent_req_nterror(req
, status
)) {
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
)) {
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
;
218 struct dom_sid
*sids
;
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
,
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
);
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()) {
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
);
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
);
297 status
= wb_parent_idmap_setup_recv(subreq
, &state
->cfg
);
299 if (tevent_req_nterror(req
, status
)) {
302 SMB_ASSERT(state
->cfg
->num_doms
> 0);
304 subreq
= wb_xids2sids_dom_send(
306 &state
->cfg
->doms
[state
->dom_idx
],
307 state
->xids
, state
->cached
, state
->num_xids
, state
->sids
);
308 if (tevent_req_nomem(subreq
, req
)) {
311 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
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
);
324 status
= wb_xids2sids_dom_recv(subreq
);
326 if (tevent_req_nterror(req
, status
)) {
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
,
343 if (tevent_req_nomem(subreq
, req
)) {
346 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
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
364 if (state
->cached
[i
]) {
368 idmap_cache_set_sid2unixid(&state
->sids
[i
], &state
->xids
[i
]);
371 tevent_req_done(req
);
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
);
382 if (tevent_req_is_nterror(req
, &status
)) {
383 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
387 *sids
= talloc_move(mem_ctx
, &state
->sids
);