root/source3/winbindd/idmap_adex/gc_util.c

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

DEFINITIONS

This source file includes following definitions.
  1. gc_list_head
  2. is_subdomain
  3. gc_find_forest_root
  4. gc_add_forest
  5. gc_server_list_destroy
  6. gc_init_list
  7. gc_search_start
  8. gc_search_forest
  9. gc_search_all_forests
  10. gc_search_all_forests_unique
  11. gc_name_to_sid
  12. get_object_account_name
  13. gc_sid_to_name
  14. add_ads_result_to_array
  15. free_result_array
  16. check_result_unique

   1 /*
   2  * idmap_adex: Global Catalog search interface
   3  *
   4  * Copyright (C) Gerald (Jerry) Carter 2007-2008
   5  *
   6  * This program is free software; you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as published by
   8  * the Free Software Foundation; either version 2 of the License, or
   9  * (at your option) any later version.
  10  *
  11  * This program is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  *
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program; if not, write to the Free Software
  18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19  */
  20 
  21 #include "includes.h"
  22 #include "idmap_adex.h"
  23 
  24 #undef DBGC_CLASS
  25 #define DBGC_CLASS DBGC_IDMAP
  26 
  27 static struct gc_info *_gc_server_list = NULL;
  28 
  29 
  30 /**********************************************************************
  31  *********************************************************************/
  32 
  33 static struct gc_info *gc_list_head(void)
     /* [<][>][^][v][top][bottom][index][help] */
  34 {
  35         return _gc_server_list;
  36 }
  37 
  38 /**********************************************************************
  39  Checks if either of the domains is a subdomain of the other
  40  *********************************************************************/
  41 
  42 static bool is_subdomain(const char* a, const char *b)
     /* [<][>][^][v][top][bottom][index][help] */
  43 {
  44         char *s;
  45         TALLOC_CTX *frame = talloc_stackframe();
  46         char *x, *y;
  47         bool ret = false;
  48 
  49         /* Trivial cases */
  50 
  51         if (!a && !b)
  52                 return true;
  53 
  54         if (!a || !b)
  55                 return false;
  56 
  57         /* Normalize the case */
  58 
  59         x = talloc_strdup(frame, a);
  60         y = talloc_strdup(frame, b);
  61         if (!x || !y) {
  62                 ret = false;
  63                 goto done;
  64         }
  65 
  66         strupper_m(x);
  67         strupper_m(y);
  68 
  69         /* Exact match */
  70 
  71         if (strcmp(x, y) == 0) {
  72                 ret = true;
  73                 goto done;
  74         }
  75 
  76         /* Check for trailing substrings */
  77 
  78         s = strstr_m(x, y);
  79         if (s && (strlen(s) == strlen(y))) {
  80                 ret = true;
  81                 goto done;
  82         }
  83 
  84         s = strstr_m(y, x);
  85         if (s && (strlen(s) == strlen(x))) {
  86                 ret = true;
  87                 goto done;
  88         }
  89 
  90 done:
  91         talloc_destroy(frame);
  92 
  93         return ret;
  94 }
  95 
  96 /**********************************************************************
  97  *********************************************************************/
  98 
  99  NTSTATUS gc_find_forest_root(struct gc_info *gc, const char *domain)
     /* [<][>][^][v][top][bottom][index][help] */
 100 {
 101         ADS_STRUCT *ads = NULL;
 102         ADS_STATUS ads_status;
 103         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 104         struct NETLOGON_SAM_LOGON_RESPONSE_EX cldap_reply;
 105         TALLOC_CTX *frame = talloc_stackframe();
 106 
 107         if (!gc || !domain) {
 108                 return NT_STATUS_INVALID_PARAMETER;
 109         }
 110 
 111         ZERO_STRUCT(cldap_reply);
 112 
 113         ads = ads_init(domain, NULL, NULL);
 114         BAIL_ON_PTR_ERROR(ads, nt_status);
 115 
 116         ads->auth.flags = ADS_AUTH_NO_BIND;
 117         ads_status = ads_connect(ads);
 118         if (!ADS_ERR_OK(ads_status)) {
 119                 DEBUG(4, ("find_forest_root: ads_connect(%s) failed! (%s)\n",
 120                           domain, ads_errstr(ads_status)));
 121         }
 122         nt_status = ads_ntstatus(ads_status);
 123         BAIL_ON_NTSTATUS_ERROR(nt_status);
 124 
 125         if (!ads_cldap_netlogon_5(frame,
 126                                   ads->config.ldap_server_name,
 127                                   ads->config.realm,
 128                                   &cldap_reply))
 129         {
 130                 DEBUG(4,("find_forest_root: Failed to get a CLDAP reply from %s!\n",
 131                          ads->server.ldap_server));
 132                 nt_status = NT_STATUS_IO_TIMEOUT;
 133                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 134         }
 135 
 136         gc->forest_name = talloc_strdup(gc, cldap_reply.forest);
 137         BAIL_ON_PTR_ERROR(gc->forest_name, nt_status);
 138 
 139 done:
 140         if (ads) {
 141                 ads_destroy(&ads);
 142         }
 143 
 144         return nt_status;
 145 }
 146 
 147 /**********************************************************************
 148  *********************************************************************/
 149 
 150 static NTSTATUS gc_add_forest(const char *domain)
     /* [<][>][^][v][top][bottom][index][help] */
 151 {
 152         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 153         struct gc_info *gc = NULL;
 154         struct gc_info *find_gc = NULL;
 155         char *dn;
 156         ADS_STRUCT *ads = NULL;
 157         struct likewise_cell *primary_cell = NULL;
 158 
 159         primary_cell = cell_list_head();
 160         if (!primary_cell) {
 161                 nt_status = NT_STATUS_INVALID_SERVER_STATE;
 162                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 163         }
 164 
 165         /* Check for duplicates based on domain name first as this
 166            requires no connection */
 167 
 168         find_gc = gc_list_head();
 169         while (find_gc) {
 170                 if (strequal (find_gc->forest_name, domain))
 171                         break;
 172                 find_gc = find_gc->next;
 173         }
 174 
 175         if (find_gc) {
 176                 DEBUG(10,("gc_add_forest: %s already in list\n", find_gc->forest_name));
 177                 return NT_STATUS_OK;
 178         }
 179 
 180         if ((gc = TALLOC_ZERO_P(NULL, struct gc_info)) == NULL) {
 181                 nt_status = NT_STATUS_NO_MEMORY;
 182                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 183         }
 184 
 185         /* Query the rootDSE for the forest root naming conect first.
 186            Check that the a GC server for the forest has not already
 187            been added */
 188 
 189         nt_status = gc_find_forest_root(gc, domain);
 190         BAIL_ON_NTSTATUS_ERROR(nt_status);
 191 
 192         find_gc = gc_list_head();
 193         while (find_gc) {
 194                 if (strequal (find_gc->forest_name, gc->forest_name))
 195                         break;
 196                 find_gc = find_gc->next;
 197         }
 198 
 199         if (find_gc) {
 200                 DEBUG(10,("gc_add_forest: Forest %s already in list\n",
 201                           find_gc->forest_name));
 202                 return NT_STATUS_OK;
 203         }
 204 
 205         /* Not found, so add it here.  Make sure we connect to
 206            a DC in _this_ domain and not the forest root. */
 207 
 208         dn = ads_build_dn(gc->forest_name);
 209         BAIL_ON_PTR_ERROR(dn, nt_status);
 210 
 211         gc->search_base = talloc_strdup(gc, dn);
 212         SAFE_FREE(dn);
 213         BAIL_ON_PTR_ERROR(gc->search_base, nt_status);
 214 
 215 #if 0
 216         /* Can't use cell_connect_dn() here as there is no way to
 217            specifiy the LWCELL_FLAG_GC_CELL flag setting for cell_connect() */
 218 
 219         nt_status = cell_connect_dn(&gc->forest_cell, gc->search_base);
 220         BAIL_ON_NTSTATUS_ERROR(nt_status);
 221 #else
 222 
 223         gc->forest_cell = cell_new();
 224         BAIL_ON_PTR_ERROR(gc->forest_cell, nt_status);
 225 
 226         /* Set the DNS domain, dn, etc ... and add it to the list */
 227 
 228         cell_set_dns_domain(gc->forest_cell, gc->forest_name);
 229         cell_set_dn(gc->forest_cell, gc->search_base);
 230         cell_set_flags(gc->forest_cell, LWCELL_FLAG_GC_CELL);
 231 #endif
 232 
 233         /* It is possible to belong to a non-forest cell and a
 234            non-provisioned forest (at our domain levele). In that
 235            case, we should just inherit the flags from our primary
 236            cell since the GC searches will match our own schema
 237            model. */
 238 
 239         if (strequal(primary_cell->forest_name, gc->forest_name)
 240             || is_subdomain(primary_cell->dns_domain, gc->forest_name))
 241         {
 242                 cell_set_flags(gc->forest_cell, cell_flags(primary_cell));
 243         } else {
 244                 /* outside of our domain */
 245 
 246                 nt_status = cell_connect(gc->forest_cell);
 247                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 248 
 249                 nt_status = cell_lookup_settings(gc->forest_cell);
 250                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 251 
 252                 /* Drop the connection now that we have the settings */
 253 
 254                 ads = cell_connection(gc->forest_cell);
 255                 ads_destroy(&ads);
 256                 cell_set_connection(gc->forest_cell, NULL);
 257         }
 258 
 259         DLIST_ADD_END(_gc_server_list, gc, struct gc_info*);
 260 
 261         DEBUG(10,("gc_add_forest: Added %s to Global Catalog list of servers\n",
 262                   gc->forest_name));
 263 
 264         nt_status = NT_STATUS_OK;
 265 
 266 done:
 267         if (!NT_STATUS_IS_OK(nt_status)) {
 268                 talloc_destroy(gc);
 269                 DEBUG(3,("LWI: Failed to add new GC connection for %s (%s)\n",
 270                          domain, nt_errstr(nt_status)));
 271         }
 272 
 273         return nt_status;
 274 }
 275 
 276 /**********************************************************************
 277  *********************************************************************/
 278 
 279 static void gc_server_list_destroy(void)
     /* [<][>][^][v][top][bottom][index][help] */
 280 {
 281         struct gc_info *gc = gc_list_head();
 282 
 283         while (gc) {
 284                 struct gc_info *p = gc->next;
 285 
 286                 cell_destroy(gc->forest_cell);
 287                 talloc_destroy(gc);
 288 
 289                 gc = p;
 290         }
 291 
 292         _gc_server_list = NULL;
 293 
 294         return;
 295 }
 296 
 297 /**********************************************************************
 298  Setup the initial list of forests and initial the forest cell
 299  settings for each.  FIXME!!!
 300  *********************************************************************/
 301 
 302  NTSTATUS gc_init_list(void)
     /* [<][>][^][v][top][bottom][index][help] */
 303 {
 304         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 305         struct winbindd_tdc_domain *domains = NULL;
 306         size_t num_domains = 0;
 307         int i;
 308 
 309         if (_gc_server_list != NULL) {
 310                 gc_server_list_destroy();
 311         }
 312 
 313         if (!wcache_tdc_fetch_list(&domains, &num_domains)) {
 314                 nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 315                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 316         }
 317 
 318         /* Find our forest first.  Have to try all domains here starting
 319            with our own.  gc_add_forest() filters duplicates */
 320 
 321         nt_status = gc_add_forest(lp_realm());
 322         WARN_ON_NTSTATUS_ERROR(nt_status);
 323 
 324         for (i=0; i<num_domains; i++) {
 325                 uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST);
 326 
 327                 /* I think we should be able to break out of loop once
 328                    we add a GC for our forest and not have to test every one.
 329                    In fact, this entire loop is probably irrelevant since
 330                    the GC location code should always find a GC given lp_realm().
 331                    Will have to spend time testing before making the change.
 332                    --jerry */
 333 
 334                 if ((domains[i].trust_flags & flags) == flags) {
 335                         nt_status = gc_add_forest(domains[i].dns_name);
 336                         WARN_ON_NTSTATUS_ERROR(nt_status);
 337                         /* Don't BAIL here since not every domain may
 338                            have a GC server */
 339                 }
 340         }
 341 
 342         /* Now add trusted forests.  gc_add_forest() will filter out
 343            duplicates. Check everything with an incoming trust path
 344            that is not in our own forest.  */
 345 
 346         for (i=0; i<num_domains; i++) {
 347                 uint32_t flags = domains[i].trust_flags;
 348                 uint32_t attribs = domains[i].trust_attribs;
 349 
 350                 /* Skip non_AD domains */
 351 
 352                 if (strlen(domains[i].dns_name) == 0) {
 353                         continue;
 354                 }
 355 
 356                 /* Only add a GC for a forest outside of our own.
 357                    Ignore QUARANTINED/EXTERNAL trusts */
 358 
 359                 if ((flags & NETR_TRUST_FLAG_INBOUND)
 360                     && !(flags & NETR_TRUST_FLAG_IN_FOREST)
 361                     && (attribs & NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE))
 362                 {
 363                         nt_status = gc_add_forest(domains[i].dns_name);
 364                         WARN_ON_NTSTATUS_ERROR(nt_status);
 365                 }
 366         }
 367 
 368         nt_status = NT_STATUS_OK;
 369 
 370 done:
 371         if (!NT_STATUS_IS_OK(nt_status)) {
 372                 DEBUG(2,("LWI: Failed to initialized GC list (%s)\n",
 373                          nt_errstr(nt_status)));
 374         }
 375 
 376         TALLOC_FREE(domains);
 377 
 378         return nt_status;
 379 }
 380 
 381 
 382 /**********************************************************************
 383  *********************************************************************/
 384 
 385  struct gc_info *gc_search_start(void)
     /* [<][>][^][v][top][bottom][index][help] */
 386 {
 387         NTSTATUS nt_status = NT_STATUS_OK;
 388         struct gc_info *gc = gc_list_head();
 389 
 390         if (!gc) {
 391                 nt_status = gc_init_list();
 392                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 393 
 394                 gc = gc_list_head();
 395         }
 396 
 397 done:
 398         if (!NT_STATUS_IS_OK(nt_status)) {
 399                 DEBUG(2,("LWI: Failed to initialize GC list (%s)\n",
 400                          nt_errstr(nt_status)));
 401         }
 402 
 403         return gc;
 404 }
 405 
 406 /**********************************************************************
 407  Search Global Catalog.  Always search our own forest.  The flags set
 408  controls whether or not we search cross forest.  Assume that the
 409  resulting set is always returned from one GC so that we don't have to
 410  both combining the LDAPMessage * results
 411  *********************************************************************/
 412 
 413  NTSTATUS gc_search_forest(struct gc_info *gc,
     /* [<][>][^][v][top][bottom][index][help] */
 414                            LDAPMessage **msg,
 415                            const char *filter)
 416 {
 417         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 418         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
 419         const char *attrs[] = {"*", NULL};
 420         LDAPMessage *m = NULL;
 421 
 422         if (!gc || !msg || !filter) {
 423                 nt_status = NT_STATUS_INVALID_PARAMETER;
 424                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 425         }
 426 
 427         /* When you have multiple domain trees in a forest, the
 428            GC will search all naming contexts when you send it
 429            and empty ("") base search suffix.   Tested against
 430            Windows 2003.  */
 431 
 432         ads_status = cell_do_search(gc->forest_cell, "",
 433                                    LDAP_SCOPE_SUBTREE, filter, attrs, &m);
 434         nt_status = ads_ntstatus(ads_status);
 435         BAIL_ON_NTSTATUS_ERROR(nt_status);
 436 
 437         *msg = m;
 438 
 439 done:
 440         if (!NT_STATUS_IS_OK(nt_status)) {
 441                 DEBUG(2,("LWI: Forest wide search %s failed (%s)\n",
 442                          filter, nt_errstr(nt_status)));
 443         }
 444 
 445         return nt_status;
 446 }
 447 
 448 /**********************************************************************
 449  Search all forests via GC and return the results in an array of
 450  ADS_STRUCT/LDAPMessage pairs.
 451  *********************************************************************/
 452 
 453  NTSTATUS gc_search_all_forests(const char *filter,
     /* [<][>][^][v][top][bottom][index][help] */
 454                                 ADS_STRUCT ***ads_list,
 455                                 LDAPMessage ***msg_list,
 456                                 int *num_resp, uint32_t flags)
 457 {
 458         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 459         struct gc_info *gc = NULL;
 460         uint32_t test_flags = ADEX_GC_SEARCH_CHECK_UNIQUE;
 461 
 462         *ads_list = NULL;
 463         *msg_list = NULL;
 464         *num_resp = 0;
 465 
 466         if ((gc = gc_search_start()) == NULL) {
 467                 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
 468                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 469         }
 470 
 471         while (gc) {
 472                 LDAPMessage *m = NULL;
 473 
 474                 nt_status = gc_search_forest(gc, &m, filter);
 475                 if (!NT_STATUS_IS_OK(nt_status)) {
 476                         gc = gc->next;
 477                         continue;
 478                 }
 479 
 480                 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
 481                                                     m, ads_list, msg_list,
 482                                                     num_resp);
 483                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 484 
 485                 /* If there can only be one match, then we are done */
 486 
 487                 if ((*num_resp > 0) && ((flags & test_flags) == test_flags)) {
 488                         break;
 489                 }
 490 
 491                 gc = gc->next;
 492         }
 493 
 494         if (*num_resp == 0) {
 495                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 496                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 497         }
 498 
 499         nt_status = NT_STATUS_OK;
 500 
 501 done:
 502         return nt_status;
 503 }
 504 
 505 /**********************************************************************
 506  Search all forests via GC and return the results in an array of
 507  ADS_STRUCT/LDAPMessage pairs.
 508  *********************************************************************/
 509 
 510  NTSTATUS gc_search_all_forests_unique(const char *filter,
     /* [<][>][^][v][top][bottom][index][help] */
 511                                        ADS_STRUCT **ads,
 512                                        LDAPMessage **msg)
 513 {
 514         ADS_STRUCT **ads_list = NULL;
 515         LDAPMessage **msg_list = NULL;
 516         int num_resp;
 517         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 518 
 519         nt_status = gc_search_all_forests(filter, &ads_list,
 520                                           &msg_list, &num_resp,
 521                                           ADEX_GC_SEARCH_CHECK_UNIQUE);
 522         BAIL_ON_NTSTATUS_ERROR(nt_status);
 523 
 524         nt_status = check_result_unique(ads_list[0], msg_list[0]);
 525         BAIL_ON_NTSTATUS_ERROR(nt_status);
 526 
 527         *ads = ads_list[0];
 528         *msg = msg_list[0];
 529 
 530 done:
 531         /* Be care that we don't free the msg result being returned */
 532 
 533         if (!NT_STATUS_IS_OK(nt_status)) {
 534                 free_result_array(ads_list, msg_list, num_resp);
 535         } else {
 536                 talloc_destroy(ads_list);
 537                 talloc_destroy(msg_list);
 538         }
 539 
 540         return nt_status;
 541 }
 542 
 543 /*********************************************************************
 544  ********************************************************************/
 545 
 546  NTSTATUS gc_name_to_sid(const char *domain,
     /* [<][>][^][v][top][bottom][index][help] */
 547                          const char *name,
 548                          DOM_SID *sid,
 549                          enum lsa_SidType *sid_type)
 550 {
 551         TALLOC_CTX *frame = talloc_stackframe();
 552         char *p, *name_user;
 553         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 554         char *name_filter;
 555         ADS_STRUCT *ads = NULL;
 556         LDAPMessage *msg = NULL;
 557         LDAPMessage *e = NULL;
 558         char *dn = NULL;
 559         char *dns_domain = NULL;
 560         ADS_STRUCT **ads_list = NULL;
 561         LDAPMessage **msg_list = NULL;
 562         int num_resp = 0;
 563         int i;
 564 
 565         /* Strip the "DOMAIN\" prefix if necessary and search for
 566            a matching sAMAccountName in the forest */
 567 
 568         if ((p = strchr_m( name, '\\' )) == NULL)
 569                 name_user = talloc_strdup( frame, name );
 570         else
 571                 name_user = talloc_strdup( frame, p+1 );
 572         BAIL_ON_PTR_ERROR(name_user, nt_status);
 573 
 574         name_filter = talloc_asprintf(frame, "(sAMAccountName=%s)", name_user);
 575         BAIL_ON_PTR_ERROR(name_filter, nt_status);
 576 
 577         nt_status = gc_search_all_forests(name_filter, &ads_list,
 578                                           &msg_list, &num_resp, 0);
 579         BAIL_ON_NTSTATUS_ERROR(nt_status);
 580 
 581         /* Assume failure until we know otherwise*/
 582 
 583         nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 584 
 585         /* Match the domain name from the DN */
 586 
 587         for (i=0; i<num_resp; i++) {
 588                 ads = ads_list[i];
 589                 msg = msg_list[i];
 590 
 591                 e = ads_first_entry(ads, msg);
 592                 while (e) {
 593                         struct winbindd_tdc_domain *domain_rec;
 594 
 595                         dn = ads_get_dn(ads, frame, e);
 596                         BAIL_ON_PTR_ERROR(dn, nt_status);
 597 
 598                         dns_domain = cell_dn_to_dns(dn);
 599                         TALLOC_FREE(dn);
 600                         BAIL_ON_PTR_ERROR(dns_domain, nt_status);
 601 
 602                         domain_rec = wcache_tdc_fetch_domain(frame, dns_domain);
 603                         SAFE_FREE(dns_domain);
 604 
 605                         /* Ignore failures and continue the search */
 606 
 607                         if (!domain_rec) {
 608                                 e = ads_next_entry(ads, e);
 609                                 continue;
 610                         }
 611 
 612                         /* Check for a match on the domain name */
 613 
 614                         if (strequal(domain, domain_rec->domain_name)) {
 615                                 if (!ads_pull_sid(ads, e, "objectSid", sid)) {
 616                                         nt_status = NT_STATUS_INVALID_SID;
 617                                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 618                                 }
 619 
 620                                 talloc_destroy(domain_rec);
 621 
 622                                 nt_status = get_sid_type(ads, msg, sid_type);
 623                                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 624 
 625                                 /* We're done! */
 626                                 nt_status = NT_STATUS_OK;
 627                                 break;
 628                         }
 629 
 630                         /* once more around thew merry-go-round */
 631 
 632                         talloc_destroy(domain_rec);
 633                         e = ads_next_entry(ads, e);
 634                 }
 635         }
 636 
 637 done:
 638         free_result_array(ads_list, msg_list, num_resp);
 639         talloc_destroy(frame);
 640 
 641         return nt_status;
 642 }
 643 
 644 /********************************************************************
 645  Pull an attribute string value
 646  *******************************************************************/
 647 
 648 static NTSTATUS get_object_account_name(ADS_STRUCT *ads,
     /* [<][>][^][v][top][bottom][index][help] */
 649                                         LDAPMessage *msg,
 650                                         char **name)
 651 {
 652         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 653         char *sam_name = NULL;
 654         struct winbindd_tdc_domain *domain_rec = NULL;
 655         char *dns_domain = NULL;
 656         char *dn = NULL;
 657         TALLOC_CTX *frame = talloc_stackframe();
 658         int len;
 659 
 660         /* Check parameters */
 661 
 662         if (!ads || !msg || !name) {
 663                 nt_status = NT_STATUS_INVALID_PARAMETER;
 664                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 665         }
 666 
 667         /* get the name and domain */
 668 
 669         dn = ads_get_dn(ads, frame, msg);
 670         BAIL_ON_PTR_ERROR(dn, nt_status);
 671 
 672         DEBUG(10,("get_object_account_name: dn = \"%s\"\n", dn));
 673 
 674         dns_domain = cell_dn_to_dns(dn);
 675         TALLOC_FREE(dn);
 676         BAIL_ON_PTR_ERROR(dns_domain, nt_status);
 677 
 678         domain_rec = wcache_tdc_fetch_domain(frame, dns_domain);
 679         SAFE_FREE(dns_domain);
 680 
 681         if (!domain_rec) {
 682                 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
 683                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 684         }
 685 
 686         sam_name = ads_pull_string(ads, frame, msg, "sAMAccountName");
 687         BAIL_ON_PTR_ERROR(sam_name, nt_status);
 688 
 689         len = asprintf(name, "%s\\%s", domain_rec->domain_name, sam_name);
 690         if (len == -1) {
 691                 *name = NULL;
 692                 BAIL_ON_PTR_ERROR((*name), nt_status);
 693         }
 694 
 695         nt_status = NT_STATUS_OK;
 696 
 697 done:
 698         talloc_destroy(frame);
 699 
 700         return nt_status;
 701 }
 702 
 703 /*********************************************************************
 704  ********************************************************************/
 705 
 706  NTSTATUS gc_sid_to_name(const DOM_SID *sid,
     /* [<][>][^][v][top][bottom][index][help] */
 707                          char **name,
 708                          enum lsa_SidType *sid_type)
 709 {
 710         TALLOC_CTX *frame = talloc_stackframe();
 711         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 712         char *filter;
 713         ADS_STRUCT *ads = NULL;
 714         LDAPMessage *msg = NULL;
 715         char *sid_string;
 716 
 717         *name = NULL;
 718 
 719         sid_string = sid_binstring(sid);
 720         BAIL_ON_PTR_ERROR(sid_string, nt_status);
 721 
 722         filter = talloc_asprintf(frame, "(objectSid=%s)", sid_string);
 723         SAFE_FREE(sid_string);
 724         BAIL_ON_PTR_ERROR(filter, nt_status);
 725 
 726         nt_status = gc_search_all_forests_unique(filter, &ads, &msg);
 727         BAIL_ON_NTSTATUS_ERROR(nt_status);
 728 
 729         nt_status = get_object_account_name(ads, msg, name);
 730         BAIL_ON_NTSTATUS_ERROR(nt_status);
 731 
 732         nt_status = get_sid_type(ads, msg, sid_type);
 733         BAIL_ON_NTSTATUS_ERROR(nt_status);
 734 
 735 done:
 736         ads_msgfree(ads, msg);
 737         talloc_destroy(frame);
 738 
 739         return nt_status;
 740 }
 741 
 742 /**********************************************************************
 743  *********************************************************************/
 744 
 745  NTSTATUS add_ads_result_to_array(ADS_STRUCT *ads,
     /* [<][>][^][v][top][bottom][index][help] */
 746                                   LDAPMessage *msg,
 747                                   ADS_STRUCT ***ads_list,
 748                                   LDAPMessage ***msg_list,
 749                                   int *size)
 750 {
 751         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 752         ADS_STRUCT **ads_tmp = NULL;
 753         LDAPMessage **msg_tmp = NULL;
 754         int count = *size;
 755 
 756         if (!ads || !msg) {
 757                 nt_status = NT_STATUS_INVALID_PARAMETER;
 758                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 759         }
 760 
 761 #if 0
 762         /* Don't add a response with no entries */
 763 
 764         if (ads_count_replies(ads, msg) == 0) {
 765                 return NT_STATUS_OK;
 766         }
 767 #endif
 768 
 769         if (count == 0) {
 770                 ads_tmp = TALLOC_ARRAY(NULL, ADS_STRUCT*, 1);
 771                 BAIL_ON_PTR_ERROR(ads_tmp, nt_status);
 772 
 773                 msg_tmp = TALLOC_ARRAY(NULL, LDAPMessage*, 1);
 774                 BAIL_ON_PTR_ERROR(msg_tmp, nt_status);
 775         } else {
 776                 ads_tmp = TALLOC_REALLOC_ARRAY(*ads_list, *ads_list, ADS_STRUCT*,
 777                                                count+1);
 778                 BAIL_ON_PTR_ERROR(ads_tmp, nt_status);
 779 
 780                 msg_tmp = TALLOC_REALLOC_ARRAY(*msg_list, *msg_list, LDAPMessage*,
 781                                                count+1);
 782                 BAIL_ON_PTR_ERROR(msg_tmp, nt_status);
 783         }
 784 
 785         ads_tmp[count] = ads;
 786         msg_tmp[count] = msg;
 787         count++;
 788 
 789         *ads_list = ads_tmp;
 790         *msg_list = msg_tmp;
 791         *size = count;
 792 
 793         nt_status = NT_STATUS_OK;
 794 
 795 done:
 796         if (!NT_STATUS_IS_OK(nt_status)) {
 797                 talloc_destroy(ads_tmp);
 798                 talloc_destroy(msg_tmp);
 799         }
 800 
 801         return nt_status;
 802 }
 803 
 804 /**********************************************************************
 805  Frees search results.  Do not free the ads_list as these are
 806  references back to the GC search structures.
 807  *********************************************************************/
 808 
 809  void free_result_array(ADS_STRUCT **ads_list,
     /* [<][>][^][v][top][bottom][index][help] */
 810                         LDAPMessage **msg_list,
 811                         int num_resp)
 812 {
 813         int i;
 814 
 815         for (i=0; i<num_resp; i++) {
 816                 ads_msgfree(ads_list[i], msg_list[i]);
 817         }
 818 
 819         talloc_destroy(ads_list);
 820         talloc_destroy(msg_list);
 821 }
 822 
 823 /**********************************************************************
 824  Check that we have exactly one entry from the search
 825  *********************************************************************/
 826 
 827  NTSTATUS check_result_unique(ADS_STRUCT *ads, LDAPMessage *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 828 {
 829         NTSTATUS nt_status;
 830         int count;
 831 
 832         count = ads_count_replies(ads, msg);
 833 
 834         if (count <= 0) {
 835                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 836                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 837         }
 838 
 839         if (count > 1) {
 840                 nt_status = NT_STATUS_DUPLICATE_NAME;
 841                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 842         }
 843 
 844         nt_status = NT_STATUS_OK;
 845 
 846 done:
 847         return nt_status;
 848 }

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