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