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