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