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