winbindd: Fix indentation
[sfrench/samba-autobuild/.git] / source3 / winbindd / wb_queryuser.c
1 /*
2    Unix SMB/CIFS implementation.
3    async queryuser
4    Copyright (C) Volker Lendecke 2009
5
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.
10
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.
15
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/>.
18 */
19
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"
25
26 struct wb_queryuser_state {
27         struct tevent_context *ev;
28         struct wbint_userinfo *info;
29         bool tried_dclookup;
30 };
31
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);
38
39 struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
40                                      struct tevent_context *ev,
41                                      const struct dom_sid *user_sid)
42 {
43         struct tevent_req *req, *subreq;
44         struct wb_queryuser_state *state;
45         struct wbint_userinfo *info;
46
47         req = tevent_req_create(mem_ctx, &state, struct wb_queryuser_state);
48         if (req == NULL) {
49                 return NULL;
50         }
51         state->ev = ev;
52
53         if (lp_winbind_trusted_domains_only()) {
54                 struct winbindd_domain *our_domain = find_our_domain();
55
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);
62                 }
63         }
64
65         state->info = talloc_zero(state, struct wbint_userinfo);
66         if (tevent_req_nomem(state->info, req)) {
67                 return tevent_req_post(req, ev);
68         }
69         info = state->info;
70
71         info->primary_gid = (gid_t)-1;
72
73         sid_copy(&info->user_sid, user_sid);
74
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);
79         }
80         tevent_req_set_callback(subreq, wb_queryuser_got_uid, req);
81         return req;
82 }
83
84 static void wb_queryuser_got_uid(struct tevent_req *subreq)
85 {
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;
95
96         status = wb_sids2xids_recv(subreq, &xid, 1);
97         TALLOC_FREE(subreq);
98         if (tevent_req_nterror(req, status)) {
99                 return;
100         }
101
102         if ((xid.type != ID_TYPE_UID) && (xid.type != ID_TYPE_BOTH)) {
103                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
104                 return;
105         }
106
107         info->uid = xid.id;
108
109         /*
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.
113          */
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);
117
118         info->homedir = talloc_strdup(info, lp_template_homedir());
119         if (tevent_req_nomem(info->homedir, req)) {
120                 return;
121         }
122
123         info->shell = talloc_strdup(info, lp_template_shell());
124         if (tevent_req_nomem(info->shell, req)) {
125                 return;
126         }
127
128         info3 = netsamlogon_cache_get(state, &info->user_sid);
129         if (info3 != NULL) {
130
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);
137
138                 info->domain_name = talloc_move(
139                         state, &info3->base.logon_domain.string);
140
141                 TALLOC_FREE(info3);
142         }
143
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;
148                 }
149                 tevent_req_set_callback(subreq, wb_queryuser_got_domain, req);
150                 return;
151         }
152
153         child = idmap_child();
154
155         subreq = dcerpc_wbint_GetNssInfo_send(
156                 state, state->ev, child->binding_handle, info);
157         if (tevent_req_nomem(subreq, req)) {
158                 return;
159         }
160         tevent_req_set_callback(subreq, wb_queryuser_done, req);
161 }
162
163 static void wb_queryuser_got_domain(struct tevent_req *subreq)
164 {
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;
173
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;
179         }
180
181         if (type != SID_NAME_USER) {
182                 /* allow SID_NAME_COMPUTER? */
183                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
184                 return;
185         }
186
187         child = idmap_child();
188
189         subreq = dcerpc_wbint_GetNssInfo_send(
190                 state, state->ev, child->binding_handle, info);
191         if (tevent_req_nomem(subreq, req)) {
192                 return;
193         }
194         tevent_req_set_callback(subreq, wb_queryuser_done, req);
195 }
196
197 static void wb_queryuser_done(struct tevent_req *subreq)
198 {
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;
207
208         status = dcerpc_wbint_GetNssInfo_recv(subreq, info, &result);
209         TALLOC_FREE(subreq);
210         if (tevent_req_nterror(req, status)) {
211                 return;
212         }
213
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;
221                 }
222                 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
223                 return;
224         }
225
226         /*
227          * Ignore failure in "result" here. We'll try to fill in stuff
228          * that misses further down.
229          */
230
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;
236                 }
237                 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
238                 return;
239         }
240
241         tmpl = lp_template_homedir();
242         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
243                 need_group_name = true;
244         }
245         tmpl = lp_template_shell();
246         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
247                 need_group_name = true;
248         }
249
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;
254                 }
255                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
256                                         req);
257                 return;
258         }
259
260         tevent_req_done(req);
261 }
262
263 static void wb_queryuser_got_dc(struct tevent_req *subreq)
264 {
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;
273
274         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
275         TALLOC_FREE(subreq);
276         if (tevent_req_nterror(req, status)) {
277                 return;
278         }
279
280         state->tried_dclookup = true;
281
282         status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
283         if (tevent_req_nterror(req, status)) {
284                 return;
285         }
286
287         child = idmap_child();
288
289         subreq = dcerpc_wbint_GetNssInfo_send(
290                 state, state->ev, child->binding_handle, info);
291         if (tevent_req_nomem(subreq, req)) {
292                 return;
293         }
294         tevent_req_set_callback(subreq, wb_queryuser_done, req);
295 }
296
297 static void wb_queryuser_got_gid(struct tevent_req *subreq)
298 {
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;
307
308         status = wb_sids2xids_recv(subreq, &xid, 1);
309         TALLOC_FREE(subreq);
310         if (tevent_req_nterror(req, status)) {
311                 return;
312         }
313
314         if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
315                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
316                 return;
317         }
318
319         state->info->primary_gid = xid.id;
320
321         tmpl = lp_template_homedir();
322         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
323                 need_group_name = true;
324         }
325         tmpl = lp_template_shell();
326         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
327                 need_group_name = true;
328         }
329
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;
335                 }
336                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
337                                         req);
338                 return;
339         }
340
341         tevent_req_done(req);
342 }
343
344 static void wb_queryuser_got_group_name(struct tevent_req *subreq)
345 {
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;
353
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;
359         }
360         tevent_req_done(req);
361 }
362
363 NTSTATUS wb_queryuser_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
364                            struct wbint_userinfo **pinfo)
365 {
366         struct wb_queryuser_state *state = tevent_req_data(
367                 req, struct wb_queryuser_state);
368         NTSTATUS status;
369
370         if (tevent_req_is_nterror(req, &status)) {
371                 return status;
372         }
373         *pinfo = talloc_move(mem_ctx, &state->info);
374         return NT_STATUS_OK;
375 }