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