1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <stdlib.h>
  26 #include <strings.h>
  27 #include <ctype.h>
  28 #include <locale.h>
  29 #include <syslog.h>
  30 #include "ns_internal.h"
  31 
  32 /*
  33  * Calculate a hash for a string
  34  * Based on elf_hash algorithm, hash is case insensitive
  35  * Uses tolower instead of _tolower because of I18N
  36  */
  37 
  38 static unsigned long
  39 ns_hash(const char *str)
  40 {
  41         unsigned int    hval = 0;
  42 
  43         while (*str) {
  44                 unsigned int    g;
  45 
  46                 hval = (hval << 4) + tolower(*str++);
  47                 if ((g = (hval & 0xf0000000)) != 0)
  48                         hval ^= g >> 24;
  49                 hval &= ~g;
  50         }
  51         return ((unsigned long)hval);
  52 }
  53 
  54 /*
  55  * Scan a hash table hit for a matching hash entry.
  56  * Assume service and str are non-NULL.
  57  */
  58 
  59 static ns_hash_t *
  60 ns_scan_hash(ns_hashtype_t type, const char *service,
  61     const char *str, ns_hash_t *idx)
  62 {
  63         while (idx) {
  64                 if (idx->h_type == type &&
  65                     strcasecmp(service, idx->h_map->service) == 0 &&
  66                     strcasecmp(str, idx->h_map->orig) == 0) {
  67                         return (idx);
  68                 }
  69                 idx = idx->h_next;
  70         }
  71         return ((ns_hash_t *)NULL);
  72 }
  73 
  74 /*
  75  * Find an entry in the hash table
  76  */
  77 
  78 static ns_hash_t *
  79 ns_get_hash(const ns_config_t *config,
  80     ns_hashtype_t type, const char *service, const char *str)
  81 {
  82         ns_hash_t       *idx, *hashp;
  83         unsigned long   hash;
  84 
  85         if (config == NULL || service == NULL || str == NULL)
  86                 return (NULL);
  87 
  88         hash = ns_hash(str) % NS_HASH_MAX;
  89         idx = config->hashTbl[hash];
  90         hashp = ns_scan_hash(type, service, str, idx);
  91 
  92         return (hashp);
  93 }
  94 
  95 /*
  96  * free a map entry
  97  */
  98 
  99 static void
 100 ns_free_map(ns_mapping_t *mapp)
 101 {
 102         char    **ptr;
 103 
 104         if (mapp == NULL)
 105                 return;
 106         if (mapp->service) {
 107                 free(mapp->service);
 108                 mapp->service = NULL;
 109         }
 110         if (mapp->orig) {
 111                 free(mapp->orig);
 112                 mapp->orig = NULL;
 113         }
 114         if (mapp->map) {
 115                 for (ptr = mapp->map; *ptr; ptr++)
 116                         free(*ptr);
 117                 free(mapp->map);
 118                 mapp->map = NULL;
 119         }
 120         free(mapp);
 121 }
 122 
 123 /*
 124  * Remove a hash table entry.
 125  * This function is not MT safe.
 126  */
 127 
 128 static ns_hash_t *
 129 ns_free_hash(ns_hash_t *p)
 130 {
 131         ns_mapping_t    *map;
 132         ns_hash_t       *next;
 133 
 134         map = p->h_map;
 135         next = p->h_next;
 136         ns_free_map(map);
 137         free(p);
 138         return (next);
 139 }
 140 
 141 /*
 142  * destroy the hash table.
 143  * This function is not MT safe.
 144  */
 145 
 146 void
 147 __s_api_destroy_hash(ns_config_t *config)
 148 {
 149         ns_hash_t       *next;
 150         int             i;
 151 
 152         if (config == NULL)
 153                 return;
 154         for (i = 0; i < NS_HASH_MAX; i++) {
 155                 next = config->hashTbl[i];
 156                 while (next != NULL) {
 157                         next = ns_free_hash(next);
 158                 }
 159                 config->hashTbl[i] = NULL;
 160         }
 161 }
 162 
 163 /*
 164  * Add a hash entry to the hash table.
 165  * This function is not MT safe.
 166  * Assume map, map->orig, map->service are non-NULL.
 167  */
 168 
 169 int
 170 __s_api_add_map2hash(ns_config_t *config, ns_hashtype_t type,
 171     ns_mapping_t *map)
 172 {
 173         ns_hash_t       *idx, *newp;
 174         unsigned long   hash;
 175 
 176         if (config == NULL)
 177                 return (NS_HASH_RC_CONFIG_ERROR);
 178 
 179         hash = ns_hash(map->orig) % NS_HASH_MAX;
 180         idx = config->hashTbl[hash];
 181         if (idx != NULL &&
 182             ns_scan_hash(type, map->service, map->orig, idx) != NULL) {
 183                 return (NS_HASH_RC_EXISTED);
 184         }
 185 
 186         newp = (ns_hash_t *)malloc(sizeof (ns_hash_t));
 187         if (newp == NULL)
 188                 return (NS_HASH_RC_NO_MEMORY);
 189         newp->h_type = type;
 190         newp->h_map = map;
 191         newp->h_next = idx;
 192         config->hashTbl[hash] = newp;
 193         newp->h_llnext = config->llHead;
 194         config->llHead = newp;
 195         return (NS_HASH_RC_SUCCESS);
 196 }
 197 
 198 
 199 /*
 200  * Parse an attribute map string.
 201  * Assume space is the only legal whitespace.
 202  * attributeMap syntax:
 203  * attributeMap      = serviceId ":" origAttribute "="
 204  *                      attributes
 205  * origAttribute     = attribute
 206  * attributes        = wattribute *( space wattribute )
 207  * wattribute        = whsp newAttribute whsp
 208  * newAttribute      = descr | "*NULL*"
 209  * attribute         = descr
 210  *
 211  * objectclassMap syntax:
 212  * objectclassMap    = serviceId ":" origObjectclass "="
 213  *                      objectclass
 214  * origObjectclass   = objectclass
 215  * objectclass       = keystring
 216  */
 217 
 218 int
 219 __s_api_parse_map(char *cp, char **sid, char **origA, char ***mapA)
 220 {
 221         char    *sptr, *dptr, **mapp;
 222         int     i, max;
 223 
 224         *sid = NULL;
 225         *origA = NULL;
 226         *mapA = NULL;
 227 
 228         sptr = cp;
 229         dptr = strchr(sptr, COLONTOK);
 230         if (dptr == NULL)
 231                 return (NS_HASH_RC_SYNTAX_ERROR);
 232         i = dptr - sptr + 1;
 233         *sid = (char *)malloc(i);
 234         if (*sid == NULL)
 235                 return (NS_HASH_RC_NO_MEMORY);
 236         (void) strlcpy(*sid, sptr, i);
 237         sptr = dptr+1;
 238 
 239         dptr = strchr(sptr, TOKENSEPARATOR);
 240         if (dptr == NULL) {
 241                 free(*sid);
 242                 *sid = NULL;
 243                 return (NS_HASH_RC_SYNTAX_ERROR);
 244         }
 245         i = dptr - sptr + 1;
 246         *origA = (char *)malloc(i);
 247         if (*origA == NULL) {
 248                 free(*sid);
 249                 *sid = NULL;
 250                 return (NS_HASH_RC_NO_MEMORY);
 251         }
 252         (void) strlcpy(*origA, sptr, i);
 253         sptr = dptr+1;
 254 
 255         max = 1;
 256         for (dptr = sptr; *dptr; dptr++) {
 257                 if (*dptr == SPACETOK) {
 258                         max++;
 259                         while (*(dptr+1) == SPACETOK)
 260                                 dptr++;
 261                 }
 262         }
 263         *mapA = (char **)calloc(max+1, sizeof (char *));
 264         if (*mapA == NULL) {
 265                 free(*sid);
 266                 *sid = NULL;
 267                 free(*origA);
 268                 *origA = NULL;
 269                 return (NS_HASH_RC_NO_MEMORY);
 270         }
 271         mapp = *mapA;
 272 
 273         while (*sptr) {
 274                 while (*sptr == SPACETOK)
 275                         sptr++;
 276                 dptr = sptr;
 277                 while (*dptr && *dptr != SPACETOK)
 278                         dptr++;
 279                 i = dptr - sptr + 1;
 280                 *mapp = (char *)malloc(i);
 281                 if (*mapp == NULL) {
 282                         free(*sid);
 283                         *sid = NULL;
 284                         free(*origA);
 285                         *origA = NULL;
 286                         __s_api_free2dArray(*mapA);
 287                         *mapA = NULL;
 288                         return (NS_HASH_RC_NO_MEMORY);
 289                 }
 290                 (void) strlcpy(*mapp, sptr, i);
 291                 mapp++;
 292                 sptr = dptr;
 293         }
 294         return (NS_HASH_RC_SUCCESS);
 295 }
 296 
 297 
 298 static void
 299 __ns_ldap_freeASearchDesc(ns_ldap_search_desc_t *ptr)
 300 {
 301         if (ptr == NULL)
 302                 return;
 303         if (ptr->basedn)
 304                 free(ptr->basedn);
 305         if (ptr->filter)
 306                 free(ptr->filter);
 307         free(ptr);
 308 }
 309 
 310 /*
 311  * Parse a service descriptor
 312  * and create a service descriptor struct
 313  * SD Format:
 314  *    serviceid:[base][?[scope][?[filter]]];[[base][?[scope][?[filter]]]]
 315  * desc format:
 316  *    [base][?[scope][?[filter]]]
 317  */
 318 
 319 typedef enum _ns_parse_state {
 320         P_ERROR, P_INIT, P_BASEDN, P_SCOPE,
 321         P_INIFILTER, P_FILTER, P_END, P_EXIT, P_MEMERR
 322 } _ns_parse_state_t;
 323 
 324 static
 325 int
 326 __s_api_parseASearchDesc(const char *service,
 327     char **cur, ns_ldap_search_desc_t **ret)
 328 {
 329         ns_ldap_search_desc_t   *ptr;
 330         char                    *sptr, *dptr;
 331         int                     i, rc;
 332         ns_ldap_error_t         **errorp = NULL;
 333         ns_ldap_error_t         *error = NULL;
 334         void                    **paramVal = NULL;
 335         char                    **dns = NULL;
 336         _ns_parse_state_t       state = P_INIT;
 337         int                     quoted = 0;
 338         int                     wasquoted = 0;
 339         int                     empty = 1;
 340 
 341         if (ret == NULL)
 342                 return (NS_LDAP_INVALID_PARAM);
 343         *ret = NULL;
 344         if (cur == NULL)
 345                 return (NS_LDAP_INVALID_PARAM);
 346 
 347         ptr = (ns_ldap_search_desc_t *)
 348             calloc(1, sizeof (ns_ldap_search_desc_t));
 349         if (ptr == NULL)
 350                 return (NS_LDAP_MEMORY);
 351 
 352         sptr = *cur;
 353 
 354         /* Get the default scope */
 355         if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
 356             &paramVal, errorp)) != NS_LDAP_SUCCESS) {
 357                 (void) __ns_ldap_freeError(errorp);
 358                 __ns_ldap_freeASearchDesc(ptr);
 359                 ptr = NULL;
 360                 return (NS_LDAP_MEMORY);
 361         }
 362         if (paramVal && *paramVal)
 363                 ptr->scope = * (ScopeType_t *)(*paramVal);
 364         else
 365                 ptr->scope = NS_LDAP_SCOPE_ONELEVEL;
 366         (void) __ns_ldap_freeParam(&paramVal);
 367         paramVal = NULL;
 368 
 369         for (/* none */; state != P_EXIT && sptr && *sptr; sptr++) {
 370                 empty = 0;
 371                 switch (state) {
 372                 case P_INIT:
 373                         if (*sptr == QUESTTOK) {
 374                                 /* No basedn */
 375                                 ptr->basedn = strdup("");
 376                                 if (!ptr->basedn) {
 377                                         state = P_MEMERR;
 378                                         break;
 379                                 }
 380                                 state = P_SCOPE;
 381                                 break;
 382                         }
 383                         if (*sptr == SEMITOK) {
 384                                 /* No SSD */
 385                                 ptr->basedn = strdup("");
 386                                 if (!ptr->basedn) {
 387                                         state = P_MEMERR;
 388                                         break;
 389                                 }
 390                                 state = P_EXIT;
 391                                 break;
 392                         }
 393                         /* prepare to copy DN */
 394                         i = strlen(sptr) + 1;
 395                         ptr->basedn = dptr = (char *)calloc(i, sizeof (char));
 396                         if (!ptr->basedn) {
 397                                 state = P_MEMERR;
 398                                 break;
 399                         }
 400                         if (*sptr == BSLTOK) {
 401                                 if (*(sptr+1) == '\0') {
 402                                         /* error */
 403                                         state = P_ERROR;
 404                                         break;
 405                                 }
 406                                 if (*(sptr+1) == QUOTETOK ||
 407                                     *(sptr+1) == BSLTOK) {
 408                                         /* escaped CHARS */
 409                                         sptr++;
 410                                 } else {
 411                                         *dptr++ = *sptr++;
 412                                 }
 413                                 *dptr++ = *sptr;
 414                         } else if (*sptr == QUOTETOK) {
 415                                 quoted = 1;
 416                                 wasquoted = 1;
 417                         } else {
 418                                 *dptr++ = *sptr;
 419                         }
 420                         state = P_BASEDN;
 421                         break;
 422                 case P_INIFILTER:
 423                         if (*sptr == SEMITOK) {
 424                                 /* No filter and no more SSD */
 425                                 state = P_EXIT;
 426                                 break;
 427                         }
 428                         /* prepare to copy DN */
 429                         i = strlen(sptr) + 1;
 430                         ptr->filter = dptr = (char *)calloc(i, sizeof (char));
 431                         if (!ptr->filter) {
 432                                 state = P_MEMERR;
 433                                 break;
 434                         }
 435                         if (*sptr == BSLTOK) {
 436                                 if (*(sptr+1) == '\0') {
 437                                         /* error */
 438                                         state = P_ERROR;
 439                                         break;
 440                                 }
 441                                 if (*(sptr+1) == QUOTETOK ||
 442                                     *(sptr+1) == BSLTOK) {
 443                                         /* escaped CHARS */
 444                                         sptr++;
 445                                 } else {
 446                                         *dptr++ = *sptr++;
 447                                 }
 448                                 *dptr++ = *sptr;
 449                         } else if (*sptr == QUOTETOK) {
 450                                 quoted = 1;
 451                                 wasquoted = 1;
 452                         } else {
 453                                 *dptr++ = *sptr;
 454                         }
 455                         state = P_FILTER;
 456                         break;
 457                 case P_SCOPE:
 458                         if (*sptr == SEMITOK) {
 459                                 /* no more SSD */
 460                                 state = P_EXIT;
 461                                 break;
 462                         }
 463                         if (strncasecmp(sptr, "base", 4) == 0) {
 464                                 sptr += 4;
 465                                 ptr->scope = NS_LDAP_SCOPE_BASE;
 466                         } else if (strncasecmp(sptr, "one", 3) == 0) {
 467                                 ptr->scope = NS_LDAP_SCOPE_ONELEVEL;
 468                                 sptr += 3;
 469                         } else if (strncasecmp(sptr, "sub", 3) == 0) {
 470                                 ptr->scope = NS_LDAP_SCOPE_SUBTREE;
 471                                 sptr += 3;
 472                         }
 473                         if (*sptr == '\0' || (*sptr == SEMITOK)) {
 474                                 /* no more SSD */
 475                                 state = P_EXIT;
 476                                 sptr--;
 477                                 break;
 478                         }
 479                         if (*sptr != QUESTTOK) {
 480                                 state = P_ERROR;
 481                                 break;
 482                         }
 483                         state = P_INIFILTER;
 484                         quoted = 0;
 485                         wasquoted = 0;
 486                         break;
 487                 case P_BASEDN:
 488                 case P_FILTER:
 489                         if (quoted) {
 490                                 /* Quoted */
 491                                 if (*sptr == BSLTOK) {
 492                                         if (*(sptr+1) == '\0') {
 493                                                 state = P_ERROR;
 494                                                 break;
 495                                         }
 496                                         if (*(sptr+1) == QUOTETOK ||
 497                                             *(sptr+1) == BSLTOK) {
 498                                                 /* escaped CHARS */
 499                                                 sptr++;
 500                                         } else {
 501                                                 *dptr++ = *sptr++;
 502                                         }
 503                                         /* fall through to char copy */
 504                                 } else if (*sptr == QUOTETOK) {
 505                                         /* end of string */
 506                                         *dptr = '\0';
 507                                         quoted = 0;
 508                                         break;
 509                                 }
 510                                 /* else fall through to char copy */
 511                         } else {
 512                                 /* Unquoted */
 513                                 if (wasquoted && *sptr != QUESTTOK) {
 514                                         /* error  past end of quoted string */
 515                                         state = P_ERROR;
 516                                         break;
 517                                 }
 518                                 if (*sptr == BSLTOK) {
 519                                         if (*(sptr+1) == '\0') {
 520                                                 state = P_ERROR;
 521                                                 break;
 522                                         }
 523                                         if (*(sptr+1) == SEMITOK ||
 524                                             *(sptr+1) == QUESTTOK ||
 525                                             *(sptr+1) == QUOTETOK ||
 526                                             *(sptr+1) == BSLTOK) {
 527                                                 /* escaped chars */
 528                                                 sptr++;
 529                                         }
 530                                         /* fall through to char copy */
 531                                 } else if (*sptr == QUOTETOK) {
 532                                         /* error */
 533                                         state = P_ERROR;
 534                                         break;
 535                                 } else if (*sptr == QUESTTOK) {
 536                                         /* if filter error */
 537                                         if (state == P_FILTER) {
 538                                                 state = P_ERROR;
 539                                                 break;
 540                                         }
 541                                         /* end of basedn goto scope */
 542                                         *dptr = '\0';
 543                                         state = P_SCOPE;
 544                                         break;
 545                                 } else if (*sptr == SEMITOK) {
 546                                         /* end of current SSD */
 547                                         *dptr = '\0';
 548                                         state = P_EXIT;
 549                                         break;
 550                                 }
 551                         }
 552                         /* normal character to copy */
 553                         *dptr++ = *sptr;
 554                         break;
 555                 case P_END:
 556                         if (*sptr == SEMITOK) {
 557                                 state = P_EXIT;
 558                                 break;
 559                         }
 560                         __ns_ldap_freeASearchDesc(ptr);
 561                         ptr = NULL;
 562                         *cur = NULL;
 563                         return (NS_LDAP_CONFIG);
 564                 default:         /* error should never arrive here */
 565                 case P_ERROR:
 566                         __ns_ldap_freeASearchDesc(ptr);
 567                         ptr = NULL;
 568                         *cur = NULL;
 569                         return (NS_LDAP_CONFIG);
 570                 case P_MEMERR:
 571                         __ns_ldap_freeASearchDesc(ptr);
 572                         ptr = NULL;
 573                         *cur = NULL;
 574                         return (NS_LDAP_MEMORY);
 575                 }
 576         }
 577 
 578         if (quoted) {
 579                 __ns_ldap_freeASearchDesc(ptr);
 580                 ptr = NULL;
 581                 *cur = NULL;
 582                 return (NS_LDAP_INVALID_PARAM);
 583         }
 584 
 585         if (empty || strlen(ptr->basedn) == 0) {
 586                 if (ptr->basedn)
 587                         free(ptr->basedn);
 588                 /* get default base */
 589                 rc = __s_api_getDNs(&dns, service, &error);
 590                 if (rc != NS_LDAP_SUCCESS) {
 591                         if (dns) {
 592                                 __s_api_free2dArray(dns);
 593                                 dns = NULL;
 594                         }
 595                         (void) __ns_ldap_freeError(&error);
 596                         __ns_ldap_freeASearchDesc(ptr);
 597                         ptr = NULL;
 598                         return (NS_LDAP_MEMORY);
 599                 }
 600                 ptr->basedn = strdup(dns[0]);
 601                 __s_api_free2dArray(dns);
 602                 dns = NULL;
 603         }
 604 
 605         *cur = sptr;
 606         *ret = ptr;
 607         return (NS_LDAP_SUCCESS);
 608 }
 609 
 610 
 611 /*
 612  * Build up the service descriptor array
 613  */
 614 #define NS_SDESC_MAX    4
 615 
 616 static int
 617 __ns_ldap_saveSearchDesc(ns_ldap_search_desc_t ***sdlist,
 618     int *cnt, int *max, ns_ldap_search_desc_t *ret)
 619 {
 620         ns_ldap_search_desc_t   **tmplist;
 621 
 622         if (*sdlist == NULL) {
 623                 *cnt = 0;
 624                 *max = NS_SDESC_MAX;
 625                 *sdlist = (ns_ldap_search_desc_t **)
 626                     calloc(*max, sizeof (ns_ldap_search_desc_t *));
 627                 if (*sdlist == NULL)
 628                         return (-1);
 629         } else if (*cnt+1 >= *max) {
 630                 *max += NS_SDESC_MAX;
 631                 tmplist = (ns_ldap_search_desc_t **)
 632                     realloc((void *)(*sdlist),
 633                     *max * sizeof (ns_ldap_search_desc_t *));
 634                 if (tmplist == NULL)
 635                         return (-1);
 636                 else
 637                         *sdlist = tmplist;
 638         }
 639         (*sdlist)[*cnt] = ret;
 640         (*cnt)++;
 641         (*sdlist)[*cnt] = NULL;
 642         return (0);
 643 }
 644 
 645 
 646 /*
 647  * Exported Search Descriptor Routines
 648  */
 649 
 650 int __ns_ldap_getSearchDescriptors(
 651         const char *service,
 652         ns_ldap_search_desc_t ***desc,
 653         ns_ldap_error_t **errorp)
 654 {
 655         int                     rc;
 656         int                     slen;
 657         void                    **param = NULL;
 658         void                    **paramVal = NULL;
 659         char                    **sdl, *srv, **sdl_save;
 660         char                    errstr[2 * MAXERROR];
 661         ns_ldap_search_desc_t   **sdlist;
 662         int                     cnt, max;
 663         int                     vers;
 664         ns_config_t             *cfg;
 665         ns_ldap_search_desc_t   *ret;
 666 
 667         if ((desc == NULL) || (errorp == NULL))
 668                 return (NS_LDAP_INVALID_PARAM);
 669 
 670         *desc = NULL;
 671         *errorp = NULL;
 672 
 673         rc = __ns_ldap_getParam(NS_LDAP_SERVICE_SEARCH_DESC_P,
 674             (void ***)&param, errorp);
 675         if (rc != NS_LDAP_SUCCESS) {
 676                 return (rc);
 677         }
 678         sdl = (char **)param;
 679         cnt = 0;
 680         max = 0;
 681         sdlist = NULL;
 682 
 683         cfg = __s_api_get_default_config();
 684 
 685         if (cfg == NULL) {
 686                 (void) snprintf(errstr, sizeof (errstr),
 687                     gettext("No configuration information available."));
 688                 MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
 689                     NS_LDAP_MEMORY);
 690                 return (NS_LDAP_CONFIG);
 691         }
 692 
 693         vers = cfg->version;
 694         __s_api_release_config(cfg);
 695 
 696         /* If using version1 or no sd's process SEARCH_DN if available */
 697         if (vers == NS_LDAP_V1 && param == NULL) {
 698                 rc = __s_api_get_search_DNs_v1(&sdl, service, errorp);
 699                 if (rc != NS_LDAP_SUCCESS || sdl == NULL) {
 700                         return (rc);
 701                 }
 702                 sdl_save = sdl;
 703                 /* Convert a SEARCH_DN to a search descriptor */
 704                 for (; *sdl; sdl++) {
 705                         ret = (ns_ldap_search_desc_t *)
 706                             calloc(1, sizeof (ns_ldap_search_desc_t));
 707                         if (ret == NULL) {
 708                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 709                                 __s_api_free2dArray(sdl_save);
 710                                 return (NS_LDAP_MEMORY);
 711                         }
 712                         ret->basedn = strdup(*sdl);
 713                         if (ret->basedn == NULL) {
 714                                 free(ret);
 715                                 (void) __ns_ldap_freeASearchDesc(ret);
 716                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 717                                 __s_api_free2dArray(sdl_save);
 718                                 return (NS_LDAP_MEMORY);
 719                         }
 720 
 721                         /* default scope */
 722                         if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
 723                             &paramVal, errorp)) != NS_LDAP_SUCCESS) {
 724                                 (void) __ns_ldap_freeASearchDesc(ret);
 725                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 726                                 __s_api_free2dArray(sdl_save);
 727                                 return (rc);
 728                         }
 729                         if (paramVal && *paramVal)
 730                                 ret->scope = * (ScopeType_t *)(*paramVal);
 731                         else
 732                                 ret->scope = NS_LDAP_SCOPE_ONELEVEL;
 733                         (void) __ns_ldap_freeParam(&paramVal);
 734                         paramVal = NULL;
 735 
 736                         rc = __ns_ldap_saveSearchDesc(&sdlist, &cnt, &max, ret);
 737                         if (rc < 0) {
 738                                 (void) __ns_ldap_freeASearchDesc(ret);
 739                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 740                                 __s_api_free2dArray(sdl_save);
 741                                 return (NS_LDAP_MEMORY);
 742                         }
 743                 }
 744                 __s_api_free2dArray(sdl_save);
 745                 *desc = sdlist;
 746                 return (NS_LDAP_SUCCESS);
 747         }
 748 
 749         if (sdl == NULL || service == NULL) {
 750                 (void) __ns_ldap_freeParam(&param);
 751                 param = NULL;
 752                 *desc = NULL;
 753                 return (NS_LDAP_SUCCESS);
 754         }
 755         slen = strlen(service);
 756 
 757         /* Process the version2 sd's */
 758         for (; *sdl; sdl++) {
 759                 srv = *sdl;
 760                 if (strncasecmp(service, srv, slen) != 0)
 761                         continue;
 762                 srv += slen;
 763                 if (*srv != COLONTOK)
 764                         continue;
 765                 srv++;
 766                 while (srv != NULL && *srv != '\0') {
 767                         /* Process 1 */
 768                         rc = __s_api_parseASearchDesc(service, &srv, &ret);
 769                         if (rc != NS_LDAP_SUCCESS) {
 770                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 771                                 (void) snprintf(errstr, (2 * MAXERROR), gettext(
 772                                     "Invalid serviceSearchDescriptor (%s). "
 773                                     "Illegal configuration"), *sdl);
 774                                 (void) __ns_ldap_freeParam(&param);
 775                                 param = NULL;
 776                                 MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX,
 777                                     strdup(errstr), NS_LDAP_MEMORY);
 778                                 return (rc);
 779                         }
 780                         if (ret != NULL) {
 781                                 rc = __ns_ldap_saveSearchDesc(
 782                                     &sdlist, &cnt, &max, ret);
 783                         }
 784                         if (rc < 0) {
 785                                 (void) __ns_ldap_freeSearchDescriptors(&sdlist);
 786                                 (void) __ns_ldap_freeParam(&param);
 787                                 param = NULL;
 788                                 return (NS_LDAP_MEMORY);
 789                         }
 790                 }
 791         }
 792 
 793         (void) __ns_ldap_freeParam(&param);
 794         param = NULL;
 795         *desc = sdlist;
 796         return (NS_LDAP_SUCCESS);
 797 }
 798 
 799 int
 800 __ns_ldap_freeSearchDescriptors(ns_ldap_search_desc_t ***desc)
 801 {
 802         ns_ldap_search_desc_t **dptr;
 803         ns_ldap_search_desc_t *ptr;
 804 
 805         if (*desc == NULL)
 806                 return (NS_LDAP_SUCCESS);
 807         for (dptr = *desc; (ptr = *dptr) != NULL; dptr++) {
 808                 __ns_ldap_freeASearchDesc(ptr);
 809         }
 810         free(*desc);
 811         *desc = NULL;
 812 
 813         return (NS_LDAP_SUCCESS);
 814 }
 815 
 816 
 817 
 818 
 819 /*
 820  * Exported Attribute/Objectclass mapping functions.
 821  */
 822 
 823 /*
 824  * This function is not supported.
 825  */
 826 /* ARGSUSED */
 827 int __ns_ldap_getAttributeMaps(
 828         const char *service,
 829         ns_ldap_attribute_map_t ***maps,
 830         ns_ldap_error_t **errorp)
 831 {
 832         *maps = NULL;
 833         return (NS_LDAP_OP_FAILED);
 834 }
 835 
 836 int
 837 __ns_ldap_freeAttributeMaps(ns_ldap_attribute_map_t ***maps)
 838 {
 839         ns_ldap_attribute_map_t **dptr;
 840         ns_ldap_attribute_map_t *ptr;
 841         char **cpp, *cp;
 842 
 843         if (*maps == NULL)
 844                 return (NS_LDAP_SUCCESS);
 845         for (dptr = *maps; (ptr = *dptr) != NULL; dptr++) {
 846                 if (ptr->origAttr) {
 847                         free(ptr->origAttr);
 848                         ptr->origAttr = NULL;
 849                 }
 850                 if (ptr->mappedAttr) {
 851                         for (cpp = ptr->mappedAttr; (cp = *cpp) != NULL; cpp++)
 852                                 free(cp);
 853                         free(ptr->mappedAttr);
 854                         ptr->mappedAttr = NULL;
 855                 }
 856                 free(ptr);
 857         }
 858         free(*maps);
 859         *maps = NULL;
 860 
 861         return (NS_LDAP_SUCCESS);
 862 }
 863 
 864 char **__ns_ldap_getMappedAttributes(
 865         const char *service,
 866         const char *origAttribute)
 867 {
 868         ns_config_t     *ptr = __s_api_loadrefresh_config();
 869         ns_hash_t       *hp;
 870         char            **ret;
 871 
 872         if (ptr == NULL)
 873                 return (NULL);
 874 
 875         hp = ns_get_hash(ptr, NS_HASH_AMAP, service, origAttribute);
 876 
 877         if (hp == NULL || hp->h_map == NULL)
 878                 ret = NULL;
 879         else
 880                 ret = __s_api_cp2dArray(hp->h_map->map);
 881         __s_api_release_config(ptr);
 882         return (ret);
 883 }
 884 
 885 char **__ns_ldap_getOrigAttribute(
 886         const char *service,
 887         const char *mappedAttribute)
 888 {
 889         ns_config_t     *ptr = __s_api_loadrefresh_config();
 890         ns_hash_t       *hp;
 891         char            **ret;
 892 
 893         if (ptr == NULL)
 894                 return (NULL);
 895 
 896         hp = ns_get_hash(ptr, NS_HASH_RAMAP, service, mappedAttribute);
 897 
 898         if (hp == NULL || hp->h_map == NULL)
 899                 ret = NULL;
 900         else
 901                 ret = __s_api_cp2dArray(hp->h_map->map);
 902         __s_api_release_config(ptr);
 903         return (ret);
 904 }
 905 
 906 /*
 907  * This function is not supported.
 908  */
 909 /* ARGSUSED */
 910 int __ns_ldap_getObjectClassMaps(
 911         const char *service,
 912         ns_ldap_objectclass_map_t ***maps,
 913         ns_ldap_error_t **errorp)
 914 {
 915         *maps = NULL;
 916         return (NS_LDAP_OP_FAILED);
 917 }
 918 
 919 int
 920 __ns_ldap_freeObjectClassMaps(ns_ldap_objectclass_map_t ***maps)
 921 {
 922         ns_ldap_objectclass_map_t **dptr;
 923         ns_ldap_objectclass_map_t *ptr;
 924 
 925         if (*maps == NULL)
 926                 return (NS_LDAP_SUCCESS);
 927         for (dptr = *maps; (ptr = *dptr) != NULL; dptr++) {
 928                 if (ptr->origOC) {
 929                         free(ptr->origOC);
 930                         ptr->origOC = NULL;
 931                 }
 932                 if (ptr->mappedOC) {
 933                         free(ptr->mappedOC);
 934                         ptr->mappedOC = NULL;
 935                 }
 936                 free(ptr);
 937         }
 938         free(*maps);
 939         *maps = NULL;
 940 
 941         return (NS_LDAP_SUCCESS);
 942 }
 943 
 944 char **__ns_ldap_getMappedObjectClass(
 945         const char *service,
 946         const char *origObjectClass)
 947 {
 948         ns_config_t     *ptr = __s_api_loadrefresh_config();
 949         ns_hash_t       *hp;
 950         char            **ret;
 951 
 952         if (ptr == NULL)
 953                 return (NULL);
 954 
 955         hp = ns_get_hash(ptr, NS_HASH_OMAP, service, origObjectClass);
 956 
 957         if (hp == NULL || hp->h_map == NULL)
 958                 ret = NULL;
 959         else
 960                 ret = __s_api_cp2dArray(hp->h_map->map);
 961         __s_api_release_config(ptr);
 962         return (ret);
 963 }
 964 
 965 char **__ns_ldap_getOrigObjectClass(
 966         const char *service,
 967         const char *mappedObjectClass)
 968 {
 969         ns_config_t     *ptr = __s_api_loadrefresh_config();
 970         ns_hash_t       *hp;
 971         char            **ret;
 972 
 973         if (ptr == NULL)
 974                 return (NULL);
 975 
 976         hp = ns_get_hash(ptr, NS_HASH_ROMAP, service, mappedObjectClass);
 977 
 978         if (hp == NULL || hp->h_map == NULL)
 979                 ret = NULL;
 980         else
 981                 ret = __s_api_cp2dArray(hp->h_map->map);
 982         __s_api_release_config(ptr);
 983         return (ret);
 984 }
 985 
 986 char **__ns_ldap_mapAttributeList(
 987         const char *service,
 988         const char * const *origAttrList)
 989 {
 990         const char * const *opp;
 991         char **cpp, **npp;
 992         int i;
 993 
 994         if (origAttrList == NULL)
 995                 return (NULL);
 996 
 997         opp = origAttrList;
 998         for (i = 0; *opp; i++, opp++)
 999                 ;
1000         cpp = (char **)calloc(i+1, sizeof (char *));
1001         if (cpp == NULL)
1002                 return (NULL);
1003 
1004         opp = origAttrList;
1005         for (i = 0; *opp; i++, opp++) {
1006                 npp =  __ns_ldap_getMappedAttributes(service, *opp);
1007                 if (npp && npp[0]) {
1008                         cpp[i] = strdup(npp[0]);
1009                         __s_api_free2dArray(npp);
1010                         npp = NULL;
1011                         if (cpp[i] == NULL) {
1012                                 __s_api_free2dArray(cpp);
1013                                 return (NULL);
1014                         }
1015                 } else {
1016                         cpp[i] = strdup(*opp);
1017                         if (cpp[i] == NULL) {
1018                                 __s_api_free2dArray(cpp);
1019                                 return (NULL);
1020                         }
1021                 }
1022         }
1023         return (cpp);
1024 }
1025 
1026 char *
1027 __ns_ldap_mapAttribute(
1028         const char *service,
1029         const char *origAttr)
1030 {
1031         char **npp;
1032         char *mappedAttr;
1033 
1034         if (origAttr == NULL)
1035                 return (NULL);
1036 
1037         npp = __ns_ldap_getMappedAttributes(service, origAttr);
1038         if (npp && npp[0]) {
1039                 mappedAttr = strdup(npp[0]);
1040                 __s_api_free2dArray(npp);
1041         } else {
1042                 mappedAttr = strdup(origAttr);
1043         }
1044         return (mappedAttr);
1045 }