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 state
->info
= talloc_zero(state
, struct wbint_userinfo
);
54 if (tevent_req_nomem(state
->info
, req
)) {
55 return tevent_req_post(req
, ev
);
59 info
->primary_gid
= (gid_t
)-1;
61 sid_copy(&info
->user_sid
, user_sid
);
63 subreq
= wb_sids2xids_send(
64 state
, state
->ev
, &state
->info
->user_sid
, 1);
65 if (tevent_req_nomem(subreq
, req
)) {
66 return tevent_req_post(req
, ev
);
68 tevent_req_set_callback(subreq
, wb_queryuser_got_uid
, req
);
72 static void wb_queryuser_got_uid(struct tevent_req
*subreq
)
74 struct tevent_req
*req
= tevent_req_callback_data(
75 subreq
, struct tevent_req
);
76 struct wb_queryuser_state
*state
= tevent_req_data(
77 req
, struct wb_queryuser_state
);
78 struct wbint_userinfo
*info
= state
->info
;
79 struct netr_SamInfo3
*info3
;
80 struct winbindd_child
*child
;
84 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
86 if (tevent_req_nterror(req
, status
)) {
90 if ((xid
.type
!= ID_TYPE_UID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
91 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
98 * Default the group sid to "Domain Users" in the user's
99 * domain. The samlogon cache or the query_user call later on
102 sid_copy(&info
->group_sid
, &info
->user_sid
);
103 sid_split_rid(&info
->group_sid
, NULL
);
104 sid_append_rid(&info
->group_sid
, DOMAIN_RID_USERS
);
106 info
->homedir
= talloc_strdup(info
, lp_template_homedir());
107 if (tevent_req_nomem(info
->homedir
, req
)) {
111 info
->shell
= talloc_strdup(info
, lp_template_shell());
112 if (tevent_req_nomem(info
->shell
, req
)) {
116 info3
= netsamlogon_cache_get(state
, &info
->user_sid
);
119 sid_compose(&info
->group_sid
, info3
->base
.domain_sid
,
120 info3
->base
.primary_gid
);
121 info
->acct_name
= talloc_move(
122 info
, &info3
->base
.account_name
.string
);
123 info
->full_name
= talloc_move(
124 info
, &info3
->base
.full_name
.string
);
126 info
->domain_name
= talloc_move(
127 state
, &info3
->base
.logon_domain
.string
);
132 if (info
->domain_name
== NULL
) {
133 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->user_sid
);
134 if (tevent_req_nomem(subreq
, req
)) {
137 tevent_req_set_callback(subreq
, wb_queryuser_got_domain
, req
);
141 child
= idmap_child();
143 subreq
= dcerpc_wbint_GetNssInfo_send(
144 state
, state
->ev
, child
->binding_handle
, info
);
145 if (tevent_req_nomem(subreq
, req
)) {
148 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
151 static void wb_queryuser_got_domain(struct tevent_req
*subreq
)
153 struct tevent_req
*req
= tevent_req_callback_data(
154 subreq
, struct tevent_req
);
155 struct wb_queryuser_state
*state
= tevent_req_data(
156 req
, struct wb_queryuser_state
);
157 struct wbint_userinfo
*info
= state
->info
;
158 enum lsa_SidType type
;
159 struct winbindd_child
*child
;
162 status
= wb_lookupsid_recv(subreq
, state
, &type
,
163 &info
->domain_name
, &info
->acct_name
);
165 if (tevent_req_nterror(req
, status
)) {
169 if (type
!= SID_NAME_USER
) {
170 /* allow SID_NAME_COMPUTER? */
171 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
175 child
= idmap_child();
177 subreq
= dcerpc_wbint_GetNssInfo_send(
178 state
, state
->ev
, child
->binding_handle
, info
);
179 if (tevent_req_nomem(subreq
, req
)) {
182 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
185 static void wb_queryuser_done(struct tevent_req
*subreq
)
187 struct tevent_req
*req
= tevent_req_callback_data(
188 subreq
, struct tevent_req
);
189 struct wb_queryuser_state
*state
= tevent_req_data(
190 req
, struct wb_queryuser_state
);
191 struct wbint_userinfo
*info
= state
->info
;
192 NTSTATUS status
, result
;
193 bool need_group_name
= false;
194 const char *tmpl
= NULL
;
196 status
= dcerpc_wbint_GetNssInfo_recv(subreq
, info
, &result
);
198 if (tevent_req_nterror(req
, status
)) {
202 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
203 !state
->tried_dclookup
) {
204 subreq
= wb_dsgetdcname_send(
205 state
, state
->ev
, state
->info
->domain_name
, NULL
, NULL
,
207 if (tevent_req_nomem(subreq
, req
)) {
210 tevent_req_set_callback(subreq
, wb_queryuser_got_dc
, req
);
215 * Ignore failure in "result" here. We'll try to fill in stuff
216 * that misses further down.
219 if (state
->info
->primary_gid
== (gid_t
)-1) {
220 subreq
= wb_sids2xids_send(
221 state
, state
->ev
, &info
->group_sid
, 1);
222 if (tevent_req_nomem(subreq
, req
)) {
225 tevent_req_set_callback(subreq
, wb_queryuser_got_gid
, req
);
229 tmpl
= lp_template_homedir();
230 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
231 need_group_name
= true;
233 tmpl
= lp_template_shell();
234 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
235 need_group_name
= true;
238 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
239 subreq
= wb_lookupsid_send(state
, state
->ev
, &info
->group_sid
);
240 if (tevent_req_nomem(subreq
, req
)) {
243 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
248 tevent_req_done(req
);
251 static void wb_queryuser_got_dc(struct tevent_req
*subreq
)
253 struct tevent_req
*req
= tevent_req_callback_data(
254 subreq
, struct tevent_req
);
255 struct wb_queryuser_state
*state
= tevent_req_data(
256 req
, struct wb_queryuser_state
);
257 struct wbint_userinfo
*info
= state
->info
;
258 struct netr_DsRGetDCNameInfo
*dcinfo
;
259 struct winbindd_child
*child
;
262 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
264 if (tevent_req_nterror(req
, status
)) {
268 state
->tried_dclookup
= true;
270 status
= wb_dsgetdcname_gencache_set(info
->domain_name
, dcinfo
);
271 if (tevent_req_nterror(req
, status
)) {
275 child
= idmap_child();
277 subreq
= dcerpc_wbint_GetNssInfo_send(
278 state
, state
->ev
, child
->binding_handle
, info
);
279 if (tevent_req_nomem(subreq
, req
)) {
282 tevent_req_set_callback(subreq
, wb_queryuser_done
, req
);
285 static void wb_queryuser_got_gid(struct tevent_req
*subreq
)
287 struct tevent_req
*req
= tevent_req_callback_data(
288 subreq
, struct tevent_req
);
289 struct wb_queryuser_state
*state
= tevent_req_data(
290 req
, struct wb_queryuser_state
);
293 bool need_group_name
= false;
294 const char *tmpl
= NULL
;
296 status
= wb_sids2xids_recv(subreq
, &xid
, 1);
298 if (tevent_req_nterror(req
, status
)) {
302 if ((xid
.type
!= ID_TYPE_GID
) && (xid
.type
!= ID_TYPE_BOTH
)) {
303 tevent_req_nterror(req
, NT_STATUS_NO_SUCH_USER
);
307 state
->info
->primary_gid
= xid
.id
;
309 tmpl
= lp_template_homedir();
310 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
311 need_group_name
= true;
313 tmpl
= lp_template_shell();
314 if(strstr_m(tmpl
, "%g") || strstr_m(tmpl
, "%G")) {
315 need_group_name
= true;
318 if (need_group_name
&& state
->info
->primary_group_name
== NULL
) {
319 subreq
= wb_lookupsid_send(state
, state
->ev
,
320 &state
->info
->group_sid
);
321 if (tevent_req_nomem(subreq
, req
)) {
324 tevent_req_set_callback(subreq
, wb_queryuser_got_group_name
,
329 tevent_req_done(req
);
332 static void wb_queryuser_got_group_name(struct tevent_req
*subreq
)
334 struct tevent_req
*req
= tevent_req_callback_data(
335 subreq
, struct tevent_req
);
336 struct wb_queryuser_state
*state
= tevent_req_data(
337 req
, struct wb_queryuser_state
);
338 enum lsa_SidType type
;
340 const char *domain_name
;
342 status
= wb_lookupsid_recv(subreq
, state
->info
, &type
, &domain_name
,
343 &state
->info
->primary_group_name
);
345 if (tevent_req_nterror(req
, status
)) {
348 tevent_req_done(req
);
351 NTSTATUS
wb_queryuser_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
352 struct wbint_userinfo
**pinfo
)
354 struct wb_queryuser_state
*state
= tevent_req_data(
355 req
, struct wb_queryuser_state
);
358 if (tevent_req_is_nterror(req
, &status
)) {
361 *pinfo
= talloc_move(mem_ctx
, &state
->info
);