xref: /illumos-gate/usr/src/lib/libsldap/common/ns_mapping.c (revision a71e11eee4676204c7609c4c9703cc98fbf4669d)
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 		    NULL);
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 != NULL) {
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), NULL);
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 }
1046