s3-winbind: Added a common rpc_lookup_groupmem function.
[samba.git] / source3 / winbindd / winbindd_rpc.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * Winbind rpc backend functions
5  *
6  * Copyright (c) 2000-2003 Tim Potter
7  * Copyright (c) 2001      Andrew Tridgell
8  * Copyright (c) 2005      Volker Lendecke
9  * Copyright (c) 2008      Guenther Deschner (pidl conversion)
10  * Copyright (c) 2010      Andreas Schneider <asn@samba.org>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25
26 #include "includes.h"
27 #include "winbindd.h"
28 #include "winbindd_rpc.h"
29
30 #include "librpc/gen_ndr/cli_samr.h"
31 #include "librpc/gen_ndr/srv_samr.h"
32 #include "librpc/gen_ndr/cli_lsa.h"
33 #include "librpc/gen_ndr/srv_lsa.h"
34 #include "rpc_client/cli_samr.h"
35 #include "rpc_client/cli_lsarpc.h"
36
37 /* Query display info for a domain */
38 NTSTATUS rpc_query_user_list(TALLOC_CTX *mem_ctx,
39                              struct rpc_pipe_client *samr_pipe,
40                              struct policy_handle *samr_policy,
41                              const struct dom_sid *domain_sid,
42                              uint32_t *pnum_info,
43                              struct wbint_userinfo **pinfo)
44 {
45         struct wbint_userinfo *info = NULL;
46         uint32_t num_info = 0;
47         uint32_t loop_count = 0;
48         uint32_t start_idx = 0;
49         uint32_t i = 0;
50         NTSTATUS status;
51
52         *pnum_info = 0;
53
54         do {
55                 uint32_t j;
56                 uint32_t num_dom_users;
57                 uint32_t max_entries, max_size;
58                 uint32_t total_size, returned_size;
59                 union samr_DispInfo disp_info;
60
61                 get_query_dispinfo_params(loop_count,
62                                           &max_entries,
63                                           &max_size);
64
65                 status = rpccli_samr_QueryDisplayInfo(samr_pipe,
66                                                       mem_ctx,
67                                                       samr_policy,
68                                                       1, /* level */
69                                                       start_idx,
70                                                       max_entries,
71                                                       max_size,
72                                                       &total_size,
73                                                       &returned_size,
74                                                       &disp_info);
75                 if (!NT_STATUS_IS_OK(status)) {
76                         if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
77                                 return status;
78                         }
79                 }
80
81                 /* increment required start query values */
82                 start_idx += disp_info.info1.count;
83                 loop_count++;
84                 num_dom_users = disp_info.info1.count;
85
86                 num_info += num_dom_users;
87
88                 info = TALLOC_REALLOC_ARRAY(mem_ctx,
89                                             info,
90                                             struct wbint_userinfo,
91                                             num_info);
92                 if (info == NULL) {
93                         return NT_STATUS_NO_MEMORY;
94                 }
95
96                 for (j = 0; j < num_dom_users; i++, j++) {
97                         uint32_t rid = disp_info.info1.entries[j].rid;
98                         struct samr_DispEntryGeneral *src;
99                         struct wbint_userinfo *dst;
100
101                         src = &(disp_info.info1.entries[j]);
102                         dst = &(info[i]);
103
104                         dst->acct_name = talloc_strdup(info,
105                                                        src->account_name.string);
106                         if (dst->acct_name == NULL) {
107                                 return NT_STATUS_NO_MEMORY;
108                         }
109
110                         dst->full_name = talloc_strdup(info, src->full_name.string);
111                         if (dst->full_name == NULL) {
112                                 return NT_STATUS_NO_MEMORY;
113                         }
114
115                         dst->homedir = NULL;
116                         dst->shell = NULL;
117
118                         sid_compose(&dst->user_sid, domain_sid, rid);
119
120                         /* For the moment we set the primary group for
121                            every user to be the Domain Users group.
122                            There are serious problems with determining
123                            the actual primary group for large domains.
124                            This should really be made into a 'winbind
125                            force group' smb.conf parameter or
126                            something like that. */
127                         sid_compose(&dst->group_sid, domain_sid,
128                                     DOMAIN_RID_USERS);
129                 }
130         } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
131
132         *pnum_info = num_info;
133         *pinfo = info;
134
135         return NT_STATUS_OK;
136 }
137
138 /* List all domain groups */
139 NTSTATUS rpc_enum_dom_groups(TALLOC_CTX *mem_ctx,
140                              struct rpc_pipe_client *samr_pipe,
141                              struct policy_handle *samr_policy,
142                              uint32_t *pnum_info,
143                              struct acct_info **pinfo)
144 {
145         struct acct_info *info = NULL;
146         uint32_t start = 0;
147         uint32_t num_info = 0;
148         NTSTATUS status;
149
150         *pnum_info = 0;
151
152         do {
153                 struct samr_SamArray *sam_array = NULL;
154                 uint32_t count = 0;
155                 uint32_t g;
156
157                 /* start is updated by this call. */
158                 status = rpccli_samr_EnumDomainGroups(samr_pipe,
159                                                       mem_ctx,
160                                                       samr_policy,
161                                                       &start,
162                                                       &sam_array,
163                                                       0xFFFF, /* buffer size? */
164                                                       &count);
165                 if (!NT_STATUS_IS_OK(status)) {
166                         if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
167                                 DEBUG(2,("query_user_list: failed to enum domain groups: %s\n",
168                                          nt_errstr(status)));
169                                 return status;
170                         }
171                 }
172
173                 info = TALLOC_REALLOC_ARRAY(mem_ctx,
174                                             info,
175                                             struct acct_info,
176                                             num_info + count);
177                 if (info == NULL) {
178                         return NT_STATUS_NO_MEMORY;
179                 }
180
181                 for (g = 0; g < count; g++) {
182                         fstrcpy(info[num_info + g].acct_name,
183                                 sam_array->entries[g].name.string);
184
185                         info[num_info + g].rid = sam_array->entries[g].idx;
186                 }
187
188                 num_info += count;
189         } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
190
191         *pnum_info = num_info;
192         *pinfo = info;
193
194         return NT_STATUS_OK;
195 }
196
197 NTSTATUS rpc_enum_local_groups(TALLOC_CTX *mem_ctx,
198                                struct rpc_pipe_client *samr_pipe,
199                                struct policy_handle *samr_policy,
200                                uint32_t *pnum_info,
201                                struct acct_info **pinfo)
202 {
203         struct acct_info *info = NULL;
204         uint32_t num_info = 0;
205         NTSTATUS status;
206
207         *pnum_info = 0;
208
209         do {
210                 struct samr_SamArray *sam_array = NULL;
211                 uint32_t count = 0;
212                 uint32_t start = num_info;
213                 uint32_t g;
214
215                 status = rpccli_samr_EnumDomainAliases(samr_pipe,
216                                                        mem_ctx,
217                                                        samr_policy,
218                                                        &start,
219                                                        &sam_array,
220                                                        0xFFFF, /* buffer size? */
221                                                        &count);
222                 if (!NT_STATUS_IS_OK(status)) {
223                         if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
224                                 return status;
225                         }
226                 }
227
228                 info = TALLOC_REALLOC_ARRAY(mem_ctx,
229                                             info,
230                                             struct acct_info,
231                                             num_info + count);
232                 if (info == NULL) {
233                         return  NT_STATUS_NO_MEMORY;
234                 }
235
236                 for (g = 0; g < count; g++) {
237                         fstrcpy(info[num_info + g].acct_name,
238                                 sam_array->entries[g].name.string);
239                         info[num_info + g].rid = sam_array->entries[g].idx;
240                 }
241
242                 num_info += count;
243         } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
244
245         *pnum_info = num_info;
246         *pinfo = info;
247
248         return NT_STATUS_OK;
249 }
250
251 /* convert a single name to a sid in a domain */
252 NTSTATUS rpc_name_to_sid(TALLOC_CTX *mem_ctx,
253                          struct rpc_pipe_client *lsa_pipe,
254                          struct policy_handle *lsa_policy,
255                          const char *domain_name,
256                          const char *name,
257                          uint32_t flags,
258                          struct dom_sid *sid,
259                          enum lsa_SidType *type)
260 {
261         enum lsa_SidType *types = NULL;
262         struct dom_sid *sids = NULL;
263         char *full_name = NULL;
264         char *mapped_name = NULL;
265         NTSTATUS status;
266
267         if (name == NULL || name[0] == '\0') {
268                 full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
269         } else if (domain_name == NULL || domain_name[0] == '\0') {
270                 full_name = talloc_asprintf(mem_ctx, "%s", name);
271         } else {
272                 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
273         }
274
275         if (full_name == NULL) {
276                 return NT_STATUS_NO_MEMORY;
277         }
278
279         status = normalize_name_unmap(mem_ctx, full_name, &mapped_name);
280         /* Reset the full_name pointer if we mapped anything */
281         if (NT_STATUS_IS_OK(status) ||
282             NT_STATUS_EQUAL(status, NT_STATUS_FILE_RENAMED)) {
283                 full_name = mapped_name;
284         }
285
286         DEBUG(3,("name_to_sid: %s for domain %s\n",
287                  full_name ? full_name : "", domain_name ));
288
289         /*
290          * We don't run into deadlocks here, cause winbind_off() is
291          * called in the main function.
292          */
293         status = rpccli_lsa_lookup_names(lsa_pipe,
294                                          mem_ctx,
295                                          lsa_policy,
296                                          1, /* num_names */
297                                          (const char **) &full_name,
298                                          NULL, /* domains */
299                                          1, /* level */
300                                          &sids,
301                                          &types);
302         if (!NT_STATUS_IS_OK(status)) {
303                 DEBUG(2,("name_to_sid: failed to lookup name: %s\n",
304                         nt_errstr(status)));
305                 return status;
306         }
307
308         sid_copy(sid, &sids[0]);
309         *type = types[0];
310
311         return NT_STATUS_OK;
312 }
313
314 /* Convert a domain SID to a user or group name */
315 NTSTATUS rpc_sid_to_name(TALLOC_CTX *mem_ctx,
316                          struct rpc_pipe_client *lsa_pipe,
317                          struct policy_handle *lsa_policy,
318                          struct winbindd_domain *domain,
319                          const struct dom_sid *sid,
320                          char **pdomain_name,
321                          char **pname,
322                          enum lsa_SidType *ptype)
323 {
324         char *mapped_name = NULL;
325         char **domains = NULL;
326         char **names = NULL;
327         enum lsa_SidType *types = NULL;
328         NTSTATUS map_status;
329         NTSTATUS status;
330
331         status = rpccli_lsa_lookup_sids(lsa_pipe,
332                                         mem_ctx,
333                                         lsa_policy,
334                                         1, /* num_sids */
335                                         sid,
336                                         &domains,
337                                         &names,
338                                         &types);
339         if (!NT_STATUS_IS_OK(status)) {
340                 DEBUG(2,("sid_to_name: failed to lookup sids: %s\n",
341                         nt_errstr(status)));
342                 return status;
343         }
344
345         *ptype = (enum lsa_SidType) types[0];
346
347         map_status = normalize_name_map(mem_ctx,
348                                         domain,
349                                         *pname,
350                                         &mapped_name);
351         if (NT_STATUS_IS_OK(map_status) ||
352             NT_STATUS_EQUAL(map_status, NT_STATUS_FILE_RENAMED)) {
353                 *pname = talloc_strdup(mem_ctx, mapped_name);
354                 DEBUG(5,("returning mapped name -- %s\n", *pname));
355         } else {
356                 *pname = talloc_strdup(mem_ctx, names[0]);
357         }
358         if (*pname == NULL) {
359                 return NT_STATUS_NO_MEMORY;
360         }
361
362         *pdomain_name = talloc_strdup(mem_ctx, domains[0]);
363         if (*pdomain_name == NULL) {
364                 return NT_STATUS_NO_MEMORY;
365         }
366
367         return NT_STATUS_OK;
368 }
369
370 /* Convert a bunch of rids to user or group names */
371 NTSTATUS rpc_rids_to_names(TALLOC_CTX *mem_ctx,
372                            struct rpc_pipe_client *lsa_pipe,
373                            struct policy_handle *lsa_policy,
374                            struct winbindd_domain *domain,
375                            const struct dom_sid *sid,
376                            uint32_t *rids,
377                            size_t num_rids,
378                            char **pdomain_name,
379                            char ***pnames,
380                            enum lsa_SidType **ptypes)
381 {
382         enum lsa_SidType *types = NULL;
383         char *domain_name = NULL;
384         char **domains = NULL;
385         char **names = NULL;
386         struct dom_sid *sids;
387         size_t i;
388         NTSTATUS status;
389
390         if (num_rids > 0) {
391                 sids = TALLOC_ARRAY(mem_ctx, struct dom_sid, num_rids);
392                 if (sids == NULL) {
393                         return NT_STATUS_NO_MEMORY;
394                 }
395         } else {
396                 sids = NULL;
397         }
398
399         for (i = 0; i < num_rids; i++) {
400                 if (!sid_compose(&sids[i], sid, rids[i])) {
401                         return NT_STATUS_INTERNAL_ERROR;
402                 }
403         }
404
405         status = rpccli_lsa_lookup_sids(lsa_pipe,
406                                         mem_ctx,
407                                         lsa_policy,
408                                         num_rids,
409                                         sids,
410                                         &domains,
411                                         &names,
412                                         &types);
413         if (!NT_STATUS_IS_OK(status) &&
414             !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
415                 DEBUG(2,("rids_to_names: failed to lookup sids: %s\n",
416                         nt_errstr(status)));
417                 return status;
418         }
419
420         for (i = 0; i < num_rids; i++) {
421                 char *mapped_name = NULL;
422                 NTSTATUS map_status;
423
424                 if (types[i] != SID_NAME_UNKNOWN) {
425                         map_status = normalize_name_map(mem_ctx,
426                                                         domain,
427                                                         names[i],
428                                                         &mapped_name);
429                         if (NT_STATUS_IS_OK(map_status) ||
430                             NT_STATUS_EQUAL(map_status, NT_STATUS_FILE_RENAMED)) {
431                                 TALLOC_FREE(names[i]);
432                                 names[i] = talloc_strdup(names, mapped_name);
433                                 if (names[i] == NULL) {
434                                         return NT_STATUS_NO_MEMORY;
435                                 }
436                         }
437
438                         domain_name = domains[i];
439                 }
440         }
441
442         *pdomain_name = domain_name;
443         *ptypes = types;
444         *pnames = names;
445
446         return NT_STATUS_OK;
447 }
448
449 /* Lookup user information from a rid or username. */
450 NTSTATUS rpc_query_user(TALLOC_CTX *mem_ctx,
451                         struct rpc_pipe_client *samr_pipe,
452                         struct policy_handle *samr_policy,
453                         const struct dom_sid *domain_sid,
454                         const struct dom_sid *user_sid,
455                         struct wbint_userinfo *user_info)
456 {
457         struct policy_handle user_policy;
458         union samr_UserInfo *info = NULL;
459         uint32_t user_rid;
460         NTSTATUS status;
461
462         if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) {
463                 return NT_STATUS_UNSUCCESSFUL;
464         }
465
466         /* Get user handle */
467         status = rpccli_samr_OpenUser(samr_pipe,
468                                       mem_ctx,
469                                       samr_policy,
470                                       SEC_FLAG_MAXIMUM_ALLOWED,
471                                       user_rid,
472                                       &user_policy);
473         if (!NT_STATUS_IS_OK(status)) {
474                 return status;
475         }
476
477         /* Get user info */
478         status = rpccli_samr_QueryUserInfo(samr_pipe,
479                                            mem_ctx,
480                                            &user_policy,
481                                            0x15,
482                                            &info);
483
484         rpccli_samr_Close(samr_pipe, mem_ctx, &user_policy);
485
486         if (!NT_STATUS_IS_OK(status)) {
487                 return status;
488         }
489
490         sid_compose(&user_info->user_sid, domain_sid, user_rid);
491         sid_compose(&user_info->group_sid, domain_sid,
492                     info->info21.primary_gid);
493
494         user_info->acct_name = talloc_strdup(user_info,
495                                         info->info21.account_name.string);
496         if (user_info->acct_name == NULL) {
497                 return NT_STATUS_NO_MEMORY;
498         }
499
500         user_info->full_name = talloc_strdup(user_info,
501                                         info->info21.full_name.string);
502         if (user_info->acct_name == NULL) {
503                 return NT_STATUS_NO_MEMORY;
504         }
505
506         user_info->homedir = NULL;
507         user_info->shell = NULL;
508         user_info->primary_gid = (gid_t)-1;
509
510         return NT_STATUS_OK;
511 }
512
513 /* Lookup groups a user is a member of. */
514 NTSTATUS rpc_lookup_usergroups(TALLOC_CTX *mem_ctx,
515                                struct rpc_pipe_client *samr_pipe,
516                                struct policy_handle *samr_policy,
517                                const struct dom_sid *domain_sid,
518                                const struct dom_sid *user_sid,
519                                uint32_t *pnum_groups,
520                                struct dom_sid **puser_grpsids)
521 {
522         struct policy_handle user_policy;
523         struct samr_RidWithAttributeArray *rid_array = NULL;
524         struct dom_sid *user_grpsids = NULL;
525         uint32_t num_groups = 0, i;
526         uint32_t user_rid;
527         NTSTATUS status;
528
529         if (!sid_peek_check_rid(domain_sid, user_sid, &user_rid)) {
530                 return NT_STATUS_UNSUCCESSFUL;
531         }
532
533         /* Get user handle */
534         status = rpccli_samr_OpenUser(samr_pipe,
535                                       mem_ctx,
536                                       samr_policy,
537                                       SEC_FLAG_MAXIMUM_ALLOWED,
538                                       user_rid,
539                                       &user_policy);
540         if (!NT_STATUS_IS_OK(status)) {
541                 return status;
542         }
543
544         /* Query user rids */
545         status = rpccli_samr_GetGroupsForUser(samr_pipe,
546                                               mem_ctx,
547                                               &user_policy,
548                                               &rid_array);
549         num_groups = rid_array->count;
550
551         rpccli_samr_Close(samr_pipe, mem_ctx, &user_policy);
552
553         if (!NT_STATUS_IS_OK(status) || num_groups == 0) {
554                 return status;
555         }
556
557         user_grpsids = TALLOC_ARRAY(mem_ctx, struct dom_sid, num_groups);
558         if (user_grpsids == NULL) {
559                 status = NT_STATUS_NO_MEMORY;
560                 return status;
561         }
562
563         for (i = 0; i < num_groups; i++) {
564                 sid_compose(&(user_grpsids[i]), domain_sid,
565                             rid_array->rids[i].rid);
566         }
567
568         *pnum_groups = num_groups;
569
570         *puser_grpsids = user_grpsids;
571
572         return NT_STATUS_OK;
573 }
574
575 NTSTATUS rpc_lookup_useraliases(TALLOC_CTX *mem_ctx,
576                                 struct rpc_pipe_client *samr_pipe,
577                                 struct policy_handle *samr_policy,
578                                 uint32_t num_sids,
579                                 const struct dom_sid *sids,
580                                 uint32_t *pnum_aliases,
581                                 uint32_t **palias_rids)
582 {
583 #define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */
584         uint32_t num_query_sids = 0;
585         uint32_t num_queries = 1;
586         uint32_t num_aliases = 0;
587         uint32_t total_sids = 0;
588         uint32_t *alias_rids = NULL;
589         uint32_t rangesize = MAX_SAM_ENTRIES_W2K;
590         uint32_t i;
591         struct samr_Ids alias_rids_query;
592         NTSTATUS status;
593
594         do {
595                 /* prepare query */
596                 struct lsa_SidArray sid_array;
597
598                 ZERO_STRUCT(sid_array);
599
600                 num_query_sids = MIN(num_sids - total_sids, rangesize);
601
602                 DEBUG(10,("rpc: lookup_useraliases: entering query %d for %d sids\n",
603                         num_queries, num_query_sids));
604
605                 if (num_query_sids) {
606                         sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_query_sids);
607                         if (sid_array.sids == NULL) {
608                                 return NT_STATUS_NO_MEMORY;
609                         }
610                 } else {
611                         sid_array.sids = NULL;
612                 }
613
614                 for (i = 0; i < num_query_sids; i++) {
615                         sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[total_sids++]);
616                         if (sid_array.sids[i].sid == NULL) {
617                                 return NT_STATUS_NO_MEMORY;
618                         }
619                 }
620                 sid_array.num_sids = num_query_sids;
621
622                 /* do request */
623                 status = rpccli_samr_GetAliasMembership(samr_pipe,
624                                                         mem_ctx,
625                                                         samr_policy,
626                                                         &sid_array,
627                                                         &alias_rids_query);
628                 if (!NT_STATUS_IS_OK(status)) {
629                         return status;
630                 }
631
632                 /* process output */
633                 for (i = 0; i < alias_rids_query.count; i++) {
634                         size_t na = num_aliases;
635
636                         if (!add_rid_to_array_unique(mem_ctx,
637                                                      alias_rids_query.ids[i],
638                                                      &alias_rids,
639                                                      &na)) {
640                                         return NT_STATUS_NO_MEMORY;
641                                 }
642                                 num_aliases = na;
643                 }
644
645                 num_queries++;
646
647         } while (total_sids < num_sids);
648
649         DEBUG(10,("rpc: rpc_lookup_useraliases: got %d aliases in %d queries "
650                   "(rangesize: %d)\n", num_aliases, num_queries, rangesize));
651
652         *pnum_aliases = num_aliases;
653         *palias_rids = alias_rids;
654
655         return NT_STATUS_OK;
656 #undef MAX_SAM_ENTRIES_W2K
657 }
658
659 /* Lookup group membership given a rid.   */
660 NTSTATUS rpc_lookup_groupmem(TALLOC_CTX *mem_ctx,
661                              struct rpc_pipe_client *samr_pipe,
662                              struct policy_handle *samr_policy,
663                              const char *domain_name,
664                              const struct dom_sid *domain_sid,
665                              const struct dom_sid *group_sid,
666                              enum lsa_SidType type,
667                              uint32_t *pnum_names,
668                              struct dom_sid **psid_mem,
669                              char ***pnames,
670                              uint32_t **pname_types)
671 {
672         struct policy_handle group_policy;
673         struct samr_RidTypeArray *rids = NULL;
674         uint32_t group_rid;
675         uint32_t *rid_mem = NULL;
676
677         uint32_t num_names = 0;
678         uint32_t total_names = 0;
679         struct dom_sid *sid_mem = NULL;
680         char **names = NULL;
681         uint32_t *name_types = NULL;
682
683         struct lsa_Strings tmp_names;
684         struct samr_Ids tmp_types;
685
686         uint32_t j, r;
687         NTSTATUS status;
688
689         if (!sid_peek_check_rid(domain_sid, group_sid, &group_rid)) {
690                 return NT_STATUS_UNSUCCESSFUL;
691         }
692
693         status = rpccli_samr_OpenGroup(samr_pipe,
694                                        mem_ctx,
695                                        samr_policy,
696                                        SEC_FLAG_MAXIMUM_ALLOWED,
697                                        group_rid,
698                                        &group_policy);
699         if (!NT_STATUS_IS_OK(status)) {
700                 return status;
701         }
702
703         /*
704          * Step #1: Get a list of user rids that are the members of the group.
705          */
706         status = rpccli_samr_QueryGroupMember(samr_pipe,
707                                               mem_ctx,
708                                               &group_policy,
709                                               &rids);
710
711         rpccli_samr_Close(samr_pipe, mem_ctx, &group_policy);
712
713         if (!NT_STATUS_IS_OK(status)) {
714                 return status;
715         }
716
717         if (rids == NULL || rids->count == 0) {
718                 pnum_names = 0;
719                 pnames = NULL;
720                 pname_types = NULL;
721                 psid_mem = NULL;
722
723                 return NT_STATUS_OK;
724         }
725
726         num_names = rids->count;
727         rid_mem = rids->rids;
728
729         /*
730          * Step #2: Convert list of rids into list of usernames.
731          */
732         if (num_names > 0) {
733                 names = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_names);
734                 name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32_t, num_names);
735                 sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_names);
736                 if (names == NULL || name_types == NULL || sid_mem == NULL) {
737                         return NT_STATUS_NO_MEMORY;
738                 }
739         }
740
741         for (j = 0; j < num_names; j++) {
742                 sid_compose(&sid_mem[j], domain_sid, rid_mem[j]);
743         }
744
745         status = rpccli_samr_LookupRids(samr_pipe,
746                                         mem_ctx,
747                                         samr_policy,
748                                         num_names,
749                                         rid_mem,
750                                         &tmp_names,
751                                         &tmp_types);
752         if (!NT_STATUS_IS_OK(status)) {
753                 if (!NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
754                         return status;
755                 }
756         }
757
758         /* Copy result into array.  The talloc system will take
759            care of freeing the temporary arrays later on. */
760         if (tmp_names.count != tmp_types.count) {
761                 return NT_STATUS_UNSUCCESSFUL;
762         }
763
764         for (r = 0; r < tmp_names.count; r++) {
765                 if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
766                         continue;
767                 }
768                 names[total_names] = fill_domain_username_talloc(names,
769                                                                  domain_name,
770                                                                  tmp_names.names[r].string,
771                                                                  true);
772                 if (names[total_names] == NULL) {
773                         return NT_STATUS_NO_MEMORY;
774                 }
775                 name_types[total_names] = tmp_types.ids[r];
776                 total_names++;
777         }
778
779         *pnum_names = total_names;
780         *pnames = names;
781         *pname_types = name_types;
782         *psid_mem = sid_mem;
783
784         return NT_STATUS_OK;
785 }