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/>.
22 #include "librpc/gen_ndr/ndr_winbind_c.h"
23 #include "../libcli/security/security.h"
24 #include "libsmb/samlogon_cache.h"
26 struct wb_queryuser_state
{
27 struct tevent_context
*ev
;
28 struct wbint_userinfo
*info
;
32 static void wb_queryuser_got_uid(struct tevent_req
*subreq
);
33 static void wb_queryuser_got_domain(struct tevent_req
*subreq
);
34 static void wb_queryuser_got_dc(struct tevent_req
*subreq
);
35 static void wb_queryuser_got_gid(struct tevent_req
*subreq
);
36 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
);
37 static void wb_queryuser_done(struct tevent_req
*subreq
);
39 struct tevent_req
*wb_queryuser_send(TALLOC_CTX
*mem_ctx
,
40 struct tevent_context
*ev
,
41 const struct dom_sid
*user_sid
)
43 struct tevent_req
*req
, *subreq
;
44 struct wb_queryuser_state
*state
;
45 struct wbint_userinfo
*info
;
47 req
= tevent_req_create(mem_ctx
, &state
, struct wb_queryuser_state
);
53 if (lp_winbind_trusted_domains_only()) {
54 struct winbindd_domain
*our_domain
= find_our_domain();
56 if (dom_sid_compare_domain(user_sid
, &our_domain
->sid
) == 0) {
57 char buf
[DOM_SID_STR_BUFLEN
];
58 dom_sid_string_buf(user_sid
, buf
, sizeof(buf
));
59 DBG_NOTICE("My domain -- rejecting %s\n", buf
);
60 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
61 return tevent_req_post(req
, ev
);
65 state
->info
= talloc_zero(state
, struct wbint_userinfo
);
66 if (tevent_req_nomem(state
->info
, req
)) {
67 return tevent_req_post(req
, ev
);
71 info
->primary_gid
= (gid_t
)-1;
73 sid_copy(&info
->user_sid
, user_sid
);
75 subreq
= wb_sids2xids_send(
76 state
, state
->ev
, &state
->info
->user_sid
, 1);
77 if (tevent_req_nomem(subreq
, req
)) {
78 return tevent_req_post(req
, ev
);
80 tevent_req_set_callback(subreq
, wb_queryuser_got_uid
, req
);
84 static void wb_queryuser_got_uid(struct tevent_req
*subreq
)
86 struct tevent_req
*req
= tevent_req_callback_data(
87 subreq
, struct tevent_req
);
88 struct wb_queryuser_state
*state
= tevent_req_data(
89 req
, struct wb_queryuser_state
);
90 struct wbint_userinfo
*info
= state
->info
;
91 struct netr_SamInfo3
*info3
;
92 struct winbindd_child
*child
;
96 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
98 if (tevent_req_nterror(req
, status
)) {
102 if ((xid
.type
!= ID_TYPE_UID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
103 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
110 * Default the group sid to "Domain Users" in the user's
111 * domain. The samlogon cache or the query_user call later on
114 sid_copy(&info
->group_sid
, &info
->user_sid
);
115 sid_split_rid(&info
->group_sid
, NULL
);
116 sid_append_rid(&info
->group_sid
, DOMAIN_RID_USERS
);
118 info
->homedir
= talloc_strdup(info
, lp_template_homedir());
119 if (tevent_req_nomem(info
->homedir
, req
)) {
123 info
->shell
= talloc_strdup(info
, lp_template_shell());
124 if (tevent_req_nomem(info
->shell
, req
)) {
128 info3
= netsamlogon_cache_get(state
, &info
->user_sid
);
131 sid_compose(&info
->group_sid
, info3
->base
.domain_sid
,
132 info3
->base
.primary_gid
);
133 info
->acct_name
= talloc_move(
134 info
, &info3
->base
.account_name
.string
);
135 info
->full_name
= talloc_move(
136 info
, &info3
->base
.full_name
.string
);
138 info
->domain_name
= talloc_move(
139 state
, &info3
->base
.logon_domain
.string
);
144 if (info
->domain_name
== NULL
) {
145 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->user_sid
);
146 if (tevent_req_nomem(subreq
, req
)) {
149 tevent_req_set_callback(subreq
, wb_queryuser_got_domain
, req
);
153 child
= idmap_child();
155 subreq
= dcerpc_wbint_GetNssInfo_send(
156 state
, state
->ev
, child
->binding_handle
, info
);
157 if (tevent_req_nomem(subreq
, req
)) {
160 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
163 static void wb_queryuser_got_domain(struct tevent_req
*subreq
)
165 struct tevent_req
*req
= tevent_req_callback_data(
166 subreq
, struct tevent_req
);
167 struct wb_queryuser_state
*state
= tevent_req_data(
168 req
, struct wb_queryuser_state
);
169 struct wbint_userinfo
*info
= state
->info
;
170 enum lsa_SidType type
;
171 struct winbindd_child
*child
;
174 status
= wb_lookupsid_recv(subreq
, state
, &type
,
175 &info
->domain_name
, &info
->acct_name
);
177 if (tevent_req_nterror(req
, status
)) {
181 if (type
!= SID_NAME_USER
) {
182 /* allow SID_NAME_COMPUTER? */
183 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
187 child
= idmap_child();
189 subreq
= dcerpc_wbint_GetNssInfo_send(
190 state
, state
->ev
, child
->binding_handle
, info
);
191 if (tevent_req_nomem(subreq
, req
)) {
194 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
197 static void wb_queryuser_done(struct tevent_req
*subreq
)
199 struct tevent_req
*req
= tevent_req_callback_data(
200 subreq
, struct tevent_req
);
201 struct wb_queryuser_state
*state
= tevent_req_data(
202 req
, struct wb_queryuser_state
);
203 struct wbint_userinfo
*info
= state
->info
;
204 NTSTATUS status
, result
;
205 bool need_group_name
= false;
206 const char *tmpl
= NULL
;
208 status
= dcerpc_wbint_GetNssInfo_recv(subreq
, info
, &result
);
210 if (tevent_req_nterror(req
, status
)) {
214 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
215 !state
->tried_dclookup
) {
216 subreq
= wb_dsgetdcname_send(
217 state
, state
->ev
, state
->info
->domain_name
, NULL
, NULL
,
219 if (tevent_req_nomem(subreq
, req
)) {
222 tevent_req_set_callback(subreq
, wb_queryuser_got_dc
, req
);
227 * Ignore failure in "result" here. We'll try to fill in stuff
228 * that misses further down.
231 if (state
->info
->primary_gid
== (gid_t
)-1) {
232 subreq
= wb_sids2xids_send(
233 state
, state
->ev
, &info
->group_sid
, 1);
234 if (tevent_req_nomem(subreq
, req
)) {
237 tevent_req_set_callback(subreq
, wb_queryuser_got_gid
, req
);
241 tmpl
= lp_template_homedir();
242 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
243 need_group_name
= true;
245 tmpl
= lp_template_shell();
246 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
247 need_group_name
= true;
250 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
251 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->group_sid
);
252 if (tevent_req_nomem(subreq
, req
)) {
255 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
260 tevent_req_done(req
);
263 static void wb_queryuser_got_dc(struct tevent_req
*subreq
)
265 struct tevent_req
*req
= tevent_req_callback_data(
266 subreq
, struct tevent_req
);
267 struct wb_queryuser_state
*state
= tevent_req_data(
268 req
, struct wb_queryuser_state
);
269 struct wbint_userinfo
*info
= state
->info
;
270 struct netr_DsRGetDCNameInfo
*dcinfo
;
271 struct winbindd_child
*child
;
274 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
276 if (tevent_req_nterror(req
, status
)) {
280 state
->tried_dclookup
= true;
282 status
= wb_dsgetdcname_gencache_set(info
->domain_name
, dcinfo
);
283 if (tevent_req_nterror(req
, status
)) {
287 child
= idmap_child();
289 subreq
= dcerpc_wbint_GetNssInfo_send(
290 state
, state
->ev
, child
->binding_handle
, info
);
291 if (tevent_req_nomem(subreq
, req
)) {
294 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
297 static void wb_queryuser_got_gid(struct tevent_req
*subreq
)
299 struct tevent_req
*req
= tevent_req_callback_data(
300 subreq
, struct tevent_req
);
301 struct wb_queryuser_state
*state
= tevent_req_data(
302 req
, struct wb_queryuser_state
);
305 bool need_group_name
= false;
306 const char *tmpl
= NULL
;
308 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
310 if (tevent_req_nterror(req
, status
)) {
314 if ((xid
.type
!= ID_TYPE_GID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
315 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
319 state
->info
->primary_gid
= xid
.id
;
321 tmpl
= lp_template_homedir();
322 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
323 need_group_name
= true;
325 tmpl
= lp_template_shell();
326 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
327 need_group_name
= true;
330 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
331 subreq
= wb_lookupsid_send(state
, state
->ev
,
332 &state
->info
->group_sid
);
333 if (tevent_req_nomem(subreq
, req
)) {
336 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
341 tevent_req_done(req
);
344 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
)
346 struct tevent_req
*req
= tevent_req_callback_data(
347 subreq
, struct tevent_req
);
348 struct wb_queryuser_state
*state
= tevent_req_data(
349 req
, struct wb_queryuser_state
);
350 enum lsa_SidType type
;
352 const char *domain_name
;
354 status
= wb_lookupsid_recv(subreq
, state
->info
, &type
, &domain_name
,
355 &state
->info
->primary_group_name
);
357 if (tevent_req_nterror(req
, status
)) {
360 tevent_req_done(req
);
363 NTSTATUS
wb_queryuser_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
364 struct wbint_userinfo
**pinfo
)
366 struct wb_queryuser_state
*state
= tevent_req_data(
367 req
, struct wb_queryuser_state
);
370 if (tevent_req_is_nterror(req
, &status
)) {
373 *pinfo
= talloc_move(mem_ctx
, &state
->info
);