Fix bug #6089 - Winbind samr_OpenDomain not possible with Samba 3.2.6+
[samba.git] / source / lib / netapi / group.c
index d46d2e61352284efdb28314699bc407b33c1841e..6dcf2e13f38da554f344d0f833bb53e75dd1bc86 100644 (file)
@@ -34,114 +34,60 @@ WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name;
+       struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
        uint32_t rid = 0;
-       bool domain_found = true;
-       int i;
-       struct GROUP_INFO_0 *info0;
-       struct GROUP_INFO_1 *info1;
-       struct GROUP_INFO_2 *info2;
-       struct GROUP_INFO_3 *info3;
+
+       struct GROUP_INFO_0 *info0 = NULL;
+       struct GROUP_INFO_1 *info1 = NULL;
+       struct GROUP_INFO_2 *info2 = NULL;
+       struct GROUP_INFO_3 *info3 = NULL;
        union samr_GroupInfo info;
 
        ZERO_STRUCT(connect_handle);
        ZERO_STRUCT(domain_handle);
        ZERO_STRUCT(group_handle);
 
-       if (!r->in.buf) {
+       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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_CREATE_GROUP |
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_CREATE_GROUP |
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -256,11 +202,10 @@ WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
        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;
@@ -272,7 +217,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);
 }
 
 /****************************************************************
@@ -285,15 +230,10 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name;
+       struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
-       bool domain_found = true;
-       int i;
+       int i = 0;
 
        struct samr_Ids rids;
        struct samr_Ids types;
@@ -308,71 +248,22 @@ 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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -417,11 +308,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);
@@ -476,11 +369,10 @@ WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
        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;
@@ -492,7 +384,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);
 }
 
 /****************************************************************
@@ -505,15 +397,9 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name;
+       struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
-       bool domain_found = true;
-       int i;
 
        struct samr_Ids rids;
        struct samr_Ids types;
@@ -533,71 +419,22 @@ 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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -632,7 +469,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,
@@ -640,7 +477,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,
@@ -648,7 +485,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,
@@ -665,7 +502,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,
@@ -682,7 +519,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,
@@ -690,7 +527,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,
@@ -717,11 +554,10 @@ WERROR NetGroupSetInfo_r(struct libnetapi_ctx *ctx,
        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;
@@ -733,7 +569,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);
 }
 
 /****************************************************************
@@ -750,6 +586,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:
@@ -775,13 +612,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));
 
@@ -805,19 +643,14 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name;
+       struct lsa_String lsa_group_name;
        struct dom_sid2 *domain_sid = NULL;
-       bool domain_found = true;
-       int i;
 
        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);
@@ -827,71 +660,22 @@ 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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -927,14 +711,23 @@ 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;
        }
@@ -946,11 +739,10 @@ WERROR NetGroupGetInfo_r(struct libnetapi_ctx *ctx,
        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;
@@ -962,7 +754,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);
 }
 
 /****************************************************************
@@ -975,15 +767,9 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name, lsa_user_name;
+       struct lsa_String lsa_group_name, lsa_user_name;
        struct dom_sid2 *domain_sid = NULL;
-       bool domain_found = true;
-       int i;
 
        struct samr_Ids rids;
        struct samr_Ids types;
@@ -996,71 +782,22 @@ 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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -1129,11 +866,10 @@ WERROR NetGroupAddUser_r(struct libnetapi_ctx *ctx,
        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;
@@ -1145,7 +881,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);
 }
 
 /****************************************************************
@@ -1158,15 +894,9 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
        struct rpc_pipe_client *pipe_cli = NULL;
        NTSTATUS status;
        WERROR werr;
-       uint32_t resume_handle = 0;
-       uint32_t num_entries = 0;
        POLICY_HND connect_handle, domain_handle, group_handle;
-       struct samr_SamArray *sam = NULL;
-       const char *domain_name = NULL;
-       struct lsa_String lsa_domain_name, lsa_group_name, lsa_user_name;
+       struct lsa_String lsa_group_name, lsa_user_name;
        struct dom_sid2 *domain_sid = NULL;
-       bool domain_found = true;
-       int i;
 
        struct samr_Ids rids;
        struct samr_Ids types;
@@ -1179,71 +909,22 @@ 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,
+                                  &cli,
+                                  &pipe_cli);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
-       status = rpccli_try_samr_connects(pipe_cli, ctx,
+       werr = libnetapi_samr_open_domain(ctx, pipe_cli,
                                          SAMR_ACCESS_ENUM_DOMAINS |
-                                         SAMR_ACCESS_OPEN_DOMAIN,
-                                         &connect_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
-                                        &connect_handle,
-                                        &resume_handle,
-                                        &sam,
-                                        0xffffffff,
-                                        &num_entries);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       for (i=0; i<num_entries; i++) {
-
-               domain_name = sam->entries[i].name.string;
-
-               if (strequal(domain_name, builtin_domain_name())) {
-                       continue;
-               }
-
-               domain_found = true;
-               break;
-       }
-
-       if (!domain_found) {
-               werr = WERR_NO_SUCH_DOMAIN;
-               goto done;
-       }
-
-       init_lsa_String(&lsa_domain_name, domain_name);
-
-       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         SAMR_ACCESS_LOOKUP_DOMAIN,
+                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
                                          &connect_handle,
-                                         &lsa_domain_name,
+                                         &domain_handle,
                                          &domain_sid);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
-               goto done;
-       }
-
-       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
-                                       &connect_handle,
-                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
-                                       domain_sid,
-                                       &domain_handle);
-       if (!NT_STATUS_IS_OK(status)) {
-               werr = ntstatus_to_werror(status);
+       if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
 
@@ -1311,11 +992,10 @@ WERROR NetGroupDelUser_r(struct libnetapi_ctx *ctx,
        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;
@@ -1327,5 +1007,681 @@ 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;
+       }
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetGroupEnum_r(struct libnetapi_ctx *ctx,
+                     struct NetGroupEnum *r)
+{
+       struct cli_state *cli = NULL;
+       struct rpc_pipe_client *pipe_cli = NULL;
+       struct policy_handle connect_handle;
+       struct dom_sid2 *domain_sid = NULL;
+       struct policy_handle domain_handle;
+       union samr_DispInfo info;
+       union samr_DomainInfo *domain_info = NULL;
+
+       uint32_t total_size = 0;
+       uint32_t returned_size = 0;
+
+       NTSTATUS status = 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,
+                                  &cli,
+                                  &pipe_cli);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       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 = rpccli_samr_QueryDomainInfo(pipe_cli, ctx,
+                                            &domain_handle,
+                                            2,
+                                            &domain_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       if (r->out.total_entries) {
+               *r->out.total_entries = domain_info->info2.num_groups;
+       }
+
+       status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
+                                              ctx,
+                                              &domain_handle,
+                                              3,
+                                              r->in.resume_handle ?
+                                              *r->in.resume_handle : 0,
+                                              (uint32_t)-1,
+                                              r->in.prefmaxlen,
+                                              &total_size,
+                                              &returned_size,
+                                              &info);
+       werr = ntstatus_to_werror(status);
+       if (NT_STATUS_IS_ERR(status)) {
+               goto done;
+       }
+
+       if (r->out.resume_handle && 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 (!cli) {
+               return werr;
+       }
+
+       /* 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;
+}
+
+/****************************************************************
+****************************************************************/
+
+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 cli_state *cli = NULL;
+       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;
+       *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,
+                                  &cli,
+                                  &pipe_cli);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       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 = 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;
+               }
+       }
+
+       *r->out.entries_read = entries_read;
+       *r->out.total_entries = entries_read;
+
+       werr = WERR_OK;
+
+ done:
+       if (!cli) {
+               return werr;
+       }
+
+       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 cli_state *cli = NULL;
+       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,
+                                  &cli,
+                                  &pipe_cli);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
+
+       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 = 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 (!cli) {
+               return werr;
+       }
+
+       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);
 }