winbindd: kill some trailing/leading whitespace.
[kai/samba.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(&domain->sid);
44         } else {
45                 search = pdb_search_groups();
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         pdb_search_destroy(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                 return NT_STATUS_NO_SUCH_USER;
271         }
272
273         result = pdb_enum_group_memberships( mem_ctx, user, &groups, &gids, &ngroups );
274
275         TALLOC_FREE( user );
276
277         *num_groups = (uint32)ngroups;
278         *user_gids = groups;
279
280         return result;
281 }
282
283 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
284                                    TALLOC_CTX *mem_ctx,
285                                    uint32 num_sids, const DOM_SID *sids,
286                                    uint32 *p_num_aliases, uint32 **rids)
287 {
288         NTSTATUS result;
289         size_t num_aliases = 0;
290
291         result = pdb_enum_alias_memberships(mem_ctx, &domain->sid,
292                                             sids, num_sids, rids, &num_aliases);
293
294         *p_num_aliases = num_aliases;
295         return result;
296 }
297
298 /* find the sequence number for a domain */
299 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
300 {
301         bool result;
302         time_t seq_num;
303
304         result = pdb_get_seq_num(&seq_num);
305         if (!result) {
306                 *seq = 1;
307         }
308
309         *seq = (int) seq_num;
310         /* *seq = 1; */
311         return NT_STATUS_OK;
312 }
313
314 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
315                                TALLOC_CTX *mem_ctx,
316                                struct samr_DomInfo12 *policy)
317 {
318         /* actually we have that */
319         return NT_STATUS_NOT_IMPLEMENTED;
320 }
321
322 static NTSTATUS password_policy(struct winbindd_domain *domain,
323                                 TALLOC_CTX *mem_ctx,
324                                 struct samr_DomInfo1 *policy)
325 {
326         uint32 min_pass_len,pass_hist,password_properties;
327         time_t u_expire, u_min_age;
328         NTTIME nt_expire, nt_min_age;
329         uint32 account_policy_temp;
330
331         if ((policy = TALLOC_ZERO_P(mem_ctx, struct samr_DomInfo1)) == NULL) {
332                 return NT_STATUS_NO_MEMORY;
333         }
334
335         if (!pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &account_policy_temp)) {
336                 return NT_STATUS_ACCESS_DENIED;
337         }
338         min_pass_len = account_policy_temp;
339
340         if (!pdb_get_account_policy(AP_PASSWORD_HISTORY, &account_policy_temp)) {
341                 return NT_STATUS_ACCESS_DENIED;
342         }
343         pass_hist = account_policy_temp;
344
345         if (!pdb_get_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS, &account_policy_temp)) {
346                 return NT_STATUS_ACCESS_DENIED;
347         }
348         password_properties = account_policy_temp;
349         
350         if (!pdb_get_account_policy(AP_MAX_PASSWORD_AGE, &account_policy_temp)) {
351                 return NT_STATUS_ACCESS_DENIED;
352         }
353         u_expire = account_policy_temp;
354
355         if (!pdb_get_account_policy(AP_MIN_PASSWORD_AGE, &account_policy_temp)) {
356                 return NT_STATUS_ACCESS_DENIED;
357         }
358         u_min_age = account_policy_temp;
359
360         unix_to_nt_time_abs(&nt_expire, u_expire);
361         unix_to_nt_time_abs(&nt_min_age, u_min_age);
362
363         init_samr_DomInfo1(policy,
364                            (uint16)min_pass_len,
365                            (uint16)pass_hist,
366                            password_properties,
367                            nt_expire,
368                            nt_min_age);
369
370         return NT_STATUS_OK;
371 }
372
373 /*********************************************************************
374  BUILTIN specific functions.
375 *********************************************************************/
376
377 /* list all domain groups */
378 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
379                                 TALLOC_CTX *mem_ctx,
380                                 uint32 *num_entries, 
381                                 struct acct_info **info)
382 {
383         /* BUILTIN doesn't have domain groups */
384         *num_entries = 0;
385         *info = NULL;
386         return NT_STATUS_OK;
387 }
388
389 /* Query display info for a domain.  This returns enough information plus a
390    bit extra to give an overview of domain users for the User Manager
391    application. */
392 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
393                                 TALLOC_CTX *mem_ctx,
394                                 uint32 *num_entries,
395                                 WINBIND_USERINFO **info)
396 {
397         /* We don't have users */
398         *num_entries = 0;
399         *info = NULL;
400         return NT_STATUS_OK;
401 }
402
403 /* Lookup user information from a rid or username. */
404 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
405                                 TALLOC_CTX *mem_ctx,
406                                 const DOM_SID *user_sid,
407                                 WINBIND_USERINFO *user_info)
408 {
409         return NT_STATUS_NO_SUCH_USER;
410 }
411
412 static NTSTATUS builtin_lookup_groupmem(struct winbindd_domain *domain,
413                                 TALLOC_CTX *mem_ctx,
414                                 const DOM_SID *group_sid, uint32 *num_names,
415                                 DOM_SID **sid_mem, char ***names,
416                                 uint32 **name_types)
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(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                 pdb_search_destroy(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         pdb_search_destroy(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         if (!sid_check_is_in_our_domain(group_sid)) {
578                 /* There's no groups, only aliases in BUILTIN */
579                 return NT_STATUS_NO_SUCH_GROUP;
580         }
581
582         if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
583                 return NT_STATUS_NO_MEMORY;
584         }
585
586         result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
587                                         &num_members);
588         if (!NT_STATUS_IS_OK(result)) {
589                 TALLOC_FREE(tmp_ctx);
590                 return result;
591         }
592
593         if (num_members == 0) {
594                 *num_names = 0;
595                 *sid_mem = NULL;
596                 *names = NULL;
597                 *name_types = NULL;
598                 TALLOC_FREE(tmp_ctx);
599                 return NT_STATUS_OK;
600         }
601
602         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
603         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
604         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
605         sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
606
607         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
608             ((*name_types) == NULL) || (sids == NULL)) {
609                 TALLOC_FREE(tmp_ctx);
610                 return NT_STATUS_NO_MEMORY;
611         }
612
613         /*
614          * Prepare an array of sid pointers for the lookup_sids calling
615          * convention.
616          */
617
618         for (i=0; i<num_members; i++) {
619                 DOM_SID *sid = &((*sid_mem)[i]);
620                 if (!sid_compose(sid, &domain->sid, rids[i])) {
621                         TALLOC_FREE(tmp_ctx);
622                         return NT_STATUS_INTERNAL_ERROR;
623                 }
624                 sids[i] = sid;
625         }
626
627         result = lookup_sids(tmp_ctx, num_members, sids, 1,
628                              &lsa_domains, &lsa_names);
629         if (!NT_STATUS_IS_OK(result)) {
630                 TALLOC_FREE(tmp_ctx);
631                 return result;
632         }
633
634         num_mapped = 0;
635         for (i=0; i<num_members; i++) {
636                 if (lsa_names[i].type != SID_NAME_USER) {
637                         DEBUG(2, ("Got %s as group member -- ignoring\n",
638                                   sid_type_lookup(lsa_names[i].type)));
639                         continue;
640                 }
641                 if (!((*names)[i] = talloc_strdup((*names),
642                                                   lsa_names[i].name))) {
643                         TALLOC_FREE(tmp_ctx);
644                         return NT_STATUS_NO_MEMORY;
645                 }
646
647                 (*name_types)[i] = lsa_names[i].type;
648
649                 num_mapped += 1;
650         }
651
652         *num_names = num_mapped;
653
654         TALLOC_FREE(tmp_ctx);
655         return NT_STATUS_OK;
656 }
657
658 /* get a list of trusted domains */
659 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
660                                 TALLOC_CTX *mem_ctx,
661                                 uint32 *num_domains,
662                                 char ***names,
663                                 char ***alt_names,
664                                 DOM_SID **dom_sids)
665 {
666         NTSTATUS nt_status;
667         struct trustdom_info **domains;
668         int i;
669         TALLOC_CTX *tmp_ctx;
670
671         *num_domains = 0;
672         *names = NULL;
673         *alt_names = NULL;
674         *dom_sids = NULL;
675
676         if (!(tmp_ctx = talloc_init("trusted_domains"))) {
677                 return NT_STATUS_NO_MEMORY;
678         }
679
680         nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
681         if (!NT_STATUS_IS_OK(nt_status)) {
682                 TALLOC_FREE(tmp_ctx);
683                 return nt_status;
684         }
685
686         if (*num_domains) {
687                 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
688                 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
689                 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
690
691                 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
692                         TALLOC_FREE(tmp_ctx);
693                         return NT_STATUS_NO_MEMORY;
694                 }
695         } else {
696                 *names = NULL;
697                 *alt_names = NULL;
698                 *dom_sids = NULL;
699         }
700
701         for (i=0; i<*num_domains; i++) {
702                 (*alt_names)[i] = NULL;
703                 if (!((*names)[i] = talloc_strdup((*names),
704                                                   domains[i]->name))) {
705                         TALLOC_FREE(tmp_ctx);
706                         return NT_STATUS_NO_MEMORY;
707                 }
708                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
709         }
710
711         TALLOC_FREE(tmp_ctx);
712         return NT_STATUS_OK;
713 }
714
715 /* the rpc backend methods are exposed via this structure */
716 struct winbindd_methods builtin_passdb_methods = {
717         false,
718         builtin_query_user_list,
719         builtin_enum_dom_groups,
720         enum_local_groups,
721         name_to_sid,
722         sid_to_name,
723         rids_to_names,
724         builtin_query_user,
725         lookup_usergroups,
726         lookup_useraliases,
727         builtin_lookup_groupmem,
728         sequence_number,
729         lockout_policy,
730         password_policy,
731         builtin_trusted_domains,
732 };
733
734 /* the rpc backend methods are exposed via this structure */
735 struct winbindd_methods sam_passdb_methods = {
736         false,
737         sam_query_user_list,
738         sam_enum_dom_groups,
739         enum_local_groups,
740         name_to_sid,
741         sid_to_name,
742         rids_to_names,
743         sam_query_user,
744         lookup_usergroups,
745         lookup_useraliases,
746         sam_lookup_groupmem,
747         sequence_number,
748         lockout_policy,
749         password_policy,
750         sam_trusted_domains,
751 };