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