xref: /illumos-gate/usr/src/lib/libsldap/common/ns_common.c (revision 7f7322febbcfe774b7270abc3b191c094bfcc517)
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 2005 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 <stdio.h>
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <libintl.h>
33 #include <ctype.h>
34 
35 #include <sys/stat.h>
36 #include <sys/mman.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <string.h>
40 #include <syslog.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <net/if.h>
46 #include <netdir.h>
47 #include <lber.h>
48 #include <ldap.h>
49 
50 #include "ns_sldap.h"
51 #include "ns_internal.h"
52 #include "ns_cache_door.h"
53 
54 #define	UDP	"/dev/udp"
55 #define	MAXIFS	32
56 
57 struct ifinfo {
58 	struct in_addr addr, netmask;
59 };
60 
61 static ns_service_map ns_def_map[] = {
62 	{ "passwd",	"ou=people,",		NULL },
63 	{ "shadow",	"ou=people,",		"passwd" },
64 	{ "user_attr",	"ou=people,",		"passwd" },
65 	{ "audit_user",	"ou=people,",		"passwd" },
66 	{ "group",	"ou=group,",		NULL },
67 	{ "rpc",	"ou=rpc,",		NULL },
68 	{ "project",	"ou=projects,",		NULL },
69 	{ "protocols",	"ou=protocols,",	NULL },
70 	{ "networks",	"ou=networks,",		NULL },
71 	{ "netmasks",	"ou=networks,",		"networks" },
72 	{ "netgroup",	"ou=netgroup,",		NULL },
73 	{ "aliases",	"ou=aliases,",		NULL },
74 	{ "Hosts",	"ou=Hosts,",		NULL },
75 	{ "ipnodes",	"ou=Hosts,",		"hosts" },
76 	{ "Services",	"ou=Services,",		NULL },
77 	{ "bootparams",	"ou=ethers,",		"ethers" },
78 	{ "ethers",	"ou=ethers,",		NULL },
79 	{ "auth_attr",	"ou=SolarisAuthAttr,",	NULL },
80 	{ "prof_attr",	"ou=SolarisProfAttr,",	NULL },
81 	{ "exec_attr",	"ou=SolarisProfAttr,",	"prof_attr" },
82 	{ "profile",	"ou=profile,",		NULL },
83 	{ "printers",	"ou=printers,",		NULL },
84 	{ "automount",	"",			NULL },
85 	{ NULL, NULL, NULL }
86 };
87 
88 
89 static char ** parseDN(const char *val, const char *service);
90 static char ** sortServerNet(char **srvlist);
91 static char ** sortServerPref(char **srvlist, char **preflist,
92 		boolean_t flag, int version, int *error);
93 
94 /*
95  * FUNCTION:	s_api_printResult
96  *	Given a ns_ldap_result structure print it.
97  */
98 int
99 __s_api_printResult(ns_ldap_result_t *result)
100 {
101 
102 	ns_ldap_entry_t	*curEntry;
103 	int		i, j, k = 0;
104 
105 #ifdef DEBUG
106 	(void) fprintf(stderr, "__s_api_printResult START\n");
107 #endif
108 	(void) printf("--------------------------------------\n");
109 	if (result == NULL) {
110 		(void) printf("No result\n");
111 		return (0);
112 	}
113 	(void) printf("entries_count %d\n", result->entries_count);
114 	curEntry = result->entry;
115 	for (i = 0; i < result->entries_count; i++) {
116 
117 	    (void) printf("entry %d has attr_count = %d \n", i,
118 				curEntry->attr_count);
119 	    for (j = 0; j < curEntry->attr_count; j++) {
120 		(void) printf("entry %d has attr_pair[%d] = %s \n", i, j,
121 		curEntry->attr_pair[j]->attrname);
122 		for (k = 0; k < 20 && curEntry->attr_pair[j]->attrvalue[k]; k++)
123 		(void) printf(
124 			"entry %d has attr_pair[%d]->attrvalue[%d] = %s \n",
125 			i, j, k, curEntry->attr_pair[j]->attrvalue[k]);
126 	    }
127 	    (void) printf("\n--------------------------------------\n");
128 	    curEntry = curEntry->next;
129 	}
130 	return (1);
131 }
132 
133 /*
134  * FUNCTION:	__s_api_getSearchScope
135  *
136  *	Retrieve the search scope for ldap search from the config module.
137  *
138  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_CONFIG
139  * INPUT:		NONE
140  * OUTPUT:		searchScope, errorp
141  */
142 int
143 __s_api_getSearchScope(
144 	int *searchScope,
145 	ns_ldap_error_t **errorp)
146 {
147 
148 	char		errmsg[MAXERROR];
149 	void		**paramVal = NULL;
150 	int		rc = 0;
151 	int		scope = 0;
152 
153 #ifdef DEBUG
154 	(void) fprintf(stderr, "__s_api_getSearchScope START\n");
155 #endif
156 	if (*searchScope == 0) {
157 		if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_SCOPE_P,
158 			&paramVal, errorp)) != NS_LDAP_SUCCESS) {
159 			return (rc);
160 		}
161 		if (paramVal && *paramVal)
162 			scope = * (int *)(*paramVal);
163 		else
164 			scope = NS_LDAP_SCOPE_ONELEVEL;
165 		(void) __ns_ldap_freeParam(&paramVal);
166 	} else {
167 		scope = *searchScope;
168 	}
169 
170 	switch (scope) {
171 
172 		case	NS_LDAP_SCOPE_ONELEVEL:
173 			*searchScope = LDAP_SCOPE_ONELEVEL;
174 			break;
175 		case	NS_LDAP_SCOPE_BASE:
176 			*searchScope = LDAP_SCOPE_BASE;
177 			break;
178 		case	NS_LDAP_SCOPE_SUBTREE:
179 			*searchScope = LDAP_SCOPE_SUBTREE;
180 			break;
181 		default:
182 			(void) snprintf(errmsg, sizeof (errmsg),
183 				gettext("Invalid search scope!"));
184 			MKERROR(LOG_ERR, *errorp, NS_CONFIG_FILE,
185 				strdup(errmsg), NS_LDAP_CONFIG);
186 			return (NS_LDAP_CONFIG);
187 	}
188 
189 	return (NS_LDAP_SUCCESS);
190 }
191 
192 /*
193  * FUNCTION:	__ns_ldap_dupAuth
194  *
195  *	Duplicates an authentication structure.
196  *
197  * RETURN VALUES:	copy of authp or NULL on error
198  * INPUT:		authp
199  */
200 ns_cred_t *
201 __ns_ldap_dupAuth(const ns_cred_t *authp)
202 {
203 	ns_cred_t *ap;
204 
205 #ifdef DEBUG
206 	(void) fprintf(stderr, "__ns_ldap_dupAuth START\n");
207 #endif
208 	if (authp == NULL)
209 		return (NULL);
210 
211 	ap = (ns_cred_t *)calloc(1, sizeof (ns_cred_t));
212 	if (ap == NULL)
213 		return (NULL);
214 
215 	if (authp->hostcertpath) {
216 		ap->hostcertpath = strdup(authp->hostcertpath);
217 		if (ap->hostcertpath == NULL) {
218 			free(ap);
219 			return (NULL);
220 		}
221 	}
222 	if (authp->cred.unix_cred.userID) {
223 		ap->cred.unix_cred.userID =
224 			strdup(authp->cred.unix_cred.userID);
225 		if (ap->cred.unix_cred.userID == NULL) {
226 			(void) __ns_ldap_freeCred(&ap);
227 			return (NULL);
228 		}
229 	}
230 	if (authp->cred.unix_cred.passwd) {
231 		ap->cred.unix_cred.passwd =
232 			strdup(authp->cred.unix_cred.passwd);
233 		if (ap->cred.unix_cred.passwd == NULL) {
234 			(void) __ns_ldap_freeCred(&ap);
235 			return (NULL);
236 		}
237 	}
238 	if (authp->cred.cert_cred.nickname) {
239 		ap->cred.cert_cred.nickname =
240 			strdup(authp->cred.cert_cred.nickname);
241 		if (ap->cred.cert_cred.nickname == NULL) {
242 			(void) __ns_ldap_freeCred(&ap);
243 			return (NULL);
244 		}
245 	}
246 	ap->auth.type = authp->auth.type;
247 	ap->auth.tlstype = authp->auth.tlstype;
248 	ap->auth.saslmech = authp->auth.saslmech;
249 	ap->auth.saslopt = authp->auth.saslopt;
250 	return (ap);
251 }
252 
253 /*
254  * FUNCTION:	__ns_ldap_freeCred
255  *
256  *	Frees all the memory associated with a ns_cred_t structure.
257  *
258  * RETURN VALUES:	NS_LDAP_INVALID_PARAM, NS_LDAP_SUCCESS, NS_LDAP_CONFIG
259  * INPUT:		ns_cred_t
260  */
261 int
262 __ns_ldap_freeCred(ns_cred_t ** credp)
263 {
264 	ns_cred_t *ap;
265 
266 #ifdef DEBUG
267 	(void) fprintf(stderr, "__ns_ldap_freeCred START\n");
268 #endif
269 	if (credp == NULL || *credp == NULL)
270 		return (NS_LDAP_INVALID_PARAM);
271 
272 	ap = *credp;
273 	if (ap->hostcertpath) {
274 		(void) memset(ap->hostcertpath, 0,
275 			strlen(ap->hostcertpath));
276 		free(ap->hostcertpath);
277 	}
278 
279 	if (ap->cred.unix_cred.userID) {
280 		(void) memset(ap->cred.unix_cred.userID, 0,
281 			strlen(ap->cred.unix_cred.userID));
282 		free(ap->cred.unix_cred.userID);
283 	}
284 
285 	if (ap->cred.unix_cred.passwd) {
286 		(void) memset(ap->cred.unix_cred.passwd, 0,
287 			strlen(ap->cred.unix_cred.passwd));
288 		free(ap->cred.unix_cred.passwd);
289 	}
290 
291 	if (ap->cred.cert_cred.nickname) {
292 		(void) memset(ap->cred.cert_cred.nickname, 0,
293 			strlen(ap->cred.cert_cred.nickname));
294 		free(ap->cred.cert_cred.nickname);
295 	}
296 
297 	free(ap);
298 	*credp = NULL;
299 	return (NS_LDAP_SUCCESS);
300 }
301 
302 /*
303  * FUNCTION:	__s_api_getDNs
304  *
305  *	Retrieves the default base dn for the given
306  *	service.
307  *
308  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
309  * INPUT:		service
310  * OUTPUT:		DN, error
311  */
312 int
313 __s_api_getDNs(
314 	char *** DN,
315 	const char *service,
316 	ns_ldap_error_t ** error)
317 {
318 
319 	void	**paramVal = NULL;
320 	char	**dns = NULL;
321 	int	rc = 0;
322 	int	i, len;
323 
324 #ifdef DEBUG
325 	(void) fprintf(stderr, "__s_api_getDNs START\n");
326 #endif
327 	if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
328 	    &paramVal, error)) != NS_LDAP_SUCCESS) {
329 		return (rc);
330 	}
331 	if (!paramVal) {
332 		char errmsg[MAXERROR];
333 
334 		(void) snprintf(errmsg, sizeof (errmsg),
335 			gettext("BaseDN not defined"));
336 		MKERROR(LOG_ERR, *error, NS_CONFIG_FILE, strdup(errmsg),
337 		    NS_LDAP_CONFIG);
338 		return (NS_LDAP_CONFIG);
339 	}
340 
341 	dns = (char **)calloc(2, sizeof (char *));
342 	if (dns == NULL) {
343 		(void) __ns_ldap_freeParam(&paramVal);
344 		return (NS_LDAP_MEMORY);
345 	}
346 
347 	if (service == NULL) {
348 		dns[0] = strdup((char *)*paramVal);
349 		if (dns[0] == NULL) {
350 			(void) __ns_ldap_freeParam(&paramVal);
351 			free(dns);
352 			return (NS_LDAP_MEMORY);
353 		}
354 	} else {
355 		for (i = 0; ns_def_map[i].service != NULL; i++) {
356 			if (strcasecmp(service,
357 				ns_def_map[i].service) == 0) {
358 
359 				len = strlen((char *)*paramVal) +
360 					strlen(ns_def_map[i].rdn) + 1;
361 				dns[0] = (char *)
362 					calloc(len, sizeof (char));
363 				if (dns[0] == NULL) {
364 					(void) __ns_ldap_freeParam(
365 						&paramVal);
366 					free(dns);
367 					return (NS_LDAP_MEMORY);
368 				}
369 				(void) strcpy(dns[0],
370 					ns_def_map[i].rdn);
371 				(void) strcat(dns[0],
372 					(char *)*paramVal);
373 				break;
374 			}
375 		}
376 		if (ns_def_map[i].service == NULL) {
377 			char *p = (char *)*paramVal;
378 			char *buffer = NULL;
379 			int  buflen = 0;
380 
381 			if (strchr(service, '=') == NULL) {
382 			    /* automount entries */
383 			    if (strncasecmp(service, "auto_", 5) == 0) {
384 				buffer = strdup(p);
385 				if (!buffer) {
386 				    free(dns);
387 				    (void) __ns_ldap_freeParam(&paramVal);
388 				    return (NS_LDAP_MEMORY);
389 				}
390 				rc = __s_api_prepend_automountmapname_to_dn(
391 					service, &buffer, error);
392 				if (rc != NS_LDAP_SUCCESS) {
393 				    free(dns);
394 				    free(buffer);
395 				    (void) __ns_ldap_freeParam(&paramVal);
396 				    return (rc);
397 				}
398 			    } else {
399 				/* strlen("nisMapName")+"="+","+'\0' = 13 */
400 				buflen = strlen(service) + strlen(p) + 13;
401 				buffer = (char *)malloc(buflen);
402 				if (buffer == NULL) {
403 					free(dns);
404 					(void) __ns_ldap_freeParam(&paramVal);
405 					return (NS_LDAP_MEMORY);
406 				}
407 				(void) snprintf(buffer, buflen,
408 				    "nisMapName=%s,%s", service, p);
409 			    }
410 			} else {
411 			    buflen = strlen(service) + strlen(p) + 2;
412 			    buffer = (char *)malloc(buflen);
413 			    if (buffer == NULL) {
414 				free(dns);
415 				(void) __ns_ldap_freeParam(&paramVal);
416 				return (NS_LDAP_MEMORY);
417 			    }
418 			    (void) snprintf(buffer, buflen,
419 					"%s,%s", service, p);
420 			}
421 			dns[0] = buffer;
422 		}
423 	}
424 
425 	(void) __ns_ldap_freeParam(&paramVal);
426 	*DN = dns;
427 	return (NS_LDAP_SUCCESS);
428 }
429 /*
430  * FUNCTION:	__s_api_get_search_DNs_v1
431  *
432  *	Retrieves the list of search DNS from the V1 profile for the given
433  *	service.
434  *
435  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_CONFIG
436  * INPUT:		service
437  * OUTPUT:		DN, error
438  */
439 int
440 __s_api_get_search_DNs_v1(
441 	char *** DN,
442 	const char *service,
443 	ns_ldap_error_t ** error)
444 {
445 
446 	void	**paramVal = NULL;
447 	void	**temptr = NULL;
448 	char	**dns = NULL;
449 	int	rc = 0;
450 
451 	if ((rc = __ns_ldap_getParam(NS_LDAP_SEARCH_DN_P,
452 	    &paramVal, error)) != NS_LDAP_SUCCESS) {
453 		return (rc);
454 	}
455 
456 	if (service && paramVal) {
457 		for (temptr = paramVal; *temptr != NULL; temptr++) {
458 			dns = parseDN((const char *)(*temptr),
459 			    (const char *)service);
460 			if (dns != NULL)
461 				break;
462 		}
463 	}
464 
465 	(void) __ns_ldap_freeParam(&paramVal);
466 	*DN = dns;
467 	return (NS_LDAP_SUCCESS);
468 
469 }
470 /*
471  * FUNCTION:	parseDN
472  *
473  *	Parse a special formated list(val) into an array of char *.
474  *
475  * RETURN VALUE:	A char * pointer to the new list of dns.
476  * INPUT:		val, service
477  */
478 static char **
479 parseDN(
480 	const char *val,
481 	const char *service)
482 {
483 
484 	size_t		len = 0;
485 	size_t		slen = 0;
486 	char		**retVal = NULL;
487 	const char	*temptr;
488 	char		*temptr2;
489 	const char	*valend;
490 	int 		valNo = 0;
491 	int		valSize = 0;
492 	int		i;
493 	char		*SSD_service = NULL;
494 
495 #ifdef DEBUG
496 	(void) fprintf(stderr, "parseDN START\n");
497 #endif
498 	if (val == NULL || *val == '\0')
499 		return (NULL);
500 	if (service == NULL || *service == '\0')
501 		return (NULL);
502 
503 	len = strlen(val);
504 	slen = strlen(service);
505 	if (strncasecmp(val, service, slen) != 0) {
506 		/*
507 		 * This routine is only called
508 		 * to process V1 profile and
509 		 * for V1 profile, map service
510 		 * to the corresponding SSD_service
511 		 * which is associated with a
512 		 * real container in the LDAP directory
513 		 * tree, e.g., map "shadow" to
514 		 * "password". See function
515 		 * __s_api_get_SSD_from_SSDtoUse_service
516 		 * for similar service to SSD_service
517 		 * mapping handling for V2 profile.
518 		 */
519 		for (i = 0; ns_def_map[i].service != NULL; i++) {
520 			if (ns_def_map[i].SSDtoUse_service &&
521 				strcasecmp(service,
522 				ns_def_map[i].service) == 0) {
523 				SSD_service =
524 				ns_def_map[i].SSDtoUse_service;
525 				break;
526 			}
527 		}
528 
529 		if (SSD_service == NULL)
530 			return (NULL);
531 
532 		slen = strlen(SSD_service);
533 		if (strncasecmp(val, SSD_service, slen) != 0)
534 			return (NULL);
535 	}
536 
537 	temptr = val + slen;
538 	while (*temptr == SPACETOK || *temptr == TABTOK)
539 		temptr++;
540 	if (*temptr != COLONTOK)
541 		return (NULL);
542 
543 	while (*temptr) {
544 		temptr2 = strchr(temptr, OPARATOK);
545 		if (temptr2 == NULL)
546 			break;
547 		temptr2++;
548 		temptr2 = strchr(temptr2, CPARATOK);
549 		if (temptr2 == NULL)
550 			break;
551 		valNo++;
552 		temptr = temptr2+1;
553 	}
554 
555 	retVal = (char **)calloc(valNo +1, sizeof (char *));
556 	if (retVal == NULL)
557 		return (NULL);
558 
559 	temptr = val;
560 	valend = val+len;
561 
562 	for (i = 0; (i < valNo) && (temptr < valend); i++) {
563 		temptr = strchr(temptr, OPARATOK);
564 		if (temptr == NULL) {
565 			__s_api_free2dArray(retVal);
566 			return (NULL);
567 		}
568 		temptr++;
569 		temptr2 = strchr(temptr, CPARATOK);
570 		if (temptr2 == NULL) {
571 			__s_api_free2dArray(retVal);
572 			return (NULL);
573 		}
574 		valSize = temptr2 - temptr;
575 
576 		retVal[i] = (char *)calloc(valSize + 1, sizeof (char));
577 		if (retVal[i] == NULL) {
578 			__s_api_free2dArray(retVal);
579 			return (NULL);
580 		}
581 		(void) strncpy(retVal[i], temptr, valSize);
582 		retVal[i][valSize] = '\0';
583 		temptr = temptr2 + 1;
584 	}
585 
586 	return (retVal);
587 }
588 
589 
590 /*
591  * __s_api_get_local_interfaces
592  *
593  * Returns a pointer to an array of addresses and netmasks of all interfaces
594  * configured on the system.
595  *
596  * NOTE: This function is very IPv4 centric.
597  */
598 static struct ifinfo *
599 __s_api_get_local_interfaces()
600 {
601 	struct ifconf		ifc;
602 	struct ifreq		ifreq, *ifr;
603 	struct ifinfo		*localinfo;
604 	struct in_addr		netmask;
605 	struct sockaddr_in	*sin;
606 	void			*buf = NULL;
607 	int			fd = 0;
608 	int			numifs = 0;
609 	int			i, n = 0;
610 
611 	if ((fd = open(UDP, O_RDONLY)) < 0)
612 		return ((struct ifinfo *)NULL);
613 
614 	if (ioctl(fd, SIOCGIFNUM, (char *)&numifs) < 0) {
615 		numifs = MAXIFS;
616 	}
617 
618 	buf = malloc(numifs * sizeof (struct ifreq));
619 	if (buf == NULL) {
620 		(void) close(fd);
621 		return ((struct ifinfo *)NULL);
622 	}
623 	ifc.ifc_len = numifs * (int)sizeof (struct ifreq);
624 	ifc.ifc_buf = buf;
625 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) {
626 		(void) close(fd);
627 		free(buf);
628 		buf = NULL;
629 		return ((struct ifinfo *)NULL);
630 	}
631 	ifr = (struct ifreq *)buf;
632 	numifs = ifc.ifc_len/(int)sizeof (struct ifreq);
633 	localinfo = (struct ifinfo *)malloc((numifs + 1) *
634 	    sizeof (struct ifinfo));
635 	if (localinfo == NULL) {
636 		(void) close(fd);
637 		free(buf);
638 		buf = NULL;
639 		return ((struct ifinfo *)NULL);
640 	}
641 
642 	for (i = 0, n = numifs; n > 0; n--, ifr++) {
643 		uint_t ifrflags;
644 
645 		ifreq = *ifr;
646 		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifreq) < 0)
647 			continue;
648 
649 		ifrflags = ifreq.ifr_flags;
650 		if (((ifrflags & IFF_UP) == 0) ||
651 		    (ifr->ifr_addr.sa_family != AF_INET))
652 			continue;
653 
654 		if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifreq) < 0)
655 			continue;
656 		netmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
657 
658 		if (ioctl(fd, SIOCGIFADDR, (char *)&ifreq) < 0)
659 			continue;
660 
661 		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
662 
663 		localinfo[i].addr = sin->sin_addr;
664 		localinfo[i].netmask = netmask;
665 		i++;
666 	}
667 	localinfo[i].addr.s_addr = 0;
668 
669 	free(buf);
670 	buf = NULL;
671 	(void) close(fd);
672 	return (localinfo);
673 }
674 
675 
676 /*
677  * __s_api_samenet(char *, struct ifinfo *)
678  *
679  * Returns 1 if address is on the same subnet of the array of addresses
680  * passed in.
681  *
682  * NOTE: This function is only valid for IPv4 addresses.
683  */
684 static int
685 __s_api_IPv4sameNet(char *addr, struct ifinfo *ifs)
686 {
687 	int		answer = 0;
688 
689 	if (addr && ifs) {
690 		char		*addr_raw;
691 		unsigned long	iaddr;
692 		int		i;
693 
694 		if ((addr_raw = strdup(addr)) != NULL) {
695 			char	*s;
696 
697 			/* Remove port number. */
698 			if ((s = strchr(addr_raw, ':')) != NULL)
699 				*s = '\0';
700 
701 			iaddr = inet_addr(addr_raw);
702 
703 			/* Loop through interface list to find match. */
704 			for (i = 0; ifs[i].addr.s_addr != 0; i++) {
705 				if ((iaddr & ifs[i].netmask.s_addr) ==
706 				    (ifs[i].addr.s_addr &
707 				    ifs[i].netmask.s_addr))
708 					answer++;
709 			}
710 			free(addr_raw);
711 		}
712 	}
713 
714 	return (answer);
715 }
716 
717 /*
718  * FUNCTION:	__s_api_getServers
719  *
720  *	Retrieve a list of ldap servers from the config module.
721  *
722  * RETURN VALUE:	NS_LDAP_SUCCESS, NS_LDAP_CONFIG, NS_LDAP_MEMORY
723  * INPUT:		NONE
724  * OUTPUT:		servers, error
725  */
726 int
727 __s_api_getServers(
728 		char *** servers,
729 		ns_ldap_error_t ** error)
730 {
731 	void	**paramVal = NULL;
732 	char	errmsg[MAXERROR];
733 	char	**sortServers = NULL;
734 	char	**netservers = NULL;
735 	int	rc = 0, err = NS_LDAP_CONFIG, version = 1;
736 	const 	char	*str, *str1;
737 
738 #ifdef DEBUG
739 	(void) fprintf(stderr, "__s_api_getServers START\n");
740 #endif
741 	*servers = NULL;
742 	/* get profile version number */
743 	if ((rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P,
744 			&paramVal, error)) != NS_LDAP_SUCCESS)
745 		return (rc);
746 
747 	if (paramVal == NULL || *paramVal == NULL) {
748 		(void) snprintf(errmsg, sizeof (errmsg),
749 				gettext("No file version"));
750 		MKERROR(LOG_INFO, *error, NS_CONFIG_FILE, strdup(errmsg),
751 			NS_LDAP_CONFIG);
752 		return (NS_LDAP_CONFIG);
753 	}
754 
755 	if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_1) == 0)
756 		version = 1;
757 	else if (strcasecmp((char *)*paramVal, NS_LDAP_VERSION_2) == 0)
758 		version = 2;
759 
760 	(void) __ns_ldap_freeParam(&paramVal);
761 	paramVal = NULL;
762 
763 	if ((rc = __ns_ldap_getParam(NS_LDAP_SERVERS_P,
764 			&paramVal, error)) != NS_LDAP_SUCCESS)
765 		return (rc);
766 
767 	/*
768 	 * For version 2, default server list could be
769 	 * empty.
770 	 */
771 	if ((paramVal == NULL || (char *)*paramVal == NULL) &&
772 		version == 1) {
773 		str = NULL_OR_STR(__s_api_get_configname(NS_LDAP_SERVERS_P));
774 		(void) snprintf(errmsg, sizeof (errmsg),
775 			gettext("Unable to retrieve the '%s' list"), str);
776 		MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE, strdup(errmsg),
777 			NS_LDAP_CONFIG);
778 		return (NS_LDAP_CONFIG);
779 	}
780 
781 	/*
782 	 * Get server address(es) and go through them.
783 	 */
784 	*servers = (char **)paramVal;
785 	paramVal = NULL;
786 
787 	/* Sort servers based on network. */
788 	if (*servers) {
789 		netservers = sortServerNet(*servers);
790 		if (netservers) {
791 			free(*servers);
792 			*servers = netservers;
793 		} else {
794 			return (NS_LDAP_MEMORY);
795 		}
796 	}
797 
798 	/* Get preferred server list and sort servers based on that. */
799 	if ((rc = __ns_ldap_getParam(NS_LDAP_SERVER_PREF_P,
800 			&paramVal, error)) != NS_LDAP_SUCCESS) {
801 		if (*servers)
802 			__s_api_free2dArray(*servers);
803 		*servers = NULL;
804 		return (rc);
805 	}
806 
807 	if (paramVal != NULL) {
808 		char **prefServers;
809 		void **val = NULL;
810 
811 		if ((rc =  __ns_ldap_getParam(NS_LDAP_PREF_ONLY_P,
812 			&val, error)) != NS_LDAP_SUCCESS) {
813 				if (*servers)
814 					__s_api_free2dArray(*servers);
815 				*servers = NULL;
816 			(void) __ns_ldap_freeParam(&paramVal);
817 			return (rc);
818 		}
819 
820 		prefServers = (char **)paramVal;
821 		paramVal = NULL;
822 		if (prefServers) {
823 			if (val != NULL && (*val) != NULL &&
824 					*(int *)val[0] == 1)
825 				sortServers = sortServerPref(*servers,
826 					prefServers, B_FALSE, version,
827 					&err);
828 			else
829 				sortServers = sortServerPref(*servers,
830 					prefServers, B_TRUE, version,
831 					&err);
832 			if (sortServers) {
833 				if (*servers)
834 					free(*servers);
835 				*servers = NULL;
836 				free(prefServers);
837 				prefServers = NULL;
838 				*servers = sortServers;
839 			} else {
840 				if (*servers)
841 					__s_api_free2dArray(*servers);
842 				*servers = NULL;
843 				__s_api_free2dArray(prefServers);
844 				prefServers = NULL;
845 			}
846 		}
847 		(void) __ns_ldap_freeParam(&val);
848 	}
849 	(void) __ns_ldap_freeParam(&paramVal);
850 
851 	if (*servers == NULL) {
852 		if (err == NS_LDAP_CONFIG) {
853 		str = NULL_OR_STR(__s_api_get_configname(
854 				NS_LDAP_SERVERS_P));
855 		str1 = NULL_OR_STR(__s_api_get_configname(
856 				NS_LDAP_SERVER_PREF_P));
857 			(void) snprintf(errmsg, sizeof (errmsg),
858 				gettext("Unable to generate a new server list "
859 				"based on '%s' and/or '%s'"), str, str1);
860 			MKERROR(LOG_WARNING, *error, NS_CONFIG_FILE,
861 				strdup(errmsg), err);
862 			return (err);
863 		}
864 		return (NS_LDAP_MEMORY);
865 	}
866 
867 	return (NS_LDAP_SUCCESS);
868 
869 }
870 
871 /*
872  * FUNCTION:	sortServerNet
873  *	Sort the serverlist based on the distance from client as long
874  *	as the list only contains IPv4 addresses.  Otherwise do nothing.
875  */
876 static char **
877 sortServerNet(char **srvlist)
878 {
879 	int		count = 0;
880 	int		all = 0;
881 	int		ipv4only = 1;
882 	struct ifinfo	*ifs = __s_api_get_local_interfaces();
883 	char		**tsrvs;
884 	char		**psrvs, **retsrvs;
885 
886 	/* Sanity check. */
887 	if (srvlist == NULL || srvlist[0] == NULL)
888 		return (NULL);
889 
890 	/* Count the number of servers to sort. */
891 	for (count = 0; srvlist[count] != NULL; count++) {
892 		if (!__s_api_isipv4(srvlist[count]))
893 			ipv4only = 0;
894 	}
895 	count++;
896 
897 	/* Make room for the returned list of servers. */
898 	retsrvs = (char **)calloc(count, sizeof (char *));
899 	if (retsrvs == NULL) {
900 		free(ifs);
901 		ifs = NULL;
902 		return (NULL);
903 	}
904 
905 	retsrvs[count - 1] = NULL;
906 
907 	/* Make a temporary list of servers. */
908 	psrvs = (char **)calloc(count, sizeof (char *));
909 	if (psrvs == NULL) {
910 		free(ifs);
911 		ifs = NULL;
912 		free(retsrvs);
913 		retsrvs = NULL;
914 		return (NULL);
915 	}
916 
917 	/* Filter servers on the same subnet */
918 	tsrvs = srvlist;
919 	while (*tsrvs) {
920 		if (ipv4only && __s_api_IPv4sameNet(*tsrvs, ifs)) {
921 			psrvs[all] = *tsrvs;
922 			retsrvs[all++] = *(tsrvs);
923 		}
924 		tsrvs++;
925 	}
926 
927 	/* Filter remaining servers. */
928 	tsrvs = srvlist;
929 	while (*tsrvs) {
930 		char	**ttsrvs = psrvs;
931 
932 		while (*ttsrvs) {
933 			if (strcmp(*tsrvs, *ttsrvs) == 0)
934 				break;
935 			ttsrvs++;
936 		}
937 
938 		if (*ttsrvs == NULL)
939 			retsrvs[all++] = *(tsrvs);
940 		tsrvs++;
941 	}
942 
943 	free(ifs);
944 	ifs = NULL;
945 	free(psrvs);
946 	psrvs = NULL;
947 
948 	return (retsrvs);
949 }
950 
951 /*
952  * FUNCTION:	sortServerPref
953  *	Sort the serverlist based on the preferred server list.
954  *
955  * The sorting algorithm works as follows:
956  *
957  * If version 1, if flag is TRUE, find all the servers in both preflist
958  * and srvlist, then append other servers in srvlist to this list
959  * and return the list.
960  * If flag is FALSE, just return srvlist.
961  * srvlist can not be empty.
962  *
963  * If version 2, append all the servers in srvlist
964  * but not in preflist to preflist, and return the merged list.
965  * If srvlist is empty, just return preflist.
966  * If preflist is empty, just return srvlist.
967  */
968 static char **
969 sortServerPref(char **srvlist, char **preflist,
970 		boolean_t flag, int version, int *error)
971 {
972 	int		i, scount = 0, pcount = 0;
973 	int		all = 0, dup = 0;
974 	char		**tsrvs;
975 	char		**retsrvs;
976 	char		**dupsrvs;
977 
978 	/* Count the number of servers to sort. */
979 	if (srvlist && srvlist[0])
980 		for (i = 0; srvlist[i] != NULL; i++)
981 			scount++;
982 
983 	/* Sanity check. */
984 	if (scount == 0 && version == 1) {
985 		*error = NS_LDAP_CONFIG;
986 		return (NULL);
987 	}
988 
989 	/* Count the number of preferred servers */
990 	if (preflist && preflist[0])
991 		for (i = 0; preflist[i] != NULL; i++)
992 			pcount++;
993 
994 	/* Sanity check. */
995 	if (scount == 0 && pcount == 0) {
996 		*error = NS_LDAP_CONFIG;
997 		return (NULL);
998 	}
999 
1000 	/* Make room for the returned list of servers */
1001 	retsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1002 	if (retsrvs == NULL) {
1003 		*error = NS_LDAP_MEMORY;
1004 		return (NULL);
1005 	}
1006 
1007 	/*
1008 	 * if the preferred server list is empty,
1009 	 * just return a copy of the server list
1010 	 */
1011 	if (pcount == 0) {
1012 		tsrvs = srvlist;
1013 		while (*tsrvs)
1014 			retsrvs[all++] = *(tsrvs++);
1015 		return (retsrvs);
1016 	}
1017 	all = 0;
1018 
1019 	/*
1020 	 * if the server list is empty,
1021 	 * just return a copy of the preferred server list
1022 	 */
1023 	if (scount == 0) {
1024 		tsrvs = preflist;
1025 		while (*tsrvs)
1026 			retsrvs[all++] = *(tsrvs++);
1027 		return (retsrvs);
1028 	}
1029 	all = 0;
1030 
1031 	/* Make room for the servers whose memory needs to be freed */
1032 	dupsrvs = (char **)calloc(scount + pcount + 1, sizeof (char *));
1033 	if (dupsrvs == NULL) {
1034 		free(retsrvs);
1035 		*error = NS_LDAP_MEMORY;
1036 		return (NULL);
1037 	}
1038 
1039 	/*
1040 	 * If version 1,
1041 	 * throw out preferred servers not on server list.
1042 	 * If version 2, make a copy of the preferred server list.
1043 	 */
1044 	if (version == 1) {
1045 		tsrvs = preflist;
1046 		while (*tsrvs) {
1047 			char	**ttsrvs = srvlist;
1048 
1049 			while (*ttsrvs) {
1050 				if (strcmp(*tsrvs, *(ttsrvs)) == 0)
1051 					break;
1052 				ttsrvs++;
1053 			}
1054 			if (*ttsrvs != NULL)
1055 				retsrvs[all++] = *tsrvs;
1056 			else
1057 				dupsrvs[dup++] = *tsrvs;
1058 			tsrvs++;
1059 		}
1060 	} else {
1061 		tsrvs = preflist;
1062 		while (*tsrvs)
1063 			retsrvs[all++] = *(tsrvs++);
1064 	}
1065 	/*
1066 	 * If version 1,
1067 	 * if PREF_ONLY is false, we append the non-preferred servers
1068 	 * to bottom of list.
1069 	 * For version 2, always append.
1070 	 */
1071 	if (flag == B_TRUE || version != 1) {
1072 
1073 		tsrvs = srvlist;
1074 		while (*tsrvs) {
1075 			char	**ttsrvs = preflist;
1076 
1077 			while (*ttsrvs) {
1078 				if (strcmp(*tsrvs, *ttsrvs) == 0) {
1079 					break;
1080 				}
1081 				ttsrvs++;
1082 			}
1083 			if (*ttsrvs == NULL)
1084 				retsrvs[all++] = *tsrvs;
1085 			else
1086 				dupsrvs[dup++] = *tsrvs;
1087 			tsrvs++;
1088 		}
1089 	}
1090 
1091 	/* free memory for duplicate servers */
1092 	if (dup) {
1093 		for (tsrvs = dupsrvs; *tsrvs; tsrvs++)
1094 			free(*tsrvs);
1095 	}
1096 	free(dupsrvs);
1097 
1098 	return (retsrvs);
1099 }
1100 
1101 
1102 /*
1103  * FUNCTION:	__s_api_free2dArray
1104  */
1105 void
1106 __s_api_free2dArray(char ** inarray)
1107 {
1108 
1109 	char	**temptr;
1110 
1111 	if (inarray == NULL)
1112 		return;
1113 
1114 	for (temptr = inarray; *temptr != NULL; temptr++) {
1115 		free(*temptr);
1116 	}
1117 	free(inarray);
1118 }
1119 
1120 /*
1121  * FUNCTION:	__s_api_cp2dArray
1122  */
1123 char **
1124 __s_api_cp2dArray(char **inarray)
1125 {
1126 	char	**newarray;
1127 	char	 **ttarray, *ret;
1128 	int	count;
1129 
1130 	if (inarray == NULL)
1131 		return (NULL);
1132 
1133 	for (count = 0; inarray[count] != NULL; count++);
1134 
1135 	newarray = (char **)calloc(count + 1, sizeof (char *));
1136 	if (newarray == NULL)
1137 		return (NULL);
1138 
1139 	ttarray = newarray;
1140 	for (; *inarray; inarray++) {
1141 		*(ttarray++) = ret = strdup(*inarray);
1142 		if (ret == NULL) {
1143 			__s_api_free2dArray(newarray);
1144 			return (NULL);
1145 		}
1146 	}
1147 	return (newarray);
1148 }
1149 
1150 /*
1151  * FUNCTION:	__s_api_isCtrlSupported
1152  *	Determines if the passed control is supported by the LDAP sever.
1153  * RETURNS:	NS_LDAP_SUCCESS if yes, NS_LDAP_OP_FAIL if not.
1154  */
1155 int
1156 __s_api_isCtrlSupported(Connection *con, char *ctrlString)
1157 {
1158 	char		**ctrl;
1159 	int		len;
1160 
1161 	len = strlen(ctrlString);
1162 	for (ctrl = con->controls; ctrl && *ctrl; ctrl++) {
1163 		if (strncasecmp(*ctrl, ctrlString, len) == 0)
1164 			return (NS_LDAP_SUCCESS);
1165 	}
1166 	return (NS_LDAP_OP_FAILED);
1167 }
1168 
1169 /*
1170  * FUNCTION:	__s_api_toFollowReferrals
1171  *	Determines if need to follow referral for an SLDAP API.
1172  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_INVALID_PARAM, or
1173  *			other rc from __ns_ldap_getParam()
1174  * INPUT:		flags
1175  * OUTPUT:		toFollow, errorp
1176  */
1177 int
1178 __s_api_toFollowReferrals(const int flags,
1179 	int *toFollow,
1180 	ns_ldap_error_t **errorp)
1181 {
1182 	void		**paramVal = NULL;
1183 	int		rc = 0;
1184 	int		iflags = 0;
1185 
1186 #ifdef DEBUG
1187 	(void) fprintf(stderr, "__s_api_toFollowReferrals START\n");
1188 #endif
1189 
1190 	/* Either NS_LDAP_NOREF or NS_LDAP_FOLLOWREF not both */
1191 	if ((flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) ==
1192 			(NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1193 		return (NS_LDAP_INVALID_PARAM);
1194 	}
1195 
1196 	/*
1197 	 * if the NS_LDAP_NOREF or NS_LDAP_FOLLOWREF is set
1198 	 * this will take precendence over the values specified
1199 	 * in the configuration file
1200 	 */
1201 	if (flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1202 			iflags = flags;
1203 	} else {
1204 		rc = __ns_ldap_getParam(NS_LDAP_SEARCH_REF_P,
1205 					&paramVal, errorp);
1206 		if (rc != NS_LDAP_SUCCESS)
1207 			return (rc);
1208 		if (paramVal == NULL || *paramVal == NULL) {
1209 			(void) __ns_ldap_freeParam(&paramVal);
1210 			if (*errorp)
1211 				(void) __ns_ldap_freeError(errorp);
1212 			*toFollow = TRUE;
1213 			return (NS_LDAP_SUCCESS);
1214 		}
1215 		iflags = (* (int *)(*paramVal));
1216 		(void) __ns_ldap_freeParam(&paramVal);
1217 	}
1218 
1219 	if (iflags & NS_LDAP_NOREF)
1220 		*toFollow = FALSE;
1221 	else
1222 		*toFollow = TRUE;
1223 
1224 	return (NS_LDAP_SUCCESS);
1225 }
1226 
1227 /*
1228  * FUNCTION:	__s_api_addRefInfo
1229  *	Insert a referral info into a referral info list.
1230  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_OP_FAILED
1231  * INPUT:		LDAP URL, pointer to the referral info list,
1232  *                      search baseDN, search scope, search filter,
1233  *                      previous connection
1234  */
1235 int
1236 __s_api_addRefInfo(ns_referral_info_t **head, char *url,
1237 			char *baseDN, int *scope,
1238 			char *filter, LDAP *ld)
1239 {
1240 	char			errmsg[MAXERROR], *tmp;
1241 	ns_referral_info_t	*ref, *tmpref;
1242 	LDAPURLDesc		*ludp = NULL;
1243 	int			hostlen;
1244 	char *ld_defhost = NULL;
1245 
1246 #ifdef DEBUG
1247 	(void) fprintf(stderr, "__s_api_addRefInfo START\n");
1248 #endif
1249 
1250 	/* sanity check */
1251 	if (head == NULL)
1252 		return (NS_LDAP_OP_FAILED);
1253 
1254 	/*
1255 	 * log error and return NS_LDAP_SUCCESS
1256 	 * if one of the following:
1257 	 * 1. non-LDAP URL
1258 	 * 2. LDAP URL which can not be parsed
1259 	 */
1260 	if (!ldap_is_ldap_url(url) ||
1261 		ldap_url_parse_nodn(url, &ludp) != 0) {
1262 		(void) snprintf(errmsg, MAXERROR, "%s: %s",
1263 			gettext("Invalid or non-LDAP URL when"
1264 				" processing referrals URL"),
1265 			url);
1266 		syslog(LOG_ERR, "libsldap: %s", errmsg);
1267 		if (ludp)
1268 				ldap_free_urldesc(ludp);
1269 		return (NS_LDAP_SUCCESS);
1270 	}
1271 
1272 	ref = (ns_referral_info_t *)calloc(1,
1273 		sizeof (ns_referral_info_t));
1274 	if (ref == NULL) {
1275 		ldap_free_urldesc(ludp);
1276 		return (NS_LDAP_MEMORY);
1277 	}
1278 
1279 	/*
1280 	 * we do have a valid URL and we were able to parse it
1281 	 * however, we still need to find out what hostport to
1282 	 * use if none were provided in the LDAP URL
1283 	 * (e.g., ldap:///...)
1284 	 */
1285 	if ((ludp->lud_port == 0) && (ludp->lud_host == NULL)) {
1286 		if (ld == NULL) {
1287 		    (void) snprintf(errmsg, MAXERROR, "%s: %s",
1288 				gettext("no LDAP handle when"
1289 					" processing referrals URL"),
1290 				url);
1291 			syslog(LOG_WARNING, "libsldap: %s", errmsg);
1292 			ldap_free_urldesc(ludp);
1293 			free(ref);
1294 			return (NS_LDAP_SUCCESS);
1295 		} else {
1296 			(void) ldap_get_option(ld, LDAP_OPT_HOST_NAME,
1297 								&ld_defhost);
1298 			if (ld_defhost == NULL) {
1299 				(void) snprintf(errmsg, MAXERROR, "%s: %s",
1300 					gettext("not able to retrieve default "
1301 						"host when processing "
1302 						"referrals URL"),
1303 					url);
1304 				syslog(LOG_WARNING, "libsldap: %s", errmsg);
1305 				ldap_free_urldesc(ludp);
1306 				free(ref);
1307 				return (NS_LDAP_SUCCESS);
1308 			} else {
1309 				ref->refHost = strdup(ld_defhost);
1310 				if (ref->refHost == NULL) {
1311 					ldap_free_urldesc(ludp);
1312 					free(ref);
1313 					return (NS_LDAP_MEMORY);
1314 				}
1315 			}
1316 		}
1317 	} else {
1318 		/*
1319 		 * add 4 here:
1320 		 * 1 for the last '\0'.
1321 		 * 1 for host and prot separator ":"
1322 		 * and "[" & "]" for possible ipV6 addressing
1323 		 */
1324 		hostlen = strlen(ludp->lud_host) +
1325 			sizeof (MAXPORTNUMBER_STR) + 4;
1326 		ref->refHost = (char *)malloc(hostlen);
1327 		if (ref->refHost == NULL) {
1328 			ldap_free_urldesc(ludp);
1329 			free(ref);
1330 			return (NS_LDAP_MEMORY);
1331 		}
1332 
1333 		if (ludp->lud_port != 0) {
1334 			/*
1335 			 * serverAddr = host:port
1336 			 * or
1337 			 * if host is an IPV6 address
1338 			 * [host]:port
1339 			 */
1340 			tmp = strstr(url, ludp->lud_host);
1341 			if (tmp && (tmp > url) && *(tmp - 1) == '[') {
1342 				(void) snprintf(ref->refHost, hostlen,
1343 					"[%s]:%d",
1344 					ludp->lud_host,
1345 					ludp->lud_port);
1346 			} else {
1347 				(void) snprintf(ref->refHost, hostlen,
1348 					"%s:%d",
1349 					ludp->lud_host,
1350 					ludp->lud_port);
1351 			}
1352 		} else {
1353 			/* serverAddr = host */
1354 			(void) snprintf(ref->refHost, hostlen, "%s",
1355 				ludp->lud_host);
1356 		}
1357 	}
1358 
1359 	if (ludp->lud_dn) {
1360 		ref->refDN = strdup(ludp->lud_dn);
1361 		if (ref->refDN == NULL) {
1362 			ldap_free_urldesc(ludp);
1363 			free(ref->refHost);
1364 			free(ref);
1365 			return (NS_LDAP_MEMORY);
1366 		}
1367 	} else {
1368 		if (baseDN) {
1369 			ref->refDN = strdup(baseDN);
1370 			if (ref->refDN == NULL) {
1371 				ldap_free_urldesc(ludp);
1372 				free(ref->refHost);
1373 				free(ref);
1374 				return (NS_LDAP_MEMORY);
1375 			}
1376 		}
1377 	}
1378 
1379 	if (filter)
1380 		ref->refFilter = strdup(filter);
1381 	else if (ludp->lud_filter)
1382 		ref->refFilter = strdup(ludp->lud_filter);
1383 	else
1384 		ref->refFilter = strdup("");
1385 
1386 	if (ref->refFilter == NULL) {
1387 		ldap_free_urldesc(ludp);
1388 		free(ref->refHost);
1389 		if (ref->refDN)
1390 			free(ref->refDN);
1391 		free(ref);
1392 		return (NS_LDAP_MEMORY);
1393 	}
1394 
1395 	if (scope)
1396 		ref->refScope = *scope;
1397 
1398 	ref->next = NULL;
1399 
1400 	ldap_free_urldesc(ludp);
1401 
1402 	/* insert the referral info */
1403 	if (*head) {
1404 		for (tmpref = *head; tmpref->next;
1405 			tmpref = tmpref->next);
1406 		tmpref->next = ref;
1407 	} else
1408 		*head = ref;
1409 
1410 	return (NS_LDAP_SUCCESS);
1411 }
1412 
1413 /*
1414  * FUNCTION:	__s_api_deleteRefInfo
1415  *	Delete a referral info list.
1416  * INPUT:		pointer to the referral info list
1417  */
1418 void
1419 __s_api_deleteRefInfo(ns_referral_info_t *head)
1420 {
1421 	ns_referral_info_t	*ref, *tmp;
1422 
1423 #ifdef DEBUG
1424 	(void) fprintf(stderr, "__s_api_deleteRefInfo START\n");
1425 #endif
1426 
1427 	for (ref = head; ref; ) {
1428 		if (ref->refHost)
1429 			free(ref->refHost);
1430 		if (ref->refDN)
1431 			free(ref->refDN);
1432 		if (ref->refFilter)
1433 			free(ref->refFilter);
1434 		tmp = ref->next;
1435 		free(ref);
1436 		ref = tmp;
1437 	}
1438 
1439 }
1440 
1441 /*
1442  * FUNCTION:	__s_api_get_SSD_from_SSDtoUse_service
1443  *
1444  *	Retrieves the Service Search Descriptors which should be used for
1445  *	the given service. For example, return all the "passwd" SSDs for
1446  *	service "shadow" if no SSD is defined for service "shadow" and
1447  *	no filter component is defined in all the "passwd" SSDs. This idea
1448  *	of sharing the SSDs defined for some other service is to reduce the
1449  *	configuration complexity. For a service, which does not have its own
1450  *	entries in the LDAP directory, SSD for it is useless, and should not
1451  *	be set. But since this service must share the container with at least
1452  *	one other service which does have it own entries, the SSD for
1453  *	this other service will be shared by this service.
1454  *	This other service is called the SSD-to-use service.
1455  *	The static data structure, ns_def_map[], in this file
1456  *	defines the SSD-to-use service for all the services supported.
1457  *
1458  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_INVALID_PARAM
1459  * INPUT:		service
1460  * OUTPUT:		*SSDlist, *errorp if error
1461  */
1462 int
1463 __s_api_get_SSD_from_SSDtoUse_service(const char *service,
1464 		ns_ldap_search_desc_t ***SSDlist,
1465 		ns_ldap_error_t **errorp)
1466 {
1467 	int 			i, rc;
1468 	int 			found = FALSE;
1469 	int 			filter_found = FALSE;
1470 	char			*SSD_service = NULL;
1471 	char			errmsg[MAXERROR];
1472 	ns_ldap_search_desc_t	**sdlist;
1473 	int			auto_service = FALSE;
1474 
1475 #ifdef DEBUG
1476 	(void) fprintf(stderr,
1477 		"__s_api_get_SSD_from_SSDtoUse_service START\n");
1478 #endif
1479 
1480 	if (SSDlist == NULL || errorp == NULL)
1481 		return (NS_LDAP_INVALID_PARAM);
1482 
1483 	*SSDlist = NULL;
1484 	*errorp = NULL;
1485 
1486 	if (service == NULL)
1487 		return (NS_LDAP_SUCCESS);
1488 
1489 	if (strncasecmp(service, "auto_", 5) == 0)
1490 		auto_service = TRUE;
1491 
1492 	/*
1493 	 * First try to return the configured SSDs for the input server
1494 	 */
1495 	rc = __ns_ldap_getSearchDescriptors(service, SSDlist, errorp);
1496 	if (rc != NS_LDAP_SUCCESS)
1497 		return (rc);
1498 	else {
1499 		if (*SSDlist != NULL)
1500 			return (NS_LDAP_SUCCESS);
1501 	}
1502 
1503 	/*
1504 	 * If service == auto_* and SSD is not found,
1505 	 * then try automount to see if there is an SSD
1506 	 * for automount.
1507 	 */
1508 
1509 	if (auto_service) {
1510 		rc = __ns_ldap_getSearchDescriptors(
1511 			"automount", SSDlist, errorp);
1512 		if (rc != NS_LDAP_SUCCESS)
1513 			return (rc);
1514 		else {
1515 			if (*SSDlist != NULL) {
1516 				/*
1517 				 * If SSDlist is found,
1518 				 * prepend automountMapName to the basedn
1519 				 * in the SSDlist
1520 				 *
1521 				 */
1522 				rc = __s_api_prepend_automountmapname(
1523 					service,
1524 					SSDlist,
1525 					errorp);
1526 
1527 				if (rc != NS_LDAP_SUCCESS) {
1528 				    (void) __ns_ldap_freeSearchDescriptors(
1529 						SSDlist);
1530 				    *SSDlist = NULL;
1531 				}
1532 
1533 				return (rc);
1534 			}
1535 		}
1536 	}
1537 
1538 	/*
1539 	 * Find the SSDtoUse service.
1540 	 * If none found, flag "found" remains FALSE.
1541 	 */
1542 	for (i = 0; ns_def_map[i].service != NULL; i++) {
1543 		if (ns_def_map[i].SSDtoUse_service &&
1544 			strcasecmp(service,
1545 			ns_def_map[i].service) == 0) {
1546 			found = TRUE;
1547 			SSD_service = ns_def_map[i].SSDtoUse_service;
1548 			break;
1549 		}
1550 	}
1551 
1552 	if (!found)
1553 		return (NS_LDAP_SUCCESS);
1554 
1555 	/*
1556 	 * return the SSDs for SSD_service only if no optional filter
1557 	 * component is defined in the SSDs
1558 	 */
1559 	rc = __ns_ldap_getSearchDescriptors(SSD_service,
1560 		SSDlist, errorp);
1561 	if (rc != NS_LDAP_SUCCESS) {
1562 		return (rc);
1563 	} else {
1564 		if (*SSDlist == NULL)
1565 			return (NS_LDAP_SUCCESS);
1566 
1567 		/* check to see if filter defined in SSD */
1568 		for (sdlist = *SSDlist; *sdlist; sdlist++) {
1569 			if ((*sdlist)->filter &&
1570 				strlen((*sdlist)->filter) > 0) {
1571 				filter_found = TRUE;
1572 				break;
1573 			}
1574 		}
1575 		if (filter_found) {
1576 			(void) __ns_ldap_freeSearchDescriptors(SSDlist);
1577 			*SSDlist = NULL;
1578 			(void) snprintf(errmsg, sizeof (errmsg),
1579 				gettext("Service search descriptor for "
1580 					"service '%s' contains filter, "
1581 					"which can not be used for "
1582 					"service '%s'."),
1583 					SSD_service, service);
1584 			MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE,
1585 				strdup(errmsg), NS_LDAP_CONFIG);
1586 			return (NS_LDAP_CONFIG);
1587 		}
1588 
1589 	}
1590 	return (NS_LDAP_SUCCESS);
1591 }
1592 
1593 
1594 /*
1595  * verify addr is an IPv4 address with the optional [:portno]
1596  * RFC2373 & RFC2732 & RFC2396
1597  */
1598 int
1599 __s_api_isipv4(char *addr)
1600 {
1601 	int i, seg, digit, port;
1602 
1603 	if (!addr)
1604 		return (0);
1605 
1606 	digit = seg = port = 0;
1607 
1608 	for (i = 0; i < strlen(addr); i++) {
1609 		if (isdigit(addr[i])) {
1610 			digit++;
1611 			continue;
1612 		}
1613 		if (addr[i] == '.') {
1614 			if (digit > 3 || digit == 0)
1615 				return (0);
1616 			digit = 0;
1617 			seg++;
1618 			continue;
1619 		}
1620 		if (addr[i] == ':') {
1621 			if (digit > 3)
1622 				return (0);
1623 			port++;
1624 			digit = 0;
1625 			seg++;
1626 			continue;
1627 		}
1628 		return (0);
1629 	}
1630 
1631 	if ((seg == 3 && port == 0 && digit > 0 && digit < 4) ||
1632 		(seg == 4 && port == 1 && digit > 0))
1633 		return (1);
1634 
1635 	return (0);
1636 }
1637 
1638 
1639 /*
1640  * verify addr is an IPv6 address with the optional [IPv6]:portno
1641  * RFC2373 & RFC2732 & RFC2396
1642  */
1643 int
1644 __s_api_isipv6(char *addr)
1645 {
1646 	int i, col, digit, port, dc, tc;
1647 	char *laddr, *c1, *s;
1648 
1649 	if (!addr)
1650 		return (0);
1651 
1652 	s = addr;
1653 	laddr = NULL;
1654 	digit = col = port = 0;
1655 	if (addr[0] == '[') {
1656 		laddr = strdup(addr);
1657 		if (!laddr)
1658 			return (0);
1659 		c1 = strchr(laddr, ']');
1660 		/* only 1 ']' should be in an addr */
1661 		if (!c1 || (strchr(c1+1, ']')))
1662 			goto bad;
1663 		switch (c1[1]) {
1664 			case ':':
1665 				port++;
1666 				for (i = 2; i < strlen(c1); i++) {
1667 					if (!isdigit(c1[i]))
1668 						goto bad;
1669 					digit++;
1670 				}
1671 				if (!digit)
1672 					goto bad;
1673 				c1[0] = '\0';
1674 				break;
1675 			case '\0':
1676 				c1[0] = '\0';
1677 				break;
1678 			default:
1679 				goto bad;
1680 		}
1681 		s = &laddr[1];
1682 	}
1683 
1684 	digit = dc = tc = 0;
1685 	for (i = 0; i < strlen(s); i++) {
1686 		if (isxdigit(s[i])) {
1687 			if (digit == 0)
1688 				dc = i;
1689 			digit++;
1690 			col = 0;
1691 			continue;
1692 		}
1693 		if (s[i] == ':') {
1694 			tc++;
1695 			if ((col > 1) || (i && !col && !digit))
1696 				goto bad;
1697 			digit = 0;
1698 			col++;
1699 			continue;
1700 		}
1701 		if (s[i] == '.') {
1702 			if (__s_api_isipv4(&s[dc]) && tc)
1703 				goto good;
1704 			else
1705 				goto bad;
1706 		}
1707 		goto bad;
1708 	}
1709 
1710 good:
1711 	free(laddr);
1712 	return (1);
1713 bad:
1714 	free(laddr);
1715 	return (0);
1716 }
1717 
1718 
1719 /*
1720  * verify addr is a valid hostname with the optional [:portno]
1721  * RFC2373 & RFC2732 & RFC2396
1722  */
1723 int
1724 __s_api_ishost(char *addr)
1725 {
1726 	int i, seg, alpha, digit, port;
1727 
1728 	if (!addr)
1729 		return (0);
1730 
1731 	alpha = digit = seg = port = 0;
1732 
1733 	/* must start with alpha character */
1734 	if (!isalpha(addr[0]))
1735 		return (0);
1736 
1737 	for (i = 0; i < strlen(addr); i++) {
1738 		if (isalpha(addr[i]) || (i && addr[i] == '-')) {
1739 			alpha++;
1740 			continue;
1741 		}
1742 		if (isdigit(addr[i])) {
1743 			digit++;
1744 			continue;
1745 		}
1746 		if (addr[i] == '.') {
1747 			if (!alpha && !digit)
1748 				return (0);
1749 			alpha = digit = 0;
1750 			seg++;
1751 			continue;
1752 		}
1753 		if (addr[i] == ':') {
1754 			if (!alpha && !digit)
1755 				return (0);
1756 			alpha = digit = 0;
1757 			port++;
1758 			seg++;
1759 			continue;
1760 		}
1761 		return (0);
1762 	}
1763 
1764 	if ((port == 0 && (seg || alpha || digit)) ||
1765 		(port == 1 && alpha == 0 && digit))
1766 		return (1);
1767 
1768 	return (0);
1769 }
1770 
1771 
1772 /*
1773  * Prepend automountMapName=auto_xxx to the basedn
1774  * in the SSDlist
1775  */
1776 
1777 int __s_api_prepend_automountmapname(
1778 	const char *service,
1779 	ns_ldap_search_desc_t ***SSDlist,
1780 	ns_ldap_error_t **errorp)
1781 {
1782 	int			i, rc;
1783 	ns_ldap_search_desc_t	** ssdlist = NULL;
1784 
1785 	if (service == NULL || SSDlist == NULL || *SSDlist == NULL)
1786 		return (NS_LDAP_INVALID_PARAM);
1787 
1788 	ssdlist = *SSDlist;
1789 
1790 	for (i = 0; ssdlist[i] != NULL; i++) {
1791 		rc = __s_api_prepend_automountmapname_to_dn(
1792 			service, &ssdlist[i]->basedn, errorp);
1793 
1794 		if (rc != NS_LDAP_SUCCESS)
1795 			return (rc);
1796 	}
1797 
1798 	return (NS_LDAP_SUCCESS);
1799 }
1800 
1801 
1802 /*
1803  * Prepend automountMapName=auto_xxx to the DN
1804  * Construct a string of
1805  * "automountMapName=auto_xxx,dn"
1806  *
1807  * If automountMapName is mapped to some other attribute,
1808  * then use the mapping in the setup.
1809  *
1810  * If a version 1 profile is in use, use nisMapName for
1811  * backward compatibility (i.e. "nisMapName=auto_xxx,dn").
1812  */
1813 
1814 int
1815 __s_api_prepend_automountmapname_to_dn(
1816 	const char *service,
1817 	char **dn,
1818 	ns_ldap_error_t **errorp)
1819 {
1820 	int rc, len_s = 0, len_d = 0, len = 0;
1821 	char *buffer = NULL;
1822 	char *default_automountmapname = "automountMapName";
1823 	char *automountmapname = NULL;
1824 	char **mappedattrs = NULL;
1825 	char errstr[MAXERROR];
1826 	void **paramVal = NULL;
1827 
1828 	if (service == NULL || dn == NULL || *dn == NULL)
1829 		return (NS_LDAP_INVALID_PARAM);
1830 
1831 	rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
1832 	if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
1833 		if (paramVal)
1834 			(void) __ns_ldap_freeParam(&paramVal);
1835 		return (rc);
1836 	}
1837 	if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) {
1838 		automountmapname = strdup("nisMapName");
1839 		(void) __ns_ldap_freeParam(&paramVal);
1840 		if (automountmapname == NULL) {
1841 			return (NS_LDAP_MEMORY);
1842 		}
1843 	} else {
1844 		(void) __ns_ldap_freeParam(&paramVal);
1845 
1846 		/* Find mapped attribute name of auto_xxx first */
1847 		mappedattrs = __ns_ldap_getMappedAttributes(
1848 			service, default_automountmapname);
1849 		/*
1850 		 * if mapped attribute name of auto_xxx is not found,
1851 		 * find the mapped attribute name of automount
1852 		 */
1853 
1854 		if (mappedattrs == NULL)
1855 			mappedattrs = __ns_ldap_getMappedAttributes(
1856 			"automount", default_automountmapname);
1857 
1858 		/*
1859 		 * if mapped attr is not found, use the default automountmapname
1860 		 */
1861 
1862 		if (mappedattrs == NULL) {
1863 			automountmapname = strdup(default_automountmapname);
1864 			if (automountmapname == NULL)
1865 				return (NS_LDAP_MEMORY);
1866 		} else {
1867 			if (mappedattrs[0] != NULL) {
1868 				/*
1869 				 * Copy it from the mapped attr list
1870 				 * Assume it's 1 to 1 mapping
1871 				 * 1 to n does not make sense
1872 				 */
1873 				automountmapname = strdup(mappedattrs[0]);
1874 				__s_api_free2dArray(mappedattrs);
1875 				if (automountmapname == NULL) {
1876 					return (NS_LDAP_MEMORY);
1877 				}
1878 			} else {
1879 
1880 				/*
1881 				 * automountmapname is mapped to an empty string
1882 				 */
1883 
1884 				__s_api_free2dArray(mappedattrs);
1885 
1886 				(void) sprintf(errstr,
1887 					gettext(
1888 					"Attribute automountMapName is "
1889 					"mapped to an empty string.\n"));
1890 
1891 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
1892 					strdup(errstr), NULL);
1893 
1894 				return (NS_LDAP_CONFIG);
1895 			}
1896 		}
1897 	}
1898 
1899 	len_s = strlen(service);
1900 	len_d  = strlen(*dn);
1901 	/* automountMapName + "=" + service + "," + dn + '\0' */
1902 	len = strlen(automountmapname) + 1 + len_s + 1 + len_d + 1;
1903 	buffer = (char *)malloc(len);
1904 	if (buffer == NULL) {
1905 		free(automountmapname);
1906 		return (NS_LDAP_MEMORY);
1907 	}
1908 
1909 	(void) snprintf(buffer, len, "%s=%s,%s",
1910 			automountmapname, service, *dn);
1911 
1912 	buffer[len-1] = '\0';
1913 
1914 	free(automountmapname);
1915 
1916 	/* free the original dn */
1917 	(void) free(*dn);
1918 
1919 	*dn = buffer;
1920 
1921 	return (NS_LDAP_SUCCESS);
1922 }
1923 
1924 /*
1925  * Map the LDAP error code and error message from LDAP server
1926  * to a password status used for password aging/management.
1927  */
1928 ns_ldap_passwd_status_t
1929 __s_api_set_passwd_status(int errnum, char *errmsg)
1930 {
1931 	if (errmsg) {
1932 		if (errnum ==
1933 			LDAP_INVALID_CREDENTIALS) {
1934 			/*
1935 			 * case 1 (Bind):
1936 			 * password expired
1937 			 */
1938 			if (strstr(errmsg,
1939 				NS_PWDERR_EXPIRED))
1940 				return (NS_PASSWD_EXPIRED);
1941 		}
1942 
1943 		if (errnum ==
1944 			LDAP_UNWILLING_TO_PERFORM) {
1945 			/*
1946 			 * case 1.1 (Bind):
1947 			 * password expired
1948 			 */
1949 			if (strstr(errmsg,
1950 				NS_PWDERR_EXPIRED))
1951 				return (NS_PASSWD_EXPIRED);
1952 
1953 			/*
1954 			 * case 2 (Bind):
1955 			 * Account inactivated
1956 			 */
1957 			if (strstr(errmsg,
1958 				NS_PWDERR_ACCT_INACTIVATED))
1959 				return (NS_PASSWD_EXPIRED);
1960 
1961 
1962 			/*
1963 			 * case 3 (Modify passwd):
1964 			 * the user is not allow to change
1965 			 * password; only admin can change it
1966 			 */
1967 			if (strstr(errmsg,
1968 				NS_PWDERR_CHANGE_NOT_ALLOW))
1969 				return (NS_PASSWD_CHANGE_NOT_ALLOWED);
1970 		}
1971 
1972 		if (errnum ==
1973 			LDAP_CONSTRAINT_VIOLATION) {
1974 			/*
1975 			 * case 4 (Bind):
1976 			 * the user account is locked due to
1977 			 * too many login failures.
1978 			 */
1979 			if (strstr(errmsg,
1980 				NS_PWDERR_MAXTRIES))
1981 				return (NS_PASSWD_RETRY_EXCEEDED);
1982 			/*
1983 			 * case 5 (Modify passwd):
1984 			 * syntax error: the new password
1985 			 * has length less than defined
1986 			 * minimum
1987 			 */
1988 			if (strstr(errmsg,
1989 				NS_PWDERR_INVALID_SYNTAX))
1990 				return (NS_PASSWD_TOO_SHORT);
1991 			/*
1992 			 * case 6 (Modify passwd):
1993 			 * trivial password: same valule as
1994 			 * that of attribute cn, sn, or uid ...
1995 			 */
1996 			if (strstr(errmsg,
1997 				NS_PWDERR_TRIVIAL_PASSWD))
1998 				return (NS_PASSWD_INVALID_SYNTAX);
1999 			/*
2000 			 * case 7 (Modify passwd):
2001 			 * re-use one of the old passwords
2002 			 * in history list
2003 			 */
2004 			if (strstr(errmsg,
2005 				NS_PWDERR_IN_HISTORY))
2006 				return (NS_PASSWD_IN_HISTORY);
2007 			/*
2008 			 * case 8 (Modify passwd):
2009 			 * password not allowed to be
2010 			 * changed yet; within minimum
2011 			 * age
2012 			 */
2013 			if (strstr(errmsg,
2014 				NS_PWDERR_WITHIN_MIN_AGE))
2015 				return (NS_PASSWD_WITHIN_MIN_AGE);
2016 		}
2017 
2018 	}
2019 
2020 	return (NS_PASSWD_GOOD);
2021 }
2022 
2023 /*
2024  * Determine if the input OID list contains
2025  * one of the password control OIDs, which are:
2026  * LDAP_CONTROL_PWEXPIRED: 2.16.840.1.113730.3.4.4
2027  * LDAP_CONTROL_PWEXPIRING: 2.16.840.1.113730.3.4.5.
2028  * If yes, return 1, if no, 0.
2029  */
2030 int
2031 __s_api_contain_passwd_control_oid(char **oids)
2032 {
2033 	char **oid;
2034 
2035 	if (oids == NULL)
2036 		return (0);
2037 
2038 	for (oid = oids; *oid; oid++) {
2039 		if (strcmp(*oid, LDAP_CONTROL_PWEXPIRED) == 0 ||
2040 			strcmp(*oid, LDAP_CONTROL_PWEXPIRING) == 0) {
2041 			return (1);
2042 		}
2043 	}
2044 
2045 	return (0);
2046 }
2047 
2048 /*
2049  * Determine if the input OID list contains LDAP V3 password less
2050  * account management control OID, which is:
2051  * NS_LDAP_ACCOUNT_USABLE_CONTROL:1.3.6.1.4.1.42.2.27.9.5.8
2052  * If yes, return 1, if no, 0.
2053  */
2054 int
2055 __s_api_contain_account_usable_control_oid(char **oids)
2056 {
2057 	char **oid;
2058 
2059 	if (oids == NULL)
2060 		return (0);
2061 
2062 	for (oid = oids; *oid; oid++) {
2063 		if (strcmp(*oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) == 0) {
2064 			return (1);
2065 		}
2066 	}
2067 
2068 	return (0);
2069 }
2070 
2071 /*
2072  * For some databases in name switch, the name and aliases are saved
2073  * as "cn". When the "cn" valuse are retrieved, there is no distinction
2074  * which is  the name and which is(are) aliase(s).
2075  * This function is to parse RDN and find the value of the "cn" and
2076  * then find the matching value in "cn" attribute.
2077  * Also see RFC 2307 section 5.6.
2078  *
2079  * Input -
2080  *  entry:	An LDAP entry
2081  *  attrptr:	A attribute which value appears in RDN
2082  *		This should be "cn" for the name switch for now.
2083  *  case_ignore:    0 Case sensitive comparison on the attribute value
2084  *		    1 Case insensitive comparison
2085  *
2086  * Return -
2087  *		The value of an attrbute which is used as canonical name
2088  *		This is read only and the caller should not try to free it.
2089  *		If it's a NULL, it could be either an RDN parsing error
2090  *		or RDN value does not match any existing "cn" values.
2091  *		e.g.
2092  *		dn: cn=xx+ipserviceprotocol=udp,......
2093  *		cn: aa
2094  *		cn: bb
2095  *
2096  * Note:
2097  *  Although the name switch/ldap's  rdn is in "cn=xx" or "cn=xx+..."
2098  * format, this function makes no such assumption. If the DN
2099  * is saved as "dn: yy=...+sn=my_canocical_name, ..", then it can still work.
2100  * The comments use "cn" as an example only.
2101  *
2102  */
2103 typedef int (*cmpfunc)(const char *, const char *);
2104 
2105 char *
2106 __s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr,
2107 			int case_ignore) {
2108 	uint_t			i;
2109 	char			*token, *lasts, *value = NULL;
2110 	char			**rdn = NULL, **attrs = NULL, **values = NULL;
2111 	char			*rdn_attr_value = NULL;
2112 	cmpfunc			cmp;
2113 
2114 	if (entry == NULL || attrptr == NULL)
2115 		return (NULL);
2116 
2117 	/* "values" is read-only */
2118 	if ((values = __ns_ldap_getAttr(entry, "dn")) == NULL ||
2119 				values[0] == NULL)
2120 		return (NULL);
2121 
2122 	if ((rdn = ldap_explode_dn(values[0], 0)) == NULL ||
2123 				rdn[0] == NULL)
2124 		return (NULL);
2125 
2126 	if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) {
2127 		ldap_value_free(rdn);
2128 		return (NULL);
2129 	}
2130 	/* Assume the rdn is normalized */
2131 	for (i = 0; attrs[i] != NULL; i++) {
2132 		/* parse attribute name and value, get attribute name first */
2133 		if ((token = strtok_r(attrs[i], "=", &lasts)) == NULL) {
2134 			goto cleanup;
2135 		}
2136 		if (strcasecmp(token, attrptr->attrname) == 0) {
2137 			/* get value */
2138 			rdn_attr_value = lasts;
2139 			break;
2140 		}
2141 	}
2142 	if (rdn_attr_value) {
2143 		if (case_ignore)
2144 			cmp = strcasecmp;
2145 		else
2146 			cmp = strcmp;
2147 		/*
2148 		 * After parsing RDN and find the matching attribute in RDN,
2149 		 * match rdn value with values in "cn".
2150 		 */
2151 		for (i = 0; i < attrptr->value_count; i++) {
2152 			if (attrptr->attrvalue[i] &&
2153 				(*cmp)(rdn_attr_value,
2154 					attrptr->attrvalue[i]) == 0) {
2155 				/* RDN "cn" value matches the "cn" value */
2156 				value = attrptr->attrvalue[i];
2157 				break;
2158 			}
2159 		}
2160 	}
2161 cleanup:
2162 	ldap_value_free(rdn);
2163 	ldap_value_free(attrs);
2164 
2165 	return (value);
2166 }
2167 
2168 /*
2169  * This function requests a server to be removed from
2170  * the cache manager maintained server list. This is
2171  * done via the door functionality.
2172  * Returns 0 if OK, else a negative value.
2173  */
2174 
2175 int
2176 __s_api_removeServer(const char *server)
2177 {
2178 	union {
2179 		ldap_data_t	s_d;
2180 		char		s_b[DOORBUFFERSIZE];
2181 	} space;
2182 
2183 	ns_server_info_t	r, *ret = &r;
2184 	const char		*ireq;
2185 	ldap_data_t		*sptr;
2186 	int			ndata;
2187 	int			adata;
2188 	int			len;
2189 	int			rc;
2190 
2191 	if (server == NULL)
2192 		return (-1);
2193 
2194 	ireq = NS_CACHE_NORESP;
2195 
2196 	(void) memset(ret, 0, sizeof (ns_server_info_t));
2197 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
2198 
2199 	adata = (sizeof (ldap_call_t) + strlen(ireq) +1);
2200 	adata += strlen(DOORLINESEP) + 1;
2201 	adata += strlen(server) + 1;
2202 
2203 	ndata = sizeof (space);
2204 	space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2205 	len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2206 	(void) strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len);
2207 	(void) strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len);
2208 	(void) strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len);
2209 	sptr = &space.s_d;
2210 
2211 	/* try to remove the server via the door interface */
2212 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2213 
2214 	/* clean up the door call */
2215 	if (sptr != &space.s_d) {
2216 		(void) munmap((char *)sptr, ndata);
2217 	}
2218 
2219 	return (rc);
2220 }
2221