s4:winbind Implement logic for getgroups to work
[abartlet/samba.git/.git] / source4 / winbind / wb_cmd_getgroups.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Backend for getgroups
5
6    Copyright (C) Matthieu Patou 2010
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/composite/composite.h"
24 #include "winbind/wb_server.h"
25 #include "smbd/service_task.h"
26 #include "libcli/security/dom_sid.h"
27
28 struct cmd_getgroups_state {
29         struct composite_context *ctx;
30         struct wbsrv_service *service;
31         char* username;
32         uint32_t num_groups;
33         uint32_t current_group;
34         struct dom_sid **sids;
35
36         gid_t *gids;
37 };
38
39 /* The idea is to get the groups for a user
40    We receive one user from this we search for his uid
41    From the uid we search for his SID
42    From the SID we search for the list of groups
43    And with the list of groups we search for each group its gid
44 */
45 static void cmd_getgroups_recv_pwnam(struct composite_context *ctx);
46 static void wb_getgroups_uid2sid_recv(struct composite_context *ctx);
47 static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx);
48 static void cmd_getgroups_recv_gid(struct composite_context *ctx);
49
50 /*
51   Ask for the uid from the username
52 */
53 struct composite_context *wb_cmd_getgroups_send(TALLOC_CTX *mem_ctx,
54                                                  struct wbsrv_service *service,
55                                                  const char* username)
56 {
57         struct composite_context *ctx, *result;
58         struct cmd_getgroups_state *state;
59
60         DEBUG(5, ("wb_cmd_getgroups_send called\n"));
61
62         result = composite_create(mem_ctx, service->task->event_ctx);
63         if (!result) return NULL;
64
65         state = talloc(mem_ctx, struct cmd_getgroups_state);
66         if (composite_nomem(state, result)) return result;
67
68         state->ctx = result;
69         result->private_data = state;
70         state->service = service;
71         state->num_groups = 0;
72
73         state->username = talloc_strdup(state,username);
74         if (composite_nomem(ctx, result)) return result;
75
76         ctx = wb_cmd_getpwnam_send(state, service, username);
77         if (composite_nomem(ctx, result)) return result;
78
79         composite_continue(result, ctx, cmd_getgroups_recv_pwnam, state);
80         return result;
81 }
82
83 /*
84   Receive the uid and send request for SID
85 */
86 static void cmd_getgroups_recv_pwnam(struct composite_context *ctx)
87 {
88         struct composite_context *res;
89         struct cmd_getgroups_state *state =
90                 talloc_get_type(ctx->async.private_data,
91                                 struct cmd_getgroups_state);
92         struct winbindd_pw *pw;
93         struct wbsrv_service *service = state->service;
94
95         DEBUG(5, ("cmd_getgroups_recv_pwnam called\n"));
96
97         state->ctx->status = wb_cmd_getpwnam_recv(ctx, state, &pw);
98         if (composite_is_ok(state->ctx)) {
99                 res = wb_uid2sid_send(state, service, pw->pw_uid);
100                 NT_STATUS_HAVE_NO_MEMORY(res);
101                 DEBUG(6, ("cmd_getgroups_recv_pwnam uid %d\n",pw->pw_uid));
102
103                 composite_continue(ctx, res, wb_getgroups_uid2sid_recv, state);
104         }
105 }
106
107 /*
108   Receive the SID and request groups through the userdomgroups helper
109 */
110 static void wb_getgroups_uid2sid_recv(struct composite_context *ctx)
111 {
112         struct composite_context *res;
113         struct cmd_getgroups_state *state =
114                 talloc_get_type(ctx->async.private_data,
115                                 struct cmd_getgroups_state);
116         NTSTATUS status;
117         struct dom_sid *sid;
118         char *sid_str;
119
120         DEBUG(5, ("wb_getgroups_uid2sid_recv called\n"));
121
122         status = wb_uid2sid_recv(ctx, state, &sid);
123         if(NT_STATUS_IS_OK(status)) {
124                 sid_str = dom_sid_string(state, sid);
125
126                 /* If the conversion failed, bail out with a failure. */
127                 if (sid_str != NULL) {
128                         DEBUG(7, ("wb_getgroups_uid2sid_recv SID = %s\n",sid_str));
129                         /* Ok got the SID now get the groups */
130                         res = wb_cmd_userdomgroups_send(state, state->service, sid);
131                         NT_STATUS_HAVE_NO_MEMORY(res);
132
133                         composite_continue(ctx, res, wb_getgroups_userdomsgroups_recv, state);
134                 } else {
135                         composite_error(state->ctx, NT_STATUS_UNSUCCESSFUL);
136                 }
137         }
138 }
139
140 /*
141   Receive groups and search for uid for the first group
142 */
143 static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx) {
144         struct cmd_getgroups_state *state =
145                 talloc_get_type(ctx->async.private_data,
146                                 struct cmd_getgroups_state);
147         int num_sids;
148         struct dom_sid **sids;
149
150         DEBUG(5, ("wb_getgroups_userdomsgroups_recv called\n"));
151         state->ctx->status = wb_cmd_userdomgroups_recv(ctx,state,&num_sids,&sids);
152         if (!composite_is_ok(state->ctx)) return;
153
154         DEBUG(5, ("wb_getgroups_userdomsgroups_recv %d groups\n",num_sids));
155
156         state->sids=sids;
157         state->num_groups=num_sids;
158         state->current_group=0;
159
160         if(num_sids > 0) {
161                 state->gids = talloc_array(state, struct gid_t *, state->num_groups);
162                 ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]);
163                 composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state);
164         } else {
165                 composite_done(state->ctx);
166         }
167 }
168
169 /*
170   Receive and uid the previous searched group and request the uid for the next one
171 */
172 static void cmd_getgroups_recv_gid(struct composite_context *ctx)
173 {
174         struct cmd_getgroups_state *state =
175                 talloc_get_type(ctx->async.private_data,
176                                 struct cmd_getgroups_state);
177         gid_t gid;
178         char* sid_str;
179
180         DEBUG(5, ("cmd_getgroups_recv_gid called\n"));
181
182         state->ctx->status = wb_sid2gid_recv(ctx, &gid);
183         if(!composite_is_ok(state->ctx)) return;
184
185         state->gids[state->current_group] = gid;
186         DEBUG(5, ("cmd_getgroups_recv_gid group %d \n",state->current_group));
187
188         state->current_group++;
189         if(state->current_group < state->num_groups ) {
190                 ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]);
191                 composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state);
192         } else {
193                 composite_done(state->ctx);
194         }
195 }
196
197 /*
198   Return list of uids when finished
199 */
200 NTSTATUS wb_cmd_getgroups_recv(struct composite_context *ctx,TALLOC_CTX *mem_ctx,gid_t **groups,uint32_t *num_groups)
201 {
202         NTSTATUS status = composite_wait(ctx);
203
204         DEBUG(5, ("wb_cmd_getgroups_recv called\n"));
205
206         if (NT_STATUS_IS_OK(status)) {
207                 struct cmd_getgroups_state *state =
208                         talloc_get_type(ctx->private_data,
209                                         struct cmd_getgroups_state);
210                 *groups = talloc_steal(mem_ctx, state->gids);
211                 *num_groups = state->num_groups;
212         }
213         talloc_free(ctx);
214         return status;
215 }