s3: VFS: Remove old traces of smb_vfs_call_llistxattr().
[Samba.git] / source3 / winbindd / wb_queryuser.c
blob69b4c8dad5aa4a65414a3f5cd47383d923df9c66
1 /*
2 Unix SMB/CIFS implementation.
3 async queryuser
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/>.
20 #include "includes.h"
21 #include "winbindd.h"
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;
29 bool tried_dclookup;
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);
48 if (req == NULL) {
49 return NULL;
51 state->ev = ev;
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);
69 info = state->info;
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);
81 return 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;
93 struct unixid xid;
94 NTSTATUS status;
96 status = wb_sids2xids_recv(subreq, &xid, 1);
97 TALLOC_FREE(subreq);
98 if (tevent_req_nterror(req, status)) {
99 return;
102 if ((xid.type != ID_TYPE_UID) && (xid.type != ID_TYPE_BOTH)) {
103 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
104 return;
107 info->uid = xid.id;
110 * Default the group sid to "Domain Users" in the user's
111 * domain. The samlogon cache or the query_user call later on
112 * can override this.
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)) {
120 return;
123 info->shell = talloc_strdup(info, lp_template_shell());
124 if (tevent_req_nomem(info->shell, req)) {
125 return;
128 info3 = netsamlogon_cache_get(state, &info->user_sid);
129 if (info3 != NULL) {
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);
141 TALLOC_FREE(info3);
144 if (info->domain_name == NULL) {
145 subreq = wb_lookupsid_send(state, state->ev, &info->user_sid);
146 if (tevent_req_nomem(subreq, req)) {
147 return;
149 tevent_req_set_callback(subreq, wb_queryuser_got_domain, req);
150 return;
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)) {
158 return;
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;
172 NTSTATUS status;
174 status = wb_lookupsid_recv(subreq, state, &type,
175 &info->domain_name, &info->acct_name);
176 TALLOC_FREE(subreq);
177 if (tevent_req_nterror(req, status)) {
178 return;
181 if (type != SID_NAME_USER) {
182 /* allow SID_NAME_COMPUTER? */
183 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
184 return;
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)) {
192 return;
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);
207 TALLOC_FREE(subreq);
208 if (tevent_req_nterror(req, status)) {
209 return;
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,
216 DS_RETURN_DNS_NAME);
217 if (tevent_req_nomem(subreq, req)) {
218 return;
220 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
221 return;
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)) {
233 return;
235 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
236 return;
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)) {
242 return;
244 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
245 req);
246 return;
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;
261 NTSTATUS status;
263 status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
264 TALLOC_FREE(subreq);
265 if (tevent_req_nterror(req, status)) {
266 return;
269 state->tried_dclookup = true;
271 status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
272 if (tevent_req_nterror(req, status)) {
273 return;
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)) {
281 return;
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);
292 struct unixid xid;
293 NTSTATUS status;
295 status = wb_sids2xids_recv(subreq, &xid, 1);
296 TALLOC_FREE(subreq);
297 if (tevent_req_nterror(req, status)) {
298 return;
301 if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
302 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
303 return;
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)) {
312 return;
314 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
315 req);
316 return;
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;
329 NTSTATUS status;
330 const char *domain_name;
332 status = wb_lookupsid_recv(subreq, state->info, &type, &domain_name,
333 &state->info->primary_group_name);
334 TALLOC_FREE(subreq);
335 if (tevent_req_nterror(req, status)) {
336 return;
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);
346 NTSTATUS status;
348 if (tevent_req_is_nterror(req, &status)) {
349 return status;
351 *pinfo = talloc_move(mem_ctx, &state->info);
352 return NT_STATUS_OK;