root/source3/winbindd/idmap_adex/provider_unified.c

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

DEFINITIONS

This source file includes following definitions.
  1. build_id_filter
  2. build_alias_filter
  3. search_cell
  4. search_domain
  5. check_forest_scope
  6. check_result_unique_scoped
  7. search_forest
  8. search_cell_list
  9. pull_sid
  10. get_object_type
  11. get_object_uint32
  12. get_object_id
  13. pull_id
  14. get_object_string
  15. pull_nss_info
  16. pull_alias
  17. _ccp_get_sid_from_id
  18. _ccp_get_id_from_sid
  19. _ccp_nss_get_info
  20. _ccp_map_to_alias
  21. _ccp_map_from_alias

   1 /*
   2  * idmap_adex
   3  *
   4  * Provider for RFC2307 and SFU AD Forests
   5  *
   6  * Copyright (C) Gerald (Jerry) Carter 2006-2008
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License as published by
  10  * the Free Software Foundation; either version 2 of the License, or
  11  * (at your option) any later version.
  12  *
  13  * This program is distributed in the hope that it will be useful,
  14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16  * GNU General Public License for more details.
  17  *
  18  * You should have received a copy of the GNU General Public License
  19  * along with this program; if not, write to the Free Software
  20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21  */
  22 
  23 #include "includes.h"
  24 #include "idmap_adex.h"
  25 
  26 #undef DBGC_CLASS
  27 #define DBGC_CLASS DBGC_IDMAP
  28 
  29 /* Information needed by the LDAP search filters */
  30 
  31 enum filterType { SidFilter, IdFilter, AliasFilter };
  32 
  33 struct lwcell_filter
  34 {
  35         enum filterType ftype;
  36         bool use2307;
  37         union {
  38                 DOM_SID sid;
  39                 struct {
  40                         uint32_t id;
  41                         enum id_type type;
  42                 } id;
  43                 fstring alias;
  44         } filter;
  45 };
  46 
  47 /********************************************************************
  48  *******************************************************************/
  49 
  50 static char* build_id_filter(uint32_t id,
     /* [<][>][^][v][top][bottom][index][help] */
  51                              enum id_type type,
  52                              uint32_t search_flags)
  53 {
  54         char *filter = NULL;
  55         char *oc_filter, *attr_filter;
  56         NTSTATUS nt_status;
  57         TALLOC_CTX *frame = talloc_stackframe();
  58         bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
  59                         == LWCELL_FLAG_USE_RFC2307_ATTRS);
  60         bool use_gc = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
  61                        == LWCELL_FLAG_SEARCH_FOREST);
  62         const char *oc;
  63 
  64         /* Construct search filter for objectclass and attributes */
  65 
  66         switch (type) {
  67         case ID_TYPE_UID:
  68                 oc = ADEX_OC_USER;
  69                 if (use2307) {
  70                         oc = ADEX_OC_POSIX_USER;
  71                         if (use_gc) {
  72                                 oc = AD_USER;
  73                         }
  74                 }
  75                 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
  76                 attr_filter = talloc_asprintf(frame, "%s=%u",
  77                                               ADEX_ATTR_UIDNUM, id);
  78                 break;
  79 
  80         case ID_TYPE_GID:
  81                 oc = ADEX_OC_GROUP;
  82                 if (use2307) {
  83                         oc = ADEX_OC_POSIX_GROUP;
  84                         if (use_gc) {
  85                                 oc = AD_GROUP;
  86                         }
  87                 }
  88                 oc_filter = talloc_asprintf(frame, "objectclass=%s", oc);
  89                 attr_filter = talloc_asprintf(frame, "%s=%u",
  90                                               ADEX_ATTR_GIDNUM, id);
  91                 break;
  92         default:
  93                 return NULL;
  94         }
  95 
  96         BAIL_ON_PTR_ERROR(oc_filter, nt_status);
  97         BAIL_ON_PTR_ERROR(attr_filter, nt_status);
  98 
  99         /* Use "keywords=%s" for non-schema cells */
 100 
 101         if (use2307) {
 102                 filter = talloc_asprintf(frame, "(&(%s)(%s))",
 103                                          oc_filter, attr_filter);
 104         } else {
 105                 filter = talloc_asprintf(frame, "(&(keywords=%s)(keywords=%s))",
 106                                          oc_filter, attr_filter);
 107         }
 108 
 109         talloc_destroy(oc_filter);
 110         talloc_destroy(attr_filter);
 111 
 112 done:
 113         /* Don't destroy the stackframe CTX since we are returning
 114            memory from it */
 115 
 116         return filter;
 117 }
 118 
 119 /********************************************************************
 120  *******************************************************************/
 121 
 122 static char* build_alias_filter(const char *alias, uint32_t search_flags)
     /* [<][>][^][v][top][bottom][index][help] */
 123 {
 124         char *filter = NULL;
 125         char *user_attr_filter, *group_attr_filter;
 126         NTSTATUS nt_status;
 127         TALLOC_CTX *frame = talloc_stackframe();
 128         bool use2307 = ((search_flags & LWCELL_FLAG_USE_RFC2307_ATTRS)
 129                         == LWCELL_FLAG_USE_RFC2307_ATTRS);
 130         bool search_forest = ((search_flags & LWCELL_FLAG_SEARCH_FOREST)
 131                               == LWCELL_FLAG_SEARCH_FOREST);
 132 
 133         /* Construct search filter for objectclass and attributes */
 134 
 135         user_attr_filter = talloc_asprintf(frame, "%s=%s",
 136                                            ADEX_ATTR_UID, alias);
 137         group_attr_filter = talloc_asprintf(frame, "%s=%s",
 138                                             ADEX_ATTR_DISPLAYNAME, alias);
 139         BAIL_ON_PTR_ERROR(user_attr_filter, nt_status);
 140         BAIL_ON_PTR_ERROR(group_attr_filter, nt_status);
 141 
 142         /* Use "keywords=%s" for non-schema cells */
 143 
 144         if (use2307) {
 145                 filter = talloc_asprintf(frame,
 146                                          "(|(&(%s)(objectclass=%s))(&(%s)(objectclass=%s)))",
 147                                          user_attr_filter,
 148                                          search_forest ? AD_USER : ADEX_OC_POSIX_USER,
 149                                          group_attr_filter,
 150                                          search_forest ? AD_GROUP : ADEX_OC_POSIX_GROUP);
 151         } else {
 152                 filter = talloc_asprintf(frame,
 153                                          "(|(keywords=%s)(keywords=%s))",
 154                                          user_attr_filter,
 155                                          group_attr_filter);
 156         }
 157 
 158         talloc_destroy(user_attr_filter);
 159         talloc_destroy(group_attr_filter);
 160 
 161 done:
 162         /* Don't destroy the stackframe CTX since we are returning
 163            memory from it */
 164 
 165         return filter;
 166 }
 167 
 168 
 169 /********************************************************************
 170  *******************************************************************/
 171 
 172 static NTSTATUS search_cell(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 173                             LDAPMessage **msg,
 174                             const struct lwcell_filter *fdata)
 175 {
 176         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 177         TALLOC_CTX* frame = talloc_stackframe();
 178         char *filter = NULL;
 179         const char *base = NULL;
 180         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
 181         const char *attrs[] = { "*", NULL };
 182         int count;
 183         char *sid_str;
 184 
 185         /* get the filter and other search parameters */
 186 
 187         switch (fdata->ftype) {
 188         case SidFilter:
 189                 sid_str = sid_string_talloc(frame, &fdata->filter.sid);
 190                 BAIL_ON_PTR_ERROR(sid_str, nt_status);
 191 
 192                 filter = talloc_asprintf(frame, "(keywords=backLink=%s)",
 193                                          sid_str);
 194                 break;
 195         case IdFilter:
 196                 filter = build_id_filter(fdata->filter.id.id,
 197                                          fdata->filter.id.type,
 198                                          cell_flags(c));
 199                 break;
 200         case AliasFilter:
 201                 filter = build_alias_filter(fdata->filter.alias,
 202                                             cell_flags(c));
 203                 break;
 204         default:
 205                 nt_status = NT_STATUS_INVALID_PARAMETER;
 206                 break;
 207         }
 208         BAIL_ON_PTR_ERROR(filter, nt_status);
 209 
 210         base = cell_search_base(c);
 211         BAIL_ON_PTR_ERROR(base, nt_status);
 212 
 213         ads_status = cell_do_search(c, base, LDAP_SCOPE_SUBTREE,
 214                                     filter, attrs, msg);
 215 
 216         nt_status = ads_ntstatus(ads_status);
 217         BAIL_ON_NTSTATUS_ERROR(nt_status);
 218 
 219         /* Now check that we got only one reply */
 220 
 221         count = ads_count_replies(c->conn, *msg);
 222         if (count < 1) {
 223                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 224                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 225         }
 226 
 227         if ( count > 1) {
 228                 nt_status = NT_STATUS_DUPLICATE_NAME;
 229                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 230         }
 231 
 232 done:
 233         PRINT_NTSTATUS_ERROR(nt_status, "search_cell", 4);
 234 
 235         talloc_destroy(CONST_DISCARD(char*, base));
 236         talloc_destroy(frame);
 237 
 238         return nt_status;
 239 }
 240 
 241 /********************************************************************
 242  *******************************************************************/
 243 
 244 static NTSTATUS search_domain(struct likewise_cell **cell,
     /* [<][>][^][v][top][bottom][index][help] */
 245                               LDAPMessage **msg,
 246                               const char *dn,
 247                               const DOM_SID *sid)
 248 {
 249         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 250         TALLOC_CTX* frame = talloc_stackframe();
 251         int count;
 252 
 253         nt_status = dc_search_domains(cell, msg, dn, sid);
 254         BAIL_ON_NTSTATUS_ERROR(nt_status);
 255 
 256         /* Now check that we got only one reply */
 257 
 258         count = ads_count_replies(cell_connection(*cell), *msg);
 259         if (count < 1) {
 260                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 261                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 262         }
 263 
 264         if ( count > 1) {
 265                 nt_status = NT_STATUS_DUPLICATE_NAME;
 266                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 267         }
 268 
 269 done:
 270         PRINT_NTSTATUS_ERROR(nt_status, "search_domain", 4);
 271         talloc_destroy(frame);
 272 
 273         return nt_status;
 274 }
 275 
 276 
 277 /********************************************************************
 278  Check that a DN is within the forest scope.
 279  *******************************************************************/
 280 
 281 static bool check_forest_scope(const char *dn)
     /* [<][>][^][v][top][bottom][index][help] */
 282 {
 283         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 284         TALLOC_CTX *frame = talloc_stackframe();
 285         char *p = NULL;
 286         char *q = NULL;
 287         char *dns_domain = NULL;
 288         struct winbindd_tdc_domain *domain;
 289 
 290         /* If the DN does *not* contain "$LikewiseIdentityCell",
 291            assume this is a schema mode forest and it is in the
 292            forest scope by definition. */
 293 
 294         if ((p = strstr_m(dn, ADEX_CELL_RDN)) == NULL) {
 295                 nt_status = NT_STATUS_OK;
 296                 goto done;
 297         }
 298 
 299         /* If this is a non-schema forest, then make sure that the DN
 300            is in the form "...,cn=$LikewiseIdentityCell,DC=..." */
 301 
 302         if ((q = strchr_m(p, ',')) == NULL) {
 303                 nt_status = NT_STATUS_OBJECT_NAME_INVALID;
 304                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 305         }
 306 
 307         q++;
 308         if (StrnCaseCmp(q, "dc=", 3) != 0) {
 309                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
 310                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 311         }
 312 
 313 
 314         dns_domain = cell_dn_to_dns(q);
 315         BAIL_ON_PTR_ERROR(dns_domain, nt_status);
 316 
 317         domain = wcache_tdc_fetch_domain(frame, dns_domain);
 318         if (!domain) {
 319                 nt_status = NT_STATUS_TRUSTED_DOMAIN_FAILURE;
 320                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 321         }
 322 
 323         nt_status = NT_STATUS_OK;
 324 
 325 done:
 326         talloc_destroy(frame);
 327         SAFE_FREE(dns_domain);
 328 
 329         return NT_STATUS_IS_OK(nt_status);
 330 }
 331 
 332 
 333 
 334 /********************************************************************
 335  Check that only one result was returned within the forest cell
 336  scope.
 337  *******************************************************************/
 338 
 339 static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list,
     /* [<][>][^][v][top][bottom][index][help] */
 340                                            LDAPMessage **msg_list,
 341                                            int num_resp,
 342                                            char **dn,
 343                                            DOM_SID *user_sid)
 344 {
 345         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 346         int i;
 347         ADS_STRUCT *ads = NULL;
 348         LDAPMessage *msg = NULL;
 349         int count = 0;
 350         char *entry_dn = NULL;
 351         TALLOC_CTX *frame = talloc_stackframe();
 352 
 353         if (!dn || !user_sid) {
 354                 nt_status = NT_STATUS_INVALID_PARAMETER;
 355                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 356         }
 357 
 358         *dn = NULL;
 359 
 360         if (!ads_list || !msg_list || (num_resp == 0)) {
 361                 nt_status = NT_STATUS_NO_SUCH_FILE;
 362                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 363         }
 364 
 365         /* Loop over all msgs */
 366 
 367         for (i=0; i<num_resp; i++) {
 368                 LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]);
 369 
 370                 while (e) {
 371                         entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e);
 372                         BAIL_ON_PTR_ERROR(entry_dn, nt_status);
 373 
 374                         if (check_forest_scope(entry_dn)) {
 375                                 count++;
 376 
 377                                 /* If we've already broken the condition, no
 378                                    need to continue */
 379 
 380                                 if (count > 1) {
 381                                         nt_status = NT_STATUS_DUPLICATE_NAME;
 382                                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 383                                 }
 384 
 385                                 ads = ads_list[i];
 386                                 msg = e;
 387                                 *dn = SMB_STRDUP(entry_dn);
 388                                 BAIL_ON_PTR_ERROR((*dn), nt_status);
 389                         }
 390 
 391                         e = ads_next_entry(ads_list[i], e);
 392                         TALLOC_FREE(entry_dn);
 393                 }
 394         }
 395 
 396         if (!ads || !msg) {
 397                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 398                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 399         }
 400 
 401         /* If we made is through the loop, then grab the user_sid and
 402            run home to base */
 403 
 404         /*
 405            Try and get the SID from either objectSid or keywords.
 406            We cannot use pull_sid() here since we want to try
 407            both methods and not only one or the other (and we
 408            have no full likewise_cell struct.
 409 
 410            Fail if both are unavailable
 411         */
 412 
 413         if (!ads_pull_sid(ads, msg, "objectSid", user_sid)) {
 414                 char **keywords;
 415                 char *s;
 416                 size_t num_lines = 0;
 417 
 418                 keywords = ads_pull_strings(ads, frame, msg, "keywords",
 419                                             &num_lines);
 420                 BAIL_ON_PTR_ERROR(keywords, nt_status);
 421 
 422                 s = find_attr_string(keywords, num_lines, "backLink");
 423                 if (!s) {
 424                         nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 425                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 426                 }
 427 
 428                 if (!string_to_sid(user_sid, s)) {
 429                         nt_status = NT_STATUS_INVALID_SID;
 430                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 431                 }
 432         }
 433 
 434         nt_status = NT_STATUS_OK;
 435 
 436 done:
 437         if (!NT_STATUS_IS_OK(nt_status)) {
 438                 SAFE_FREE(*dn);
 439         }
 440 
 441         talloc_destroy(frame);
 442 
 443         return nt_status;
 444 }
 445 
 446 /********************************************************************
 447  Search all forests.  Each forest can have it's own forest-cell
 448  settings so we have to generate the filter for each search.
 449  We don't use gc_search_all_forests() since we may have a different
 450  schema model in each forest and need to construct the search
 451  filter for each GC search.
 452  *******************************************************************/
 453 
 454 static NTSTATUS search_forest(struct likewise_cell *forest_cell,
     /* [<][>][^][v][top][bottom][index][help] */
 455                               LDAPMessage **msg,
 456                               const struct lwcell_filter *fdata)
 457 {
 458         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 459         TALLOC_CTX *frame = talloc_stackframe();
 460         char *filter = NULL;
 461         char *dn = NULL;
 462         struct gc_info *gc = NULL;
 463         ADS_STRUCT **ads_list = NULL;
 464         LDAPMessage **msg_list = NULL;
 465         int num_resp = 0;
 466         LDAPMessage *m;
 467         DOM_SID user_sid;
 468         struct likewise_cell *domain_cell = NULL;
 469 
 470         if ((gc = gc_search_start()) == NULL) {
 471                 nt_status = NT_STATUS_INVALID_DOMAIN_STATE;
 472                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 473         }
 474 
 475         while (gc) {
 476                 char *sid_binstr = NULL;
 477                 uint32_t flags = LWCELL_FLAG_SEARCH_FOREST;
 478 
 479                 m = NULL;
 480 
 481                 flags |= cell_flags(gc->forest_cell);
 482 
 483                 switch (fdata->ftype) {
 484                 case SidFilter:
 485                         sid_binstr = sid_binstring(&fdata->filter.sid);
 486                         BAIL_ON_PTR_ERROR(sid_binstr, nt_status);
 487 
 488                         filter = talloc_asprintf(frame, "(objectSid=%s)", sid_binstr);
 489                         SAFE_FREE(sid_binstr);
 490                         break;
 491                 case IdFilter:
 492                         filter = build_id_filter(fdata->filter.id.id,
 493                                                  fdata->filter.id.type, flags);
 494                         break;
 495                 case AliasFilter:
 496                         filter = build_alias_filter(fdata->filter.alias, flags);
 497                         break;
 498                 }
 499 
 500                 /* First find the sparse object in GC */
 501                 nt_status = gc_search_forest(gc, &m, filter);
 502                 if (!NT_STATUS_IS_OK(nt_status)) {
 503                         gc = gc->next;
 504                         continue;
 505                 }
 506 
 507                 nt_status = add_ads_result_to_array(cell_connection(gc->forest_cell),
 508                                                     m, &ads_list, &msg_list,
 509                                                     &num_resp);
 510                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 511 
 512                 gc = gc->next;
 513         }
 514 
 515         /* Uniqueness check across forests */
 516 
 517         nt_status = check_result_unique_scoped(ads_list, msg_list, num_resp,
 518                                                &dn, &user_sid);
 519         BAIL_ON_NTSTATUS_ERROR(nt_status);
 520 
 521         nt_status = search_domain(&domain_cell, &m, dn, &user_sid);
 522         BAIL_ON_NTSTATUS_ERROR(nt_status);
 523 
 524         /* Save the connection and results in the return parameters */
 525 
 526         forest_cell->gc_search_cell = domain_cell;
 527         *msg = m;
 528 
 529 done:
 530         PRINT_NTSTATUS_ERROR(nt_status, "search_forest", 4);
 531 
 532         SAFE_FREE(dn);
 533 
 534         free_result_array(ads_list, msg_list, num_resp);
 535         talloc_destroy(frame);
 536 
 537         return nt_status;
 538 }
 539 
 540 /********************************************************************
 541  *******************************************************************/
 542 
 543 static NTSTATUS search_cell_list(struct likewise_cell **c,
     /* [<][>][^][v][top][bottom][index][help] */
 544                                  LDAPMessage **m,
 545                                  const struct lwcell_filter *fdata)
 546 {
 547         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 548         struct likewise_cell *cell = NULL;
 549         LDAPMessage *msg = NULL;
 550         struct likewise_cell *result_cell = NULL;
 551 
 552         if ((cell = cell_list_head()) == NULL) {
 553                 nt_status = NT_STATUS_INVALID_SERVER_STATE;
 554                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 555         }
 556 
 557         while (cell) {
 558                 /* Clear any previous GC search results */
 559 
 560                 cell->gc_search_cell = NULL;
 561 
 562                 if (cell_search_forest(cell)) {
 563                         nt_status = search_forest(cell, &msg, fdata);
 564                 } else {
 565                         nt_status = search_cell(cell, &msg, fdata);
 566                 }
 567 
 568                 /* Always point to the search result cell.
 569                    In forests this might be for another domain
 570                    which means the schema model may be different */
 571 
 572                 result_cell = cell->gc_search_cell ?
 573                         cell->gc_search_cell : cell;
 574 
 575                 /* Check if we are done */
 576 
 577                 if (NT_STATUS_IS_OK(nt_status)) {
 578                         break;
 579                 }
 580 
 581                 /* No luck.  Free memory and hit the next cell.
 582                    Forest searches always set the gc_search_cell
 583                    so give preference to that connection if possible. */
 584 
 585                 ads_msgfree(cell_connection(result_cell), msg);
 586                 msg = NULL;
 587 
 588                 cell = cell->next;
 589         }
 590 
 591         /* This might be assigning NULL but that is ok as long as we
 592            give back the proper error code */
 593 
 594         *c = result_cell;
 595         *m = msg;
 596 
 597 done:
 598         PRINT_NTSTATUS_ERROR(nt_status, "search_cell_list", 3);
 599 
 600         return nt_status;
 601 }
 602 
 603 /********************************************************************
 604  Pull the SID from an object which is always stored in the keywords
 605  attribute as "backLink=S-1-5-21-..."
 606  *******************************************************************/
 607 
 608 static NTSTATUS pull_sid(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 609                          LDAPMessage *msg,
 610                          DOM_SID *sid)
 611 {
 612         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 613         TALLOC_CTX *frame = talloc_stackframe();
 614         ADS_STRUCT *ads = NULL;
 615 
 616         ads = cell_connection(c);
 617 
 618         /*
 619            We have two ways of getting the sid:
 620            (a) from the objectSID in case of a GC search,
 621            (b) from backLink in the case of a cell search.
 622            Pull the keywords attributes and grab the backLink.
 623         */
 624 
 625         if (!ads_pull_sid(ads, msg, "objectSid", sid)) {
 626                 char **keywords;
 627                 char *s;
 628                 size_t num_lines = 0;
 629 
 630                 keywords = ads_pull_strings(ads, frame, msg,
 631                                             "keywords", &num_lines);
 632                 BAIL_ON_PTR_ERROR(keywords, nt_status);
 633 
 634                 s = find_attr_string(keywords, num_lines, "backLink");
 635                 if (!s) {
 636                         nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 637                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 638                 }
 639 
 640                 if (!string_to_sid(sid, s)) {
 641                         nt_status = NT_STATUS_INVALID_SID;
 642                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 643                 }
 644         }
 645 
 646         nt_status = NT_STATUS_OK;
 647 
 648 done:
 649         talloc_destroy(frame);
 650 
 651         return nt_status;
 652 }
 653 
 654 /********************************************************************
 655  *******************************************************************/
 656 
 657 static NTSTATUS get_object_type(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 658                                 LDAPMessage *msg,
 659                                 enum id_type *type)
 660 {
 661         TALLOC_CTX *ctx = talloc_stackframe();
 662         char **oc_list = NULL;
 663         NTSTATUS nt_status = NT_STATUS_OK;
 664         size_t list_size = 0;
 665         char *s = NULL;
 666         ADS_STRUCT *ads = NULL;
 667 
 668         ads = cell_connection(c);
 669 
 670         /* Deal with RFC 2307 support first */
 671 
 672         if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
 673                 oc_list = ads_pull_strings(ads, ctx, msg,
 674                                            "objectClass", &list_size);
 675                 if (!oc_list) {
 676                         nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 677                         goto done;
 678                 }
 679 
 680                 /* Check for posix classes and AD classes */
 681 
 682                 if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_USER)
 683                     || is_object_class(oc_list, list_size, AD_USER)) {
 684                         *type = ID_TYPE_UID;
 685                 } else if (is_object_class(oc_list, list_size, ADEX_OC_POSIX_GROUP)
 686                            || is_object_class(oc_list, list_size, AD_GROUP)) {
 687                         *type = ID_TYPE_GID;
 688                 } else {
 689                         *type = ID_TYPE_NOT_SPECIFIED;
 690                         nt_status = NT_STATUS_INVALID_PARAMETER;
 691                 }
 692         } else {
 693                 /* Default to non-schema mode */
 694 
 695                 oc_list = ads_pull_strings(ads, ctx, msg,
 696                                            "keywords", &list_size);
 697                 if (!oc_list) {
 698                         nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 699                         goto done;
 700                 }
 701 
 702                 s = find_attr_string(oc_list, list_size, "objectClass");
 703                 if (!s) {
 704                         nt_status = NT_STATUS_INTERNAL_DB_CORRUPTION;
 705                         goto done;
 706                 }
 707 
 708                 if (strequal(s, ADEX_OC_USER)) {
 709                         *type = ID_TYPE_UID;
 710                 } else if (strequal(s, ADEX_OC_GROUP)) {
 711                         *type = ID_TYPE_GID;
 712                 } else {
 713                         *type = ID_TYPE_NOT_SPECIFIED;
 714                         nt_status = NT_STATUS_INVALID_PARAMETER;
 715                 }
 716         }
 717 
 718         nt_status = NT_STATUS_OK;
 719 
 720 done:
 721         talloc_destroy(ctx);
 722 
 723         return nt_status;
 724 }
 725 
 726 /********************************************************************
 727  Pull an attribute uint32_t  value
 728  *******************************************************************/
 729 
 730 static NTSTATUS get_object_uint32(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 731                                   LDAPMessage *msg,
 732                                   const char *attrib,
 733                                   uint32_t *x)
 734 {
 735         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 736         char **keywords = NULL;
 737         size_t list_size = 0;
 738         TALLOC_CTX *frame = talloc_stackframe();
 739         ADS_STRUCT *ads = NULL;
 740 
 741         ads = cell_connection(c);
 742 
 743         /* Deal with RFC2307 schema */
 744 
 745         if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
 746                 if (!ads_pull_uint32(ads, msg, attrib, x)) {
 747                         nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 748                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 749                 }
 750         } else {
 751                 /* Non-schema mode */
 752                 char *s = NULL;
 753                 uint32_t num;
 754 
 755                 keywords = ads_pull_strings(ads, frame, msg, "keywords",
 756                                             &list_size);
 757                 BAIL_ON_PTR_ERROR(keywords, nt_status);
 758 
 759                 s = find_attr_string(keywords, list_size, attrib);
 760                 if (!s) {
 761                         nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 762                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 763                 }
 764 
 765                 num = strtoll(s, NULL, 10);
 766                 if (errno == ERANGE) {
 767                         nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 768                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 769                 }
 770                 *x = num;
 771         }
 772 
 773         nt_status = NT_STATUS_OK;
 774 
 775 done:
 776         talloc_destroy(frame);
 777 
 778         return nt_status;
 779 }
 780 
 781 /********************************************************************
 782  *******************************************************************/
 783 
 784 static NTSTATUS get_object_id(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 785                               LDAPMessage *msg,
 786                               enum id_type type,
 787                               uint32_t *id)
 788 {
 789         NTSTATUS nt_status = NT_STATUS_OK;
 790         const char *id_attr;
 791 
 792         /* Figure out which attribute we need to pull */
 793 
 794         switch (type) {
 795         case ID_TYPE_UID:
 796                 id_attr = ADEX_ATTR_UIDNUM;
 797                 break;
 798         case ID_TYPE_GID:
 799                 id_attr = ADEX_ATTR_GIDNUM;
 800                 break;
 801         default:
 802                 nt_status = NT_STATUS_INVALID_PARAMETER;
 803                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 804                 break;
 805         }
 806 
 807         nt_status = get_object_uint32(c, msg, id_attr, id);
 808         BAIL_ON_NTSTATUS_ERROR(nt_status);
 809 
 810 done:
 811         return nt_status;
 812 }
 813 
 814 /********************************************************************
 815  Pull the uid/gid and type from an object.  This differs depending on
 816  the cell flags.
 817  *******************************************************************/
 818 
 819 static NTSTATUS pull_id(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 820                         LDAPMessage *msg,
 821                         uint32_t *id,
 822                         enum id_type *type)
 823 {
 824         NTSTATUS nt_status;
 825 
 826         nt_status = get_object_type(c, msg, type);
 827         BAIL_ON_NTSTATUS_ERROR(nt_status);
 828 
 829         nt_status = get_object_id(c, msg, *type, id);
 830         BAIL_ON_NTSTATUS_ERROR(nt_status);
 831 
 832 done:
 833         return nt_status;
 834 }
 835 
 836 /********************************************************************
 837  Pull an attribute string value
 838  *******************************************************************/
 839 
 840 static NTSTATUS get_object_string(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 841                                   LDAPMessage *msg,
 842                                   TALLOC_CTX *ctx,
 843                                   const char *attrib,
 844                                   char **string)
 845 {
 846         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 847         char **keywords = NULL;
 848         size_t list_size = 0;
 849         TALLOC_CTX *frame = talloc_stackframe();
 850         ADS_STRUCT *ads = NULL;
 851 
 852         *string = NULL;
 853 
 854         ads = cell_connection(c);
 855 
 856         /* Deal with RFC2307 schema */
 857 
 858         if (cell_flags(c) & LWCELL_FLAG_USE_RFC2307_ATTRS) {
 859                 *string = ads_pull_string(ads, ctx, msg, attrib);
 860         } else {
 861                 /* Non-schema mode */
 862 
 863                 char *s = NULL;
 864 
 865                 keywords = ads_pull_strings(ads, frame, msg,
 866                                             "keywords", &list_size);
 867                 if (!keywords) {
 868                         nt_status = NT_STATUS_NO_MEMORY;
 869                         BAIL_ON_NTSTATUS_ERROR(nt_status);
 870                 }
 871                 s = find_attr_string(keywords, list_size, attrib);
 872                 if (s) {
 873                         *string = talloc_strdup(ctx, s);
 874                 }
 875         }
 876 
 877         if (!*string) {
 878                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 879                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 880         }
 881 
 882         nt_status = NT_STATUS_OK;
 883 
 884 done:
 885         talloc_destroy(frame);
 886 
 887         return nt_status;
 888 }
 889 
 890 /********************************************************************
 891  Pull the struct passwd fields for a user
 892  *******************************************************************/
 893 
 894 static NTSTATUS pull_nss_info(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 895                               LDAPMessage *msg,
 896                               TALLOC_CTX *ctx,
 897                               char **homedir,
 898                               char **shell,
 899                               char **gecos,
 900                               gid_t *p_gid)
 901 {
 902         NTSTATUS nt_status;
 903 
 904         nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_HOMEDIR, homedir);
 905         BAIL_ON_NTSTATUS_ERROR(nt_status);
 906 
 907         nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_SHELL, shell);
 908         BAIL_ON_NTSTATUS_ERROR(nt_status);
 909 
 910         nt_status = get_object_string(c, msg, ctx, ADEX_ATTR_GECOS, gecos);
 911         /* Gecos is often not set so ignore failures */
 912 
 913         nt_status = get_object_uint32(c, msg, ADEX_ATTR_GIDNUM, p_gid);
 914         BAIL_ON_NTSTATUS_ERROR(nt_status);
 915 
 916 done:
 917         return nt_status;
 918 }
 919 
 920 /********************************************************************
 921  Pull the struct passwd fields for a user
 922  *******************************************************************/
 923 
 924 static NTSTATUS pull_alias(struct likewise_cell *c,
     /* [<][>][^][v][top][bottom][index][help] */
 925                            LDAPMessage *msg,
 926                            TALLOC_CTX *ctx,
 927                            char **alias)
 928 {
 929         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 930         enum id_type type;
 931         const char *attr = NULL;
 932 
 933         /* Figure out if this is a user or a group */
 934 
 935         nt_status = get_object_type(c, msg, &type);
 936         BAIL_ON_NTSTATUS_ERROR(nt_status);
 937 
 938         switch (type) {
 939         case ID_TYPE_UID:
 940                 attr = ADEX_ATTR_UID;
 941                 break;
 942         case ID_TYPE_GID:
 943                 /* What is the group attr for RFC2307 Forests? */
 944                 attr = ADEX_ATTR_DISPLAYNAME;
 945                 break;
 946         default:
 947                 nt_status = NT_STATUS_INVALID_PARAMETER;
 948                 BAIL_ON_NTSTATUS_ERROR(nt_status);
 949                 break;
 950         }
 951 
 952         nt_status = get_object_string(c, msg, ctx, attr, alias);
 953         BAIL_ON_NTSTATUS_ERROR(nt_status);
 954 
 955 done:
 956         return nt_status;
 957 }
 958 
 959 /********************************************************************
 960  *******************************************************************/
 961 
 962 static NTSTATUS _ccp_get_sid_from_id(DOM_SID * sid,
     /* [<][>][^][v][top][bottom][index][help] */
 963                                      uint32_t id, enum id_type type)
 964 {
 965         struct likewise_cell *cell = NULL;
 966         LDAPMessage *msg = NULL;
 967         NTSTATUS nt_status;
 968         struct lwcell_filter filter;
 969 
 970         filter.ftype = IdFilter;
 971         filter.filter.id.id = id;
 972         filter.filter.id.type = type;
 973 
 974         nt_status = search_cell_list(&cell, &msg, &filter);
 975         BAIL_ON_NTSTATUS_ERROR(nt_status);
 976 
 977         nt_status = pull_sid(cell, msg, sid);
 978         BAIL_ON_NTSTATUS_ERROR(nt_status);
 979 
 980 done:
 981         ads_msgfree(cell->conn, msg);
 982 
 983         return nt_status;
 984 }
 985 
 986 /********************************************************************
 987  *******************************************************************/
 988 
 989 static NTSTATUS _ccp_get_id_from_sid(uint32_t * id,
     /* [<][>][^][v][top][bottom][index][help] */
 990                                      enum id_type *type,
 991                                      const DOM_SID * sid)
 992 {
 993         struct likewise_cell *cell = NULL;
 994         LDAPMessage *msg = NULL;
 995         NTSTATUS nt_status;
 996         struct lwcell_filter filter;
 997 
 998         filter.ftype = SidFilter;
 999         sid_copy(&filter.filter.sid, sid);
1000 
1001         nt_status = search_cell_list(&cell, &msg, &filter);
1002         BAIL_ON_NTSTATUS_ERROR(nt_status);
1003 
1004         nt_status = pull_id(cell, msg, id, type);
1005         BAIL_ON_NTSTATUS_ERROR(nt_status);
1006 
1007         if (*id < min_id_value()) {
1008                 nt_status = NT_STATUS_INVALID_PARAMETER;
1009                 BAIL_ON_NTSTATUS_ERROR(nt_status);
1010         }
1011 
1012 done:
1013         ads_msgfree(cell->conn, msg);
1014 
1015         return nt_status;
1016 }
1017 
1018 /********************************************************************
1019  *******************************************************************/
1020 
1021 static NTSTATUS _ccp_nss_get_info(const DOM_SID * sid,
     /* [<][>][^][v][top][bottom][index][help] */
1022                                   TALLOC_CTX * ctx,
1023                                   char **homedir,
1024                                   char **shell,
1025                                   char **gecos, gid_t * p_gid)
1026 {
1027         struct likewise_cell *cell = NULL;
1028         LDAPMessage *msg = NULL;
1029         NTSTATUS nt_status;
1030         struct lwcell_filter filter;
1031         enum id_type type;
1032 
1033         filter.ftype = SidFilter;
1034         sid_copy(&filter.filter.sid, sid);
1035 
1036         nt_status = search_cell_list(&cell, &msg, &filter);
1037         BAIL_ON_NTSTATUS_ERROR(nt_status);
1038 
1039         nt_status = get_object_type(cell, msg, &type);
1040         BAIL_ON_NTSTATUS_ERROR(nt_status);
1041 
1042         if (type != ID_TYPE_UID) {
1043                 nt_status = NT_STATUS_NO_SUCH_USER;
1044                 BAIL_ON_NTSTATUS_ERROR(nt_status);
1045         }
1046 
1047         nt_status = pull_nss_info(cell, msg, ctx, homedir, shell, gecos,
1048                                   (uint32_t*) p_gid);
1049         BAIL_ON_NTSTATUS_ERROR(nt_status);
1050 
1051 done:
1052         ads_msgfree(cell->conn, msg);
1053 
1054         return nt_status;
1055 }
1056 
1057 /**********************************************************************
1058  *********************************************************************/
1059 
1060 static NTSTATUS _ccp_map_to_alias(TALLOC_CTX *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1061                                   const char *domain,
1062                                   const char *name, char **alias)
1063 {
1064         TALLOC_CTX *frame = talloc_stackframe();
1065         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1066         DOM_SID sid;
1067         struct likewise_cell *cell = NULL;
1068         LDAPMessage *msg = NULL;
1069         struct lwcell_filter filter;
1070         enum lsa_SidType sid_type;
1071 
1072         /* Convert the name to a SID */
1073 
1074         nt_status = gc_name_to_sid(domain, name, &sid, &sid_type);
1075         BAIL_ON_NTSTATUS_ERROR(nt_status);
1076 
1077         /* Find the user/group */
1078 
1079         filter.ftype = SidFilter;
1080         sid_copy(&filter.filter.sid, &sid);
1081 
1082         nt_status = search_cell_list(&cell, &msg, &filter);
1083         BAIL_ON_NTSTATUS_ERROR(nt_status);
1084 
1085         /* Pull the alias and return */
1086 
1087         nt_status = pull_alias(cell, msg, ctx, alias);
1088         BAIL_ON_NTSTATUS_ERROR(nt_status);
1089 
1090 done:
1091         PRINT_NTSTATUS_ERROR(nt_status, "map_to_alias", 3);
1092 
1093         talloc_destroy(frame);
1094         ads_msgfree(cell_connection(cell), msg);
1095 
1096         return nt_status;
1097 }
1098 
1099 /**********************************************************************
1100  Map from an alias name to the canonical, qualified name.
1101  Ensure that the alias is only pull from the closest in which
1102  the user or gorup is enabled in
1103  *********************************************************************/
1104 
1105 static NTSTATUS _ccp_map_from_alias(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1106                                     const char *domain,
1107                                     const char *alias, char **name)
1108 {
1109         TALLOC_CTX *frame = talloc_stackframe();
1110         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
1111         DOM_SID sid;
1112         struct likewise_cell *cell_alias = NULL;
1113         LDAPMessage *msg_alias = NULL;
1114         struct likewise_cell *cell_sid = NULL;
1115         LDAPMessage *msg_sid = NULL;
1116         struct lwcell_filter filter;
1117         char *canonical_name = NULL;
1118         enum lsa_SidType type;
1119 
1120         /* Find the user/group */
1121 
1122         filter.ftype = AliasFilter;
1123         fstrcpy(filter.filter.alias, alias);
1124 
1125         nt_status = search_cell_list(&cell_alias, &msg_alias, &filter);
1126         BAIL_ON_NTSTATUS_ERROR(nt_status);
1127 
1128         nt_status = pull_sid(cell_alias, msg_alias, &sid);
1129         BAIL_ON_NTSTATUS_ERROR(nt_status);
1130 
1131         /* Now search again for the SID according to the cell list.
1132            Verify that the cell of both search results is the same
1133            so that we only match an alias from the closest cell
1134            in which a user/group has been instantied. */
1135 
1136         filter.ftype = SidFilter;
1137         sid_copy(&filter.filter.sid, &sid);
1138 
1139         nt_status = search_cell_list(&cell_sid, &msg_sid, &filter);
1140         BAIL_ON_NTSTATUS_ERROR(nt_status);
1141 
1142         if (cell_alias != cell_sid) {
1143                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
1144                 BAIL_ON_NTSTATUS_ERROR(nt_status);
1145         }
1146 
1147         /* Finally do the GC sid/name conversion */
1148 
1149         nt_status = gc_sid_to_name(&sid, &canonical_name, &type);
1150         BAIL_ON_NTSTATUS_ERROR(nt_status);
1151 
1152         *name = talloc_strdup(mem_ctx, canonical_name);
1153         BAIL_ON_PTR_ERROR((*name), nt_status);
1154 
1155         nt_status = NT_STATUS_OK;
1156 
1157 done:
1158         PRINT_NTSTATUS_ERROR(nt_status, "map_from_alias", 3);
1159 
1160         ads_msgfree(cell_connection(cell_alias), msg_alias);
1161         ads_msgfree(cell_connection(cell_sid), msg_sid);
1162 
1163         SAFE_FREE(canonical_name);
1164 
1165         talloc_destroy(frame);
1166 
1167         return nt_status;
1168 }
1169 
1170 /********************************************************************
1171  *******************************************************************/
1172 
1173 struct cell_provider_api ccp_unified = {
1174         .get_sid_from_id = _ccp_get_sid_from_id,
1175         .get_id_from_sid = _ccp_get_id_from_sid,
1176         .get_nss_info    = _ccp_nss_get_info,
1177         .map_to_alias    = _ccp_map_to_alias,
1178         .map_from_alias  = _ccp_map_from_alias
1179 };

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