mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
5e26e94092
Using the standard macro makes it easier to move code into common, as TALLOC_ZERO_ARRAY isn't standard talloc.
1883 lines
45 KiB
C
1883 lines
45 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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"
|
|
#include "rpc_client/rpc_client.h"
|
|
#include "../librpc/gen_ndr/ndr_samr_c.h"
|
|
#include "rpc_client/init_lsa.h"
|
|
#include "../libcli/security/security.h"
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupAdd *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
uint32_t rid = 0;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
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.buffer) {
|
|
return WERR_INVALID_PARAM;
|
|
}
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
info0 = (struct GROUP_INFO_0 *)r->in.buffer;
|
|
break;
|
|
case 1:
|
|
info1 = (struct GROUP_INFO_1 *)r->in.buffer;
|
|
break;
|
|
case 2:
|
|
info2 = (struct GROUP_INFO_2 *)r->in.buffer;
|
|
break;
|
|
case 3:
|
|
info3 = (struct GROUP_INFO_3 *)r->in.buffer;
|
|
break;
|
|
default:
|
|
werr = WERR_UNKNOWN_LEVEL;
|
|
goto done;
|
|
}
|
|
|
|
werr = libnetapi_open_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_CreateDomainGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
&lsa_group_name,
|
|
SEC_STD_DELETE |
|
|
SAMR_GROUP_ACCESS_SET_INFO,
|
|
&group_handle,
|
|
&rid,
|
|
&result);
|
|
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
switch (r->in.level) {
|
|
case 1:
|
|
if (info1->grpi1_comment) {
|
|
init_lsa_String(&info.description,
|
|
info1->grpi1_comment);
|
|
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (info2->grpi2_comment) {
|
|
init_lsa_String(&info.description,
|
|
info2->grpi2_comment);
|
|
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto failed;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
if (info2->grpi2_attributes != 0) {
|
|
info.attributes.attributes = info2->grpi2_attributes;
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
|
|
}
|
|
break;
|
|
case 3:
|
|
if (info3->grpi3_comment) {
|
|
init_lsa_String(&info.description,
|
|
info3->grpi3_comment);
|
|
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto failed;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
if (info3->grpi3_attributes != 0) {
|
|
info.attributes.attributes = info3->grpi3_attributes;
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto failed;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto failed;
|
|
}
|
|
|
|
werr = WERR_OK;
|
|
goto done;
|
|
|
|
failed:
|
|
dcerpc_samr_DeleteDomainGroup(b, talloc_tos(),
|
|
&group_handle, &result);
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupAdd *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAdd);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupDel *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
int i = 0;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
struct samr_Ids rids;
|
|
struct samr_Ids types;
|
|
union samr_GroupInfo *info = NULL;
|
|
struct samr_RidAttrArray *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_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_group_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_DOM_GRP) {
|
|
werr = WERR_INVALID_DATATYPE;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&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,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_QueryGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
#if 0
|
|
/* breaks against NT4 */
|
|
if (!(info->attributes.attributes & SE_GROUP_ENABLED)) {
|
|
werr = WERR_ACCESS_DENIED;
|
|
goto done;
|
|
}
|
|
#endif
|
|
status = dcerpc_samr_QueryGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
&rid_array,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
{
|
|
struct lsa_Strings names;
|
|
struct samr_Ids member_types;
|
|
|
|
status = dcerpc_samr_LookupRids(b, talloc_tos(),
|
|
&domain_handle,
|
|
rid_array->count,
|
|
rid_array->rids,
|
|
&names,
|
|
&member_types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
for (i=0; i < rid_array->count; i++) {
|
|
|
|
status = dcerpc_samr_DeleteGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
rid_array->rids[i],
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
status = dcerpc_samr_DeleteDomainGroup(b, talloc_tos(),
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
ZERO_STRUCT(group_handle);
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupDel *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDel);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupSetInfo *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
struct dcerpc_binding_handle *b = 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_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_group_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_DOM_GRP) {
|
|
werr = WERR_INVALID_DATATYPE;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_SET_INFO |
|
|
SAMR_GROUP_ACCESS_LOOKUP_INFO,
|
|
rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
g0 = (struct GROUP_INFO_0 *)r->in.buffer;
|
|
init_lsa_String(&info.name, g0->grpi0_name);
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFONAME,
|
|
&info,
|
|
&result);
|
|
break;
|
|
case 1:
|
|
g1 = (struct GROUP_INFO_1 *)r->in.buffer;
|
|
init_lsa_String(&info.description, g1->grpi1_comment);
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
break;
|
|
case 2:
|
|
g2 = (struct GROUP_INFO_2 *)r->in.buffer;
|
|
init_lsa_String(&info.description, g2->grpi2_comment);
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
info.attributes.attributes = g2->grpi2_attributes;
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
break;
|
|
case 3:
|
|
g3 = (struct GROUP_INFO_3 *)r->in.buffer;
|
|
init_lsa_String(&info.description, g3->grpi3_comment);
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
info.attributes.attributes = g3->grpi3_attributes;
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
break;
|
|
case 1002:
|
|
g1002 = (struct GROUP_INFO_1002 *)r->in.buffer;
|
|
init_lsa_String(&info.description, g1002->grpi1002_comment);
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFODESCRIPTION,
|
|
&info,
|
|
&result);
|
|
break;
|
|
case 1005:
|
|
g1005 = (struct GROUP_INFO_1005 *)r->in.buffer;
|
|
info.attributes.attributes = g1005->grpi1005_attributes;
|
|
status = dcerpc_samr_SetGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&info,
|
|
&result);
|
|
break;
|
|
default:
|
|
status = NT_STATUS_INVALID_LEVEL;
|
|
break;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupSetInfo *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetInfo);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
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 *)dom_sid_dup(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 rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
struct samr_Ids rids;
|
|
struct samr_Ids types;
|
|
union samr_GroupInfo *info = NULL;
|
|
bool group_info_all = false;
|
|
|
|
ZERO_STRUCT(connect_handle);
|
|
ZERO_STRUCT(domain_handle);
|
|
ZERO_STRUCT(group_handle);
|
|
|
|
if (!r->in.group_name) {
|
|
return WERR_INVALID_PARAM;
|
|
}
|
|
|
|
werr = libnetapi_open_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_group_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_DOM_GRP) {
|
|
werr = WERR_INVALID_DATATYPE;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_LOOKUP_INFO,
|
|
rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_QueryGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOALL2,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
|
|
if (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS)) {
|
|
status = dcerpc_samr_QueryGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOALL,
|
|
&info,
|
|
&result);
|
|
group_info_all = true;
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
werr = map_group_info_to_buffer(ctx, r->in.level,
|
|
group_info_all ? &info->all : &info->all2,
|
|
domain_sid, rids.ids[0],
|
|
r->out.buffer);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupGetInfo *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetInfo);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupAddUser *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name, lsa_user_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
struct dcerpc_binding_handle *b = 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_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_group_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = WERR_GROUPNOTFOUND;
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_DOM_GRP) {
|
|
werr = WERR_GROUPNOTFOUND;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_ADD_MEMBER,
|
|
rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
init_lsa_String(&lsa_user_name, r->in.user_name);
|
|
|
|
status = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_user_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = WERR_USER_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_USER) {
|
|
werr = WERR_USER_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_AddGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
rids.ids[0],
|
|
7, /* why ? */
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupAddUser *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAddUser);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupDelUser *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
NTSTATUS status, result;
|
|
WERROR werr;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_group_name, lsa_user_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
struct dcerpc_binding_handle *b = 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_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_group_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = WERR_GROUPNOTFOUND;
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_DOM_GRP) {
|
|
werr = WERR_GROUPNOTFOUND;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_REMOVE_MEMBER,
|
|
rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
init_lsa_String(&lsa_user_name, r->in.user_name);
|
|
|
|
status = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_user_name,
|
|
&rids,
|
|
&types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = WERR_USER_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
if (types.ids[0] != SID_NAME_USER) {
|
|
werr = WERR_USER_NOT_FOUND;
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_DeleteGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
rids.ids[0],
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupDelUser *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDelUser);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
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; i<groups->count; 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; i<groups->count; 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; i<groups->count; 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; i<groups->count; 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 *)dom_sid_dup(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 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;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
uint32_t total_size = 0;
|
|
uint32_t returned_size = 0;
|
|
|
|
NTSTATUS result = NT_STATUS_OK;
|
|
NTSTATUS status = NT_STATUS_OK;
|
|
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_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_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 = dcerpc_samr_QueryDomainInfo(b, talloc_tos(),
|
|
&domain_handle,
|
|
2,
|
|
&domain_info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
if (r->out.total_entries) {
|
|
*r->out.total_entries = domain_info->general.num_groups;
|
|
}
|
|
|
|
status = dcerpc_samr_QueryDisplayInfo2(b,
|
|
ctx,
|
|
&domain_handle,
|
|
3,
|
|
r->in.resume_handle ?
|
|
*r->in.resume_handle : 0,
|
|
(uint32_t)-1,
|
|
r->in.prefmaxlen,
|
|
&total_size,
|
|
&returned_size,
|
|
&info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
|
|
werr = ntstatus_to_werror(result);
|
|
if (NT_STATUS_IS_ERR(result)) {
|
|
goto done;
|
|
}
|
|
|
|
if (r->out.resume_handle && info.info3.count > 0) {
|
|
*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 last query */
|
|
if (NT_STATUS_IS_OK(result) ||
|
|
NT_STATUS_IS_ERR(result)) {
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupEnum *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupEnum);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupGetUsers_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupGetUsers *r)
|
|
{
|
|
/* FIXME: this call needs to cope with large replies */
|
|
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_account_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
struct samr_Ids group_rids, name_types;
|
|
struct samr_RidAttrArray *rid_array = NULL;
|
|
struct lsa_Strings names;
|
|
struct samr_Ids member_types;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
int i;
|
|
uint32_t entries_read = 0;
|
|
|
|
NTSTATUS status = NT_STATUS_OK;
|
|
NTSTATUS result = NT_STATUS_OK;
|
|
WERROR werr;
|
|
|
|
ZERO_STRUCT(connect_handle);
|
|
ZERO_STRUCT(domain_handle);
|
|
|
|
if (!r->out.buffer) {
|
|
return WERR_INVALID_PARAM;
|
|
}
|
|
|
|
*r->out.buffer = NULL;
|
|
*r->out.entries_read = 0;
|
|
*r->out.total_entries = 0;
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
case 1:
|
|
break;
|
|
default:
|
|
return WERR_UNKNOWN_LEVEL;
|
|
}
|
|
|
|
|
|
werr = libnetapi_open_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_DOMAIN,
|
|
SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
|
|
&connect_handle,
|
|
&domain_handle,
|
|
&domain_sid);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
init_lsa_String(&lsa_account_name, r->in.group_name);
|
|
|
|
status = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_account_name,
|
|
&group_rids,
|
|
&name_types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_GET_MEMBERS,
|
|
group_rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_QueryGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
&rid_array,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_LookupRids(b, talloc_tos(),
|
|
&domain_handle,
|
|
rid_array->count,
|
|
rid_array->rids,
|
|
&names,
|
|
&member_types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
for (i=0; i < names.count; i++) {
|
|
|
|
if (member_types.ids[i] != SID_NAME_USER) {
|
|
continue;
|
|
}
|
|
|
|
status = add_GROUP_USERS_INFO_X_buffer(ctx,
|
|
r->in.level,
|
|
names.names[i].string,
|
|
7,
|
|
r->out.buffer,
|
|
&entries_read);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
*r->out.entries_read = entries_read;
|
|
*r->out.total_entries = entries_read;
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupGetUsers_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupGetUsers *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetUsers);
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupSetUsers_r(struct libnetapi_ctx *ctx,
|
|
struct NetGroupSetUsers *r)
|
|
{
|
|
struct rpc_pipe_client *pipe_cli = NULL;
|
|
struct policy_handle connect_handle, domain_handle, group_handle;
|
|
struct lsa_String lsa_account_name;
|
|
struct dom_sid2 *domain_sid = NULL;
|
|
union samr_GroupInfo *group_info = NULL;
|
|
struct samr_Ids user_rids, name_types;
|
|
struct samr_Ids group_rids, group_types;
|
|
struct samr_RidAttrArray *rid_array = NULL;
|
|
struct lsa_String *lsa_names = NULL;
|
|
struct dcerpc_binding_handle *b = NULL;
|
|
|
|
uint32_t *add_rids = NULL;
|
|
uint32_t *del_rids = NULL;
|
|
size_t num_add_rids = 0;
|
|
size_t num_del_rids = 0;
|
|
|
|
uint32_t *member_rids = NULL;
|
|
|
|
struct GROUP_USERS_INFO_0 *i0 = NULL;
|
|
struct GROUP_USERS_INFO_1 *i1 = NULL;
|
|
|
|
int i, k;
|
|
|
|
NTSTATUS status = NT_STATUS_OK;
|
|
NTSTATUS result = NT_STATUS_OK;
|
|
WERROR werr;
|
|
|
|
ZERO_STRUCT(connect_handle);
|
|
ZERO_STRUCT(domain_handle);
|
|
|
|
if (!r->in.buffer) {
|
|
return WERR_INVALID_PARAM;
|
|
}
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
case 1:
|
|
break;
|
|
default:
|
|
return WERR_UNKNOWN_LEVEL;
|
|
}
|
|
|
|
werr = libnetapi_open_pipe(ctx, r->in.server_name,
|
|
&ndr_table_samr.syntax_id,
|
|
&pipe_cli);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
b = pipe_cli->binding_handle;
|
|
|
|
werr = libnetapi_samr_open_domain(ctx, pipe_cli,
|
|
SAMR_ACCESS_ENUM_DOMAINS |
|
|
SAMR_ACCESS_LOOKUP_DOMAIN,
|
|
SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
|
|
&connect_handle,
|
|
&domain_handle,
|
|
&domain_sid);
|
|
if (!W_ERROR_IS_OK(werr)) {
|
|
goto done;
|
|
}
|
|
|
|
init_lsa_String(&lsa_account_name, r->in.group_name);
|
|
|
|
status = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
1,
|
|
&lsa_account_name,
|
|
&group_rids,
|
|
&group_types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_OpenGroup(b, talloc_tos(),
|
|
&domain_handle,
|
|
SAMR_GROUP_ACCESS_GET_MEMBERS |
|
|
SAMR_GROUP_ACCESS_ADD_MEMBER |
|
|
SAMR_GROUP_ACCESS_REMOVE_MEMBER |
|
|
SAMR_GROUP_ACCESS_LOOKUP_INFO,
|
|
group_rids.ids[0],
|
|
&group_handle,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
status = dcerpc_samr_QueryGroupInfo(b, talloc_tos(),
|
|
&group_handle,
|
|
GROUPINFOATTRIBUTES,
|
|
&group_info,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
i0 = (struct GROUP_USERS_INFO_0 *)r->in.buffer;
|
|
break;
|
|
case 1:
|
|
i1 = (struct GROUP_USERS_INFO_1 *)r->in.buffer;
|
|
break;
|
|
}
|
|
|
|
lsa_names = talloc_array(ctx, struct lsa_String, r->in.num_entries);
|
|
if (!lsa_names) {
|
|
werr = WERR_NOMEM;
|
|
goto done;
|
|
}
|
|
|
|
for (i=0; i < r->in.num_entries; i++) {
|
|
|
|
switch (r->in.level) {
|
|
case 0:
|
|
init_lsa_String(&lsa_names[i], i0->grui0_name);
|
|
i0++;
|
|
break;
|
|
case 1:
|
|
init_lsa_String(&lsa_names[i], i1->grui1_name);
|
|
i1++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
status = dcerpc_samr_LookupNames(b, talloc_tos(),
|
|
&domain_handle,
|
|
r->in.num_entries,
|
|
lsa_names,
|
|
&user_rids,
|
|
&name_types,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
member_rids = user_rids.ids;
|
|
|
|
status = dcerpc_samr_QueryGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
&rid_array,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
|
|
/* add list */
|
|
|
|
for (i=0; i < r->in.num_entries; i++) {
|
|
bool already_member = false;
|
|
for (k=0; k < rid_array->count; k++) {
|
|
if (member_rids[i] == rid_array->rids[k]) {
|
|
already_member = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!already_member) {
|
|
if (!add_rid_to_array_unique(ctx,
|
|
member_rids[i],
|
|
&add_rids, &num_add_rids)) {
|
|
werr = WERR_GENERAL_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* del list */
|
|
|
|
for (k=0; k < rid_array->count; k++) {
|
|
bool keep_member = false;
|
|
for (i=0; i < r->in.num_entries; i++) {
|
|
if (member_rids[i] == rid_array->rids[k]) {
|
|
keep_member = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!keep_member) {
|
|
if (!add_rid_to_array_unique(ctx,
|
|
rid_array->rids[k],
|
|
&del_rids, &num_del_rids)) {
|
|
werr = WERR_GENERAL_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* add list */
|
|
|
|
for (i=0; i < num_add_rids; i++) {
|
|
status = dcerpc_samr_AddGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
add_rids[i],
|
|
7 /* ? */,
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* del list */
|
|
|
|
for (i=0; i < num_del_rids; i++) {
|
|
status = dcerpc_samr_DeleteGroupMember(b, talloc_tos(),
|
|
&group_handle,
|
|
del_rids[i],
|
|
&result);
|
|
if (!NT_STATUS_IS_OK(status)) {
|
|
werr = ntstatus_to_werror(status);
|
|
goto done;
|
|
}
|
|
if (!NT_STATUS_IS_OK(result)) {
|
|
werr = ntstatus_to_werror(result);
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
werr = WERR_OK;
|
|
|
|
done:
|
|
if (is_valid_policy_hnd(&group_handle)) {
|
|
dcerpc_samr_Close(b, talloc_tos(), &group_handle, &result);
|
|
}
|
|
|
|
if (ctx->disable_policy_handle_cache) {
|
|
libnetapi_samr_close_domain_handle(ctx, &domain_handle);
|
|
libnetapi_samr_close_connect_handle(ctx, &connect_handle);
|
|
}
|
|
|
|
return werr;
|
|
}
|
|
|
|
/****************************************************************
|
|
****************************************************************/
|
|
|
|
WERROR NetGroupSetUsers_l(struct libnetapi_ctx *ctx,
|
|
struct NetGroupSetUsers *r)
|
|
{
|
|
LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetUsers);
|
|
}
|