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