winbindd: queryuser - only get group name if needed
[Samba.git] / source3 / winbindd / wb_queryuser.c
blob1c91949c2558bc674966ab5d91e420dd1f1065e3
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;
205 bool need_group_name = false;
206 const char *tmpl = NULL;
208 status = dcerpc_wbint_GetNssInfo_recv(subreq, info, &result);
209 TALLOC_FREE(subreq);
210 if (tevent_req_nterror(req, status)) {
211 return;
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,
218 DS_RETURN_DNS_NAME);
219 if (tevent_req_nomem(subreq, req)) {
220 return;
222 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
223 return;
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)) {
235 return;
237 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
238 return;
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)) {
253 return;
255 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
256 req);
257 return;
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;
272 NTSTATUS status;
274 status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
275 TALLOC_FREE(subreq);
276 if (tevent_req_nterror(req, status)) {
277 return;
280 state->tried_dclookup = true;
282 status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
283 if (tevent_req_nterror(req, status)) {
284 return;
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)) {
292 return;
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);
303 struct unixid xid;
304 NTSTATUS status;
305 bool need_group_name = false;
306 const char *tmpl = NULL;
308 status = wb_sids2xids_recv(subreq, &xid, 1);
309 TALLOC_FREE(subreq);
310 if (tevent_req_nterror(req, status)) {
311 return;
314 if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
315 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
316 return;
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)) {
334 return;
336 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
337 req);
338 return;
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;
351 NTSTATUS status;
352 const char *domain_name;
354 status = wb_lookupsid_recv(subreq, state->info, &type, &domain_name,
355 &state->info->primary_group_name);
356 TALLOC_FREE(subreq);
357 if (tevent_req_nterror(req, status)) {
358 return;
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);
368 NTSTATUS status;
370 if (tevent_req_is_nterror(req, &status)) {
371 return status;
373 *pinfo = talloc_move(mem_ctx, &state->info);
374 return NT_STATUS_OK;