root/source3/winbindd/winbindd_ads.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ads_cached_connection
  2. query_user_list
  3. enum_dom_groups
  4. enum_local_groups
  5. name_to_sid
  6. sid_to_name
  7. rids_to_names
  8. query_user
  9. lookup_usergroups_member
  10. lookup_usergroups_memberof
  11. lookup_usergroups
  12. lookup_useraliases
  13. lookup_groupmem
  14. sequence_number
  15. lockout_policy
  16. password_policy
  17. trusted_domains

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

/* [<][>][^][v][top][bottom][index][help] */