5dd7eafcd18565e65d8a4ea33d28c0c2535c8015
[sfrench/samba-autobuild/.git] / source / 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         if (!(ldap_exp = talloc_asprintf(mem_ctx, "(&(member=%s)(objectCategory=group))", escaped_dn))) {
574                 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
575                 SAFE_FREE(escaped_dn);
576                 status = NT_STATUS_NO_MEMORY;
577                 goto done;
578         }
579
580         SAFE_FREE(escaped_dn);
581
582         rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
583         
584         if (!ADS_ERR_OK(rc) || !res) {
585                 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
586                 return ads_ntstatus(rc);
587         }
588         
589         count = ads_count_replies(ads, res);
590         
591         *user_sids = NULL;
592         num_groups = 0;
593
594         /* always add the primary group to the sid array */
595         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
596                 status = NT_STATUS_NO_MEMORY;
597                 goto done;
598         }
599
600         if (count > 0) {
601                 for (msg = ads_first_entry(ads, res); msg;
602                      msg = ads_next_entry(ads, msg)) {
603                         DOM_SID group_sid;
604                 
605                         if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
606                                 DEBUG(1,("No sid for this group ?!?\n"));
607                                 continue;
608                         }
609         
610                         /* ignore Builtin groups from ADS - Guenther */
611                         if (sid_check_is_in_builtin(&group_sid)) {
612                                 continue;
613                         }
614                                
615                         if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
616                                          &num_groups)) {
617                                 status = NT_STATUS_NO_MEMORY;
618                                 goto done;
619                         }
620                 }
621
622         }
623
624         *p_num_groups = num_groups;
625         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
626
627         DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
628 done:
629         if (res) 
630                 ads_msgfree(ads, res);
631
632         return status;
633 }
634
635 /* Lookup groups a user is a member of - alternate method, for when
636    tokenGroups are not available. */
637 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
638                                            TALLOC_CTX *mem_ctx,
639                                            const char *user_dn, 
640                                            DOM_SID *primary_group,
641                                            size_t *p_num_groups, DOM_SID **user_sids)
642 {
643         ADS_STATUS rc;
644         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
645         ADS_STRUCT *ads;
646         const char *attrs[] = {"memberOf", NULL};
647         size_t num_groups = 0;
648         DOM_SID *group_sids = NULL;
649         int i;
650         char **strings;
651         size_t num_strings = 0;
652
653
654         DEBUG(3,("ads: lookup_usergroups_memberof\n"));
655
656         if ( !winbindd_can_contact_domain( domain ) ) {
657                 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n",
658                           domain->name));               
659                 return NT_STATUS_OK;
660         }
661
662         ads = ads_cached_connection(domain);
663
664         if (!ads) {
665                 domain->last_status = NT_STATUS_SERVER_DISABLED;
666                 goto done;
667         }
668
669         rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs, 
670                                                  ADS_EXTENDED_DN_HEX_STRING, 
671                                                  &strings, &num_strings);
672
673         if (!ADS_ERR_OK(rc)) {
674                 DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n", 
675                         user_dn, ads_errstr(rc)));
676                 return ads_ntstatus(rc);
677         }
678         
679         *user_sids = NULL;
680         num_groups = 0;
681
682         /* always add the primary group to the sid array */
683         if (!add_sid_to_array(mem_ctx, primary_group, user_sids, &num_groups)) {
684                 status = NT_STATUS_NO_MEMORY;
685                 goto done;
686         }
687
688         group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
689         if (!group_sids) {
690                 TALLOC_FREE(strings);
691                 status = NT_STATUS_NO_MEMORY;
692                 goto done;
693         }
694
695         for (i=0; i<num_strings; i++) {
696
697                 if (!ads_get_sid_from_extended_dn(mem_ctx, strings[i], 
698                                                   ADS_EXTENDED_DN_HEX_STRING, 
699                                                   &(group_sids)[i])) {
700                         TALLOC_FREE(group_sids);
701                         TALLOC_FREE(strings);
702                         status = NT_STATUS_NO_MEMORY;
703                         goto done;
704                 }
705         }
706
707         if (i == 0) {
708                 DEBUG(1,("No memberOf for this user?!?\n"));
709                 status = NT_STATUS_NO_MEMORY;
710                 goto done;
711         }
712
713         for (i=0; i<num_strings; i++) {
714
715                 /* ignore Builtin groups from ADS - Guenther */
716                 if (sid_check_is_in_builtin(&group_sids[i])) {
717                         continue;
718                 }
719                        
720                 if (!add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
721                                  &num_groups)) {
722                         status = NT_STATUS_NO_MEMORY;
723                         goto done;
724                 }
725         
726         }
727
728         *p_num_groups = num_groups;
729         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
730
731         DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn));
732 done:
733         TALLOC_FREE(group_sids);
734
735         return status;
736 }
737
738
739 /* Lookup groups a user is a member of. */
740 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
741                                   TALLOC_CTX *mem_ctx,
742                                   const DOM_SID *sid, 
743                                   uint32 *p_num_groups, DOM_SID **user_sids)
744 {
745         ADS_STRUCT *ads = NULL;
746         const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
747         ADS_STATUS rc;
748         int count;
749         LDAPMessage *msg = NULL;
750         char *user_dn = NULL;
751         DOM_SID *sids;
752         int i;
753         DOM_SID primary_group;
754         uint32 primary_group_rid;
755         fstring sid_string;
756         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
757         size_t num_groups = 0;
758
759         DEBUG(3,("ads: lookup_usergroups\n"));
760         *p_num_groups = 0;
761
762         status = lookup_usergroups_cached(domain, mem_ctx, sid, 
763                                           p_num_groups, user_sids);
764         if (NT_STATUS_IS_OK(status)) {
765                 return NT_STATUS_OK;
766         }
767
768         if ( !winbindd_can_contact_domain( domain ) ) {
769                 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
770                           domain->name));
771
772                 /* Tell the cache manager not to remember this one */
773
774                 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
775         }
776
777         ads = ads_cached_connection(domain);
778         
779         if (!ads) {
780                 domain->last_status = NT_STATUS_SERVER_DISABLED;
781                 status = NT_STATUS_SERVER_DISABLED;
782                 goto done;
783         }
784
785         rc = ads_search_retry_sid(ads, &msg, sid, attrs);
786
787         if (!ADS_ERR_OK(rc)) {
788                 status = ads_ntstatus(rc);
789                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n", 
790                          sid_to_string(sid_string, sid), ads_errstr(rc)));
791                 goto done;
792         }
793         
794         count = ads_count_replies(ads, msg);
795         if (count != 1) {
796                 status = NT_STATUS_UNSUCCESSFUL;
797                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
798                          "invalid number of results (count=%d)\n", 
799                          sid_to_string(sid_string, sid), count));
800                 goto done;
801         }
802
803         if (!msg) {
804                 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n", 
805                          sid_to_string(sid_string, sid)));
806                 status = NT_STATUS_UNSUCCESSFUL;
807                 goto done;
808         }
809
810         user_dn = ads_get_dn(ads, msg);
811         if (user_dn == NULL) {
812                 status = NT_STATUS_NO_MEMORY;
813                 goto done;
814         }
815
816         if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
817                 DEBUG(1,("%s: No primary group for sid=%s !?\n", 
818                          domain->name, sid_to_string(sid_string, sid)));
819                 goto done;
820         }
821
822         sid_copy(&primary_group, &domain->sid);
823         sid_append_rid(&primary_group, primary_group_rid);
824
825         count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
826
827         /* there must always be at least one group in the token, 
828            unless we are talking to a buggy Win2k server */
829
830         /* actually this only happens when the machine account has no read
831          * permissions on the tokenGroup attribute - gd */
832
833         if (count == 0) {
834
835                 /* no tokenGroups */
836                 
837                 /* lookup what groups this user is a member of by DN search on
838                  * "memberOf" */
839
840                 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
841                                                     &primary_group,
842                                                     &num_groups, user_sids);
843                 *p_num_groups = (uint32)num_groups;
844                 if (NT_STATUS_IS_OK(status)) {
845                         goto done;
846                 }
847
848                 /* lookup what groups this user is a member of by DN search on
849                  * "member" */
850
851                 status = lookup_usergroups_member(domain, mem_ctx, user_dn, 
852                                                   &primary_group,
853                                                   &num_groups, user_sids);
854                 *p_num_groups = (uint32)num_groups;
855                 goto done;
856         }
857
858         *user_sids = NULL;
859         num_groups = 0;
860
861         if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
862                 status = NT_STATUS_NO_MEMORY;
863                 goto done;
864         }
865         
866         for (i=0;i<count;i++) {
867
868                 /* ignore Builtin groups from ADS - Guenther */
869                 if (sid_check_is_in_builtin(&sids[i])) {
870                         continue;
871                 }
872                                
873                 if (!add_sid_to_array_unique(mem_ctx, &sids[i],
874                                         user_sids, &num_groups)) {
875                         status = NT_STATUS_NO_MEMORY;
876                         goto done;
877                 }
878         }
879
880         *p_num_groups = (uint32)num_groups;
881         status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
882
883         DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
884                  sid_to_string(sid_string, sid)));
885 done:
886         ads_memfree(ads, user_dn);
887         ads_msgfree(ads, msg);
888         return status;
889 }
890
891 /*
892   find the members of a group, given a group rid and domain
893  */
894 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
895                                 TALLOC_CTX *mem_ctx,
896                                 const DOM_SID *group_sid, uint32 *num_names, 
897                                 DOM_SID **sid_mem, char ***names, 
898                                 uint32 **name_types)
899 {
900         ADS_STATUS rc;
901         ADS_STRUCT *ads = NULL;
902         char *ldap_exp;
903         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
904         char *sidbinstr;
905         char **members = NULL;
906         int i;
907         size_t num_members = 0;
908         ads_control args;
909         struct rpc_pipe_client *cli;
910         POLICY_HND lsa_policy;
911         DOM_SID *sid_mem_nocache = NULL;
912         char **names_nocache = NULL;
913         uint32 *name_types_nocache = NULL;
914         char **domains_nocache = NULL;     /* only needed for rpccli_lsa_lookup_sids */
915         uint32 num_nocache = 0;
916         TALLOC_CTX *tmp_ctx = NULL;
917
918         DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name, 
919                   sid_string_static(group_sid)));
920
921         *num_names = 0;
922
923         tmp_ctx = talloc_new(mem_ctx);
924         if (!tmp_ctx) {
925                 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
926                 status = NT_STATUS_NO_MEMORY;
927                 goto done;
928         }
929
930         if ( !winbindd_can_contact_domain( domain ) ) {
931                 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
932                           domain->name));               
933                 return NT_STATUS_OK;
934         }
935
936         ads = ads_cached_connection(domain);
937         
938         if (!ads) {
939                 domain->last_status = NT_STATUS_SERVER_DISABLED;
940                 goto done;
941         }
942
943         if ((sidbinstr = sid_binstring(group_sid)) == NULL) {
944                 status = NT_STATUS_NO_MEMORY;
945                 goto done;
946         }
947
948         /* search for all members of the group */
949         if (!(ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", 
950                                          sidbinstr))) 
951         {
952                 SAFE_FREE(sidbinstr);
953                 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
954                 status = NT_STATUS_NO_MEMORY;
955                 goto done;
956         }
957         SAFE_FREE(sidbinstr);
958
959         args.control = ADS_EXTENDED_DN_OID;
960         args.val = ADS_EXTENDED_DN_HEX_STRING;
961         args.critical = True;
962
963         rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path, 
964                                ldap_exp, &args, "member", &members, &num_members);
965
966         if (!ADS_ERR_OK(rc)) {
967                 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
968                 status = NT_STATUS_UNSUCCESSFUL;
969                 goto done;
970         } 
971         
972         DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
973         
974         /* Now that we have a list of sids, we need to get the
975          * lists of names and name_types belonging to these sids.
976          * even though conceptually not quite clean,  we use the 
977          * RPC call lsa_lookup_sids for this since it can handle a 
978          * list of sids. ldap calls can just resolve one sid at a time.
979          *
980          * At this stage, the sids are still hidden in the exetended dn
981          * member output format. We actually do a little better than
982          * stated above: In extracting the sids from the member strings,
983          * we try to resolve as many sids as possible from the
984          * cache. Only the rest is passed to the lsa_lookup_sids call. */
985         
986         if (num_members) {
987                 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
988                 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
989                 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
990                 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, DOM_SID, num_members);
991
992                 if ((members == NULL) || (*sid_mem == NULL) ||
993                     (*names == NULL) || (*name_types == NULL) ||
994                     (sid_mem_nocache == NULL))
995                 {
996                         DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
997                         status = NT_STATUS_NO_MEMORY;
998                         goto done;
999                 }
1000         }
1001         else {
1002                 (*sid_mem) = NULL;
1003                 (*names) = NULL;
1004                 (*name_types) = NULL;
1005         }
1006
1007         for (i=0; i<num_members; i++) {
1008                 uint32 name_type;
1009                 char *name, *domain_name;
1010                 DOM_SID sid;
1011
1012                 if (!ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val, &sid)) {
1013                         status = NT_STATUS_INVALID_PARAMETER;
1014                         goto done;
1015                 }
1016                 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name, &name_type)) {
1017                         DEBUG(10,("ads: lookup_groupmem: got sid %s from cache\n",
1018                                  sid_string_static(&sid)));
1019                         sid_copy(&(*sid_mem)[*num_names], &sid);
1020                         (*names)[*num_names] = CONST_DISCARD(char *,name);
1021                         (*name_types)[*num_names] = name_type;
1022                         (*num_names)++;
1023                 }
1024                 else {
1025                         DEBUG(10, ("ads: lookup_groupmem: sid %s not found in cache\n",
1026                                   sid_string_static(&sid)));
1027                         sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1028                         num_nocache++;
1029                 }
1030         }
1031
1032         DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1033                   "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1034
1035         /* handle sids not resolved from cache by lsa_lookup_sids */
1036         if (num_nocache > 0) {
1037
1038                 status = cm_connect_lsa(domain, tmp_ctx, &cli, &lsa_policy);
1039
1040                 if (!NT_STATUS_IS_OK(status)) {
1041                         goto done;
1042                 }
1043
1044                 status = rpccli_lsa_lookup_sids_all(cli, tmp_ctx, 
1045                                                     &lsa_policy,
1046                                                     num_nocache, 
1047                                                     sid_mem_nocache, 
1048                                                     &domains_nocache, 
1049                                                     &names_nocache, 
1050                                                     &name_types_nocache);
1051
1052                 if (NT_STATUS_IS_OK(status) ||
1053                     NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) 
1054                 {
1055                         /* Copy the entries over from the "_nocache" arrays 
1056                          * to the result arrays, skipping the gaps the 
1057                          * lookup_sids call left. */
1058                         *num_names = 0;
1059                         for (i=0; i < num_nocache; i++) {
1060                                 if (((names_nocache)[i] != NULL) && 
1061                                     ((name_types_nocache)[i] != SID_NAME_UNKNOWN)) 
1062                                 {
1063                                         sid_copy(&(*sid_mem)[*num_names],
1064                                                  &sid_mem_nocache[i]);
1065                                         (*names)[*num_names] = talloc_move(*names, &names_nocache[i]);
1066                                         (*name_types)[*num_names] = name_types_nocache[i];
1067                                         (*num_names)++;
1068                                 }
1069                         }
1070                 }
1071                 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1072                         DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1073                                    "not map any SIDs at all.\n"));
1074                         /* Don't handle this as an error here.
1075                          * There is nothing left to do with respect to the 
1076                          * overall result... */
1077                 }
1078                 else if (!NT_STATUS_IS_OK(status)) {
1079                         DEBUG(10, ("lookup_groupmem: Error looking up %d "
1080                                    "sids via rpc_lsa_lookup_sids: %s\n",
1081                                    (int)num_members, nt_errstr(status)));
1082                         goto done;
1083                 }
1084         }
1085
1086         status = NT_STATUS_OK;
1087         DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1088                  sid_string_static(group_sid)));
1089
1090 done:
1091
1092         TALLOC_FREE(tmp_ctx);
1093
1094         return status;
1095 }
1096
1097 /* find the sequence number for a domain */
1098 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1099 {
1100         ADS_STRUCT *ads = NULL;
1101         ADS_STATUS rc;
1102
1103         DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1104
1105         if ( !winbindd_can_contact_domain( domain ) ) {
1106                 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1107                           domain->name));
1108                 *seq = time(NULL);              
1109                 return NT_STATUS_OK;
1110         }
1111
1112         *seq = DOM_SEQUENCE_NONE;
1113
1114         ads = ads_cached_connection(domain);
1115         
1116         if (!ads) {
1117                 domain->last_status = NT_STATUS_SERVER_DISABLED;
1118                 return NT_STATUS_UNSUCCESSFUL;
1119         }
1120
1121         rc = ads_USN(ads, seq);
1122         
1123         if (!ADS_ERR_OK(rc)) {
1124         
1125                 /* its a dead connection, destroy it */
1126
1127                 if (domain->private_data) {
1128                         ads = (ADS_STRUCT *)domain->private_data;
1129                         ads->is_mine = True;
1130                         ads_destroy(&ads);
1131                         ads_kdestroy("MEMORY:winbind_ccache");
1132                         domain->private_data = NULL;
1133                 }
1134         }
1135         return ads_ntstatus(rc);
1136 }
1137
1138 /* get a list of trusted domains */
1139 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1140                                 TALLOC_CTX *mem_ctx,
1141                                 uint32 *num_domains,
1142                                 char ***names,
1143                                 char ***alt_names,
1144                                 DOM_SID **dom_sids)
1145 {
1146         NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
1147         struct ds_domain_trust  *domains = NULL;
1148         int                     count = 0;
1149         int                     i;
1150         uint32                  flags;  
1151         struct rpc_pipe_client *cli;
1152         uint32                 fr_flags = (DS_DOMAIN_IN_FOREST | DS_DOMAIN_TREE_ROOT);  
1153         int ret_count;
1154         
1155         DEBUG(3,("ads: trusted_domains\n"));
1156
1157         *num_domains = 0;
1158         *alt_names   = NULL;
1159         *names       = NULL;
1160         *dom_sids    = NULL;
1161
1162         /* If this is our primary domain or a root in our forest,
1163            query for all trusts.  If not, then just look for domain
1164            trusts in the target forest */
1165
1166         if ( domain->primary ||
1167                 ((domain->domain_flags&fr_flags) == fr_flags) ) 
1168         {
1169                 flags = DS_DOMAIN_DIRECT_OUTBOUND | 
1170                         DS_DOMAIN_DIRECT_INBOUND | 
1171                         DS_DOMAIN_IN_FOREST;
1172         } else {
1173                 flags = DS_DOMAIN_IN_FOREST;
1174         }       
1175
1176         result = cm_connect_netlogon(domain, &cli);
1177
1178         if (!NT_STATUS_IS_OK(result)) {
1179                 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1180                           "for PIPE_NETLOGON (%s)\n", 
1181                           domain->name, nt_errstr(result)));
1182                 return NT_STATUS_UNSUCCESSFUL;
1183         }
1184         
1185         if ( NT_STATUS_IS_OK(result) ) {
1186                 result = rpccli_ds_enum_domain_trusts(cli, mem_ctx,
1187                                                       cli->cli->desthost, 
1188                                                       flags, &domains,
1189                                                       (unsigned int *)&count);
1190         }
1191         
1192         if ( NT_STATUS_IS_OK(result) && count) {
1193
1194                 /* Allocate memory for trusted domain names and sids */
1195
1196                 if ( !(*names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
1197                         DEBUG(0, ("trusted_domains: out of memory\n"));
1198                         return NT_STATUS_NO_MEMORY;
1199                 }
1200
1201                 if ( !(*alt_names = TALLOC_ARRAY(mem_ctx, char *, count)) ) {
1202                         DEBUG(0, ("trusted_domains: out of memory\n"));
1203                         return NT_STATUS_NO_MEMORY;
1204                 }
1205
1206                 if ( !(*dom_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, count)) ) {
1207                         DEBUG(0, ("trusted_domains: out of memory\n"));
1208                         return NT_STATUS_NO_MEMORY;
1209                 }
1210
1211                 /* Copy across names and sids */
1212
1213
1214                 ret_count = 0;          
1215                 for (i = 0; i < count; i++) {
1216                         struct winbindd_domain d;
1217                         
1218                         /* drop external trusts if this is not our primary 
1219                            domain.  This means that the returned number of 
1220                            domains may be less that the ones actually trusted
1221                            by the DC. */
1222
1223                         if ( (domains[i].trust_attributes == DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN) && 
1224                              !domain->primary ) 
1225                         {
1226                                 DEBUG(10,("trusted_domains: Skipping external trusted domain "
1227                                           "%s because it is outside of our primary domain\n",
1228                                           domains[i].netbios_domain));                          
1229                                 continue;                               
1230                         }
1231                         
1232                         (*names)[ret_count] = domains[i].netbios_domain;
1233                         (*alt_names)[ret_count] = domains[i].dns_domain;
1234                         sid_copy(&(*dom_sids)[ret_count], &domains[i].sid);
1235
1236                         /* add to the trusted domain cache */
1237
1238                         fstrcpy( d.name,  domains[i].netbios_domain );
1239                         fstrcpy( d.alt_name, domains[i].dns_domain );                   
1240                         sid_copy( &d.sid, &domains[i].sid );
1241
1242                         /* This gets a little tricky.  If we are
1243                            following a transitive forest trust, then
1244                            innerit the flags, type, and attrins from
1245                            the domain we queried to make sure we don't
1246                            record the view of the trust from the wrong
1247                            side.  Always view it from the side of our
1248                            primary domain.   --jerry */
1249                         if ( domain->primary ||
1250                              ((domain->domain_flags&fr_flags) == fr_flags) ) 
1251                         {
1252                                 DEBUG(10,("trusted_domains(ads):  Storing trust "
1253                                           "flags for domain %s\n", d.alt_name));
1254
1255                                 /* Look this up in cache to make sure
1256                                    we have the current trust flags and
1257                                    attributes */
1258
1259                                 d.domain_flags = domains[i].flags;
1260                                 d.domain_type = domains[i].trust_type;
1261                                 d.domain_trust_attribs = domains[i].trust_attributes;
1262                         } else {
1263                                 DEBUG(10,("trusted_domains(ads):  Inheriting trust "
1264                                           "flags for domain %s\n", d.alt_name));                                
1265                                 d.domain_flags = domain->domain_flags;                          
1266                                 d.domain_type  = domain->domain_type;
1267                                 d.domain_trust_attribs = domain->domain_trust_attribs;
1268                         }
1269
1270                         wcache_tdc_add_domain( &d );
1271
1272                         ret_count++;
1273
1274                 }
1275
1276                 *num_domains = ret_count;       
1277         }
1278
1279         return result;
1280 }
1281
1282 /* the ADS backend methods are exposed via this structure */
1283 struct winbindd_methods ads_methods = {
1284         True,
1285         query_user_list,
1286         enum_dom_groups,
1287         enum_local_groups,
1288         msrpc_name_to_sid,
1289         msrpc_sid_to_name,
1290         msrpc_rids_to_names,
1291         query_user,
1292         lookup_usergroups,
1293         msrpc_lookup_useraliases,
1294         lookup_groupmem,
1295         sequence_number,
1296         msrpc_lockout_policy,
1297         msrpc_password_policy,
1298         trusted_domains,
1299 };
1300
1301 #endif