s3:winbind: WINBIND_USERINFO -> wbint_userinfo
[metze/samba/wip.git] / source3 / winbindd / winbindd_passdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind rpc backend functions
5
6    Copyright (C) Tim Potter 2000-2001,2003
7    Copyright (C) Simo Sorce 2003
8    Copyright (C) Volker Lendecke 2004
9    Copyright (C) Jeremy Allison 2008
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 static NTSTATUS enum_groups_internal(struct winbindd_domain *domain,
32                                 TALLOC_CTX *mem_ctx,
33                                 uint32 *num_entries, 
34                                 struct acct_info **info,
35                                 enum lsa_SidType sidtype)
36 {
37         struct pdb_search *search;
38         struct samr_displayentry *entries;
39         int i;
40         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
41
42         if (sidtype == SID_NAME_ALIAS) {
43                 search = pdb_search_aliases(talloc_tos(), &domain->sid);
44         } else {
45                 search = pdb_search_groups(talloc_tos());
46         }
47
48         if (search == NULL) goto done;
49
50         *num_entries = pdb_search_entries(search, 0, 0xffffffff, &entries);
51         if (*num_entries == 0) {
52                 /* Zero entries isn't an error */
53                 result = NT_STATUS_OK;
54                 goto done;
55         }
56
57         *info = TALLOC_ARRAY(mem_ctx, struct acct_info, *num_entries);
58         if (*info == NULL) {
59                 result = NT_STATUS_NO_MEMORY;
60                 goto done;
61         }
62
63         for (i=0; i<*num_entries; i++) {
64                 fstrcpy((*info)[i].acct_name, entries[i].account_name);
65                 fstrcpy((*info)[i].acct_desc, entries[i].description);
66                 (*info)[i].rid = entries[i].rid;
67         }
68
69         result = NT_STATUS_OK;
70  done:
71         TALLOC_FREE(search);
72         return result;
73 }
74
75 /* List all local groups (aliases) */
76 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
77                                 TALLOC_CTX *mem_ctx,
78                                 uint32 *num_entries, 
79                                 struct acct_info **info)
80 {
81         return enum_groups_internal(domain,
82                                 mem_ctx,
83                                 num_entries,
84                                 info,
85                                 SID_NAME_ALIAS);
86 }
87
88 /* convert a single name to a sid in a domain */
89 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
90                             TALLOC_CTX *mem_ctx,
91                             const char *domain_name,
92                             const char *name,
93                             uint32_t flags,
94                             DOM_SID *sid,
95                             enum lsa_SidType *type)
96 {
97         const char *fullname;
98
99         flags |= LOOKUP_NAME_ALL;
100
101         if (domain_name && domain_name[0] && strchr_m(name, '\\') == NULL) {
102                 fullname = talloc_asprintf(mem_ctx, "%s\\%s",
103                                 domain_name, name);
104                 if (fullname == NULL) {
105                         return NT_STATUS_NO_MEMORY;
106                 }
107         } else {
108                 fullname = name;
109         }
110
111         DEBUG(10, ("Finding fullname %s\n", fullname));
112
113         if ( !lookup_name( mem_ctx, fullname, flags, NULL, NULL, sid, type ) ) {
114                 return NT_STATUS_NONE_MAPPED;
115         }
116
117         DEBUG(10, ("name_to_sid for %s returned %s (%s)\n",
118                 fullname,
119                 sid_string_dbg(sid),
120                 sid_type_lookup((uint32)*type)));
121
122         return NT_STATUS_OK;
123 }
124
125 /*
126   convert a domain SID to a user or group name
127 */
128 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
129                             TALLOC_CTX *mem_ctx,
130                             const DOM_SID *sid,
131                             char **domain_name,
132                             char **name,
133                             enum lsa_SidType *type)
134 {
135         const char *dom, *nam;
136
137         DEBUG(10, ("Converting SID %s\n", sid_string_dbg(sid)));
138
139         /* Paranoia check */
140         if (!sid_check_is_in_builtin(sid) &&
141             !sid_check_is_in_our_domain(sid) &&
142             !sid_check_is_in_unix_users(sid) &&
143             !sid_check_is_unix_users(sid) &&
144             !sid_check_is_in_unix_groups(sid) &&
145             !sid_check_is_unix_groups(sid) &&
146             !sid_check_is_in_wellknown_domain(sid))
147         {
148                 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
149                           "passdb backend\n", sid_string_dbg(sid)));
150                 return NT_STATUS_NONE_MAPPED;
151         }
152
153         if (!lookup_sid(mem_ctx, sid, &dom, &nam, type)) {
154                 return NT_STATUS_NONE_MAPPED;
155         }
156
157         *domain_name = talloc_strdup(mem_ctx, dom);
158         *name = talloc_strdup(mem_ctx, nam);
159
160         return NT_STATUS_OK;
161 }
162
163 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
164                               TALLOC_CTX *mem_ctx,
165                               const DOM_SID *sid,
166                               uint32 *rids,
167                               size_t num_rids,
168                               char **domain_name,
169                               char ***names,
170                               enum lsa_SidType **types)
171 {
172         size_t i;
173         bool have_mapped;
174         bool have_unmapped;
175
176         *domain_name = NULL;
177         *names = NULL;
178         *types = NULL;
179
180         if (!num_rids) {
181                 return NT_STATUS_OK;
182         }
183
184         /* Paranoia check */
185         if (!sid_check_is_in_builtin(sid) &&
186             !sid_check_is_in_our_domain(sid) &&
187             !sid_check_is_in_unix_users(sid) &&
188             !sid_check_is_unix_users(sid) &&
189             !sid_check_is_in_unix_groups(sid) &&
190             !sid_check_is_unix_groups(sid) &&
191             !sid_check_is_in_wellknown_domain(sid))
192         {
193                 DEBUG(0, ("Possible deadlock: Trying to lookup SID %s with "
194                           "passdb backend\n", sid_string_dbg(sid)));
195                 return NT_STATUS_NONE_MAPPED;
196         }
197
198         *names = TALLOC_ARRAY(mem_ctx, char *, num_rids);
199         *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
200
201         if ((*names == NULL) || (*types == NULL)) {
202                 return NT_STATUS_NO_MEMORY;
203         }
204
205         have_mapped = have_unmapped = false;
206
207         for (i=0; i<num_rids; i++) {
208                 DOM_SID lsid;
209                 const char *dom = NULL, *nam = NULL;
210                 enum lsa_SidType type = SID_NAME_UNKNOWN;
211
212                 if (!sid_compose(&lsid, sid, rids[i])) {
213                         return NT_STATUS_INTERNAL_ERROR;
214                 }
215
216                 if (!lookup_sid(mem_ctx, &lsid, &dom, &nam, &type)) {
217                         have_unmapped = true;
218                         (*types)[i] = SID_NAME_UNKNOWN;
219                         (*names)[i] = talloc_strdup(mem_ctx, "");
220                 } else {
221                         have_mapped = true;
222                         (*types)[i] = type;
223                         (*names)[i] = CONST_DISCARD(char *, nam);
224                 }
225
226                 if (*domain_name == NULL) {
227                         *domain_name = CONST_DISCARD(char *, dom);
228                 } else {
229                         char *dname = CONST_DISCARD(char *, dom);
230                         TALLOC_FREE(dname);
231                 }
232         }
233
234         if (!have_mapped) {
235                 return NT_STATUS_NONE_MAPPED;
236         }
237         if (!have_unmapped) {
238                 return NT_STATUS_OK;
239         }
240         return STATUS_SOME_UNMAPPED;
241 }
242
243 /* Lookup groups a user is a member of.  I wish Unix had a call like this! */
244 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
245                                   TALLOC_CTX *mem_ctx,
246                                   const DOM_SID *user_sid,
247                                   uint32 *num_groups, DOM_SID **user_gids)
248 {
249         NTSTATUS result;
250         DOM_SID *groups = NULL;
251         gid_t *gids = NULL;
252         size_t ngroups = 0;
253         struct samu *user;
254
255         if ( (user = samu_new(mem_ctx)) == NULL ) {
256                 return NT_STATUS_NO_MEMORY;
257         }
258
259         if ( !pdb_getsampwsid( user, user_sid ) ) {
260                 TALLOC_FREE( user );
261                 return NT_STATUS_NO_SUCH_USER;
262         }
263
264         result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
265
266         TALLOC_FREE( user );
267
268         *num_groups = (uint32)ngroups;
269         *user_gids = groups;
270
271         return result;
272 }
273
274 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
275                                    TALLOC_CTX *mem_ctx,
276                                    uint32 num_sids, const DOM_SID *sids,
277                                    uint32 *p_num_aliases, uint32 **rids)
278 {
279         NTSTATUS result;
280         size_t num_aliases = 0;
281
282         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
283                                             sids, num_sids, rids, &num_aliases);
284
285         *p_num_aliases = num_aliases;
286         return result;
287 }
288
289 /* find the sequence number for a domain */
290 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
291 {
292         bool result;
293         time_t seq_num;
294
295         result = pdb_get_seq_num(&seq_num);
296         if (!result) {
297                 *seq = 1;
298         }
299
300         *seq = (int) seq_num;
301         /* *seq = 1; */
302         return NT_STATUS_OK;
303 }
304
305 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
306                                TALLOC_CTX *mem_ctx,
307                                struct samr_DomInfo12 *policy)
308 {
309         /* actually we have that */
310         return NT_STATUS_NOT_IMPLEMENTED;
311 }
312
313 static NTSTATUS password_policy(struct winbindd_domain *domain,
314                                 TALLOC_CTX *mem_ctx,
315                                 struct samr_DomInfo1 *policy)
316 {
317         struct samr_DomInfo1 *p;
318         time_t u_expire, u_min_age;
319         uint32 account_policy_temp;
320
321         if ((p = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
322                 return NT_STATUS_NO_MEMORY;
323         }
324
325         if (!pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN,
326                                     &account_policy_temp)) {
327                 return NT_STATUS_ACCESS_DENIED;
328         }
329         p->min_password_length = account_policy_temp;
330
331         if (!pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY,
332                                     &account_policy_temp)) {
333                 return NT_STATUS_ACCESS_DENIED;
334         }
335         p->password_history_length = account_policy_temp;
336
337         if (!pdb_get_account_policy(PDB_POLICY_USER_MUST_LOGON_TO_CHG_PASS,
338                                     &p->password_properties)) {
339                 return NT_STATUS_ACCESS_DENIED;
340         }
341
342         if (!pdb_get_account_policy(PDB_POLICY_MAX_PASSWORD_AGE, &account_policy_temp)) {
343                 return NT_STATUS_ACCESS_DENIED;
344         }
345         u_expire = account_policy_temp;
346
347         if (!pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_AGE, &account_policy_temp)) {
348                 return NT_STATUS_ACCESS_DENIED;
349         }
350         u_min_age = account_policy_temp;
351
352         unix_to_nt_time_abs((NTTIME *)&p->max_password_age, u_expire);
353         unix_to_nt_time_abs((NTTIME *)&p->min_password_age, u_min_age);
354
355         policy = p;
356
357         return NT_STATUS_OK;
358 }
359
360 /*********************************************************************
361  BUILTIN specific functions.
362 *********************************************************************/
363
364 /* list all domain groups */
365 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
366                                 TALLOC_CTX *mem_ctx,
367                                 uint32 *num_entries, 
368                                 struct acct_info **info)
369 {
370         /* BUILTIN doesn't have domain groups */
371         *num_entries = 0;
372         *info = NULL;
373         return NT_STATUS_OK;
374 }
375
376 /* Query display info for a domain.  This returns enough information plus a
377    bit extra to give an overview of domain users for the User Manager
378    application. */
379 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
380                                 TALLOC_CTX *mem_ctx,
381                                 uint32 *num_entries,
382                                 struct wbint_userinfo **info)
383 {
384         /* We don't have users */
385         *num_entries = 0;
386         *info = NULL;
387         return NT_STATUS_OK;
388 }
389
390 /* Lookup user information from a rid or username. */
391 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
392                                 TALLOC_CTX *mem_ctx,
393                                 const DOM_SID *user_sid,
394                                 struct wbint_userinfo *user_info)
395 {
396         return NT_STATUS_NO_SUCH_USER;
397 }
398
399 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
400                                 TALLOC_CTX *mem_ctx,
401                                 const DOM_SID *group_sid, uint32 *num_names,
402                                 DOM_SID **sid_mem, char ***names,
403                                 uint32 **name_types)
404 {
405         DEBUG(10,("passdb: lookup_groupmem (builtin) %s sid=%s\n", domain->name,
406                   sid_string_dbg(group_sid)));
407
408         *num_names = 0;
409         *sid_mem = NULL;
410         *names = NULL;
411         *name_types = 0;
412         return NT_STATUS_NO_SUCH_GROUP;
413 }
414
415 /* get a list of trusted domains - builtin domain */
416 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
417                                 TALLOC_CTX *mem_ctx,
418                                 uint32 *num_domains,
419                                 char ***names,
420                                 char ***alt_names,
421                                 DOM_SID **dom_sids)
422 {
423         *num_domains = 0;
424         *names = NULL;
425         *alt_names = NULL;
426         *dom_sids = NULL;
427         return NT_STATUS_OK;
428 }
429
430 /*********************************************************************
431  SAM specific functions.
432 *********************************************************************/
433
434 /* list all domain groups */
435 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
436                                 TALLOC_CTX *mem_ctx,
437                                 uint32 *num_entries, 
438                                 struct acct_info **info)
439 {
440         return enum_groups_internal(domain,
441                                 mem_ctx,
442                                 num_entries,
443                                 info,
444                                 SID_NAME_DOM_GRP);
445 }
446
447 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
448                                 TALLOC_CTX *mem_ctx,
449                                 uint32 *num_entries,
450                                 struct wbint_userinfo **info)
451 {
452         struct pdb_search *ps = pdb_search_users(talloc_tos(), ACB_NORMAL);
453         struct samr_displayentry *entries = NULL;
454         uint32 i;
455
456         *num_entries = 0;
457         *info = NULL;
458
459         if (!ps) {
460                 return NT_STATUS_NO_MEMORY;
461         }
462
463         *num_entries = pdb_search_entries(ps,
464                                         1, 0xffffffff,
465                                         &entries);
466
467         *info = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, *num_entries);
468         if (!(*info)) {
469                 TALLOC_FREE(ps);
470                 return NT_STATUS_NO_MEMORY;
471         }
472
473         for (i = 0; i < *num_entries; i++) {
474                 struct samr_displayentry *e = &entries[i];
475
476                 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
477                 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
478                 (*info)[i].homedir = NULL;
479                 (*info)[i].shell = NULL;
480                 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
481
482                 /* For the moment we set the primary group for
483                    every user to be the Domain Users group.
484                    There are serious problems with determining
485                    the actual primary group for large domains.
486                    This should really be made into a 'winbind
487                    force group' smb.conf parameter or
488                    something like that. */
489
490                 sid_compose(&(*info)[i].group_sid, &domain->sid,
491                                 DOMAIN_GROUP_RID_USERS);
492         }
493
494         TALLOC_FREE(ps);
495         return NT_STATUS_OK;
496 }
497
498 /* Lookup user information from a rid or username. */
499 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
500                            TALLOC_CTX *mem_ctx,
501                            const DOM_SID *user_sid,
502                            struct wbint_userinfo *user_info)
503 {
504         struct samu *sampass = NULL;
505
506         ZERO_STRUCTP(user_info);
507
508         if (!sid_check_is_in_our_domain(user_sid)) {
509                 return NT_STATUS_NO_SUCH_USER;
510         }
511
512         DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
513                 sid_string_dbg(user_sid) ));
514
515         if (!(sampass = samu_new(mem_ctx))) {
516                 return NT_STATUS_NO_MEMORY;
517         }
518
519         if (!pdb_getsampwsid(sampass, user_sid)) {
520                 TALLOC_FREE(sampass);
521                 return NT_STATUS_NO_SUCH_USER;
522         }
523
524         if (pdb_get_group_sid(sampass) == NULL) {
525                 TALLOC_FREE(sampass);
526                 return NT_STATUS_NO_SUCH_GROUP;
527         }
528
529         DEBUG(10,("sam_query_user: group sid %s\n",
530                 sid_string_dbg(sampass->group_sid) ));
531
532         sid_copy(&user_info->user_sid, user_sid);
533         sid_copy(&user_info->group_sid, sampass->group_sid);
534
535         user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
536                                         sampass->username : "");
537         user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
538                                         sampass->full_name : "");
539         user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
540                                         sampass->home_dir : "");
541         if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
542                 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
543         } else {
544                 user_info->shell = talloc_strdup(mem_ctx, "");
545         }
546         user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
547
548         TALLOC_FREE(sampass);
549         return NT_STATUS_OK;
550 }
551
552 /* Lookup group membership given a rid.   */
553 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
554                                 TALLOC_CTX *mem_ctx,
555                                 const DOM_SID *group_sid, uint32 *num_names, 
556                                 DOM_SID **sid_mem, char ***names, 
557                                 uint32 **name_types)
558 {
559         size_t i, num_members, num_mapped;
560         uint32 *rids;
561         NTSTATUS result;
562         const DOM_SID **sids;
563         struct lsa_dom_info *lsa_domains;
564         struct lsa_name_info *lsa_names;
565         TALLOC_CTX *tmp_ctx;
566
567         DEBUG(10,("passdb: lookup_groupmem (sam) %s sid=%s\n", domain->name,
568                   sid_string_dbg(group_sid)));
569
570         if (!sid_check_is_in_our_domain(group_sid)) {
571                 /* There's no groups, only aliases in BUILTIN */
572                 return NT_STATUS_NO_SUCH_GROUP;
573         }
574
575         if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
576                 return NT_STATUS_NO_MEMORY;
577         }
578
579         result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
580                                         &num_members);
581         if (!NT_STATUS_IS_OK(result)) {
582                 TALLOC_FREE(tmp_ctx);
583                 return result;
584         }
585
586         if (num_members == 0) {
587                 *num_names = 0;
588                 *sid_mem = NULL;
589                 *names = NULL;
590                 *name_types = NULL;
591                 TALLOC_FREE(tmp_ctx);
592                 return NT_STATUS_OK;
593         }
594
595         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
596         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
597         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
598         sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
599
600         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
601             ((*name_types) == NULL) || (sids == NULL)) {
602                 TALLOC_FREE(tmp_ctx);
603                 return NT_STATUS_NO_MEMORY;
604         }
605
606         /*
607          * Prepare an array of sid pointers for the lookup_sids calling
608          * convention.
609          */
610
611         for (i=0; i<num_members; i++) {
612                 DOM_SID *sid = &((*sid_mem)[i]);
613                 if (!sid_compose(sid, &domain->sid, rids[i])) {
614                         TALLOC_FREE(tmp_ctx);
615                         return NT_STATUS_INTERNAL_ERROR;
616                 }
617                 sids[i] = sid;
618         }
619
620         result = lookup_sids(tmp_ctx, num_members, sids, 1,
621                              &lsa_domains, &lsa_names);
622         if (!NT_STATUS_IS_OK(result)) {
623                 TALLOC_FREE(tmp_ctx);
624                 return result;
625         }
626
627         num_mapped = 0;
628         for (i=0; i<num_members; i++) {
629                 if (lsa_names[i].type != SID_NAME_USER) {
630                         DEBUG(2, ("Got %s as group member -- ignoring\n",
631                                   sid_type_lookup(lsa_names[i].type)));
632                         continue;
633                 }
634                 if (!((*names)[num_mapped] = talloc_strdup((*names),
635                                                   lsa_names[i].name))) {
636                         TALLOC_FREE(tmp_ctx);
637                         return NT_STATUS_NO_MEMORY;
638                 }
639
640                 (*name_types)[num_mapped] = lsa_names[i].type;
641
642                 num_mapped += 1;
643         }
644
645         *num_names = num_mapped;
646
647         TALLOC_FREE(tmp_ctx);
648         return NT_STATUS_OK;
649 }
650
651 /* get a list of trusted domains */
652 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
653                                 TALLOC_CTX *mem_ctx,
654                                 uint32 *num_domains,
655                                 char ***names,
656                                 char ***alt_names,
657                                 DOM_SID **dom_sids)
658 {
659         NTSTATUS nt_status;
660         struct trustdom_info **domains;
661         int i;
662         TALLOC_CTX *tmp_ctx;
663
664         *num_domains = 0;
665         *names = NULL;
666         *alt_names = NULL;
667         *dom_sids = NULL;
668
669         if (!(tmp_ctx = talloc_init("trusted_domains"))) {
670                 return NT_STATUS_NO_MEMORY;
671         }
672
673         nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
674         if (!NT_STATUS_IS_OK(nt_status)) {
675                 TALLOC_FREE(tmp_ctx);
676                 return nt_status;
677         }
678
679         if (*num_domains) {
680                 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
681                 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
682                 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
683
684                 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
685                         TALLOC_FREE(tmp_ctx);
686                         return NT_STATUS_NO_MEMORY;
687                 }
688         } else {
689                 *names = NULL;
690                 *alt_names = NULL;
691                 *dom_sids = NULL;
692         }
693
694         for (i=0; i<*num_domains; i++) {
695                 (*alt_names)[i] = NULL;
696                 if (!((*names)[i] = talloc_strdup((*names),
697                                                   domains[i]->name))) {
698                         TALLOC_FREE(tmp_ctx);
699                         return NT_STATUS_NO_MEMORY;
700                 }
701                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
702         }
703
704         TALLOC_FREE(tmp_ctx);
705         return NT_STATUS_OK;
706 }
707
708 /* the rpc backend methods are exposed via this structure */
709 struct winbindd_methods builtin_passdb_methods = {
710         false,
711         builtin_query_user_list,
712         builtin_enum_dom_groups,
713         enum_local_groups,
714         name_to_sid,
715         sid_to_name,
716         rids_to_names,
717         builtin_query_user,
718         lookup_usergroups,
719         lookup_useraliases,
720         builtin_lookup_groupmem,
721         sequence_number,
722         lockout_policy,
723         password_policy,
724         builtin_trusted_domains,
725 };
726
727 /* the rpc backend methods are exposed via this structure */
728 struct winbindd_methods sam_passdb_methods = {
729         false,
730         sam_query_user_list,
731         sam_enum_dom_groups,
732         enum_local_groups,
733         name_to_sid,
734         sid_to_name,
735         rids_to_names,
736         sam_query_user,
737         lookup_usergroups,
738         lookup_useraliases,
739         sam_lookup_groupmem,
740         sequence_number,
741         lockout_policy,
742         password_policy,
743         sam_trusted_domains,
744 };