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