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
38static unsigned long
39ns_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
59static ns_hash_t *
60ns_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
78static ns_hash_t *
79ns_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
99static void
100ns_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
128static ns_hash_t *
129ns_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
146void
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
169int
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
218int
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
298static 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
319typedef 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
324static
325int
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
618static 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
652int __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
801int
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 */
829int __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
838int
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
866char **__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
887char **__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 */
912int __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
921int
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
946char **__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
967char **__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
988char **__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
1028char *
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