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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*a506a34cSth160488 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <synch.h> 307c478bd9Sstevel@tonic-gate #include <strings.h> 317c478bd9Sstevel@tonic-gate #include <sys/time.h> 327c478bd9Sstevel@tonic-gate #include <ctype.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include "ldap_op.h" 357c478bd9Sstevel@tonic-gate #include "ldap_util.h" 367c478bd9Sstevel@tonic-gate #include "ldap_structs.h" 377c478bd9Sstevel@tonic-gate #include "ldap_ruleval.h" 387c478bd9Sstevel@tonic-gate #include "ldap_attr.h" 397c478bd9Sstevel@tonic-gate #include "ldap_print.h" 407c478bd9Sstevel@tonic-gate #include "ldap_glob.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include "nis_parse_ldap_conf.h" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #ifndef LDAPS_PORT 457c478bd9Sstevel@tonic-gate #define LDAPS_PORT 636 467c478bd9Sstevel@tonic-gate #endif 477c478bd9Sstevel@tonic-gate 48*a506a34cSth160488 static int setupConList(char *serverList, char *who, 49*a506a34cSth160488 char *cred, auth_method_t method); 50*a506a34cSth160488 51*a506a34cSth160488 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Build one of our internal LDAP search structures, containing copies of 547c478bd9Sstevel@tonic-gate * the supplied input. return NULL in case of error. 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate * If 'filter' is NULL, build an AND-filter using the filter components. 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate __nis_ldap_search_t * 597c478bd9Sstevel@tonic-gate buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp, 607c478bd9Sstevel@tonic-gate char *filter, char **attrs, int attrsonly, int isDN) { 617c478bd9Sstevel@tonic-gate __nis_ldap_search_t *ls; 627c478bd9Sstevel@tonic-gate char **a; 637c478bd9Sstevel@tonic-gate int i, na, err = 0; 647c478bd9Sstevel@tonic-gate char *myself = "buildLdapSearch"; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate ls = am(myself, sizeof (*ls)); 677c478bd9Sstevel@tonic-gate if (ls == 0) 687c478bd9Sstevel@tonic-gate return (0); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate ls->base = sdup(myself, T, base); 717c478bd9Sstevel@tonic-gate if (ls->base == 0 && base != 0) 727c478bd9Sstevel@tonic-gate err++; 737c478bd9Sstevel@tonic-gate ls->scope = scope; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate if (filterComp != 0 && numFilterComps > 0) { 767c478bd9Sstevel@tonic-gate ls->filterComp = am(myself, numFilterComps * 777c478bd9Sstevel@tonic-gate sizeof (ls->filterComp[0])); 787c478bd9Sstevel@tonic-gate if (ls->filterComp == 0) { 797c478bd9Sstevel@tonic-gate err++; 807c478bd9Sstevel@tonic-gate numFilterComps = 0; 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate for (i = 0; i < numFilterComps; i++) { 837c478bd9Sstevel@tonic-gate ls->filterComp[i] = sdup(myself, T, filterComp[i]); 847c478bd9Sstevel@tonic-gate if (ls->filterComp[i] == 0 && filterComp[i] != 0) 857c478bd9Sstevel@tonic-gate err++; 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate ls->numFilterComps = numFilterComps; 887c478bd9Sstevel@tonic-gate if (filter == 0) { 897c478bd9Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 907c478bd9Sstevel@tonic-gate ls->filterComp); 917c478bd9Sstevel@tonic-gate if (ls->filter == 0) 927c478bd9Sstevel@tonic-gate err++; 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate } else { 957c478bd9Sstevel@tonic-gate ls->filterComp = 0; 967c478bd9Sstevel@tonic-gate ls->numFilterComps = 0; 977c478bd9Sstevel@tonic-gate ls->filter = sdup(myself, T, filter); 987c478bd9Sstevel@tonic-gate if (ls->filter == 0 && filter != 0) 997c478bd9Sstevel@tonic-gate err++; 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if (attrs != 0) { 1037c478bd9Sstevel@tonic-gate for (na = 0, a = attrs; *a != 0; a++, na++); 1047c478bd9Sstevel@tonic-gate ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0])); 1057c478bd9Sstevel@tonic-gate if (ls->attrs != 0) { 1067c478bd9Sstevel@tonic-gate for (i = 0; i < na; i++) { 1077c478bd9Sstevel@tonic-gate ls->attrs[i] = sdup(myself, T, attrs[i]); 1087c478bd9Sstevel@tonic-gate if (ls->attrs[i] == 0 && attrs[i] != 0) 1097c478bd9Sstevel@tonic-gate err++; 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate ls->attrs[na] = 0; 1127c478bd9Sstevel@tonic-gate ls->numAttrs = na; 1137c478bd9Sstevel@tonic-gate } else { 1147c478bd9Sstevel@tonic-gate err++; 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate } else { 1177c478bd9Sstevel@tonic-gate ls->attrs = 0; 1187c478bd9Sstevel@tonic-gate ls->numAttrs = 0; 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate ls->attrsonly = attrsonly; 1227c478bd9Sstevel@tonic-gate ls->isDN = isDN; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate if (err > 0) { 1257c478bd9Sstevel@tonic-gate freeLdapSearch(ls); 1267c478bd9Sstevel@tonic-gate ls = 0; 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate return (ls); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate void 1337c478bd9Sstevel@tonic-gate freeLdapSearch(__nis_ldap_search_t *ls) { 1347c478bd9Sstevel@tonic-gate int i; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate if (ls == 0) 1377c478bd9Sstevel@tonic-gate return; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate sfree(ls->base); 1407c478bd9Sstevel@tonic-gate if (ls->filterComp != 0) { 1417c478bd9Sstevel@tonic-gate for (i = 0; i < ls->numFilterComps; i++) { 1427c478bd9Sstevel@tonic-gate sfree(ls->filterComp[i]); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate sfree(ls->filterComp); 1457c478bd9Sstevel@tonic-gate } 1467c478bd9Sstevel@tonic-gate sfree(ls->filter); 1477c478bd9Sstevel@tonic-gate if (ls->attrs != 0) { 1487c478bd9Sstevel@tonic-gate for (i = 0; i < ls->numAttrs; i++) { 1497c478bd9Sstevel@tonic-gate sfree(ls->attrs[i]); 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate sfree(ls->attrs); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate free(ls); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * Given a table mapping, and a rule/value pointer, 1597c478bd9Sstevel@tonic-gate * return an LDAP search structure with values suitable for use 1607c478bd9Sstevel@tonic-gate * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value 1617c478bd9Sstevel@tonic-gate * may be modified. 1627c478bd9Sstevel@tonic-gate * 1637c478bd9Sstevel@tonic-gate * If dn != 0 and *dn == 0, the function attemps to return a pointer 1647c478bd9Sstevel@tonic-gate * to the DN. This may necessitate an ldapSearch, if the rule set doesn't 1657c478bd9Sstevel@tonic-gate * produce a DN directly. 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * if dn == 0, and the rule set produces a DN as well as other attribute/ 1687c478bd9Sstevel@tonic-gate * value pairs, the function returns an LDAP search structure with the 1697c478bd9Sstevel@tonic-gate * DN only. 1707c478bd9Sstevel@tonic-gate * 1717c478bd9Sstevel@tonic-gate * If 'fromLDAP' is set, the caller wants base/scope/filter from 1727c478bd9Sstevel@tonic-gate * t->objectDN->read; otherwise, from t->objectDN->write. 1737c478bd9Sstevel@tonic-gate * 1747c478bd9Sstevel@tonic-gate * If 'rv' is NULL, the caller wants an enumeration of the container. 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * Note that this function only creates a search structure for 't' itself; 1777c478bd9Sstevel@tonic-gate * if there are alternative mappings for the table, those must be handled 1787c478bd9Sstevel@tonic-gate * by our caller. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate __nis_ldap_search_t * 1817c478bd9Sstevel@tonic-gate createLdapRequest(__nis_table_mapping_t *t, 1827c478bd9Sstevel@tonic-gate __nis_rule_value_t *rv, char **dn, int fromLDAP, 1837c478bd9Sstevel@tonic-gate int *res, __nis_object_dn_t *obj_dn) { 1847c478bd9Sstevel@tonic-gate int i, j; 1857c478bd9Sstevel@tonic-gate __nis_ldap_search_t *ls = 0; 1867c478bd9Sstevel@tonic-gate char **locDN; 1877c478bd9Sstevel@tonic-gate int numLocDN, stat = 0, count = 0; 1887c478bd9Sstevel@tonic-gate char *myself = "createLdapRequest"; 1897c478bd9Sstevel@tonic-gate __nis_object_dn_t *objectDN = NULL; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate if (t == 0) 1927c478bd9Sstevel@tonic-gate return (0); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if (obj_dn == NULL) 1957c478bd9Sstevel@tonic-gate objectDN = t->objectDN; 1967c478bd9Sstevel@tonic-gate else 1977c478bd9Sstevel@tonic-gate objectDN = obj_dn; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if (rv == 0) { 2007c478bd9Sstevel@tonic-gate char *base; 2017c478bd9Sstevel@tonic-gate char *filter; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (fromLDAP) { 2047c478bd9Sstevel@tonic-gate base = objectDN->read.base; 2057c478bd9Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 2067c478bd9Sstevel@tonic-gate } else { 2077c478bd9Sstevel@tonic-gate base = objectDN->write.base; 2087c478bd9Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 2097c478bd9Sstevel@tonic-gate } 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* Create request to enumerate container */ 2127c478bd9Sstevel@tonic-gate ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter, 2137c478bd9Sstevel@tonic-gate 0, 0, 0); 2147c478bd9Sstevel@tonic-gate sfree(filter); 2157c478bd9Sstevel@tonic-gate return (ls); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate for (i = 0; i < t->numRulesToLDAP; i++) { 2197c478bd9Sstevel@tonic-gate rv = addLdapRuleValue(t, t->ruleToLDAP[i], 2207c478bd9Sstevel@tonic-gate mit_ldap, mit_nisplus, rv, !fromLDAP, &stat); 2217c478bd9Sstevel@tonic-gate if (rv == 0) 2227c478bd9Sstevel@tonic-gate return (0); 2237c478bd9Sstevel@tonic-gate if (stat == NP_LDAP_RULES_NO_VALUE) 2247c478bd9Sstevel@tonic-gate count++; 2257c478bd9Sstevel@tonic-gate stat = 0; 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * If none of the rules produced a value despite 2307c478bd9Sstevel@tonic-gate * having enough NIS+ columns, return error. 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate if (rv->numAttrs == 0 && count > 0) { 2337c478bd9Sstevel@tonic-gate *res = NP_LDAP_RULES_NO_VALUE; 2347c478bd9Sstevel@tonic-gate return (0); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * 'rv' now contains everything we know about the attributes and 2397c478bd9Sstevel@tonic-gate * values. Build an LDAP search structure from it. 2407c478bd9Sstevel@tonic-gate */ 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* Look for a single-valued DN */ 2437c478bd9Sstevel@tonic-gate locDN = findDNs(myself, rv, 1, 2447c478bd9Sstevel@tonic-gate fromLDAP ? objectDN->read.base : 2457c478bd9Sstevel@tonic-gate objectDN->write.base, 2467c478bd9Sstevel@tonic-gate &numLocDN); 2477c478bd9Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 2487c478bd9Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 2497c478bd9Sstevel@tonic-gate *dn = locDN[0]; 2507c478bd9Sstevel@tonic-gate sfree(locDN); 2517c478bd9Sstevel@tonic-gate } else { 2527c478bd9Sstevel@tonic-gate char *filter; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate if (fromLDAP) 2557c478bd9Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 2567c478bd9Sstevel@tonic-gate else 2577c478bd9Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 2587c478bd9Sstevel@tonic-gate ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0, 2597c478bd9Sstevel@tonic-gate filter, 0, 0, 1); 2607c478bd9Sstevel@tonic-gate sfree(filter); 2617c478bd9Sstevel@tonic-gate freeDNs(locDN, numLocDN); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate } else { 2647c478bd9Sstevel@tonic-gate freeDNs(locDN, numLocDN); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (ls != 0) { 2687c478bd9Sstevel@tonic-gate ls->useCon = 1; 2697c478bd9Sstevel@tonic-gate return (ls); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * No DN, or caller wanted a search structure with the non-DN 2747c478bd9Sstevel@tonic-gate * attributes. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate /* Initialize search structure */ 2787c478bd9Sstevel@tonic-gate { 2797c478bd9Sstevel@tonic-gate char *filter = (fromLDAP) ? 2807c478bd9Sstevel@tonic-gate makeFilter(objectDN->read.attrs) : 2817c478bd9Sstevel@tonic-gate makeFilter(objectDN->write.attrs); 2827c478bd9Sstevel@tonic-gate char **ofc; 2837c478bd9Sstevel@tonic-gate int nofc = 0; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate ofc = makeFilterComp(filter, &nofc); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if (filter != 0 && ofc == 0) { 2887c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 2897c478bd9Sstevel@tonic-gate "%s: Unable to break filter into components: \"%s\"", 2907c478bd9Sstevel@tonic-gate myself, NIL(filter)); 2917c478bd9Sstevel@tonic-gate sfree(filter); 2927c478bd9Sstevel@tonic-gate return (0); 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (fromLDAP) 2967c478bd9Sstevel@tonic-gate ls = buildLdapSearch(objectDN->read.base, 2977c478bd9Sstevel@tonic-gate objectDN->read.scope, 2987c478bd9Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 2997c478bd9Sstevel@tonic-gate else 3007c478bd9Sstevel@tonic-gate ls = buildLdapSearch(objectDN->write.base, 3017c478bd9Sstevel@tonic-gate objectDN->write.scope, 3027c478bd9Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 3037c478bd9Sstevel@tonic-gate sfree(filter); 3047c478bd9Sstevel@tonic-gate freeFilterComp(ofc, nofc); 3057c478bd9Sstevel@tonic-gate if (ls == 0) 3067c478bd9Sstevel@tonic-gate return (0); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate /* Build and add the filter components */ 3107c478bd9Sstevel@tonic-gate for (i = 0; i < rv->numAttrs; i++) { 3117c478bd9Sstevel@tonic-gate /* Skip DN */ 3127c478bd9Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 3137c478bd9Sstevel@tonic-gate continue; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* Skip vt_ber values */ 3167c478bd9Sstevel@tonic-gate if (rv->attrVal[i].type == vt_ber) 3177c478bd9Sstevel@tonic-gate continue; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 3207c478bd9Sstevel@tonic-gate __nis_buffer_t b = {0, 0}; 3217c478bd9Sstevel@tonic-gate char **tmpComp; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate bp2buf(myself, &b, "%s=%s", 3247c478bd9Sstevel@tonic-gate rv->attrName[i], rv->attrVal[i].val[j].value); 3257c478bd9Sstevel@tonic-gate tmpComp = addFilterComp(b.buf, ls->filterComp, 3267c478bd9Sstevel@tonic-gate &ls->numFilterComps); 3277c478bd9Sstevel@tonic-gate if (tmpComp == 0) { 3287c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 3297c478bd9Sstevel@tonic-gate "%s: Unable to add filter component \"%s\"", 3307c478bd9Sstevel@tonic-gate myself, NIL(b.buf)); 3317c478bd9Sstevel@tonic-gate sfree(b.buf); 3327c478bd9Sstevel@tonic-gate freeLdapSearch(ls); 3337c478bd9Sstevel@tonic-gate return (0); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate ls->filterComp = tmpComp; 3367c478bd9Sstevel@tonic-gate sfree(b.buf); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate if (ls->numFilterComps > 0) { 3417c478bd9Sstevel@tonic-gate sfree(ls->filter); 3427c478bd9Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 3437c478bd9Sstevel@tonic-gate ls->filterComp); 3447c478bd9Sstevel@tonic-gate if (ls->filter == 0) { 3457c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 3467c478bd9Sstevel@tonic-gate "%s: Unable to concatenate filter components", 3477c478bd9Sstevel@tonic-gate myself); 3487c478bd9Sstevel@tonic-gate freeLdapSearch(ls); 3497c478bd9Sstevel@tonic-gate return (0); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * The caller wants a DN, but we didn't get one from the 3567c478bd9Sstevel@tonic-gate * the rule set. We have an 'ls', so use it to ldapSearch() 3577c478bd9Sstevel@tonic-gate * for an entry from which we can extract the DN. 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate __nis_rule_value_t *rvtmp; 3607c478bd9Sstevel@tonic-gate char **locDN; 3617c478bd9Sstevel@tonic-gate int nv = 0, numLocDN; 3627c478bd9Sstevel@tonic-gate 3637c478bd9Sstevel@tonic-gate rvtmp = ldapSearch(ls, &nv, 0, 0); 3647c478bd9Sstevel@tonic-gate locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN); 3657c478bd9Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 3667c478bd9Sstevel@tonic-gate *dn = locDN[0]; 3677c478bd9Sstevel@tonic-gate sfree(locDN); 3687c478bd9Sstevel@tonic-gate } else { 3697c478bd9Sstevel@tonic-gate freeDNs(locDN, numLocDN); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate freeRuleValue(rvtmp, nv); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate ls->useCon = 1; 3757c478bd9Sstevel@tonic-gate return (ls); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate int ldapConnAttemptRetryTimeout = 60; /* seconds */ 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate typedef struct { 3817c478bd9Sstevel@tonic-gate LDAP *ld; 3827c478bd9Sstevel@tonic-gate mutex_t mutex; /* Mutex for update of structure */ 3837c478bd9Sstevel@tonic-gate pthread_t owner; /* Thread holding mutex */ 3847c478bd9Sstevel@tonic-gate mutex_t rcMutex; /* Mutex for refCount */ 3857c478bd9Sstevel@tonic-gate int refCount; /* Reference count */ 3867c478bd9Sstevel@tonic-gate int isBound; /* Is connection open and usable ? */ 3877c478bd9Sstevel@tonic-gate time_t retryTime; /* When should open be retried */ 3887c478bd9Sstevel@tonic-gate int status; /* Status of last operation */ 3897c478bd9Sstevel@tonic-gate int doDis; /* To be disconnected if refCount==0 */ 3907c478bd9Sstevel@tonic-gate int doDel; /* To be deleted if refCount zero */ 3917c478bd9Sstevel@tonic-gate int onList; /* True if on the 'ldapCon' list */ 3927c478bd9Sstevel@tonic-gate char *sp; /* server string */ 3937c478bd9Sstevel@tonic-gate char *who; 3947c478bd9Sstevel@tonic-gate char *cred; 3957c478bd9Sstevel@tonic-gate auth_method_t method; 3967c478bd9Sstevel@tonic-gate int port; 3977c478bd9Sstevel@tonic-gate struct timeval bindTimeout; 3987c478bd9Sstevel@tonic-gate struct timeval searchTimeout; 3997c478bd9Sstevel@tonic-gate struct timeval modifyTimeout; 4007c478bd9Sstevel@tonic-gate struct timeval addTimeout; 4017c478bd9Sstevel@tonic-gate struct timeval deleteTimeout; 4027c478bd9Sstevel@tonic-gate int simplePage; /* Can do simple-page */ 4037c478bd9Sstevel@tonic-gate int vlv; /* Can do VLV */ 4047c478bd9Sstevel@tonic-gate uint_t batchFrom; /* # entries read in one operation */ 4057c478bd9Sstevel@tonic-gate void *next; 4067c478bd9Sstevel@tonic-gate } __nis_ldap_conn_t; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* 4097c478bd9Sstevel@tonic-gate * List of connections, 'ldapCon', protected by an RW lock. 4107c478bd9Sstevel@tonic-gate * 4117c478bd9Sstevel@tonic-gate * The following locking scheme is used: 4127c478bd9Sstevel@tonic-gate * 4137c478bd9Sstevel@tonic-gate * (1) Find a connection structure to use to talk to LDAP 4147c478bd9Sstevel@tonic-gate * Rlock list 4157c478bd9Sstevel@tonic-gate * Locate structure 4167c478bd9Sstevel@tonic-gate * Acquire 'mutex' 4177c478bd9Sstevel@tonic-gate * Acquire 'rcMutex' 4187c478bd9Sstevel@tonic-gate * update refCount 4197c478bd9Sstevel@tonic-gate * Release 'rcMutex' 4207c478bd9Sstevel@tonic-gate * release 'mutex' 4217c478bd9Sstevel@tonic-gate * Unlock list 4227c478bd9Sstevel@tonic-gate * Use structure 4237c478bd9Sstevel@tonic-gate * Release structure when done 4247c478bd9Sstevel@tonic-gate * (2) Insert/delete structure(s) on/from list 4257c478bd9Sstevel@tonic-gate * Wlock list 4267c478bd9Sstevel@tonic-gate * Insert/delete structure; if deleting, must 4277c478bd9Sstevel@tonic-gate * acquire 'mutex', and 'rcMutex' (in that order), 4287c478bd9Sstevel@tonic-gate * and 'refCount' must be zero. 4297c478bd9Sstevel@tonic-gate * Unlock list 4307c478bd9Sstevel@tonic-gate * (3) Modify structure 4317c478bd9Sstevel@tonic-gate * Find structure 4327c478bd9Sstevel@tonic-gate * Acquire 'mutex' 4337c478bd9Sstevel@tonic-gate * Modify (except refCount) 4347c478bd9Sstevel@tonic-gate * Release 'mutex' 4357c478bd9Sstevel@tonic-gate * Release structure 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *ldapCon = 0; 4397c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *ldapReferralCon = 0; 4407c478bd9Sstevel@tonic-gate static rwlock_t ldapConLock = DEFAULTRWLOCK; 4417c478bd9Sstevel@tonic-gate static rwlock_t referralConLock = DEFAULTRWLOCK; 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate void 4447c478bd9Sstevel@tonic-gate exclusiveLC(__nis_ldap_conn_t *lc) { 4457c478bd9Sstevel@tonic-gate pthread_t me = pthread_self(); 4467c478bd9Sstevel@tonic-gate int stat; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate if (lc == 0) 4497c478bd9Sstevel@tonic-gate return; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 4527c478bd9Sstevel@tonic-gate if (stat == EBUSY && lc->owner != me) 4537c478bd9Sstevel@tonic-gate mutex_lock(&lc->mutex); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate lc->owner = me; 4567c478bd9Sstevel@tonic-gate } 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate /* Return 1 if mutex held by this thread, 0 otherwise */ 4597c478bd9Sstevel@tonic-gate int 4607c478bd9Sstevel@tonic-gate assertExclusive(__nis_ldap_conn_t *lc) { 4617c478bd9Sstevel@tonic-gate pthread_t me; 4627c478bd9Sstevel@tonic-gate int stat; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate if (lc == 0) 4657c478bd9Sstevel@tonic-gate return (0); 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (stat == 0) { 4707c478bd9Sstevel@tonic-gate mutex_unlock(&lc->mutex); 4717c478bd9Sstevel@tonic-gate return (0); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate me = pthread_self(); 4757c478bd9Sstevel@tonic-gate if (stat != EBUSY || lc->owner != me) 4767c478bd9Sstevel@tonic-gate return (0); 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate return (1); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate void 4827c478bd9Sstevel@tonic-gate releaseLC(__nis_ldap_conn_t *lc) { 4837c478bd9Sstevel@tonic-gate pthread_t me = pthread_self(); 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (lc == 0 || lc->owner != me) 4867c478bd9Sstevel@tonic-gate return; 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate lc->owner = 0; 4897c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lc->mutex); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate void 4937c478bd9Sstevel@tonic-gate incrementRC(__nis_ldap_conn_t *lc) { 4947c478bd9Sstevel@tonic-gate if (lc == 0) 4957c478bd9Sstevel@tonic-gate return; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 4987c478bd9Sstevel@tonic-gate lc->refCount++; 4997c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate void 5037c478bd9Sstevel@tonic-gate decrementRC(__nis_ldap_conn_t *lc) { 5047c478bd9Sstevel@tonic-gate if (lc == 0) 5057c478bd9Sstevel@tonic-gate return; 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 5087c478bd9Sstevel@tonic-gate if (lc->refCount > 0) 5097c478bd9Sstevel@tonic-gate lc->refCount--; 5107c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* Accept a server/port indication, and call ldap_init() */ 5147c478bd9Sstevel@tonic-gate static LDAP * 5157c478bd9Sstevel@tonic-gate ldapInit(char *srv, int port, bool_t use_ssl) { 5167c478bd9Sstevel@tonic-gate LDAP *ld; 5177c478bd9Sstevel@tonic-gate int ldapVersion = LDAP_VERSION3; 5187c478bd9Sstevel@tonic-gate int derefOption = LDAP_DEREF_ALWAYS; 5197c478bd9Sstevel@tonic-gate int timelimit = proxyInfo.search_time_limit; 5207c478bd9Sstevel@tonic-gate int sizelimit = proxyInfo.search_size_limit; 5217c478bd9Sstevel@tonic-gate char *myself = "ldapInit"; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if (srv == 0) 5247c478bd9Sstevel@tonic-gate return (0); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate if (use_ssl) { 5277c478bd9Sstevel@tonic-gate ld = ldapssl_init(srv, port, 1); 5287c478bd9Sstevel@tonic-gate } else { 5297c478bd9Sstevel@tonic-gate ld = ldap_init(srv, port); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate if (ld != 0) { 5337c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 5347c478bd9Sstevel@tonic-gate &ldapVersion); 5357c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 5367c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 5377c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit); 5387c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit); 5397c478bd9Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate return (ld); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * Bind the specified LDAP structure per the supplied authentication. 5477c478bd9Sstevel@tonic-gate * Note: tested with none, simple, and digest_md5. May or may not 5487c478bd9Sstevel@tonic-gate * work with other authentication methods, mostly depending on whether 5497c478bd9Sstevel@tonic-gate * or not 'who' and 'cred' contain sufficient information. 5507c478bd9Sstevel@tonic-gate */ 5517c478bd9Sstevel@tonic-gate static int 5527c478bd9Sstevel@tonic-gate ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method, 5537c478bd9Sstevel@tonic-gate struct timeval timeout) { 5547c478bd9Sstevel@tonic-gate int ret; 5557c478bd9Sstevel@tonic-gate LDAP *ld; 5567c478bd9Sstevel@tonic-gate char *myself = "ldapBind"; 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (ldP == 0 || (ld = *ldP) == 0) 5597c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (method == none) { 5627c478bd9Sstevel@tonic-gate /* No ldap_bind() required (or even possible) */ 5637c478bd9Sstevel@tonic-gate ret = LDAP_SUCCESS; 5647c478bd9Sstevel@tonic-gate } else if (method == simple) { 5657c478bd9Sstevel@tonic-gate struct timeval tv; 5667c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate tv = timeout; 5697c478bd9Sstevel@tonic-gate ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE); 5707c478bd9Sstevel@tonic-gate if (ret != -1) { 5717c478bd9Sstevel@tonic-gate ret = ldap_result(ld, ret, 0, &tv, &msg); 5727c478bd9Sstevel@tonic-gate if (ret == 0) { 5737c478bd9Sstevel@tonic-gate ret = LDAP_TIMEOUT; 5747c478bd9Sstevel@tonic-gate } else if (ret == -1) { 5757c478bd9Sstevel@tonic-gate (void) ldap_get_option(ld, 5767c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, 5777c478bd9Sstevel@tonic-gate &ret); 5787c478bd9Sstevel@tonic-gate } else { 5797c478bd9Sstevel@tonic-gate ret = ldap_result2error(ld, msg, 0); 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate if (msg != 0) 5827c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 5837c478bd9Sstevel@tonic-gate } else { 5847c478bd9Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 5857c478bd9Sstevel@tonic-gate &ret); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate } else if (method == cram_md5) { 5887c478bd9Sstevel@tonic-gate /* Note: there is only a synchronous call for cram-md5 */ 5897c478bd9Sstevel@tonic-gate struct berval ber_cred; 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 5927c478bd9Sstevel@tonic-gate ber_cred.bv_val = cred; 5937c478bd9Sstevel@tonic-gate ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL); 5947c478bd9Sstevel@tonic-gate } else if (method == digest_md5) { 5957c478bd9Sstevel@tonic-gate /* Note: there is only a synchronous call for digest-md5 */ 5967c478bd9Sstevel@tonic-gate struct berval ber_cred; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 5997c478bd9Sstevel@tonic-gate ber_cred.bv_val = cred; 6007c478bd9Sstevel@tonic-gate ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL, 6017c478bd9Sstevel@tonic-gate NULL); 6027c478bd9Sstevel@tonic-gate } else { 6037c478bd9Sstevel@tonic-gate ret = LDAP_AUTH_METHOD_NOT_SUPPORTED; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate if (ret != LDAP_SUCCESS) { 6077c478bd9Sstevel@tonic-gate (void) ldap_unbind_s(ld); 6087c478bd9Sstevel@tonic-gate *ldP = 0; 6097c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 6107c478bd9Sstevel@tonic-gate "%s: Unable to bind as: %s: %s", 6117c478bd9Sstevel@tonic-gate myself, who, ldap_err2string(ret)); 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate return (ret); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * Free 'lc' and all related memory. Caller must hold the exclusive lock. 6197c478bd9Sstevel@tonic-gate * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't 6207c478bd9Sstevel@tonic-gate * try to use the structure pointer in any way. 6217c478bd9Sstevel@tonic-gate */ 6227c478bd9Sstevel@tonic-gate static int 6237c478bd9Sstevel@tonic-gate freeCon(__nis_ldap_conn_t *lc) { 6247c478bd9Sstevel@tonic-gate char *myself = "freeCon"; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (!assertExclusive(lc)) 6277c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate incrementRC(lc); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* Must be unused, unbound, and not on the 'ldapCon' list */ 6327c478bd9Sstevel@tonic-gate if (lc->onList || lc->refCount != 1 || lc->isBound) { 6337c478bd9Sstevel@tonic-gate lc->doDel++; 6347c478bd9Sstevel@tonic-gate decrementRC(lc); 6357c478bd9Sstevel@tonic-gate return (LDAP_BUSY); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate sfree(lc->sp); 6397c478bd9Sstevel@tonic-gate sfree(lc->who); 6407c478bd9Sstevel@tonic-gate sfree(lc->cred); 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* Delete structure with both mutex:es held */ 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate free(lc); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'. 6517c478bd9Sstevel@tonic-gate * 6527c478bd9Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 6537c478bd9Sstevel@tonic-gate * the structure in any way. 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate static int 6567c478bd9Sstevel@tonic-gate disconnectCon(__nis_ldap_conn_t *lc) { 6577c478bd9Sstevel@tonic-gate int stat; 6587c478bd9Sstevel@tonic-gate char *myself = "disconnectCon"; 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate if (lc == 0) 6617c478bd9Sstevel@tonic-gate return (LDAP_SUCCESS); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate if (!assertExclusive(lc)) 6647c478bd9Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate if (lc->doDis) { 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Increment refCount to protect against interference */ 6697c478bd9Sstevel@tonic-gate incrementRC(lc); 6707c478bd9Sstevel@tonic-gate /* refCount must be one (i.e., just us) */ 6717c478bd9Sstevel@tonic-gate if (lc->refCount != 1) { 6727c478bd9Sstevel@tonic-gate /* 6737c478bd9Sstevel@tonic-gate * In use; already marked for disconnect, 6747c478bd9Sstevel@tonic-gate * so do nothing. 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate decrementRC(lc); 6777c478bd9Sstevel@tonic-gate return (LDAP_BUSY); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate stat = ldap_unbind_s(lc->ld); 6817c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 6827c478bd9Sstevel@tonic-gate lc->ld = 0; 6837c478bd9Sstevel@tonic-gate lc->isBound = 0; 6847c478bd9Sstevel@tonic-gate lc->doDis = 0; 6857c478bd9Sstevel@tonic-gate /* Reset simple page and vlv indication */ 6867c478bd9Sstevel@tonic-gate lc->simplePage = 0; 6877c478bd9Sstevel@tonic-gate lc->vlv = 0; 6887c478bd9Sstevel@tonic-gate } else if (verbose) { 6897c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 6907c478bd9Sstevel@tonic-gate "%s: ldap_unbind_s() => %d (%s)", 6917c478bd9Sstevel@tonic-gate myself, stat, ldap_err2string(stat)); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate decrementRC(lc); 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if (lc->doDel) { 6987c478bd9Sstevel@tonic-gate if (LDAP_UNAVAILABLE == freeCon(lc)) 6997c478bd9Sstevel@tonic-gate stat = LDAP_UNAVAILABLE; 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate return (stat); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate /* 7067c478bd9Sstevel@tonic-gate * controlSupported will determine for a given connection whether a set 7077c478bd9Sstevel@tonic-gate * of controls is supported or not. The input parameters: 7087c478bd9Sstevel@tonic-gate * lc The connection 7097c478bd9Sstevel@tonic-gate * ctrl A an array of OID strings, the terminal string should be NULL 7107c478bd9Sstevel@tonic-gate * The returned values if LDAP_SUCCESS is returned: 7117c478bd9Sstevel@tonic-gate * supported A caller supplied array which will be set to TRUE or 7127c478bd9Sstevel@tonic-gate * FALSE depending on whether the corresponding control 7137c478bd9Sstevel@tonic-gate * is reported as supported. 7147c478bd9Sstevel@tonic-gate * Returns LDAP_SUCCESS if the supportedControl attribute is read. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate static int 7187c478bd9Sstevel@tonic-gate controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) { 7197c478bd9Sstevel@tonic-gate LDAPMessage *res, *e; 7207c478bd9Sstevel@tonic-gate char *attr[2], *a, **val; 7217c478bd9Sstevel@tonic-gate int stat, i; 7227c478bd9Sstevel@tonic-gate BerElement *ber = 0; 7237c478bd9Sstevel@tonic-gate char *myself = "controlSupported"; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate attr[0] = "supportedControl"; 7267c478bd9Sstevel@tonic-gate attr[1] = 0; 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", 7297c478bd9Sstevel@tonic-gate attr, 0, &lc->searchTimeout, &res); 7307c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 7317c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 7327c478bd9Sstevel@tonic-gate "%s: Unable to retrieve supported control information for %s: %s", 7337c478bd9Sstevel@tonic-gate myself, NIL(lc->sp), ldap_err2string(stat)); 7347c478bd9Sstevel@tonic-gate return (stat); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate e = ldap_first_entry(lc->ld, res); 7387c478bd9Sstevel@tonic-gate if (e != 0) { 7397c478bd9Sstevel@tonic-gate a = ldap_first_attribute(lc->ld, e, &ber); 7407c478bd9Sstevel@tonic-gate if (a != 0) { 7417c478bd9Sstevel@tonic-gate val = ldap_get_values(lc->ld, e, a); 7427c478bd9Sstevel@tonic-gate if (val == 0) { 7437c478bd9Sstevel@tonic-gate ldap_memfree(a); 7447c478bd9Sstevel@tonic-gate if (ber != 0) 7457c478bd9Sstevel@tonic-gate ber_free(ber, 0); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate if (e == 0 || a == 0 || val == 0) { 7507c478bd9Sstevel@tonic-gate ldap_msgfree(res); 7517c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 7527c478bd9Sstevel@tonic-gate "%s: Unable to get root DSE for %s", 7537c478bd9Sstevel@tonic-gate myself, NIL(lc->sp)); 7547c478bd9Sstevel@tonic-gate return (LDAP_OPERATIONS_ERROR); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate while (*ctrl != NULL) { 7587c478bd9Sstevel@tonic-gate *supported = FALSE; 7597c478bd9Sstevel@tonic-gate for (i = 0; val[i] != 0; i++) { 7607c478bd9Sstevel@tonic-gate if (strstr(val[i], *ctrl) != 0) { 7617c478bd9Sstevel@tonic-gate *supported = TRUE; 7627c478bd9Sstevel@tonic-gate break; 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 7667c478bd9Sstevel@tonic-gate "%s: %s: %s: %s", 7677c478bd9Sstevel@tonic-gate myself, NIL(lc->sp), NIL(*ctrl), 7687c478bd9Sstevel@tonic-gate *supported ? "enabled" : "disabled"); 7697c478bd9Sstevel@tonic-gate ctrl++; 7707c478bd9Sstevel@tonic-gate supported++; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate ldap_value_free(val); 7747c478bd9Sstevel@tonic-gate ldap_memfree(a); 7757c478bd9Sstevel@tonic-gate if (ber != 0) 7767c478bd9Sstevel@tonic-gate ber_free(ber, 0); 7777c478bd9Sstevel@tonic-gate ldap_msgfree(res); 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate return (stat); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex', 7847c478bd9Sstevel@tonic-gate * and the refCount must be zero. 7857c478bd9Sstevel@tonic-gate * 7867c478bd9Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 7877c478bd9Sstevel@tonic-gate * the structure in any way. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate static int 7907c478bd9Sstevel@tonic-gate connectCon(__nis_ldap_conn_t *lc, int check_ctrl) { 7917c478bd9Sstevel@tonic-gate struct timeval tp; 7927c478bd9Sstevel@tonic-gate int stat; 7937c478bd9Sstevel@tonic-gate bool_t supported[2] = {FALSE, FALSE}; 7947c478bd9Sstevel@tonic-gate char *ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE, 7957c478bd9Sstevel@tonic-gate LDAP_CONTROL_VLVREQUEST, 7967c478bd9Sstevel@tonic-gate NULL}; 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate if (lc == 0) 7997c478bd9Sstevel@tonic-gate return (LDAP_SUCCESS); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate if (!assertExclusive(lc)) 8027c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate incrementRC(lc); 8057c478bd9Sstevel@tonic-gate if (lc->refCount != 1) { 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Don't want to step on structure when it's used by someone 8087c478bd9Sstevel@tonic-gate * else. 8097c478bd9Sstevel@tonic-gate */ 8107c478bd9Sstevel@tonic-gate decrementRC(lc); 8117c478bd9Sstevel@tonic-gate return (LDAP_BUSY); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate (void) gettimeofday(&tp, 0); 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate if (lc->ld != 0) { 8177c478bd9Sstevel@tonic-gate /* Try to disconnect */ 8187c478bd9Sstevel@tonic-gate lc->doDis++; 8197c478bd9Sstevel@tonic-gate decrementRC(lc); 8207c478bd9Sstevel@tonic-gate /* disconnctCon() will do the delete if required */ 8217c478bd9Sstevel@tonic-gate stat = disconnectCon(lc); 8227c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) 8237c478bd9Sstevel@tonic-gate return (stat); 8247c478bd9Sstevel@tonic-gate incrementRC(lc); 8257c478bd9Sstevel@tonic-gate if (lc->refCount != 1 || lc->ld != 0) { 8267c478bd9Sstevel@tonic-gate decrementRC(lc); 8277c478bd9Sstevel@tonic-gate return (lc->ld != 0) ? LDAP_SUCCESS : 8287c478bd9Sstevel@tonic-gate LDAP_BUSY; 8297c478bd9Sstevel@tonic-gate } 8307c478bd9Sstevel@tonic-gate } else if (tp.tv_sec < lc->retryTime) { 8317c478bd9Sstevel@tonic-gate /* Too early to retry connect */ 8327c478bd9Sstevel@tonic-gate decrementRC(lc); 8337c478bd9Sstevel@tonic-gate return (LDAP_SERVER_DOWN); 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate /* Set new retry time in case we fail below */ 8377c478bd9Sstevel@tonic-gate lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls); 8407c478bd9Sstevel@tonic-gate if (lc->ld == 0) { 8417c478bd9Sstevel@tonic-gate decrementRC(lc); 8427c478bd9Sstevel@tonic-gate return (LDAP_LOCAL_ERROR); 8437c478bd9Sstevel@tonic-gate } 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method, 8467c478bd9Sstevel@tonic-gate lc->bindTimeout); 8477c478bd9Sstevel@tonic-gate if (lc->status == LDAP_SUCCESS) { 8487c478bd9Sstevel@tonic-gate lc->isBound = 1; 8497c478bd9Sstevel@tonic-gate lc->retryTime = 0; 8507c478bd9Sstevel@tonic-gate if (check_ctrl) { 8517c478bd9Sstevel@tonic-gate (void) controlSupported(lc, ctrl, supported); 8527c478bd9Sstevel@tonic-gate lc->simplePage = supported[0]; 8537c478bd9Sstevel@tonic-gate lc->vlv = supported[1]; 8547c478bd9Sstevel@tonic-gate lc->batchFrom = 50000; 8557c478bd9Sstevel@tonic-gate } 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate decrementRC(lc); 8597c478bd9Sstevel@tonic-gate 8607c478bd9Sstevel@tonic-gate return (stat); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate /* 8647c478bd9Sstevel@tonic-gate * Find and return a connection believed to be OK. 8657c478bd9Sstevel@tonic-gate */ 8667c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t * 8677c478bd9Sstevel@tonic-gate findCon(int *stat) { 8687c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc; 8697c478bd9Sstevel@tonic-gate int ldapStat; 8707c478bd9Sstevel@tonic-gate char *myself = "findCon"; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate if (stat == 0) 8737c478bd9Sstevel@tonic-gate stat = &ldapStat; 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate if (ldapCon == 0) { 8787c478bd9Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 8797c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 8807c478bd9Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 8817c478bd9Sstevel@tonic-gate proxyInfo.proxy_dn, 8827c478bd9Sstevel@tonic-gate proxyInfo.proxy_passwd, 8837c478bd9Sstevel@tonic-gate proxyInfo.auth_method)) != 8847c478bd9Sstevel@tonic-gate LDAP_SUCCESS) 8857c478bd9Sstevel@tonic-gate return (0); 8867c478bd9Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 8907c478bd9Sstevel@tonic-gate exclusiveLC(lc); 8917c478bd9Sstevel@tonic-gate if (!lc->isBound) { 8927c478bd9Sstevel@tonic-gate *stat = connectCon(lc, 1); 8937c478bd9Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 8947c478bd9Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 8957c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 8967c478bd9Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 8977c478bd9Sstevel@tonic-gate myself, NIL(lc->sp), 8987c478bd9Sstevel@tonic-gate ldap_err2string(*stat)); 8997c478bd9Sstevel@tonic-gate releaseLC(lc); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate continue; 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 9047c478bd9Sstevel@tonic-gate *stat = disconnectCon(lc); 9057c478bd9Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 9067c478bd9Sstevel@tonic-gate releaseLC(lc); 9077c478bd9Sstevel@tonic-gate continue; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate incrementRC(lc); 9107c478bd9Sstevel@tonic-gate releaseLC(lc); 9117c478bd9Sstevel@tonic-gate break; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate return (lc); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* Release connection; decrements ref count for the connection */ 9207c478bd9Sstevel@tonic-gate static void 9217c478bd9Sstevel@tonic-gate releaseCon(__nis_ldap_conn_t *lc, int status) { 9227c478bd9Sstevel@tonic-gate int stat; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate if (lc == 0) 9257c478bd9Sstevel@tonic-gate return; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate exclusiveLC(lc); 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate lc->status = status; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate decrementRC(lc); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate if (lc->doDis) 9347c478bd9Sstevel@tonic-gate stat = disconnectCon(lc); 9357c478bd9Sstevel@tonic-gate else 9367c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 9377c478bd9Sstevel@tonic-gate 9387c478bd9Sstevel@tonic-gate if (stat != LDAP_UNAVAILABLE) 9397c478bd9Sstevel@tonic-gate releaseLC(lc); 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t * 9437c478bd9Sstevel@tonic-gate createCon(char *sp, char *who, char *cred, auth_method_t method, int port) { 9447c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc; 9457c478bd9Sstevel@tonic-gate char *myself = "createCon"; 9467c478bd9Sstevel@tonic-gate char *r; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (sp == 0) 9497c478bd9Sstevel@tonic-gate return (0); 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate lc = am(myself, sizeof (*lc)); 9527c478bd9Sstevel@tonic-gate if (lc == 0) 9537c478bd9Sstevel@tonic-gate return (0); 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate (void) mutex_init(&lc->mutex, 0, 0); 9567c478bd9Sstevel@tonic-gate (void) mutex_init(&lc->rcMutex, 0, 0); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate /* If we need to delete 'lc', freeCon() wants the mutex held */ 9597c478bd9Sstevel@tonic-gate exclusiveLC(lc); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate lc->sp = sdup(myself, T, sp); 9627c478bd9Sstevel@tonic-gate if (lc->sp == 0) { 9637c478bd9Sstevel@tonic-gate (void) freeCon(lc); 9647c478bd9Sstevel@tonic-gate return (0); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate if ((r = strchr(lc->sp, ']')) != 0) { 9687c478bd9Sstevel@tonic-gate /* 9697c478bd9Sstevel@tonic-gate * IPv6 address. Does libldap want this with the 9707c478bd9Sstevel@tonic-gate * '[' and ']' left in place ? Assume so for now. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate r = strchr(r, ':'); 9737c478bd9Sstevel@tonic-gate } else { 9747c478bd9Sstevel@tonic-gate r = strchr(lc->sp, ':'); 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate if (r != NULL) { 9787c478bd9Sstevel@tonic-gate *r++ = '\0'; 9797c478bd9Sstevel@tonic-gate port = atoi(r); 9807c478bd9Sstevel@tonic-gate } else if (port == 0) 9817c478bd9Sstevel@tonic-gate port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT; 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate if (who != 0) { 9847c478bd9Sstevel@tonic-gate lc->who = sdup(myself, T, who); 9857c478bd9Sstevel@tonic-gate if (lc->who == 0) { 9867c478bd9Sstevel@tonic-gate (void) freeCon(lc); 9877c478bd9Sstevel@tonic-gate return (0); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate if (cred != 0) { 9927c478bd9Sstevel@tonic-gate lc->cred = sdup(myself, T, cred); 9937c478bd9Sstevel@tonic-gate if (lc->cred == 0) { 9947c478bd9Sstevel@tonic-gate (void) freeCon(lc); 9957c478bd9Sstevel@tonic-gate return (0); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate lc->method = method; 10007c478bd9Sstevel@tonic-gate lc->port = port; 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate lc->bindTimeout = proxyInfo.bind_timeout; 10037c478bd9Sstevel@tonic-gate lc->searchTimeout = proxyInfo.search_timeout; 10047c478bd9Sstevel@tonic-gate lc->modifyTimeout = proxyInfo.modify_timeout; 10057c478bd9Sstevel@tonic-gate lc->addTimeout = proxyInfo.add_timeout; 10067c478bd9Sstevel@tonic-gate lc->deleteTimeout = proxyInfo.delete_timeout; 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate /* All other fields OK at zero */ 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate releaseLC(lc); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate return (lc); 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate static int 10167c478bd9Sstevel@tonic-gate setupConList(char *serverList, char *who, char *cred, auth_method_t method) { 10177c478bd9Sstevel@tonic-gate char *sls, *sl, *s, *e; 10187c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc, *tmp; 10197c478bd9Sstevel@tonic-gate char *myself = "setupConList"; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate if (serverList == 0) 10227c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate (void) rw_wrlock(&ldapConLock); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate if (ldapCon != 0) { 10277c478bd9Sstevel@tonic-gate /* Assume we've already been called and done the set-up */ 10287c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10297c478bd9Sstevel@tonic-gate return (LDAP_SUCCESS); 10307c478bd9Sstevel@tonic-gate } 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* Work on a copy of 'serverList' */ 10337c478bd9Sstevel@tonic-gate sl = sls = sdup(myself, T, serverList); 10347c478bd9Sstevel@tonic-gate if (sl == 0) { 10357c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10367c478bd9Sstevel@tonic-gate return (LDAP_NO_MEMORY); 10377c478bd9Sstevel@tonic-gate } 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* Remove leading white space */ 10407c478bd9Sstevel@tonic-gate for (0; *sl == ' ' || *sl == '\t'; sl++); 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate /* Create connection for each server on the list */ 10437c478bd9Sstevel@tonic-gate for (s = sl; *s != '\0'; s = e+1) { 10447c478bd9Sstevel@tonic-gate int l; 10457c478bd9Sstevel@tonic-gate 10467c478bd9Sstevel@tonic-gate /* Find end of server/port token */ 10477c478bd9Sstevel@tonic-gate for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++); 10487c478bd9Sstevel@tonic-gate if (*e != '\0') 10497c478bd9Sstevel@tonic-gate *e = '\0'; 10507c478bd9Sstevel@tonic-gate else 10517c478bd9Sstevel@tonic-gate e--; 10527c478bd9Sstevel@tonic-gate l = slen(s); 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate if (l > 0) { 10557c478bd9Sstevel@tonic-gate lc = createCon(s, who, cred, method, 0); 10567c478bd9Sstevel@tonic-gate if (lc == 0) { 10577c478bd9Sstevel@tonic-gate free(sls); 10587c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10597c478bd9Sstevel@tonic-gate return (LDAP_NO_MEMORY); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate lc->onList = 1; 10627c478bd9Sstevel@tonic-gate if (ldapCon == 0) { 10637c478bd9Sstevel@tonic-gate ldapCon = lc; 10647c478bd9Sstevel@tonic-gate } else { 10657c478bd9Sstevel@tonic-gate /* Insert at end of list */ 10667c478bd9Sstevel@tonic-gate for (tmp = ldapCon; tmp->next != 0; 10677c478bd9Sstevel@tonic-gate tmp = tmp->next); 10687c478bd9Sstevel@tonic-gate tmp->next = lc; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate free(sls); 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate return (LDAP_SUCCESS); 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate static bool_t 10817c478bd9Sstevel@tonic-gate is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp) 10827c478bd9Sstevel@tonic-gate { 10837c478bd9Sstevel@tonic-gate return (strcasecmp(ludpp->lud_host, lc->sp) == 0 && 10847c478bd9Sstevel@tonic-gate ludpp->lud_port == lc->port); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t * 10887c478bd9Sstevel@tonic-gate find_connection_from_list(__nis_ldap_conn_t *list, 10897c478bd9Sstevel@tonic-gate LDAPURLDesc *ludpp, int *stat) 10907c478bd9Sstevel@tonic-gate { 10917c478bd9Sstevel@tonic-gate int ldapStat; 10927c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 10937c478bd9Sstevel@tonic-gate if (stat == 0) 10947c478bd9Sstevel@tonic-gate stat = &ldapStat; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate *stat = LDAP_SUCCESS; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate for (lc = list; lc != 0; lc = lc->next) { 10997c478bd9Sstevel@tonic-gate exclusiveLC(lc); 11007c478bd9Sstevel@tonic-gate if (is_same_connection(lc, ludpp)) { 11017c478bd9Sstevel@tonic-gate if (!lc->isBound) { 11027c478bd9Sstevel@tonic-gate *stat = connectCon(lc, 1); 11037c478bd9Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 11047c478bd9Sstevel@tonic-gate releaseLC(lc); 11057c478bd9Sstevel@tonic-gate continue; 11067c478bd9Sstevel@tonic-gate } 11077c478bd9Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 11087c478bd9Sstevel@tonic-gate (void) disconnectCon(lc); 11097c478bd9Sstevel@tonic-gate releaseLC(lc); 11107c478bd9Sstevel@tonic-gate continue; 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate incrementRC(lc); 11137c478bd9Sstevel@tonic-gate releaseLC(lc); 11147c478bd9Sstevel@tonic-gate break; 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate releaseLC(lc); 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate return (lc); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t * 11227c478bd9Sstevel@tonic-gate findReferralCon(char **referralsp, int *stat) 11237c478bd9Sstevel@tonic-gate { 11247c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 11257c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *tmp; 11267c478bd9Sstevel@tonic-gate int ldapStat; 11277c478bd9Sstevel@tonic-gate int i; 11287c478bd9Sstevel@tonic-gate LDAPURLDesc *ludpp = NULL; 11297c478bd9Sstevel@tonic-gate char *myself = "findReferralCon"; 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate if (stat == 0) 11327c478bd9Sstevel@tonic-gate stat = &ldapStat; 11337c478bd9Sstevel@tonic-gate 11347c478bd9Sstevel@tonic-gate *stat = LDAP_SUCCESS; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* 11377c478bd9Sstevel@tonic-gate * We have the referral lock - to prevent multiple 11387c478bd9Sstevel@tonic-gate * threads from creating a referred connection simultaneously 11397c478bd9Sstevel@tonic-gate * 11407c478bd9Sstevel@tonic-gate * Note that this code assumes that the ldapCon list is a 11417c478bd9Sstevel@tonic-gate * static list - that it has previously been created 11427c478bd9Sstevel@tonic-gate * (otherwise we wouldn't have gotten a referral) and that 11437c478bd9Sstevel@tonic-gate * it will neither grow or shrink - elements may have new 11447c478bd9Sstevel@tonic-gate * connections or unbound. If this assumption is no longer valid, 11457c478bd9Sstevel@tonic-gate * the locking needs to be reworked. 11467c478bd9Sstevel@tonic-gate */ 11477c478bd9Sstevel@tonic-gate (void) rw_rdlock(&referralConLock); 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 11507c478bd9Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 11517c478bd9Sstevel@tonic-gate continue; 11527c478bd9Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 11537c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 11547c478bd9Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 11557c478bd9Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 11567c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11577c478bd9Sstevel@tonic-gate continue; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate } else { 11607c478bd9Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 11617c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11627c478bd9Sstevel@tonic-gate continue; 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate #endif 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate /* Determine if we already have a connection to the server */ 11687c478bd9Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 11697c478bd9Sstevel@tonic-gate if (lc == NULL) 11707c478bd9Sstevel@tonic-gate lc = find_connection_from_list(ldapCon, ludpp, stat); 11717c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11727c478bd9Sstevel@tonic-gate if (lc != NULL) { 11737c478bd9Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 11747c478bd9Sstevel@tonic-gate return (lc); 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 11797c478bd9Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 11807c478bd9Sstevel@tonic-gate continue; 11817c478bd9Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 11827c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 11837c478bd9Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 11847c478bd9Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 11857c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11867c478bd9Sstevel@tonic-gate continue; 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate } else { 11897c478bd9Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 11907c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11917c478bd9Sstevel@tonic-gate continue; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate #endif 11957c478bd9Sstevel@tonic-gate lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn, 11967c478bd9Sstevel@tonic-gate proxyInfo.proxy_passwd, 11977c478bd9Sstevel@tonic-gate proxyInfo.auth_method, 11987c478bd9Sstevel@tonic-gate ludpp->lud_port); 11997c478bd9Sstevel@tonic-gate if (lc == 0) { 12007c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 12017c478bd9Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 12027c478bd9Sstevel@tonic-gate *stat = LDAP_NO_MEMORY; 12037c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 12047c478bd9Sstevel@tonic-gate "%s: Could not connect to host: %s", 12057c478bd9Sstevel@tonic-gate myself, NIL(ludpp->lud_host)); 12067c478bd9Sstevel@tonic-gate return (NULL); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate lc->onList = 1; 12107c478bd9Sstevel@tonic-gate if (ldapReferralCon == 0) { 12117c478bd9Sstevel@tonic-gate ldapReferralCon = lc; 12127c478bd9Sstevel@tonic-gate } else { 12137c478bd9Sstevel@tonic-gate /* Insert at end of list */ 12147c478bd9Sstevel@tonic-gate for (tmp = ldapReferralCon; tmp->next != 0; 12157c478bd9Sstevel@tonic-gate tmp = tmp->next) {} 12167c478bd9Sstevel@tonic-gate tmp->next = lc; 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 12197c478bd9Sstevel@tonic-gate ldap_free_urldesc(ludpp); 12207c478bd9Sstevel@tonic-gate if (lc != NULL) 12217c478bd9Sstevel@tonic-gate break; 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 12247c478bd9Sstevel@tonic-gate if (lc == NULL) { 12257c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 12267c478bd9Sstevel@tonic-gate "%s: Could not find a connection to %s, ...", 12277c478bd9Sstevel@tonic-gate myself, NIL(referralsp[0])); 12287c478bd9Sstevel@tonic-gate } 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate return (lc); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate /* 12347c478bd9Sstevel@tonic-gate * Find and return a connection believed to be OK and ensure children 12357c478bd9Sstevel@tonic-gate * will never use parent's connection. 12367c478bd9Sstevel@tonic-gate */ 12377c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t * 12387c478bd9Sstevel@tonic-gate findYPCon(__nis_ldap_search_t *ls, int *stat) { 12397c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc, *newlc; 12407c478bd9Sstevel@tonic-gate int ldapStat, newstat; 12417c478bd9Sstevel@tonic-gate char *myself = "findYPCon"; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate if (stat == 0) 12447c478bd9Sstevel@tonic-gate stat = &ldapStat; 12457c478bd9Sstevel@tonic-gate 12467c478bd9Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate if (ldapCon == 0) { 12497c478bd9Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 12507c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 12517c478bd9Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 12527c478bd9Sstevel@tonic-gate proxyInfo.proxy_dn, 12537c478bd9Sstevel@tonic-gate proxyInfo.proxy_passwd, 12547c478bd9Sstevel@tonic-gate proxyInfo.auth_method)) != 12557c478bd9Sstevel@tonic-gate LDAP_SUCCESS) 12567c478bd9Sstevel@tonic-gate return (0); 12577c478bd9Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 12617c478bd9Sstevel@tonic-gate exclusiveLC(lc); 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate if (lc->isBound && (lc->doDis || lc->doDel)) { 12647c478bd9Sstevel@tonic-gate *stat = disconnectCon(lc); 12657c478bd9Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 12667c478bd9Sstevel@tonic-gate releaseLC(lc); 12677c478bd9Sstevel@tonic-gate continue; 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Use a new connection for all cases except when 12727c478bd9Sstevel@tonic-gate * requested by the main thread in the parent ypserv 12737c478bd9Sstevel@tonic-gate * process. 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate if (ls->useCon == 0) { 12767c478bd9Sstevel@tonic-gate newlc = createCon(lc->sp, lc->who, lc->cred, 12777c478bd9Sstevel@tonic-gate lc->method, lc->port); 12787c478bd9Sstevel@tonic-gate if (!newlc) { 12797c478bd9Sstevel@tonic-gate releaseLC(lc); 12807c478bd9Sstevel@tonic-gate continue; 12817c478bd9Sstevel@tonic-gate } 12827c478bd9Sstevel@tonic-gate if (lc->ld != 0) { 12837c478bd9Sstevel@tonic-gate newlc->simplePage = lc->simplePage; 12847c478bd9Sstevel@tonic-gate newlc->vlv = lc->vlv; 12857c478bd9Sstevel@tonic-gate newlc->batchFrom = lc->batchFrom; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate releaseLC(lc); 12887c478bd9Sstevel@tonic-gate exclusiveLC(newlc); 12897c478bd9Sstevel@tonic-gate newstat = connectCon(newlc, 0); 12907c478bd9Sstevel@tonic-gate if (newstat != LDAP_SUCCESS) { 12917c478bd9Sstevel@tonic-gate if (newstat != LDAP_UNAVAILABLE) { 12927c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 12937c478bd9Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 12947c478bd9Sstevel@tonic-gate myself, NIL(newlc->sp), 12957c478bd9Sstevel@tonic-gate ldap_err2string(*stat)); 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate (void) freeCon(newlc); 12987c478bd9Sstevel@tonic-gate newlc = 0; 12997c478bd9Sstevel@tonic-gate continue; 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * No need to put newlc on the ldapCon list as this 13047c478bd9Sstevel@tonic-gate * connection will be freed after use. 13057c478bd9Sstevel@tonic-gate */ 13067c478bd9Sstevel@tonic-gate newlc->onList = 0; 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate lc = newlc; 13097c478bd9Sstevel@tonic-gate } else if (!lc->isBound) { 13107c478bd9Sstevel@tonic-gate *stat = connectCon(lc, 1); 13117c478bd9Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 13127c478bd9Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 13137c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 13147c478bd9Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 13157c478bd9Sstevel@tonic-gate myself, NIL(lc->sp), 13167c478bd9Sstevel@tonic-gate ldap_err2string(*stat)); 13177c478bd9Sstevel@tonic-gate releaseLC(lc); 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate continue; 13207c478bd9Sstevel@tonic-gate } 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate incrementRC(lc); 13247c478bd9Sstevel@tonic-gate releaseLC(lc); 13257c478bd9Sstevel@tonic-gate break; 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate return (lc); 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate #define SORTKEYLIST "cn uid" 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* 13367c478bd9Sstevel@tonic-gate * Perform an LDAP search operation per 'ls', adding the result(s) to 13377c478bd9Sstevel@tonic-gate * a copy of the 'rvIn' structure; the copy becomes the return value. 13387c478bd9Sstevel@tonic-gate * The caller must deallocate both 'rvIn' and the result, if any. 13397c478bd9Sstevel@tonic-gate * 13407c478bd9Sstevel@tonic-gate * On entry, '*numValues' contains a hint regarding the expected 13417c478bd9Sstevel@tonic-gate * number of entries. Zero is the same as one, and negative values 13427c478bd9Sstevel@tonic-gate * imply no information. This is used to decide whether or not to 13437c478bd9Sstevel@tonic-gate * try an indexed search. 13447c478bd9Sstevel@tonic-gate * 13457c478bd9Sstevel@tonic-gate * On successful (non-NULL) return, '*numValues' contains the number 13467c478bd9Sstevel@tonic-gate * of __nis_rule_value_t elements in the returned array, and '*stat' 13477c478bd9Sstevel@tonic-gate * the LDAP operations status. 13487c478bd9Sstevel@tonic-gate */ 13497c478bd9Sstevel@tonic-gate __nis_rule_value_t * 13507c478bd9Sstevel@tonic-gate ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn, 13517c478bd9Sstevel@tonic-gate int *ldapStat) { 13527c478bd9Sstevel@tonic-gate __nis_rule_value_t *rv = 0; 13537c478bd9Sstevel@tonic-gate int stat, numEntries, numVals, tnv, done, lprEc; 13547c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0, *m; 13557c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc; 13567c478bd9Sstevel@tonic-gate struct timeval tv, start, now; 13577c478bd9Sstevel@tonic-gate LDAPsortkey **sortKeyList = 0; 13587c478bd9Sstevel@tonic-gate LDAPControl *ctrls[3], *sortCtrl = 0, *vlvCtrl = 0; 13597c478bd9Sstevel@tonic-gate LDAPControl **retCtrls = 0; 13607c478bd9Sstevel@tonic-gate LDAPVirtualList vList; 13617c478bd9Sstevel@tonic-gate struct berval *spCookie = 0; 13627c478bd9Sstevel@tonic-gate int doVLV = 0; 13637c478bd9Sstevel@tonic-gate int doSP = 0; 13647c478bd9Sstevel@tonic-gate long index; 13657c478bd9Sstevel@tonic-gate char *myself = "ldapSearch"; 13667c478bd9Sstevel@tonic-gate bool_t follow_referral = 13677c478bd9Sstevel@tonic-gate proxyInfo.follow_referral == follow; 13687c478bd9Sstevel@tonic-gate int doIndex = 1; 13697c478bd9Sstevel@tonic-gate char **referralsp = NULL; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate if (ldapStat == 0) 13727c478bd9Sstevel@tonic-gate ldapStat = &stat; 13737c478bd9Sstevel@tonic-gate 13747c478bd9Sstevel@tonic-gate if (ls == 0) { 13757c478bd9Sstevel@tonic-gate *ldapStat = LDAP_PARAM_ERROR; 13767c478bd9Sstevel@tonic-gate return (0); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate if (yp2ldap) { 13807c478bd9Sstevel@tonic-gate /* make sure the parent's connection is not used by child */ 13817c478bd9Sstevel@tonic-gate if ((lc = findYPCon(ls, ldapStat)) == 0) { 13827c478bd9Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 13837c478bd9Sstevel@tonic-gate return (0); 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate } else { 13867c478bd9Sstevel@tonic-gate if ((lc = findCon(ldapStat)) == 0) { 13877c478bd9Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 13887c478bd9Sstevel@tonic-gate return (0); 13897c478bd9Sstevel@tonic-gate } 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate 13927c478bd9Sstevel@tonic-gate if (numValues != 0 && (*numValues == 0 || *numValues == 1)) 13937c478bd9Sstevel@tonic-gate doIndex = 0; 13947c478bd9Sstevel@tonic-gate 13957c478bd9Sstevel@tonic-gate retry_new_conn: 13967c478bd9Sstevel@tonic-gate /* Prefer VLV over simple page, and SP over nothing */ 13977c478bd9Sstevel@tonic-gate if (doIndex && lc->vlv) { 13987c478bd9Sstevel@tonic-gate stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST); 13997c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 14007c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14017c478bd9Sstevel@tonic-gate "%s: Error creating sort keylist: %s", 14027c478bd9Sstevel@tonic-gate myself, ldap_err2string(stat)); 14037c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 14047c478bd9Sstevel@tonic-gate *ldapStat = stat; 14057c478bd9Sstevel@tonic-gate rv = 0; 14067c478bd9Sstevel@tonic-gate goto retry_noVLV; 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate stat = ldap_create_sort_control(lc->ld, sortKeyList, 1, 14097c478bd9Sstevel@tonic-gate &sortCtrl); 14107c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 14117c478bd9Sstevel@tonic-gate vList.ldvlist_before_count = 0; 14127c478bd9Sstevel@tonic-gate vList.ldvlist_after_count = lc->batchFrom - 1; 14137c478bd9Sstevel@tonic-gate vList.ldvlist_attrvalue = 0; 14147c478bd9Sstevel@tonic-gate vList.ldvlist_extradata = 0; 14157c478bd9Sstevel@tonic-gate index = 1; 14167c478bd9Sstevel@tonic-gate doVLV = 1; 14177c478bd9Sstevel@tonic-gate } else { 14187c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 14197c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14207c478bd9Sstevel@tonic-gate "%s: Error creating VLV sort control: %s", 14217c478bd9Sstevel@tonic-gate myself, ldap_err2string(stat)); 14227c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 14237c478bd9Sstevel@tonic-gate *ldapStat = stat; 14247c478bd9Sstevel@tonic-gate rv = 0; 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate } 14277c478bd9Sstevel@tonic-gate 14287c478bd9Sstevel@tonic-gate retry_noVLV: 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate if (doIndex && !doVLV && lc->simplePage) { 14317c478bd9Sstevel@tonic-gate spCookie = am(myself, sizeof (*spCookie)); 14327c478bd9Sstevel@tonic-gate if (spCookie != 0 && 14337c478bd9Sstevel@tonic-gate (spCookie->bv_val = sdup(myself, T, "")) != 0) { 14347c478bd9Sstevel@tonic-gate spCookie->bv_len = 0; 14357c478bd9Sstevel@tonic-gate doSP = 1; 14367c478bd9Sstevel@tonic-gate } else { 14377c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14387c478bd9Sstevel@tonic-gate "%s: No memory for simple page cookie; using un-paged LDAP search", 14397c478bd9Sstevel@tonic-gate myself); 14407c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 14417c478bd9Sstevel@tonic-gate *ldapStat = stat; 14427c478bd9Sstevel@tonic-gate rv = 0; 14437c478bd9Sstevel@tonic-gate goto cleanup; 14447c478bd9Sstevel@tonic-gate } 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate 14477c478bd9Sstevel@tonic-gate if (!doVLV && !doSP) 14487c478bd9Sstevel@tonic-gate ctrls[0] = ctrls[1] = 0; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate numVals = 0; 14517c478bd9Sstevel@tonic-gate done = 0; 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (ls->timeout.tv_sec || ls->timeout.tv_usec) { 14547c478bd9Sstevel@tonic-gate tv = ls->timeout; 14557c478bd9Sstevel@tonic-gate } else { 14567c478bd9Sstevel@tonic-gate tv = lc->searchTimeout; 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate (void) gettimeofday(&start, 0); 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate do { 14617c478bd9Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 14627c478bd9Sstevel@tonic-gate if (doVLV && ls->base != LDAP_SCOPE_BASE) { 14637c478bd9Sstevel@tonic-gate vList.ldvlist_index = index; 14647c478bd9Sstevel@tonic-gate vList.ldvlist_size = 0; 14657c478bd9Sstevel@tonic-gate if (vlvCtrl != 0) 14667c478bd9Sstevel@tonic-gate ldap_control_free(vlvCtrl); 14677c478bd9Sstevel@tonic-gate stat = ldap_create_virtuallist_control(lc->ld, 14687c478bd9Sstevel@tonic-gate &vList, &vlvCtrl); 14697c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 14707c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 14717c478bd9Sstevel@tonic-gate &stat); 14727c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 14737c478bd9Sstevel@tonic-gate "%s: Error creating VLV at index %ld: %s", 14747c478bd9Sstevel@tonic-gate myself, index, ldap_err2string(stat)); 14757c478bd9Sstevel@tonic-gate *ldapStat = stat; 14767c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 14777c478bd9Sstevel@tonic-gate rv = 0; 14787c478bd9Sstevel@tonic-gate goto cleanup; 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate ctrls[0] = sortCtrl; 14817c478bd9Sstevel@tonic-gate ctrls[1] = vlvCtrl; 14827c478bd9Sstevel@tonic-gate ctrls[2] = 0; 14837c478bd9Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 14847c478bd9Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 14857c478bd9Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 14867c478bd9Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 14877c478bd9Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 14887c478bd9Sstevel@tonic-gate } else if (doSP && ls->base != LDAP_SCOPE_BASE) { 14897c478bd9Sstevel@tonic-gate if (ctrls[0] != 0) 14907c478bd9Sstevel@tonic-gate ldap_control_free(ctrls[0]); 14917c478bd9Sstevel@tonic-gate stat = ldap_create_page_control(lc->ld, 14927c478bd9Sstevel@tonic-gate lc->batchFrom, spCookie, 0, &ctrls[0]); 14937c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 14947c478bd9Sstevel@tonic-gate ber_bvfree(spCookie); 14957c478bd9Sstevel@tonic-gate spCookie = 0; 14967c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 14977c478bd9Sstevel@tonic-gate &stat); 14987c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 14997c478bd9Sstevel@tonic-gate "%s: Simple page error: %s", 15007c478bd9Sstevel@tonic-gate myself, ldap_err2string(stat)); 15017c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 15027c478bd9Sstevel@tonic-gate *ldapStat = stat; 15037c478bd9Sstevel@tonic-gate rv = 0; 15047c478bd9Sstevel@tonic-gate goto cleanup; 15057c478bd9Sstevel@tonic-gate } 15067c478bd9Sstevel@tonic-gate ctrls[1] = 0; 15077c478bd9Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 15087c478bd9Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 15097c478bd9Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 15107c478bd9Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 15117c478bd9Sstevel@tonic-gate } else { 15127c478bd9Sstevel@tonic-gate stat = ldap_search_st(lc->ld, ls->base, ls->scope, 15137c478bd9Sstevel@tonic-gate ls->filter, ls->attrs, ls->attrsonly, 15147c478bd9Sstevel@tonic-gate &tv, &msg); 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 15177c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate if (stat == LDAP_SERVER_DOWN) { 15207c478bd9Sstevel@tonic-gate lc->doDis++; 15217c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 15227c478bd9Sstevel@tonic-gate lc = (yp2ldap)?findYPCon(ls, ldapStat): 15237c478bd9Sstevel@tonic-gate findCon(ldapStat); 15247c478bd9Sstevel@tonic-gate if (lc == 0) { 15257c478bd9Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 15267c478bd9Sstevel@tonic-gate rv = 0; 15277c478bd9Sstevel@tonic-gate goto cleanup; 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate goto retry_new_conn; 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate 15327c478bd9Sstevel@tonic-gate if (stat == LDAP_REFERRAL && follow_referral) { 15337c478bd9Sstevel@tonic-gate (void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL, 15347c478bd9Sstevel@tonic-gate &referralsp, NULL, 0); 15357c478bd9Sstevel@tonic-gate if (referralsp != NULL) { 15367c478bd9Sstevel@tonic-gate /* We support at most one level of referrals */ 15377c478bd9Sstevel@tonic-gate follow_referral = FALSE; 15387c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 15397c478bd9Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 15407c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 15417c478bd9Sstevel@tonic-gate if (lc == NULL) { 15427c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 15437c478bd9Sstevel@tonic-gate rv = 0; 15447c478bd9Sstevel@tonic-gate *ldapStat = stat; 15457c478bd9Sstevel@tonic-gate goto cleanup; 15467c478bd9Sstevel@tonic-gate } 15477c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 15487c478bd9Sstevel@tonic-gate goto retry_new_conn; 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate } 15517c478bd9Sstevel@tonic-gate *ldapStat = stat; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if (*ldapStat == LDAP_NO_SUCH_OBJECT) { 15547c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 15557c478bd9Sstevel@tonic-gate rv = 0; 15567c478bd9Sstevel@tonic-gate goto cleanup; 15577c478bd9Sstevel@tonic-gate } else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) { 15587c478bd9Sstevel@tonic-gate /* 15597c478bd9Sstevel@tonic-gate * The LDAP server (at least Netscape 4.x) can return 15607c478bd9Sstevel@tonic-gate * LDAP_INSUFFICIENT_ACCESS when VLV is supported, 15617c478bd9Sstevel@tonic-gate * but not for the bind DN specified. So, just in 15627c478bd9Sstevel@tonic-gate * case, we clean up, and try again without VLV. 15637c478bd9Sstevel@tonic-gate */ 15647c478bd9Sstevel@tonic-gate doVLV = 0; 15657c478bd9Sstevel@tonic-gate if (msg != 0) { 15667c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 15677c478bd9Sstevel@tonic-gate msg = 0; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate if (ctrls[0] != 0) { 15707c478bd9Sstevel@tonic-gate ldap_control_free(ctrls[0]); 15717c478bd9Sstevel@tonic-gate ctrls[0] = 0; 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate if (ctrls[1] != 0) { 15747c478bd9Sstevel@tonic-gate ldap_control_free(ctrls[1]); 15757c478bd9Sstevel@tonic-gate ctrls[1] = 0; 15767c478bd9Sstevel@tonic-gate } 15777c478bd9Sstevel@tonic-gate logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING, 15787c478bd9Sstevel@tonic-gate "%s: VLV insufficient access from server %s; retrying without VLV", 15797c478bd9Sstevel@tonic-gate myself, NIL(lc->sp)); 15807c478bd9Sstevel@tonic-gate goto retry_noVLV; 15817c478bd9Sstevel@tonic-gate } else if (*ldapStat != LDAP_SUCCESS) { 15827c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 15837c478bd9Sstevel@tonic-gate "ldap_search(0x%x,\n\t\"%s\",\n\t %d,", 15847c478bd9Sstevel@tonic-gate lc->ld, NIL(ls->base), ls->scope); 15857c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 15867c478bd9Sstevel@tonic-gate "\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)", 15877c478bd9Sstevel@tonic-gate NIL(ls->filter), ls->attrs, ls->attrsonly, 15887c478bd9Sstevel@tonic-gate *ldapStat, ldap_err2string(stat)); 15897c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 15907c478bd9Sstevel@tonic-gate rv = 0; 15917c478bd9Sstevel@tonic-gate goto cleanup; 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate 15947c478bd9Sstevel@tonic-gate numEntries = ldap_count_entries(lc->ld, msg); 15957c478bd9Sstevel@tonic-gate if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) { 15967c478bd9Sstevel@tonic-gate /* 15977c478bd9Sstevel@tonic-gate * This is a bit weird, but the server (or, at least, 15987c478bd9Sstevel@tonic-gate * ldap_search_ext()) can sometimes return 15997c478bd9Sstevel@tonic-gate * LDAP_SUCCESS and no entries when it didn't 16007c478bd9Sstevel@tonic-gate * find what we were looking for. Seems it ought to 16017c478bd9Sstevel@tonic-gate * return LDAP_NO_SUCH_OBJECT or some such. 16027c478bd9Sstevel@tonic-gate */ 16037c478bd9Sstevel@tonic-gate freeRuleValue(rv, numVals); 16047c478bd9Sstevel@tonic-gate rv = 0; 16057c478bd9Sstevel@tonic-gate *ldapStat = LDAP_NO_SUCH_OBJECT; 16067c478bd9Sstevel@tonic-gate goto cleanup; 16077c478bd9Sstevel@tonic-gate } 16087c478bd9Sstevel@tonic-gate 16097c478bd9Sstevel@tonic-gate tnv = numVals + numEntries; 16107c478bd9Sstevel@tonic-gate if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) { 16117c478bd9Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16127c478bd9Sstevel@tonic-gate goto cleanup; 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate for (m = ldap_first_entry(lc->ld, msg); m != 0; 16167c478bd9Sstevel@tonic-gate m = ldap_next_entry(lc->ld, m), numVals++) { 16177c478bd9Sstevel@tonic-gate char *nm; 16187c478bd9Sstevel@tonic-gate BerElement *ber = 0; 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate if (numVals > tnv) { 16217c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 16227c478bd9Sstevel@tonic-gate "%s: Inconsistent LDAP entry count > %d", 16237c478bd9Sstevel@tonic-gate myself, numEntries); 16247c478bd9Sstevel@tonic-gate break; 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate 16277c478bd9Sstevel@tonic-gate nm = ldap_get_dn(lc->ld, m); 16287c478bd9Sstevel@tonic-gate if (nm == 0 || addSAttr2RuleValue("dn", nm, 16297c478bd9Sstevel@tonic-gate &rv[numVals])) { 16307c478bd9Sstevel@tonic-gate sfree(nm); 16317c478bd9Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16327c478bd9Sstevel@tonic-gate freeRuleValue(rv, tnv); 16337c478bd9Sstevel@tonic-gate rv = 0; 16347c478bd9Sstevel@tonic-gate goto cleanup; 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate sfree(nm); 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate for (nm = ldap_first_attribute(lc->ld, m, &ber); 16397c478bd9Sstevel@tonic-gate nm != 0; 16407c478bd9Sstevel@tonic-gate nm = ldap_next_attribute(lc->ld, m, ber)) { 16417c478bd9Sstevel@tonic-gate struct berval **val; 16427c478bd9Sstevel@tonic-gate int i, nv; 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate val = ldap_get_values_len(lc->ld, m, nm); 16457c478bd9Sstevel@tonic-gate nv = (val == 0) ? 0 : 16467c478bd9Sstevel@tonic-gate ldap_count_values_len(val); 16477c478bd9Sstevel@tonic-gate for (i = 0; i < nv; i++) { 16487c478bd9Sstevel@tonic-gate /* 16497c478bd9Sstevel@tonic-gate * Since we don't know if the value is 16507c478bd9Sstevel@tonic-gate * BER-encoded or not, we mark it as a 16517c478bd9Sstevel@tonic-gate * string. All is well as long as we 16527c478bd9Sstevel@tonic-gate * don't insist on 'vt_ber' when 16537c478bd9Sstevel@tonic-gate * interpreting. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate if (addAttr2RuleValue(vt_string, nm, 16567c478bd9Sstevel@tonic-gate val[i]->bv_val, 16577c478bd9Sstevel@tonic-gate val[i]->bv_len, 16587c478bd9Sstevel@tonic-gate &rv[numVals])) { 16597c478bd9Sstevel@tonic-gate if (ber != 0) 16607c478bd9Sstevel@tonic-gate ber_free(ber, 0); 16617c478bd9Sstevel@tonic-gate ldap_value_free_len(val); 16627c478bd9Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16637c478bd9Sstevel@tonic-gate freeRuleValue(rv, tnv); 16647c478bd9Sstevel@tonic-gate rv = 0; 16657c478bd9Sstevel@tonic-gate goto cleanup; 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate } 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * XXX the ldap_first_attribute(3LDAP) man 16707c478bd9Sstevel@tonic-gate * page says that the ldap_first_attribute/ 16717c478bd9Sstevel@tonic-gate * ldap_next_attribute should be treated as 16727c478bd9Sstevel@tonic-gate * static, but the libldap.so.4 code mallocs 16737c478bd9Sstevel@tonic-gate * (and it's not TSD). So, in order to avoid 16747c478bd9Sstevel@tonic-gate * a leak, we free the return value. 16757c478bd9Sstevel@tonic-gate */ 16767c478bd9Sstevel@tonic-gate ldap_memfree(nm); 16777c478bd9Sstevel@tonic-gate if (val != 0) 16787c478bd9Sstevel@tonic-gate ldap_value_free_len(val); 16797c478bd9Sstevel@tonic-gate } 16807c478bd9Sstevel@tonic-gate /* 16817c478bd9Sstevel@tonic-gate * XXX ldap_next_attribute(3LDAP) says that the 'ber' 16827c478bd9Sstevel@tonic-gate * pointer is freed when it returns NULL, but that's 16837c478bd9Sstevel@tonic-gate * not implemented in the libldap.so.4 code, so we 16847c478bd9Sstevel@tonic-gate * free it here in order to avoid a memory leak. 16857c478bd9Sstevel@tonic-gate */ 16867c478bd9Sstevel@tonic-gate if (ber != 0) 16877c478bd9Sstevel@tonic-gate ber_free(ber, 0); 16887c478bd9Sstevel@tonic-gate } 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate if (numVals != tnv) { 16917c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 16927c478bd9Sstevel@tonic-gate "%s: Inconsistent LDAP entry count, found = %d, expected %d", 16937c478bd9Sstevel@tonic-gate myself, numVals, tnv); 16947c478bd9Sstevel@tonic-gate } 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate if (doVLV) { 16977c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 16987c478bd9Sstevel@tonic-gate &retCtrls, 0); 16997c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 17007c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 17017c478bd9Sstevel@tonic-gate &stat); 17027c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 17037c478bd9Sstevel@tonic-gate "%s: VLV parse result error: %s", 17047c478bd9Sstevel@tonic-gate myself, ldap_err2string(stat)); 17057c478bd9Sstevel@tonic-gate *ldapStat = stat; 17067c478bd9Sstevel@tonic-gate freeRuleValue(rv, tnv); 17077c478bd9Sstevel@tonic-gate rv = 0; 17087c478bd9Sstevel@tonic-gate goto cleanup; 17097c478bd9Sstevel@tonic-gate } 17107c478bd9Sstevel@tonic-gate if (retCtrls != 0) { 17117c478bd9Sstevel@tonic-gate unsigned long targetPosP = 0; 17127c478bd9Sstevel@tonic-gate unsigned long listSize = 0; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate stat = ldap_parse_virtuallist_control(lc->ld, 17157c478bd9Sstevel@tonic-gate retCtrls, &targetPosP, &listSize, 17167c478bd9Sstevel@tonic-gate &lprEc); 17177c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 17187c478bd9Sstevel@tonic-gate index = targetPosP + lc->batchFrom; 17197c478bd9Sstevel@tonic-gate if (index >= listSize) 17207c478bd9Sstevel@tonic-gate done = 1; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate ldap_controls_free(retCtrls); 17237c478bd9Sstevel@tonic-gate retCtrls = 0; 17247c478bd9Sstevel@tonic-gate } else { 17257c478bd9Sstevel@tonic-gate done = 1; 17267c478bd9Sstevel@tonic-gate } 17277c478bd9Sstevel@tonic-gate } else if (doSP) { 17287c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 17297c478bd9Sstevel@tonic-gate &retCtrls, 0); 17307c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 17317c478bd9Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 17327c478bd9Sstevel@tonic-gate &stat); 17337c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 17347c478bd9Sstevel@tonic-gate "%s: Simple page parse result error: %s", 17357c478bd9Sstevel@tonic-gate myself, ldap_err2string(stat)); 17367c478bd9Sstevel@tonic-gate *ldapStat = stat; 17377c478bd9Sstevel@tonic-gate freeRuleValue(rv, tnv); 17387c478bd9Sstevel@tonic-gate rv = 0; 17397c478bd9Sstevel@tonic-gate goto cleanup; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate if (retCtrls != 0) { 17427c478bd9Sstevel@tonic-gate unsigned int count; 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate if (spCookie != 0) { 17457c478bd9Sstevel@tonic-gate ber_bvfree(spCookie); 17467c478bd9Sstevel@tonic-gate spCookie = 0; 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate stat = ldap_parse_page_control(lc->ld, 17497c478bd9Sstevel@tonic-gate retCtrls, &count, &spCookie); 17507c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 17517c478bd9Sstevel@tonic-gate if (spCookie == 0 || 17527c478bd9Sstevel@tonic-gate spCookie->bv_val == 0 || 17537c478bd9Sstevel@tonic-gate spCookie->bv_len == 0) 17547c478bd9Sstevel@tonic-gate done = 1; 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate ldap_controls_free(retCtrls); 17577c478bd9Sstevel@tonic-gate retCtrls = 0; 17587c478bd9Sstevel@tonic-gate } else { 17597c478bd9Sstevel@tonic-gate done = 1; 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate } else { 17627c478bd9Sstevel@tonic-gate done = 1; 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 17667c478bd9Sstevel@tonic-gate msg = 0; 17677c478bd9Sstevel@tonic-gate 17687c478bd9Sstevel@tonic-gate /* 17697c478bd9Sstevel@tonic-gate * If we're using VLV or SP, the timeout should apply 17707c478bd9Sstevel@tonic-gate * to all calls as an aggregate, so we need to reduce 17717c478bd9Sstevel@tonic-gate * 'tv' with the time spent on this chunk of data. 17727c478bd9Sstevel@tonic-gate */ 17737c478bd9Sstevel@tonic-gate if (!done) { 17747c478bd9Sstevel@tonic-gate struct timeval tmp; 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, 0); 17777c478bd9Sstevel@tonic-gate tmp = now; 17787c478bd9Sstevel@tonic-gate now.tv_sec -= start.tv_sec; 17797c478bd9Sstevel@tonic-gate now.tv_usec -= start.tv_usec; 17807c478bd9Sstevel@tonic-gate if (now.tv_usec < 0) { 17817c478bd9Sstevel@tonic-gate now.tv_usec += 1000000; 17827c478bd9Sstevel@tonic-gate now.tv_sec -= 1; 17837c478bd9Sstevel@tonic-gate } 17847c478bd9Sstevel@tonic-gate tv.tv_sec -= now.tv_sec; 17857c478bd9Sstevel@tonic-gate tv.tv_usec -= now.tv_usec; 17867c478bd9Sstevel@tonic-gate if (tv.tv_usec < 0) { 17877c478bd9Sstevel@tonic-gate tv.tv_usec += 1000000; 17887c478bd9Sstevel@tonic-gate tv.tv_sec -= 1; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate if (tv.tv_sec < 0) { 17917c478bd9Sstevel@tonic-gate *ldapStat = LDAP_TIMEOUT; 17927c478bd9Sstevel@tonic-gate freeRuleValue(rv, tnv); 17937c478bd9Sstevel@tonic-gate rv = 0; 17947c478bd9Sstevel@tonic-gate goto cleanup; 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate start = tmp; 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate 17997c478bd9Sstevel@tonic-gate } while (!done); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate if (numValues != 0) 18027c478bd9Sstevel@tonic-gate *numValues = numVals; 18037c478bd9Sstevel@tonic-gate 18047c478bd9Sstevel@tonic-gate cleanup: 18057c478bd9Sstevel@tonic-gate if (NULL != lc) { 18067c478bd9Sstevel@tonic-gate if (yp2ldap && ls->useCon == 0) { 18077c478bd9Sstevel@tonic-gate /* Disconnect and free the connection */ 18087c478bd9Sstevel@tonic-gate lc->doDis++; 18097c478bd9Sstevel@tonic-gate lc->doDel++; 18107c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 18117c478bd9Sstevel@tonic-gate releaseLC(lc); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate } else { 18147c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 18157c478bd9Sstevel@tonic-gate } 18167c478bd9Sstevel@tonic-gate } 18177c478bd9Sstevel@tonic-gate if (msg != 0) 18187c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 18197c478bd9Sstevel@tonic-gate if (ctrls[0] != 0) 18207c478bd9Sstevel@tonic-gate ldap_control_free(ctrls[0]); 18217c478bd9Sstevel@tonic-gate if (ctrls[1] != 0) 18227c478bd9Sstevel@tonic-gate ldap_control_free(ctrls[1]); 18237c478bd9Sstevel@tonic-gate if (spCookie != 0) 18247c478bd9Sstevel@tonic-gate ber_bvfree(spCookie); 18257c478bd9Sstevel@tonic-gate if (sortKeyList != 0) 18267c478bd9Sstevel@tonic-gate ldap_free_sort_keylist(sortKeyList); 18277c478bd9Sstevel@tonic-gate 18287c478bd9Sstevel@tonic-gate return (rv); 18297c478bd9Sstevel@tonic-gate } 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate static void 18327c478bd9Sstevel@tonic-gate freeLdapModEntry(LDAPMod *m) { 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate if (m == 0) 18357c478bd9Sstevel@tonic-gate return; 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate sfree(m->mod_type); 18387c478bd9Sstevel@tonic-gate if ((m->mod_op & LDAP_MOD_BVALUES) == 0) { 18397c478bd9Sstevel@tonic-gate char **v = m->mod_values; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate if (v != 0) { 18427c478bd9Sstevel@tonic-gate while (*v != 0) { 18437c478bd9Sstevel@tonic-gate sfree(*v); 18447c478bd9Sstevel@tonic-gate v++; 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate free(m->mod_values); 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate } else { 18497c478bd9Sstevel@tonic-gate struct berval **b = m->mod_bvalues; 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate if (b != 0) { 18527c478bd9Sstevel@tonic-gate while (*b != 0) { 18537c478bd9Sstevel@tonic-gate sfree((*b)->bv_val); 18547c478bd9Sstevel@tonic-gate free(*b); 18557c478bd9Sstevel@tonic-gate b++; 18567c478bd9Sstevel@tonic-gate } 18577c478bd9Sstevel@tonic-gate free(m->mod_bvalues); 18587c478bd9Sstevel@tonic-gate } 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate free(m); 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate static void 18657c478bd9Sstevel@tonic-gate freeLdapMod(LDAPMod **mods) { 18667c478bd9Sstevel@tonic-gate LDAPMod *m, **org = mods; 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate if (mods == 0) 18697c478bd9Sstevel@tonic-gate return; 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate while ((m = *mods) != 0) { 18727c478bd9Sstevel@tonic-gate freeLdapModEntry(m); 18737c478bd9Sstevel@tonic-gate mods++; 18747c478bd9Sstevel@tonic-gate } 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate free(org); 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate /* 18807c478bd9Sstevel@tonic-gate * Convert a rule-value structure to the corresponding LDAPMod. 18817c478bd9Sstevel@tonic-gate * If 'add' is set, attributes/values are added; object classes 18827c478bd9Sstevel@tonic-gate * are also added. If 'add' is cleared, attributes/values are modified, 18837c478bd9Sstevel@tonic-gate * and 'oc' controls whether or not object classes are added. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate LDAPMod ** 18867c478bd9Sstevel@tonic-gate search2LdapMod(__nis_rule_value_t *rv, int add, int oc) { 18877c478bd9Sstevel@tonic-gate LDAPMod **mods; 18887c478bd9Sstevel@tonic-gate int i, j, nm; 18897c478bd9Sstevel@tonic-gate char *myself = "search2LdapMod"; 18907c478bd9Sstevel@tonic-gate 18917c478bd9Sstevel@tonic-gate if (rv == 0 || rv->numAttrs <= 0) 18927c478bd9Sstevel@tonic-gate return (0); 18937c478bd9Sstevel@tonic-gate 18947c478bd9Sstevel@tonic-gate mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0])); 18957c478bd9Sstevel@tonic-gate if (mods == 0) 18967c478bd9Sstevel@tonic-gate return (0); 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate for (i = 0, nm = 0; i < rv->numAttrs; i++) { 18997c478bd9Sstevel@tonic-gate int isOc; 19007c478bd9Sstevel@tonic-gate /* 19017c478bd9Sstevel@tonic-gate * If we're creating an LDAPMod array for an add operation, 19027c478bd9Sstevel@tonic-gate * just skip attributes that should be deleted. 19037c478bd9Sstevel@tonic-gate */ 19047c478bd9Sstevel@tonic-gate if (add && rv->attrVal[i].numVals < 0) 19057c478bd9Sstevel@tonic-gate continue; 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate /* 19087c478bd9Sstevel@tonic-gate * Skip DN; it's specified separately to ldap_modify() 19097c478bd9Sstevel@tonic-gate * and ldap_add(), and mustn't appear among the 19107c478bd9Sstevel@tonic-gate * attributes to be modified/added. 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 19137c478bd9Sstevel@tonic-gate continue; 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate /* 19167c478bd9Sstevel@tonic-gate * If modifying, and 'oc' is off, skip object class 19177c478bd9Sstevel@tonic-gate * attributes. 19187c478bd9Sstevel@tonic-gate */ 19197c478bd9Sstevel@tonic-gate isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0); 19207c478bd9Sstevel@tonic-gate if (!add && !oc && isOc) 19217c478bd9Sstevel@tonic-gate continue; 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate mods[nm] = am(myself, sizeof (*mods[nm])); 19247c478bd9Sstevel@tonic-gate if (mods[nm] == 0) { 19257c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19267c478bd9Sstevel@tonic-gate return (0); 19277c478bd9Sstevel@tonic-gate } 19287c478bd9Sstevel@tonic-gate 19297c478bd9Sstevel@tonic-gate /* 'mod_type' is the attribute name */ 19307c478bd9Sstevel@tonic-gate mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]); 19317c478bd9Sstevel@tonic-gate if (mods[nm]->mod_type == 0) { 19327c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19337c478bd9Sstevel@tonic-gate return (0); 19347c478bd9Sstevel@tonic-gate } 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate /* 19377c478bd9Sstevel@tonic-gate * numVals < 0 means attribute and all values should 19387c478bd9Sstevel@tonic-gate * be deleted. 19397c478bd9Sstevel@tonic-gate */ 19407c478bd9Sstevel@tonic-gate if (rv->attrVal[i].numVals < 0) { 19417c478bd9Sstevel@tonic-gate mods[nm]->mod_op = LDAP_MOD_DELETE; 19427c478bd9Sstevel@tonic-gate mods[nm]->mod_values = 0; 19437c478bd9Sstevel@tonic-gate nm++; 19447c478bd9Sstevel@tonic-gate continue; 19457c478bd9Sstevel@tonic-gate } 19467c478bd9Sstevel@tonic-gate 19477c478bd9Sstevel@tonic-gate /* objectClass attributes always added */ 19487c478bd9Sstevel@tonic-gate mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE); 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate if (rv->attrVal[i].type == vt_string) { 19517c478bd9Sstevel@tonic-gate /* 19527c478bd9Sstevel@tonic-gate * mods[]->mod_values is a NULL-terminated array 19537c478bd9Sstevel@tonic-gate * of (char *)'s. 19547c478bd9Sstevel@tonic-gate */ 19557c478bd9Sstevel@tonic-gate mods[nm]->mod_values = am(myself, 19567c478bd9Sstevel@tonic-gate (rv->attrVal[i].numVals + 1) * 19577c478bd9Sstevel@tonic-gate sizeof (mods[nm]->mod_values[0])); 19587c478bd9Sstevel@tonic-gate if (mods[nm]->mod_values == 0) { 19597c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19607c478bd9Sstevel@tonic-gate return (0); 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 19637c478bd9Sstevel@tonic-gate /* 19647c478bd9Sstevel@tonic-gate * Just in case the string isn't NUL 19657c478bd9Sstevel@tonic-gate * terminated, add one byte to the 19667c478bd9Sstevel@tonic-gate * allocated length; am() will initialize 19677c478bd9Sstevel@tonic-gate * the buffer to zero. 19687c478bd9Sstevel@tonic-gate */ 19697c478bd9Sstevel@tonic-gate mods[nm]->mod_values[j] = am(myself, 19707c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].length + 1); 19717c478bd9Sstevel@tonic-gate if (mods[nm]->mod_values[j] == 0) { 19727c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19737c478bd9Sstevel@tonic-gate return (0); 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate memcpy(mods[nm]->mod_values[j], 19767c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].value, 19777c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].length); 19787c478bd9Sstevel@tonic-gate } 19797c478bd9Sstevel@tonic-gate } else { 19807c478bd9Sstevel@tonic-gate mods[nm]->mod_op |= LDAP_MOD_BVALUES; 19817c478bd9Sstevel@tonic-gate mods[nm]->mod_bvalues = am(myself, 19827c478bd9Sstevel@tonic-gate (rv->attrVal[i].numVals+1) * 19837c478bd9Sstevel@tonic-gate sizeof (mods[nm]->mod_bvalues[0])); 19847c478bd9Sstevel@tonic-gate if (mods[nm]->mod_bvalues == 0) { 19857c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19867c478bd9Sstevel@tonic-gate return (0); 19877c478bd9Sstevel@tonic-gate } 19887c478bd9Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 19897c478bd9Sstevel@tonic-gate mods[nm]->mod_bvalues[j] = am(myself, 19907c478bd9Sstevel@tonic-gate sizeof (*mods[nm]->mod_bvalues[j])); 19917c478bd9Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j] == 0) { 19927c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19937c478bd9Sstevel@tonic-gate return (0); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_val = am(myself, 19967c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].length); 19977c478bd9Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j]->bv_val == 0) { 19987c478bd9Sstevel@tonic-gate freeLdapMod(mods); 19997c478bd9Sstevel@tonic-gate return (0); 20007c478bd9Sstevel@tonic-gate } 20017c478bd9Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len = 20027c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].length; 20037c478bd9Sstevel@tonic-gate memcpy(mods[nm]->mod_bvalues[j]->bv_val, 20047c478bd9Sstevel@tonic-gate rv->attrVal[i].val[j].value, 20057c478bd9Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len); 20067c478bd9Sstevel@tonic-gate } 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate nm++; 20097c478bd9Sstevel@tonic-gate } 20107c478bd9Sstevel@tonic-gate 20117c478bd9Sstevel@tonic-gate return (mods); 20127c478bd9Sstevel@tonic-gate } 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate /* 20157c478bd9Sstevel@tonic-gate * Remove 'value' from 'val'. If value==0, remove the entire 20167c478bd9Sstevel@tonic-gate * __nis_single_value_t array from 'val'. 20177c478bd9Sstevel@tonic-gate */ 20187c478bd9Sstevel@tonic-gate static void 20197c478bd9Sstevel@tonic-gate removeSingleValue(__nis_value_t *val, void *value, int length) { 20207c478bd9Sstevel@tonic-gate int i; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate if (val == 0) 20237c478bd9Sstevel@tonic-gate return; 20247c478bd9Sstevel@tonic-gate 20257c478bd9Sstevel@tonic-gate if (value == 0) { 20267c478bd9Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 20277c478bd9Sstevel@tonic-gate sfree(val->val[i].value); 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate sfree(val->val); 20307c478bd9Sstevel@tonic-gate val->val = 0; 20317c478bd9Sstevel@tonic-gate val->numVals = 0; 20327c478bd9Sstevel@tonic-gate return; 20337c478bd9Sstevel@tonic-gate } 20347c478bd9Sstevel@tonic-gate 20357c478bd9Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 20367c478bd9Sstevel@tonic-gate if (val->val[i].value == 0 || (val->val[i].length != length)) 20377c478bd9Sstevel@tonic-gate continue; 20387c478bd9Sstevel@tonic-gate if (memcmp(val->val[i].value, value, length) != 0) 20397c478bd9Sstevel@tonic-gate continue; 20407c478bd9Sstevel@tonic-gate sfree(val->val[i].value); 20417c478bd9Sstevel@tonic-gate if (i != (val->numVals - 1)) { 20427c478bd9Sstevel@tonic-gate (void) memmove(&val->val[i], &val->val[i+1], 20437c478bd9Sstevel@tonic-gate (val->numVals - 1 - i) * sizeof (val->val[0])); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate val->numVals -= 1; 20467c478bd9Sstevel@tonic-gate break; 20477c478bd9Sstevel@tonic-gate } 20487c478bd9Sstevel@tonic-gate } 20497c478bd9Sstevel@tonic-gate 20507c478bd9Sstevel@tonic-gate /* 20517c478bd9Sstevel@tonic-gate * Helper function for LdapModify 20527c478bd9Sstevel@tonic-gate * When a modify operation fails with an object class violation, 20537c478bd9Sstevel@tonic-gate * the most probable reason is that the attributes we're modifying are new, 20547c478bd9Sstevel@tonic-gate * and the needed object class are not present. So, try the modify again, 20557c478bd9Sstevel@tonic-gate * but add the object classes this time. 20567c478bd9Sstevel@tonic-gate */ 20577c478bd9Sstevel@tonic-gate 20587c478bd9Sstevel@tonic-gate static int 20597c478bd9Sstevel@tonic-gate ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn, 20607c478bd9Sstevel@tonic-gate __nis_rule_value_t *rvIn, char *objClassAttrs) 20617c478bd9Sstevel@tonic-gate { 20627c478bd9Sstevel@tonic-gate LDAPMod **mods = 0; 20637c478bd9Sstevel@tonic-gate int msgid; 20647c478bd9Sstevel@tonic-gate int lderr; 20657c478bd9Sstevel@tonic-gate struct timeval tv; 20667c478bd9Sstevel@tonic-gate int stat; 20677c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0; 20687c478bd9Sstevel@tonic-gate char **referralsp = NULL; 20697c478bd9Sstevel@tonic-gate __nis_rule_value_t *rv, *rvldap; 20707c478bd9Sstevel@tonic-gate __nis_ldap_search_t *ls; 20717c478bd9Sstevel@tonic-gate int i, ocrv, ocrvldap, nv; 20727c478bd9Sstevel@tonic-gate char *oc[2] = { "objectClass", 0}; 20737c478bd9Sstevel@tonic-gate char *myself = "ldapModifyObjectClass"; 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate rv = initRuleValue(1, rvIn); 20767c478bd9Sstevel@tonic-gate if (rv == 0) 20777c478bd9Sstevel@tonic-gate return (LDAP_NO_MEMORY); 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 20807c478bd9Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 20817c478bd9Sstevel@tonic-gate if (rv == 0) { 20827c478bd9Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 20837c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 20847c478bd9Sstevel@tonic-gate "%s: addObjectClasses failed for %s", 20857c478bd9Sstevel@tonic-gate myself, NIL(dn)); 20867c478bd9Sstevel@tonic-gate goto cleanup; 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate 20897c478bd9Sstevel@tonic-gate /* 20907c478bd9Sstevel@tonic-gate * Before adding the object classes whole-sale, try retrieving 20917c478bd9Sstevel@tonic-gate * the entry specified by the 'dn'. If it exists, we filter out 20927c478bd9Sstevel@tonic-gate * those object classes that already are present in LDAP from our 20937c478bd9Sstevel@tonic-gate * update. 20947c478bd9Sstevel@tonic-gate */ 20957c478bd9Sstevel@tonic-gate ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*", 20967c478bd9Sstevel@tonic-gate oc, 0, 1); 20977c478bd9Sstevel@tonic-gate if (ls == 0) { 20987c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 20997c478bd9Sstevel@tonic-gate "%s: Unable to build DN search for \"%s\"", 21007c478bd9Sstevel@tonic-gate myself, NIL(dn)); 21017c478bd9Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 21027c478bd9Sstevel@tonic-gate goto addObjectClasses; 21037c478bd9Sstevel@tonic-gate } 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate nv = 0; 21067c478bd9Sstevel@tonic-gate rvldap = ldapSearch(ls, &nv, 0, &lderr); 21077c478bd9Sstevel@tonic-gate freeLdapSearch(ls); 21087c478bd9Sstevel@tonic-gate if (rvldap == 0) { 21097c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 21107c478bd9Sstevel@tonic-gate "%s: No data for DN search (\"%s\"); LDAP status %d", 21117c478bd9Sstevel@tonic-gate myself, NIL(dn), lderr); 21127c478bd9Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 21137c478bd9Sstevel@tonic-gate goto addObjectClasses; 21147c478bd9Sstevel@tonic-gate } 21157c478bd9Sstevel@tonic-gate 21167c478bd9Sstevel@tonic-gate /* 21177c478bd9Sstevel@tonic-gate * Find the indices of the 'objectClass' attribute 21187c478bd9Sstevel@tonic-gate * in 'rvldap' and 'rv'. 21197c478bd9Sstevel@tonic-gate */ 21207c478bd9Sstevel@tonic-gate for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) { 21217c478bd9Sstevel@tonic-gate if (rvldap->attrName[i] != 0 && 21227c478bd9Sstevel@tonic-gate strcasecmp("objectClass", rvldap->attrName[i]) == 0) { 21237c478bd9Sstevel@tonic-gate ocrvldap = i; 21247c478bd9Sstevel@tonic-gate break; 21257c478bd9Sstevel@tonic-gate } 21267c478bd9Sstevel@tonic-gate } 21277c478bd9Sstevel@tonic-gate for (i = 0, ocrv = -1; i < rv->numAttrs; i++) { 21287c478bd9Sstevel@tonic-gate if (rv->attrName[i] != 0 && 21297c478bd9Sstevel@tonic-gate strcasecmp("objectClass", rv->attrName[i]) == 0) { 21307c478bd9Sstevel@tonic-gate ocrv = i; 21317c478bd9Sstevel@tonic-gate break; 21327c478bd9Sstevel@tonic-gate } 21337c478bd9Sstevel@tonic-gate } 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate /* 21367c478bd9Sstevel@tonic-gate * Remove those object classes that already exist 21377c478bd9Sstevel@tonic-gate * in LDAP (i.e., in 'rvldap') from 'rv'. 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate if (ocrv >= 0 && ocrvldap >= 0) { 21407c478bd9Sstevel@tonic-gate for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) { 21417c478bd9Sstevel@tonic-gate removeSingleValue(&rv->attrVal[ocrv], 21427c478bd9Sstevel@tonic-gate rvldap->attrVal[ocrvldap].val[i].value, 21437c478bd9Sstevel@tonic-gate rvldap->attrVal[ocrvldap].val[i].length); 21447c478bd9Sstevel@tonic-gate } 21457c478bd9Sstevel@tonic-gate /* 21467c478bd9Sstevel@tonic-gate * If no 'objectClass' values left in 'rv', delete 21477c478bd9Sstevel@tonic-gate * 'objectClass' from 'rv'. 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate if (rv->attrVal[ocrv].numVals == 0) 21507c478bd9Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 21517c478bd9Sstevel@tonic-gate } 21527c478bd9Sstevel@tonic-gate 21537c478bd9Sstevel@tonic-gate /* 21547c478bd9Sstevel@tonic-gate * 'rv' now contains the update we want to make, with just the 21557c478bd9Sstevel@tonic-gate * object class(es) that need to be added. Fall through to the 21567c478bd9Sstevel@tonic-gate * actual LDAP modify operation. 21577c478bd9Sstevel@tonic-gate */ 21587c478bd9Sstevel@tonic-gate freeRuleValue(rvldap, 1); 21597c478bd9Sstevel@tonic-gate 21607c478bd9Sstevel@tonic-gate addObjectClasses: 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 1); 21637c478bd9Sstevel@tonic-gate if (mods == 0) { 21647c478bd9Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 21657c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 21667c478bd9Sstevel@tonic-gate "%s: Unable to create LDAP modify changes with object classes for %s", 21677c478bd9Sstevel@tonic-gate myself, NIL(dn)); 21687c478bd9Sstevel@tonic-gate goto cleanup; 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 21717c478bd9Sstevel@tonic-gate if (msgid != -1) { 21727c478bd9Sstevel@tonic-gate tv = (*lc)->modifyTimeout; 21737c478bd9Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 21747c478bd9Sstevel@tonic-gate if (stat == 0) { 21757c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 21767c478bd9Sstevel@tonic-gate } else if (stat == -1) { 21777c478bd9Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 21787c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 21797c478bd9Sstevel@tonic-gate } else { 21807c478bd9Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL, 21817c478bd9Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 21827c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 21837c478bd9Sstevel@tonic-gate stat = lderr; 21847c478bd9Sstevel@tonic-gate stat = ldap_result2error((*lc)->ld, msg, 0); 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate } else { 21877c478bd9Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER, 21887c478bd9Sstevel@tonic-gate &stat); 21897c478bd9Sstevel@tonic-gate } 21907c478bd9Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 21917c478bd9Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 21927c478bd9Sstevel@tonic-gate releaseCon(*lc, stat); 21937c478bd9Sstevel@tonic-gate if (msg != NULL) 21947c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 21957c478bd9Sstevel@tonic-gate msg = NULL; 21967c478bd9Sstevel@tonic-gate *lc = findReferralCon(referralsp, &stat); 21977c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 21987c478bd9Sstevel@tonic-gate referralsp = NULL; 21997c478bd9Sstevel@tonic-gate if (*lc == NULL) 22007c478bd9Sstevel@tonic-gate goto cleanup; 22017c478bd9Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 22027c478bd9Sstevel@tonic-gate if (msgid == -1) { 22037c478bd9Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 22047c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 22057c478bd9Sstevel@tonic-gate goto cleanup; 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 22087c478bd9Sstevel@tonic-gate if (stat == 0) { 22097c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22107c478bd9Sstevel@tonic-gate } else if (stat == -1) { 22117c478bd9Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 22127c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 22137c478bd9Sstevel@tonic-gate } else { 22147c478bd9Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, 22157c478bd9Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 22167c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 22177c478bd9Sstevel@tonic-gate stat = lderr; 22187c478bd9Sstevel@tonic-gate } 22197c478bd9Sstevel@tonic-gate } 22207c478bd9Sstevel@tonic-gate cleanup: 22217c478bd9Sstevel@tonic-gate if (mods != 0) 22227c478bd9Sstevel@tonic-gate freeLdapMod(mods); 22237c478bd9Sstevel@tonic-gate freeRuleValue(rv, 1); 22247c478bd9Sstevel@tonic-gate return (stat); 22257c478bd9Sstevel@tonic-gate } 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate /* 22287c478bd9Sstevel@tonic-gate * Modify the specified 'dn' per the attribute names/values in 'rv'. 22297c478bd9Sstevel@tonic-gate * If 'rv' is NULL, we attempt to delete the entire entry. 22307c478bd9Sstevel@tonic-gate * 22317c478bd9Sstevel@tonic-gate * The 'objClassAttrs' parameter is needed if the entry must be added 22327c478bd9Sstevel@tonic-gate * (i.e., created), or a modify fails with an object class violation. 22337c478bd9Sstevel@tonic-gate * 22347c478bd9Sstevel@tonic-gate * If 'addFirst' is set, we try an add before a modify; modify before 22357c478bd9Sstevel@tonic-gate * add otherwise (ignored if we're deleting). 22367c478bd9Sstevel@tonic-gate */ 22377c478bd9Sstevel@tonic-gate int 22387c478bd9Sstevel@tonic-gate ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, 22397c478bd9Sstevel@tonic-gate int addFirst) { 22407c478bd9Sstevel@tonic-gate int stat, add = 0; 22417c478bd9Sstevel@tonic-gate LDAPMod **mods = 0; 22427c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc; 22437c478bd9Sstevel@tonic-gate struct timeval tv; 22447c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0; 22457c478bd9Sstevel@tonic-gate char *myself = "ldapModify"; 22467c478bd9Sstevel@tonic-gate int msgid; 22477c478bd9Sstevel@tonic-gate int lderr; 22487c478bd9Sstevel@tonic-gate char **referralsp = NULL; 22497c478bd9Sstevel@tonic-gate bool_t delete = FALSE; 22507c478bd9Sstevel@tonic-gate 22517c478bd9Sstevel@tonic-gate if (dn == 0) 22527c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 22537c478bd9Sstevel@tonic-gate 22547c478bd9Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 22557c478bd9Sstevel@tonic-gate return (stat); 22567c478bd9Sstevel@tonic-gate 22577c478bd9Sstevel@tonic-gate if (rv == 0) { 22587c478bd9Sstevel@tonic-gate delete = TRUE; 22597c478bd9Sstevel@tonic-gate /* Simple case: if rv == 0, try to delete the entire entry */ 22607c478bd9Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 22617c478bd9Sstevel@tonic-gate if (msgid == -1) { 22627c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 22637c478bd9Sstevel@tonic-gate &stat); 22647c478bd9Sstevel@tonic-gate goto cleanup; 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate tv = lc->deleteTimeout; 22677c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 22687c478bd9Sstevel@tonic-gate 22697c478bd9Sstevel@tonic-gate if (stat == 0) { 22707c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22717c478bd9Sstevel@tonic-gate } else if (stat == -1) { 22727c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 22737c478bd9Sstevel@tonic-gate &stat); 22747c478bd9Sstevel@tonic-gate } else { 22757c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 22767c478bd9Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 22777c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 22787c478bd9Sstevel@tonic-gate stat = lderr; 22797c478bd9Sstevel@tonic-gate } 22807c478bd9Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 22817c478bd9Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 22827c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 22837c478bd9Sstevel@tonic-gate if (msg != NULL) 22847c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 22857c478bd9Sstevel@tonic-gate msg = NULL; 22867c478bd9Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 22877c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 22887c478bd9Sstevel@tonic-gate if (lc == NULL) 22897c478bd9Sstevel@tonic-gate goto cleanup; 22907c478bd9Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 22917c478bd9Sstevel@tonic-gate if (msgid == -1) { 22927c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 22937c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 22947c478bd9Sstevel@tonic-gate goto cleanup; 22957c478bd9Sstevel@tonic-gate } 22967c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 22977c478bd9Sstevel@tonic-gate if (stat == 0) { 22987c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22997c478bd9Sstevel@tonic-gate } else if (stat == -1) { 23007c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23017c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23027c478bd9Sstevel@tonic-gate } else { 23037c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 23047c478bd9Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 23057c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23067c478bd9Sstevel@tonic-gate stat = lderr; 23077c478bd9Sstevel@tonic-gate } 23087c478bd9Sstevel@tonic-gate } 23097c478bd9Sstevel@tonic-gate /* No such object means someone else has done our job */ 23107c478bd9Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) 23117c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 23127c478bd9Sstevel@tonic-gate } else { 23137c478bd9Sstevel@tonic-gate if (addFirst) { 23147c478bd9Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 23157c478bd9Sstevel@tonic-gate lc = NULL; 23167c478bd9Sstevel@tonic-gate if (stat != LDAP_ALREADY_EXISTS) 23177c478bd9Sstevel@tonic-gate goto cleanup; 23187c478bd9Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 23197c478bd9Sstevel@tonic-gate return (stat); 23207c478bd9Sstevel@tonic-gate } 23217c478bd9Sstevel@tonic-gate 23227c478bd9Sstevel@tonic-gate /* 23237c478bd9Sstevel@tonic-gate * First try the modify without specifying object classes 23247c478bd9Sstevel@tonic-gate * (i.e., assume they're already present). 23257c478bd9Sstevel@tonic-gate */ 23267c478bd9Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 0); 23277c478bd9Sstevel@tonic-gate if (mods == 0) { 23287c478bd9Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 23297c478bd9Sstevel@tonic-gate goto cleanup; 23307c478bd9Sstevel@tonic-gate } 23317c478bd9Sstevel@tonic-gate 23327c478bd9Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 23337c478bd9Sstevel@tonic-gate if (msgid == -1) { 23347c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 23357c478bd9Sstevel@tonic-gate &stat); 23367c478bd9Sstevel@tonic-gate goto cleanup; 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate tv = lc->modifyTimeout; 23397c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 23407c478bd9Sstevel@tonic-gate if (stat == 0) { 23417c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 23427c478bd9Sstevel@tonic-gate } else if (stat == -1) { 23437c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 23447c478bd9Sstevel@tonic-gate &stat); 23457c478bd9Sstevel@tonic-gate } else { 23467c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 23477c478bd9Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 23487c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23497c478bd9Sstevel@tonic-gate stat = lderr; 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 23527c478bd9Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 23537c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 23547c478bd9Sstevel@tonic-gate if (msg != NULL) 23557c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 23567c478bd9Sstevel@tonic-gate msg = NULL; 23577c478bd9Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 23587c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 23597c478bd9Sstevel@tonic-gate referralsp = NULL; 23607c478bd9Sstevel@tonic-gate if (lc == NULL) 23617c478bd9Sstevel@tonic-gate goto cleanup; 23627c478bd9Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 23637c478bd9Sstevel@tonic-gate if (msgid == -1) { 23647c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23657c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23667c478bd9Sstevel@tonic-gate goto cleanup; 23677c478bd9Sstevel@tonic-gate } 23687c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 23697c478bd9Sstevel@tonic-gate if (stat == 0) { 23707c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 23717c478bd9Sstevel@tonic-gate } else if (stat == -1) { 23727c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23737c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23747c478bd9Sstevel@tonic-gate } else { 23757c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 23767c478bd9Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 23777c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23787c478bd9Sstevel@tonic-gate stat = lderr; 23797c478bd9Sstevel@tonic-gate } 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate /* 23837c478bd9Sstevel@tonic-gate * If the modify failed with an object class violation, 23847c478bd9Sstevel@tonic-gate * the most probable reason is that at least on of the 23857c478bd9Sstevel@tonic-gate * attributes we're modifying didn't exist before, and 23867c478bd9Sstevel@tonic-gate * neither did its object class. So, try the modify again, 23877c478bd9Sstevel@tonic-gate * but add the object classes this time. 23887c478bd9Sstevel@tonic-gate */ 23897c478bd9Sstevel@tonic-gate if (stat == LDAP_OBJECT_CLASS_VIOLATION && 23907c478bd9Sstevel@tonic-gate objClassAttrs != 0) { 23917c478bd9Sstevel@tonic-gate freeLdapMod(mods); 23927c478bd9Sstevel@tonic-gate mods = 0; 23937c478bd9Sstevel@tonic-gate stat = ldapModifyObjectClass(&lc, dn, rv, 23947c478bd9Sstevel@tonic-gate objClassAttrs); 23957c478bd9Sstevel@tonic-gate } 23967c478bd9Sstevel@tonic-gate 23977c478bd9Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_ATTRIBUTE) { 23987c478bd9Sstevel@tonic-gate /* 23997c478bd9Sstevel@tonic-gate * If there was at least one attribute delete, then 24007c478bd9Sstevel@tonic-gate * the cause of this error could be that said attribute 24017c478bd9Sstevel@tonic-gate * didn't exist in LDAP. So, do things the slow way, 24027c478bd9Sstevel@tonic-gate * and try to delete one attribute at a time. 24037c478bd9Sstevel@tonic-gate */ 24047c478bd9Sstevel@tonic-gate int d, numDelete, st; 24057c478bd9Sstevel@tonic-gate __nis_rule_value_t *rvt; 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate for (d = 0, numDelete = 0; d < rv->numAttrs; d++) { 24087c478bd9Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) 24097c478bd9Sstevel@tonic-gate numDelete++; 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate /* If there's just one, we've already tried */ 24137c478bd9Sstevel@tonic-gate if (numDelete <= 1) 24147c478bd9Sstevel@tonic-gate goto cleanup; 24157c478bd9Sstevel@tonic-gate 24167c478bd9Sstevel@tonic-gate /* Make a copy of the rule value */ 24177c478bd9Sstevel@tonic-gate rvt = initRuleValue(1, rv); 24187c478bd9Sstevel@tonic-gate if (rvt == 0) 24197c478bd9Sstevel@tonic-gate goto cleanup; 24207c478bd9Sstevel@tonic-gate 24217c478bd9Sstevel@tonic-gate /* 24227c478bd9Sstevel@tonic-gate * Remove all delete attributes from the tmp 24237c478bd9Sstevel@tonic-gate * rule value. 24247c478bd9Sstevel@tonic-gate */ 24257c478bd9Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 24267c478bd9Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) { 24277c478bd9Sstevel@tonic-gate delAttrFromRuleValue(rvt, 24287c478bd9Sstevel@tonic-gate rv->attrName[d]); 24297c478bd9Sstevel@tonic-gate } 24307c478bd9Sstevel@tonic-gate } 24317c478bd9Sstevel@tonic-gate 24327c478bd9Sstevel@tonic-gate /* 24337c478bd9Sstevel@tonic-gate * Now put the attributes back in one by one, and 24347c478bd9Sstevel@tonic-gate * invoke ourselves. 24357c478bd9Sstevel@tonic-gate */ 24367c478bd9Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 24377c478bd9Sstevel@tonic-gate if (rv->attrVal[d].numVals >= 0) 24387c478bd9Sstevel@tonic-gate continue; 24397c478bd9Sstevel@tonic-gate st = addAttr2RuleValue(rv->attrVal[d].type, 24407c478bd9Sstevel@tonic-gate rv->attrName[d], 0, 0, rvt); 24417c478bd9Sstevel@tonic-gate if (st != 0) { 24427c478bd9Sstevel@tonic-gate logmsg(MSG_NOMEM, LOG_ERR, 24437c478bd9Sstevel@tonic-gate "%s: Error deleting \"%s\" for \"%s\"", 24447c478bd9Sstevel@tonic-gate NIL(rv->attrName[d]), NIL(dn)); 24457c478bd9Sstevel@tonic-gate stat = LDAP_NO_MEMORY; 24467c478bd9Sstevel@tonic-gate freeRuleValue(rvt, 1); 24477c478bd9Sstevel@tonic-gate goto cleanup; 24487c478bd9Sstevel@tonic-gate } 24497c478bd9Sstevel@tonic-gate stat = ldapModify(dn, rvt, objClassAttrs, 0); 24507c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS && 24517c478bd9Sstevel@tonic-gate stat != LDAP_NO_SUCH_ATTRIBUTE) { 24527c478bd9Sstevel@tonic-gate freeRuleValue(rvt, 1); 24537c478bd9Sstevel@tonic-gate goto cleanup; 24547c478bd9Sstevel@tonic-gate } 24557c478bd9Sstevel@tonic-gate delAttrFromRuleValue(rvt, rv->attrName[d]); 24567c478bd9Sstevel@tonic-gate } 24577c478bd9Sstevel@tonic-gate 24587c478bd9Sstevel@tonic-gate /* 24597c478bd9Sstevel@tonic-gate * If we got here, then all attributes that should 24607c478bd9Sstevel@tonic-gate * be deleted either have been, or didn't exist. For 24617c478bd9Sstevel@tonic-gate * our purposes, the latter is as good as the former. 24627c478bd9Sstevel@tonic-gate */ 24637c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 24647c478bd9Sstevel@tonic-gate freeRuleValue(rvt, 1); 24657c478bd9Sstevel@tonic-gate } 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) { 24687c478bd9Sstevel@tonic-gate /* 24697c478bd9Sstevel@tonic-gate * Entry doesn't exist, so try an ldap_add(). If the 24707c478bd9Sstevel@tonic-gate * ldap_add() also fails, that could be because someone 24717c478bd9Sstevel@tonic-gate * else added it between our modify and add operations. 24727c478bd9Sstevel@tonic-gate * If so, we consider that foreign add to be 24737c478bd9Sstevel@tonic-gate * authoritative (meaning we don't retry our modify). 24747c478bd9Sstevel@tonic-gate * 24757c478bd9Sstevel@tonic-gate * Also, if all modify operations specified by 'mods' 24767c478bd9Sstevel@tonic-gate * are deletes, LDAP_NO_SUCH_OBJECT is a kind of 24777c478bd9Sstevel@tonic-gate * success; we certainly don't want to create the 24787c478bd9Sstevel@tonic-gate * entry. 24797c478bd9Sstevel@tonic-gate */ 24807c478bd9Sstevel@tonic-gate int allDelete; 24817c478bd9Sstevel@tonic-gate LDAPMod **m; 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate for (m = mods, allDelete = 1; *m != 0 && allDelete; 24847c478bd9Sstevel@tonic-gate m++) { 24857c478bd9Sstevel@tonic-gate if (((*m)->mod_op & LDAP_MOD_DELETE) == 0) 24867c478bd9Sstevel@tonic-gate allDelete = 0; 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate add = 1; 24907c478bd9Sstevel@tonic-gate 24917c478bd9Sstevel@tonic-gate if (allDelete) { 24927c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 24937c478bd9Sstevel@tonic-gate } else if (objClassAttrs == 0) { 24947c478bd9Sstevel@tonic-gate /* Now we need it, so this is fatal */ 24957c478bd9Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 24967c478bd9Sstevel@tonic-gate } else { 24977c478bd9Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 24987c478bd9Sstevel@tonic-gate lc = NULL; 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate } 25017c478bd9Sstevel@tonic-gate } 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate cleanup: 25047c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 25057c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 25067c478bd9Sstevel@tonic-gate "%s(0x%x (%s), \"%s\") => %d (%s)\n", 25077c478bd9Sstevel@tonic-gate !delete ? (add ? "ldap_add" : "ldap_modify") : 25087c478bd9Sstevel@tonic-gate "ldap_delete", 25097c478bd9Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 25107c478bd9Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 25117c478bd9Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 25127c478bd9Sstevel@tonic-gate } 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 25157c478bd9Sstevel@tonic-gate freeLdapMod(mods); 25167c478bd9Sstevel@tonic-gate if (msg != 0) 25177c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate return (stat); 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate /* 25237c478bd9Sstevel@tonic-gate * Create the entry specified by 'dn' to have the values per 'rv'. 25247c478bd9Sstevel@tonic-gate * The 'objClassAttrs' are the extra object classes we need when 25257c478bd9Sstevel@tonic-gate * creating an entry. 25267c478bd9Sstevel@tonic-gate * 25277c478bd9Sstevel@tonic-gate * If 'lc' is non-NULL, we use that connection; otherwise, we find 25287c478bd9Sstevel@tonic-gate * our own. CAUTION: This connection will be released on return. Regardless 25297c478bd9Sstevel@tonic-gate * of return value, this connection should not subsequently used by the 25307c478bd9Sstevel@tonic-gate * caller. 25317c478bd9Sstevel@tonic-gate * 25327c478bd9Sstevel@tonic-gate * Returns an LDAP status. 25337c478bd9Sstevel@tonic-gate */ 25347c478bd9Sstevel@tonic-gate int 25357c478bd9Sstevel@tonic-gate ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) { 25367c478bd9Sstevel@tonic-gate int stat; 25377c478bd9Sstevel@tonic-gate LDAPMod **mods = 0; 25387c478bd9Sstevel@tonic-gate struct timeval tv; 25397c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0; 25407c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc = lcv; 25417c478bd9Sstevel@tonic-gate int msgid; 25427c478bd9Sstevel@tonic-gate int lderr; 25437c478bd9Sstevel@tonic-gate char **referralsp = NULL; 25447c478bd9Sstevel@tonic-gate 25457c478bd9Sstevel@tonic-gate if (dn == 0 || rv == 0 || objClassAttrs == 0) { 25467c478bd9Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 25477c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate if (lc == 0) { 25517c478bd9Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 25527c478bd9Sstevel@tonic-gate return (stat); 25537c478bd9Sstevel@tonic-gate } 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 25567c478bd9Sstevel@tonic-gate if (rv == 0) { 25577c478bd9Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 25587c478bd9Sstevel@tonic-gate goto cleanup; 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate 25617c478bd9Sstevel@tonic-gate mods = search2LdapMod(rv, 1, 0); 25627c478bd9Sstevel@tonic-gate if (mods == 0) { 25637c478bd9Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 25647c478bd9Sstevel@tonic-gate goto cleanup; 25657c478bd9Sstevel@tonic-gate } 25667c478bd9Sstevel@tonic-gate 25677c478bd9Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 25687c478bd9Sstevel@tonic-gate if (msgid == -1) { 25697c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 25707c478bd9Sstevel@tonic-gate goto cleanup; 25717c478bd9Sstevel@tonic-gate } 25727c478bd9Sstevel@tonic-gate tv = lc->addTimeout; 25737c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 25747c478bd9Sstevel@tonic-gate if (stat == 0) { 25757c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 25767c478bd9Sstevel@tonic-gate } else if (stat == -1) { 25777c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 25787c478bd9Sstevel@tonic-gate } else { 25797c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL, 25807c478bd9Sstevel@tonic-gate &referralsp, NULL, 0); 25817c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 25827c478bd9Sstevel@tonic-gate stat = lderr; 25837c478bd9Sstevel@tonic-gate } 25847c478bd9Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL && 25857c478bd9Sstevel@tonic-gate referralsp != NULL) { 25867c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 25877c478bd9Sstevel@tonic-gate if (msg != NULL) 25887c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 25897c478bd9Sstevel@tonic-gate msg = NULL; 25907c478bd9Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 25917c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 25927c478bd9Sstevel@tonic-gate if (lc == NULL) 25937c478bd9Sstevel@tonic-gate goto cleanup; 25947c478bd9Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 25957c478bd9Sstevel@tonic-gate if (msgid == -1) { 25967c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 25977c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 25987c478bd9Sstevel@tonic-gate goto cleanup; 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 26017c478bd9Sstevel@tonic-gate if (stat == 0) { 26027c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 26037c478bd9Sstevel@tonic-gate } else if (stat == -1) { 26047c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 26057c478bd9Sstevel@tonic-gate &stat); 26067c478bd9Sstevel@tonic-gate } else { 26077c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 26087c478bd9Sstevel@tonic-gate NULL, NULL, NULL, 0); 26097c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 26107c478bd9Sstevel@tonic-gate stat = lderr; 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate } 26137c478bd9Sstevel@tonic-gate 26147c478bd9Sstevel@tonic-gate cleanup: 26157c478bd9Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 26167c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 26177c478bd9Sstevel@tonic-gate "ldap_add(0x%x (%s), \"%s\") => %d (%s)\n", 26187c478bd9Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 26197c478bd9Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 26207c478bd9Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 26217c478bd9Sstevel@tonic-gate } 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 26247c478bd9Sstevel@tonic-gate freeLdapMod(mods); 26257c478bd9Sstevel@tonic-gate if (msg != 0) 26267c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate return (stat); 26297c478bd9Sstevel@tonic-gate } 26307c478bd9Sstevel@tonic-gate 26317c478bd9Sstevel@tonic-gate /* 26327c478bd9Sstevel@tonic-gate * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'. 26337c478bd9Sstevel@tonic-gate * Returns an LDAP error status. 26347c478bd9Sstevel@tonic-gate */ 26357c478bd9Sstevel@tonic-gate int 26367c478bd9Sstevel@tonic-gate ldapChangeDN(char *oldDn, char *dn) { 26377c478bd9Sstevel@tonic-gate int stat; 26387c478bd9Sstevel@tonic-gate __nis_ldap_conn_t *lc; 26397c478bd9Sstevel@tonic-gate int i, j, lo, ln; 26407c478bd9Sstevel@tonic-gate char *rdn; 26417c478bd9Sstevel@tonic-gate int msgid; 26427c478bd9Sstevel@tonic-gate int lderr; 26437c478bd9Sstevel@tonic-gate struct timeval tv; 26447c478bd9Sstevel@tonic-gate LDAPMessage *msg = 0; 26457c478bd9Sstevel@tonic-gate char **referralsp = NULL; 26467c478bd9Sstevel@tonic-gate char *myself = "ldapChangeDN"; 26477c478bd9Sstevel@tonic-gate 26487c478bd9Sstevel@tonic-gate if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0) 26497c478bd9Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 26507c478bd9Sstevel@tonic-gate 26517c478bd9Sstevel@tonic-gate if (strcasecmp(oldDn, dn) == 0) 26527c478bd9Sstevel@tonic-gate return (LDAP_SUCCESS); 26537c478bd9Sstevel@tonic-gate 26547c478bd9Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 26557c478bd9Sstevel@tonic-gate return (stat); 26567c478bd9Sstevel@tonic-gate 26577c478bd9Sstevel@tonic-gate rdn = sdup(myself, T, dn); 26587c478bd9Sstevel@tonic-gate if (rdn == 0) { 26597c478bd9Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 26607c478bd9Sstevel@tonic-gate return (LDAP_NO_MEMORY); 26617c478bd9Sstevel@tonic-gate } 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate /* Compare old and new DN from the end */ 26647c478bd9Sstevel@tonic-gate for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) { 26657c478bd9Sstevel@tonic-gate if (tolower(oldDn[i]) != tolower(rdn[j])) { 26667c478bd9Sstevel@tonic-gate /* 26677c478bd9Sstevel@tonic-gate * Terminate 'rdn' after this character in order 26687c478bd9Sstevel@tonic-gate * to snip off the portion of the new DN that is 26697c478bd9Sstevel@tonic-gate * the same as the old DN. What remains in 'rdn' 26707c478bd9Sstevel@tonic-gate * is the relative DN. 26717c478bd9Sstevel@tonic-gate */ 26727c478bd9Sstevel@tonic-gate rdn[j+1] = '\0'; 26737c478bd9Sstevel@tonic-gate break; 26747c478bd9Sstevel@tonic-gate } 26757c478bd9Sstevel@tonic-gate } 26767c478bd9Sstevel@tonic-gate 26777c478bd9Sstevel@tonic-gate stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid); 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate if (msgid != -1) { 26807c478bd9Sstevel@tonic-gate tv = lc->modifyTimeout; 26817c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 26827c478bd9Sstevel@tonic-gate if (stat == 0) { 26837c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 26847c478bd9Sstevel@tonic-gate } else if (stat == -1) { 26857c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 26867c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 26877c478bd9Sstevel@tonic-gate } else { 26887c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 26897c478bd9Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 26907c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 26917c478bd9Sstevel@tonic-gate stat = lderr; 26927c478bd9Sstevel@tonic-gate stat = ldap_result2error(lc->ld, msg, 0); 26937c478bd9Sstevel@tonic-gate } 26947c478bd9Sstevel@tonic-gate } else { 26957c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 26967c478bd9Sstevel@tonic-gate &stat); 26977c478bd9Sstevel@tonic-gate } 26987c478bd9Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 26997c478bd9Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 27007c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 27017c478bd9Sstevel@tonic-gate if (msg != NULL) 27027c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 27037c478bd9Sstevel@tonic-gate msg = NULL; 27047c478bd9Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 27057c478bd9Sstevel@tonic-gate ldap_value_free(referralsp); 27067c478bd9Sstevel@tonic-gate referralsp = NULL; 27077c478bd9Sstevel@tonic-gate if (lc == NULL) 27087c478bd9Sstevel@tonic-gate goto cleanup; 27097c478bd9Sstevel@tonic-gate msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, 27107c478bd9Sstevel@tonic-gate &msgid); 27117c478bd9Sstevel@tonic-gate if (msgid == -1) { 27127c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 27137c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 27147c478bd9Sstevel@tonic-gate goto cleanup; 27157c478bd9Sstevel@tonic-gate } 27167c478bd9Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 27177c478bd9Sstevel@tonic-gate if (stat == 0) { 27187c478bd9Sstevel@tonic-gate stat = LDAP_TIMEOUT; 27197c478bd9Sstevel@tonic-gate } else if (stat == -1) { 27207c478bd9Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 27217c478bd9Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 27227c478bd9Sstevel@tonic-gate } else { 27237c478bd9Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 27247c478bd9Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 27257c478bd9Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 27267c478bd9Sstevel@tonic-gate stat = lderr; 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate cleanup: 27317c478bd9Sstevel@tonic-gate if (msg != NULL) 27327c478bd9Sstevel@tonic-gate (void) ldap_msgfree(msg); 27337c478bd9Sstevel@tonic-gate 27347c478bd9Sstevel@tonic-gate #if 1 27357c478bd9Sstevel@tonic-gate fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n", 27367c478bd9Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 27377c478bd9Sstevel@tonic-gate ldap_err2string(stat)); 27387c478bd9Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 27397c478bd9Sstevel@tonic-gate "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s", 27407c478bd9Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 27417c478bd9Sstevel@tonic-gate ldap_err2string(stat)); 27427c478bd9Sstevel@tonic-gate #endif 27437c478bd9Sstevel@tonic-gate 27447c478bd9Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) { 27457c478bd9Sstevel@tonic-gate /* 27467c478bd9Sstevel@tonic-gate * Fine from our point of view, since all we want to do 27477c478bd9Sstevel@tonic-gate * is to make sure that an update to the new DN doesn't 27487c478bd9Sstevel@tonic-gate * leave the old entry around. 27497c478bd9Sstevel@tonic-gate */ 27507c478bd9Sstevel@tonic-gate stat = LDAP_SUCCESS; 27517c478bd9Sstevel@tonic-gate } 27527c478bd9Sstevel@tonic-gate 27537c478bd9Sstevel@tonic-gate releaseCon(lc, stat); 27547c478bd9Sstevel@tonic-gate sfree(rdn); 27557c478bd9Sstevel@tonic-gate 27567c478bd9Sstevel@tonic-gate return (stat); 27577c478bd9Sstevel@tonic-gate } 2758