s3: remove POLICY_HND.
[samba.git] / source3 / lib / netapi / group.c
index 5807ad83c12609091ce6372583ff2a3225588080..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;
        }
@@ -313,11 +300,13 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
                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);
@@ -365,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;
@@ -388,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);
 }
 
 /****************************************************************
@@ -397,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;
 
@@ -423,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;
        }
@@ -475,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,
@@ -483,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,
@@ -491,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,
@@ -508,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,
@@ -525,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,
@@ -533,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,
@@ -553,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;
@@ -576,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);
 }
 
 /****************************************************************
@@ -593,6 +568,7 @@ static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
        struct GROUP_INFO_1 info1;
        struct GROUP_INFO_2 info2;
        struct GROUP_INFO_3 info3;
+       struct dom_sid sid;
 
        switch (level) {
                case 0:
@@ -618,13 +594,14 @@ static WERROR map_group_info_to_buffer(TALLOC_CTX *mem_ctx,
 
                        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;
-
-                       if (!sid_compose((struct dom_sid *)&info3.grpi3_group_sid, domain_sid, rid)) {
-                               return WERR_NOMEM;
-                       }
+                       info3.grpi3_group_sid   = (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
 
                        *buffer = (uint8_t *)talloc_memdup(mem_ctx, &info3, sizeof(info3));
 
@@ -644,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);
@@ -664,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;
        }
@@ -717,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;
@@ -752,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);
 }
 
 /****************************************************************
@@ -761,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;
 
@@ -780,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;
        }
@@ -859,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;
@@ -882,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);
 }
 
 /****************************************************************
@@ -891,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;
 
@@ -910,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;
        }
@@ -988,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;
@@ -1011,7 +971,157 @@ 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);
+}
+
+/****************************************************************
+****************************************************************/
+
+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 *)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;
+       }
 }
 
 /****************************************************************
@@ -1020,7 +1130,109 @@ WERROR NetGroupDelUser_l(struct libnetapi_ctx *ctx,
 WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
                      struct NetGroupEnum *r)
 {
-       return WERR_NOT_SUPPORTED;
+       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 = 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;
+       }
+
+       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->general.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 && 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(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);
+               }
+       }
+
+       return werr;
 }
 
 /****************************************************************
@@ -1029,5 +1241,397 @@ WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
 WERROR NetGroupEnum_l(struct libnetapi_ctx *ctx,
                      struct NetGroupEnum *r)
 {
-       return WERR_NOT_SUPPORTED;
+       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);
 }