b6aa95c51ead41e5f2ffa6f193e5a25331f4b8ae
[samba.git] / source3 / nsswitch / winbindd_ads.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind ADS backend functions
5
6    Copyright (C) Andrew Tridgell 2001
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8    Copyright (C) Gerald (Jerry) Carter 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "winbindd.h"
27
28 #ifdef HAVE_ADS
29
30 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_WINBIND
32
33 extern struct winbindd_methods reconnect_methods;
34
35 /*
36   return our ads connections structure for a domain. We keep the connection
37   open to make things faster
38 */
39 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
40 {
41         ADS_STRUCT *ads;
42         ADS_STATUS status;
43         fstring dc_name;
44         struct in_addr dc_ip;   
45
46         DEBUG(10,("ads_cached_connection\n"));
47
48         if (domain->private_data) {
49
50                 time_t expire;
51                 time_t now = time(NULL);
52
53                 /* check for a valid structure */
54                 ads = (ADS_STRUCT *)domain->private_data;
55
56                 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
57
58                 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
59                           (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
60
61                 if ( ads->config.realm && (expire > now)) {
62                         return ads;
63                 } else {
64                         /* we own this ADS_STRUCT so make sure it goes away */
65                         DEBUG(7,("Deleting expired krb5 credential cache\n"));
66                         ads->is_mine = True;
67                         ads_destroy( &ads );
68                         ads_kdestroy("MEMORY:winbind_ccache");
69                         domain->private_data = NULL;
70                 }       
71         }
72
73         /* we don't want this to affect the users ccache */
74         setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
75
76         ads = ads_init(domain->alt_name, domain->name, NULL);
77         if (!ads) {
78                 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
79                 return NULL;
80         }
81
82         /* the machine acct password might have change - fetch it every time */
83
84         SAFE_FREE(ads->auth.password);
85         SAFE_FREE(ads->auth.realm);
86
87         if ( IS_DC ) {
88                 DOM_SID sid;
89                 time_t last_set_time;
90
91                 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, &sid, &last_set_time ) ) {
92                         ads_destroy( &ads );
93                         return NULL;
94                 }
95                 ads->auth.realm = SMB_STRDUP( ads->server.realm );
96                 strupper_m( ads->auth.realm );
97         }
98         else {
99                 struct winbindd_domain *our_domain = domain;
100
101                 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
102
103                 /* always give preference to the alt_name in our 
104                    primary domain if possible */
105
106                 if ( !domain->primary )
107                         our_domain = find_our_domain();
108
109                 if ( our_domain->alt_name[0] != '\0' ) {
110                         ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
111                         strupper_m( ads->auth.realm );
112                 }
113                 else
114                         ads->auth.realm = SMB_STRDUP( lp_realm() );
115         }
116
117         ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
118
119         /* Setup the server affinity cache.  We don't reaally care
120            about the name.  Just setup affinity and the KRB5_CONFIG 
121            file. */
122
123         get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ip );
124         
125         status = ads_connect(ads);
126         if (!ADS_ERR_OK(status) || !ads->config.realm) {
127                 DEBUG(1,("ads_connect for domain %s failed: %s\n", 
128                          domain->name, ads_errstr(status)));
129                 ads_destroy(&ads);
130
131                 /* if we get ECONNREFUSED then it might be a NT4
132                    server, fall back to MSRPC */
133                 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
134                     status.err.rc == ECONNREFUSED) {
135                         /* 'reconnect_methods' is the MS-RPC backend. */
136                         DEBUG(1,("Trying MSRPC methods\n"));
137                         domain->backend = &reconnect_methods;
138                 }
139                 return NULL;
140         }
141
142         /* set the flag that says we don't own the memory even 
143            though we do so that ads_destroy() won't destroy the 
144            structure we pass back by reference */
145
146         ads->is_mine = False;
147
148         domain->private_data = (void *)ads;
149         return ads;
150 }
151
152
153 /* Query display info for a realm. This is the basic user list fn */
154 static NTSTATUS query_user_list(struct winbindd_domain *domain,
155                                TALLOC_CTX *mem_ctx,
156                                uint32 *num_entries, 
157                                WINBIND_USERINFO **info)
158 {
159         ADS_STRUCT *ads = NULL;
160         const char *attrs[] = { "*", NULL };
161         int i, count;
162         ADS_STATUS rc;
163         LDAPMessage *res = NULL;
164         LDAPMessage *msg = NULL;
165         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
166
167         *num_entries = 0;
168
169         DEBUG(3,("ads: query_user_list\n"));
170
171         if ( !winbindd_can_contact_domain( domain ) ) {
172                 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
173                           domain->name));               
174                 return NT_STATUS_OK;
175         }
176
177         ads = ads_cached_connection(domain);
178         
179         if (!ads) {
180                 domain->last_status = NT_STATUS_SERVER_DISABLED;
181                 goto done;
182         }
183
184         rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
185         if (!ADS_ERR_OK(rc) || !res) {
186                 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
187                 goto done;
188         }
189
190         count = ads_count_replies(ads, res);
191         if (count == 0) {
192                 DEBUG(1,("query_user_list: No users found\n"));
193                 goto done;
194         }
195
196         (*info) = TALLOC_ZERO_ARRAY(mem_ctx, WINBIND_USERINFO, count);
197         if (!*info) {
198                 status = NT_STATUS_NO_MEMORY;
199                 goto done;
200         }
201
202         i = 0;
203
204         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
205                 char *name, *gecos = NULL;
206                 char *homedir = NULL;
207                 char *shell = NULL;
208                 uint32 group;
209                 uint32 atype;
210                 DOM_SID user_sid;
211                 gid_t primary_gid = (gid_t)-1;
212
213                 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
214                     ads_atype_map(atype) != SID_NAME_USER) {
215                         DEBUG(1,("Not a user account? atype=0x%x\n", atype));
216                         continue;
217                 }
218
219                 name = ads_pull_username(ads, mem_ctx, msg);
220
221                 if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
222                         status = nss_get_info_cached( domain, &user_sid, mem_ctx, 
223                                                ads, msg, &homedir, &shell, &gecos,
224                                                &primary_gid );
225                 }
226
227                 if (gecos == NULL) {
228                         gecos = ads_pull_string(ads, mem_ctx, msg, "name");
229                 }
230         
231                 if (!ads_pull_sid(ads, msg, "objectSid",
232                                   &(*info)[i].user_sid)) {
233                         DEBUG(1,("No sid for %s !?\n", name));
234                         continue;
235                 }
236                 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
237                         DEBUG(1,("No primary group for %s !?\n", name));
238                         continue;
239                 }
240
241                 (*info)[i].acct_name = name;
242                 (*info)[i].full_name = gecos;
243                 (*info)[i].homedir = homedir;
244                 (*info)[i].shell = shell;
245                 (*info)[i].primary_gid = primary_gid;
246                 sid_compose(&(*info)[i].group_sid, &domain->sid, group);
247                 i++;
248         }
249
250         (*num_entries) = i;
251         status = NT_STATUS_OK;
252
253         DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
254
255 done:
256         if (res) 
257                 ads_msgfree(ads, res);
258
259         return status;
260 }
261
262 /* list all domain groups */
263 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
264                                 TALLOC_CTX *mem_ctx,
265                                 uint32 *num_entries, 
266                                 struct acct_info **info)
267 {
268         ADS_STRUCT *ads = NULL;
269         const char *attrs[] = {"userPrincipalName", "sAMAccountName",
270                                "name", "objectSid", NULL};
271         int i, count;
272         ADS_STATUS rc;
273         LDAPMessage *res = NULL;
274         LDAPMessage *msg = NULL;
275         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
276         const char *filter;
277         BOOL enum_dom_local_groups = False;
278
279         *num_entries = 0;
280
281         DEBUG(3,("ads: enum_dom_groups\n"));
282
283         if ( !winbindd_can_contact_domain( domain ) ) {
284                 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
285                           domain->name));               
286                 return NT_STATUS_OK;
287         }
288
289         /* only grab domain local groups for our domain */
290         if ( domain->active_directory && strequal(lp_realm(), domain->alt_name)  ) {
291                 enum_dom_local_groups = True;
292         }
293
294         /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
295          * rollup-fixes:
296          *
297          * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
298          * default value, it MUST be absent. In case of extensible matching the
299          * "dnattr" boolean defaults to FALSE and so it must be only be present
300          * when set to TRUE. 
301          *
302          * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
303          * filter using bitwise matching rule then the buggy AD fails to decode
304          * the extensible match. As a workaround set it to TRUE and thereby add
305          * the dnAttributes "dn" field to cope with those older AD versions.
306          * It should not harm and won't put any additional load on the AD since
307          * none of the dn components have a bitmask-attribute.
308          *
309          * Thanks to Ralf Haferkamp for input and testing - Guenther */
310
311         filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))", 
312                                  ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
313                                  ADS_LDAP_MATCHING_RULE_BIT_AND, 
314                                  enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
315
316         if (filter == NULL) {
317                 status = NT_STATUS_NO_MEMORY;
318                 goto done;
319         }
320
321         ads = ads_cached_connection(domain);
322
323         if (!ads) {
324                 domain->last_status = NT_STATUS_SERVER_DISABLED;
325                 goto done;
326         }
327
328         rc = ads_search_retry(ads, &res, filter, attrs);
329         if (!ADS_ERR_OK(rc) || !res) {
330                 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
331                 goto done;
332         }
333
334         count = ads_count_replies(ads, res);
335         if (count == 0) {
336                 DEBUG(1,("enum_dom_groups: No groups found\n"));
337                 goto done;
338         }
339
340         (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
341         if (!*info) {
342                 status = NT_STATUS_NO_MEMORY;
343                 goto done;
344         }
345
346         i = 0;
347         
348         for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
349                 char *name, *gecos;
350                 DOM_SID sid;
351                 uint32 rid;
352
353                 name = ads_pull_username(ads, mem_ctx, msg);
354                 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
355                 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
356                         DEBUG(1,("No sid for %s !?\n", name));
357                         continue;
358                 }
359
360                 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
361                         DEBUG(1,("No rid for %s !?\n", name));
362                         continue;
363                 }
364
365                 fstrcpy((*info)[i].acct_name, name);
366                 fstrcpy((*info)[i].acct_desc, gecos);
367                 (*info)[i].rid = rid;
368                 i++;
369         }
370
371         (*num_entries) = i;
372
373         status = NT_STATUS_OK;
374
375         DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
376
377 done:
378         if (res) 
379                 ads_msgfree(ads, res);
380
381         return status;
382 }
383
384 /* list all domain local groups */
385 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
386                                 TALLOC_CTX *mem_ctx,
387                                 uint32 *num_entries, 
388                                 struct acct_info **info)
389 {
390         /*
391          * This is a stub function only as we returned the domain 
392          * local groups in enum_dom_groups() if the domain->native field
393          * was true.  This is a simple performance optimization when
394          * using LDAP.
395          *
396          * if we ever need to enumerate domain local groups separately, 
397          * then this the optimization in enum_dom_groups() will need 
398          * to be split out
399          */
400         *num_entries = 0;
401         
402         return NT_STATUS_OK;
403 }
404
405 /* If you are looking for "dn_lookup": Yes, it used to be here!
406  * It has gone now since it was a major speed bottleneck in
407  * lookup_groupmem (its only use). It has been replaced by
408  * an rpc lookup sids call... R.I.P. */
409
410 /* Lookup user information from a rid */
411 static NTSTATUS query_user(struct winbindd_domain *domain, 
412                            TALLOC_CTX *mem_ctx, 
413                            const DOM_SID *sid, 
414                            WINBIND_USERINFO *info)
415 {
416         ADS_STRUCT *ads = NULL;
417         const char *attrs[] = { "*", NULL };
418         ADS_STATUS rc;
419         int count;
420         LDAPMessage *msg = NULL;
421         char *ldap_exp;
422         char *sidstr;
423         uint32 group_rid;
424         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
425         NET_USER_INFO_3 *user;
426
427         DEBUG(3,("ads: query_user\n"));
428
429         info->homedir = NULL;
430         info->shell = NULL;
431         info->primary_gid = (gid_t)-1;
432
433         /* try netsamlogon cache first */
434                         
435         if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL ) 
436         {
437                                 
438                 DEBUG(5,("query_user: Cache lookup succeeded for %s\n", 
439                         sid_string_static(sid)));
440
441                 sid_compose(&info->user_sid, &domain->sid, user->user_rid);
442                 sid_compose(&info->group_sid, &domain->sid, user->group_rid);
443                                 
444                 info->acct_name = unistr2_tdup(mem_ctx, &user->uni_user_name);
445                 info->full_name = unistr2_tdup(mem_ctx, &user->uni_full_name);
446                 
447                 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
448                               &info->homedir, &info->shell, &info->full_name, 
449                               &info->primary_gid );     
450
451                 TALLOC_FREE(user);
452                                 
453                 return NT_STATUS_OK;
454         }
455
456         if ( !winbindd_can_contact_domain(domain)) {
457                 DEBUG(8,("query_user: No incoming trust from domain %s\n",
458                          domain->name));
459
460                 /* We still need to generate some basic information
461                    about the user even if we cannot contact the 
462                    domain.  Most of this stuff we can deduce. */
463
464                 sid_copy( &info->user_sid, sid );
465
466                 /* Assume "Domain Users" for the primary group */
467
468                 sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );
469
470                 /* Try to fill in what the nss_info backend can do */
471
472                 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL, 
473                               &info->homedir, &info->shell, &info->full_name, 
474                               &info->primary_gid );
475
476                 status = NT_STATUS_OK;
477                 goto done;
478         }
479
480         /* no cache...do the query */
481
482         if ( (ads = ads_cached_connection(domain)) == NULL ) {
483                 domain->last_status = NT_STATUS_SERVER_DISABLED;
484                 goto done;
485         }
486
487         sidstr = sid_binstring(sid);
488         asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
489         rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
490         free(ldap_exp);
491         free(sidstr);
492         if (!ADS_ERR_OK(rc) || !msg) {
493                 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
494                          sid_string_static(sid), ads_errstr(rc)));
495                 goto done;
496         }
497
498         count = ads_count_replies(ads, msg);
499         if (count != 1) {
500                 DEBUG(1,("query_user(sid=%s): Not found\n",
501                          sid_string_static(sid)));
502                 goto done;
503         }
504
505         info->acct_name = ads_pull_username(ads, mem_ctx, msg);
506
507         nss_get_info_cached( domain, sid, mem_ctx, ads, msg, 
508                       &info->homedir, &info->shell, &info->full_name, 
509                       &info->primary_gid );     
510
511         if (info->full_name == NULL) {
512                 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
513         }
514
515         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
516                 DEBUG(1,("No primary group for %s !?\n",
517                          sid_string_static(sid)));
518                 goto done;
519         }
520
521         sid_copy(&info->user_sid, sid);
522         sid_compose(&info->group_sid, &domain->sid, group_rid);
523
524         status = NT_STATUS_OK;
525
526         DEBUG(3,("ads query_user gave %s\n", info->acct_name));
527 done:
528         if (msg) 
529                 ads_msgfree(ads, msg);
530
531         return status;
532 }
533
534 /* Lookup groups a user is a member of - alternate method, for when
535    tokenGroups are not available. */
536 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
537                                          TALLOC_CTX *mem_ctx,
538                                          const char *user_dn, 
539                                          DOM_SID *primary_group,
540                                          size_t *p_num_groups, DOM_SID **user_sids)
541 {
542         ADS_STATUS rc;
543         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
544         int count;
545         LDAPMessage *res = NULL;
546         LDAPMessage *msg = NULL;
547         char *ldap_exp;
548         ADS_STRUCT *ads;
549         const char *group_attrs[] = {"objectSid", NULL};
550         char *escaped_dn;
551         size_t num_groups = 0;
552
553         DEBUG(3,("ads: lookup_usergroups_member\n"));
554
555         if ( !winbindd_can_contact_domain( domain ) ) {
556                 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
557                           domain->name));               
558                 return NT_STATUS_OK;
559         }
560
561         ads = ads_cached_connection(domain);
562
563         if (!ads) {
564                 domain->last_status = NT_STATUS_SERVER_DISABLED;
565                 goto done;
566         }
567
568         if (!(escaped_dn = escape_ldap_string_alloc(user_dn))) {
569                 status = NT_STATUS_NO_MEMORY;
570                 goto done;
571         }
572
573         ldap_exp = talloc_asprintf(mem_ctx,
574                 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
575                 escaped_dn,
576                 ADS_LDAP_MATCHING_RULE_BIT_AND,
577                 GROUP_TYPE_SECURITY_ENABLED);
578         if (!ldap_exp) {
579                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
580                 SAFE_FREE(escaped_dn);
581                 status = NT_STATUS_NO_MEMORY;
582                 goto done;
583         }
584
585         SAFE_FREE(escaped_dn);
586
587         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
588         
589         if (!ADS_ERR_OK(rc) || !res) {
590                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
591                 return ads_ntstatus(rc);
592         }
593         
594         count = ads_count_replies(ads, res);
595         
596         *user_sids = NULL;
597         num_groups = 0;
598
599         /* always add the primary group to the sid array */
600         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
601                 status = NT_STATUS_NO_MEMORY;
602                 goto done;
603         }
604
605         if (count > 0) {
606                 for (msg = ads_first_entry(ads, res); msg;
607                      msg = ads_next_entry(ads, msg)) {
608                         DOM_SID group_sid;
609                 
610                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
611                                 DEBUG(1,("No sid for this group ?!?\n"));
612                                 continue;
613                         }
614         
615                         /* ignore Builtin groups from ADS - Guenther */
616                         if (sid_check_is_in_builtin(&group_sid)) {
617                                 continue;
618                         }
619                                
620                         if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
621                                          &num_groups)) {
622                                 status = NT_STATUS_NO_MEMORY;
623                                 goto done;
624                         }
625                 }
626
627         }
628
629         *p_num_groups = num_groups;
630         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
631
632         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
633 done:
634         if (res) 
635                 ads_msgfree(ads, res);
636
637         return status;
638 }
639
640 /* Lookup groups a user is a member of - alternate method, for when
641    tokenGroups are not available. */
642 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
643                                            TALLOC_CTX *mem_ctx,
644                                            const char *user_dn, 
645                                            DOM_SID *primary_group,
646                                            size_t *p_num_groups, DOM_SID **user_sids)
647 {
648         ADS_STATUS rc;
649         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
650         ADS_STRUCT *ads;
651         const char *attrs[] = {"memberOf", NULL};
652         size_t num_groups = 0;
653         DOM_SID *group_sids = NULL;
654         int i;
655         char **strings;
656         size_t num_strings = 0;
657
658
659         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
660
661         if ( !winbindd_can_contact_domain( domain ) ) {
662                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n",
663                           domain->name));               
664                 return NT_STATUS_OK;
665         }
666
667         ads = ads_cached_connection(domain);
668
669         if (!ads) {
670                 domain->last_status = NT_STATUS_SERVER_DISABLED;
671                 goto done;
672         }
673
674         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, 
675                                                  ADS_EXTENDED_DN_HEX_STRING, 
676                                                  &strings, &num_strings);
677
678         if (!ADS_ERR_OK(rc)) {
679                 DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", 
680                         user_dn, ads_errstr(rc)));
681                 return ads_ntstatus(rc);
682         }
683         
684         *user_sids = NULL;
685         num_groups = 0;
686
687         /* always add the primary group to the sid array */
688         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
689                 status = NT_STATUS_NO_MEMORY;
690                 goto done;
691         }
692
693         group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
694         if (!group_sids) {
695                 TALLOC_FREE(strings);
696                 status = NT_STATUS_NO_MEMORY;
697                 goto done;
698         }
699
700         for (i=0; i<num_strings; i++) {
701
702                 if (!ads_get_sid_from_extended_dn(mem_ctx, strings[i], 
703                                                   ADS_EXTENDED_DN_HEX_STRING, 
704                                                   &(group_sids)[i])) {
705                         TALLOC_FREE(group_sids);
706                         TALLOC_FREE(strings);
707                         status = NT_STATUS_NO_MEMORY;
708                         goto done;
709                 }
710         }
711
712         if (i == 0) {
713                 DEBUG(1,("No memberOf for this user?!?\n"));
714                 status = NT_STATUS_NO_MEMORY;
715                 goto done;
716         }
717
718         for (i=0; i<num_strings; i++) {
719
720                 /* ignore Builtin groups from ADS - Guenther */
721                 if (sid_check_is_in_builtin(&group_sids[i])) {
722                         continue;
723                 }
724                        
725                 if (!add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
726                                  &num_groups)) {
727                         status = NT_STATUS_NO_MEMORY;
728                         goto done;
729                 }
730         
731         }
732
733         *p_num_groups = num_groups;
734         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
735
736         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn));
737 done:
738         TALLOC_FREE(group_sids);
739
740         return status;
741 }
742
743
744 /* Lookup groups a user is a member of. */
745 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
746                                   TALLOC_CTX *mem_ctx,
747                                   const DOM_SID *sid, 
748                                   uint32 *p_num_groups, DOM_SID **user_sids)
749 {
750         ADS_STRUCT *ads = NULL;
751         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
752         ADS_STATUS rc;
753         int count;
754         LDAPMessage *msg = NULL;
755         char *user_dn = NULL;
756         DOM_SID *sids;
757         int i;
758         DOM_SID primary_group;
759         uint32 primary_group_rid;
760         fstring sid_string;
761         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
762         size_t num_groups = 0;
763
764         DEBUG(3,("ads: lookup_usergroups\n"));
765         *p_num_groups = 0;
766
767         status = lookup_usergroups_cached(domain, mem_ctx, sid, 
768                                           p_num_groups, user_sids);
769         if (NT_STATUS_IS_OK(status)) {
770                 return NT_STATUS_OK;
771         }
772
773         if ( !winbindd_can_contact_domain( domain ) ) {
774                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
775                           domain->name));
776
777                 /* Tell the cache manager not to remember this one */
778
779                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
780         }
781
782         ads = ads_cached_connection(domain);
783         
784         if (!ads) {
785                 domain->last_status = NT_STATUS_SERVER_DISABLED;
786                 status = NT_STATUS_SERVER_DISABLED;
787                 goto done;
788         }
789
790         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
791
792         if (!ADS_ERR_OK(rc)) {
793                 status = ads_ntstatus(rc);
794                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", 
795                          sid_to_string(sid_string, sid), ads_errstr(rc)));
796                 goto done;
797         }
798         
799         count = ads_count_replies(ads, msg);
800         if (count != 1) {
801                 status = NT_STATUS_UNSUCCESSFUL;
802                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
803                          "invalid number of results (count=%d)\n", 
804                          sid_to_string(sid_string, sid), count));
805                 goto done;
806         }
807
808         if (!msg) {
809                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
810                          sid_to_string(sid_string, sid)));
811                 status = NT_STATUS_UNSUCCESSFUL;
812                 goto done;
813         }
814
815         user_dn = ads_get_dn(ads, msg);
816         if (user_dn == NULL) {
817                 status = NT_STATUS_NO_MEMORY;
818                 goto done;
819         }
820
821         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
822                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
823                          domain->name, sid_to_string(sid_string, sid)));
824                 goto done;
825         }
826
827         sid_copy(&primary_group, &domain->sid);
828         sid_append_rid(&primary_group, primary_group_rid);
829
830         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
831
832         /* there must always be at least one group in the token, 
833            unless we are talking to a buggy Win2k server */
834
835         /* actually this only happens when the machine account has no read
836          * permissions on the tokenGroup attribute - gd */
837
838         if (count == 0) {
839
840                 /* no tokenGroups */
841                 
842                 /* lookup what groups this user is a member of by DN search on
843                  * "memberOf" */
844
845                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
846                                                     &primary_group,
847                                                     &num_groups, user_sids);
848                 *p_num_groups = (uint32)num_groups;
849                 if (NT_STATUS_IS_OK(status)) {
850                         goto done;
851                 }
852
853                 /* lookup what groups this user is a member of by DN search on
854                  * "member" */
855
856                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
857                                                   &primary_group,
858                                                   &num_groups, user_sids);
859                 *p_num_groups = (uint32)num_groups;
860                 goto done;
861         }
862
863         *user_sids = NULL;
864         num_groups = 0;
865
866         if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
867                 status = NT_STATUS_NO_MEMORY;
868                 goto done;
869         }
870         
871         for (i=0;i<count;i++) {
872
873                 /* ignore Builtin groups from ADS - Guenther */
874                 if (sid_check_is_in_builtin(&sids[i])) {
875                         continue;
876                 }
877                                
878                 if (!add_sid_to_array_unique(mem_ctx, &sids[i],
879                                         user_sids, &num_groups)) {
880                         status = NT_STATUS_NO_MEMORY;
881                         goto done;
882                 }
883         }
884
885         *p_num_groups = (uint32)num_groups;
886         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
887
888         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
889                  sid_to_string(sid_string, sid)));
890 done:
891         ads_memfree(ads, user_dn);
892         ads_msgfree(ads, msg);
893         return status;
894 }
895
896 /*
897   find the members of a group, given a group rid and domain
898  */
899 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
900                                 TALLOC_CTX *mem_ctx,
901                                 const DOM_SID *group_sid, uint32 *num_names, 
902                                 DOM_SID **sid_mem, char ***names, 
903                                 uint32 **name_types)
904 {
905         ADS_STATUS rc;
906         ADS_STRUCT *ads = NULL;
907         char *ldap_exp;
908         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
909         char *sidbinstr;
910         char **members = NULL;
911         int i;
912         size_t num_members = 0;
913         ads_control args;
914         struct rpc_pipe_client *cli;
915         POLICY_HND lsa_policy;
916         DOM_SID *sid_mem_nocache = NULL;
917         char **names_nocache = NULL;
918         uint32 *name_types_nocache = NULL;
919         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
920         uint32 num_nocache = 0;
921         TALLOC_CTX *tmp_ctx = NULL;
922
923         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, 
924                   sid_string_static(group_sid)));
925
926         *num_names = 0;
927
928         tmp_ctx = talloc_new(mem_ctx);
929         if (!tmp_ctx) {
930                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
931                 status = NT_STATUS_NO_MEMORY;
932                 goto done;
933         }
934
935         if ( !winbindd_can_contact_domain( domain ) ) {
936                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
937                           domain->name));               
938                 return NT_STATUS_OK;
939         }
940
941         ads = ads_cached_connection(domain);
942         
943         if (!ads) {
944                 domain->last_status = NT_STATUS_SERVER_DISABLED;
945                 goto done;
946         }
947
948         if ((sidbinstr = sid_binstring(group_sid)) == NULL) {
949                 status = NT_STATUS_NO_MEMORY;
950                 goto done;
951         }
952
953         /* search for all members of the group */
954         if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", 
955                                          sidbinstr))) 
956         {
957                 SAFE_FREE(sidbinstr);
958                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
959                 status = NT_STATUS_NO_MEMORY;
960                 goto done;
961         }
962         SAFE_FREE(sidbinstr);
963
964         args.control = ADS_EXTENDED_DN_OID;
965         args.val = ADS_EXTENDED_DN_HEX_STRING;
966         args.critical = True;
967
968         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path, 
969                                ldap_exp, &args, "member", &members, &num_members);
970
971         if (!ADS_ERR_OK(rc)) {
972                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
973                 status = NT_STATUS_UNSUCCESSFUL;
974                 goto done;
975         } 
976         
977         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
978         
979         /* Now that we have a list of sids, we need to get the
980          * lists of names and name_types belonging to these sids.
981          * even though conceptually not quite clean,  we use the 
982          * RPC call lsa_lookup_sids for this since it can handle a 
983          * list of sids. ldap calls can just resolve one sid at a time.
984          *
985          * At this stage, the sids are still hidden in the exetended dn
986          * member output format. We actually do a little better than
987          * stated above: In extracting the sids from the member strings,
988          * we try to resolve as many sids as possible from the
989          * cache. Only the rest is passed to the lsa_lookup_sids call. */
990         
991         if (num_members) {
992                 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
993                 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
994                 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
995                 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, DOM_SID, num_members);
996
997                 if ((members == NULL) || (*sid_mem == NULL) ||
998                     (*names == NULL) || (*name_types == NULL) ||
999                     (sid_mem_nocache == NULL))
1000                 {
1001                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1002                         status = NT_STATUS_NO_MEMORY;
1003                         goto done;
1004                 }
1005         }
1006         else {
1007                 (*sid_mem) = NULL;
1008                 (*names) = NULL;
1009                 (*name_types) = NULL;
1010         }
1011
1012         for (i=0; i<num_members; i++) {
1013                 uint32 name_type;
1014                 char *name, *domain_name;
1015                 DOM_SID sid;
1016
1017                 if (!ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, &sid)) {
1018                         status = NT_STATUS_INVALID_PARAMETER;
1019                         goto done;
1020                 }
1021                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, &name_type)) {
1022                         DEBUG(10,("ads: lookup_groupmem: got sid %s from cache\n",
1023                                  sid_string_static(&sid)));
1024                         sid_copy(&(*sid_mem)[*num_names], &sid);
1025                         (*names)[*num_names] = talloc_asprintf(*names, "%s%c%s",
1026                                                                domain_name,
1027                                                                *lp_winbind_separator(),
1028                                                                name );
1029
1030                         (*name_types)[*num_names] = name_type;
1031                         (*num_names)++;
1032                 }
1033                 else {
1034                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in cache\n",
1035                                   sid_string_static(&sid)));
1036                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1037                         num_nocache++;
1038                 }
1039         }
1040
1041         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1042                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1043
1044         /* handle sids not resolved from cache by lsa_lookup_sids */
1045         if (num_nocache > 0) {
1046
1047                 status = cm_connect_lsa(domain, tmp_ctx, &cli, &lsa_policy);
1048
1049                 if (!NT_STATUS_IS_OK(status)) {
1050                         goto done;
1051                 }
1052
1053                 status = rpccli_lsa_lookup_sids_all(cli, tmp_ctx, 
1054                                                     &lsa_policy,
1055                                                     num_nocache, 
1056                                                     sid_mem_nocache, 
1057                                                     &domains_nocache, 
1058                                                     &names_nocache, 
1059                                                     &name_types_nocache);
1060
1061                 if (NT_STATUS_IS_OK(status) ||
1062                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) 
1063                 {
1064                         /* Copy the entries over from the "_nocache" arrays 
1065                          * to the result arrays, skipping the gaps the 
1066                          * lookup_sids call left. */
1067                         for (i=0; i < num_nocache; i++) {
1068                                 if (((names_nocache)[i] != NULL) && 
1069                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN)) 
1070                                 {
1071                                         sid_copy(&(*sid_mem)[*num_names],
1072                                                  &sid_mem_nocache[i]);
1073                                         (*names)[*num_names] = talloc_asprintf( *names, 
1074                                                                                 "%s%c%s",
1075                                                                                 domains_nocache[i],
1076                                                                                 *lp_winbind_separator(),
1077                                                                                 names_nocache[i] );
1078                                         (*name_types)[*num_names] = name_types_nocache[i];
1079                                         (*num_names)++;
1080                                 }
1081                         }
1082                 }
1083                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1084                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1085                                    "not map any SIDs at all.\n"));
1086                         /* Don't handle this as an error here.
1087                          * There is nothing left to do with respect to the 
1088                          * overall result... */
1089                 }
1090                 else if (!NT_STATUS_IS_OK(status)) {
1091                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1092                                    "sids via rpc_lsa_lookup_sids: %s\n",
1093                                    (int)num_members, nt_errstr(status)));
1094                         goto done;
1095                 }
1096         }
1097
1098         status = NT_STATUS_OK;
1099         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1100                  sid_string_static(group_sid)));
1101
1102 done:
1103
1104         TALLOC_FREE(tmp_ctx);
1105
1106         return status;
1107 }
1108
1109 /* find the sequence number for a domain */
1110 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1111 {
1112         ADS_STRUCT *ads = NULL;
1113         ADS_STATUS rc;
1114
1115         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1116
1117         if ( !winbindd_can_contact_domain( domain ) ) {
1118                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1119                           domain->name));
1120                 *seq = time(NULL);              
1121                 return NT_STATUS_OK;
1122         }
1123
1124         *seq = DOM_SEQUENCE_NONE;
1125
1126         ads = ads_cached_connection(domain);
1127         
1128         if (!ads) {
1129                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1130                 return NT_STATUS_UNSUCCESSFUL;
1131         }
1132
1133         rc = ads_USN(ads, seq);
1134         
1135         if (!ADS_ERR_OK(rc)) {
1136         
1137                 /* its a dead connection, destroy it */
1138
1139                 if (domain->private_data) {
1140                         ads = (ADS_STRUCT *)domain->private_data;
1141                         ads->is_mine = True;
1142                         ads_destroy(&ads);
1143                         ads_kdestroy("MEMORY:winbind_ccache");
1144                         domain->private_data = NULL;
1145                 }
1146         }
1147         return ads_ntstatus(rc);
1148 }
1149
1150 /* get a list of trusted domains */
1151 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1152                                 TALLOC_CTX *mem_ctx,
1153                                 uint32 *num_domains,
1154                                 char ***names,
1155                                 char ***alt_names,
1156                                 DOM_SID **dom_sids)
1157 {
1158         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1159         struct ds_domain_trust  *domains = NULL;
1160         int                     count = 0;
1161         int                     i;
1162         uint32                  flags;  
1163         struct rpc_pipe_client *cli;
1164         uint32                 fr_flags = (DS_DOMAIN_IN_FOREST | DS_DOMAIN_TREE_ROOT);  
1165         int ret_count;
1166         
1167         DEBUG(3,("ads: trusted_domains\n"));
1168
1169         *num_domains = 0;
1170         *alt_names   = NULL;
1171         *names       = NULL;
1172         *dom_sids    = NULL;
1173
1174         /* If this is our primary domain or a root in our forest,
1175            query for all trusts.  If not, then just look for domain
1176            trusts in the target forest */
1177
1178         if ( domain->primary ||
1179                 ((domain->domain_flags&fr_flags) == fr_flags) ) 
1180         {
1181                 flags = DS_DOMAIN_DIRECT_OUTBOUND | 
1182                         DS_DOMAIN_DIRECT_INBOUND | 
1183                         DS_DOMAIN_IN_FOREST;
1184         } else {
1185                 flags = DS_DOMAIN_IN_FOREST;
1186         }       
1187
1188         result = cm_connect_netlogon(domain, &cli);
1189
1190         if (!NT_STATUS_IS_OK(result)) {
1191                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1192                           "for PIPE_NETLOGON (%s)\n", 
1193                           domain->name, nt_errstr(result)));
1194                 return NT_STATUS_UNSUCCESSFUL;
1195         }
1196         
1197         if ( NT_STATUS_IS_OK(result) ) {
1198                 result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
1199                                                       cli->cli->desthost, 
1200                                                       flags, &domains,
1201                                                       (unsigned int *)&count);
1202         }
1203         
1204         if ( NT_STATUS_IS_OK(result) && count) {
1205
1206                 /* Allocate memory for trusted domain names and sids */
1207
1208                 if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
1209                         DEBUG(0, ("trusted_domains: out of memory\n"));
1210                         return NT_STATUS_NO_MEMORY;
1211                 }
1212
1213                 if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
1214                         DEBUG(0, ("trusted_domains: out of memory\n"));
1215                         return NT_STATUS_NO_MEMORY;
1216                 }
1217
1218                 if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
1219                         DEBUG(0, ("trusted_domains: out of memory\n"));
1220                         return NT_STATUS_NO_MEMORY;
1221                 }
1222
1223                 /* Copy across names and sids */
1224
1225
1226                 ret_count = 0;          
1227                 for (i = 0; i < count; i++) {
1228                         struct winbindd_domain d;
1229                         
1230                         /* drop external trusts if this is not our primary 
1231                            domain.  This means that the returned number of 
1232                            domains may be less that the ones actually trusted
1233                            by the DC. */
1234
1235                         if ( (domains[i].trust_attributes == DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN) && 
1236                              !domain->primary ) 
1237                         {
1238                                 DEBUG(10,("trusted_domains: Skipping external trusted domain "
1239                                           "%s because it is outside of our primary domain\n",
1240                                           domains[i].netbios_domain));                          
1241                                 continue;                               
1242                         }
1243                         
1244                         (*names)[ret_count] = domains[i].netbios_domain;
1245                         (*alt_names)[ret_count] = domains[i].dns_domain;
1246                         sid_copy(&(*dom_sids)[ret_count], &domains[i].sid);
1247
1248                         /* add to the trusted domain cache */
1249
1250                         fstrcpy( d.name,  domains[i].netbios_domain );
1251                         fstrcpy( d.alt_name, domains[i].dns_domain );                   
1252                         sid_copy( &d.sid, &domains[i].sid );
1253
1254                         /* This gets a little tricky.  If we are
1255                            following a transitive forest trust, then
1256                            innerit the flags, type, and attrins from
1257                            the domain we queried to make sure we don't
1258                            record the view of the trust from the wrong
1259                            side.  Always view it from the side of our
1260                            primary domain.   --jerry */
1261                         if ( domain->primary ||
1262                              ((domain->domain_flags&fr_flags) == fr_flags) ) 
1263                         {
1264                                 DEBUG(10,("trusted_domains(ads):  Storing trust "
1265                                           "flags for domain %s\n", d.alt_name));
1266
1267                                 /* Look this up in cache to make sure
1268                                    we have the current trust flags and
1269                                    attributes */
1270
1271                                 d.domain_flags = domains[i].flags;
1272                                 d.domain_type = domains[i].trust_type;
1273                                 d.domain_trust_attribs = domains[i].trust_attributes;
1274                         } else {
1275                                 DEBUG(10,("trusted_domains(ads):  Inheriting trust "
1276                                           "flags for domain %s\n", d.alt_name));                                
1277                                 d.domain_flags = domain->domain_flags;                          
1278                                 d.domain_type  = domain->domain_type;
1279                                 d.domain_trust_attribs = domain->domain_trust_attribs;
1280                         }
1281
1282                         wcache_tdc_add_domain( &d );
1283
1284                         ret_count++;
1285
1286                 }
1287
1288                 *num_domains = ret_count;       
1289         }
1290
1291         return result;
1292 }
1293
1294 /* the ADS backend methods are exposed via this structure */
1295 struct winbindd_methods ads_methods = {
1296         True,
1297         query_user_list,
1298         enum_dom_groups,
1299         enum_local_groups,
1300         msrpc_name_to_sid,
1301         msrpc_sid_to_name,
1302         msrpc_rids_to_names,
1303         query_user,
1304         lookup_usergroups,
1305         msrpc_lookup_useraliases,
1306         lookup_groupmem,
1307         sequence_number,
1308         msrpc_lockout_policy,
1309         msrpc_password_policy,
1310         trusted_domains,
1311 };
1312
1313 #endif