xref: /onnv-gate/usr/src/lib/libsldap/common/ns_common.c (revision 1676:37f4a3e2bd99)
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 /*
1104  * FUNCTION:	__s_api_free2dArray
1105  */
1106 void
1107 __s_api_free2dArray(char ** inarray)
1108 {
1109 
1110 	char	**temptr;
1111 
1112 	if (inarray == NULL)
1113 		return;
1114 
1115 	for (temptr = inarray; *temptr != NULL; temptr++) {
1116 		free(*temptr);
1117 	}
1118 	free(inarray);
1119 }
1120 
1121 /*
1122  * FUNCTION:	__s_api_cp2dArray
1123  */
1124 char **
1125 __s_api_cp2dArray(char **inarray)
1126 {
1127 	char	**newarray;
1128 	char	 **ttarray, *ret;
1129 	int	count;
1130 
1131 	if (inarray == NULL)
1132 		return (NULL);
1133 
1134 	for (count = 0; inarray[count] != NULL; count++);
1135 
1136 	newarray = (char **)calloc(count + 1, sizeof (char *));
1137 	if (newarray == NULL)
1138 		return (NULL);
1139 
1140 	ttarray = newarray;
1141 	for (; *inarray; inarray++) {
1142 		*(ttarray++) = ret = strdup(*inarray);
1143 		if (ret == NULL) {
1144 			__s_api_free2dArray(newarray);
1145 			return (NULL);
1146 		}
1147 	}
1148 	return (newarray);
1149 }
1150 
1151 /*
1152  * FUNCTION:	__s_api_isCtrlSupported
1153  *	Determines if the passed control is supported by the LDAP sever.
1154  * RETURNS:	NS_LDAP_SUCCESS if yes, NS_LDAP_OP_FAIL if not.
1155  */
1156 int
1157 __s_api_isCtrlSupported(Connection *con, char *ctrlString)
1158 {
1159 	char		**ctrl;
1160 	int		len;
1161 
1162 	len = strlen(ctrlString);
1163 	for (ctrl = con->controls; ctrl && *ctrl; ctrl++) {
1164 		if (strncasecmp(*ctrl, ctrlString, len) == 0)
1165 			return (NS_LDAP_SUCCESS);
1166 	}
1167 	return (NS_LDAP_OP_FAILED);
1168 }
1169 
1170 /*
1171  * FUNCTION:	__s_api_toFollowReferrals
1172  *	Determines if need to follow referral for an SLDAP API.
1173  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_INVALID_PARAM, or
1174  *			other rc from __ns_ldap_getParam()
1175  * INPUT:		flags
1176  * OUTPUT:		toFollow, errorp
1177  */
1178 int
1179 __s_api_toFollowReferrals(const int flags,
1180 	int *toFollow,
1181 	ns_ldap_error_t **errorp)
1182 {
1183 	void		**paramVal = NULL;
1184 	int		rc = 0;
1185 	int		iflags = 0;
1186 
1187 #ifdef DEBUG
1188 	(void) fprintf(stderr, "__s_api_toFollowReferrals START\n");
1189 #endif
1190 
1191 	/* Either NS_LDAP_NOREF or NS_LDAP_FOLLOWREF not both */
1192 	if ((flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) ==
1193 			(NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1194 		return (NS_LDAP_INVALID_PARAM);
1195 	}
1196 
1197 	/*
1198 	 * if the NS_LDAP_NOREF or NS_LDAP_FOLLOWREF is set
1199 	 * this will take precendence over the values specified
1200 	 * in the configuration file
1201 	 */
1202 	if (flags & (NS_LDAP_NOREF | NS_LDAP_FOLLOWREF)) {
1203 			iflags = flags;
1204 	} else {
1205 		rc = __ns_ldap_getParam(NS_LDAP_SEARCH_REF_P,
1206 					&paramVal, errorp);
1207 		if (rc != NS_LDAP_SUCCESS)
1208 			return (rc);
1209 		if (paramVal == NULL || *paramVal == NULL) {
1210 			(void) __ns_ldap_freeParam(&paramVal);
1211 			if (*errorp)
1212 				(void) __ns_ldap_freeError(errorp);
1213 			*toFollow = TRUE;
1214 			return (NS_LDAP_SUCCESS);
1215 		}
1216 		iflags = (* (int *)(*paramVal));
1217 		(void) __ns_ldap_freeParam(&paramVal);
1218 	}
1219 
1220 	if (iflags & NS_LDAP_NOREF)
1221 		*toFollow = FALSE;
1222 	else
1223 		*toFollow = TRUE;
1224 
1225 	return (NS_LDAP_SUCCESS);
1226 }
1227 
1228 /*
1229  * FUNCTION:	__s_api_addRefInfo
1230  *	Insert a referral info into a referral info list.
1231  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_OP_FAILED
1232  * INPUT:		LDAP URL, pointer to the referral info list,
1233  *                      search baseDN, search scope, search filter,
1234  *                      previous connection
1235  */
1236 int
1237 __s_api_addRefInfo(ns_referral_info_t **head, char *url,
1238 			char *baseDN, int *scope,
1239 			char *filter, LDAP *ld)
1240 {
1241 	char			errmsg[MAXERROR], *tmp;
1242 	ns_referral_info_t	*ref, *tmpref;
1243 	LDAPURLDesc		*ludp = NULL;
1244 	int			hostlen;
1245 	char *ld_defhost = NULL;
1246 
1247 #ifdef DEBUG
1248 	(void) fprintf(stderr, "__s_api_addRefInfo START\n");
1249 #endif
1250 
1251 	/* sanity check */
1252 	if (head == NULL)
1253 		return (NS_LDAP_OP_FAILED);
1254 
1255 	/*
1256 	 * log error and return NS_LDAP_SUCCESS
1257 	 * if one of the following:
1258 	 * 1. non-LDAP URL
1259 	 * 2. LDAP URL which can not be parsed
1260 	 */
1261 	if (!ldap_is_ldap_url(url) ||
1262 		ldap_url_parse_nodn(url, &ludp) != 0) {
1263 		(void) snprintf(errmsg, MAXERROR, "%s: %s",
1264 			gettext("Invalid or non-LDAP URL when"
1265 				" processing referrals URL"),
1266 			url);
1267 		syslog(LOG_ERR, "libsldap: %s", errmsg);
1268 		if (ludp)
1269 				ldap_free_urldesc(ludp);
1270 		return (NS_LDAP_SUCCESS);
1271 	}
1272 
1273 	ref = (ns_referral_info_t *)calloc(1,
1274 		sizeof (ns_referral_info_t));
1275 	if (ref == NULL) {
1276 		ldap_free_urldesc(ludp);
1277 		return (NS_LDAP_MEMORY);
1278 	}
1279 
1280 	/*
1281 	 * we do have a valid URL and we were able to parse it
1282 	 * however, we still need to find out what hostport to
1283 	 * use if none were provided in the LDAP URL
1284 	 * (e.g., ldap:///...)
1285 	 */
1286 	if ((ludp->lud_port == 0) && (ludp->lud_host == NULL)) {
1287 		if (ld == NULL) {
1288 		    (void) snprintf(errmsg, MAXERROR, "%s: %s",
1289 				gettext("no LDAP handle when"
1290 					" processing referrals URL"),
1291 				url);
1292 			syslog(LOG_WARNING, "libsldap: %s", errmsg);
1293 			ldap_free_urldesc(ludp);
1294 			free(ref);
1295 			return (NS_LDAP_SUCCESS);
1296 		} else {
1297 			(void) ldap_get_option(ld, LDAP_OPT_HOST_NAME,
1298 								&ld_defhost);
1299 			if (ld_defhost == NULL) {
1300 				(void) snprintf(errmsg, MAXERROR, "%s: %s",
1301 					gettext("not able to retrieve default "
1302 						"host when processing "
1303 						"referrals URL"),
1304 					url);
1305 				syslog(LOG_WARNING, "libsldap: %s", errmsg);
1306 				ldap_free_urldesc(ludp);
1307 				free(ref);
1308 				return (NS_LDAP_SUCCESS);
1309 			} else {
1310 				ref->refHost = strdup(ld_defhost);
1311 				if (ref->refHost == NULL) {
1312 					ldap_free_urldesc(ludp);
1313 					free(ref);
1314 					return (NS_LDAP_MEMORY);
1315 				}
1316 			}
1317 		}
1318 	} else {
1319 		/*
1320 		 * add 4 here:
1321 		 * 1 for the last '\0'.
1322 		 * 1 for host and prot separator ":"
1323 		 * and "[" & "]" for possible ipV6 addressing
1324 		 */
1325 		hostlen = strlen(ludp->lud_host) +
1326 			sizeof (MAXPORTNUMBER_STR) + 4;
1327 		ref->refHost = (char *)malloc(hostlen);
1328 		if (ref->refHost == NULL) {
1329 			ldap_free_urldesc(ludp);
1330 			free(ref);
1331 			return (NS_LDAP_MEMORY);
1332 		}
1333 
1334 		if (ludp->lud_port != 0) {
1335 			/*
1336 			 * serverAddr = host:port
1337 			 * or
1338 			 * if host is an IPV6 address
1339 			 * [host]:port
1340 			 */
1341 			tmp = strstr(url, ludp->lud_host);
1342 			if (tmp && (tmp > url) && *(tmp - 1) == '[') {
1343 				(void) snprintf(ref->refHost, hostlen,
1344 					"[%s]:%d",
1345 					ludp->lud_host,
1346 					ludp->lud_port);
1347 			} else {
1348 				(void) snprintf(ref->refHost, hostlen,
1349 					"%s:%d",
1350 					ludp->lud_host,
1351 					ludp->lud_port);
1352 			}
1353 		} else {
1354 			/* serverAddr = host */
1355 			(void) snprintf(ref->refHost, hostlen, "%s",
1356 				ludp->lud_host);
1357 		}
1358 	}
1359 
1360 	if (ludp->lud_dn) {
1361 		ref->refDN = strdup(ludp->lud_dn);
1362 		if (ref->refDN == NULL) {
1363 			ldap_free_urldesc(ludp);
1364 			free(ref->refHost);
1365 			free(ref);
1366 			return (NS_LDAP_MEMORY);
1367 		}
1368 	} else {
1369 		if (baseDN) {
1370 			ref->refDN = strdup(baseDN);
1371 			if (ref->refDN == NULL) {
1372 				ldap_free_urldesc(ludp);
1373 				free(ref->refHost);
1374 				free(ref);
1375 				return (NS_LDAP_MEMORY);
1376 			}
1377 		}
1378 	}
1379 
1380 	if (filter)
1381 		ref->refFilter = strdup(filter);
1382 	else if (ludp->lud_filter)
1383 		ref->refFilter = strdup(ludp->lud_filter);
1384 	else
1385 		ref->refFilter = strdup("");
1386 
1387 	if (ref->refFilter == NULL) {
1388 		ldap_free_urldesc(ludp);
1389 		free(ref->refHost);
1390 		if (ref->refDN)
1391 			free(ref->refDN);
1392 		free(ref);
1393 		return (NS_LDAP_MEMORY);
1394 	}
1395 
1396 	if (scope)
1397 		ref->refScope = *scope;
1398 
1399 	ref->next = NULL;
1400 
1401 	ldap_free_urldesc(ludp);
1402 
1403 	/* insert the referral info */
1404 	if (*head) {
1405 		for (tmpref = *head; tmpref->next;
1406 			tmpref = tmpref->next);
1407 		tmpref->next = ref;
1408 	} else
1409 		*head = ref;
1410 
1411 	return (NS_LDAP_SUCCESS);
1412 }
1413 
1414 /*
1415  * FUNCTION:	__s_api_deleteRefInfo
1416  *	Delete a referral info list.
1417  * INPUT:		pointer to the referral info list
1418  */
1419 void
1420 __s_api_deleteRefInfo(ns_referral_info_t *head)
1421 {
1422 	ns_referral_info_t	*ref, *tmp;
1423 
1424 #ifdef DEBUG
1425 	(void) fprintf(stderr, "__s_api_deleteRefInfo START\n");
1426 #endif
1427 
1428 	for (ref = head; ref; ) {
1429 		if (ref->refHost)
1430 			free(ref->refHost);
1431 		if (ref->refDN)
1432 			free(ref->refDN);
1433 		if (ref->refFilter)
1434 			free(ref->refFilter);
1435 		tmp = ref->next;
1436 		free(ref);
1437 		ref = tmp;
1438 	}
1439 
1440 }
1441 
1442 /*
1443  * FUNCTION:	__s_api_get_SSD_from_SSDtoUse_service
1444  *
1445  *	Retrieves the Service Search Descriptors which should be used for
1446  *	the given service. For example, return all the "passwd" SSDs for
1447  *	service "shadow" if no SSD is defined for service "shadow" and
1448  *	no filter component is defined in all the "passwd" SSDs. This idea
1449  *	of sharing the SSDs defined for some other service is to reduce the
1450  *	configuration complexity. For a service, which does not have its own
1451  *	entries in the LDAP directory, SSD for it is useless, and should not
1452  *	be set. But since this service must share the container with at least
1453  *	one other service which does have it own entries, the SSD for
1454  *	this other service will be shared by this service.
1455  *	This other service is called the SSD-to-use service.
1456  *	The static data structure, ns_def_map[], in this file
1457  *	defines the SSD-to-use service for all the services supported.
1458  *
1459  * RETURN VALUES:	NS_LDAP_SUCCESS, NS_LDAP_MEMORY, NS_LDAP_INVALID_PARAM
1460  * INPUT:		service
1461  * OUTPUT:		*SSDlist, *errorp if error
1462  */
1463 int
1464 __s_api_get_SSD_from_SSDtoUse_service(const char *service,
1465 		ns_ldap_search_desc_t ***SSDlist,
1466 		ns_ldap_error_t **errorp)
1467 {
1468 	int 			i, rc;
1469 	int 			found = FALSE;
1470 	int 			filter_found = FALSE;
1471 	char			*SSD_service = NULL;
1472 	char			errmsg[MAXERROR];
1473 	ns_ldap_search_desc_t	**sdlist;
1474 	int			auto_service = FALSE;
1475 
1476 #ifdef DEBUG
1477 	(void) fprintf(stderr,
1478 		"__s_api_get_SSD_from_SSDtoUse_service START\n");
1479 #endif
1480 
1481 	if (SSDlist == NULL || errorp == NULL)
1482 		return (NS_LDAP_INVALID_PARAM);
1483 
1484 	*SSDlist = NULL;
1485 	*errorp = NULL;
1486 
1487 	if (service == NULL)
1488 		return (NS_LDAP_SUCCESS);
1489 
1490 	if (strncasecmp(service, "auto_", 5) == 0)
1491 		auto_service = TRUE;
1492 
1493 	/*
1494 	 * First try to return the configured SSDs for the input server
1495 	 */
1496 	rc = __ns_ldap_getSearchDescriptors(service, SSDlist, errorp);
1497 	if (rc != NS_LDAP_SUCCESS)
1498 		return (rc);
1499 	else {
1500 		if (*SSDlist != NULL)
1501 			return (NS_LDAP_SUCCESS);
1502 	}
1503 
1504 	/*
1505 	 * If service == auto_* and SSD is not found,
1506 	 * then try automount to see if there is an SSD
1507 	 * for automount.
1508 	 */
1509 
1510 	if (auto_service) {
1511 		rc = __ns_ldap_getSearchDescriptors(
1512 			"automount", SSDlist, errorp);
1513 		if (rc != NS_LDAP_SUCCESS)
1514 			return (rc);
1515 		else {
1516 			if (*SSDlist != NULL) {
1517 				/*
1518 				 * If SSDlist is found,
1519 				 * prepend automountMapName to the basedn
1520 				 * in the SSDlist
1521 				 *
1522 				 */
1523 				rc = __s_api_prepend_automountmapname(
1524 					service,
1525 					SSDlist,
1526 					errorp);
1527 
1528 				if (rc != NS_LDAP_SUCCESS) {
1529 				    (void) __ns_ldap_freeSearchDescriptors(
1530 						SSDlist);
1531 				    *SSDlist = NULL;
1532 				}
1533 
1534 				return (rc);
1535 			}
1536 		}
1537 	}
1538 
1539 	/*
1540 	 * Find the SSDtoUse service.
1541 	 * If none found, flag "found" remains FALSE.
1542 	 */
1543 	for (i = 0; ns_def_map[i].service != NULL; i++) {
1544 		if (ns_def_map[i].SSDtoUse_service &&
1545 			strcasecmp(service,
1546 			ns_def_map[i].service) == 0) {
1547 			found = TRUE;
1548 			SSD_service = ns_def_map[i].SSDtoUse_service;
1549 			break;
1550 		}
1551 	}
1552 
1553 	if (!found)
1554 		return (NS_LDAP_SUCCESS);
1555 
1556 	/*
1557 	 * return the SSDs for SSD_service only if no optional filter
1558 	 * component is defined in the SSDs
1559 	 */
1560 	rc = __ns_ldap_getSearchDescriptors(SSD_service,
1561 		SSDlist, errorp);
1562 	if (rc != NS_LDAP_SUCCESS) {
1563 		return (rc);
1564 	} else {
1565 		if (*SSDlist == NULL)
1566 			return (NS_LDAP_SUCCESS);
1567 
1568 		/* check to see if filter defined in SSD */
1569 		for (sdlist = *SSDlist; *sdlist; sdlist++) {
1570 			if ((*sdlist)->filter &&
1571 				strlen((*sdlist)->filter) > 0) {
1572 				filter_found = TRUE;
1573 				break;
1574 			}
1575 		}
1576 		if (filter_found) {
1577 			(void) __ns_ldap_freeSearchDescriptors(SSDlist);
1578 			*SSDlist = NULL;
1579 			(void) snprintf(errmsg, sizeof (errmsg),
1580 				gettext("Service search descriptor for "
1581 					"service '%s' contains filter, "
1582 					"which can not be used for "
1583 					"service '%s'."),
1584 					SSD_service, service);
1585 			MKERROR(LOG_WARNING, *errorp, NS_CONFIG_FILE,
1586 				strdup(errmsg), NS_LDAP_CONFIG);
1587 			return (NS_LDAP_CONFIG);
1588 		}
1589 
1590 	}
1591 	return (NS_LDAP_SUCCESS);
1592 }
1593 
1594 
1595 /*
1596  * verify addr is an IPv4 address with the optional [:portno]
1597  * RFC2373 & RFC2732 & RFC2396
1598  */
1599 int
1600 __s_api_isipv4(char *addr)
1601 {
1602 	int i, seg, digit, port;
1603 
1604 	if (!addr)
1605 		return (0);
1606 
1607 	digit = seg = port = 0;
1608 
1609 	for (i = 0; i < strlen(addr); i++) {
1610 		if (isdigit(addr[i])) {
1611 			digit++;
1612 			continue;
1613 		}
1614 		if (addr[i] == '.') {
1615 			if (digit > 3 || digit == 0)
1616 				return (0);
1617 			digit = 0;
1618 			seg++;
1619 			continue;
1620 		}
1621 		if (addr[i] == ':') {
1622 			if (digit > 3)
1623 				return (0);
1624 			port++;
1625 			digit = 0;
1626 			seg++;
1627 			continue;
1628 		}
1629 		return (0);
1630 	}
1631 
1632 	if ((seg == 3 && port == 0 && digit > 0 && digit < 4) ||
1633 		(seg == 4 && port == 1 && digit > 0))
1634 		return (1);
1635 
1636 	return (0);
1637 }
1638 
1639 
1640 /*
1641  * verify addr is an IPv6 address with the optional [IPv6]:portno
1642  * RFC2373 & RFC2732 & RFC2396
1643  */
1644 int
1645 __s_api_isipv6(char *addr)
1646 {
1647 	int i, col, digit, port, dc, tc;
1648 	char *laddr, *c1, *s;
1649 
1650 	if (!addr)
1651 		return (0);
1652 
1653 	s = addr;
1654 	laddr = NULL;
1655 	digit = col = port = 0;
1656 	if (addr[0] == '[') {
1657 		laddr = strdup(addr);
1658 		if (!laddr)
1659 			return (0);
1660 		c1 = strchr(laddr, ']');
1661 		/* only 1 ']' should be in an addr */
1662 		if (!c1 || (strchr(c1+1, ']')))
1663 			goto bad;
1664 		switch (c1[1]) {
1665 			case ':':
1666 				port++;
1667 				for (i = 2; i < strlen(c1); i++) {
1668 					if (!isdigit(c1[i]))
1669 						goto bad;
1670 					digit++;
1671 				}
1672 				if (!digit)
1673 					goto bad;
1674 				c1[0] = '\0';
1675 				break;
1676 			case '\0':
1677 				c1[0] = '\0';
1678 				break;
1679 			default:
1680 				goto bad;
1681 		}
1682 		s = &laddr[1];
1683 	}
1684 
1685 	digit = dc = tc = 0;
1686 	for (i = 0; i < strlen(s); i++) {
1687 		if (isxdigit(s[i])) {
1688 			if (digit == 0)
1689 				dc = i;
1690 			digit++;
1691 			col = 0;
1692 			continue;
1693 		}
1694 		if (s[i] == ':') {
1695 			tc++;
1696 			if ((col > 1) || (i && !col && !digit))
1697 				goto bad;
1698 			digit = 0;
1699 			col++;
1700 			continue;
1701 		}
1702 		if (s[i] == '.') {
1703 			if (__s_api_isipv4(&s[dc]) && tc)
1704 				goto good;
1705 			else
1706 				goto bad;
1707 		}
1708 		goto bad;
1709 	}
1710 
1711 good:
1712 	free(laddr);
1713 	return (1);
1714 bad:
1715 	free(laddr);
1716 	return (0);
1717 }
1718 
1719 
1720 /*
1721  * verify addr is a valid hostname with the optional [:portno]
1722  * RFC2373 & RFC2732 & RFC2396
1723  */
1724 int
1725 __s_api_ishost(char *addr)
1726 {
1727 	int i, seg, alpha, digit, port;
1728 
1729 	if (!addr)
1730 		return (0);
1731 
1732 	alpha = digit = seg = port = 0;
1733 
1734 	/* must start with alpha character */
1735 	if (!isalpha(addr[0]))
1736 		return (0);
1737 
1738 	for (i = 0; i < strlen(addr); i++) {
1739 		if (isalpha(addr[i]) || (i && addr[i] == '-')) {
1740 			alpha++;
1741 			continue;
1742 		}
1743 		if (isdigit(addr[i])) {
1744 			digit++;
1745 			continue;
1746 		}
1747 		if (addr[i] == '.') {
1748 			if (!alpha && !digit)
1749 				return (0);
1750 			alpha = digit = 0;
1751 			seg++;
1752 			continue;
1753 		}
1754 		if (addr[i] == ':') {
1755 			if (!alpha && !digit)
1756 				return (0);
1757 			alpha = digit = 0;
1758 			port++;
1759 			seg++;
1760 			continue;
1761 		}
1762 		return (0);
1763 	}
1764 
1765 	if ((port == 0 && (seg || alpha || digit)) ||
1766 		(port == 1 && alpha == 0 && digit))
1767 		return (1);
1768 
1769 	return (0);
1770 }
1771 
1772 
1773 /*
1774  * Prepend automountMapName=auto_xxx to the basedn
1775  * in the SSDlist
1776  */
1777 
1778 int __s_api_prepend_automountmapname(
1779 	const char *service,
1780 	ns_ldap_search_desc_t ***SSDlist,
1781 	ns_ldap_error_t **errorp)
1782 {
1783 	int			i, rc;
1784 	ns_ldap_search_desc_t	** ssdlist = NULL;
1785 
1786 	if (service == NULL || SSDlist == NULL || *SSDlist == NULL)
1787 		return (NS_LDAP_INVALID_PARAM);
1788 
1789 	ssdlist = *SSDlist;
1790 
1791 	for (i = 0; ssdlist[i] != NULL; i++) {
1792 		rc = __s_api_prepend_automountmapname_to_dn(
1793 			service, &ssdlist[i]->basedn, errorp);
1794 
1795 		if (rc != NS_LDAP_SUCCESS)
1796 			return (rc);
1797 	}
1798 
1799 	return (NS_LDAP_SUCCESS);
1800 }
1801 
1802 
1803 /*
1804  * Prepend automountMapName=auto_xxx to the DN
1805  * Construct a string of
1806  * "automountMapName=auto_xxx,dn"
1807  *
1808  * If automountMapName is mapped to some other attribute,
1809  * then use the mapping in the setup.
1810  *
1811  * If a version 1 profile is in use, use nisMapName for
1812  * backward compatibility (i.e. "nisMapName=auto_xxx,dn").
1813  */
1814 
1815 int
1816 __s_api_prepend_automountmapname_to_dn(
1817 	const char *service,
1818 	char **dn,
1819 	ns_ldap_error_t **errorp)
1820 {
1821 	int rc, len_s = 0, len_d = 0, len = 0;
1822 	char *buffer = NULL;
1823 	char *default_automountmapname = "automountMapName";
1824 	char *automountmapname = NULL;
1825 	char **mappedattrs = NULL;
1826 	char errstr[MAXERROR];
1827 	void **paramVal = NULL;
1828 
1829 	if (service == NULL || dn == NULL || *dn == NULL)
1830 		return (NS_LDAP_INVALID_PARAM);
1831 
1832 	rc = __ns_ldap_getParam(NS_LDAP_FILE_VERSION_P, &paramVal, errorp);
1833 	if (rc != NS_LDAP_SUCCESS || !paramVal || !*paramVal) {
1834 		if (paramVal)
1835 			(void) __ns_ldap_freeParam(&paramVal);
1836 		return (rc);
1837 	}
1838 	if (strcasecmp(*paramVal, NS_LDAP_VERSION_1) == 0) {
1839 		automountmapname = strdup("nisMapName");
1840 		(void) __ns_ldap_freeParam(&paramVal);
1841 		if (automountmapname == NULL) {
1842 			return (NS_LDAP_MEMORY);
1843 		}
1844 	} else {
1845 		(void) __ns_ldap_freeParam(&paramVal);
1846 
1847 		/* Find mapped attribute name of auto_xxx first */
1848 		mappedattrs = __ns_ldap_getMappedAttributes(
1849 			service, default_automountmapname);
1850 		/*
1851 		 * if mapped attribute name of auto_xxx is not found,
1852 		 * find the mapped attribute name of automount
1853 		 */
1854 
1855 		if (mappedattrs == NULL)
1856 			mappedattrs = __ns_ldap_getMappedAttributes(
1857 			"automount", default_automountmapname);
1858 
1859 		/*
1860 		 * if mapped attr is not found, use the default automountmapname
1861 		 */
1862 
1863 		if (mappedattrs == NULL) {
1864 			automountmapname = strdup(default_automountmapname);
1865 			if (automountmapname == NULL)
1866 				return (NS_LDAP_MEMORY);
1867 		} else {
1868 			if (mappedattrs[0] != NULL) {
1869 				/*
1870 				 * Copy it from the mapped attr list
1871 				 * Assume it's 1 to 1 mapping
1872 				 * 1 to n does not make sense
1873 				 */
1874 				automountmapname = strdup(mappedattrs[0]);
1875 				__s_api_free2dArray(mappedattrs);
1876 				if (automountmapname == NULL) {
1877 					return (NS_LDAP_MEMORY);
1878 				}
1879 			} else {
1880 
1881 				/*
1882 				 * automountmapname is mapped to an empty string
1883 				 */
1884 
1885 				__s_api_free2dArray(mappedattrs);
1886 
1887 				(void) sprintf(errstr,
1888 					gettext(
1889 					"Attribute automountMapName is "
1890 					"mapped to an empty string.\n"));
1891 
1892 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
1893 					strdup(errstr), NULL);
1894 
1895 				return (NS_LDAP_CONFIG);
1896 			}
1897 		}
1898 	}
1899 
1900 	len_s = strlen(service);
1901 	len_d  = strlen(*dn);
1902 	/* automountMapName + "=" + service + "," + dn + '\0' */
1903 	len = strlen(automountmapname) + 1 + len_s + 1 + len_d + 1;
1904 	buffer = (char *)malloc(len);
1905 	if (buffer == NULL) {
1906 		free(automountmapname);
1907 		return (NS_LDAP_MEMORY);
1908 	}
1909 
1910 	(void) snprintf(buffer, len, "%s=%s,%s",
1911 			automountmapname, service, *dn);
1912 
1913 	buffer[len-1] = '\0';
1914 
1915 	free(automountmapname);
1916 
1917 	/* free the original dn */
1918 	(void) free(*dn);
1919 
1920 	*dn = buffer;
1921 
1922 	return (NS_LDAP_SUCCESS);
1923 }
1924 
1925 /*
1926  * Map the LDAP error code and error message from LDAP server
1927  * to a password status used for password aging/management.
1928  */
1929 ns_ldap_passwd_status_t
1930 __s_api_set_passwd_status(int errnum, char *errmsg)
1931 {
1932 	if (errmsg) {
1933 		if (errnum ==
1934 			LDAP_INVALID_CREDENTIALS) {
1935 			/*
1936 			 * case 1 (Bind):
1937 			 * password expired
1938 			 */
1939 			if (strstr(errmsg,
1940 				NS_PWDERR_EXPIRED))
1941 				return (NS_PASSWD_EXPIRED);
1942 		}
1943 
1944 		if (errnum ==
1945 			LDAP_UNWILLING_TO_PERFORM) {
1946 			/*
1947 			 * case 1.1 (Bind):
1948 			 * password expired
1949 			 */
1950 			if (strstr(errmsg,
1951 				NS_PWDERR_EXPIRED))
1952 				return (NS_PASSWD_EXPIRED);
1953 
1954 			/*
1955 			 * case 2 (Bind):
1956 			 * Account inactivated
1957 			 */
1958 			if (strstr(errmsg,
1959 				NS_PWDERR_ACCT_INACTIVATED))
1960 				return (NS_PASSWD_EXPIRED);
1961 
1962 
1963 			/*
1964 			 * case 3 (Modify passwd):
1965 			 * the user is not allow to change
1966 			 * password; only admin can change it
1967 			 */
1968 			if (strstr(errmsg,
1969 				NS_PWDERR_CHANGE_NOT_ALLOW))
1970 				return (NS_PASSWD_CHANGE_NOT_ALLOWED);
1971 		}
1972 
1973 		if (errnum ==
1974 			LDAP_CONSTRAINT_VIOLATION) {
1975 			/*
1976 			 * case 4 (Bind):
1977 			 * the user account is locked due to
1978 			 * too many login failures.
1979 			 */
1980 			if (strstr(errmsg,
1981 				NS_PWDERR_MAXTRIES))
1982 				return (NS_PASSWD_RETRY_EXCEEDED);
1983 			/*
1984 			 * case 5 (Modify passwd):
1985 			 * syntax error: the new password
1986 			 * has length less than defined
1987 			 * minimum
1988 			 */
1989 			if (strstr(errmsg,
1990 				NS_PWDERR_INVALID_SYNTAX))
1991 				return (NS_PASSWD_TOO_SHORT);
1992 			/*
1993 			 * case 6 (Modify passwd):
1994 			 * trivial password: same valule as
1995 			 * that of attribute cn, sn, or uid ...
1996 			 */
1997 			if (strstr(errmsg,
1998 				NS_PWDERR_TRIVIAL_PASSWD))
1999 				return (NS_PASSWD_INVALID_SYNTAX);
2000 			/*
2001 			 * case 7 (Modify passwd):
2002 			 * re-use one of the old passwords
2003 			 * in history list
2004 			 */
2005 			if (strstr(errmsg,
2006 				NS_PWDERR_IN_HISTORY))
2007 				return (NS_PASSWD_IN_HISTORY);
2008 			/*
2009 			 * case 8 (Modify passwd):
2010 			 * password not allowed to be
2011 			 * changed yet; within minimum
2012 			 * age
2013 			 */
2014 			if (strstr(errmsg,
2015 				NS_PWDERR_WITHIN_MIN_AGE))
2016 				return (NS_PASSWD_WITHIN_MIN_AGE);
2017 		}
2018 
2019 	}
2020 
2021 	return (NS_PASSWD_GOOD);
2022 }
2023 
2024 /*
2025  * Determine if the input OID list contains
2026  * one of the password control OIDs, which are:
2027  * LDAP_CONTROL_PWEXPIRED: 2.16.840.1.113730.3.4.4
2028  * LDAP_CONTROL_PWEXPIRING: 2.16.840.1.113730.3.4.5.
2029  * If yes, return 1, if no, 0.
2030  */
2031 int
2032 __s_api_contain_passwd_control_oid(char **oids)
2033 {
2034 	char **oid;
2035 
2036 	if (oids == NULL)
2037 		return (0);
2038 
2039 	for (oid = oids; *oid; oid++) {
2040 		if (strcmp(*oid, LDAP_CONTROL_PWEXPIRED) == 0 ||
2041 			strcmp(*oid, LDAP_CONTROL_PWEXPIRING) == 0) {
2042 			return (1);
2043 		}
2044 	}
2045 
2046 	return (0);
2047 }
2048 
2049 /*
2050  * Determine if the input OID list contains LDAP V3 password less
2051  * account management control OID, which is:
2052  * NS_LDAP_ACCOUNT_USABLE_CONTROL:1.3.6.1.4.1.42.2.27.9.5.8
2053  * If yes, return 1, if no, 0.
2054  */
2055 int
2056 __s_api_contain_account_usable_control_oid(char **oids)
2057 {
2058 	char **oid;
2059 
2060 	if (oids == NULL)
2061 		return (0);
2062 
2063 	for (oid = oids; *oid; oid++) {
2064 		if (strcmp(*oid, NS_LDAP_ACCOUNT_USABLE_CONTROL) == 0) {
2065 			return (1);
2066 		}
2067 	}
2068 
2069 	return (0);
2070 }
2071 
2072 /*
2073  * For some databases in name switch, the name and aliases are saved
2074  * as "cn". When the "cn" valuse are retrieved, there is no distinction
2075  * which is  the name and which is(are) aliase(s).
2076  * This function is to parse RDN and find the value of the "cn" and
2077  * then find the matching value in "cn" attribute.
2078  * Also see RFC 2307 section 5.6.
2079  *
2080  * Input -
2081  *  entry:	An LDAP entry
2082  *  attrptr:	A attribute which value appears in RDN
2083  *		This should be "cn" for the name switch for now.
2084  *  case_ignore:    0 Case sensitive comparison on the attribute value
2085  *		    1 Case insensitive comparison
2086  *
2087  * Return -
2088  *		The value of an attrbute which is used as canonical name
2089  *		This is read only and the caller should not try to free it.
2090  *		If it's a NULL, it could be either an RDN parsing error
2091  *		or RDN value does not match any existing "cn" values.
2092  *		e.g.
2093  *		dn: cn=xx+ipserviceprotocol=udp,......
2094  *		cn: aa
2095  *		cn: bb
2096  *
2097  * Note:
2098  *  Although the name switch/ldap's  rdn is in "cn=xx" or "cn=xx+..."
2099  * format, this function makes no such assumption. If the DN
2100  * is saved as "dn: yy=...+sn=my_canocical_name, ..", then it can still work.
2101  * The comments use "cn" as an example only.
2102  *
2103  */
2104 typedef int (*cmpfunc)(const char *, const char *);
2105 
2106 char *
2107 __s_api_get_canonical_name(ns_ldap_entry_t *entry, ns_ldap_attr_t *attrptr,
2108 			int case_ignore) {
2109 	uint_t			i;
2110 	char			*token, *lasts, *value = NULL;
2111 	char			**rdn = NULL, **attrs = NULL, **values = NULL;
2112 	char			*rdn_attr_value = NULL;
2113 	cmpfunc			cmp;
2114 
2115 	if (entry == NULL || attrptr == NULL)
2116 		return (NULL);
2117 
2118 	/* "values" is read-only */
2119 	if ((values = __ns_ldap_getAttr(entry, "dn")) == NULL ||
2120 				values[0] == NULL)
2121 		return (NULL);
2122 
2123 	if ((rdn = ldap_explode_dn(values[0], 0)) == NULL ||
2124 				rdn[0] == NULL)
2125 		return (NULL);
2126 
2127 	if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) {
2128 		ldap_value_free(rdn);
2129 		return (NULL);
2130 	}
2131 	/* Assume the rdn is normalized */
2132 	for (i = 0; attrs[i] != NULL; i++) {
2133 		/* parse attribute name and value, get attribute name first */
2134 		if ((token = strtok_r(attrs[i], "=", &lasts)) == NULL) {
2135 			goto cleanup;
2136 		}
2137 		if (strcasecmp(token, attrptr->attrname) == 0) {
2138 			/* get value */
2139 			rdn_attr_value = lasts;
2140 			break;
2141 		}
2142 	}
2143 	if (rdn_attr_value) {
2144 		if (case_ignore)
2145 			cmp = strcasecmp;
2146 		else
2147 			cmp = strcmp;
2148 		/*
2149 		 * After parsing RDN and find the matching attribute in RDN,
2150 		 * match rdn value with values in "cn".
2151 		 */
2152 		for (i = 0; i < attrptr->value_count; i++) {
2153 			if (attrptr->attrvalue[i] &&
2154 				(*cmp)(rdn_attr_value,
2155 					attrptr->attrvalue[i]) == 0) {
2156 				/* RDN "cn" value matches the "cn" value */
2157 				value = attrptr->attrvalue[i];
2158 				break;
2159 			}
2160 		}
2161 	}
2162 cleanup:
2163 	ldap_value_free(rdn);
2164 	ldap_value_free(attrs);
2165 
2166 	return (value);
2167 }
2168 
2169 /*
2170  * This function requests a server to be removed from
2171  * the cache manager maintained server list. This is
2172  * done via the door functionality.
2173  * Returns 0 if OK, else a negative value.
2174  */
2175 
2176 int
2177 __s_api_removeServer(const char *server)
2178 {
2179 	union {
2180 		ldap_data_t	s_d;
2181 		char		s_b[DOORBUFFERSIZE];
2182 	} space;
2183 
2184 	ns_server_info_t	r, *ret = &r;
2185 	const char		*ireq;
2186 	ldap_data_t		*sptr;
2187 	int			ndata;
2188 	int			adata;
2189 	int			len;
2190 	int			rc;
2191 
2192 	if (server == NULL)
2193 		return (-1);
2194 
2195 	ireq = NS_CACHE_NORESP;
2196 
2197 	(void) memset(ret, 0, sizeof (ns_server_info_t));
2198 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
2199 
2200 	adata = (sizeof (ldap_call_t) + strlen(ireq) +1);
2201 	adata += strlen(DOORLINESEP) + 1;
2202 	adata += strlen(server) + 1;
2203 
2204 	ndata = sizeof (space);
2205 	space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2206 	len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2207 	(void) strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len);
2208 	(void) strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len);
2209 	(void) strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len);
2210 	sptr = &space.s_d;
2211 
2212 	/* try to remove the server via the door interface */
2213 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2214 
2215 	/* clean up the door call */
2216 	if (sptr != &space.s_d) {
2217 		(void) munmap((char *)sptr, ndata);
2218 	}
2219 
2220 	return (rc);
2221 }
2222