diff options
Diffstat (limited to 'source4/winbind/wb_cmd_getgroups.c')
-rw-r--r-- | source4/winbind/wb_cmd_getgroups.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/source4/winbind/wb_cmd_getgroups.c b/source4/winbind/wb_cmd_getgroups.c new file mode 100644 index 0000000000..de70b0b911 --- /dev/null +++ b/source4/winbind/wb_cmd_getgroups.c @@ -0,0 +1,215 @@ +/* + Unix SMB/CIFS implementation. + + Backend for getgroups + + Copyright (C) Matthieu Patou 2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "libcli/composite/composite.h" +#include "winbind/wb_server.h" +#include "smbd/service_task.h" +#include "libcli/security/dom_sid.h" + +struct cmd_getgroups_state { + struct composite_context *ctx; + struct wbsrv_service *service; + char* username; + uint32_t num_groups; + uint32_t current_group; + struct dom_sid **sids; + + gid_t *gids; +}; + +/* The idea is to get the groups for a user + We receive one user from this we search for his uid + From the uid we search for his SID + From the SID we search for the list of groups + And with the list of groups we search for each group its gid +*/ +static void cmd_getgroups_recv_pwnam(struct composite_context *ctx); +static void wb_getgroups_uid2sid_recv(struct composite_context *ctx); +static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx); +static void cmd_getgroups_recv_gid(struct composite_context *ctx); + +/* + Ask for the uid from the username +*/ +struct composite_context *wb_cmd_getgroups_send(TALLOC_CTX *mem_ctx, + struct wbsrv_service *service, + const char* username) +{ + struct composite_context *ctx, *result; + struct cmd_getgroups_state *state; + + DEBUG(5, ("wb_cmd_getgroups_send called\n")); + + result = composite_create(mem_ctx, service->task->event_ctx); + if (!result) return NULL; + + state = talloc(mem_ctx, struct cmd_getgroups_state); + if (composite_nomem(state, result)) return result; + + state->ctx = result; + result->private_data = state; + state->service = service; + state->num_groups = 0; + + state->username = talloc_strdup(state,username); + if (composite_nomem(ctx, result)) return result; + + ctx = wb_cmd_getpwnam_send(state, service, username); + if (composite_nomem(ctx, result)) return result; + + composite_continue(result, ctx, cmd_getgroups_recv_pwnam, state); + return result; +} + +/* + Receive the uid and send request for SID +*/ +static void cmd_getgroups_recv_pwnam(struct composite_context *ctx) +{ + struct composite_context *res; + struct cmd_getgroups_state *state = + talloc_get_type(ctx->async.private_data, + struct cmd_getgroups_state); + struct winbindd_pw *pw; + struct wbsrv_service *service = state->service; + + DEBUG(5, ("cmd_getgroups_recv_pwnam called\n")); + + state->ctx->status = wb_cmd_getpwnam_recv(ctx, state, &pw); + if (composite_is_ok(state->ctx)) { + res = wb_uid2sid_send(state, service, pw->pw_uid); + NT_STATUS_HAVE_NO_MEMORY(res); + DEBUG(6, ("cmd_getgroups_recv_pwnam uid %d\n",pw->pw_uid)); + + composite_continue(ctx, res, wb_getgroups_uid2sid_recv, state); + } +} + +/* + Receive the SID and request groups through the userdomgroups helper +*/ +static void wb_getgroups_uid2sid_recv(struct composite_context *ctx) +{ + struct composite_context *res; + struct cmd_getgroups_state *state = + talloc_get_type(ctx->async.private_data, + struct cmd_getgroups_state); + NTSTATUS status; + struct dom_sid *sid; + char *sid_str; + + DEBUG(5, ("wb_getgroups_uid2sid_recv called\n")); + + status = wb_uid2sid_recv(ctx, state, &sid); + if(NT_STATUS_IS_OK(status)) { + sid_str = dom_sid_string(state, sid); + + /* If the conversion failed, bail out with a failure. */ + if (sid_str != NULL) { + DEBUG(7, ("wb_getgroups_uid2sid_recv SID = %s\n",sid_str)); + /* Ok got the SID now get the groups */ + res = wb_cmd_userdomgroups_send(state, state->service, sid); + NT_STATUS_HAVE_NO_MEMORY(res); + + composite_continue(ctx, res, wb_getgroups_userdomsgroups_recv, state); + } else { + composite_error(state->ctx, NT_STATUS_UNSUCCESSFUL); + } + } +} + +/* + Receive groups and search for uid for the first group +*/ +static void wb_getgroups_userdomsgroups_recv(struct composite_context *ctx) { + struct cmd_getgroups_state *state = + talloc_get_type(ctx->async.private_data, + struct cmd_getgroups_state); + int num_sids; + struct dom_sid **sids; + + DEBUG(5, ("wb_getgroups_userdomsgroups_recv called\n")); + state->ctx->status = wb_cmd_userdomgroups_recv(ctx,state,&num_sids,&sids); + if (!composite_is_ok(state->ctx)) return; + + DEBUG(5, ("wb_getgroups_userdomsgroups_recv %d groups\n",num_sids)); + + state->sids=sids; + state->num_groups=num_sids; + state->current_group=0; + + if(num_sids > 0) { + state->gids = talloc_array(state, struct gid_t *, state->num_groups); + ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]); + composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state); + } else { + composite_done(state->ctx); + } +} + +/* + Receive and uid the previous searched group and request the uid for the next one +*/ +static void cmd_getgroups_recv_gid(struct composite_context *ctx) +{ + struct cmd_getgroups_state *state = + talloc_get_type(ctx->async.private_data, + struct cmd_getgroups_state); + gid_t gid; + char* sid_str; + + DEBUG(5, ("cmd_getgroups_recv_gid called\n")); + + state->ctx->status = wb_sid2gid_recv(ctx, &gid); + if(!composite_is_ok(state->ctx)) return; + + state->gids[state->current_group] = gid; + DEBUG(5, ("cmd_getgroups_recv_gid group %d \n",state->current_group)); + + state->current_group++; + if(state->current_group < state->num_groups ) { + ctx = wb_sid2gid_send(state, state->service, state->sids[state->current_group]); + composite_continue(state->ctx, ctx, cmd_getgroups_recv_gid, state); + } else { + composite_done(state->ctx); + } +} + +/* + Return list of uids when finished +*/ +NTSTATUS wb_cmd_getgroups_recv(struct composite_context *ctx,TALLOC_CTX *mem_ctx,gid_t **groups,uint32_t *num_groups) +{ + NTSTATUS status = composite_wait(ctx); + + DEBUG(5, ("wb_cmd_getgroups_recv called\n")); + + if (NT_STATUS_IS_OK(status)) { + struct cmd_getgroups_state *state = + talloc_get_type(ctx->private_data, + struct cmd_getgroups_state); + *groups = talloc_steal(mem_ctx, state->gids); + *num_groups = state->num_groups; + } + talloc_free(ctx); + return status; +} |