r11181: Implement wbinfo -s and wbinfo --user-sids. The patch is so large because
[bbaumbach/samba-autobuild/.git] / source4 / winbind / wb_cmd_usersids.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Command backend for wbinfo --user-sids
5
6    Copyright (C) Volker Lendecke 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/composite/composite.h"
25 #include "winbind/wb_server.h"
26 #include "smbd/service_stream.h"
27 #include "smbd/service_task.h"
28 #include "lib/events/events.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "librpc/gen_ndr/ndr_samr.h"
31
32 /* Calculate the token in two steps: Go the user's originating domain, asking
33  * for the user's domain groups. Then with the resulting list of sids go to
34  * our own domain, expanding the aliases aka domain local groups. Two helpers
35  * are needed: composite_samr_GetAliasMembership and wb_sidaliases. The core
36  * function this file supplies is wb_cmd_usersids somewhere down. */
37
38
39 /* composite_context wrapper around dcerpc_samr_GetAliasMembership */
40
41 static void composite_samr_GetAliasMembership_recv_rpc(struct rpc_request *req);
42
43 static struct composite_context *composite_samr_GetAliasMembership_send(struct dcerpc_pipe *p,
44                                                                         TALLOC_CTX *mem_ctx,
45                                                                         struct samr_GetAliasMembership *r)
46 {
47         struct composite_context *result;
48         struct rpc_request *req;
49
50         result = talloc(mem_ctx, struct composite_context);
51         if (result == NULL) goto failed;
52         result->state = COMPOSITE_STATE_IN_PROGRESS;
53         result->async.fn = NULL;
54         result->event_ctx = p->conn->event_ctx;
55
56         req = dcerpc_samr_GetAliasMembership_send(p, mem_ctx, r);
57         if (req == NULL) goto failed;
58         req->async.callback = composite_samr_GetAliasMembership_recv_rpc;
59         req->async.private = result;
60         return result;
61
62  failed:
63         talloc_free(result);
64         return NULL;
65 }
66
67 static void composite_samr_GetAliasMembership_recv_rpc(struct rpc_request *req)
68 {
69         struct composite_context *ctx =
70                 talloc_get_type(req->async.private, struct composite_context);
71
72         ctx->status = dcerpc_ndr_request_recv(req);
73         if (!composite_is_ok(ctx)) return;
74         composite_done(ctx);
75 }
76
77 static NTSTATUS composite_samr_GetAliasMembership_recv(struct composite_context *ctx)
78 {
79         NTSTATUS status = composite_wait(ctx);
80         talloc_free(ctx);
81         return status;
82 }
83
84 /* Composite wrapper including domain selection and domain queueing around
85  * GetAliasMemberships */
86
87 struct sidaliases_state {
88         struct composite_context *ctx;
89         int num_sids;
90         const struct dom_sid *domain_sid;
91         const struct dom_sid *sids;
92
93         struct lsa_SidArray lsa_sids;
94         struct samr_Ids rids;
95         struct samr_GetAliasMembership r;
96 };
97
98 static struct composite_context *sidaliases_send_req(struct wbsrv_domain *domain,
99                                                      void *p);
100 static NTSTATUS sidaliases_recv_req(struct composite_context *ctx, void *p);
101
102 static struct composite_context *wb_sidaliases_send(struct wbsrv_service *service,
103                                                     int num_sids,
104                                                     struct dom_sid **sids)
105 {
106         struct sidaliases_state *state;
107         int i;
108
109         state = talloc(NULL, struct sidaliases_state);
110
111         state->domain_sid = talloc_reference(state, service->primary_sid);
112         if (state->domain_sid == NULL) goto failed;
113
114         state->lsa_sids.num_sids = num_sids;
115         state->lsa_sids.sids = talloc_array(state, struct lsa_SidPtr,
116                                             num_sids);
117         if (state->lsa_sids.sids == NULL) goto failed;
118
119         for (i=0; i<state->lsa_sids.num_sids; i++) {
120                 state->lsa_sids.sids[i].sid =
121                         talloc_reference(state->lsa_sids.sids, sids[i]);
122                 if (state->lsa_sids.sids[i].sid == NULL) goto failed;
123         }
124
125         state->rids.count = 0;
126         state->rids.ids = NULL;
127
128         state->ctx = wb_domain_request_send(state, service,
129                                             service->primary_sid,
130                                             sidaliases_send_req,
131                                             sidaliases_recv_req,
132                                             state);
133         if (state->ctx == NULL) goto failed;
134         state->ctx->private_data = state;
135         return state->ctx;
136
137  failed:
138         talloc_free(state);
139         return NULL;
140 }
141
142 static struct composite_context *sidaliases_send_req(struct wbsrv_domain *domain,
143                                                      void *p)
144 {
145         struct sidaliases_state *state =
146                 talloc_get_type(p, struct sidaliases_state);
147
148         state->r.in.domain_handle = domain->domain_handle;
149         state->r.in.sids = &state->lsa_sids;
150         state->r.out.rids = &state->rids;
151
152         return composite_samr_GetAliasMembership_send(domain->samr_pipe,
153                                                       state, &state->r);
154 }
155
156 static NTSTATUS sidaliases_recv_req(struct composite_context *ctx, void *p)
157 {
158         struct sidaliases_state *state =
159                 talloc_get_type(p, struct sidaliases_state);
160         NTSTATUS status;
161
162         status = composite_samr_GetAliasMembership_recv(ctx);
163         NT_STATUS_NOT_OK_RETURN(status);
164         return state->r.out.result;
165 }
166
167 static NTSTATUS wb_sidaliases_recv(struct composite_context *ctx,
168                                    TALLOC_CTX *mem_ctx,
169                                    int *num_sids,
170                                    struct dom_sid ***sids)
171 {
172         struct sidaliases_state *state =
173                 talloc_get_type(ctx->private_data,
174                                 struct sidaliases_state);
175         NTSTATUS status;
176         int i;
177
178         status = composite_wait(ctx);
179         if (!NT_STATUS_IS_OK(status)) goto done;
180
181         *num_sids = state->r.out.rids->count;
182         *sids = talloc_array(mem_ctx, struct dom_sid *, *num_sids);
183         if (*sids == NULL) {
184                 status = NT_STATUS_NO_MEMORY;
185                 goto done;
186         }
187         for (i=0; i<*num_sids; i++) {
188                 (*sids)[i] = dom_sid_add_rid((*sids), state->domain_sid,
189                                              state->r.out.rids->ids[i]);
190                 if ((*sids)[i] == NULL) {
191                         status = NT_STATUS_NO_MEMORY;
192                         goto done;
193                 }
194         }
195
196  done:
197         talloc_free(state);
198         return status;
199 }
200
201 /* Supplied a SID, go to the user's DC, ask it for the user's domain
202  * groups. Then go to our DC, ask it for the domain local groups. */
203
204 struct cmd_usersids_state {
205         struct composite_context *ctx;
206         struct wbsrv_service *service;
207         struct dom_sid *user_sid;
208         int num_domgroups;
209         struct dom_sid **domgroups;
210         int num_sids;
211         struct dom_sid **sids;
212 };
213
214 static void cmd_usersids_recv_domgroups(struct composite_context *ctx);
215 static void cmd_usersids_recv_aliases(struct composite_context *ctx);
216
217 struct composite_context *wb_cmd_usersids_send(struct wbsrv_service *service,
218                                                const struct dom_sid *sid)
219 {
220         struct composite_context *result, *ctx;
221         struct cmd_usersids_state *state;
222
223         result = talloc_zero(NULL, struct composite_context);
224         if (result == NULL) goto failed;
225         result->state = COMPOSITE_STATE_IN_PROGRESS;
226         result->async.fn = NULL;
227         result->event_ctx = service->task->event_ctx;
228
229         state = talloc(result, struct cmd_usersids_state);
230         if (state == NULL) goto failed;
231         state->ctx = result;
232         result->private_data = state;
233
234         state->service = service;
235         state->user_sid = dom_sid_dup(state, sid);
236         if (state->user_sid == NULL) goto failed;
237
238         ctx = wb_cmd_userdomgroups_send(service, sid);
239         if (ctx == NULL) goto failed;
240
241         ctx->async.fn = cmd_usersids_recv_domgroups;
242         ctx->async.private_data = state;
243         return result;
244
245  failed:
246         talloc_free(result);
247         return NULL;
248 }
249
250 static void cmd_usersids_recv_domgroups(struct composite_context *ctx)
251 {
252         struct cmd_usersids_state *state =
253                 talloc_get_type(ctx->async.private_data,
254                                 struct cmd_usersids_state);
255
256         int i;
257         struct dom_sid **sids;
258
259         state->ctx->status = wb_cmd_userdomgroups_recv(ctx, state,
260                                                        &state->num_domgroups,
261                                                        &state->domgroups);
262         if (!composite_is_ok(state->ctx)) return;
263
264         sids = talloc_array(state, struct dom_sid *, state->num_domgroups+1);
265         if (composite_nomem(sids, state->ctx)) return;
266
267         sids[0] = state->user_sid;
268         for (i=0; i<state->num_domgroups; i++) {
269                 sids[i+1] = state->domgroups[i];
270         }
271
272         ctx = wb_sidaliases_send(state->service, state->num_domgroups+1,
273                                  sids);
274         composite_continue(state->ctx, ctx, cmd_usersids_recv_aliases, state);
275 }
276
277 static void cmd_usersids_recv_aliases(struct composite_context *ctx)
278 {
279         struct cmd_usersids_state *state =
280                 talloc_get_type(ctx->async.private_data,
281                                 struct cmd_usersids_state);
282         int i, num_aliases;
283         struct dom_sid **aliases;
284
285         state->ctx->status = wb_sidaliases_recv(ctx, state, &num_aliases,
286                                                 &aliases);
287         if (!composite_is_ok(state->ctx)) return;
288
289         state->num_sids = 1 + state->num_domgroups + num_aliases;
290         state->sids = talloc_array(state, struct dom_sid *, state->num_sids);
291         if (composite_nomem(state->sids, state->ctx)) return;
292
293         state->sids[0] = talloc_steal(state->sids, state->user_sid);
294
295         for (i=0; i<state->num_domgroups; i++) {
296                 state->sids[1+i] =
297                         talloc_steal(state->sids, state->domgroups[i]);
298         }
299
300         for (i=0; i<num_aliases; i++) {
301                 state->sids[1+i+state->num_domgroups] =
302                         talloc_steal(state->sids, aliases[i]);
303         }
304
305         composite_done(state->ctx);
306 }
307
308 NTSTATUS wb_cmd_usersids_recv(struct composite_context *ctx,
309                               TALLOC_CTX *mem_ctx,
310                               int *num_sids, struct dom_sid ***sids)
311 {
312         NTSTATUS status = composite_wait(ctx);
313         if (NT_STATUS_IS_OK(status)) {
314                 struct cmd_usersids_state *state =
315                         talloc_get_type(ctx->private_data,
316                                         struct cmd_usersids_state);
317                 *num_sids = state->num_sids;
318                 *sids = talloc_steal(mem_ctx, state->sids);
319         }
320         talloc_free(ctx);
321         return status;
322 }
323
324 NTSTATUS wb_cmd_usersids(struct wbsrv_service *service,
325                               const struct dom_sid *sid,
326                               TALLOC_CTX *mem_ctx, int *num_sids,
327                               struct dom_sid ***sids)
328 {
329         struct composite_context *c =
330                 wb_cmd_usersids_send(service, sid);
331         return wb_cmd_usersids_recv(c, mem_ctx, num_sids, sids);
332 }
333