lib: modules: Change XXX_init interface from XXX_init(void) to XXX_init(TALLOC_CTX *)
[metze/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
206         status = dcerpc_wbint_GetNssInfo_recv(subreq, info, &result);
207         TALLOC_FREE(subreq);
208         if (tevent_req_nterror(req, status)) {
209                 return;
210         }
211
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;
219                 }
220                 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
221                 return;
222         }
223
224         /*
225          * Ignore failure in "result" here. We'll try to fill in stuff
226          * that misses further down.
227          */
228
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;
234                 }
235                 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
236                 return;
237         }
238
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;
243                 }
244                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
245                                         req);
246                 return;
247         }
248
249         tevent_req_done(req);
250 }
251
252 static void wb_queryuser_got_dc(struct tevent_req *subreq)
253 {
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;
262
263         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
264         TALLOC_FREE(subreq);
265         if (tevent_req_nterror(req, status)) {
266                 return;
267         }
268
269         state->tried_dclookup = true;
270
271         status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
272         if (tevent_req_nterror(req, status)) {
273                 return;
274         }
275
276         child = idmap_child();
277
278         subreq = dcerpc_wbint_GetNssInfo_send(
279                 state, state->ev, child->binding_handle, info);
280         if (tevent_req_nomem(subreq, req)) {
281                 return;
282         }
283         tevent_req_set_callback(subreq, wb_queryuser_done, req);
284 }
285
286 static void wb_queryuser_got_gid(struct tevent_req *subreq)
287 {
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;
294
295         status = wb_sids2xids_recv(subreq, &xid, 1);
296         TALLOC_FREE(subreq);
297         if (tevent_req_nterror(req, status)) {
298                 return;
299         }
300
301         if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
302                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
303                 return;
304         }
305
306         state->info->primary_gid = xid.id;
307
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;
313                 }
314                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
315                                         req);
316                 return;
317         }
318
319         tevent_req_done(req);
320 }
321
322 static void wb_queryuser_got_group_name(struct tevent_req *subreq)
323 {
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;
331
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;
337         }
338         tevent_req_done(req);
339 }
340
341 NTSTATUS wb_queryuser_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
342                            struct wbint_userinfo **pinfo)
343 {
344         struct wb_queryuser_state *state = tevent_req_data(
345                 req, struct wb_queryuser_state);
346         NTSTATUS status;
347
348         if (tevent_req_is_nterror(req, &status)) {
349                 return status;
350         }
351         *pinfo = talloc_move(mem_ctx, &state->info);
352         return NT_STATUS_OK;
353 }