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