2f4cec811cfd282c0fc1fe2da446ecdc9f0e71f0
[samba.git] / source3 / winbindd / wb_gettoken.c
1 /*
2    Unix SMB/CIFS implementation.
3    async gettoken
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_wbint_c.h"
23 #include "../libcli/security/security.h"
24
25 struct wb_gettoken_state {
26         struct tevent_context *ev;
27         struct dom_sid usersid;
28         int num_sids;
29         struct dom_sid *sids;
30 };
31
32 static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx,
33                                 int *pnum_sids, struct dom_sid **psids,
34                                 const struct dom_sid *domain_sid,
35                                 int num_rids, uint32_t *rids);
36
37 static void wb_gettoken_gotgroups(struct tevent_req *subreq);
38 static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq);
39 static void wb_gettoken_gotbuiltins(struct tevent_req *subreq);
40
41 struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx,
42                                     struct tevent_context *ev,
43                                     const struct dom_sid *sid)
44 {
45         struct tevent_req *req, *subreq;
46         struct wb_gettoken_state *state;
47         struct winbindd_domain *domain;
48
49         req = tevent_req_create(mem_ctx, &state, struct wb_gettoken_state);
50         if (req == NULL) {
51                 return NULL;
52         }
53         sid_copy(&state->usersid, sid);
54         state->ev = ev;
55
56         domain = find_domain_from_sid_noinit(sid);
57         if (domain == NULL) {
58                 DEBUG(5, ("Could not find domain from SID %s\n",
59                           sid_string_dbg(sid)));
60                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
61                 return tevent_req_post(req, ev);
62         }
63
64         if (lp_winbind_trusted_domains_only() && domain->primary) {
65                 DEBUG(7, ("wb_gettoken: My domain -- rejecting getgroups() "
66                           "for %s.\n", sid_string_tos(sid)));
67                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
68                 return tevent_req_post(req, ev);
69         }
70
71         subreq = wb_lookupusergroups_send(state, ev, domain, &state->usersid);
72         if (tevent_req_nomem(subreq, req)) {
73                 return tevent_req_post(req, ev);
74         }
75         tevent_req_set_callback(subreq, wb_gettoken_gotgroups, req);
76         return req;
77 }
78
79 static void wb_gettoken_gotgroups(struct tevent_req *subreq)
80 {
81         struct tevent_req *req = tevent_req_callback_data(
82                 subreq, struct tevent_req);
83         struct wb_gettoken_state *state = tevent_req_data(
84                 req, struct wb_gettoken_state);
85         struct dom_sid *sids;
86         struct winbindd_domain *domain;
87         NTSTATUS status;
88
89         status = wb_lookupusergroups_recv(subreq, state, &state->num_sids,
90                                           &state->sids);
91         TALLOC_FREE(subreq);
92         if (!NT_STATUS_IS_OK(status)) {
93                 tevent_req_nterror(req, status);
94                 return;
95         }
96
97         sids = talloc_realloc(state, state->sids, struct dom_sid,
98                               state->num_sids + 1);
99         if (tevent_req_nomem(sids, req)) {
100                 return;
101         }
102         memmove(&sids[1], &sids[0], state->num_sids * sizeof(sids[0]));
103         sid_copy(&sids[0], &state->usersid);
104         state->num_sids += 1;
105         state->sids = sids;
106
107         /*
108          * Expand our domain's aliases
109          */
110         domain = find_domain_from_sid_noinit(get_global_sam_sid());
111         if (domain == NULL) {
112                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
113                 return;
114         }
115
116         subreq = wb_lookupuseraliases_send(state, state->ev, domain,
117                                            state->num_sids, state->sids);
118         if (tevent_req_nomem(subreq, req)) {
119                 return;
120         }
121         tevent_req_set_callback(subreq, wb_gettoken_gotlocalgroups, req);
122 }
123
124 static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq)
125 {
126         struct tevent_req *req = tevent_req_callback_data(
127                 subreq, struct tevent_req);
128         struct wb_gettoken_state *state = tevent_req_data(
129                 req, struct wb_gettoken_state);
130         uint32_t num_rids;
131         uint32_t *rids;
132         struct winbindd_domain *domain;
133         NTSTATUS status;
134
135         status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids);
136         TALLOC_FREE(subreq);
137         if (!NT_STATUS_IS_OK(status)) {
138                 tevent_req_nterror(req, status);
139                 return;
140         }
141         domain = find_domain_from_sid_noinit(get_global_sam_sid());
142         if (domain == NULL) {
143                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
144                 return;
145         }
146         if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
147                                  &domain->sid, num_rids, rids)) {
148                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
149                 return;
150         }
151         TALLOC_FREE(rids);
152
153         /*
154          * Now expand the builtin groups
155          */
156
157         domain = find_builtin_domain();
158         if (domain == NULL) {
159                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
160                 return;
161         }
162
163         subreq = wb_lookupuseraliases_send(state, state->ev, domain,
164                                            state->num_sids, state->sids);
165         if (tevent_req_nomem(subreq, req)) {
166                 return;
167         }
168         tevent_req_set_callback(subreq, wb_gettoken_gotbuiltins, req);
169 }
170
171 static void wb_gettoken_gotbuiltins(struct tevent_req *subreq)
172 {
173         struct tevent_req *req = tevent_req_callback_data(
174                 subreq, struct tevent_req);
175         struct wb_gettoken_state *state = tevent_req_data(
176                 req, struct wb_gettoken_state);
177         uint32_t num_rids;
178         uint32_t *rids;
179         NTSTATUS status;
180
181         status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids);
182         TALLOC_FREE(subreq);
183         if (!NT_STATUS_IS_OK(status)) {
184                 tevent_req_nterror(req, status);
185                 return;
186         }
187         if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
188                                  &global_sid_Builtin, num_rids, rids)) {
189                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
190                 return;
191         }
192         tevent_req_done(req);
193 }
194
195 NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
196                           int *num_sids, struct dom_sid **sids)
197 {
198         struct wb_gettoken_state *state = tevent_req_data(
199                 req, struct wb_gettoken_state);
200         NTSTATUS status;
201
202         if (tevent_req_is_nterror(req, &status)) {
203                 return status;
204         }
205         *num_sids = state->num_sids;
206         *sids = talloc_move(mem_ctx, &state->sids);
207         return NT_STATUS_OK;
208 }
209
210 static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx,
211                                 int *pnum_sids, struct dom_sid **psids,
212                                 const struct dom_sid *domain_sid,
213                                 int num_rids, uint32_t *rids)
214 {
215         struct dom_sid *sids;
216         int i;
217
218         sids = talloc_realloc(mem_ctx, *psids, struct dom_sid,
219                               *pnum_sids + num_rids);
220         if (sids == NULL) {
221                 return false;
222         }
223         for (i=0; i<num_rids; i++) {
224                 sid_compose(&sids[i+*pnum_sids], domain_sid, rids[i]);
225         }
226
227         *pnum_sids += num_rids;
228         *psids = sids;
229         return true;
230 }