s3:winbindd: move non event related code out of process_loop() in the the caller
[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(AP_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(AP_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(AP_USER_MUST_LOGON_TO_CHG_PASS,
348                                     &p->password_properties)) {
349                 return NT_STATUS_ACCESS_DENIED;
350         }
351
352         if (!pdb_get_account_policy(AP_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(AP_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         *num_names = 0;
416         *sid_mem = NULL;
417         *names = NULL;
418         *name_types = 0;
419         return NT_STATUS_NO_SUCH_GROUP;
420 }
421
422 /* get a list of trusted domains - builtin domain */
423 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
424                                 TALLOC_CTX *mem_ctx,
425                                 uint32 *num_domains,
426                                 char ***names,
427                                 char ***alt_names,
428                                 DOM_SID **dom_sids)
429 {
430         *num_domains = 0;
431         *names = NULL;
432         *alt_names = NULL;
433         *dom_sids = NULL;
434         return NT_STATUS_OK;
435 }
436
437 /*********************************************************************
438  SAM specific functions.
439 *********************************************************************/
440
441 /* list all domain groups */
442 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
443                                 TALLOC_CTX *mem_ctx,
444                                 uint32 *num_entries, 
445                                 struct acct_info **info)
446 {
447         return enum_groups_internal(domain,
448                                 mem_ctx,
449                                 num_entries,
450                                 info,
451                                 SID_NAME_DOM_GRP);
452 }
453
454 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
455                                 TALLOC_CTX *mem_ctx,
456                                 uint32 *num_entries,
457                                 WINBIND_USERINFO **info)
458 {
459         struct pdb_search *ps = pdb_search_users(talloc_tos(), ACB_NORMAL);
460         struct samr_displayentry *entries = NULL;
461         uint32 i;
462
463         *num_entries = 0;
464         *info = NULL;
465
466         if (!ps) {
467                 return NT_STATUS_NO_MEMORY;
468         }
469
470         *num_entries = pdb_search_entries(ps,
471                                         1, 0xffffffff,
472                                         &entries);
473
474         *info = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, *num_entries);
475         if (!(*info)) {
476                 TALLOC_FREE(ps);
477                 return NT_STATUS_NO_MEMORY;
478         }
479
480         for (i = 0; i < *num_entries; i++) {
481                 struct samr_displayentry *e = &entries[i];
482
483                 (*info)[i].acct_name = talloc_strdup(mem_ctx, e->account_name );
484                 (*info)[i].full_name = talloc_strdup(mem_ctx, e->fullname );
485                 (*info)[i].homedir = NULL;
486                 (*info)[i].shell = NULL;
487                 sid_compose(&(*info)[i].user_sid, &domain->sid, e->rid);
488
489                 /* For the moment we set the primary group for
490                    every user to be the Domain Users group.
491                    There are serious problems with determining
492                    the actual primary group for large domains.
493                    This should really be made into a 'winbind
494                    force group' smb.conf parameter or
495                    something like that. */
496
497                 sid_compose(&(*info)[i].group_sid, &domain->sid,
498                                 DOMAIN_GROUP_RID_USERS);
499         }
500
501         TALLOC_FREE(ps);
502         return NT_STATUS_OK;
503 }
504
505 /* Lookup user information from a rid or username. */
506 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
507                            TALLOC_CTX *mem_ctx,
508                            const DOM_SID *user_sid,
509                            WINBIND_USERINFO *user_info)
510 {
511         struct samu *sampass = NULL;
512
513         ZERO_STRUCTP(user_info);
514
515         if (!sid_check_is_in_our_domain(user_sid)) {
516                 return NT_STATUS_NO_SUCH_USER;
517         }
518
519         DEBUG(10,("sam_query_user: getting samu info for sid %s\n",
520                 sid_string_dbg(user_sid) ));
521
522         if (!(sampass = samu_new(mem_ctx))) {
523                 return NT_STATUS_NO_MEMORY;
524         }
525
526         if (!pdb_getsampwsid(sampass, user_sid)) {
527                 TALLOC_FREE(sampass);
528                 return NT_STATUS_NO_SUCH_USER;
529         }
530
531         if (pdb_get_group_sid(sampass) == NULL) {
532                 TALLOC_FREE(sampass);
533                 return NT_STATUS_NO_SUCH_GROUP;
534         }
535
536         DEBUG(10,("sam_query_user: group sid %s\n",
537                 sid_string_dbg(sampass->group_sid) ));
538
539         sid_copy(&user_info->user_sid, user_sid);
540         sid_copy(&user_info->group_sid, sampass->group_sid);
541
542         user_info->acct_name = talloc_strdup(mem_ctx, sampass->username ?
543                                         sampass->username : "");
544         user_info->full_name = talloc_strdup(mem_ctx, sampass->full_name ?
545                                         sampass->full_name : "");
546         user_info->homedir = talloc_strdup(mem_ctx, sampass->home_dir ?
547                                         sampass->home_dir : "");
548         if (sampass->unix_pw && sampass->unix_pw->pw_shell) {
549                 user_info->shell = talloc_strdup(mem_ctx, sampass->unix_pw->pw_shell);
550         } else {
551                 user_info->shell = talloc_strdup(mem_ctx, "");
552         }
553         user_info->primary_gid = sampass->unix_pw ? sampass->unix_pw->pw_gid : (gid_t)-1;
554
555         TALLOC_FREE(sampass);
556         return NT_STATUS_OK;
557 }
558
559 /* Lookup group membership given a rid.   */
560 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
561                                 TALLOC_CTX *mem_ctx,
562                                 const DOM_SID *group_sid, uint32 *num_names, 
563                                 DOM_SID **sid_mem, char ***names, 
564                                 uint32 **name_types)
565 {
566         size_t i, num_members, num_mapped;
567         uint32 *rids;
568         NTSTATUS result;
569         const DOM_SID **sids;
570         struct lsa_dom_info *lsa_domains;
571         struct lsa_name_info *lsa_names;
572         TALLOC_CTX *tmp_ctx;
573
574         if (!sid_check_is_in_our_domain(group_sid)) {
575                 /* There's no groups, only aliases in BUILTIN */
576                 return NT_STATUS_NO_SUCH_GROUP;
577         }
578
579         if (!(tmp_ctx = talloc_init("lookup_groupmem"))) {
580                 return NT_STATUS_NO_MEMORY;
581         }
582
583         result = pdb_enum_group_members(tmp_ctx, group_sid, &rids,
584                                         &num_members);
585         if (!NT_STATUS_IS_OK(result)) {
586                 TALLOC_FREE(tmp_ctx);
587                 return result;
588         }
589
590         if (num_members == 0) {
591                 *num_names = 0;
592                 *sid_mem = NULL;
593                 *names = NULL;
594                 *name_types = NULL;
595                 TALLOC_FREE(tmp_ctx);
596                 return NT_STATUS_OK;
597         }
598
599         *sid_mem = TALLOC_ARRAY(mem_ctx, DOM_SID, num_members);
600         *names = TALLOC_ARRAY(mem_ctx, char *, num_members);
601         *name_types = TALLOC_ARRAY(mem_ctx, uint32, num_members);
602         sids = TALLOC_ARRAY(tmp_ctx, const DOM_SID *, num_members);
603
604         if (((*sid_mem) == NULL) || ((*names) == NULL) ||
605             ((*name_types) == NULL) || (sids == NULL)) {
606                 TALLOC_FREE(tmp_ctx);
607                 return NT_STATUS_NO_MEMORY;
608         }
609
610         /*
611          * Prepare an array of sid pointers for the lookup_sids calling
612          * convention.
613          */
614
615         for (i=0; i<num_members; i++) {
616                 DOM_SID *sid = &((*sid_mem)[i]);
617                 if (!sid_compose(sid, &domain->sid, rids[i])) {
618                         TALLOC_FREE(tmp_ctx);
619                         return NT_STATUS_INTERNAL_ERROR;
620                 }
621                 sids[i] = sid;
622         }
623
624         result = lookup_sids(tmp_ctx, num_members, sids, 1,
625                              &lsa_domains, &lsa_names);
626         if (!NT_STATUS_IS_OK(result)) {
627                 TALLOC_FREE(tmp_ctx);
628                 return result;
629         }
630
631         num_mapped = 0;
632         for (i=0; i<num_members; i++) {
633                 if (lsa_names[i].type != SID_NAME_USER) {
634                         DEBUG(2, ("Got %s as group member -- ignoring\n",
635                                   sid_type_lookup(lsa_names[i].type)));
636                         continue;
637                 }
638                 if (!((*names)[num_mapped] = talloc_strdup((*names),
639                                                   lsa_names[i].name))) {
640                         TALLOC_FREE(tmp_ctx);
641                         return NT_STATUS_NO_MEMORY;
642                 }
643
644                 (*name_types)[num_mapped] = lsa_names[i].type;
645
646                 num_mapped += 1;
647         }
648
649         *num_names = num_mapped;
650
651         TALLOC_FREE(tmp_ctx);
652         return NT_STATUS_OK;
653 }
654
655 /* get a list of trusted domains */
656 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
657                                 TALLOC_CTX *mem_ctx,
658                                 uint32 *num_domains,
659                                 char ***names,
660                                 char ***alt_names,
661                                 DOM_SID **dom_sids)
662 {
663         NTSTATUS nt_status;
664         struct trustdom_info **domains;
665         int i;
666         TALLOC_CTX *tmp_ctx;
667
668         *num_domains = 0;
669         *names = NULL;
670         *alt_names = NULL;
671         *dom_sids = NULL;
672
673         if (!(tmp_ctx = talloc_init("trusted_domains"))) {
674                 return NT_STATUS_NO_MEMORY;
675         }
676
677         nt_status = pdb_enum_trusteddoms(tmp_ctx, num_domains, &domains);
678         if (!NT_STATUS_IS_OK(nt_status)) {
679                 TALLOC_FREE(tmp_ctx);
680                 return nt_status;
681         }
682
683         if (*num_domains) {
684                 *names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
685                 *alt_names = TALLOC_ARRAY(mem_ctx, char *, *num_domains);
686                 *dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_domains);
687
688                 if ((*alt_names == NULL) || (*names == NULL) || (*dom_sids == NULL)) {
689                         TALLOC_FREE(tmp_ctx);
690                         return NT_STATUS_NO_MEMORY;
691                 }
692         } else {
693                 *names = NULL;
694                 *alt_names = NULL;
695                 *dom_sids = NULL;
696         }
697
698         for (i=0; i<*num_domains; i++) {
699                 (*alt_names)[i] = NULL;
700                 if (!((*names)[i] = talloc_strdup((*names),
701                                                   domains[i]->name))) {
702                         TALLOC_FREE(tmp_ctx);
703                         return NT_STATUS_NO_MEMORY;
704                 }
705                 sid_copy(&(*dom_sids)[i], &domains[i]->sid);
706         }
707
708         TALLOC_FREE(tmp_ctx);
709         return NT_STATUS_OK;
710 }
711
712 /* the rpc backend methods are exposed via this structure */
713 struct winbindd_methods builtin_passdb_methods = {
714         false,
715         builtin_query_user_list,
716         builtin_enum_dom_groups,
717         enum_local_groups,
718         name_to_sid,
719         sid_to_name,
720         rids_to_names,
721         builtin_query_user,
722         lookup_usergroups,
723         lookup_useraliases,
724         builtin_lookup_groupmem,
725         sequence_number,
726         lockout_policy,
727         password_policy,
728         builtin_trusted_domains,
729 };
730
731 /* the rpc backend methods are exposed via this structure */
732 struct winbindd_methods sam_passdb_methods = {
733         false,
734         sam_query_user_list,
735         sam_enum_dom_groups,
736         enum_local_groups,
737         name_to_sid,
738         sid_to_name,
739         rids_to_names,
740         sam_query_user,
741         lookup_usergroups,
742         lookup_useraliases,
743         sam_lookup_groupmem,
744         sequence_number,
745         lockout_policy,
746         password_policy,
747         sam_trusted_domains,
748 };