Revert "s3/service: convert lp_force_group() to const"
[Samba.git] / source3 / winbindd / wb_queryuser.c
blob17170c3352ac189daf0055956fb0fa04fd165bf2
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 state->info = talloc_zero(state, struct wbint_userinfo);
54 if (tevent_req_nomem(state->info, req)) {
55 return tevent_req_post(req, ev);
57 info = state->info;
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);
69 return 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;
81 struct unixid xid;
82 NTSTATUS status;
84 status = wb_sids2xids_recv(subreq, &xid, 1);
85 TALLOC_FREE(subreq);
86 if (tevent_req_nterror(req, status)) {
87 return;
90 if ((xid.type != ID_TYPE_UID) && (xid.type != ID_TYPE_BOTH)) {
91 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
92 return;
95 info->uid = xid.id;
98 * Default the group sid to "Domain Users" in the user's
99 * domain. The samlogon cache or the query_user call later on
100 * can override this.
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)) {
108 return;
111 info->shell = talloc_strdup(info, lp_template_shell());
112 if (tevent_req_nomem(info->shell, req)) {
113 return;
116 info3 = netsamlogon_cache_get(state, &info->user_sid);
117 if (info3 != NULL) {
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);
129 TALLOC_FREE(info3);
132 if (info->domain_name == NULL) {
133 subreq = wb_lookupsid_send(state, state->ev, &info->user_sid);
134 if (tevent_req_nomem(subreq, req)) {
135 return;
137 tevent_req_set_callback(subreq, wb_queryuser_got_domain, req);
138 return;
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)) {
146 return;
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;
160 NTSTATUS status;
162 status = wb_lookupsid_recv(subreq, state, &type,
163 &info->domain_name, &info->acct_name);
164 TALLOC_FREE(subreq);
165 if (tevent_req_nterror(req, status)) {
166 return;
169 if (type != SID_NAME_USER) {
170 /* allow SID_NAME_COMPUTER? */
171 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
172 return;
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)) {
180 return;
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);
197 TALLOC_FREE(subreq);
198 if (tevent_req_nterror(req, status)) {
199 return;
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,
206 DS_RETURN_DNS_NAME);
207 if (tevent_req_nomem(subreq, req)) {
208 return;
210 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
211 return;
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)) {
223 return;
225 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
226 return;
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)) {
241 return;
243 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
244 req);
245 return;
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;
260 NTSTATUS status;
262 status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
263 TALLOC_FREE(subreq);
264 if (tevent_req_nterror(req, status)) {
265 return;
268 state->tried_dclookup = true;
270 status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
271 if (tevent_req_nterror(req, status)) {
272 return;
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)) {
280 return;
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);
291 struct unixid xid;
292 NTSTATUS status;
293 bool need_group_name = false;
294 const char *tmpl = NULL;
296 status = wb_sids2xids_recv(subreq, &xid, 1);
297 TALLOC_FREE(subreq);
298 if (tevent_req_nterror(req, status)) {
299 return;
302 if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
303 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
304 return;
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)) {
322 return;
324 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
325 req);
326 return;
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;
339 NTSTATUS status;
340 const char *domain_name;
342 status = wb_lookupsid_recv(subreq, state->info, &type, &domain_name,
343 &state->info->primary_group_name);
344 TALLOC_FREE(subreq);
345 if (tevent_req_nterror(req, status)) {
346 return;
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);
356 NTSTATUS status;
358 if (tevent_req_is_nterror(req, &status)) {
359 return status;
361 *pinfo = talloc_move(mem_ctx, &state->info);
362 return NT_STATUS_OK;