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