s3: remove POLICY_HND.
[samba.git] / source3 / lib / netapi / group.c
index 6d9ed18b6891acad14521c510b96c99327635072..189902a78eda535a6629e4272f2f7e3ab3a26788 100644 (file)
 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 policy_handle connect_handle, domain_handle, group_handle;
        struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
        uint32_t rid = 0;
@@ -49,34 +48,31 @@ WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
        ZERO_STRUCT(domain_handle);
        ZERO_STRUCT(group_handle);
 
-       if (!r->in.buf) {
+       if (!r->in.buffer) {
                return WERR_INVALID_PARAM;
        }
 
        switch (r->in.level) {
                case 0:
-                       info0 = (struct GROUP_INFO_0 *)r->in.buf;
+                       info0 = (struct GROUP_INFO_0 *)r->in.buffer;
                        break;
                case 1:
-                       info1 = (struct GROUP_INFO_1 *)r->in.buf;
+                       info1 = (struct GROUP_INFO_1 *)r->in.buffer;
                        break;
                case 2:
-                       info2 = (struct GROUP_INFO_2 *)r->in.buf;
+                       info2 = (struct GROUP_INFO_2 *)r->in.buffer;
                        break;
                case 3:
-                       info3 = (struct GROUP_INFO_3 *)r->in.buf;
+                       info3 = (struct GROUP_INFO_3 *)r->in.buffer;
                        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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -197,18 +193,13 @@ WERROR NetGroupAdd_r(struct libnetapi_ctx *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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -220,7 +211,7 @@ WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
                     struct NetGroupAdd *r)
 {
-       return NetGroupAdd_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAdd);
 }
 
 /****************************************************************
@@ -229,11 +220,10 @@ WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
 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 policy_handle connect_handle, domain_handle, group_handle;
        struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
        int i = 0;
@@ -251,12 +241,9 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
                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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -367,18 +354,13 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
        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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -390,7 +372,7 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
                     struct NetGroupDel *r)
 {
-       return NetGroupDel_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDel);
 }
 
 /****************************************************************
@@ -399,11 +381,10 @@ WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
 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 policy_handle connect_handle, domain_handle, group_handle;
        struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
 
@@ -425,12 +406,9 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -477,7 +455,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
 
        switch (r->in.level) {
                case 0:
-                       g0 = (struct GROUP_INFO_0 *)r->in.buf;
+                       g0 = (struct GROUP_INFO_0 *)r->in.buffer;
                        init_lsa_String(&info.name, g0->grpi0_name);
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -485,7 +463,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                                                          &info);
                        break;
                case 1:
-                       g1 = (struct GROUP_INFO_1 *)r->in.buf;
+                       g1 = (struct GROUP_INFO_1 *)r->in.buffer;
                        init_lsa_String(&info.description, g1->grpi1_comment);
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -493,7 +471,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                                                          &info);
                        break;
                case 2:
-                       g2 = (struct GROUP_INFO_2 *)r->in.buf;
+                       g2 = (struct GROUP_INFO_2 *)r->in.buffer;
                        init_lsa_String(&info.description, g2->grpi2_comment);
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -510,7 +488,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                                                          &info);
                        break;
                case 3:
-                       g3 = (struct GROUP_INFO_3 *)r->in.buf;
+                       g3 = (struct GROUP_INFO_3 *)r->in.buffer;
                        init_lsa_String(&info.description, g3->grpi3_comment);
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -527,7 +505,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                                                          &info);
                        break;
                case 1002:
-                       g1002 = (struct GROUP_INFO_1002 *)r->in.buf;
+                       g1002 = (struct GROUP_INFO_1002 *)r->in.buffer;
                        init_lsa_String(&info.description, g1002->grpi1002_comment);
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -535,7 +513,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
                                                          &info);
                        break;
                case 1005:
-                       g1005 = (struct GROUP_INFO_1005 *)r->in.buf;
+                       g1005 = (struct GROUP_INFO_1005 *)r->in.buffer;
                        info.attributes.attributes = g1005->grpi1005_attributes;
                        status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
                                                          &group_handle,
@@ -555,18 +533,13 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
        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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -578,7 +551,7 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupSetInfo_l(struct libnetapi_ctx *ctx,
                         struct NetGroupSetInfo *r)
 {
-       return NetGroupSetInfo_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupSetInfo);
 }
 
 /****************************************************************
@@ -648,17 +621,17 @@ static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
 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 policy_handle 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;
+       bool group_info_all = false;
 
        ZERO_STRUCT(connect_handle);
        ZERO_STRUCT(domain_handle);
@@ -668,12 +641,9 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
                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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -721,30 +691,34 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
                                            &group_handle,
                                            GROUPINFOALL2,
                                            &info);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)) {
+               status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+                                                   &group_handle,
+                                                   GROUPINFOALL,
+                                                   &info);
+               group_info_all = true;
+       }
+
        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);
+                                       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 (!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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -756,7 +730,7 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
                         struct NetGroupGetInfo *r)
 {
-       return NetGroupGetInfo_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupGetInfo);
 }
 
 /****************************************************************
@@ -765,11 +739,10 @@ WERROR NetGroupGetInfo_l(struct libnetapi_ctx *ctx,
 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 policy_handle connect_handle, domain_handle, group_handle;
        struct lsa_String lsa_group_name, lsa_user_name;
        struct dom_sid2 *domain_sid = NULL;
 
@@ -784,12 +757,9 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
                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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -863,18 +833,13 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
        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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -886,7 +851,7 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
                         struct NetGroupAddUser *r)
 {
-       return NetGroupAddUser_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupAddUser);
 }
 
 /****************************************************************
@@ -895,11 +860,10 @@ WERROR NetGroupAddUser_l(struct libnetapi_ctx *ctx,
 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 policy_handle connect_handle, domain_handle, group_handle;
        struct lsa_String lsa_group_name, lsa_user_name;
        struct dom_sid2 *domain_sid = NULL;
 
@@ -914,12 +878,9 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
                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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -992,18 +953,13 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
        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);
+
+       if (ctx->disable_policy_handle_cache) {
+               libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+               libnetapi_samr_close_connect_handle(ctx, &connect_handle);
        }
 
        return werr;
@@ -1015,7 +971,7 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
                         struct NetGroupDelUser *r)
 {
-       return NetGroupDelUser_r(ctx, r);
+       LIBNETAPI_REDIRECT_TO_LOCALHOST(ctx, r, NetGroupDelUser);
 }
 
 /****************************************************************
@@ -1174,7 +1130,6 @@ static WERROR convert_samr_disp_groups_to_GROUP_INFO_buffer(TALLOC_CTX *mem_ctx,
 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;
@@ -1185,7 +1140,7 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
        uint32_t total_size = 0;
        uint32_t returned_size = 0;
 
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_OK;
        WERROR werr, tmp_werr;
 
        ZERO_STRUCT(connect_handle);
@@ -1201,12 +1156,9 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
                        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);
+       werr = libnetapi_open_pipe(ctx, r->in.server_name,
+                                  &ndr_table_samr.syntax_id,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -1234,7 +1186,7 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
        }
 
        if (r->out.total_entries) {
-               *r->out.total_entries = domain_info->info2.num_groups;
+               *r->out.total_entries = domain_info->general.num_groups;
        }
 
        status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
@@ -1253,7 +1205,7 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
                goto done;
        }
 
-       if (r->out.resume_handle) {
+       if (r->out.resume_handle && info.info3.count > 0) {
                *r->out.resume_handle =
                        info.info3.entries[info.info3.count-1].idx;
        }
@@ -1270,17 +1222,16 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
        }
 
  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);
+       /* if last query */
+       if (NT_STATUS_IS_OK(status) ||
+           NT_STATUS_IS_ERR(status)) {
+
+               if (ctx->disable_policy_handle_cache) {
+                       libnetapi_samr_close_domain_handle(ctx, &domain_handle);
+                       libnetapi_samr_close_connect_handle(ctx, &connect_handle);
+               }
        }
-#endif
+
        return werr;
 }
 
@@ -1290,5 +1241,397 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
                      struct NetGroupEnum *r)
 {
-       return NetGroupEnum_r(ctx, 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_RidTypeArray *rid_array = NULL;
+       struct lsa_Strings names;
+       struct samr_Ids member_types;
+
+       int i;
+       uint32_t entries_read = 0;
+
+       NTSTATUS status = 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;
+
+       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;
+       }
+
+       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_account_name, r->in.group_name);
+
+       status = rpccli_samr_LookupNames(pipe_cli, ctx,
+                                        &domain_handle,
+                                        1,
+                                        &lsa_account_name,
+                                        &group_rids,
+                                        &name_types);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+                                      &domain_handle,
+                                      SAMR_GROUP_ACCESS_GET_MEMBERS,
+                                      group_rids.ids[0],
+                                      &group_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
+                                             &group_handle,
+                                             &rid_array);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       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 < 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;
+               }
+       }
+
+       if (r->out.entries_read) {
+               *r->out.entries_read = entries_read;
+       }
+
+       if (r->out.total_entries) {
+               *r->out.total_entries = entries_read;
+       }
+
+       werr = WERR_OK;
+
+ done:
+       if (is_valid_policy_hnd(&group_handle)) {
+               rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+       }
+
+       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_RidTypeArray *rid_array = NULL;
+       struct lsa_String *lsa_names = 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;
+       size_t num_member_rids = 0;
+
+       struct GROUP_USERS_INFO_0 *i0 = NULL;
+       struct GROUP_USERS_INFO_1 *i1 = NULL;
+
+       int i, k;
+
+       NTSTATUS status = 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;
+       }
+
+       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_account_name, r->in.group_name);
+
+       status = rpccli_samr_LookupNames(pipe_cli, ctx,
+                                        &domain_handle,
+                                        1,
+                                        &lsa_account_name,
+                                        &group_rids,
+                                        &group_types);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_OpenGroup(pipe_cli, ctx,
+                                      &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);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
+                                           &group_handle,
+                                           GROUPINFOATTRIBUTES,
+                                           &group_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               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 = rpccli_samr_LookupNames(pipe_cli, ctx,
+                                        &domain_handle,
+                                        r->in.num_entries,
+                                        lsa_names,
+                                        &user_rids,
+                                        &name_types);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       member_rids = user_rids.ids;
+       num_member_rids = user_rids.count;
+
+       status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
+                                             &group_handle,
+                                             &rid_array);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               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 = rpccli_samr_AddGroupMember(pipe_cli, ctx,
+                                                   &group_handle,
+                                                   add_rids[i],
+                                                   7 /* ? */);
+               if (!NT_STATUS_IS_OK(status)) {
+                       werr = ntstatus_to_werror(status);
+                       goto done;
+               }
+       }
+
+       /* del list */
+
+       for (i=0; i < num_del_rids; i++) {
+               status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
+                                                      &group_handle,
+                                                      del_rids[i]);
+               if (!NT_STATUS_IS_OK(status)) {
+                       werr = ntstatus_to_werror(status);
+                       goto done;
+               }
+       }
+
+       werr = WERR_OK;
+
+ done:
+       if (is_valid_policy_hnd(&group_handle)) {
+               rpccli_samr_Close(pipe_cli, ctx, &group_handle);
+       }
+
+       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);
 }