/* * Unix SMB/CIFS implementation. * NetApi Group Support * Copyright (C) Guenther Deschner 2008 * * 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 . */ #include "includes.h" #include "librpc/gen_ndr/libnetapi.h" #include "lib/netapi/netapi.h" #include "lib/netapi/netapi_private.h" #include "lib/netapi/libnetapi.h" /**************************************************************** ****************************************************************/ WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx, struct NetGroupAdd *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name; struct dom_sid2 *domain_sid = NULL; uint32_t rid = 0; struct GROUP_INFO_0 *info0 = NULL; struct GROUP_INFO_1 *info1 = NULL; struct GROUP_INFO_2 *info2 = NULL; struct GROUP_INFO_3 *info3 = NULL; union samr_GroupInfo info; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.buf) { return WERR_INVALID_PARAM; } switch (r->in.level) { case 0: info0 = (struct GROUP_INFO_0 *)r->in.buf; break; case 1: info1 = (struct GROUP_INFO_1 *)r->in.buf; break; case 2: info2 = (struct GROUP_INFO_2 *)r->in.buf; break; case 3: info3 = (struct GROUP_INFO_3 *)r->in.buf; break; default: werr = WERR_UNKNOWN_LEVEL; goto done; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_CREATE_GROUP | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } switch (r->in.level) { case 0: init_lsa_String(&lsa_group_name, info0->grpi0_name); break; case 1: init_lsa_String(&lsa_group_name, info1->grpi1_name); break; case 2: init_lsa_String(&lsa_group_name, info2->grpi2_name); break; case 3: init_lsa_String(&lsa_group_name, info3->grpi3_name); break; } status = rpccli_samr_CreateDomainGroup(pipe_cli, ctx, &domain_handle, &lsa_group_name, SEC_STD_DELETE | SAMR_GROUP_ACCESS_SET_INFO, &group_handle, &rid); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } switch (r->in.level) { case 1: if (info1->grpi1_comment) { init_lsa_String(&info.description, info1->grpi1_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); } break; case 2: if (info2->grpi2_comment) { init_lsa_String(&info.description, info2->grpi2_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto failed; } } if (info2->grpi2_attributes != 0) { info.attributes.attributes = info2->grpi2_attributes; status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); } break; case 3: if (info3->grpi3_comment) { init_lsa_String(&info.description, info3->grpi3_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto failed; } } if (info3->grpi3_attributes != 0) { info.attributes.attributes = info3->grpi3_attributes; status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); } break; default: break; } if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto failed; } werr = WERR_OK; goto done; failed: rpccli_samr_DeleteDomainGroup(pipe_cli, ctx, &group_handle); done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx, struct NetGroupAdd *r) { return NetGroupAdd_r(ctx, r); } /**************************************************************** ****************************************************************/ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx, struct NetGroupDel *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name; struct dom_sid2 *domain_sid = NULL; int i = 0; struct samr_Ids rids; struct samr_Ids types; union samr_GroupInfo *info = NULL; struct samr_RidTypeArray *rid_array = NULL; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.group_name) { return WERR_INVALID_PARAM; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } init_lsa_String(&lsa_group_name, r->in.group_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_group_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; goto done; } status = rpccli_samr_OpenGroup(pipe_cli, ctx, &domain_handle, SEC_STD_DELETE | SAMR_GROUP_ACCESS_GET_MEMBERS | SAMR_GROUP_ACCESS_REMOVE_MEMBER | SAMR_GROUP_ACCESS_ADD_MEMBER | SAMR_GROUP_ACCESS_LOOKUP_INFO, rids.ids[0], &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } #if 0 /* breaks against NT4 */ if (!(info->attributes.attributes & SE_GROUP_ENABLED)) { werr = WERR_ACCESS_DENIED; goto done; } #endif status = rpccli_samr_QueryGroupMember(pipe_cli, ctx, &group_handle, &rid_array); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } { struct lsa_Strings names; struct samr_Ids member_types; status = rpccli_samr_LookupRids(pipe_cli, ctx, &domain_handle, rid_array->count, rid_array->rids, &names, &member_types); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } } for (i=0; i < rid_array->count; i++) { status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx, &group_handle, rid_array->rids[i]); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } } status = rpccli_samr_DeleteDomainGroup(pipe_cli, ctx, &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } ZERO_STRUCT(group_handle); werr = WERR_OK; done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupDel_l(struct libnetapi_ctx *ctx, struct NetGroupDel *r) { return NetGroupDel_r(ctx, r); } /**************************************************************** ****************************************************************/ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx, struct NetGroupSetInfo *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name; struct dom_sid2 *domain_sid = NULL; struct samr_Ids rids; struct samr_Ids types; union samr_GroupInfo info; struct GROUP_INFO_0 *g0; struct GROUP_INFO_1 *g1; struct GROUP_INFO_2 *g2; struct GROUP_INFO_3 *g3; struct GROUP_INFO_1002 *g1002; struct GROUP_INFO_1005 *g1005; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.group_name) { return WERR_INVALID_PARAM; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } init_lsa_String(&lsa_group_name, r->in.group_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_group_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; goto done; } status = rpccli_samr_OpenGroup(pipe_cli, ctx, &domain_handle, SAMR_GROUP_ACCESS_SET_INFO | SAMR_GROUP_ACCESS_LOOKUP_INFO, rids.ids[0], &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } switch (r->in.level) { case 0: g0 = (struct GROUP_INFO_0 *)r->in.buf; init_lsa_String(&info.name, g0->grpi0_name); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFONAME, &info); break; case 1: g1 = (struct GROUP_INFO_1 *)r->in.buf; init_lsa_String(&info.description, g1->grpi1_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); break; case 2: g2 = (struct GROUP_INFO_2 *)r->in.buf; init_lsa_String(&info.description, g2->grpi2_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } info.attributes.attributes = g2->grpi2_attributes; status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); break; case 3: g3 = (struct GROUP_INFO_3 *)r->in.buf; init_lsa_String(&info.description, g3->grpi3_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } info.attributes.attributes = g3->grpi3_attributes; status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); break; case 1002: g1002 = (struct GROUP_INFO_1002 *)r->in.buf; init_lsa_String(&info.description, g1002->grpi1002_comment); status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFODESCRIPTION, &info); break; case 1005: g1005 = (struct GROUP_INFO_1005 *)r->in.buf; info.attributes.attributes = g1005->grpi1005_attributes; status = rpccli_samr_SetGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOATTRIBUTES, &info); break; default: status = NT_STATUS_INVALID_LEVEL; break; } if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } werr = WERR_OK; done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx, struct NetGroupSetInfo *r) { return NetGroupSetInfo_r(ctx, r); } /**************************************************************** ****************************************************************/ static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx, uint32_t level, struct samr_GroupInfoAll *info, struct dom_sid2 *domain_sid, uint32_t rid, uint8_t **buffer) { struct GROUP_INFO_0 info0; struct GROUP_INFO_1 info1; struct GROUP_INFO_2 info2; struct GROUP_INFO_3 info3; struct dom_sid sid; switch (level) { case 0: info0.grpi0_name = info->name.string; *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info0, sizeof(info0)); break; case 1: info1.grpi1_name = info->name.string; info1.grpi1_comment = info->description.string; *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info1, sizeof(info1)); break; case 2: info2.grpi2_name = info->name.string; info2.grpi2_comment = info->description.string; info2.grpi2_group_id = rid; info2.grpi2_attributes = info->attributes; *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info2, sizeof(info2)); break; case 3: if (!sid_compose(&sid, domain_sid, rid)) { return WERR_NOMEM; } info3.grpi3_name = info->name.string; info3.grpi3_comment = info->description.string; info3.grpi3_attributes = info->attributes; info3.grpi3_group_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid); *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3, sizeof(info3)); break; default: return WERR_UNKNOWN_LEVEL; } W_ERROR_HAVE_NO_MEMORY(*buffer); return WERR_OK; } /**************************************************************** ****************************************************************/ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx, struct NetGroupGetInfo *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name; struct dom_sid2 *domain_sid = NULL; struct samr_Ids rids; struct samr_Ids types; union samr_GroupInfo *info = NULL; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.group_name) { return WERR_INVALID_PARAM; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } init_lsa_String(&lsa_group_name, r->in.group_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_group_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_INVALID_DATATYPE; goto done; } status = rpccli_samr_OpenGroup(pipe_cli, ctx, &domain_handle, SAMR_GROUP_ACCESS_LOOKUP_INFO, rids.ids[0], &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx, &group_handle, GROUPINFOALL2, &info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } werr = map_group_info_to_buffer(ctx, r->in.level, &info->all2, domain_sid, rids.ids[0], r->out.buf); if (!W_ERROR_IS_OK(werr)) { goto done; } done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx, struct NetGroupGetInfo *r) { return NetGroupGetInfo_r(ctx, r); } /**************************************************************** ****************************************************************/ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx, struct NetGroupAddUser *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name, lsa_user_name; struct dom_sid2 *domain_sid = NULL; struct samr_Ids rids; struct samr_Ids types; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.group_name) { return WERR_INVALID_PARAM; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } init_lsa_String(&lsa_group_name, r->in.group_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_group_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = WERR_GROUP_NOT_FOUND; goto done; } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_GROUP_NOT_FOUND; goto done; } status = rpccli_samr_OpenGroup(pipe_cli, ctx, &domain_handle, SAMR_GROUP_ACCESS_ADD_MEMBER, rids.ids[0], &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } init_lsa_String(&lsa_user_name, r->in.user_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_user_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = WERR_USER_NOT_FOUND; goto done; } if (types.ids[0] != SID_NAME_USER) { werr = WERR_USER_NOT_FOUND; goto done; } status = rpccli_samr_AddGroupMember(pipe_cli, ctx, &group_handle, rids.ids[0], 7); /* why ? */ if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } werr = WERR_OK; done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx, struct NetGroupAddUser *r) { return NetGroupAddUser_r(ctx, r); } /**************************************************************** ****************************************************************/ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx, struct NetGroupDelUser *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; NTSTATUS status; WERROR werr; POLICY_HND connect_handle, domain_handle, group_handle; struct lsa_String lsa_group_name, lsa_user_name; struct dom_sid2 *domain_sid = NULL; struct samr_Ids rids; struct samr_Ids types; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); ZERO_STRUCT(group_handle); if (!r->in.group_name) { return WERR_INVALID_PARAM; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } init_lsa_String(&lsa_group_name, r->in.group_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_group_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = WERR_GROUP_NOT_FOUND; goto done; } if (types.ids[0] != SID_NAME_DOM_GRP) { werr = WERR_GROUP_NOT_FOUND; goto done; } status = rpccli_samr_OpenGroup(pipe_cli, ctx, &domain_handle, SAMR_GROUP_ACCESS_REMOVE_MEMBER, rids.ids[0], &group_handle); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } init_lsa_String(&lsa_user_name, r->in.user_name); status = rpccli_samr_LookupNames(pipe_cli, ctx, &domain_handle, 1, &lsa_user_name, &rids, &types); if (!NT_STATUS_IS_OK(status)) { werr = WERR_USER_NOT_FOUND; goto done; } if (types.ids[0] != SID_NAME_USER) { werr = WERR_USER_NOT_FOUND; goto done; } status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx, &group_handle, rids.ids[0]); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } werr = WERR_OK; done: if (!cli) { return werr; } if (is_valid_policy_hnd(&group_handle)) { rpccli_samr_Close(pipe_cli, ctx, &group_handle); } if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx, struct NetGroupDelUser *r) { return NetGroupDelUser_r(ctx, r); } /**************************************************************** ****************************************************************/ static WERROR convert_samr_disp_groups_to_GROUP_INFO_0_buffer(TALLOC_CTX *mem_ctx, struct samr_DispInfoFullGroups *groups, uint8_t **buffer) { struct GROUP_INFO_0 *g0; int i; g0 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_0, groups->count); W_ERROR_HAVE_NO_MEMORY(g0); for (i=0; icount; i++) { g0[i].grpi0_name = talloc_strdup(mem_ctx, groups->entries[i].account_name.string); W_ERROR_HAVE_NO_MEMORY(g0[i].grpi0_name); } *buffer = (uint8_t *)talloc_memdup(mem_ctx, g0, sizeof(struct GROUP_INFO_0) * groups->count); W_ERROR_HAVE_NO_MEMORY(*buffer); return WERR_OK; } /**************************************************************** ****************************************************************/ static WERROR convert_samr_disp_groups_to_GROUP_INFO_1_buffer(TALLOC_CTX *mem_ctx, struct samr_DispInfoFullGroups *groups, uint8_t **buffer) { struct GROUP_INFO_1 *g1; int i; g1 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_1, groups->count); W_ERROR_HAVE_NO_MEMORY(g1); for (i=0; icount; i++) { g1[i].grpi1_name = talloc_strdup(mem_ctx, groups->entries[i].account_name.string); g1[i].grpi1_comment = talloc_strdup(mem_ctx, groups->entries[i].description.string); W_ERROR_HAVE_NO_MEMORY(g1[i].grpi1_name); } *buffer = (uint8_t *)talloc_memdup(mem_ctx, g1, sizeof(struct GROUP_INFO_1) * groups->count); W_ERROR_HAVE_NO_MEMORY(*buffer); return WERR_OK; } /**************************************************************** ****************************************************************/ static WERROR convert_samr_disp_groups_to_GROUP_INFO_2_buffer(TALLOC_CTX *mem_ctx, struct samr_DispInfoFullGroups *groups, uint8_t **buffer) { struct GROUP_INFO_2 *g2; int i; g2 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_2, groups->count); W_ERROR_HAVE_NO_MEMORY(g2); for (i=0; icount; i++) { g2[i].grpi2_name = talloc_strdup(mem_ctx, groups->entries[i].account_name.string); g2[i].grpi2_comment = talloc_strdup(mem_ctx, groups->entries[i].description.string); g2[i].grpi2_group_id = groups->entries[i].rid; g2[i].grpi2_attributes = groups->entries[i].acct_flags; W_ERROR_HAVE_NO_MEMORY(g2[i].grpi2_name); } *buffer = (uint8_t *)talloc_memdup(mem_ctx, g2, sizeof(struct GROUP_INFO_2) * groups->count); W_ERROR_HAVE_NO_MEMORY(*buffer); return WERR_OK; } /**************************************************************** ****************************************************************/ static WERROR convert_samr_disp_groups_to_GROUP_INFO_3_buffer(TALLOC_CTX *mem_ctx, struct samr_DispInfoFullGroups *groups, const struct dom_sid *domain_sid, uint8_t **buffer) { struct GROUP_INFO_3 *g3; int i; g3 = TALLOC_ZERO_ARRAY(mem_ctx, struct GROUP_INFO_3, groups->count); W_ERROR_HAVE_NO_MEMORY(g3); for (i=0; icount; i++) { struct dom_sid sid; if (!sid_compose(&sid, domain_sid, groups->entries[i].rid)) { return WERR_NOMEM; } g3[i].grpi3_name = talloc_strdup(mem_ctx, groups->entries[i].account_name.string); g3[i].grpi3_comment = talloc_strdup(mem_ctx, groups->entries[i].description.string); g3[i].grpi3_group_sid = (struct domsid *)sid_dup_talloc(mem_ctx, &sid); g3[i].grpi3_attributes = groups->entries[i].acct_flags; W_ERROR_HAVE_NO_MEMORY(g3[i].grpi3_name); } *buffer = (uint8_t *)talloc_memdup(mem_ctx, g3, sizeof(struct GROUP_INFO_3) * groups->count); W_ERROR_HAVE_NO_MEMORY(*buffer); return WERR_OK; } /**************************************************************** ****************************************************************/ static WERROR convert_samr_disp_groups_to_GROUP_INFO_buffer(TALLOC_CTX *mem_ctx, uint32_t level, struct samr_DispInfoFullGroups *groups, const struct dom_sid *domain_sid, uint32_t *entries_read, uint8_t **buffer) { if (entries_read) { *entries_read = groups->count; } switch (level) { case 0: return convert_samr_disp_groups_to_GROUP_INFO_0_buffer(mem_ctx, groups, buffer); case 1: return convert_samr_disp_groups_to_GROUP_INFO_1_buffer(mem_ctx, groups, buffer); case 2: return convert_samr_disp_groups_to_GROUP_INFO_2_buffer(mem_ctx, groups, buffer); case 3: return convert_samr_disp_groups_to_GROUP_INFO_3_buffer(mem_ctx, groups, domain_sid, buffer); default: return WERR_UNKNOWN_LEVEL; } } /**************************************************************** ****************************************************************/ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx, struct NetGroupEnum *r) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_cli = NULL; struct policy_handle connect_handle; struct dom_sid2 *domain_sid = NULL; struct policy_handle domain_handle; union samr_DispInfo info; union samr_DomainInfo *domain_info = NULL; uint32_t total_size = 0; uint32_t returned_size = 0; NTSTATUS status; WERROR werr, tmp_werr; ZERO_STRUCT(connect_handle); ZERO_STRUCT(domain_handle); switch (r->in.level) { case 0: case 1: case 2: case 3: break; default: return WERR_UNKNOWN_LEVEL; } werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli); if (!W_ERROR_IS_OK(werr)) { goto done; } werr = libnetapi_samr_open_domain(ctx, pipe_cli, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_OPEN_DOMAIN, SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 | SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, &connect_handle, &domain_handle, &domain_sid); if (!W_ERROR_IS_OK(werr)) { goto done; } status = rpccli_samr_QueryDomainInfo(pipe_cli, ctx, &domain_handle, 2, &domain_info); if (!NT_STATUS_IS_OK(status)) { werr = ntstatus_to_werror(status); goto done; } if (r->out.total_entries) { *r->out.total_entries = domain_info->info2.num_groups; } status = rpccli_samr_QueryDisplayInfo2(pipe_cli, ctx, &domain_handle, 3, r->in.resume_handle ? *r->in.resume_handle : 0, (uint32_t)-1, r->in.prefmaxlen, &total_size, &returned_size, &info); werr = ntstatus_to_werror(status); if (NT_STATUS_IS_ERR(status)) { goto done; } if (r->out.resume_handle) { *r->out.resume_handle = info.info3.entries[info.info3.count-1].idx; } tmp_werr = convert_samr_disp_groups_to_GROUP_INFO_buffer(ctx, r->in.level, &info.info3, domain_sid, r->out.entries_read, r->out.buffer); if (!W_ERROR_IS_OK(tmp_werr)) { werr = tmp_werr; goto done; } done: if (!cli) { return werr; } #if 0 if (is_valid_policy_hnd(&domain_handle)) { rpccli_samr_Close(pipe_cli, ctx, &domain_handle); } if (is_valid_policy_hnd(&connect_handle)) { rpccli_samr_Close(pipe_cli, ctx, &connect_handle); } #endif return werr; } /**************************************************************** ****************************************************************/ WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx, struct NetGroupEnum *r) { return NetGroupEnum_r(ctx, r); }