s3: Fix bug 7843: Expand the local SAMs aliases
[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/cli_wbint.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 (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
143                                  &domain->sid, num_rids, rids)) {
144                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
145                 return;
146         }
147         TALLOC_FREE(rids);
148
149         /*
150          * Now expand the builtin groups
151          */
152
153         domain = find_builtin_domain();
154         if (domain == NULL) {
155                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
156                 return;
157         }
158
159         subreq = wb_lookupuseraliases_send(state, state->ev, domain,
160                                            state->num_sids, state->sids);
161         if (tevent_req_nomem(subreq, req)) {
162                 return;
163         }
164         tevent_req_set_callback(subreq, wb_gettoken_gotbuiltins, req);
165 }
166
167 static void wb_gettoken_gotbuiltins(struct tevent_req *subreq)
168 {
169         struct tevent_req *req = tevent_req_callback_data(
170                 subreq, struct tevent_req);
171         struct wb_gettoken_state *state = tevent_req_data(
172                 req, struct wb_gettoken_state);
173         uint32_t num_rids;
174         uint32_t *rids;
175         NTSTATUS status;
176
177         status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids);
178         TALLOC_FREE(subreq);
179         if (!NT_STATUS_IS_OK(status)) {
180                 tevent_req_nterror(req, status);
181                 return;
182         }
183         if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
184                                  &global_sid_Builtin, num_rids, rids)) {
185                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
186                 return;
187         }
188         tevent_req_done(req);
189 }
190
191 NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
192                           int *num_sids, struct dom_sid **sids)
193 {
194         struct wb_gettoken_state *state = tevent_req_data(
195                 req, struct wb_gettoken_state);
196         NTSTATUS status;
197
198         if (tevent_req_is_nterror(req, &status)) {
199                 return status;
200         }
201         *num_sids = state->num_sids;
202         *sids = talloc_move(mem_ctx, &state->sids);
203         return NT_STATUS_OK;
204 }
205
206 static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx,
207                                 int *pnum_sids, struct dom_sid **psids,
208                                 const struct dom_sid *domain_sid,
209                                 int num_rids, uint32_t *rids)
210 {
211         struct dom_sid *sids;
212         int i;
213
214         sids = talloc_realloc(mem_ctx, *psids, struct dom_sid,
215                               *pnum_sids + num_rids);
216         if (sids == NULL) {
217                 return false;
218         }
219         for (i=0; i<num_rids; i++) {
220                 sid_compose(&sids[i+*pnum_sids], domain_sid, rids[i]);
221         }
222
223         *pnum_sids += num_rids;
224         *psids = sids;
225         return true;
226 }