xref: /illumos-gate/usr/src/lib/libsldap/common/ns_mapping.c (revision ce17336ed725d3b7fdff67bf0a0ee2b55018fec6)
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 }
1047