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
;
206 status
= dcerpc_wbint_GetNssInfo_recv(subreq
, info
, &result
);
208 if (tevent_req_nterror(req
, status
)) {
212 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
213 !state
->tried_dclookup
) {
214 subreq
= wb_dsgetdcname_send(
215 state
, state
->ev
, state
->info
->domain_name
, NULL
, NULL
,
217 if (tevent_req_nomem(subreq
, req
)) {
220 tevent_req_set_callback(subreq
, wb_queryuser_got_dc
, req
);
225 * Ignore failure in "result" here. We'll try to fill in stuff
226 * that misses further down.
229 if (state
->info
->primary_gid
== (gid_t
)-1) {
230 subreq
= wb_sids2xids_send(
231 state
, state
->ev
, &info
->group_sid
, 1);
232 if (tevent_req_nomem(subreq
, req
)) {
235 tevent_req_set_callback(subreq
, wb_queryuser_got_gid
, req
);
239 if (state
->info
->primary_group_name
== NULL
) {
240 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->group_sid
);
241 if (tevent_req_nomem(subreq
, req
)) {
244 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
249 tevent_req_done(req
);
252 static void wb_queryuser_got_dc(struct tevent_req
*subreq
)
254 struct tevent_req
*req
= tevent_req_callback_data(
255 subreq
, struct tevent_req
);
256 struct wb_queryuser_state
*state
= tevent_req_data(
257 req
, struct wb_queryuser_state
);
258 struct wbint_userinfo
*info
= state
->info
;
259 struct netr_DsRGetDCNameInfo
*dcinfo
;
260 struct winbindd_child
*child
;
263 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
265 if (tevent_req_nterror(req
, status
)) {
269 state
->tried_dclookup
= true;
271 status
= wb_dsgetdcname_gencache_set(info
->domain_name
, dcinfo
);
272 if (tevent_req_nterror(req
, status
)) {
276 child
= idmap_child();
278 subreq
= dcerpc_wbint_GetNssInfo_send(
279 state
, state
->ev
, child
->binding_handle
, info
);
280 if (tevent_req_nomem(subreq
, req
)) {
283 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
286 static void wb_queryuser_got_gid(struct tevent_req
*subreq
)
288 struct tevent_req
*req
= tevent_req_callback_data(
289 subreq
, struct tevent_req
);
290 struct wb_queryuser_state
*state
= tevent_req_data(
291 req
, struct wb_queryuser_state
);
295 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
297 if (tevent_req_nterror(req
, status
)) {
301 if ((xid
.type
!= ID_TYPE_GID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
302 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
306 state
->info
->primary_gid
= xid
.id
;
308 if (state
->info
->primary_group_name
== NULL
) {
309 subreq
= wb_lookupsid_send(state
, state
->ev
,
310 &state
->info
->group_sid
);
311 if (tevent_req_nomem(subreq
, req
)) {
314 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
319 tevent_req_done(req
);
322 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
)
324 struct tevent_req
*req
= tevent_req_callback_data(
325 subreq
, struct tevent_req
);
326 struct wb_queryuser_state
*state
= tevent_req_data(
327 req
, struct wb_queryuser_state
);
328 enum lsa_SidType type
;
330 const char *domain_name
;
332 status
= wb_lookupsid_recv(subreq
, state
->info
, &type
, &domain_name
,
333 &state
->info
->primary_group_name
);
335 if (tevent_req_nterror(req
, status
)) {
338 tevent_req_done(req
);
341 NTSTATUS
wb_queryuser_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
342 struct wbint_userinfo
**pinfo
)
344 struct wb_queryuser_state
*state
= tevent_req_data(
345 req
, struct wb_queryuser_state
);
348 if (tevent_req_is_nterror(req
, &status
)) {
351 *pinfo
= talloc_move(mem_ctx
, &state
->info
);