ns_common.c revision 2830:5228d1267a01
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
56struct ifinfo {
57	struct in_addr addr, netmask;
58};
59
60static 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
90static char ** parseDN(const char *val, const char *service);
91static char ** sortServerNet(char **srvlist);
92static 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 */
99int
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 */
143int
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 */
201ns_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 */
262int
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 */
313int
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 */
440int
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 */
479static char **
480parseDN(
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 */
599static 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 */
685static 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 */
727int
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 */
877static char **
878sortServerNet(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 */
969static char **
970sortServerPref(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 */
1108void
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 */
1132void
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 */
1150char **
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 */
1182int
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 */
1204int
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 */
1262int
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 */
1445void
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 */
1489int
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 */
1625int
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 */
1670int
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
1737good:
1738	free(laddr);
1739	return (1);
1740bad:
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 */
1750int
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
1804int __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
1841int
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 */
1955ns_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 */
2057int
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 */
2081int
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 */
2130typedef int (*cmpfunc)(const char *, const char *);
2131
2132char *
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	}
2188cleanup:
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
2202int
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) +
2227			strlen(NS_CACHE_ADDR_IP) + 1);
2228	adata += strlen(DOORLINESEP) + 1;
2229	adata += strlen(server) + 1;
2230
2231	ndata = sizeof (space);
2232	space.s_d.ldap_call.ldap_callnumber = GETLDAPSERVER;
2233	len = sizeof (space) - sizeof (space.s_d.ldap_call.ldap_callnumber);
2234	if (strlcpy(space.s_d.ldap_call.ldap_u.domainname, ireq, len) >= len)
2235		return (-1);
2236	if (strlcat(space.s_d.ldap_call.ldap_u.domainname,
2237		NS_CACHE_ADDR_IP, len) >= len)
2238		return (-1);
2239	if (strlcat(space.s_d.ldap_call.ldap_u.domainname, DOORLINESEP, len) >=
2240			len)
2241		return (-1);
2242	if (strlcat(space.s_d.ldap_call.ldap_u.domainname, server, len) >= len)
2243		return (-1);
2244	sptr = &space.s_d;
2245
2246	/* try to remove the server via the door interface */
2247	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
2248
2249	/* clean up the door call */
2250	if (sptr != &space.s_d) {
2251		(void) munmap((char *)sptr, ndata);
2252	}
2253
2254	return (rc);
2255}
2256