2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2009
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/>.
21 #include "util/debug.h"
23 #include "librpc/gen_ndr/ndr_winbind_c.h"
24 #include "../libcli/security/security.h"
25 #include "libsmb/samlogon_cache.h"
26 #include "librpc/gen_ndr/ndr_winbind.h"
28 struct wb_queryuser_state
{
29 struct tevent_context
*ev
;
30 struct wbint_userinfo
*info
;
31 const struct wb_parent_idmap_config
*idmap_cfg
;
35 static void wb_queryuser_idmap_setup_done(struct tevent_req
*subreq
);
36 static void wb_queryuser_got_uid(struct tevent_req
*subreq
);
37 static void wb_queryuser_got_domain(struct tevent_req
*subreq
);
38 static void wb_queryuser_got_dc(struct tevent_req
*subreq
);
39 static void wb_queryuser_got_gid(struct tevent_req
*subreq
);
40 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
);
41 static void wb_queryuser_done(struct tevent_req
*subreq
);
43 struct tevent_req
*wb_queryuser_send(TALLOC_CTX
*mem_ctx
,
44 struct tevent_context
*ev
,
45 const struct dom_sid
*user_sid
)
47 struct tevent_req
*req
, *subreq
;
48 struct wb_queryuser_state
*state
;
49 struct wbint_userinfo
*info
;
50 struct dom_sid_buf buf
;
52 req
= tevent_req_create(mem_ctx
, &state
, struct wb_queryuser_state
);
56 D_INFO("WB command queryuser start.\nQuery user sid %s\n",
57 dom_sid_str_buf(user_sid
, &buf
));
60 state
->info
= talloc_zero(state
, struct wbint_userinfo
);
61 if (tevent_req_nomem(state
->info
, req
)) {
62 return tevent_req_post(req
, ev
);
66 info
->primary_gid
= (gid_t
)-1;
68 sid_copy(&info
->user_sid
, user_sid
);
70 subreq
= wb_parent_idmap_setup_send(state
, state
->ev
);
71 if (tevent_req_nomem(subreq
, req
)) {
72 return tevent_req_post(req
, ev
);
74 tevent_req_set_callback(subreq
, wb_queryuser_idmap_setup_done
, req
);
78 static void wb_queryuser_idmap_setup_done(struct tevent_req
*subreq
)
80 struct tevent_req
*req
= tevent_req_callback_data(
81 subreq
, struct tevent_req
);
82 struct wb_queryuser_state
*state
= tevent_req_data(
83 req
, struct wb_queryuser_state
);
85 struct dom_sid_buf buf
;
87 status
= wb_parent_idmap_setup_recv(subreq
, &state
->idmap_cfg
);
89 if (tevent_req_nterror(req
, status
)) {
90 D_WARNING("wb_parent_idmap_setup_recv() failed with %s.\n",
95 D_DEBUG("Convert the user SID %s to XID.\n",
96 dom_sid_str_buf(&state
->info
->user_sid
, &buf
));
97 subreq
= wb_sids2xids_send(
98 state
, state
->ev
, &state
->info
->user_sid
, 1);
99 if (tevent_req_nomem(subreq
, req
)) {
102 tevent_req_set_callback(subreq
, wb_queryuser_got_uid
, req
);
106 static void wb_queryuser_got_uid(struct tevent_req
*subreq
)
108 struct tevent_req
*req
= tevent_req_callback_data(
109 subreq
, struct tevent_req
);
110 struct wb_queryuser_state
*state
= tevent_req_data(
111 req
, struct wb_queryuser_state
);
112 struct wbint_userinfo
*info
= state
->info
;
113 struct netr_SamInfo3
*info3
;
114 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
117 struct dom_sid_buf buf
, buf1
;
119 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
121 if (tevent_req_nterror(req
, status
)) {
122 D_WARNING("wb_sids2xids_recv() failed with %s.\n",
127 if ((xid
.type
!= ID_TYPE_UID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
128 D_WARNING("XID type is %d, should be ID_TYPE_UID or ID_TYPE_BOTH.\n",
130 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
134 D_DEBUG("Received XID %"PRIu32
" for SID %s.\n",
136 dom_sid_str_buf(&info
->user_sid
, &buf1
));
140 * Default the group sid to "Domain Users" in the user's
141 * domain. The samlogon cache or the query_user call later on
144 sid_copy(&info
->group_sid
, &info
->user_sid
);
145 sid_split_rid(&info
->group_sid
, NULL
);
146 sid_append_rid(&info
->group_sid
, DOMAIN_RID_USERS
);
148 D_DEBUG("Preconfigured 'Domain Users' RID %u was used to create group SID %s from user SID %s.\n",
150 dom_sid_str_buf(&info
->group_sid
, &buf
),
151 dom_sid_str_buf(&info
->user_sid
, &buf1
));
153 info
->homedir
= talloc_strdup(info
, lp_template_homedir());
154 D_DEBUG("Setting 'homedir' to the template '%s'.\n", info
->homedir
);
155 if (tevent_req_nomem(info
->homedir
, req
)) {
159 info
->shell
= talloc_strdup(info
, lp_template_shell());
160 D_DEBUG("Setting 'shell' to the template '%s'.\n", info
->shell
);
161 if (tevent_req_nomem(info
->shell
, req
)) {
165 info3
= netsamlogon_cache_get(state
, &info
->user_sid
);
167 D_DEBUG("Filling data received from netsamlogon_cache\n");
168 sid_compose(&info
->group_sid
, info3
->base
.domain_sid
,
169 info3
->base
.primary_gid
);
170 info
->acct_name
= talloc_move(
171 info
, &info3
->base
.account_name
.string
);
172 info
->full_name
= talloc_move(
173 info
, &info3
->base
.full_name
.string
);
175 info
->domain_name
= talloc_move(
176 state
, &info3
->base
.logon_domain
.string
);
181 NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG
, wbint_userinfo
, state
->info
);
182 if (info
->domain_name
== NULL
) {
183 D_DEBUG("Domain name is empty, calling wb_lookupsid_send() to get it.\n");
184 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->user_sid
);
185 if (tevent_req_nomem(subreq
, req
)) {
188 tevent_req_set_callback(subreq
, wb_queryuser_got_domain
, req
);
193 * Note wb_sids2xids_send/recv was called before,
194 * so we're sure that wb_parent_idmap_setup_send/recv
195 * was already called.
197 child_binding_handle
= idmap_child_handle();
198 D_DEBUG("Domain name is set, calling dcerpc_wbint_GetNssInfo_send()\n");
199 subreq
= dcerpc_wbint_GetNssInfo_send(
200 state
, state
->ev
, child_binding_handle
, info
);
201 if (tevent_req_nomem(subreq
, req
)) {
204 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
207 static void wb_queryuser_got_domain(struct tevent_req
*subreq
)
209 struct tevent_req
*req
= tevent_req_callback_data(
210 subreq
, struct tevent_req
);
211 struct wb_queryuser_state
*state
= tevent_req_data(
212 req
, struct wb_queryuser_state
);
213 struct wbint_userinfo
*info
= state
->info
;
214 enum lsa_SidType type
;
215 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
218 status
= wb_lookupsid_recv(subreq
, state
, &type
,
219 &info
->domain_name
, &info
->acct_name
);
221 if (tevent_req_nterror(req
, status
)) {
222 D_WARNING("wb_lookupsid_recv failed with %s.\n",
227 NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG
, wbint_userinfo
, state
->info
);
230 case SID_NAME_COMPUTER
:
232 * user case: we only need the account name from lookup_sids
235 case SID_NAME_DOM_GRP
:
237 case SID_NAME_WKN_GRP
:
239 * also treat group-type SIDs (they might map to ID_TYPE_BOTH)
241 sid_copy(&info
->group_sid
, &info
->user_sid
);
244 D_WARNING("Unknown type:%d, return NT_STATUS_NO_SUCH_USER.\n",
246 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
251 * Note wb_sids2xids_send/recv was called before,
252 * so we're sure that wb_parent_idmap_setup_send/recv
253 * was already called.
255 child_binding_handle
= idmap_child_handle();
256 D_DEBUG("About to call dcerpc_wbint_GetNssInfo_send()\n");
257 subreq
= dcerpc_wbint_GetNssInfo_send(
258 state
, state
->ev
, child_binding_handle
, info
);
259 if (tevent_req_nomem(subreq
, req
)) {
262 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
265 static void wb_queryuser_done(struct tevent_req
*subreq
)
267 struct tevent_req
*req
= tevent_req_callback_data(
268 subreq
, struct tevent_req
);
269 struct wb_queryuser_state
*state
= tevent_req_data(
270 req
, struct wb_queryuser_state
);
271 struct wbint_userinfo
*info
= state
->info
;
272 NTSTATUS status
, result
;
273 bool need_group_name
= false;
274 const char *tmpl
= NULL
;
276 status
= dcerpc_wbint_GetNssInfo_recv(subreq
, info
, &result
);
278 if (tevent_req_nterror(req
, status
)) {
279 D_WARNING("GetNssInfo failed with %s.\n", nt_errstr(status
));
283 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
284 !state
->tried_dclookup
) {
285 D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling wb_dsgetdcname_send()\n");
286 subreq
= wb_dsgetdcname_send(
287 state
, state
->ev
, state
->info
->domain_name
, NULL
, NULL
,
289 if (tevent_req_nomem(subreq
, req
)) {
292 tevent_req_set_callback(subreq
, wb_queryuser_got_dc
, req
);
297 * Ignore failure in "result" here. We'll try to fill in stuff
298 * that misses further down.
301 if (state
->info
->primary_gid
== (gid_t
)-1) {
302 D_DEBUG("Calling wb_sids2xids_send() to resolve primary gid.\n");
303 subreq
= wb_sids2xids_send(
304 state
, state
->ev
, &info
->group_sid
, 1);
305 if (tevent_req_nomem(subreq
, req
)) {
308 tevent_req_set_callback(subreq
, wb_queryuser_got_gid
, req
);
312 tmpl
= lp_template_homedir();
313 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
314 need_group_name
= true;
316 tmpl
= lp_template_shell();
317 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
318 need_group_name
= true;
321 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
322 D_DEBUG("Calling wb_lookupsid_send() to resolve primary group name.\n");
323 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->group_sid
);
324 if (tevent_req_nomem(subreq
, req
)) {
327 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
332 NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG
, wbint_userinfo
, state
->info
);
333 tevent_req_done(req
);
336 static void wb_queryuser_got_dc(struct tevent_req
*subreq
)
338 struct tevent_req
*req
= tevent_req_callback_data(
339 subreq
, struct tevent_req
);
340 struct wb_queryuser_state
*state
= tevent_req_data(
341 req
, struct wb_queryuser_state
);
342 struct wbint_userinfo
*info
= state
->info
;
343 struct netr_DsRGetDCNameInfo
*dcinfo
;
344 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
347 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
349 if (tevent_req_nterror(req
, status
)) {
350 D_WARNING("wb_dsgetdcname_recv() failed with %s.\n",
355 state
->tried_dclookup
= true;
357 D_DEBUG("Got DC name, calling wb_dsgetdcname_gencache_set().\n");
358 status
= wb_dsgetdcname_gencache_set(info
->domain_name
, dcinfo
);
359 if (tevent_req_nterror(req
, status
)) {
360 D_WARNING("wb_dsgetdcname_gencache_set() failed with %s.\n",
364 NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG
, wbint_userinfo
, state
->info
);
367 * Note wb_sids2xids_send/recv was called before,
368 * so we're sure that wb_parent_idmap_setup_send/recv
369 * was already called.
371 child_binding_handle
= idmap_child_handle();
372 subreq
= dcerpc_wbint_GetNssInfo_send(
373 state
, state
->ev
, child_binding_handle
, info
);
374 if (tevent_req_nomem(subreq
, req
)) {
377 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
380 static void wb_queryuser_got_gid(struct tevent_req
*subreq
)
382 struct tevent_req
*req
= tevent_req_callback_data(
383 subreq
, struct tevent_req
);
384 struct wb_queryuser_state
*state
= tevent_req_data(
385 req
, struct wb_queryuser_state
);
388 bool need_group_name
= false;
389 const char *tmpl
= NULL
;
390 struct dom_sid_buf buf
;
392 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
394 if (tevent_req_nterror(req
, status
)) {
395 D_WARNING("wb_sids2xids_recv() failed with %s.\n",
400 D_DEBUG("Got XID %"PRIu32
" with type %d.\n", xid
.id
, xid
.type
);
401 if ((xid
.type
!= ID_TYPE_GID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
402 D_WARNING("Returning NT_STATUS_NO_SUCH_USER\n"
403 "xid.type must be ID_TYPE_UID or ID_TYPE_BOTH.\n");
404 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
408 state
->info
->primary_gid
= xid
.id
;
410 tmpl
= lp_template_homedir();
411 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
412 need_group_name
= true;
414 tmpl
= lp_template_shell();
415 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
416 need_group_name
= true;
419 NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG
, wbint_userinfo
, state
->info
);
421 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
422 D_DEBUG("Calling wb_lookupsid_send for group SID %s.\n",
423 dom_sid_str_buf(&state
->info
->group_sid
, &buf
));
424 subreq
= wb_lookupsid_send(state
, state
->ev
,
425 &state
->info
->group_sid
);
426 if (tevent_req_nomem(subreq
, req
)) {
429 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
434 D_DEBUG("No need to lookup primary group name. Request is done!\n");
435 tevent_req_done(req
);
438 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
)
440 struct tevent_req
*req
= tevent_req_callback_data(
441 subreq
, struct tevent_req
);
442 struct wb_queryuser_state
*state
= tevent_req_data(
443 req
, struct wb_queryuser_state
);
444 enum lsa_SidType type
;
446 const char *domain_name
;
448 status
= wb_lookupsid_recv(subreq
, state
->info
, &type
, &domain_name
,
449 &state
->info
->primary_group_name
);
451 if (tevent_req_nterror(req
, status
)) {
452 D_WARNING("wb_lookupsid_recv() failed with %s.\n",
456 tevent_req_done(req
);
459 NTSTATUS
wb_queryuser_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
460 struct wbint_userinfo
**pinfo
)
462 struct wb_queryuser_state
*state
= tevent_req_data(
463 req
, struct wb_queryuser_state
);
466 D_INFO("WB command queryuser end.\n");
467 NDR_PRINT_DEBUG_LEVEL(DBGLVL_INFO
, wbint_userinfo
, state
->info
);
468 if (tevent_req_is_nterror(req
, &status
)) {
471 *pinfo
= talloc_move(mem_ctx
, &state
->info
);