xref: /illumos-gate/usr/src/lib/libsldap/common/ns_mapping.c (revision 3bbf88b3546192f29c18986b9fb8a19ff364a4ea)
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 	char			buf[BUFSIZ];
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 			buf[0] = '\0';
460 			if (*sptr == SEMITOK) {
461 				/* no more SSD */
462 				state = P_EXIT;
463 				break;
464 			}
465 			if (strncasecmp(sptr, "base", 4) == 0) {
466 				sptr += 4;
467 				ptr->scope = NS_LDAP_SCOPE_BASE;
468 			} else if (strncasecmp(sptr, "one", 3) == 0) {
469 				ptr->scope = NS_LDAP_SCOPE_ONELEVEL;
470 				sptr += 3;
471 			} else if (strncasecmp(sptr, "sub", 3) == 0) {
472 				ptr->scope = NS_LDAP_SCOPE_SUBTREE;
473 				sptr += 3;
474 			}
475 			if (*sptr == '\0' || (*sptr == SEMITOK)) {
476 				/* no more SSD */
477 				state = P_EXIT;
478 				sptr--;
479 				break;
480 			}
481 			if (*sptr != QUESTTOK) {
482 				state = P_ERROR;
483 				break;
484 			}
485 			state = P_INIFILTER;
486 			quoted = 0;
487 			wasquoted = 0;
488 			break;
489 		case P_BASEDN:
490 		case P_FILTER:
491 			if (quoted) {
492 				/* Quoted */
493 				if (*sptr == BSLTOK) {
494 					if (*(sptr+1) == '\0') {
495 						state = P_ERROR;
496 						break;
497 					}
498 					if (*(sptr+1) == QUOTETOK ||
499 					    *(sptr+1) == BSLTOK) {
500 						/* escaped CHARS */
501 						sptr++;
502 					} else {
503 						*dptr++ = *sptr++;
504 					}
505 					/* fall through to char copy */
506 				} else if (*sptr == QUOTETOK) {
507 					/* end of string */
508 					*dptr = '\0';
509 					quoted = 0;
510 					break;
511 				}
512 				/* else fall through to char copy */
513 			} else {
514 				/* Unquoted */
515 				if (wasquoted && *sptr != QUESTTOK) {
516 					/* error  past end of quoted string */
517 					state = P_ERROR;
518 					break;
519 				}
520 				if (*sptr == BSLTOK) {
521 					if (*(sptr+1) == '\0') {
522 						state = P_ERROR;
523 						break;
524 					}
525 					if (*(sptr+1) == SEMITOK ||
526 					    *(sptr+1) == QUESTTOK ||
527 					    *(sptr+1) == QUOTETOK ||
528 					    *(sptr+1) == BSLTOK) {
529 						/* escaped chars */
530 						sptr++;
531 					}
532 					/* fall through to char copy */
533 				} else if (*sptr == QUOTETOK) {
534 					/* error */
535 					state = P_ERROR;
536 					break;
537 				} else if (*sptr == QUESTTOK) {
538 					/* if filter error */
539 					if (state == P_FILTER) {
540 						state = P_ERROR;
541 						break;
542 					}
543 					/* end of basedn goto scope */
544 					*dptr = '\0';
545 					state = P_SCOPE;
546 					break;
547 				} else if (*sptr == SEMITOK) {
548 					/* end of current SSD */
549 					*dptr = '\0';
550 					state = P_EXIT;
551 					break;
552 				}
553 			}
554 			/* normal character to copy */
555 			*dptr++ = *sptr;
556 			break;
557 		case P_END:
558 			if (*sptr == SEMITOK) {
559 				state = P_EXIT;
560 				break;
561 			}
562 			__ns_ldap_freeASearchDesc(ptr);
563 			ptr = NULL;
564 			*cur = NULL;
565 			return (NS_LDAP_CONFIG);
566 		default:	 /* error should never arrive here */
567 		case P_ERROR:
568 			__ns_ldap_freeASearchDesc(ptr);
569 			ptr = NULL;
570 			*cur = NULL;
571 			return (NS_LDAP_CONFIG);
572 		case P_MEMERR:
573 			__ns_ldap_freeASearchDesc(ptr);
574 			ptr = NULL;
575 			*cur = NULL;
576 			return (NS_LDAP_MEMORY);
577 		}
578 	}
579 
580 	if (quoted) {
581 		__ns_ldap_freeASearchDesc(ptr);
582 		ptr = NULL;
583 		*cur = NULL;
584 		return (NS_LDAP_INVALID_PARAM);
585 	}
586 
587 	if (empty || strlen(ptr->basedn) == 0) {
588 		if (ptr->basedn)
589 			free(ptr->basedn);
590 		/* get default base */
591 		rc = __s_api_getDNs(&dns, service, &error);
592 		if (rc != NS_LDAP_SUCCESS) {
593 			if (dns) {
594 				__s_api_free2dArray(dns);
595 				dns = NULL;
596 			}
597 			(void) __ns_ldap_freeError(&error);
598 			__ns_ldap_freeASearchDesc(ptr);
599 			ptr = NULL;
600 			return (NS_LDAP_MEMORY);
601 		}
602 		ptr->basedn = strdup(dns[0]);
603 		__s_api_free2dArray(dns);
604 		dns = NULL;
605 	}
606 
607 	*cur = sptr;
608 	*ret = ptr;
609 	return (NS_LDAP_SUCCESS);
610 }
611 
612 
613 /*
614  * Build up the service descriptor array
615  */
616 #define	NS_SDESC_MAX	4
617 
618 static int
619 __ns_ldap_saveSearchDesc(ns_ldap_search_desc_t ***sdlist,
620 	int *cnt, int *max, ns_ldap_search_desc_t *ret)
621 {
622 	ns_ldap_search_desc_t	**tmplist;
623 
624 	if (*sdlist == NULL) {
625 		*cnt = 0;
626 		*max = NS_SDESC_MAX;
627 		*sdlist = (ns_ldap_search_desc_t **)
628 		    calloc(*max, sizeof (ns_ldap_search_desc_t *));
629 		if (*sdlist == NULL)
630 			return (-1);
631 	} else if (*cnt+1 >= *max) {
632 		*max += NS_SDESC_MAX;
633 		tmplist = (ns_ldap_search_desc_t **)
634 		    realloc((void *)(*sdlist),
635 		    *max * sizeof (ns_ldap_search_desc_t *));
636 		if (tmplist == NULL)
637 			return (-1);
638 		else
639 			*sdlist = tmplist;
640 	}
641 	(*sdlist)[*cnt] = ret;
642 	(*cnt)++;
643 	(*sdlist)[*cnt] = NULL;
644 	return (0);
645 }
646 
647 
648 /*
649  * Exported Search Descriptor Routines
650  */
651 
652 int __ns_ldap_getSearchDescriptors(
653 	const char *service,
654 	ns_ldap_search_desc_t ***desc,
655 	ns_ldap_error_t **errorp)
656 {
657 	int			rc;
658 	int			slen;
659 	void			**param = NULL;
660 	void			**paramVal = NULL;
661 	char			**sdl, *srv, **sdl_save;
662 	char			errstr[2 * MAXERROR];
663 	ns_ldap_search_desc_t	**sdlist;
664 	int			cnt, max;
665 	int			vers;
666 	ns_config_t		*cfg;
667 	ns_ldap_search_desc_t 	*ret;
668 
669 	if ((desc == NULL) || (errorp == NULL))
670 		return (NS_LDAP_INVALID_PARAM);
671 
672 	*desc = NULL;
673 	*errorp = NULL;
674 
675 	rc = __ns_ldap_getParam(NS_LDAP_SERVICE_SEARCH_DESC_P,
676 	    (void ***)&param, errorp);
677 	if (rc != NS_LDAP_SUCCESS) {
678 		return (rc);
679 	}
680 	sdl = (char **)param;
681 	cnt = 0;
682 	max = 0;
683 	sdlist = NULL;
684 
685 	cfg = __s_api_get_default_config();
686 
687 	if (cfg == NULL) {
688 		(void) snprintf(errstr, sizeof (errstr),
689 		    gettext("No configuration information available."));
690 		MKERROR(LOG_ERR, *errorp, NS_CONFIG_NOTLOADED, strdup(errstr),
691 		    NULL);
692 		return (NS_LDAP_CONFIG);
693 	}
694 
695 	vers = cfg->version;
696 	__s_api_release_config(cfg);
697 
698 	/* If using version1 or no sd's process SEARCH_DN if available */
699 	if (vers == NS_LDAP_V1 && param == NULL) {
700 		rc = __s_api_get_search_DNs_v1(&sdl, service, errorp);
701 		if (rc != NS_LDAP_SUCCESS || sdl == NULL) {
702 			return (rc);
703 		}
704 		sdl_save = sdl;
705 		/* Convert a SEARCH_DN to a search descriptor */
706 		for (; *sdl; sdl++) {
707 			ret = (ns_ldap_search_desc_t *)
708 			    calloc(1, sizeof (ns_ldap_search_desc_t));
709 			if (ret == NULL) {
710 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
711 				__s_api_free2dArray(sdl_save);
712 				return (NS_LDAP_MEMORY);
713 			}
714 			ret->basedn = strdup(*sdl);
715 			if (ret->basedn == NULL) {
716 				free(ret);
717 				(void) __ns_ldap_freeASearchDesc(ret);
718 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
719 				__s_api_free2dArray(sdl_save);
720 				return (NS_LDAP_MEMORY);
721 			}
722 
723 			/* default scope */
724 			if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
725 			    &paramVal, errorp)) != NS_LDAP_SUCCESS) {
726 				(void) __ns_ldap_freeASearchDesc(ret);
727 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
728 				__s_api_free2dArray(sdl_save);
729 				return (rc);
730 			}
731 			if (paramVal && *paramVal)
732 				ret->scope = * (ScopeType_t *)(*paramVal);
733 			else
734 				ret->scope = NS_LDAP_SCOPE_ONELEVEL;
735 			(void) __ns_ldap_freeParam(&paramVal);
736 			paramVal = NULL;
737 
738 			rc = __ns_ldap_saveSearchDesc(&sdlist, &cnt, &max, ret);
739 			if (rc < 0) {
740 				(void) __ns_ldap_freeASearchDesc(ret);
741 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
742 				__s_api_free2dArray(sdl_save);
743 				return (NS_LDAP_MEMORY);
744 			}
745 		}
746 		__s_api_free2dArray(sdl_save);
747 		*desc = sdlist;
748 		return (NS_LDAP_SUCCESS);
749 	}
750 
751 	if (sdl == NULL || service == NULL) {
752 		(void) __ns_ldap_freeParam(&param);
753 		param = NULL;
754 		*desc = NULL;
755 		return (NS_LDAP_SUCCESS);
756 	}
757 	slen = strlen(service);
758 
759 	/* Process the version2 sd's */
760 	for (; *sdl; sdl++) {
761 		srv = *sdl;
762 		if (strncasecmp(service, srv, slen) != 0)
763 			continue;
764 		srv += slen;
765 		if (*srv != COLONTOK)
766 			continue;
767 		srv++;
768 		while (srv != NULL && *srv != NULL) {
769 			/* Process 1 */
770 			rc = __s_api_parseASearchDesc(service, &srv, &ret);
771 			if (rc != NS_LDAP_SUCCESS) {
772 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
773 				(void) snprintf(errstr, (2 * MAXERROR), gettext(
774 				    "Invalid serviceSearchDescriptor (%s). "
775 				    "Illegal configuration"), *sdl);
776 				(void) __ns_ldap_freeParam(&param);
777 				param = NULL;
778 				MKERROR(LOG_ERR, *errorp, NS_CONFIG_SYNTAX,
779 				    strdup(errstr), NULL);
780 				return (rc);
781 			}
782 			if (ret != NULL) {
783 				rc = __ns_ldap_saveSearchDesc(
784 				    &sdlist, &cnt, &max, ret);
785 			}
786 			if (rc < 0) {
787 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
788 				(void) __ns_ldap_freeParam(&param);
789 				param = NULL;
790 				return (NS_LDAP_MEMORY);
791 			}
792 		}
793 	}
794 
795 	(void) __ns_ldap_freeParam(&param);
796 	param = NULL;
797 	*desc = sdlist;
798 	return (NS_LDAP_SUCCESS);
799 }
800 
801 int
802 __ns_ldap_freeSearchDescriptors(ns_ldap_search_desc_t ***desc)
803 {
804 	ns_ldap_search_desc_t **dptr;
805 	ns_ldap_search_desc_t *ptr;
806 
807 	if (*desc == NULL)
808 		return (NS_LDAP_SUCCESS);
809 	for (dptr = *desc; (ptr = *dptr) != NULL; dptr++) {
810 		__ns_ldap_freeASearchDesc(ptr);
811 	}
812 	free(*desc);
813 	*desc = NULL;
814 
815 	return (NS_LDAP_SUCCESS);
816 }
817 
818 
819 
820 
821 /*
822  * Exported Attribute/Objectclass mapping functions.
823  */
824 
825 /*
826  * This function is not supported.
827  */
828 /* ARGSUSED */
829 int __ns_ldap_getAttributeMaps(
830 	const char *service,
831 	ns_ldap_attribute_map_t ***maps,
832 	ns_ldap_error_t **errorp)
833 {
834 	*maps = NULL;
835 	return (NS_LDAP_OP_FAILED);
836 }
837 
838 int
839 __ns_ldap_freeAttributeMaps(ns_ldap_attribute_map_t ***maps)
840 {
841 	ns_ldap_attribute_map_t **dptr;
842 	ns_ldap_attribute_map_t *ptr;
843 	char **cpp, *cp;
844 
845 	if (*maps == NULL)
846 		return (NS_LDAP_SUCCESS);
847 	for (dptr = *maps; (ptr = *dptr) != NULL; dptr++) {
848 		if (ptr->origAttr) {
849 			free(ptr->origAttr);
850 			ptr->origAttr = NULL;
851 		}
852 		if (ptr->mappedAttr) {
853 			for (cpp = ptr->mappedAttr; (cp = *cpp) != NULL; cpp++)
854 				free(cp);
855 			free(ptr->mappedAttr);
856 			ptr->mappedAttr = NULL;
857 		}
858 		free(ptr);
859 	}
860 	free(*maps);
861 	*maps = NULL;
862 
863 	return (NS_LDAP_SUCCESS);
864 }
865 
866 char **__ns_ldap_getMappedAttributes(
867 	const char *service,
868 	const char *origAttribute)
869 {
870 	ns_config_t	*ptr = __s_api_loadrefresh_config();
871 	ns_hash_t	*hp;
872 	char		**ret;
873 
874 	if (ptr == NULL)
875 		return (NULL);
876 
877 	hp = ns_get_hash(ptr, NS_HASH_AMAP, service, origAttribute);
878 
879 	if (hp == NULL || hp->h_map == NULL)
880 		ret = NULL;
881 	else
882 		ret = __s_api_cp2dArray(hp->h_map->map);
883 	__s_api_release_config(ptr);
884 	return (ret);
885 }
886 
887 char **__ns_ldap_getOrigAttribute(
888 	const char *service,
889 	const char *mappedAttribute)
890 {
891 	ns_config_t	*ptr = __s_api_loadrefresh_config();
892 	ns_hash_t	*hp;
893 	char		**ret;
894 
895 	if (ptr == NULL)
896 		return (NULL);
897 
898 	hp = ns_get_hash(ptr, NS_HASH_RAMAP, service, mappedAttribute);
899 
900 	if (hp == NULL || hp->h_map == NULL)
901 		ret = NULL;
902 	else
903 		ret = __s_api_cp2dArray(hp->h_map->map);
904 	__s_api_release_config(ptr);
905 	return (ret);
906 }
907 
908 /*
909  * This function is not supported.
910  */
911 /* ARGSUSED */
912 int __ns_ldap_getObjectClassMaps(
913 	const char *service,
914 	ns_ldap_objectclass_map_t ***maps,
915 	ns_ldap_error_t **errorp)
916 {
917 	*maps = NULL;
918 	return (NS_LDAP_OP_FAILED);
919 }
920 
921 int
922 __ns_ldap_freeObjectClassMaps(ns_ldap_objectclass_map_t ***maps)
923 {
924 	ns_ldap_objectclass_map_t **dptr;
925 	ns_ldap_objectclass_map_t *ptr;
926 
927 	if (*maps == NULL)
928 		return (NS_LDAP_SUCCESS);
929 	for (dptr = *maps; (ptr = *dptr) != NULL; dptr++) {
930 		if (ptr->origOC) {
931 			free(ptr->origOC);
932 			ptr->origOC = NULL;
933 		}
934 		if (ptr->mappedOC) {
935 			free(ptr->mappedOC);
936 			ptr->mappedOC = NULL;
937 		}
938 		free(ptr);
939 	}
940 	free(*maps);
941 	*maps = NULL;
942 
943 	return (NS_LDAP_SUCCESS);
944 }
945 
946 char **__ns_ldap_getMappedObjectClass(
947 	const char *service,
948 	const char *origObjectClass)
949 {
950 	ns_config_t	*ptr = __s_api_loadrefresh_config();
951 	ns_hash_t	*hp;
952 	char		**ret;
953 
954 	if (ptr == NULL)
955 		return (NULL);
956 
957 	hp = ns_get_hash(ptr, NS_HASH_OMAP, service, origObjectClass);
958 
959 	if (hp == NULL || hp->h_map == NULL)
960 		ret = NULL;
961 	else
962 		ret = __s_api_cp2dArray(hp->h_map->map);
963 	__s_api_release_config(ptr);
964 	return (ret);
965 }
966 
967 char **__ns_ldap_getOrigObjectClass(
968 	const char *service,
969 	const char *mappedObjectClass)
970 {
971 	ns_config_t	*ptr = __s_api_loadrefresh_config();
972 	ns_hash_t	*hp;
973 	char		**ret;
974 
975 	if (ptr == NULL)
976 		return (NULL);
977 
978 	hp = ns_get_hash(ptr, NS_HASH_ROMAP, service, mappedObjectClass);
979 
980 	if (hp == NULL || hp->h_map == NULL)
981 		ret = NULL;
982 	else
983 		ret = __s_api_cp2dArray(hp->h_map->map);
984 	__s_api_release_config(ptr);
985 	return (ret);
986 }
987 
988 char **__ns_ldap_mapAttributeList(
989 	const char *service,
990 	const char * const *origAttrList)
991 {
992 	const char * const *opp;
993 	char **cpp, **npp;
994 	int i;
995 
996 	if (origAttrList == NULL)
997 		return (NULL);
998 
999 	opp = origAttrList;
1000 	for (i = 0; *opp; i++, opp++)
1001 		;
1002 	cpp = (char **)calloc(i+1, sizeof (char *));
1003 	if (cpp == NULL)
1004 		return (NULL);
1005 
1006 	opp = origAttrList;
1007 	for (i = 0; *opp; i++, opp++) {
1008 		npp =  __ns_ldap_getMappedAttributes(service, *opp);
1009 		if (npp && npp[0]) {
1010 			cpp[i] = strdup(npp[0]);
1011 			__s_api_free2dArray(npp);
1012 			npp = NULL;
1013 			if (cpp[i] == NULL) {
1014 				__s_api_free2dArray(cpp);
1015 				return (NULL);
1016 			}
1017 		} else {
1018 			cpp[i] = strdup(*opp);
1019 			if (cpp[i] == NULL) {
1020 				__s_api_free2dArray(cpp);
1021 				return (NULL);
1022 			}
1023 		}
1024 	}
1025 	return (cpp);
1026 }
1027 
1028 char *
1029 __ns_ldap_mapAttribute(
1030 	const char *service,
1031 	const char *origAttr)
1032 {
1033 	char **npp;
1034 	char *mappedAttr;
1035 
1036 	if (origAttr == NULL)
1037 		return (NULL);
1038 
1039 	npp = __ns_ldap_getMappedAttributes(service, origAttr);
1040 	if (npp && npp[0]) {
1041 		mappedAttr = strdup(npp[0]);
1042 		__s_api_free2dArray(npp);
1043 	} else {
1044 		mappedAttr = strdup(origAttr);
1045 	}
1046 	return (mappedAttr);
1047 }
1048