17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21225376fbSJulian Pullen 
227c478bd9Sstevel@tonic-gate /*
23225376fbSJulian Pullen  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2433f5ff17SMilan Jurik  * Copyright 2012 Milan Jurik. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <libintl.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/stat.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <lber.h>
387c478bd9Sstevel@tonic-gate #include <ldap.h>
397c478bd9Sstevel@tonic-gate #include <syslog.h>
40dd1104fbSMichen Chang #include <stddef.h>
41dd1104fbSMichen Chang #include <sys/mman.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
447c478bd9Sstevel@tonic-gate #include "ns_internal.h"
45e1dd0a2fSth #include "ns_connmgmt.h"
46dd1104fbSMichen Chang #include "ns_cache_door.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /* Additional headers for addTypedEntry Conversion routines */
497c478bd9Sstevel@tonic-gate #include <pwd.h>
50e1dd0a2fSth #include <project.h>
517c478bd9Sstevel@tonic-gate #include <shadow.h>
527c478bd9Sstevel@tonic-gate #include <grp.h>
537c478bd9Sstevel@tonic-gate #include <netinet/in.h>
547c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
557c478bd9Sstevel@tonic-gate #include <netdb.h>
567c478bd9Sstevel@tonic-gate #include <rpc/rpcent.h>
577c478bd9Sstevel@tonic-gate #include <auth_attr.h>
587c478bd9Sstevel@tonic-gate #include <exec_attr.h>
597c478bd9Sstevel@tonic-gate #include <prof_attr.h>
607c478bd9Sstevel@tonic-gate #include <user_attr.h>
617c478bd9Sstevel@tonic-gate #include <bsm/libbsm.h>
6245916cd2Sjpk #include <sys/tsol/tndb.h>
6345916cd2Sjpk #include <tsol/label.h>
647c478bd9Sstevel@tonic-gate 
65dd1104fbSMichen Chang static int send_to_cachemgr(const char *,
66dd1104fbSMichen Chang     ns_ldap_attr_t **, ns_ldap_error_t **);
6750b7bd51SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 
6850b7bd51SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India static int escape_str(char *, char *);
6950b7bd51SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * If the rdn is a mapped attr:
7291b658d3SToomas Soome  *	return NS_LDAP_SUCCESS and a new_dn.
737c478bd9Sstevel@tonic-gate  * If no mapped attr is found in the rdn:
7491b658d3SToomas Soome  *	return NS_LDAP_SUCCESS and *new_dn == NULL
757c478bd9Sstevel@tonic-gate  * For example:
767c478bd9Sstevel@tonic-gate  *  service = abc
777c478bd9Sstevel@tonic-gate  *  dn =  cn=foo,dc=bar,dc=com
787c478bd9Sstevel@tonic-gate  *  attributeMapping: abc:cn=sn
797c478bd9Sstevel@tonic-gate  * Then:
807c478bd9Sstevel@tonic-gate  *  new_dn = sn=foo,dc=bar,dc=com
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate static int
replace_mapped_attr_in_dn(const char * service,const char * dn,char ** new_dn)847c478bd9Sstevel@tonic-gate replace_mapped_attr_in_dn(
857c478bd9Sstevel@tonic-gate 	const char *service, const char *dn, char **new_dn)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	char	**mappedattr;
887c478bd9Sstevel@tonic-gate 	char	**dnArray = NULL;
897c478bd9Sstevel@tonic-gate 	char	*rservice;
907c478bd9Sstevel@tonic-gate 	char	*cur = NULL;
917c478bd9Sstevel@tonic-gate 	int	len = 0, orig_len = 0, mapped_len = 0;
927c478bd9Sstevel@tonic-gate 	int	dn_len = 0;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	*new_dn = NULL;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/*
97da6c28aaSamw 	 * separate dn into individual componets
987c478bd9Sstevel@tonic-gate 	 * e.g.
997c478bd9Sstevel@tonic-gate 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
1007c478bd9Sstevel@tonic-gate 	 */
1017c478bd9Sstevel@tonic-gate 	dnArray = ldap_explode_dn(dn, 0);
1027c478bd9Sstevel@tonic-gate 	if (!dnArray || !*dnArray)
1037c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	cur = strchr(dnArray[0], '=');
1067c478bd9Sstevel@tonic-gate 	if (!cur) {
1077c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
1087c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
1097c478bd9Sstevel@tonic-gate 	}
1107c478bd9Sstevel@tonic-gate 	*cur = '\0';
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/* we only check schema mapping for automount, not for auto_* */
1137c478bd9Sstevel@tonic-gate 	if (strncasecmp(service, NS_LDAP_TYPE_AUTOMOUNT,
1147c478bd9Sstevel@tonic-gate 	    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0)
1157c478bd9Sstevel@tonic-gate 		rservice = "automount";
1167c478bd9Sstevel@tonic-gate 	else
1177c478bd9Sstevel@tonic-gate 		rservice = (char *)service;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	mappedattr = __ns_ldap_getMappedAttributes(rservice, dnArray[0]);
1207c478bd9Sstevel@tonic-gate 	if (!mappedattr || !mappedattr[0]) {
1217c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
1227c478bd9Sstevel@tonic-gate 		if (mappedattr)
1237c478bd9Sstevel@tonic-gate 			__s_api_free2dArray(mappedattr);
1247c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 	orig_len = strlen(dnArray[0]);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	/*
1297c478bd9Sstevel@tonic-gate 	 * The new length is *dn length + (difference between
1307c478bd9Sstevel@tonic-gate 	 * orig attr and mapped attr) + 1 ;
1317c478bd9Sstevel@tonic-gate 	 * e.g.
1327c478bd9Sstevel@tonic-gate 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
1337c478bd9Sstevel@tonic-gate 	 * ==>
1347c478bd9Sstevel@tonic-gate 	 * cn=aa,automountMapName=auto_home,dc=foo,dc=com
1357c478bd9Sstevel@tonic-gate 	 */
1367c478bd9Sstevel@tonic-gate 	mapped_len = strlen(mappedattr[0]);
1377c478bd9Sstevel@tonic-gate 	dn_len = strlen(dn);
1387c478bd9Sstevel@tonic-gate 	len = dn_len - orig_len + mapped_len + 1;
1397c478bd9Sstevel@tonic-gate 	*new_dn = (char *)calloc(1, len);
1407c478bd9Sstevel@tonic-gate 	if (*new_dn == NULL) {
1417c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
1427c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mappedattr);
1437c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	(void) snprintf(*new_dn, len, "%s=%s", mappedattr[0], dn + orig_len +1);
1477c478bd9Sstevel@tonic-gate 	__s_api_free2dArray(dnArray);
1487c478bd9Sstevel@tonic-gate 	__s_api_free2dArray(mappedattr);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * The following function is only used by the
1567c478bd9Sstevel@tonic-gate  * "gecos" 1 to N attribute mapping code. It expects
1577c478bd9Sstevel@tonic-gate  * and handle only one data/length pair.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static int
init_bval_mod(LDAPMod * mod,int mop,char * mtype,char * mvptr,int mvlen)1607c478bd9Sstevel@tonic-gate init_bval_mod(
1617c478bd9Sstevel@tonic-gate 	LDAPMod *mod,
1627c478bd9Sstevel@tonic-gate 	int	mop,
1637c478bd9Sstevel@tonic-gate 	char	*mtype,
1647c478bd9Sstevel@tonic-gate 	char	*mvptr,
16591b658d3SToomas Soome 	int	mvlen)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	struct berval	**bmodval;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* dup attribute name */
1717c478bd9Sstevel@tonic-gate 	mod->mod_type = strdup(mtype);
1727c478bd9Sstevel@tonic-gate 	if (mod->mod_type == NULL)
1737c478bd9Sstevel@tonic-gate 		return (-1);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	/*
1767c478bd9Sstevel@tonic-gate 	 * assume single value,
1777c478bd9Sstevel@tonic-gate 	 * since only one value/length pair passed in
1787c478bd9Sstevel@tonic-gate 	 */
179e1dd0a2fSth 	bmodval = (struct berval **)calloc(2, sizeof (struct berval *));
1807c478bd9Sstevel@tonic-gate 	if (bmodval == NULL) {
1817c478bd9Sstevel@tonic-gate 		free(mod->mod_type);
1827c478bd9Sstevel@tonic-gate 		mod->mod_type = NULL;
1837c478bd9Sstevel@tonic-gate 		return	(-1);
1847c478bd9Sstevel@tonic-gate 	}
185e1dd0a2fSth 	bmodval[0] = (struct berval *)calloc(1, sizeof (struct berval));
1867c478bd9Sstevel@tonic-gate 	if (bmodval[0] == NULL) {
1877c478bd9Sstevel@tonic-gate 		free(mod->mod_type);
1887c478bd9Sstevel@tonic-gate 		mod->mod_type = NULL;
1897c478bd9Sstevel@tonic-gate 		free(bmodval);
1907c478bd9Sstevel@tonic-gate 		return	(-1);
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* set pointer to data */
1947c478bd9Sstevel@tonic-gate 	bmodval[0]->bv_val = mvptr;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/* set length */
1977c478bd9Sstevel@tonic-gate 	bmodval[0]->bv_len = mvlen;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/*
2007c478bd9Sstevel@tonic-gate 	 * turn on the BVALUE bit to indicate
2017c478bd9Sstevel@tonic-gate 	 * that the length of data is supplied
2027c478bd9Sstevel@tonic-gate 	 */
2037c478bd9Sstevel@tonic-gate 	mod->mod_op = mop | LDAP_MOD_BVALUES;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	mod->mod_bvalues = bmodval;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	return	(0);
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static void
freeModList(LDAPMod ** mods)2117c478bd9Sstevel@tonic-gate freeModList(LDAPMod **mods)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	int i, j;
2147c478bd9Sstevel@tonic-gate 	int name_is_oc;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (mods == NULL)
2177c478bd9Sstevel@tonic-gate 		return;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	for (i = 0; mods[i]; i++) {
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		/* free attribute name */
2227c478bd9Sstevel@tonic-gate 		name_is_oc = FALSE;
2237c478bd9Sstevel@tonic-gate 		if (mods[i]->mod_type) {
224e1dd0a2fSth 			if (strcasecmp(mods[i]->mod_type, "objectclass") == 0)
2257c478bd9Sstevel@tonic-gate 				name_is_oc = TRUE;
2267c478bd9Sstevel@tonic-gate 			free(mods[i]->mod_type);
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 		if (mods[i]->mod_bvalues == NULL)
2307c478bd9Sstevel@tonic-gate 			continue;
2317c478bd9Sstevel@tonic-gate 		/*
2327c478bd9Sstevel@tonic-gate 		 * LDAP_MOD_BVALUES is only set by
2337c478bd9Sstevel@tonic-gate 		 * the "gecos" 1 to N attribute mapping
2347c478bd9Sstevel@tonic-gate 		 * code, and the attribute is single valued.
2357c478bd9Sstevel@tonic-gate 		 */
2367c478bd9Sstevel@tonic-gate 		if (mods[i]->mod_op & LDAP_MOD_BVALUES) {
2377c478bd9Sstevel@tonic-gate 			if (mods[i]->mod_bvalues[0])
2387c478bd9Sstevel@tonic-gate 				free(mods[i]->mod_bvalues[0]);
2397c478bd9Sstevel@tonic-gate 		} else {
2407c478bd9Sstevel@tonic-gate 			if (name_is_oc) {
2417c478bd9Sstevel@tonic-gate 				/*
2427c478bd9Sstevel@tonic-gate 				 * only values for the "objectclass"
2437c478bd9Sstevel@tonic-gate 				 * were dupped using strdup.
2447c478bd9Sstevel@tonic-gate 				 * other attribute values were
2457c478bd9Sstevel@tonic-gate 				 * not dupped, but via pointer
2467c478bd9Sstevel@tonic-gate 				 * assignment. So here the
2477c478bd9Sstevel@tonic-gate 				 * values for "objectclass"
2487c478bd9Sstevel@tonic-gate 				 * is freed one by one,
2497c478bd9Sstevel@tonic-gate 				 * but the values for other
2507c478bd9Sstevel@tonic-gate 				 * attributes need not be freed.
2517c478bd9Sstevel@tonic-gate 				 */
2527c478bd9Sstevel@tonic-gate 				for (j = 0; mods[i]->mod_values[j]; j++)
2537c478bd9Sstevel@tonic-gate 					free(mods[i]->mod_values[j]);
2547c478bd9Sstevel@tonic-gate 			}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		free(mods[i]->mod_bvalues);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/* modlist */
2617c478bd9Sstevel@tonic-gate 	free((char *)(mods[0]));
2627c478bd9Sstevel@tonic-gate 	free(mods);
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static LDAPMod **
__s_api_makeModListCount(const char * service,const ns_ldap_attr_t * const * attr,const int mod_op,const int count,const int flags)2667c478bd9Sstevel@tonic-gate __s_api_makeModListCount(
2677c478bd9Sstevel@tonic-gate 	const char *service,
2687c478bd9Sstevel@tonic-gate 	const ns_ldap_attr_t * const *attr,
2697c478bd9Sstevel@tonic-gate 	const int mod_op,
2707c478bd9Sstevel@tonic-gate 	const int count,
2717c478bd9Sstevel@tonic-gate 	const int flags)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	LDAPMod		**mods, *modlist;
2747c478bd9Sstevel@tonic-gate 	char		**modval;
2757c478bd9Sstevel@tonic-gate 	char		**mapping;
2767c478bd9Sstevel@tonic-gate 	int		i;
2777c478bd9Sstevel@tonic-gate 	int		j;
2787c478bd9Sstevel@tonic-gate 	int		k, rc, vlen;
2797c478bd9Sstevel@tonic-gate 	char		*c, *comma1 = NULL, *comma2 = NULL;
2807c478bd9Sstevel@tonic-gate 	int		schema_mapping_existed = FALSE;
2817c478bd9Sstevel@tonic-gate 	int		auto_service = FALSE;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * add 2 for "gecos" 1 to up to 3 attribute mapping
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	mods = (LDAPMod **)calloc((count + 3), sizeof (LDAPMod *));
2887c478bd9Sstevel@tonic-gate 	if (mods == NULL) {
2897c478bd9Sstevel@tonic-gate 		return (NULL);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 	/*
2927c478bd9Sstevel@tonic-gate 	 * add 2 for "gecos" 1 to up to 3 attribute mapping
2937c478bd9Sstevel@tonic-gate 	 */
2947c478bd9Sstevel@tonic-gate 	modlist = (LDAPMod *)calloc(count + 2, sizeof (LDAPMod));
2957c478bd9Sstevel@tonic-gate 	if (modlist == NULL) {
2967c478bd9Sstevel@tonic-gate 		free(mods);
2977c478bd9Sstevel@tonic-gate 		return (NULL);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	if (service != NULL && strncasecmp(service, NS_LDAP_TYPE_AUTOMOUNT,
3017c478bd9Sstevel@tonic-gate 	    sizeof (NS_LDAP_TYPE_AUTOMOUNT) - 1) == 0)
3027c478bd9Sstevel@tonic-gate 		auto_service = TRUE;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * see if schema mapping existed for the given service
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	mapping = __ns_ldap_getOrigAttribute(service,
3087c478bd9Sstevel@tonic-gate 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
3097c478bd9Sstevel@tonic-gate 	if (mapping) {
3107c478bd9Sstevel@tonic-gate 		schema_mapping_existed = TRUE;
3117c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
3127c478bd9Sstevel@tonic-gate 		mapping = NULL;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	for (i = 0, k = 0; k < count && attr[k] != NULL; i++, k++) {
3167c478bd9Sstevel@tonic-gate 		mods[i] = &modlist[i];
3177c478bd9Sstevel@tonic-gate 		mods[i]->mod_op = mod_op;
3187c478bd9Sstevel@tonic-gate 		/*
3197c478bd9Sstevel@tonic-gate 		 * Perform attribute mapping if necessary.
3207c478bd9Sstevel@tonic-gate 		 */
321e1dd0a2fSth 		if (schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0) {
3227c478bd9Sstevel@tonic-gate 			mapping = __ns_ldap_getMappedAttributes(service,
3237c478bd9Sstevel@tonic-gate 			    attr[k]->attrname);
3247c478bd9Sstevel@tonic-gate 		} else
3257c478bd9Sstevel@tonic-gate 			mapping = NULL;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		if (mapping == NULL && auto_service &&
3287c478bd9Sstevel@tonic-gate 		    (flags & NS_LDAP_NOMAP) == 0) {
3297c478bd9Sstevel@tonic-gate 			/*
3307c478bd9Sstevel@tonic-gate 			 * if service == auto_xxx and
3317c478bd9Sstevel@tonic-gate 			 * no mapped attribute is found
3327c478bd9Sstevel@tonic-gate 			 * and NS_LDAP_NOMAP is not set
3337c478bd9Sstevel@tonic-gate 			 * then try automount's mapped attribute
3347c478bd9Sstevel@tonic-gate 			 */
3357c478bd9Sstevel@tonic-gate 			mapping = __ns_ldap_getMappedAttributes("automount",
3367c478bd9Sstevel@tonic-gate 			    attr[k]->attrname);
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 		if (mapping == NULL) {
340e1dd0a2fSth 			mods[i]->mod_type = strdup(attr[k]->attrname);
341e1dd0a2fSth 			if (mods[i]->mod_type == NULL)
342e1dd0a2fSth 				goto free_memory;
3437c478bd9Sstevel@tonic-gate 		} else {
3447c478bd9Sstevel@tonic-gate 			/*
3457c478bd9Sstevel@tonic-gate 			 * 1 to N attribute mapping is only done for "gecos",
3467c478bd9Sstevel@tonic-gate 			 * and only 1 to 3 mapping.
3477c478bd9Sstevel@tonic-gate 			 * nine cases here:
3487c478bd9Sstevel@tonic-gate 			 *
3497c478bd9Sstevel@tonic-gate 			 * A. attrMap=passwd:gecos=a
3507c478bd9Sstevel@tonic-gate 			 *    1. gecos="xx,yy,zz" -> a="xx,yy,zz"
3517c478bd9Sstevel@tonic-gate 			 *    2. gecos="xx,yy" -> a="xx,yy"
3527c478bd9Sstevel@tonic-gate 			 *    3. gecos="xx" -> a="xx"
3537c478bd9Sstevel@tonic-gate 			 *
3547c478bd9Sstevel@tonic-gate 			 * B. attrMap=passwd:gecos=a b
3557c478bd9Sstevel@tonic-gate 			 *    4. gecos="xx,yy,zz" -> a="xx" b="yy,zz"
3567c478bd9Sstevel@tonic-gate 			 *    5. gecos="xx,yy" -> a="xx" b="yy"
3577c478bd9Sstevel@tonic-gate 			 *    6. gecos="xx" -> a="xx"
3587c478bd9Sstevel@tonic-gate 			 *
3597c478bd9Sstevel@tonic-gate 			 * C. attrMap=passwd:gecos=a b c
3607c478bd9Sstevel@tonic-gate 			 *    7. gecos="xx,yy,zz" -> a="xx" b="yy" c="zz"
3617c478bd9Sstevel@tonic-gate 			 *    8. gecos="xx,yy" -> a="xx" b="yy"
3627c478bd9Sstevel@tonic-gate 			 *    9. gecos="xx" -> a="xx"
3637c478bd9Sstevel@tonic-gate 			 *
3647c478bd9Sstevel@tonic-gate 			 * This can be grouped as:
3657c478bd9Sstevel@tonic-gate 			 *
3667c478bd9Sstevel@tonic-gate 			 * c1 cases: 1,2,3,6,9
3677c478bd9Sstevel@tonic-gate 			 *    if ((attrMap=passwd:gecos=a) ||
3687c478bd9Sstevel@tonic-gate 			 *		(no "," in gecos value))
3697c478bd9Sstevel@tonic-gate 			 *	same as other no-mapping attributes,
3707c478bd9Sstevel@tonic-gate 			 *	no special processing needed
3717c478bd9Sstevel@tonic-gate 			 *    else
3727c478bd9Sstevel@tonic-gate 			 *
3737c478bd9Sstevel@tonic-gate 			 * c2 cases: 4,5,8
3747c478bd9Sstevel@tonic-gate 			 *    if ((attrMap=passwd:gecos=a b) ||
3757c478bd9Sstevel@tonic-gate 			 *	(only one "," in gecos value))
3767c478bd9Sstevel@tonic-gate 			 *	a=xx b=yy[,...]
3777c478bd9Sstevel@tonic-gate 			 *    else
3787c478bd9Sstevel@tonic-gate 			 *
3797c478bd9Sstevel@tonic-gate 			 * c3 case: 7
3807c478bd9Sstevel@tonic-gate 			 *    a=xx b=yy c=...
3817c478bd9Sstevel@tonic-gate 			 *
3827c478bd9Sstevel@tonic-gate 			 * notes: in case c2 and c3, ... could still contain ","
3837c478bd9Sstevel@tonic-gate 			 */
384e1dd0a2fSth 			if (strcasecmp(service, "passwd") == 0 &&
385e1dd0a2fSth 			    strcasecmp(attr[k]->attrname, "gecos") == 0 &&
386e1dd0a2fSth 			    mapping[1] && attr[k]->attrvalue[0] &&
387e1dd0a2fSth 			    (comma1 = strchr(attr[k]->attrvalue[0],
388e1dd0a2fSth 			    COMMATOK)) != NULL) {
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 			/* is there a second comma? */
3917c478bd9Sstevel@tonic-gate 			if (*(comma1 + 1) != '\0')
3927c478bd9Sstevel@tonic-gate 				comma2 = strchr(comma1 + 1, COMMATOK);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 			/*
3957c478bd9Sstevel@tonic-gate 			 * Process case c2 or c3.
3967c478bd9Sstevel@tonic-gate 			 * case c2: mapped to two attributes or just
3977c478bd9Sstevel@tonic-gate 			 * one comma
3987c478bd9Sstevel@tonic-gate 			 */
399e1dd0a2fSth 			if (mapping[2] == NULL || comma2 == NULL) {
4007c478bd9Sstevel@tonic-gate 				/* case c2 */
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 				/*
4037c478bd9Sstevel@tonic-gate 				 * int mod structure for the first attribute
4047c478bd9Sstevel@tonic-gate 				 */
4057c478bd9Sstevel@tonic-gate 				vlen = comma1 - attr[k]->attrvalue[0];
4067c478bd9Sstevel@tonic-gate 				c = attr[k]->attrvalue[0];
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 				if (vlen > 0 && c) {
4097c478bd9Sstevel@tonic-gate 					rc = init_bval_mod(mods[i], mod_op,
410e1dd0a2fSth 					    mapping[0], c, vlen);
4117c478bd9Sstevel@tonic-gate 					if (rc != 0)
4127c478bd9Sstevel@tonic-gate 						goto free_memory;
4137c478bd9Sstevel@tonic-gate 				} else {
4147c478bd9Sstevel@tonic-gate 					/* don't leave a hole in mods array */
4157c478bd9Sstevel@tonic-gate 					mods[i] = NULL;
4167c478bd9Sstevel@tonic-gate 					i--;
4177c478bd9Sstevel@tonic-gate 				}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 				/*
4217c478bd9Sstevel@tonic-gate 				 * init mod structure for the 2nd attribute
4227c478bd9Sstevel@tonic-gate 				 */
4237c478bd9Sstevel@tonic-gate 				if (*(comma1 + 1) == '\0') {
4247c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(mapping);
4257c478bd9Sstevel@tonic-gate 					mapping = NULL;
4267c478bd9Sstevel@tonic-gate 					continue;
4277c478bd9Sstevel@tonic-gate 				}
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 				i++;
4307c478bd9Sstevel@tonic-gate 				mods[i] = &modlist[i];
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 				/*
4337c478bd9Sstevel@tonic-gate 				 * get pointer to data.
4347c478bd9Sstevel@tonic-gate 				 * Skip leading spaces.
4357c478bd9Sstevel@tonic-gate 				 */
436e1dd0a2fSth 				for (c = comma1 + 1; *c == SPACETOK; c++) {
437e1dd0a2fSth 					/* empty */
438e1dd0a2fSth 				}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 				/* get data length */
4417c478bd9Sstevel@tonic-gate 				vlen = strlen(attr[k]->attrvalue[0]) -
442e1dd0a2fSth 				    (c - attr[k]->attrvalue[0]);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 				if (vlen > 0 && c) {
4457c478bd9Sstevel@tonic-gate 					rc = init_bval_mod(mods[i], mod_op,
446e1dd0a2fSth 					    mapping[1], c, vlen);
4477c478bd9Sstevel@tonic-gate 					if (rc != 0)
4487c478bd9Sstevel@tonic-gate 						goto free_memory;
4497c478bd9Sstevel@tonic-gate 				} else {
4507c478bd9Sstevel@tonic-gate 					/* don't leave a hole in mods array */
4517c478bd9Sstevel@tonic-gate 					mods[i] = NULL;
4527c478bd9Sstevel@tonic-gate 					i--;
4537c478bd9Sstevel@tonic-gate 				}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 				/* done with the mapping array */
4567c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mapping);
4577c478bd9Sstevel@tonic-gate 				mapping = NULL;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 				continue;
4607c478bd9Sstevel@tonic-gate 			} else {
4617c478bd9Sstevel@tonic-gate 				/* case c3 */
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 				/*
4647c478bd9Sstevel@tonic-gate 				 * int mod structure for the first attribute
4657c478bd9Sstevel@tonic-gate 				 */
4667c478bd9Sstevel@tonic-gate 				vlen = comma1 - attr[k]->attrvalue[0];
4677c478bd9Sstevel@tonic-gate 				c = attr[k]->attrvalue[0];
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 				if (vlen > 0 && c) {
4707c478bd9Sstevel@tonic-gate 					rc = init_bval_mod(mods[i], mod_op,
471e1dd0a2fSth 					    mapping[0], c, vlen);
4727c478bd9Sstevel@tonic-gate 					if (rc != 0)
4737c478bd9Sstevel@tonic-gate 						goto free_memory;
4747c478bd9Sstevel@tonic-gate 				} else {
4757c478bd9Sstevel@tonic-gate 					/* don't leave a hole in mods array */
4767c478bd9Sstevel@tonic-gate 					mods[i] = NULL;
4777c478bd9Sstevel@tonic-gate 					i--;
4787c478bd9Sstevel@tonic-gate 				}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 				/*
4817c478bd9Sstevel@tonic-gate 				 * init mod structure for the 2nd attribute
4827c478bd9Sstevel@tonic-gate 				 */
4837c478bd9Sstevel@tonic-gate 				i++;
4847c478bd9Sstevel@tonic-gate 				mods[i] = &modlist[i];
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 				/*
4877c478bd9Sstevel@tonic-gate 				 * get pointer to data.
4887c478bd9Sstevel@tonic-gate 				 * Skip leading spaces.
4897c478bd9Sstevel@tonic-gate 				 */
490e1dd0a2fSth 				for (c = comma1 + 1; *c == SPACETOK; c++) {
491e1dd0a2fSth 					/* empty */
492e1dd0a2fSth 				};
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 				/* get data length */
4957c478bd9Sstevel@tonic-gate 				vlen = comma2 - c;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 				if (vlen > 0 && c) {
4987c478bd9Sstevel@tonic-gate 					rc = init_bval_mod(mods[i], mod_op,
499e1dd0a2fSth 					    mapping[1], c, vlen);
5007c478bd9Sstevel@tonic-gate 					if (rc != 0)
5017c478bd9Sstevel@tonic-gate 						goto free_memory;
5027c478bd9Sstevel@tonic-gate 				} else {
5037c478bd9Sstevel@tonic-gate 					/* don't leave a hole in mods array */
5047c478bd9Sstevel@tonic-gate 					mods[i] = NULL;
5057c478bd9Sstevel@tonic-gate 					i--;
5067c478bd9Sstevel@tonic-gate 				}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 				/*
5097c478bd9Sstevel@tonic-gate 				 * init mod structure for the 3rd attribute
5107c478bd9Sstevel@tonic-gate 				 */
5117c478bd9Sstevel@tonic-gate 				if (*(comma2 + 1) == '\0') {
5127c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(mapping);
5137c478bd9Sstevel@tonic-gate 					mapping = NULL;
5147c478bd9Sstevel@tonic-gate 					continue;
5157c478bd9Sstevel@tonic-gate 				}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 				i++;
5187c478bd9Sstevel@tonic-gate 				mods[i] = &modlist[i];
5197c478bd9Sstevel@tonic-gate 				/*
5207c478bd9Sstevel@tonic-gate 				 * get pointer to data.
5217c478bd9Sstevel@tonic-gate 				 * Skip leading spaces.
5227c478bd9Sstevel@tonic-gate 				 */
523e1dd0a2fSth 				for (c = comma2 + 1; *c == SPACETOK; c++) {
524e1dd0a2fSth 					/* empty */
525e1dd0a2fSth 				}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 				/* get data length */
5287c478bd9Sstevel@tonic-gate 				vlen = strlen(attr[k]->attrvalue[0]) -
529e1dd0a2fSth 				    (c - attr[k]->attrvalue[0]);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 				if (vlen > 0 && c) {
5327c478bd9Sstevel@tonic-gate 					rc = init_bval_mod(mods[i], mod_op,
533e1dd0a2fSth 					    mapping[2], c, vlen);
5347c478bd9Sstevel@tonic-gate 					if (rc != 0)
5357c478bd9Sstevel@tonic-gate 						goto free_memory;
5367c478bd9Sstevel@tonic-gate 				} else {
5377c478bd9Sstevel@tonic-gate 					/* don't leave a hole in mods array */
5387c478bd9Sstevel@tonic-gate 					mods[i] = NULL;
5397c478bd9Sstevel@tonic-gate 					i--;
5407c478bd9Sstevel@tonic-gate 				}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 				/* done with the mapping array */
5437c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mapping);
5447c478bd9Sstevel@tonic-gate 				mapping = NULL;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 				continue;
547e1dd0a2fSth 				}
5487c478bd9Sstevel@tonic-gate 			}
5497c478bd9Sstevel@tonic-gate 
550e1dd0a2fSth 			/* case c1 */
551e1dd0a2fSth 			mods[i]->mod_type = strdup(mapping[0]);
552e1dd0a2fSth 			if (mods[i]->mod_type == NULL) {
5537c478bd9Sstevel@tonic-gate 				goto free_memory;
554e1dd0a2fSth 			}
555e1dd0a2fSth 			__s_api_free2dArray(mapping);
556e1dd0a2fSth 			mapping = NULL;
5577c478bd9Sstevel@tonic-gate 		}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 		modval = (char **)calloc(attr[k]->value_count+1,
560e1dd0a2fSth 		    sizeof (char *));
5617c478bd9Sstevel@tonic-gate 		if (modval == NULL)
5627c478bd9Sstevel@tonic-gate 			goto free_memory;
5637c478bd9Sstevel@tonic-gate 		/*
5647c478bd9Sstevel@tonic-gate 		 * Perform objectclass mapping.
5657c478bd9Sstevel@tonic-gate 		 * Note that the values for the "objectclass" attribute
5667c478bd9Sstevel@tonic-gate 		 * will be dupped using strdup. Values for other
5677c478bd9Sstevel@tonic-gate 		 * attributes will be referenced via pointer
5687c478bd9Sstevel@tonic-gate 		 * assignments.
5697c478bd9Sstevel@tonic-gate 		 */
5707c478bd9Sstevel@tonic-gate 		if (strcasecmp(mods[i]->mod_type, "objectclass") == 0) {
5717c478bd9Sstevel@tonic-gate 			for (j = 0; j < attr[k]->value_count; j++) {
5727c478bd9Sstevel@tonic-gate 				if (schema_mapping_existed &&
573e1dd0a2fSth 				    (flags & NS_LDAP_NOMAP) == 0)
5747c478bd9Sstevel@tonic-gate 					mapping =
575e1dd0a2fSth 					    __ns_ldap_getMappedObjectClass(
576e1dd0a2fSth 					    service, attr[k]->attrvalue[j]);
5777c478bd9Sstevel@tonic-gate 				else
5787c478bd9Sstevel@tonic-gate 					mapping = NULL;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 				if (mapping == NULL && auto_service &&
581e1dd0a2fSth 				    (flags & NS_LDAP_NOMAP) == 0)
5827c478bd9Sstevel@tonic-gate 					/*
5837c478bd9Sstevel@tonic-gate 					 * if service == auto_xxx and
5847c478bd9Sstevel@tonic-gate 					 * no mapped objectclass is found
5857c478bd9Sstevel@tonic-gate 					 * then try automount
5867c478bd9Sstevel@tonic-gate 					 */
5877c478bd9Sstevel@tonic-gate 					mapping =
588e1dd0a2fSth 					    __ns_ldap_getMappedObjectClass(
589e1dd0a2fSth 					    "automount", attr[k]->attrvalue[j]);
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 				if (mapping && mapping[0]) {
5927c478bd9Sstevel@tonic-gate 					/* assume single mapping */
5937c478bd9Sstevel@tonic-gate 					modval[j] = strdup(mapping[0]);
5947c478bd9Sstevel@tonic-gate 				} else {
5957c478bd9Sstevel@tonic-gate 					modval[j] = strdup(attr[k]->
596e1dd0a2fSth 					    attrvalue[j]);
5977c478bd9Sstevel@tonic-gate 				}
5987c478bd9Sstevel@tonic-gate 				if (modval[j] == NULL)
5997c478bd9Sstevel@tonic-gate 					goto free_memory;
6007c478bd9Sstevel@tonic-gate 			}
6017c478bd9Sstevel@tonic-gate 		} else {
6027c478bd9Sstevel@tonic-gate 			for (j = 0; j < attr[k]->value_count; j++) {
6037c478bd9Sstevel@tonic-gate 				/* ASSIGN NOT COPY */
6047c478bd9Sstevel@tonic-gate 				modval[j] = attr[k]->attrvalue[j];
6057c478bd9Sstevel@tonic-gate 			}
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 		mods[i]->mod_values = modval;
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	return (mods);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate free_memory:
6137c478bd9Sstevel@tonic-gate 	freeModList(mods);
6147c478bd9Sstevel@tonic-gate 	if (mapping)
6157c478bd9Sstevel@tonic-gate 	__s_api_free2dArray(mapping);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	return (NULL);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate static LDAPMod **
__s_api_makeModList(const char * service,const ns_ldap_attr_t * const * attr,const int mod_op,const int flags)6227c478bd9Sstevel@tonic-gate __s_api_makeModList(
6237c478bd9Sstevel@tonic-gate 	const char *service,
6247c478bd9Sstevel@tonic-gate 	const ns_ldap_attr_t * const *attr,
6257c478bd9Sstevel@tonic-gate 	const int mod_op,
6267c478bd9Sstevel@tonic-gate 	const int flags)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	ns_ldap_attr_t	**aptr = (ns_ldap_attr_t **)attr;
6297c478bd9Sstevel@tonic-gate 	int		count = 0;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (aptr == NULL)
6327c478bd9Sstevel@tonic-gate 		return (NULL);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	/* count number of attributes */
6357c478bd9Sstevel@tonic-gate 	while (*aptr++)
6367c478bd9Sstevel@tonic-gate 		count++;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	return (__s_api_makeModListCount(service, attr, mod_op, count, flags));
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate static void
__s_cvt_freeEntryRdn(ns_ldap_entry_t ** entry,char ** rdn)6427c478bd9Sstevel@tonic-gate __s_cvt_freeEntryRdn(ns_ldap_entry_t **entry, char **rdn)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	if (*entry != NULL) {
6457c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(*entry);
6467c478bd9Sstevel@tonic-gate 		*entry = NULL;
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 	if (*rdn != NULL) {
6497c478bd9Sstevel@tonic-gate 		free(*rdn);
6507c478bd9Sstevel@tonic-gate 		*rdn = NULL;
6517c478bd9Sstevel@tonic-gate 	}
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * This state machine performs one or more LDAP add/delete/modify
6567c478bd9Sstevel@tonic-gate  * operations to configured LDAP servers.
6577c478bd9Sstevel@tonic-gate  */
6587c478bd9Sstevel@tonic-gate static int
write_state_machine(int ldap_op,char * dn,LDAPMod ** mods,const ns_cred_t * cred,const int flags,ns_ldap_error_t ** errorp)6597c478bd9Sstevel@tonic-gate write_state_machine(
66091b658d3SToomas Soome 	int		ldap_op,
66191b658d3SToomas Soome 	char		*dn,
6627c478bd9Sstevel@tonic-gate 	LDAPMod		**mods,
6637c478bd9Sstevel@tonic-gate 	const ns_cred_t *cred,
66491b658d3SToomas Soome 	const int	flags,
6657c478bd9Sstevel@tonic-gate 	ns_ldap_error_t ** errorp)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	ConnectionID    connectionId = -1;
6687c478bd9Sstevel@tonic-gate 	Connection	*conp = NULL;
66991b658d3SToomas Soome 	LDAPMessage	*res;
6707c478bd9Sstevel@tonic-gate 	char		*target_dn = NULL;
6717c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
6727c478bd9Sstevel@tonic-gate 	int		rc = NS_LDAP_SUCCESS;
6737c478bd9Sstevel@tonic-gate 	int		return_rc = NS_LDAP_SUCCESS;
6747c478bd9Sstevel@tonic-gate 	int		followRef = FALSE;
6757c478bd9Sstevel@tonic-gate 	int		target_dn_allocated = FALSE;
6767c478bd9Sstevel@tonic-gate 	int		len;
6777c478bd9Sstevel@tonic-gate 	int		msgid;
6787c478bd9Sstevel@tonic-gate 	int		Errno;
67920945219SMichen Chang 	boolean_t	from_get_lderrno = B_FALSE;
6807c478bd9Sstevel@tonic-gate 	int		always = 1;
6817c478bd9Sstevel@tonic-gate 	char		*err, *errmsg = NULL;
6827d575517Ssdussud 	/* referrals returned by the LDAP operation */
6837c478bd9Sstevel@tonic-gate 	char		**referrals = NULL;
6847d575517Ssdussud 	/*
6857d575517Ssdussud 	 * list of referrals used by the state machine, built from
6867d575517Ssdussud 	 * the referrals variable above
6877d575517Ssdussud 	 */
6887d575517Ssdussud 	ns_referral_info_t *ref_list = NULL;
6897d575517Ssdussud 	/* current referral */
6907d575517Ssdussud 	ns_referral_info_t *current_ref = NULL;
6917c478bd9Sstevel@tonic-gate 	ns_write_state_t state = W_INIT, new_state, err_state = W_INIT;
6927c478bd9Sstevel@tonic-gate 	int		do_not_fail_if_new_pwd_reqd = 0;
6937c478bd9Sstevel@tonic-gate 	ns_ldap_passwd_status_t	pwd_status = NS_PASSWD_GOOD;
6947c478bd9Sstevel@tonic-gate 	int		passwd_mgmt = 0;
6957d575517Ssdussud 	int		i = 0;
6967d575517Ssdussud 	int		ldap_error;
69747789246Svv 	int		nopasswd_acct_mgmt = 0;
698e1dd0a2fSth 	ns_conn_user_t	*conn_user = NULL;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	while (always) {
7017c478bd9Sstevel@tonic-gate 		switch (state) {
7027c478bd9Sstevel@tonic-gate 		case W_EXIT:
703e1dd0a2fSth 			/* return the MT connection and free the conn user */
704e1dd0a2fSth 			if (conn_user != NULL) {
705e1dd0a2fSth 				if (conn_user->use_mt_conn == B_TRUE) {
706e1dd0a2fSth 					if (conn_user->ns_error != NULL) {
707e1dd0a2fSth 						*errorp = conn_user->ns_error;
708e1dd0a2fSth 						conn_user->ns_error = NULL;
709e1dd0a2fSth 						return_rc = conn_user->ns_rc;
710e1dd0a2fSth 					}
711e1dd0a2fSth 					if (conn_user->conn_mt != NULL)
712e1dd0a2fSth 						__s_api_conn_mt_return(
713e1dd0a2fSth 						    conn_user);
714e1dd0a2fSth 				}
715e1dd0a2fSth 				__s_api_conn_user_free(conn_user);
716e1dd0a2fSth 			}
717e1dd0a2fSth 
7187c478bd9Sstevel@tonic-gate 			if (connectionId > -1)
719cb5caa98Sdjl 				DropConnection(connectionId, NS_LDAP_NEW_CONN);
7207d575517Ssdussud 			if (ref_list)
7217d575517Ssdussud 				__s_api_deleteRefInfo(ref_list);
7227c478bd9Sstevel@tonic-gate 			if (target_dn && target_dn_allocated)
7237c478bd9Sstevel@tonic-gate 				free(target_dn);
7247c478bd9Sstevel@tonic-gate 			return (return_rc);
7257c478bd9Sstevel@tonic-gate 		case W_INIT:
7267c478bd9Sstevel@tonic-gate 			/* see if need to follow referrals */
7277c478bd9Sstevel@tonic-gate 			rc = __s_api_toFollowReferrals(flags,
728e1dd0a2fSth 			    &followRef, errorp);
7297c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
7307c478bd9Sstevel@tonic-gate 				return_rc = rc;
7317c478bd9Sstevel@tonic-gate 				new_state = W_ERROR;
7327c478bd9Sstevel@tonic-gate 				break;
7337c478bd9Sstevel@tonic-gate 			}
7347c478bd9Sstevel@tonic-gate 			len = strlen(dn);
7357c478bd9Sstevel@tonic-gate 			if (dn[len-1] == COMMATOK)
7367c478bd9Sstevel@tonic-gate 				rc = __s_api_append_default_basedn(
737e1dd0a2fSth 				    dn, &target_dn, &target_dn_allocated,
738e1dd0a2fSth 				    errorp);
7397c478bd9Sstevel@tonic-gate 			else
7407c478bd9Sstevel@tonic-gate 				target_dn = dn;
7417c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
7427c478bd9Sstevel@tonic-gate 				return_rc = rc;
7437c478bd9Sstevel@tonic-gate 				new_state = W_ERROR;
7447c478bd9Sstevel@tonic-gate 			}
7457c478bd9Sstevel@tonic-gate 			else
7467c478bd9Sstevel@tonic-gate 				new_state = GET_CONNECTION;
7477c478bd9Sstevel@tonic-gate 			break;
7487c478bd9Sstevel@tonic-gate 		case GET_CONNECTION:
749e1dd0a2fSth 			/* identify self as a write user */
750e1dd0a2fSth 			conn_user = __s_api_conn_user_init(NS_CONN_USER_WRITE,
751e1dd0a2fSth 			    NULL, B_FALSE);
7527c478bd9Sstevel@tonic-gate 			rc = __s_api_getConnection(NULL,
753e1dd0a2fSth 			    flags, cred, &connectionId, &conp, errorp,
754e1dd0a2fSth 			    do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
755e1dd0a2fSth 			    conn_user);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 			/*
7587c478bd9Sstevel@tonic-gate 			 * If password control attached
7597c478bd9Sstevel@tonic-gate 			 * in *errorp,
7607c478bd9Sstevel@tonic-gate 			 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
7617c478bd9Sstevel@tonic-gate 			 * free the error structure (we do not need
7627c478bd9Sstevel@tonic-gate 			 * the password management info).
7637c478bd9Sstevel@tonic-gate 			 * Reset rc to NS_LDAP_SUCCESS.
7647c478bd9Sstevel@tonic-gate 			 */
7657c478bd9Sstevel@tonic-gate 			if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
766e1dd0a2fSth 				(void) __ns_ldap_freeError(errorp);
7677c478bd9Sstevel@tonic-gate 				*errorp = NULL;
7687c478bd9Sstevel@tonic-gate 				rc = NS_LDAP_SUCCESS;
7697c478bd9Sstevel@tonic-gate 			}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
7727c478bd9Sstevel@tonic-gate 				return_rc = rc;
7737c478bd9Sstevel@tonic-gate 				new_state = W_ERROR;
7747c478bd9Sstevel@tonic-gate 				break;
7757c478bd9Sstevel@tonic-gate 			}
7767c478bd9Sstevel@tonic-gate 			if (followRef)
7777c478bd9Sstevel@tonic-gate 				new_state = SELECT_OPERATION_ASYNC;
7787c478bd9Sstevel@tonic-gate 			else
7797c478bd9Sstevel@tonic-gate 				new_state = SELECT_OPERATION_SYNC;
7807c478bd9Sstevel@tonic-gate 			break;
7817c478bd9Sstevel@tonic-gate 		case SELECT_OPERATION_SYNC:
7827c478bd9Sstevel@tonic-gate 			if (ldap_op == LDAP_REQ_ADD)
7837c478bd9Sstevel@tonic-gate 				new_state = DO_ADD_SYNC;
7847c478bd9Sstevel@tonic-gate 			else if (ldap_op == LDAP_REQ_DELETE)
7857c478bd9Sstevel@tonic-gate 				new_state = DO_DELETE_SYNC;
7867c478bd9Sstevel@tonic-gate 			else if (ldap_op == LDAP_REQ_MODIFY)
7877c478bd9Sstevel@tonic-gate 				new_state = DO_MODIFY_SYNC;
7887c478bd9Sstevel@tonic-gate 			break;
7897c478bd9Sstevel@tonic-gate 		case SELECT_OPERATION_ASYNC:
7907c478bd9Sstevel@tonic-gate 			if (ldap_op == LDAP_REQ_ADD)
7917c478bd9Sstevel@tonic-gate 				new_state = DO_ADD_ASYNC;
7927c478bd9Sstevel@tonic-gate 			else if (ldap_op == LDAP_REQ_DELETE)
7937c478bd9Sstevel@tonic-gate 				new_state = DO_DELETE_ASYNC;
7947c478bd9Sstevel@tonic-gate 			else if (ldap_op == LDAP_REQ_MODIFY)
7957c478bd9Sstevel@tonic-gate 				new_state = DO_MODIFY_ASYNC;
7967c478bd9Sstevel@tonic-gate 			break;
7977c478bd9Sstevel@tonic-gate 		case DO_ADD_SYNC:
7987c478bd9Sstevel@tonic-gate 			rc = ldap_add_ext_s(conp->ld, target_dn,
799e1dd0a2fSth 			    mods, NULL, NULL);
8007c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_SYNC;
8017c478bd9Sstevel@tonic-gate 			break;
8027c478bd9Sstevel@tonic-gate 		case DO_DELETE_SYNC:
8037c478bd9Sstevel@tonic-gate 			rc = ldap_delete_ext_s(conp->ld, target_dn,
804e1dd0a2fSth 			    NULL, NULL);
8057c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_SYNC;
8067c478bd9Sstevel@tonic-gate 			break;
8077c478bd9Sstevel@tonic-gate 		case DO_MODIFY_SYNC:
8087c478bd9Sstevel@tonic-gate 			rc = ldap_modify_ext_s(conp->ld, target_dn,
809e1dd0a2fSth 			    mods, NULL, NULL);
8107c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_SYNC;
8117c478bd9Sstevel@tonic-gate 			break;
8127c478bd9Sstevel@tonic-gate 		case DO_ADD_ASYNC:
8137c478bd9Sstevel@tonic-gate 			rc = ldap_add_ext(conp->ld, target_dn,
814e1dd0a2fSth 			    mods, NULL, NULL, &msgid);
8157c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_ASYNC;
8167c478bd9Sstevel@tonic-gate 			break;
8177c478bd9Sstevel@tonic-gate 		case DO_DELETE_ASYNC:
8187c478bd9Sstevel@tonic-gate 			rc = ldap_delete_ext(conp->ld, target_dn,
819e1dd0a2fSth 			    NULL, NULL, &msgid);
8207c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_ASYNC;
8217c478bd9Sstevel@tonic-gate 			break;
8227c478bd9Sstevel@tonic-gate 		case DO_MODIFY_ASYNC:
8237c478bd9Sstevel@tonic-gate 			rc = ldap_modify_ext(conp->ld, target_dn,
824e1dd0a2fSth 			    mods, NULL, NULL, &msgid);
8257c478bd9Sstevel@tonic-gate 			new_state = GET_RESULT_ASYNC;
8267c478bd9Sstevel@tonic-gate 			break;
8277c478bd9Sstevel@tonic-gate 		case GET_RESULT_SYNC:
8287c478bd9Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
8297c478bd9Sstevel@tonic-gate 				Errno = rc;
8307c478bd9Sstevel@tonic-gate 				(void) ldap_get_lderrno(conp->ld,
831e1dd0a2fSth 				    NULL, &errmsg);
83220945219SMichen Chang 
8337c478bd9Sstevel@tonic-gate 				/*
83420945219SMichen Chang 				 * No need to deal with the error message if
83520945219SMichen Chang 				 * it's an empty string.
8367c478bd9Sstevel@tonic-gate 				 */
83720945219SMichen Chang 				if (errmsg != NULL && *errmsg == '\0')
8387c478bd9Sstevel@tonic-gate 					errmsg = NULL;
83920945219SMichen Chang 
84020945219SMichen Chang 				if (errmsg != NULL) {
84120945219SMichen Chang 					/*
84220945219SMichen Chang 					 * ldap_get_lderrno does not expect
84320945219SMichen Chang 					 * errmsg to be freed after use, while
84420945219SMichen Chang 					 * ldap_parse_result below does, so set
84520945219SMichen Chang 					 * a flag to indicate source.
84620945219SMichen Chang 					 */
84720945219SMichen Chang 					from_get_lderrno = B_TRUE;
8487c478bd9Sstevel@tonic-gate 				}
84920945219SMichen Chang 
8507c478bd9Sstevel@tonic-gate 				new_state = W_LDAP_ERROR;
8517c478bd9Sstevel@tonic-gate 			} else {
8527c478bd9Sstevel@tonic-gate 				return_rc = NS_LDAP_SUCCESS;
8537c478bd9Sstevel@tonic-gate 				new_state = W_EXIT;
8547c478bd9Sstevel@tonic-gate 			}
8557c478bd9Sstevel@tonic-gate 			break;
8567c478bd9Sstevel@tonic-gate 		case GET_RESULT_ASYNC:
8577c478bd9Sstevel@tonic-gate 			rc = ldap_result(conp->ld, msgid, 1,
858e1dd0a2fSth 			    (struct timeval *)NULL, &res);
8597c478bd9Sstevel@tonic-gate 			/* if no server response, set Errno */
8607c478bd9Sstevel@tonic-gate 			if (rc == -1) {
8617c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(conp->ld,
8627c478bd9Sstevel@tonic-gate 				    LDAP_OPT_ERROR_NUMBER, &Errno);
8637c478bd9Sstevel@tonic-gate 				new_state = W_LDAP_ERROR;
8647c478bd9Sstevel@tonic-gate 				break;
8657c478bd9Sstevel@tonic-gate 			}
866e1dd0a2fSth 			if (rc == LDAP_RES_ADD || rc == LDAP_RES_MODIFY ||
867e1dd0a2fSth 			    rc == LDAP_RES_DELETE) {
8687c478bd9Sstevel@tonic-gate 				new_state = PARSE_RESULT;
8697c478bd9Sstevel@tonic-gate 				break;
8707c478bd9Sstevel@tonic-gate 			} else {
8717c478bd9Sstevel@tonic-gate 				return_rc = rc;
8727c478bd9Sstevel@tonic-gate 				new_state = W_ERROR;
8737c478bd9Sstevel@tonic-gate 			}
8747c478bd9Sstevel@tonic-gate 			break;
8757c478bd9Sstevel@tonic-gate 		case PARSE_RESULT:
8767c478bd9Sstevel@tonic-gate 			/*
8777c478bd9Sstevel@tonic-gate 			 * need Errno, referrals, error msg,
8787c478bd9Sstevel@tonic-gate 			 * and the last "1" is to free
8797c478bd9Sstevel@tonic-gate 			 * the result (res)
8807c478bd9Sstevel@tonic-gate 			 */
881e1dd0a2fSth 			rc = ldap_parse_result(conp->ld, res, &Errno,
882e1dd0a2fSth 			    NULL, &errmsg, &referrals, NULL, 1);
8837c478bd9Sstevel@tonic-gate 			/*
8847c478bd9Sstevel@tonic-gate 			 * free errmsg if it is an empty string
8857c478bd9Sstevel@tonic-gate 			 */
8867c478bd9Sstevel@tonic-gate 			if (errmsg && *errmsg == '\0') {
8877c478bd9Sstevel@tonic-gate 				ldap_memfree(errmsg);
8887c478bd9Sstevel@tonic-gate 				errmsg = NULL;
8897c478bd9Sstevel@tonic-gate 			}
8907d575517Ssdussud 			/*
8917d575517Ssdussud 			 * If we received referral data, process
8927d575517Ssdussud 			 * it if:
8937d575517Ssdussud 			 * - we are configured to follow referrals
8947d575517Ssdussud 			 * - and not already in referral mode (to keep
8957d575517Ssdussud 			 *   consistency with search_state_machine()
8967d575517Ssdussud 			 *   which follows 1 level of referrals only;
8977d575517Ssdussud 			 *   see proc_result_referrals() and
8987d575517Ssdussud 			 *   proc_search_references().
8997d575517Ssdussud 			 */
9007d575517Ssdussud 			if (Errno == LDAP_REFERRAL && followRef && !ref_list) {
9017d575517Ssdussud 				for (i = 0; referrals[i] != NULL; i++) {
9027d575517Ssdussud 					/* add to referral list */
9037d575517Ssdussud 					rc = __s_api_addRefInfo(&ref_list,
904e1dd0a2fSth 					    referrals[i], NULL, NULL, NULL,
905e1dd0a2fSth 					    conp->ld);
9067d575517Ssdussud 					if (rc != NS_LDAP_SUCCESS) {
9077d575517Ssdussud 						__s_api_deleteRefInfo(ref_list);
9087d575517Ssdussud 						ref_list = NULL;
9097d575517Ssdussud 						break;
9107d575517Ssdussud 					}
9117c478bd9Sstevel@tonic-gate 				}
9127c478bd9Sstevel@tonic-gate 				ldap_value_free(referrals);
9137d575517Ssdussud 				if (ref_list == NULL) {
9147c478bd9Sstevel@tonic-gate 					if (rc != NS_LDAP_MEMORY)
9157c478bd9Sstevel@tonic-gate 						rc = NS_LDAP_INTERNAL;
9167d575517Ssdussud 					return_rc = rc;
9177c478bd9Sstevel@tonic-gate 					new_state = W_ERROR;
9187d575517Ssdussud 				} else {
9197c478bd9Sstevel@tonic-gate 					new_state = GET_REFERRAL_CONNECTION;
9207d575517Ssdussud 					current_ref = ref_list;
9217d575517Ssdussud 				}
9227c478bd9Sstevel@tonic-gate 				if (errmsg) {
9237c478bd9Sstevel@tonic-gate 					ldap_memfree(errmsg);
9247c478bd9Sstevel@tonic-gate 					errmsg = NULL;
9257c478bd9Sstevel@tonic-gate 				}
9267c478bd9Sstevel@tonic-gate 				break;
9277c478bd9Sstevel@tonic-gate 			}
9287c478bd9Sstevel@tonic-gate 			if (Errno != LDAP_SUCCESS) {
9297c478bd9Sstevel@tonic-gate 				new_state = W_LDAP_ERROR;
9307c478bd9Sstevel@tonic-gate 			} else {
9317c478bd9Sstevel@tonic-gate 				return_rc = NS_LDAP_SUCCESS;
9327c478bd9Sstevel@tonic-gate 				new_state = W_EXIT;
9337c478bd9Sstevel@tonic-gate 			}
9347c478bd9Sstevel@tonic-gate 			break;
9357c478bd9Sstevel@tonic-gate 		case GET_REFERRAL_CONNECTION:
9367d575517Ssdussud 			/*
9377d575517Ssdussud 			 * since we are starting over,
9387d575517Ssdussud 			 * discard the old error info
9397d575517Ssdussud 			 */
9407d575517Ssdussud 			return_rc = NS_LDAP_SUCCESS;
9417d575517Ssdussud 			if (*errorp)
9427d575517Ssdussud 				(void) __ns_ldap_freeError(errorp);
9437c478bd9Sstevel@tonic-gate 			if (connectionId > -1)
944cb5caa98Sdjl 				DropConnection(connectionId, NS_LDAP_NEW_CONN);
945e1dd0a2fSth 
946e1dd0a2fSth 			/* set it up to use a referral connection */
947e1dd0a2fSth 			if (conn_user != NULL) {
948e1dd0a2fSth 				/*
949e1dd0a2fSth 				 * If an MT connection is being used,
950e1dd0a2fSth 				 * return it to the pool.
951e1dd0a2fSth 				 */
952e1dd0a2fSth 				if (conn_user->conn_mt != NULL)
953e1dd0a2fSth 					__s_api_conn_mt_return(conn_user);
954e1dd0a2fSth 
955e1dd0a2fSth 				conn_user->referral = B_TRUE;
956e1dd0a2fSth 			}
9577d575517Ssdussud 			rc = __s_api_getConnection(current_ref->refHost,
958