10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*8035SSreedhar.Chalamalasetti@Sun.COM * Common Development and Distribution License (the "License"). 6*8035SSreedhar.Chalamalasetti@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*8035SSreedhar.Chalamalasetti@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <synch.h> 270Sstevel@tonic-gate #include <strings.h> 280Sstevel@tonic-gate #include <sys/time.h> 290Sstevel@tonic-gate #include <ctype.h> 300Sstevel@tonic-gate 310Sstevel@tonic-gate #include "ldap_op.h" 320Sstevel@tonic-gate #include "ldap_util.h" 330Sstevel@tonic-gate #include "ldap_structs.h" 340Sstevel@tonic-gate #include "ldap_ruleval.h" 350Sstevel@tonic-gate #include "ldap_attr.h" 360Sstevel@tonic-gate #include "ldap_print.h" 370Sstevel@tonic-gate #include "ldap_glob.h" 380Sstevel@tonic-gate 390Sstevel@tonic-gate #include "nis_parse_ldap_conf.h" 400Sstevel@tonic-gate 410Sstevel@tonic-gate #ifndef LDAPS_PORT 420Sstevel@tonic-gate #define LDAPS_PORT 636 430Sstevel@tonic-gate #endif 440Sstevel@tonic-gate 45702Sth160488 static int setupConList(char *serverList, char *who, 46702Sth160488 char *cred, auth_method_t method); 47702Sth160488 48702Sth160488 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * Build one of our internal LDAP search structures, containing copies of 510Sstevel@tonic-gate * the supplied input. return NULL in case of error. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * If 'filter' is NULL, build an AND-filter using the filter components. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate __nis_ldap_search_t * 560Sstevel@tonic-gate buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp, 570Sstevel@tonic-gate char *filter, char **attrs, int attrsonly, int isDN) { 580Sstevel@tonic-gate __nis_ldap_search_t *ls; 590Sstevel@tonic-gate char **a; 600Sstevel@tonic-gate int i, na, err = 0; 610Sstevel@tonic-gate char *myself = "buildLdapSearch"; 620Sstevel@tonic-gate 630Sstevel@tonic-gate ls = am(myself, sizeof (*ls)); 640Sstevel@tonic-gate if (ls == 0) 650Sstevel@tonic-gate return (0); 660Sstevel@tonic-gate 670Sstevel@tonic-gate ls->base = sdup(myself, T, base); 680Sstevel@tonic-gate if (ls->base == 0 && base != 0) 690Sstevel@tonic-gate err++; 700Sstevel@tonic-gate ls->scope = scope; 710Sstevel@tonic-gate 720Sstevel@tonic-gate if (filterComp != 0 && numFilterComps > 0) { 730Sstevel@tonic-gate ls->filterComp = am(myself, numFilterComps * 740Sstevel@tonic-gate sizeof (ls->filterComp[0])); 750Sstevel@tonic-gate if (ls->filterComp == 0) { 760Sstevel@tonic-gate err++; 770Sstevel@tonic-gate numFilterComps = 0; 780Sstevel@tonic-gate } 790Sstevel@tonic-gate for (i = 0; i < numFilterComps; i++) { 800Sstevel@tonic-gate ls->filterComp[i] = sdup(myself, T, filterComp[i]); 810Sstevel@tonic-gate if (ls->filterComp[i] == 0 && filterComp[i] != 0) 820Sstevel@tonic-gate err++; 830Sstevel@tonic-gate } 840Sstevel@tonic-gate ls->numFilterComps = numFilterComps; 850Sstevel@tonic-gate if (filter == 0) { 860Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 870Sstevel@tonic-gate ls->filterComp); 880Sstevel@tonic-gate if (ls->filter == 0) 890Sstevel@tonic-gate err++; 900Sstevel@tonic-gate } 910Sstevel@tonic-gate } else { 920Sstevel@tonic-gate ls->filterComp = 0; 930Sstevel@tonic-gate ls->numFilterComps = 0; 940Sstevel@tonic-gate ls->filter = sdup(myself, T, filter); 950Sstevel@tonic-gate if (ls->filter == 0 && filter != 0) 960Sstevel@tonic-gate err++; 970Sstevel@tonic-gate } 980Sstevel@tonic-gate 990Sstevel@tonic-gate if (attrs != 0) { 1000Sstevel@tonic-gate for (na = 0, a = attrs; *a != 0; a++, na++); 1010Sstevel@tonic-gate ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0])); 1020Sstevel@tonic-gate if (ls->attrs != 0) { 1030Sstevel@tonic-gate for (i = 0; i < na; i++) { 1040Sstevel@tonic-gate ls->attrs[i] = sdup(myself, T, attrs[i]); 1050Sstevel@tonic-gate if (ls->attrs[i] == 0 && attrs[i] != 0) 1060Sstevel@tonic-gate err++; 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate ls->attrs[na] = 0; 1090Sstevel@tonic-gate ls->numAttrs = na; 1100Sstevel@tonic-gate } else { 1110Sstevel@tonic-gate err++; 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate } else { 1140Sstevel@tonic-gate ls->attrs = 0; 1150Sstevel@tonic-gate ls->numAttrs = 0; 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate ls->attrsonly = attrsonly; 1190Sstevel@tonic-gate ls->isDN = isDN; 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate if (err > 0) { 1220Sstevel@tonic-gate freeLdapSearch(ls); 1230Sstevel@tonic-gate ls = 0; 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate return (ls); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate void 1300Sstevel@tonic-gate freeLdapSearch(__nis_ldap_search_t *ls) { 1310Sstevel@tonic-gate int i; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate if (ls == 0) 1340Sstevel@tonic-gate return; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate sfree(ls->base); 1370Sstevel@tonic-gate if (ls->filterComp != 0) { 1380Sstevel@tonic-gate for (i = 0; i < ls->numFilterComps; i++) { 1390Sstevel@tonic-gate sfree(ls->filterComp[i]); 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate sfree(ls->filterComp); 1420Sstevel@tonic-gate } 1430Sstevel@tonic-gate sfree(ls->filter); 1440Sstevel@tonic-gate if (ls->attrs != 0) { 1450Sstevel@tonic-gate for (i = 0; i < ls->numAttrs; i++) { 1460Sstevel@tonic-gate sfree(ls->attrs[i]); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate sfree(ls->attrs); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate free(ls); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * Given a table mapping, and a rule/value pointer, 1560Sstevel@tonic-gate * return an LDAP search structure with values suitable for use 1570Sstevel@tonic-gate * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value 1580Sstevel@tonic-gate * may be modified. 1590Sstevel@tonic-gate * 1600Sstevel@tonic-gate * If dn != 0 and *dn == 0, the function attemps to return a pointer 1610Sstevel@tonic-gate * to the DN. This may necessitate an ldapSearch, if the rule set doesn't 1620Sstevel@tonic-gate * produce a DN directly. 1630Sstevel@tonic-gate * 1640Sstevel@tonic-gate * if dn == 0, and the rule set produces a DN as well as other attribute/ 1650Sstevel@tonic-gate * value pairs, the function returns an LDAP search structure with the 1660Sstevel@tonic-gate * DN only. 1670Sstevel@tonic-gate * 1680Sstevel@tonic-gate * If 'fromLDAP' is set, the caller wants base/scope/filter from 1690Sstevel@tonic-gate * t->objectDN->read; otherwise, from t->objectDN->write. 1700Sstevel@tonic-gate * 1710Sstevel@tonic-gate * If 'rv' is NULL, the caller wants an enumeration of the container. 1720Sstevel@tonic-gate * 1730Sstevel@tonic-gate * Note that this function only creates a search structure for 't' itself; 1740Sstevel@tonic-gate * if there are alternative mappings for the table, those must be handled 1750Sstevel@tonic-gate * by our caller. 1760Sstevel@tonic-gate */ 1770Sstevel@tonic-gate __nis_ldap_search_t * 1780Sstevel@tonic-gate createLdapRequest(__nis_table_mapping_t *t, 1790Sstevel@tonic-gate __nis_rule_value_t *rv, char **dn, int fromLDAP, 1800Sstevel@tonic-gate int *res, __nis_object_dn_t *obj_dn) { 1810Sstevel@tonic-gate int i, j; 1820Sstevel@tonic-gate __nis_ldap_search_t *ls = 0; 1830Sstevel@tonic-gate char **locDN; 1840Sstevel@tonic-gate int numLocDN, stat = 0, count = 0; 1850Sstevel@tonic-gate char *myself = "createLdapRequest"; 1860Sstevel@tonic-gate __nis_object_dn_t *objectDN = NULL; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate if (t == 0) 1890Sstevel@tonic-gate return (0); 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate if (obj_dn == NULL) 1920Sstevel@tonic-gate objectDN = t->objectDN; 1930Sstevel@tonic-gate else 1940Sstevel@tonic-gate objectDN = obj_dn; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate if (rv == 0) { 1970Sstevel@tonic-gate char *base; 1980Sstevel@tonic-gate char *filter; 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (fromLDAP) { 2010Sstevel@tonic-gate base = objectDN->read.base; 2020Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 2030Sstevel@tonic-gate } else { 2040Sstevel@tonic-gate base = objectDN->write.base; 2050Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* Create request to enumerate container */ 2090Sstevel@tonic-gate ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter, 2100Sstevel@tonic-gate 0, 0, 0); 2110Sstevel@tonic-gate sfree(filter); 2120Sstevel@tonic-gate return (ls); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate for (i = 0; i < t->numRulesToLDAP; i++) { 2160Sstevel@tonic-gate rv = addLdapRuleValue(t, t->ruleToLDAP[i], 2170Sstevel@tonic-gate mit_ldap, mit_nisplus, rv, !fromLDAP, &stat); 2180Sstevel@tonic-gate if (rv == 0) 2190Sstevel@tonic-gate return (0); 2200Sstevel@tonic-gate if (stat == NP_LDAP_RULES_NO_VALUE) 2210Sstevel@tonic-gate count++; 2220Sstevel@tonic-gate stat = 0; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate /* 2260Sstevel@tonic-gate * If none of the rules produced a value despite 2270Sstevel@tonic-gate * having enough NIS+ columns, return error. 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate if (rv->numAttrs == 0 && count > 0) { 2300Sstevel@tonic-gate *res = NP_LDAP_RULES_NO_VALUE; 2310Sstevel@tonic-gate return (0); 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* 2350Sstevel@tonic-gate * 'rv' now contains everything we know about the attributes and 2360Sstevel@tonic-gate * values. Build an LDAP search structure from it. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate /* Look for a single-valued DN */ 2400Sstevel@tonic-gate locDN = findDNs(myself, rv, 1, 2410Sstevel@tonic-gate fromLDAP ? objectDN->read.base : 2420Sstevel@tonic-gate objectDN->write.base, 2430Sstevel@tonic-gate &numLocDN); 2440Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 2450Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 2460Sstevel@tonic-gate *dn = locDN[0]; 2470Sstevel@tonic-gate sfree(locDN); 2480Sstevel@tonic-gate } else { 2490Sstevel@tonic-gate char *filter; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (fromLDAP) 2520Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 2530Sstevel@tonic-gate else 2540Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 2550Sstevel@tonic-gate ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0, 2560Sstevel@tonic-gate filter, 0, 0, 1); 2570Sstevel@tonic-gate sfree(filter); 2580Sstevel@tonic-gate freeDNs(locDN, numLocDN); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate } else { 2610Sstevel@tonic-gate freeDNs(locDN, numLocDN); 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if (ls != 0) { 2650Sstevel@tonic-gate ls->useCon = 1; 2660Sstevel@tonic-gate return (ls); 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* 2700Sstevel@tonic-gate * No DN, or caller wanted a search structure with the non-DN 2710Sstevel@tonic-gate * attributes. 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* Initialize search structure */ 2750Sstevel@tonic-gate { 2760Sstevel@tonic-gate char *filter = (fromLDAP) ? 2770Sstevel@tonic-gate makeFilter(objectDN->read.attrs) : 2780Sstevel@tonic-gate makeFilter(objectDN->write.attrs); 2790Sstevel@tonic-gate char **ofc; 2800Sstevel@tonic-gate int nofc = 0; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate ofc = makeFilterComp(filter, &nofc); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate if (filter != 0 && ofc == 0) { 2850Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 2860Sstevel@tonic-gate "%s: Unable to break filter into components: \"%s\"", 2870Sstevel@tonic-gate myself, NIL(filter)); 2880Sstevel@tonic-gate sfree(filter); 2890Sstevel@tonic-gate return (0); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate if (fromLDAP) 2930Sstevel@tonic-gate ls = buildLdapSearch(objectDN->read.base, 2940Sstevel@tonic-gate objectDN->read.scope, 2950Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 2960Sstevel@tonic-gate else 2970Sstevel@tonic-gate ls = buildLdapSearch(objectDN->write.base, 2980Sstevel@tonic-gate objectDN->write.scope, 2990Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 3000Sstevel@tonic-gate sfree(filter); 3010Sstevel@tonic-gate freeFilterComp(ofc, nofc); 3020Sstevel@tonic-gate if (ls == 0) 3030Sstevel@tonic-gate return (0); 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate /* Build and add the filter components */ 3070Sstevel@tonic-gate for (i = 0; i < rv->numAttrs; i++) { 3080Sstevel@tonic-gate /* Skip DN */ 3090Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 3100Sstevel@tonic-gate continue; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate /* Skip vt_ber values */ 3130Sstevel@tonic-gate if (rv->attrVal[i].type == vt_ber) 3140Sstevel@tonic-gate continue; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 3170Sstevel@tonic-gate __nis_buffer_t b = {0, 0}; 3180Sstevel@tonic-gate char **tmpComp; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate bp2buf(myself, &b, "%s=%s", 3210Sstevel@tonic-gate rv->attrName[i], rv->attrVal[i].val[j].value); 3220Sstevel@tonic-gate tmpComp = addFilterComp(b.buf, ls->filterComp, 3230Sstevel@tonic-gate &ls->numFilterComps); 3240Sstevel@tonic-gate if (tmpComp == 0) { 3250Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 3260Sstevel@tonic-gate "%s: Unable to add filter component \"%s\"", 3270Sstevel@tonic-gate myself, NIL(b.buf)); 3280Sstevel@tonic-gate sfree(b.buf); 3290Sstevel@tonic-gate freeLdapSearch(ls); 3300Sstevel@tonic-gate return (0); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate ls->filterComp = tmpComp; 3330Sstevel@tonic-gate sfree(b.buf); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate if (ls->numFilterComps > 0) { 3380Sstevel@tonic-gate sfree(ls->filter); 3390Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 3400Sstevel@tonic-gate ls->filterComp); 3410Sstevel@tonic-gate if (ls->filter == 0) { 3420Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 3430Sstevel@tonic-gate "%s: Unable to concatenate filter components", 3440Sstevel@tonic-gate myself); 3450Sstevel@tonic-gate freeLdapSearch(ls); 3460Sstevel@tonic-gate return (0); 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 3510Sstevel@tonic-gate /* 3520Sstevel@tonic-gate * The caller wants a DN, but we didn't get one from the 3530Sstevel@tonic-gate * the rule set. We have an 'ls', so use it to ldapSearch() 3540Sstevel@tonic-gate * for an entry from which we can extract the DN. 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate __nis_rule_value_t *rvtmp; 3570Sstevel@tonic-gate char **locDN; 3580Sstevel@tonic-gate int nv = 0, numLocDN; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate rvtmp = ldapSearch(ls, &nv, 0, 0); 3610Sstevel@tonic-gate locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN); 3620Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 3630Sstevel@tonic-gate *dn = locDN[0]; 3640Sstevel@tonic-gate sfree(locDN); 3650Sstevel@tonic-gate } else { 3660Sstevel@tonic-gate freeDNs(locDN, numLocDN); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate freeRuleValue(rvtmp, nv); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate ls->useCon = 1; 3720Sstevel@tonic-gate return (ls); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate int ldapConnAttemptRetryTimeout = 60; /* seconds */ 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate typedef struct { 3780Sstevel@tonic-gate LDAP *ld; 3790Sstevel@tonic-gate mutex_t mutex; /* Mutex for update of structure */ 3800Sstevel@tonic-gate pthread_t owner; /* Thread holding mutex */ 3810Sstevel@tonic-gate mutex_t rcMutex; /* Mutex for refCount */ 3820Sstevel@tonic-gate int refCount; /* Reference count */ 3830Sstevel@tonic-gate int isBound; /* Is connection open and usable ? */ 3840Sstevel@tonic-gate time_t retryTime; /* When should open be retried */ 3850Sstevel@tonic-gate int status; /* Status of last operation */ 3860Sstevel@tonic-gate int doDis; /* To be disconnected if refCount==0 */ 3870Sstevel@tonic-gate int doDel; /* To be deleted if refCount zero */ 3880Sstevel@tonic-gate int onList; /* True if on the 'ldapCon' list */ 3890Sstevel@tonic-gate char *sp; /* server string */ 3900Sstevel@tonic-gate char *who; 3910Sstevel@tonic-gate char *cred; 3920Sstevel@tonic-gate auth_method_t method; 3930Sstevel@tonic-gate int port; 3940Sstevel@tonic-gate struct timeval bindTimeout; 3950Sstevel@tonic-gate struct timeval searchTimeout; 3960Sstevel@tonic-gate struct timeval modifyTimeout; 3970Sstevel@tonic-gate struct timeval addTimeout; 3980Sstevel@tonic-gate struct timeval deleteTimeout; 3990Sstevel@tonic-gate int simplePage; /* Can do simple-page */ 4000Sstevel@tonic-gate int vlv; /* Can do VLV */ 4010Sstevel@tonic-gate uint_t batchFrom; /* # entries read in one operation */ 4020Sstevel@tonic-gate void *next; 4030Sstevel@tonic-gate } __nis_ldap_conn_t; 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * List of connections, 'ldapCon', protected by an RW lock. 4070Sstevel@tonic-gate * 4080Sstevel@tonic-gate * The following locking scheme is used: 4090Sstevel@tonic-gate * 4100Sstevel@tonic-gate * (1) Find a connection structure to use to talk to LDAP 4110Sstevel@tonic-gate * Rlock list 4120Sstevel@tonic-gate * Locate structure 4130Sstevel@tonic-gate * Acquire 'mutex' 4140Sstevel@tonic-gate * Acquire 'rcMutex' 4150Sstevel@tonic-gate * update refCount 4160Sstevel@tonic-gate * Release 'rcMutex' 4170Sstevel@tonic-gate * release 'mutex' 4180Sstevel@tonic-gate * Unlock list 4190Sstevel@tonic-gate * Use structure 4200Sstevel@tonic-gate * Release structure when done 4210Sstevel@tonic-gate * (2) Insert/delete structure(s) on/from list 4220Sstevel@tonic-gate * Wlock list 4230Sstevel@tonic-gate * Insert/delete structure; if deleting, must 4240Sstevel@tonic-gate * acquire 'mutex', and 'rcMutex' (in that order), 4250Sstevel@tonic-gate * and 'refCount' must be zero. 4260Sstevel@tonic-gate * Unlock list 4270Sstevel@tonic-gate * (3) Modify structure 4280Sstevel@tonic-gate * Find structure 4290Sstevel@tonic-gate * Acquire 'mutex' 4300Sstevel@tonic-gate * Modify (except refCount) 4310Sstevel@tonic-gate * Release 'mutex' 4320Sstevel@tonic-gate * Release structure 4330Sstevel@tonic-gate */ 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate __nis_ldap_conn_t *ldapCon = 0; 4360Sstevel@tonic-gate __nis_ldap_conn_t *ldapReferralCon = 0; 4370Sstevel@tonic-gate static rwlock_t ldapConLock = DEFAULTRWLOCK; 4380Sstevel@tonic-gate static rwlock_t referralConLock = DEFAULTRWLOCK; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate void 4410Sstevel@tonic-gate exclusiveLC(__nis_ldap_conn_t *lc) { 4420Sstevel@tonic-gate pthread_t me = pthread_self(); 4430Sstevel@tonic-gate int stat; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (lc == 0) 4460Sstevel@tonic-gate return; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 4490Sstevel@tonic-gate if (stat == EBUSY && lc->owner != me) 4500Sstevel@tonic-gate mutex_lock(&lc->mutex); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate lc->owner = me; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* Return 1 if mutex held by this thread, 0 otherwise */ 4560Sstevel@tonic-gate int 4570Sstevel@tonic-gate assertExclusive(__nis_ldap_conn_t *lc) { 4580Sstevel@tonic-gate pthread_t me; 4590Sstevel@tonic-gate int stat; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (lc == 0) 4620Sstevel@tonic-gate return (0); 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate if (stat == 0) { 4670Sstevel@tonic-gate mutex_unlock(&lc->mutex); 4680Sstevel@tonic-gate return (0); 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate me = pthread_self(); 4720Sstevel@tonic-gate if (stat != EBUSY || lc->owner != me) 4730Sstevel@tonic-gate return (0); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate return (1); 4760Sstevel@tonic-gate } 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate void 4790Sstevel@tonic-gate releaseLC(__nis_ldap_conn_t *lc) { 4800Sstevel@tonic-gate pthread_t me = pthread_self(); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate if (lc == 0 || lc->owner != me) 4830Sstevel@tonic-gate return; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate lc->owner = 0; 4860Sstevel@tonic-gate (void) mutex_unlock(&lc->mutex); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate void 4900Sstevel@tonic-gate incrementRC(__nis_ldap_conn_t *lc) { 4910Sstevel@tonic-gate if (lc == 0) 4920Sstevel@tonic-gate return; 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 4950Sstevel@tonic-gate lc->refCount++; 4960Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate void 5000Sstevel@tonic-gate decrementRC(__nis_ldap_conn_t *lc) { 5010Sstevel@tonic-gate if (lc == 0) 5020Sstevel@tonic-gate return; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 5050Sstevel@tonic-gate if (lc->refCount > 0) 5060Sstevel@tonic-gate lc->refCount--; 5070Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 5080Sstevel@tonic-gate } 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* Accept a server/port indication, and call ldap_init() */ 5110Sstevel@tonic-gate static LDAP * 5120Sstevel@tonic-gate ldapInit(char *srv, int port, bool_t use_ssl) { 5130Sstevel@tonic-gate LDAP *ld; 5140Sstevel@tonic-gate int ldapVersion = LDAP_VERSION3; 5150Sstevel@tonic-gate int derefOption = LDAP_DEREF_ALWAYS; 5160Sstevel@tonic-gate int timelimit = proxyInfo.search_time_limit; 5170Sstevel@tonic-gate int sizelimit = proxyInfo.search_size_limit; 5180Sstevel@tonic-gate char *myself = "ldapInit"; 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate if (srv == 0) 5210Sstevel@tonic-gate return (0); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate if (use_ssl) { 5240Sstevel@tonic-gate ld = ldapssl_init(srv, port, 1); 5250Sstevel@tonic-gate } else { 5260Sstevel@tonic-gate ld = ldap_init(srv, port); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate if (ld != 0) { 5300Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 5310Sstevel@tonic-gate &ldapVersion); 5320Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 5330Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 5340Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit); 5350Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit); 5360Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0); 5370Sstevel@tonic-gate } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate return (ld); 5400Sstevel@tonic-gate } 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate /* 5430Sstevel@tonic-gate * Bind the specified LDAP structure per the supplied authentication. 5440Sstevel@tonic-gate * Note: tested with none, simple, and digest_md5. May or may not 5450Sstevel@tonic-gate * work with other authentication methods, mostly depending on whether 5460Sstevel@tonic-gate * or not 'who' and 'cred' contain sufficient information. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate static int 5490Sstevel@tonic-gate ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method, 5500Sstevel@tonic-gate struct timeval timeout) { 5510Sstevel@tonic-gate int ret; 5520Sstevel@tonic-gate LDAP *ld; 5530Sstevel@tonic-gate char *myself = "ldapBind"; 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate if (ldP == 0 || (ld = *ldP) == 0) 5560Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate if (method == none) { 5590Sstevel@tonic-gate /* No ldap_bind() required (or even possible) */ 5600Sstevel@tonic-gate ret = LDAP_SUCCESS; 5610Sstevel@tonic-gate } else if (method == simple) { 5620Sstevel@tonic-gate struct timeval tv; 5630Sstevel@tonic-gate LDAPMessage *msg = 0; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate tv = timeout; 5660Sstevel@tonic-gate ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE); 5670Sstevel@tonic-gate if (ret != -1) { 5680Sstevel@tonic-gate ret = ldap_result(ld, ret, 0, &tv, &msg); 5690Sstevel@tonic-gate if (ret == 0) { 5700Sstevel@tonic-gate ret = LDAP_TIMEOUT; 5710Sstevel@tonic-gate } else if (ret == -1) { 5720Sstevel@tonic-gate (void) ldap_get_option(ld, 5730Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, 5740Sstevel@tonic-gate &ret); 5750Sstevel@tonic-gate } else { 5760Sstevel@tonic-gate ret = ldap_result2error(ld, msg, 0); 5770Sstevel@tonic-gate } 5780Sstevel@tonic-gate if (msg != 0) 5790Sstevel@tonic-gate (void) ldap_msgfree(msg); 5800Sstevel@tonic-gate } else { 5810Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 5820Sstevel@tonic-gate &ret); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate } else if (method == cram_md5) { 5850Sstevel@tonic-gate /* Note: there is only a synchronous call for cram-md5 */ 5860Sstevel@tonic-gate struct berval ber_cred; 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 5890Sstevel@tonic-gate ber_cred.bv_val = cred; 5900Sstevel@tonic-gate ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL); 5910Sstevel@tonic-gate } else if (method == digest_md5) { 5920Sstevel@tonic-gate /* Note: there is only a synchronous call for digest-md5 */ 5930Sstevel@tonic-gate struct berval ber_cred; 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 5960Sstevel@tonic-gate ber_cred.bv_val = cred; 5970Sstevel@tonic-gate ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL, 5980Sstevel@tonic-gate NULL); 5990Sstevel@tonic-gate } else { 6000Sstevel@tonic-gate ret = LDAP_AUTH_METHOD_NOT_SUPPORTED; 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate if (ret != LDAP_SUCCESS) { 6040Sstevel@tonic-gate (void) ldap_unbind_s(ld); 6050Sstevel@tonic-gate *ldP = 0; 6060Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 6070Sstevel@tonic-gate "%s: Unable to bind as: %s: %s", 6080Sstevel@tonic-gate myself, who, ldap_err2string(ret)); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate return (ret); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * Free 'lc' and all related memory. Caller must hold the exclusive lock. 6160Sstevel@tonic-gate * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't 6170Sstevel@tonic-gate * try to use the structure pointer in any way. 6180Sstevel@tonic-gate */ 6190Sstevel@tonic-gate static int 6200Sstevel@tonic-gate freeCon(__nis_ldap_conn_t *lc) { 6210Sstevel@tonic-gate char *myself = "freeCon"; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if (!assertExclusive(lc)) 6240Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate incrementRC(lc); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* Must be unused, unbound, and not on the 'ldapCon' list */ 6290Sstevel@tonic-gate if (lc->onList || lc->refCount != 1 || lc->isBound) { 6300Sstevel@tonic-gate lc->doDel++; 6310Sstevel@tonic-gate decrementRC(lc); 6320Sstevel@tonic-gate return (LDAP_BUSY); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate sfree(lc->sp); 6360Sstevel@tonic-gate sfree(lc->who); 6370Sstevel@tonic-gate sfree(lc->cred); 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* Delete structure with both mutex:es held */ 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate free(lc); 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 6440Sstevel@tonic-gate } 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate /* 6470Sstevel@tonic-gate * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'. 6480Sstevel@tonic-gate * 6490Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 6500Sstevel@tonic-gate * the structure in any way. 6510Sstevel@tonic-gate */ 6520Sstevel@tonic-gate static int 6530Sstevel@tonic-gate disconnectCon(__nis_ldap_conn_t *lc) { 6540Sstevel@tonic-gate int stat; 6550Sstevel@tonic-gate char *myself = "disconnectCon"; 6560Sstevel@tonic-gate 6570Sstevel@tonic-gate if (lc == 0) 6580Sstevel@tonic-gate return (LDAP_SUCCESS); 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate if (!assertExclusive(lc)) 6610Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate if (lc->doDis) { 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* Increment refCount to protect against interference */ 6660Sstevel@tonic-gate incrementRC(lc); 6670Sstevel@tonic-gate /* refCount must be one (i.e., just us) */ 6680Sstevel@tonic-gate if (lc->refCount != 1) { 6690Sstevel@tonic-gate /* 6700Sstevel@tonic-gate * In use; already marked for disconnect, 6710Sstevel@tonic-gate * so do nothing. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate decrementRC(lc); 6740Sstevel@tonic-gate return (LDAP_BUSY); 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate stat = ldap_unbind_s(lc->ld); 6780Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 6790Sstevel@tonic-gate lc->ld = 0; 6800Sstevel@tonic-gate lc->isBound = 0; 6810Sstevel@tonic-gate lc->doDis = 0; 6820Sstevel@tonic-gate /* Reset simple page and vlv indication */ 6830Sstevel@tonic-gate lc->simplePage = 0; 6840Sstevel@tonic-gate lc->vlv = 0; 6850Sstevel@tonic-gate } else if (verbose) { 6860Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 6870Sstevel@tonic-gate "%s: ldap_unbind_s() => %d (%s)", 6880Sstevel@tonic-gate myself, stat, ldap_err2string(stat)); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate decrementRC(lc); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate if (lc->doDel) { 6950Sstevel@tonic-gate if (LDAP_UNAVAILABLE == freeCon(lc)) 6960Sstevel@tonic-gate stat = LDAP_UNAVAILABLE; 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate return (stat); 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate /* 7030Sstevel@tonic-gate * controlSupported will determine for a given connection whether a set 7040Sstevel@tonic-gate * of controls is supported or not. The input parameters: 7050Sstevel@tonic-gate * lc The connection 7060Sstevel@tonic-gate * ctrl A an array of OID strings, the terminal string should be NULL 7070Sstevel@tonic-gate * The returned values if LDAP_SUCCESS is returned: 7080Sstevel@tonic-gate * supported A caller supplied array which will be set to TRUE or 7090Sstevel@tonic-gate * FALSE depending on whether the corresponding control 7100Sstevel@tonic-gate * is reported as supported. 7110Sstevel@tonic-gate * Returns LDAP_SUCCESS if the supportedControl attribute is read. 7120Sstevel@tonic-gate */ 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate static int 7150Sstevel@tonic-gate controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) { 7160Sstevel@tonic-gate LDAPMessage *res, *e; 7170Sstevel@tonic-gate char *attr[2], *a, **val; 7180Sstevel@tonic-gate int stat, i; 7190Sstevel@tonic-gate BerElement *ber = 0; 7200Sstevel@tonic-gate char *myself = "controlSupported"; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate attr[0] = "supportedControl"; 7230Sstevel@tonic-gate attr[1] = 0; 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", 7260Sstevel@tonic-gate attr, 0, &lc->searchTimeout, &res); 7270Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 7280Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 7290Sstevel@tonic-gate "%s: Unable to retrieve supported control information for %s: %s", 7300Sstevel@tonic-gate myself, NIL(lc->sp), ldap_err2string(stat)); 7310Sstevel@tonic-gate return (stat); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate e = ldap_first_entry(lc->ld, res); 7350Sstevel@tonic-gate if (e != 0) { 7360Sstevel@tonic-gate a = ldap_first_attribute(lc->ld, e, &ber); 7370Sstevel@tonic-gate if (a != 0) { 7380Sstevel@tonic-gate val = ldap_get_values(lc->ld, e, a); 7390Sstevel@tonic-gate if (val == 0) { 7400Sstevel@tonic-gate ldap_memfree(a); 7410Sstevel@tonic-gate if (ber != 0) 7420Sstevel@tonic-gate ber_free(ber, 0); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate if (e == 0 || a == 0 || val == 0) { 7470Sstevel@tonic-gate ldap_msgfree(res); 7480Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 7490Sstevel@tonic-gate "%s: Unable to get root DSE for %s", 7500Sstevel@tonic-gate myself, NIL(lc->sp)); 7510Sstevel@tonic-gate return (LDAP_OPERATIONS_ERROR); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate while (*ctrl != NULL) { 7550Sstevel@tonic-gate *supported = FALSE; 7560Sstevel@tonic-gate for (i = 0; val[i] != 0; i++) { 7570Sstevel@tonic-gate if (strstr(val[i], *ctrl) != 0) { 7580Sstevel@tonic-gate *supported = TRUE; 7590Sstevel@tonic-gate break; 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 7630Sstevel@tonic-gate "%s: %s: %s: %s", 7640Sstevel@tonic-gate myself, NIL(lc->sp), NIL(*ctrl), 7650Sstevel@tonic-gate *supported ? "enabled" : "disabled"); 7660Sstevel@tonic-gate ctrl++; 7670Sstevel@tonic-gate supported++; 7680Sstevel@tonic-gate } 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate ldap_value_free(val); 7710Sstevel@tonic-gate ldap_memfree(a); 7720Sstevel@tonic-gate if (ber != 0) 7730Sstevel@tonic-gate ber_free(ber, 0); 7740Sstevel@tonic-gate ldap_msgfree(res); 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate return (stat); 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7800Sstevel@tonic-gate * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex', 7810Sstevel@tonic-gate * and the refCount must be zero. 7820Sstevel@tonic-gate * 7830Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 7840Sstevel@tonic-gate * the structure in any way. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate static int 7870Sstevel@tonic-gate connectCon(__nis_ldap_conn_t *lc, int check_ctrl) { 7880Sstevel@tonic-gate struct timeval tp; 7890Sstevel@tonic-gate int stat; 7900Sstevel@tonic-gate bool_t supported[2] = {FALSE, FALSE}; 7910Sstevel@tonic-gate char *ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE, 7920Sstevel@tonic-gate LDAP_CONTROL_VLVREQUEST, 7930Sstevel@tonic-gate NULL}; 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate if (lc == 0) 7960Sstevel@tonic-gate return (LDAP_SUCCESS); 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate if (!assertExclusive(lc)) 7990Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate incrementRC(lc); 8020Sstevel@tonic-gate if (lc->refCount != 1) { 8030Sstevel@tonic-gate /* 8040Sstevel@tonic-gate * Don't want to step on structure when it's used by someone 8050Sstevel@tonic-gate * else. 8060Sstevel@tonic-gate */ 8070Sstevel@tonic-gate decrementRC(lc); 8080Sstevel@tonic-gate return (LDAP_BUSY); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate (void) gettimeofday(&tp, 0); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate if (lc->ld != 0) { 8140Sstevel@tonic-gate /* Try to disconnect */ 8150Sstevel@tonic-gate lc->doDis++; 8160Sstevel@tonic-gate decrementRC(lc); 8170Sstevel@tonic-gate /* disconnctCon() will do the delete if required */ 8180Sstevel@tonic-gate stat = disconnectCon(lc); 8190Sstevel@tonic-gate if (stat != LDAP_SUCCESS) 8200Sstevel@tonic-gate return (stat); 8210Sstevel@tonic-gate incrementRC(lc); 8220Sstevel@tonic-gate if (lc->refCount != 1 || lc->ld != 0) { 8230Sstevel@tonic-gate decrementRC(lc); 8240Sstevel@tonic-gate return (lc->ld != 0) ? LDAP_SUCCESS : 8250Sstevel@tonic-gate LDAP_BUSY; 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate } else if (tp.tv_sec < lc->retryTime) { 8280Sstevel@tonic-gate /* Too early to retry connect */ 8290Sstevel@tonic-gate decrementRC(lc); 8300Sstevel@tonic-gate return (LDAP_SERVER_DOWN); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* Set new retry time in case we fail below */ 8340Sstevel@tonic-gate lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout; 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls); 8370Sstevel@tonic-gate if (lc->ld == 0) { 8380Sstevel@tonic-gate decrementRC(lc); 8390Sstevel@tonic-gate return (LDAP_LOCAL_ERROR); 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method, 8430Sstevel@tonic-gate lc->bindTimeout); 8440Sstevel@tonic-gate if (lc->status == LDAP_SUCCESS) { 8450Sstevel@tonic-gate lc->isBound = 1; 8460Sstevel@tonic-gate lc->retryTime = 0; 8470Sstevel@tonic-gate if (check_ctrl) { 8480Sstevel@tonic-gate (void) controlSupported(lc, ctrl, supported); 8490Sstevel@tonic-gate lc->simplePage = supported[0]; 8500Sstevel@tonic-gate lc->vlv = supported[1]; 8510Sstevel@tonic-gate lc->batchFrom = 50000; 8520Sstevel@tonic-gate } 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate decrementRC(lc); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate return (stat); 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate /* 8610Sstevel@tonic-gate * Find and return a connection believed to be OK. 8620Sstevel@tonic-gate */ 8630Sstevel@tonic-gate static __nis_ldap_conn_t * 8640Sstevel@tonic-gate findCon(int *stat) { 8650Sstevel@tonic-gate __nis_ldap_conn_t *lc; 8660Sstevel@tonic-gate int ldapStat; 8670Sstevel@tonic-gate char *myself = "findCon"; 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate if (stat == 0) 8700Sstevel@tonic-gate stat = &ldapStat; 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (ldapCon == 0) { 8750Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 8760Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 8770Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 8780Sstevel@tonic-gate proxyInfo.proxy_dn, 8790Sstevel@tonic-gate proxyInfo.proxy_passwd, 8800Sstevel@tonic-gate proxyInfo.auth_method)) != 8810Sstevel@tonic-gate LDAP_SUCCESS) 8820Sstevel@tonic-gate return (0); 8830Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate 8860Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 8870Sstevel@tonic-gate exclusiveLC(lc); 8880Sstevel@tonic-gate if (!lc->isBound) { 8890Sstevel@tonic-gate *stat = connectCon(lc, 1); 8900Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 8910Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 8920Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 8930Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 8940Sstevel@tonic-gate myself, NIL(lc->sp), 8950Sstevel@tonic-gate ldap_err2string(*stat)); 8960Sstevel@tonic-gate releaseLC(lc); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate continue; 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 9010Sstevel@tonic-gate *stat = disconnectCon(lc); 9020Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 9030Sstevel@tonic-gate releaseLC(lc); 9040Sstevel@tonic-gate continue; 9050Sstevel@tonic-gate } 9060Sstevel@tonic-gate incrementRC(lc); 9070Sstevel@tonic-gate releaseLC(lc); 9080Sstevel@tonic-gate break; 9090Sstevel@tonic-gate } 9100Sstevel@tonic-gate 9110Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate return (lc); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate /* Release connection; decrements ref count for the connection */ 9170Sstevel@tonic-gate static void 9180Sstevel@tonic-gate releaseCon(__nis_ldap_conn_t *lc, int status) { 9190Sstevel@tonic-gate int stat; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate if (lc == 0) 9220Sstevel@tonic-gate return; 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate exclusiveLC(lc); 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate lc->status = status; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate decrementRC(lc); 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate if (lc->doDis) 9310Sstevel@tonic-gate stat = disconnectCon(lc); 9320Sstevel@tonic-gate else 9330Sstevel@tonic-gate stat = LDAP_SUCCESS; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate if (stat != LDAP_UNAVAILABLE) 9360Sstevel@tonic-gate releaseLC(lc); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate static __nis_ldap_conn_t * 9400Sstevel@tonic-gate createCon(char *sp, char *who, char *cred, auth_method_t method, int port) { 9410Sstevel@tonic-gate __nis_ldap_conn_t *lc; 9420Sstevel@tonic-gate char *myself = "createCon"; 9430Sstevel@tonic-gate char *r; 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate if (sp == 0) 9460Sstevel@tonic-gate return (0); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate lc = am(myself, sizeof (*lc)); 9490Sstevel@tonic-gate if (lc == 0) 9500Sstevel@tonic-gate return (0); 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate (void) mutex_init(&lc->mutex, 0, 0); 9530Sstevel@tonic-gate (void) mutex_init(&lc->rcMutex, 0, 0); 9540Sstevel@tonic-gate 9550Sstevel@tonic-gate /* If we need to delete 'lc', freeCon() wants the mutex held */ 9560Sstevel@tonic-gate exclusiveLC(lc); 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate lc->sp = sdup(myself, T, sp); 9590Sstevel@tonic-gate if (lc->sp == 0) { 9600Sstevel@tonic-gate (void) freeCon(lc); 9610Sstevel@tonic-gate return (0); 9620Sstevel@tonic-gate } 9630Sstevel@tonic-gate 9640Sstevel@tonic-gate if ((r = strchr(lc->sp, ']')) != 0) { 9650Sstevel@tonic-gate /* 9660Sstevel@tonic-gate * IPv6 address. Does libldap want this with the 9670Sstevel@tonic-gate * '[' and ']' left in place ? Assume so for now. 9680Sstevel@tonic-gate */ 9690Sstevel@tonic-gate r = strchr(r, ':'); 9700Sstevel@tonic-gate } else { 9710Sstevel@tonic-gate r = strchr(lc->sp, ':'); 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate if (r != NULL) { 9750Sstevel@tonic-gate *r++ = '\0'; 9760Sstevel@tonic-gate port = atoi(r); 9770Sstevel@tonic-gate } else if (port == 0) 9780Sstevel@tonic-gate port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT; 9790Sstevel@tonic-gate 9800Sstevel@tonic-gate if (who != 0) { 9810Sstevel@tonic-gate lc->who = sdup(myself, T, who); 9820Sstevel@tonic-gate if (lc->who == 0) { 9830Sstevel@tonic-gate (void) freeCon(lc); 9840Sstevel@tonic-gate return (0); 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate if (cred != 0) { 9890Sstevel@tonic-gate lc->cred = sdup(myself, T, cred); 9900Sstevel@tonic-gate if (lc->cred == 0) { 9910Sstevel@tonic-gate (void) freeCon(lc); 9920Sstevel@tonic-gate return (0); 9930Sstevel@tonic-gate } 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate lc->method = method; 9970Sstevel@tonic-gate lc->port = port; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate lc->bindTimeout = proxyInfo.bind_timeout; 10000Sstevel@tonic-gate lc->searchTimeout = proxyInfo.search_timeout; 10010Sstevel@tonic-gate lc->modifyTimeout = proxyInfo.modify_timeout; 10020Sstevel@tonic-gate lc->addTimeout = proxyInfo.add_timeout; 10030Sstevel@tonic-gate lc->deleteTimeout = proxyInfo.delete_timeout; 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate /* All other fields OK at zero */ 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate releaseLC(lc); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate return (lc); 10100Sstevel@tonic-gate } 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate static int 10130Sstevel@tonic-gate setupConList(char *serverList, char *who, char *cred, auth_method_t method) { 10140Sstevel@tonic-gate char *sls, *sl, *s, *e; 10150Sstevel@tonic-gate __nis_ldap_conn_t *lc, *tmp; 10160Sstevel@tonic-gate char *myself = "setupConList"; 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate if (serverList == 0) 10190Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate (void) rw_wrlock(&ldapConLock); 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate if (ldapCon != 0) { 10240Sstevel@tonic-gate /* Assume we've already been called and done the set-up */ 10250Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10260Sstevel@tonic-gate return (LDAP_SUCCESS); 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate /* Work on a copy of 'serverList' */ 10300Sstevel@tonic-gate sl = sls = sdup(myself, T, serverList); 10310Sstevel@tonic-gate if (sl == 0) { 10320Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10330Sstevel@tonic-gate return (LDAP_NO_MEMORY); 10340Sstevel@tonic-gate } 10350Sstevel@tonic-gate 10360Sstevel@tonic-gate /* Remove leading white space */ 10370Sstevel@tonic-gate for (0; *sl == ' ' || *sl == '\t'; sl++); 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate /* Create connection for each server on the list */ 10400Sstevel@tonic-gate for (s = sl; *s != '\0'; s = e+1) { 10410Sstevel@tonic-gate int l; 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate /* Find end of server/port token */ 10440Sstevel@tonic-gate for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++); 10450Sstevel@tonic-gate if (*e != '\0') 10460Sstevel@tonic-gate *e = '\0'; 10470Sstevel@tonic-gate else 10480Sstevel@tonic-gate e--; 10490Sstevel@tonic-gate l = slen(s); 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate if (l > 0) { 10520Sstevel@tonic-gate lc = createCon(s, who, cred, method, 0); 10530Sstevel@tonic-gate if (lc == 0) { 10540Sstevel@tonic-gate free(sls); 10550Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10560Sstevel@tonic-gate return (LDAP_NO_MEMORY); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate lc->onList = 1; 10590Sstevel@tonic-gate if (ldapCon == 0) { 10600Sstevel@tonic-gate ldapCon = lc; 10610Sstevel@tonic-gate } else { 10620Sstevel@tonic-gate /* Insert at end of list */ 10630Sstevel@tonic-gate for (tmp = ldapCon; tmp->next != 0; 10640Sstevel@tonic-gate tmp = tmp->next); 10650Sstevel@tonic-gate tmp->next = lc; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate free(sls); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate return (LDAP_SUCCESS); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate static bool_t 10780Sstevel@tonic-gate is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp) 10790Sstevel@tonic-gate { 10800Sstevel@tonic-gate return (strcasecmp(ludpp->lud_host, lc->sp) == 0 && 1081*8035SSreedhar.Chalamalasetti@Sun.COM ludpp->lud_port == lc->port); 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate static __nis_ldap_conn_t * 10850Sstevel@tonic-gate find_connection_from_list(__nis_ldap_conn_t *list, 10860Sstevel@tonic-gate LDAPURLDesc *ludpp, int *stat) 10870Sstevel@tonic-gate { 10880Sstevel@tonic-gate int ldapStat; 10890Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 10900Sstevel@tonic-gate if (stat == 0) 10910Sstevel@tonic-gate stat = &ldapStat; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate *stat = LDAP_SUCCESS; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate for (lc = list; lc != 0; lc = lc->next) { 10960Sstevel@tonic-gate exclusiveLC(lc); 10970Sstevel@tonic-gate if (is_same_connection(lc, ludpp)) { 10980Sstevel@tonic-gate if (!lc->isBound) { 10990Sstevel@tonic-gate *stat = connectCon(lc, 1); 11000Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 11010Sstevel@tonic-gate releaseLC(lc); 11020Sstevel@tonic-gate continue; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 11050Sstevel@tonic-gate (void) disconnectCon(lc); 11060Sstevel@tonic-gate releaseLC(lc); 11070Sstevel@tonic-gate continue; 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate incrementRC(lc); 11100Sstevel@tonic-gate releaseLC(lc); 11110Sstevel@tonic-gate break; 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate releaseLC(lc); 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate return (lc); 11160Sstevel@tonic-gate } 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate static __nis_ldap_conn_t * 11190Sstevel@tonic-gate findReferralCon(char **referralsp, int *stat) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 11220Sstevel@tonic-gate __nis_ldap_conn_t *tmp; 11230Sstevel@tonic-gate int ldapStat; 11240Sstevel@tonic-gate int i; 11250Sstevel@tonic-gate LDAPURLDesc *ludpp = NULL; 11260Sstevel@tonic-gate char *myself = "findReferralCon"; 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate if (stat == 0) 11290Sstevel@tonic-gate stat = &ldapStat; 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate *stat = LDAP_SUCCESS; 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate /* 11340Sstevel@tonic-gate * We have the referral lock - to prevent multiple 11350Sstevel@tonic-gate * threads from creating a referred connection simultaneously 11360Sstevel@tonic-gate * 11370Sstevel@tonic-gate * Note that this code assumes that the ldapCon list is a 11380Sstevel@tonic-gate * static list - that it has previously been created 11390Sstevel@tonic-gate * (otherwise we wouldn't have gotten a referral) and that 11400Sstevel@tonic-gate * it will neither grow or shrink - elements may have new 11410Sstevel@tonic-gate * connections or unbound. If this assumption is no longer valid, 11420Sstevel@tonic-gate * the locking needs to be reworked. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate (void) rw_rdlock(&referralConLock); 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 11470Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 11480Sstevel@tonic-gate continue; 11490Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 11500Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 11510Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 11520Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 11530Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11540Sstevel@tonic-gate continue; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate } else { 11570Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 11580Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11590Sstevel@tonic-gate continue; 11600Sstevel@tonic-gate } 11610Sstevel@tonic-gate } 11620Sstevel@tonic-gate #endif 11630Sstevel@tonic-gate 11640Sstevel@tonic-gate /* Determine if we already have a connection to the server */ 11650Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 11660Sstevel@tonic-gate if (lc == NULL) 11670Sstevel@tonic-gate lc = find_connection_from_list(ldapCon, ludpp, stat); 11680Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11690Sstevel@tonic-gate if (lc != NULL) { 11700Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 11710Sstevel@tonic-gate return (lc); 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate } 11740Sstevel@tonic-gate 11750Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 11760Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 11770Sstevel@tonic-gate continue; 11780Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 11790Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 11800Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 11810Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 11820Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11830Sstevel@tonic-gate continue; 11840Sstevel@tonic-gate } 11850Sstevel@tonic-gate } else { 11860Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 11870Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11880Sstevel@tonic-gate continue; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate } 11910Sstevel@tonic-gate #endif 11920Sstevel@tonic-gate lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn, 1193*8035SSreedhar.Chalamalasetti@Sun.COM proxyInfo.proxy_passwd, 1194*8035SSreedhar.Chalamalasetti@Sun.COM proxyInfo.auth_method, 1195*8035SSreedhar.Chalamalasetti@Sun.COM ludpp->lud_port); 11960Sstevel@tonic-gate if (lc == 0) { 11970Sstevel@tonic-gate ldap_free_urldesc(ludpp); 11980Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 11990Sstevel@tonic-gate *stat = LDAP_NO_MEMORY; 12000Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1201*8035SSreedhar.Chalamalasetti@Sun.COM "%s: Could not connect to host: %s", 1202*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(ludpp->lud_host)); 12030Sstevel@tonic-gate return (NULL); 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate lc->onList = 1; 12070Sstevel@tonic-gate if (ldapReferralCon == 0) { 12080Sstevel@tonic-gate ldapReferralCon = lc; 12090Sstevel@tonic-gate } else { 12100Sstevel@tonic-gate /* Insert at end of list */ 12110Sstevel@tonic-gate for (tmp = ldapReferralCon; tmp->next != 0; 1212*8035SSreedhar.Chalamalasetti@Sun.COM tmp = tmp->next) {} 12130Sstevel@tonic-gate tmp->next = lc; 12140Sstevel@tonic-gate } 12150Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 12160Sstevel@tonic-gate ldap_free_urldesc(ludpp); 12170Sstevel@tonic-gate if (lc != NULL) 12180Sstevel@tonic-gate break; 12190Sstevel@tonic-gate } 12200Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 12210Sstevel@tonic-gate if (lc == NULL) { 12220Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1223*8035SSreedhar.Chalamalasetti@Sun.COM "%s: Could not find a connection to %s, ...", 1224*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(referralsp[0])); 12250Sstevel@tonic-gate } 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate return (lc); 12280Sstevel@tonic-gate } 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate /* 12310Sstevel@tonic-gate * Find and return a connection believed to be OK and ensure children 12320Sstevel@tonic-gate * will never use parent's connection. 12330Sstevel@tonic-gate */ 12340Sstevel@tonic-gate static __nis_ldap_conn_t * 12350Sstevel@tonic-gate findYPCon(__nis_ldap_search_t *ls, int *stat) { 12360Sstevel@tonic-gate __nis_ldap_conn_t *lc, *newlc; 12370Sstevel@tonic-gate int ldapStat, newstat; 12380Sstevel@tonic-gate char *myself = "findYPCon"; 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate if (stat == 0) 12410Sstevel@tonic-gate stat = &ldapStat; 12420Sstevel@tonic-gate 12430Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate if (ldapCon == 0) { 12460Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 12470Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 12480Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 12490Sstevel@tonic-gate proxyInfo.proxy_dn, 12500Sstevel@tonic-gate proxyInfo.proxy_passwd, 12510Sstevel@tonic-gate proxyInfo.auth_method)) != 12520Sstevel@tonic-gate LDAP_SUCCESS) 12530Sstevel@tonic-gate return (0); 12540Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 12550Sstevel@tonic-gate } 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 12580Sstevel@tonic-gate exclusiveLC(lc); 12590Sstevel@tonic-gate 12600Sstevel@tonic-gate if (lc->isBound && (lc->doDis || lc->doDel)) { 12610Sstevel@tonic-gate *stat = disconnectCon(lc); 12620Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 12630Sstevel@tonic-gate releaseLC(lc); 12640Sstevel@tonic-gate continue; 12650Sstevel@tonic-gate } 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate /* 12680Sstevel@tonic-gate * Use a new connection for all cases except when 12690Sstevel@tonic-gate * requested by the main thread in the parent ypserv 12700Sstevel@tonic-gate * process. 12710Sstevel@tonic-gate */ 12720Sstevel@tonic-gate if (ls->useCon == 0) { 12730Sstevel@tonic-gate newlc = createCon(lc->sp, lc->who, lc->cred, 12740Sstevel@tonic-gate lc->method, lc->port); 12750Sstevel@tonic-gate if (!newlc) { 12760Sstevel@tonic-gate releaseLC(lc); 12770Sstevel@tonic-gate continue; 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate if (lc->ld != 0) { 12800Sstevel@tonic-gate newlc->simplePage = lc->simplePage; 12810Sstevel@tonic-gate newlc->vlv = lc->vlv; 12820Sstevel@tonic-gate newlc->batchFrom = lc->batchFrom; 12830Sstevel@tonic-gate } 12840Sstevel@tonic-gate releaseLC(lc); 12850Sstevel@tonic-gate exclusiveLC(newlc); 12860Sstevel@tonic-gate newstat = connectCon(newlc, 0); 12870Sstevel@tonic-gate if (newstat != LDAP_SUCCESS) { 12880Sstevel@tonic-gate if (newstat != LDAP_UNAVAILABLE) { 12890Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 12900Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 12910Sstevel@tonic-gate myself, NIL(newlc->sp), 12920Sstevel@tonic-gate ldap_err2string(*stat)); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate (void) freeCon(newlc); 12950Sstevel@tonic-gate newlc = 0; 12960Sstevel@tonic-gate continue; 12970Sstevel@tonic-gate } 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * No need to put newlc on the ldapCon list as this 13010Sstevel@tonic-gate * connection will be freed after use. 13020Sstevel@tonic-gate */ 13030Sstevel@tonic-gate newlc->onList = 0; 13040Sstevel@tonic-gate 13050Sstevel@tonic-gate lc = newlc; 13060Sstevel@tonic-gate } else if (!lc->isBound) { 13070Sstevel@tonic-gate *stat = connectCon(lc, 1); 13080Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 13090Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 13100Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 13110Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 13120Sstevel@tonic-gate myself, NIL(lc->sp), 13130Sstevel@tonic-gate ldap_err2string(*stat)); 13140Sstevel@tonic-gate releaseLC(lc); 13150Sstevel@tonic-gate } 13160Sstevel@tonic-gate continue; 13170Sstevel@tonic-gate } 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate incrementRC(lc); 13210Sstevel@tonic-gate releaseLC(lc); 13220Sstevel@tonic-gate break; 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate 13250Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate return (lc); 13280Sstevel@tonic-gate } 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate #define SORTKEYLIST "cn uid" 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate /* 13330Sstevel@tonic-gate * Perform an LDAP search operation per 'ls', adding the result(s) to 13340Sstevel@tonic-gate * a copy of the 'rvIn' structure; the copy becomes the return value. 13350Sstevel@tonic-gate * The caller must deallocate both 'rvIn' and the result, if any. 13360Sstevel@tonic-gate * 13370Sstevel@tonic-gate * On entry, '*numValues' contains a hint regarding the expected 13380Sstevel@tonic-gate * number of entries. Zero is the same as one, and negative values 13390Sstevel@tonic-gate * imply no information. This is used to decide whether or not to 13400Sstevel@tonic-gate * try an indexed search. 13410Sstevel@tonic-gate * 13420Sstevel@tonic-gate * On successful (non-NULL) return, '*numValues' contains the number 13430Sstevel@tonic-gate * of __nis_rule_value_t elements in the returned array, and '*stat' 13440Sstevel@tonic-gate * the LDAP operations status. 13450Sstevel@tonic-gate */ 13460Sstevel@tonic-gate __nis_rule_value_t * 13470Sstevel@tonic-gate ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn, 13480Sstevel@tonic-gate int *ldapStat) { 13490Sstevel@tonic-gate __nis_rule_value_t *rv = 0; 13500Sstevel@tonic-gate int stat, numEntries, numVals, tnv, done, lprEc; 13510Sstevel@tonic-gate LDAPMessage *msg = 0, *m; 13520Sstevel@tonic-gate __nis_ldap_conn_t *lc; 13530Sstevel@tonic-gate struct timeval tv, start, now; 13540Sstevel@tonic-gate LDAPsortkey **sortKeyList = 0; 13550Sstevel@tonic-gate LDAPControl *ctrls[3], *sortCtrl = 0, *vlvCtrl = 0; 13560Sstevel@tonic-gate LDAPControl **retCtrls = 0; 13570Sstevel@tonic-gate LDAPVirtualList vList; 13580Sstevel@tonic-gate struct berval *spCookie = 0; 13590Sstevel@tonic-gate int doVLV = 0; 13600Sstevel@tonic-gate int doSP = 0; 13610Sstevel@tonic-gate long index; 13620Sstevel@tonic-gate char *myself = "ldapSearch"; 13630Sstevel@tonic-gate bool_t follow_referral = 13640Sstevel@tonic-gate proxyInfo.follow_referral == follow; 13650Sstevel@tonic-gate int doIndex = 1; 13660Sstevel@tonic-gate char **referralsp = NULL; 13670Sstevel@tonic-gate 1368*8035SSreedhar.Chalamalasetti@Sun.COM ctrls[0] = ctrls[1] = ctrls[2] = 0; 1369*8035SSreedhar.Chalamalasetti@Sun.COM 13700Sstevel@tonic-gate if (ldapStat == 0) 13710Sstevel@tonic-gate ldapStat = &stat; 13720Sstevel@tonic-gate 13730Sstevel@tonic-gate if (ls == 0) { 13740Sstevel@tonic-gate *ldapStat = LDAP_PARAM_ERROR; 13750Sstevel@tonic-gate return (0); 13760Sstevel@tonic-gate } 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate if (yp2ldap) { 13790Sstevel@tonic-gate /* make sure the parent's connection is not used by child */ 13800Sstevel@tonic-gate if ((lc = findYPCon(ls, ldapStat)) == 0) { 13810Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 13820Sstevel@tonic-gate return (0); 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate } else { 13850Sstevel@tonic-gate if ((lc = findCon(ldapStat)) == 0) { 13860Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 13870Sstevel@tonic-gate return (0); 13880Sstevel@tonic-gate } 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate if (numValues != 0 && (*numValues == 0 || *numValues == 1)) 13920Sstevel@tonic-gate doIndex = 0; 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate retry_new_conn: 13950Sstevel@tonic-gate /* Prefer VLV over simple page, and SP over nothing */ 13960Sstevel@tonic-gate if (doIndex && lc->vlv) { 13970Sstevel@tonic-gate stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST); 13980Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 13990Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14000Sstevel@tonic-gate "%s: Error creating sort keylist: %s", 14010Sstevel@tonic-gate myself, ldap_err2string(stat)); 14020Sstevel@tonic-gate freeRuleValue(rv, numVals); 14030Sstevel@tonic-gate *ldapStat = stat; 14040Sstevel@tonic-gate rv = 0; 14050Sstevel@tonic-gate goto retry_noVLV; 14060Sstevel@tonic-gate } 14070Sstevel@tonic-gate stat = ldap_create_sort_control(lc->ld, sortKeyList, 1, 14080Sstevel@tonic-gate &sortCtrl); 14090Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 14100Sstevel@tonic-gate vList.ldvlist_before_count = 0; 14110Sstevel@tonic-gate vList.ldvlist_after_count = lc->batchFrom - 1; 14120Sstevel@tonic-gate vList.ldvlist_attrvalue = 0; 14130Sstevel@tonic-gate vList.ldvlist_extradata = 0; 14140Sstevel@tonic-gate index = 1; 14150Sstevel@tonic-gate doVLV = 1; 14160Sstevel@tonic-gate } else { 14170Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 14180Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14190Sstevel@tonic-gate "%s: Error creating VLV sort control: %s", 14200Sstevel@tonic-gate myself, ldap_err2string(stat)); 14210Sstevel@tonic-gate freeRuleValue(rv, numVals); 14220Sstevel@tonic-gate *ldapStat = stat; 14230Sstevel@tonic-gate rv = 0; 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate } 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate retry_noVLV: 14280Sstevel@tonic-gate 14290Sstevel@tonic-gate if (doIndex && !doVLV && lc->simplePage) { 14300Sstevel@tonic-gate spCookie = am(myself, sizeof (*spCookie)); 14310Sstevel@tonic-gate if (spCookie != 0 && 14320Sstevel@tonic-gate (spCookie->bv_val = sdup(myself, T, "")) != 0) { 14330Sstevel@tonic-gate spCookie->bv_len = 0; 14340Sstevel@tonic-gate doSP = 1; 14350Sstevel@tonic-gate } else { 14360Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 14370Sstevel@tonic-gate "%s: No memory for simple page cookie; using un-paged LDAP search", 14380Sstevel@tonic-gate myself); 14390Sstevel@tonic-gate freeRuleValue(rv, numVals); 14400Sstevel@tonic-gate *ldapStat = stat; 14410Sstevel@tonic-gate rv = 0; 14420Sstevel@tonic-gate goto cleanup; 14430Sstevel@tonic-gate } 14440Sstevel@tonic-gate } 14450Sstevel@tonic-gate 14460Sstevel@tonic-gate if (!doVLV && !doSP) 14470Sstevel@tonic-gate ctrls[0] = ctrls[1] = 0; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate numVals = 0; 14500Sstevel@tonic-gate done = 0; 14510Sstevel@tonic-gate 14520Sstevel@tonic-gate if (ls->timeout.tv_sec || ls->timeout.tv_usec) { 14530Sstevel@tonic-gate tv = ls->timeout; 14540Sstevel@tonic-gate } else { 14550Sstevel@tonic-gate tv = lc->searchTimeout; 14560Sstevel@tonic-gate } 14570Sstevel@tonic-gate (void) gettimeofday(&start, 0); 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate do { 14600Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 14610Sstevel@tonic-gate if (doVLV && ls->base != LDAP_SCOPE_BASE) { 14620Sstevel@tonic-gate vList.ldvlist_index = index; 14630Sstevel@tonic-gate vList.ldvlist_size = 0; 14640Sstevel@tonic-gate if (vlvCtrl != 0) 14650Sstevel@tonic-gate ldap_control_free(vlvCtrl); 14660Sstevel@tonic-gate stat = ldap_create_virtuallist_control(lc->ld, 14670Sstevel@tonic-gate &vList, &vlvCtrl); 14680Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 14690Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 14700Sstevel@tonic-gate &stat); 14710Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 14720Sstevel@tonic-gate "%s: Error creating VLV at index %ld: %s", 14730Sstevel@tonic-gate myself, index, ldap_err2string(stat)); 14740Sstevel@tonic-gate *ldapStat = stat; 14750Sstevel@tonic-gate freeRuleValue(rv, numVals); 14760Sstevel@tonic-gate rv = 0; 14770Sstevel@tonic-gate goto cleanup; 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate ctrls[0] = sortCtrl; 14800Sstevel@tonic-gate ctrls[1] = vlvCtrl; 14810Sstevel@tonic-gate ctrls[2] = 0; 14820Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 14830Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 14840Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 14850Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 14860Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 14870Sstevel@tonic-gate } else if (doSP && ls->base != LDAP_SCOPE_BASE) { 14880Sstevel@tonic-gate if (ctrls[0] != 0) 14890Sstevel@tonic-gate ldap_control_free(ctrls[0]); 14900Sstevel@tonic-gate stat = ldap_create_page_control(lc->ld, 14910Sstevel@tonic-gate lc->batchFrom, spCookie, 0, &ctrls[0]); 14920Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 14930Sstevel@tonic-gate ber_bvfree(spCookie); 14940Sstevel@tonic-gate spCookie = 0; 14950Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 14960Sstevel@tonic-gate &stat); 14970Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 14980Sstevel@tonic-gate "%s: Simple page error: %s", 14990Sstevel@tonic-gate myself, ldap_err2string(stat)); 15000Sstevel@tonic-gate freeRuleValue(rv, numVals); 15010Sstevel@tonic-gate *ldapStat = stat; 15020Sstevel@tonic-gate rv = 0; 15030Sstevel@tonic-gate goto cleanup; 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate ctrls[1] = 0; 15060Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 15070Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 15080Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 15090Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 15100Sstevel@tonic-gate } else { 15110Sstevel@tonic-gate stat = ldap_search_st(lc->ld, ls->base, ls->scope, 15120Sstevel@tonic-gate ls->filter, ls->attrs, ls->attrsonly, 15130Sstevel@tonic-gate &tv, &msg); 15140Sstevel@tonic-gate } 15150Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 15160Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate if (stat == LDAP_SERVER_DOWN) { 15190Sstevel@tonic-gate lc->doDis++; 15200Sstevel@tonic-gate releaseCon(lc, stat); 15210Sstevel@tonic-gate lc = (yp2ldap)?findYPCon(ls, ldapStat): 15220Sstevel@tonic-gate findCon(ldapStat); 15230Sstevel@tonic-gate if (lc == 0) { 15240Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 15250Sstevel@tonic-gate rv = 0; 15260Sstevel@tonic-gate goto cleanup; 15270Sstevel@tonic-gate } 15280Sstevel@tonic-gate goto retry_new_conn; 15290Sstevel@tonic-gate } 15300Sstevel@tonic-gate 15310Sstevel@tonic-gate if (stat == LDAP_REFERRAL && follow_referral) { 15320Sstevel@tonic-gate (void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL, 15330Sstevel@tonic-gate &referralsp, NULL, 0); 15340Sstevel@tonic-gate if (referralsp != NULL) { 15350Sstevel@tonic-gate /* We support at most one level of referrals */ 15360Sstevel@tonic-gate follow_referral = FALSE; 15370Sstevel@tonic-gate releaseCon(lc, stat); 15380Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 15390Sstevel@tonic-gate ldap_value_free(referralsp); 15400Sstevel@tonic-gate if (lc == NULL) { 15410Sstevel@tonic-gate freeRuleValue(rv, numVals); 15420Sstevel@tonic-gate rv = 0; 15430Sstevel@tonic-gate *ldapStat = stat; 15440Sstevel@tonic-gate goto cleanup; 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate stat = LDAP_SUCCESS; 15470Sstevel@tonic-gate goto retry_new_conn; 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate *ldapStat = stat; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate if (*ldapStat == LDAP_NO_SUCH_OBJECT) { 15530Sstevel@tonic-gate freeRuleValue(rv, numVals); 15540Sstevel@tonic-gate rv = 0; 15550Sstevel@tonic-gate goto cleanup; 15560Sstevel@tonic-gate } else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) { 15570Sstevel@tonic-gate /* 15580Sstevel@tonic-gate * The LDAP server (at least Netscape 4.x) can return 15590Sstevel@tonic-gate * LDAP_INSUFFICIENT_ACCESS when VLV is supported, 15600Sstevel@tonic-gate * but not for the bind DN specified. So, just in 15610Sstevel@tonic-gate * case, we clean up, and try again without VLV. 15620Sstevel@tonic-gate */ 15630Sstevel@tonic-gate doVLV = 0; 15640Sstevel@tonic-gate if (msg != 0) { 15650Sstevel@tonic-gate (void) ldap_msgfree(msg); 15660Sstevel@tonic-gate msg = 0; 15670Sstevel@tonic-gate } 15680Sstevel@tonic-gate if (ctrls[0] != 0) { 15690Sstevel@tonic-gate ldap_control_free(ctrls[0]); 15700Sstevel@tonic-gate ctrls[0] = 0; 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate if (ctrls[1] != 0) { 15730Sstevel@tonic-gate ldap_control_free(ctrls[1]); 15740Sstevel@tonic-gate ctrls[1] = 0; 15750Sstevel@tonic-gate } 15760Sstevel@tonic-gate logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING, 15770Sstevel@tonic-gate "%s: VLV insufficient access from server %s; retrying without VLV", 15780Sstevel@tonic-gate myself, NIL(lc->sp)); 15790Sstevel@tonic-gate goto retry_noVLV; 15800Sstevel@tonic-gate } else if (*ldapStat != LDAP_SUCCESS) { 15810Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 15820Sstevel@tonic-gate "ldap_search(0x%x,\n\t\"%s\",\n\t %d,", 15830Sstevel@tonic-gate lc->ld, NIL(ls->base), ls->scope); 15840Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 15850Sstevel@tonic-gate "\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)", 15860Sstevel@tonic-gate NIL(ls->filter), ls->attrs, ls->attrsonly, 15870Sstevel@tonic-gate *ldapStat, ldap_err2string(stat)); 15880Sstevel@tonic-gate freeRuleValue(rv, numVals); 15890Sstevel@tonic-gate rv = 0; 15900Sstevel@tonic-gate goto cleanup; 15910Sstevel@tonic-gate } 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate numEntries = ldap_count_entries(lc->ld, msg); 15940Sstevel@tonic-gate if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) { 15950Sstevel@tonic-gate /* 15960Sstevel@tonic-gate * This is a bit weird, but the server (or, at least, 15970Sstevel@tonic-gate * ldap_search_ext()) can sometimes return 15980Sstevel@tonic-gate * LDAP_SUCCESS and no entries when it didn't 15990Sstevel@tonic-gate * find what we were looking for. Seems it ought to 16000Sstevel@tonic-gate * return LDAP_NO_SUCH_OBJECT or some such. 16010Sstevel@tonic-gate */ 16020Sstevel@tonic-gate freeRuleValue(rv, numVals); 16030Sstevel@tonic-gate rv = 0; 16040Sstevel@tonic-gate *ldapStat = LDAP_NO_SUCH_OBJECT; 16050Sstevel@tonic-gate goto cleanup; 16060Sstevel@tonic-gate } 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate tnv = numVals + numEntries; 16090Sstevel@tonic-gate if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) { 16100Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16110Sstevel@tonic-gate goto cleanup; 16120Sstevel@tonic-gate } 16130Sstevel@tonic-gate 16140Sstevel@tonic-gate for (m = ldap_first_entry(lc->ld, msg); m != 0; 16150Sstevel@tonic-gate m = ldap_next_entry(lc->ld, m), numVals++) { 16160Sstevel@tonic-gate char *nm; 16170Sstevel@tonic-gate BerElement *ber = 0; 16180Sstevel@tonic-gate 16190Sstevel@tonic-gate if (numVals > tnv) { 16200Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 16210Sstevel@tonic-gate "%s: Inconsistent LDAP entry count > %d", 16220Sstevel@tonic-gate myself, numEntries); 16230Sstevel@tonic-gate break; 16240Sstevel@tonic-gate } 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate nm = ldap_get_dn(lc->ld, m); 16270Sstevel@tonic-gate if (nm == 0 || addSAttr2RuleValue("dn", nm, 16280Sstevel@tonic-gate &rv[numVals])) { 16290Sstevel@tonic-gate sfree(nm); 16300Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16310Sstevel@tonic-gate freeRuleValue(rv, tnv); 16320Sstevel@tonic-gate rv = 0; 16330Sstevel@tonic-gate goto cleanup; 16340Sstevel@tonic-gate } 16350Sstevel@tonic-gate sfree(nm); 16360Sstevel@tonic-gate 16370Sstevel@tonic-gate for (nm = ldap_first_attribute(lc->ld, m, &ber); 16380Sstevel@tonic-gate nm != 0; 16390Sstevel@tonic-gate nm = ldap_next_attribute(lc->ld, m, ber)) { 16400Sstevel@tonic-gate struct berval **val; 16410Sstevel@tonic-gate int i, nv; 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate val = ldap_get_values_len(lc->ld, m, nm); 16440Sstevel@tonic-gate nv = (val == 0) ? 0 : 16450Sstevel@tonic-gate ldap_count_values_len(val); 16460Sstevel@tonic-gate for (i = 0; i < nv; i++) { 16470Sstevel@tonic-gate /* 16480Sstevel@tonic-gate * Since we don't know if the value is 16490Sstevel@tonic-gate * BER-encoded or not, we mark it as a 16500Sstevel@tonic-gate * string. All is well as long as we 16510Sstevel@tonic-gate * don't insist on 'vt_ber' when 16520Sstevel@tonic-gate * interpreting. 16530Sstevel@tonic-gate */ 16540Sstevel@tonic-gate if (addAttr2RuleValue(vt_string, nm, 16550Sstevel@tonic-gate val[i]->bv_val, 16560Sstevel@tonic-gate val[i]->bv_len, 16570Sstevel@tonic-gate &rv[numVals])) { 16580Sstevel@tonic-gate if (ber != 0) 16590Sstevel@tonic-gate ber_free(ber, 0); 16600Sstevel@tonic-gate ldap_value_free_len(val); 16610Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 16620Sstevel@tonic-gate freeRuleValue(rv, tnv); 16630Sstevel@tonic-gate rv = 0; 16640Sstevel@tonic-gate goto cleanup; 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate } 16670Sstevel@tonic-gate /* 16680Sstevel@tonic-gate * XXX the ldap_first_attribute(3LDAP) man 16690Sstevel@tonic-gate * page says that the ldap_first_attribute/ 16700Sstevel@tonic-gate * ldap_next_attribute should be treated as 16710Sstevel@tonic-gate * static, but the libldap.so.4 code mallocs 16720Sstevel@tonic-gate * (and it's not TSD). So, in order to avoid 16730Sstevel@tonic-gate * a leak, we free the return value. 16740Sstevel@tonic-gate */ 16750Sstevel@tonic-gate ldap_memfree(nm); 16760Sstevel@tonic-gate if (val != 0) 16770Sstevel@tonic-gate ldap_value_free_len(val); 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate /* 16800Sstevel@tonic-gate * XXX ldap_next_attribute(3LDAP) says that the 'ber' 16810Sstevel@tonic-gate * pointer is freed when it returns NULL, but that's 16820Sstevel@tonic-gate * not implemented in the libldap.so.4 code, so we 16830Sstevel@tonic-gate * free it here in order to avoid a memory leak. 16840Sstevel@tonic-gate */ 16850Sstevel@tonic-gate if (ber != 0) 16860Sstevel@tonic-gate ber_free(ber, 0); 16870Sstevel@tonic-gate } 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate if (numVals != tnv) { 16900Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 16910Sstevel@tonic-gate "%s: Inconsistent LDAP entry count, found = %d, expected %d", 16920Sstevel@tonic-gate myself, numVals, tnv); 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate if (doVLV) { 16960Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 16970Sstevel@tonic-gate &retCtrls, 0); 16980Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 16990Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 17000Sstevel@tonic-gate &stat); 17010Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 17020Sstevel@tonic-gate "%s: VLV parse result error: %s", 17030Sstevel@tonic-gate myself, ldap_err2string(stat)); 17040Sstevel@tonic-gate *ldapStat = stat; 17050Sstevel@tonic-gate freeRuleValue(rv, tnv); 17060Sstevel@tonic-gate rv = 0; 17070Sstevel@tonic-gate goto cleanup; 17080Sstevel@tonic-gate } 17090Sstevel@tonic-gate if (retCtrls != 0) { 17100Sstevel@tonic-gate unsigned long targetPosP = 0; 17110Sstevel@tonic-gate unsigned long listSize = 0; 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate stat = ldap_parse_virtuallist_control(lc->ld, 17140Sstevel@tonic-gate retCtrls, &targetPosP, &listSize, 17150Sstevel@tonic-gate &lprEc); 17160Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 17170Sstevel@tonic-gate index = targetPosP + lc->batchFrom; 17180Sstevel@tonic-gate if (index >= listSize) 17190Sstevel@tonic-gate done = 1; 17200Sstevel@tonic-gate } 17210Sstevel@tonic-gate ldap_controls_free(retCtrls); 17220Sstevel@tonic-gate retCtrls = 0; 17230Sstevel@tonic-gate } else { 17240Sstevel@tonic-gate done = 1; 17250Sstevel@tonic-gate } 17260Sstevel@tonic-gate } else if (doSP) { 17270Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 17280Sstevel@tonic-gate &retCtrls, 0); 17290Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 17300Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 17310Sstevel@tonic-gate &stat); 17320Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 17330Sstevel@tonic-gate "%s: Simple page parse result error: %s", 17340Sstevel@tonic-gate myself, ldap_err2string(stat)); 17350Sstevel@tonic-gate *ldapStat = stat; 17360Sstevel@tonic-gate freeRuleValue(rv, tnv); 17370Sstevel@tonic-gate rv = 0; 17380Sstevel@tonic-gate goto cleanup; 17390Sstevel@tonic-gate } 17400Sstevel@tonic-gate if (retCtrls != 0) { 17410Sstevel@tonic-gate unsigned int count; 17420Sstevel@tonic-gate 17430Sstevel@tonic-gate if (spCookie != 0) { 17440Sstevel@tonic-gate ber_bvfree(spCookie); 17450Sstevel@tonic-gate spCookie = 0; 17460Sstevel@tonic-gate } 17470Sstevel@tonic-gate stat = ldap_parse_page_control(lc->ld, 17480Sstevel@tonic-gate retCtrls, &count, &spCookie); 17490Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 17500Sstevel@tonic-gate if (spCookie == 0 || 17510Sstevel@tonic-gate spCookie->bv_val == 0 || 17520Sstevel@tonic-gate spCookie->bv_len == 0) 17530Sstevel@tonic-gate done = 1; 17540Sstevel@tonic-gate } 17550Sstevel@tonic-gate ldap_controls_free(retCtrls); 17560Sstevel@tonic-gate retCtrls = 0; 17570Sstevel@tonic-gate } else { 17580Sstevel@tonic-gate done = 1; 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate } else { 17610Sstevel@tonic-gate done = 1; 17620Sstevel@tonic-gate } 17630Sstevel@tonic-gate 17640Sstevel@tonic-gate (void) ldap_msgfree(msg); 17650Sstevel@tonic-gate msg = 0; 17660Sstevel@tonic-gate 17670Sstevel@tonic-gate /* 17680Sstevel@tonic-gate * If we're using VLV or SP, the timeout should apply 17690Sstevel@tonic-gate * to all calls as an aggregate, so we need to reduce 17700Sstevel@tonic-gate * 'tv' with the time spent on this chunk of data. 17710Sstevel@tonic-gate */ 17720Sstevel@tonic-gate if (!done) { 17730Sstevel@tonic-gate struct timeval tmp; 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate (void) gettimeofday(&now, 0); 17760Sstevel@tonic-gate tmp = now; 17770Sstevel@tonic-gate now.tv_sec -= start.tv_sec; 17780Sstevel@tonic-gate now.tv_usec -= start.tv_usec; 17790Sstevel@tonic-gate if (now.tv_usec < 0) { 17800Sstevel@tonic-gate now.tv_usec += 1000000; 17810Sstevel@tonic-gate now.tv_sec -= 1; 17820Sstevel@tonic-gate } 17830Sstevel@tonic-gate tv.tv_sec -= now.tv_sec; 17840Sstevel@tonic-gate tv.tv_usec -= now.tv_usec; 17850Sstevel@tonic-gate if (tv.tv_usec < 0) { 17860Sstevel@tonic-gate tv.tv_usec += 1000000; 17870Sstevel@tonic-gate tv.tv_sec -= 1; 17880Sstevel@tonic-gate } 17890Sstevel@tonic-gate if (tv.tv_sec < 0) { 17900Sstevel@tonic-gate *ldapStat = LDAP_TIMEOUT; 17910Sstevel@tonic-gate freeRuleValue(rv, tnv); 17920Sstevel@tonic-gate rv = 0; 17930Sstevel@tonic-gate goto cleanup; 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate start = tmp; 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate } while (!done); 17990Sstevel@tonic-gate 18000Sstevel@tonic-gate if (numValues != 0) 18010Sstevel@tonic-gate *numValues = numVals; 18020Sstevel@tonic-gate 18030Sstevel@tonic-gate cleanup: 18040Sstevel@tonic-gate if (NULL != lc) { 18050Sstevel@tonic-gate if (yp2ldap && ls->useCon == 0) { 18060Sstevel@tonic-gate /* Disconnect and free the connection */ 18070Sstevel@tonic-gate lc->doDis++; 18080Sstevel@tonic-gate lc->doDel++; 18090Sstevel@tonic-gate releaseCon(lc, stat); 18100Sstevel@tonic-gate releaseLC(lc); 18110Sstevel@tonic-gate 18120Sstevel@tonic-gate } else { 18130Sstevel@tonic-gate releaseCon(lc, stat); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate } 18160Sstevel@tonic-gate if (msg != 0) 18170Sstevel@tonic-gate (void) ldap_msgfree(msg); 18180Sstevel@tonic-gate if (ctrls[0] != 0) 18190Sstevel@tonic-gate ldap_control_free(ctrls[0]); 18200Sstevel@tonic-gate if (ctrls[1] != 0) 18210Sstevel@tonic-gate ldap_control_free(ctrls[1]); 18220Sstevel@tonic-gate if (spCookie != 0) 18230Sstevel@tonic-gate ber_bvfree(spCookie); 18240Sstevel@tonic-gate if (sortKeyList != 0) 18250Sstevel@tonic-gate ldap_free_sort_keylist(sortKeyList); 18260Sstevel@tonic-gate 18270Sstevel@tonic-gate return (rv); 18280Sstevel@tonic-gate } 18290Sstevel@tonic-gate 18300Sstevel@tonic-gate static void 18310Sstevel@tonic-gate freeLdapModEntry(LDAPMod *m) { 18320Sstevel@tonic-gate 18330Sstevel@tonic-gate if (m == 0) 18340Sstevel@tonic-gate return; 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate sfree(m->mod_type); 18370Sstevel@tonic-gate if ((m->mod_op & LDAP_MOD_BVALUES) == 0) { 18380Sstevel@tonic-gate char **v = m->mod_values; 18390Sstevel@tonic-gate 18400Sstevel@tonic-gate if (v != 0) { 18410Sstevel@tonic-gate while (*v != 0) { 18420Sstevel@tonic-gate sfree(*v); 18430Sstevel@tonic-gate v++; 18440Sstevel@tonic-gate } 18450Sstevel@tonic-gate free(m->mod_values); 18460Sstevel@tonic-gate } 18470Sstevel@tonic-gate } else { 18480Sstevel@tonic-gate struct berval **b = m->mod_bvalues; 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate if (b != 0) { 18510Sstevel@tonic-gate while (*b != 0) { 18520Sstevel@tonic-gate sfree((*b)->bv_val); 18530Sstevel@tonic-gate free(*b); 18540Sstevel@tonic-gate b++; 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate free(m->mod_bvalues); 18570Sstevel@tonic-gate } 18580Sstevel@tonic-gate } 18590Sstevel@tonic-gate 18600Sstevel@tonic-gate free(m); 18610Sstevel@tonic-gate } 18620Sstevel@tonic-gate 18630Sstevel@tonic-gate static void 18640Sstevel@tonic-gate freeLdapMod(LDAPMod **mods) { 18650Sstevel@tonic-gate LDAPMod *m, **org = mods; 18660Sstevel@tonic-gate 18670Sstevel@tonic-gate if (mods == 0) 18680Sstevel@tonic-gate return; 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate while ((m = *mods) != 0) { 18710Sstevel@tonic-gate freeLdapModEntry(m); 18720Sstevel@tonic-gate mods++; 18730Sstevel@tonic-gate } 18740Sstevel@tonic-gate 18750Sstevel@tonic-gate free(org); 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate 18780Sstevel@tonic-gate /* 18790Sstevel@tonic-gate * Convert a rule-value structure to the corresponding LDAPMod. 18800Sstevel@tonic-gate * If 'add' is set, attributes/values are added; object classes 18810Sstevel@tonic-gate * are also added. If 'add' is cleared, attributes/values are modified, 18820Sstevel@tonic-gate * and 'oc' controls whether or not object classes are added. 18830Sstevel@tonic-gate */ 18840Sstevel@tonic-gate LDAPMod ** 18850Sstevel@tonic-gate search2LdapMod(__nis_rule_value_t *rv, int add, int oc) { 18860Sstevel@tonic-gate LDAPMod **mods; 18870Sstevel@tonic-gate int i, j, nm; 18880Sstevel@tonic-gate char *myself = "search2LdapMod"; 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate if (rv == 0 || rv->numAttrs <= 0) 18910Sstevel@tonic-gate return (0); 18920Sstevel@tonic-gate 18930Sstevel@tonic-gate mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0])); 18940Sstevel@tonic-gate if (mods == 0) 18950Sstevel@tonic-gate return (0); 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate for (i = 0, nm = 0; i < rv->numAttrs; i++) { 18980Sstevel@tonic-gate int isOc; 18990Sstevel@tonic-gate /* 19000Sstevel@tonic-gate * If we're creating an LDAPMod array for an add operation, 19010Sstevel@tonic-gate * just skip attributes that should be deleted. 19020Sstevel@tonic-gate */ 19030Sstevel@tonic-gate if (add && rv->attrVal[i].numVals < 0) 19040Sstevel@tonic-gate continue; 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate /* 19070Sstevel@tonic-gate * Skip DN; it's specified separately to ldap_modify() 19080Sstevel@tonic-gate * and ldap_add(), and mustn't appear among the 19090Sstevel@tonic-gate * attributes to be modified/added. 19100Sstevel@tonic-gate */ 19110Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 19120Sstevel@tonic-gate continue; 19130Sstevel@tonic-gate 19140Sstevel@tonic-gate /* 19150Sstevel@tonic-gate * If modifying, and 'oc' is off, skip object class 19160Sstevel@tonic-gate * attributes. 19170Sstevel@tonic-gate */ 19180Sstevel@tonic-gate isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0); 19190Sstevel@tonic-gate if (!add && !oc && isOc) 19200Sstevel@tonic-gate continue; 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate mods[nm] = am(myself, sizeof (*mods[nm])); 19230Sstevel@tonic-gate if (mods[nm] == 0) { 19240Sstevel@tonic-gate freeLdapMod(mods); 19250Sstevel@tonic-gate return (0); 19260Sstevel@tonic-gate } 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate /* 'mod_type' is the attribute name */ 19290Sstevel@tonic-gate mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]); 19300Sstevel@tonic-gate if (mods[nm]->mod_type == 0) { 19310Sstevel@tonic-gate freeLdapMod(mods); 19320Sstevel@tonic-gate return (0); 19330Sstevel@tonic-gate } 19340Sstevel@tonic-gate 19350Sstevel@tonic-gate /* 19360Sstevel@tonic-gate * numVals < 0 means attribute and all values should 19370Sstevel@tonic-gate * be deleted. 19380Sstevel@tonic-gate */ 19390Sstevel@tonic-gate if (rv->attrVal[i].numVals < 0) { 19400Sstevel@tonic-gate mods[nm]->mod_op = LDAP_MOD_DELETE; 19410Sstevel@tonic-gate mods[nm]->mod_values = 0; 19420Sstevel@tonic-gate nm++; 19430Sstevel@tonic-gate continue; 19440Sstevel@tonic-gate } 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate /* objectClass attributes always added */ 19470Sstevel@tonic-gate mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE); 19480Sstevel@tonic-gate 19490Sstevel@tonic-gate if (rv->attrVal[i].type == vt_string) { 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate * mods[]->mod_values is a NULL-terminated array 19520Sstevel@tonic-gate * of (char *)'s. 19530Sstevel@tonic-gate */ 19540Sstevel@tonic-gate mods[nm]->mod_values = am(myself, 19550Sstevel@tonic-gate (rv->attrVal[i].numVals + 1) * 19560Sstevel@tonic-gate sizeof (mods[nm]->mod_values[0])); 19570Sstevel@tonic-gate if (mods[nm]->mod_values == 0) { 19580Sstevel@tonic-gate freeLdapMod(mods); 19590Sstevel@tonic-gate return (0); 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 19620Sstevel@tonic-gate /* 19630Sstevel@tonic-gate * Just in case the string isn't NUL 19640Sstevel@tonic-gate * terminated, add one byte to the 19650Sstevel@tonic-gate * allocated length; am() will initialize 19660Sstevel@tonic-gate * the buffer to zero. 19670Sstevel@tonic-gate */ 19680Sstevel@tonic-gate mods[nm]->mod_values[j] = am(myself, 19690Sstevel@tonic-gate rv->attrVal[i].val[j].length + 1); 19700Sstevel@tonic-gate if (mods[nm]->mod_values[j] == 0) { 19710Sstevel@tonic-gate freeLdapMod(mods); 19720Sstevel@tonic-gate return (0); 19730Sstevel@tonic-gate } 19740Sstevel@tonic-gate memcpy(mods[nm]->mod_values[j], 19750Sstevel@tonic-gate rv->attrVal[i].val[j].value, 19760Sstevel@tonic-gate rv->attrVal[i].val[j].length); 19770Sstevel@tonic-gate } 19780Sstevel@tonic-gate } else { 19790Sstevel@tonic-gate mods[nm]->mod_op |= LDAP_MOD_BVALUES; 19800Sstevel@tonic-gate mods[nm]->mod_bvalues = am(myself, 19810Sstevel@tonic-gate (rv->attrVal[i].numVals+1) * 19820Sstevel@tonic-gate sizeof (mods[nm]->mod_bvalues[0])); 19830Sstevel@tonic-gate if (mods[nm]->mod_bvalues == 0) { 19840Sstevel@tonic-gate freeLdapMod(mods); 19850Sstevel@tonic-gate return (0); 19860Sstevel@tonic-gate } 19870Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 19880Sstevel@tonic-gate mods[nm]->mod_bvalues[j] = am(myself, 19890Sstevel@tonic-gate sizeof (*mods[nm]->mod_bvalues[j])); 19900Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j] == 0) { 19910Sstevel@tonic-gate freeLdapMod(mods); 19920Sstevel@tonic-gate return (0); 19930Sstevel@tonic-gate } 19940Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_val = am(myself, 19950Sstevel@tonic-gate rv->attrVal[i].val[j].length); 19960Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j]->bv_val == 0) { 19970Sstevel@tonic-gate freeLdapMod(mods); 19980Sstevel@tonic-gate return (0); 19990Sstevel@tonic-gate } 20000Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len = 20010Sstevel@tonic-gate rv->attrVal[i].val[j].length; 20020Sstevel@tonic-gate memcpy(mods[nm]->mod_bvalues[j]->bv_val, 20030Sstevel@tonic-gate rv->attrVal[i].val[j].value, 20040Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len); 20050Sstevel@tonic-gate } 20060Sstevel@tonic-gate } 20070Sstevel@tonic-gate nm++; 20080Sstevel@tonic-gate } 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate return (mods); 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate /* 20140Sstevel@tonic-gate * Remove 'value' from 'val'. If value==0, remove the entire 20150Sstevel@tonic-gate * __nis_single_value_t array from 'val'. 20160Sstevel@tonic-gate */ 20170Sstevel@tonic-gate static void 20180Sstevel@tonic-gate removeSingleValue(__nis_value_t *val, void *value, int length) { 20190Sstevel@tonic-gate int i; 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate if (val == 0) 20220Sstevel@tonic-gate return; 20230Sstevel@tonic-gate 20240Sstevel@tonic-gate if (value == 0) { 20250Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 20260Sstevel@tonic-gate sfree(val->val[i].value); 20270Sstevel@tonic-gate } 20280Sstevel@tonic-gate sfree(val->val); 20290Sstevel@tonic-gate val->val = 0; 20300Sstevel@tonic-gate val->numVals = 0; 20310Sstevel@tonic-gate return; 20320Sstevel@tonic-gate } 20330Sstevel@tonic-gate 20340Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 20350Sstevel@tonic-gate if (val->val[i].value == 0 || (val->val[i].length != length)) 20360Sstevel@tonic-gate continue; 20370Sstevel@tonic-gate if (memcmp(val->val[i].value, value, length) != 0) 20380Sstevel@tonic-gate continue; 20390Sstevel@tonic-gate sfree(val->val[i].value); 20400Sstevel@tonic-gate if (i != (val->numVals - 1)) { 20410Sstevel@tonic-gate (void) memmove(&val->val[i], &val->val[i+1], 20420Sstevel@tonic-gate (val->numVals - 1 - i) * sizeof (val->val[0])); 20430Sstevel@tonic-gate } 20440Sstevel@tonic-gate val->numVals -= 1; 20450Sstevel@tonic-gate break; 20460Sstevel@tonic-gate } 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate /* 20500Sstevel@tonic-gate * Helper function for LdapModify 20510Sstevel@tonic-gate * When a modify operation fails with an object class violation, 20520Sstevel@tonic-gate * the most probable reason is that the attributes we're modifying are new, 20530Sstevel@tonic-gate * and the needed object class are not present. So, try the modify again, 20540Sstevel@tonic-gate * but add the object classes this time. 20550Sstevel@tonic-gate */ 20560Sstevel@tonic-gate 20570Sstevel@tonic-gate static int 20580Sstevel@tonic-gate ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn, 20590Sstevel@tonic-gate __nis_rule_value_t *rvIn, char *objClassAttrs) 20600Sstevel@tonic-gate { 20610Sstevel@tonic-gate LDAPMod **mods = 0; 20620Sstevel@tonic-gate int msgid; 20630Sstevel@tonic-gate int lderr; 20640Sstevel@tonic-gate struct timeval tv; 20650Sstevel@tonic-gate int stat; 20660Sstevel@tonic-gate LDAPMessage *msg = 0; 20670Sstevel@tonic-gate char **referralsp = NULL; 20680Sstevel@tonic-gate __nis_rule_value_t *rv, *rvldap; 20690Sstevel@tonic-gate __nis_ldap_search_t *ls; 20700Sstevel@tonic-gate int i, ocrv, ocrvldap, nv; 20710Sstevel@tonic-gate char *oc[2] = { "objectClass", 0}; 20720Sstevel@tonic-gate char *myself = "ldapModifyObjectClass"; 20730Sstevel@tonic-gate 20740Sstevel@tonic-gate rv = initRuleValue(1, rvIn); 20750Sstevel@tonic-gate if (rv == 0) 20760Sstevel@tonic-gate return (LDAP_NO_MEMORY); 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 20790Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 20800Sstevel@tonic-gate if (rv == 0) { 20810Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 20820Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2083*8035SSreedhar.Chalamalasetti@Sun.COM "%s: addObjectClasses failed for %s", 2084*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(dn)); 20850Sstevel@tonic-gate goto cleanup; 20860Sstevel@tonic-gate } 20870Sstevel@tonic-gate 20880Sstevel@tonic-gate /* 20890Sstevel@tonic-gate * Before adding the object classes whole-sale, try retrieving 20900Sstevel@tonic-gate * the entry specified by the 'dn'. If it exists, we filter out 20910Sstevel@tonic-gate * those object classes that already are present in LDAP from our 20920Sstevel@tonic-gate * update. 20930Sstevel@tonic-gate */ 20940Sstevel@tonic-gate ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*", 2095*8035SSreedhar.Chalamalasetti@Sun.COM oc, 0, 1); 20960Sstevel@tonic-gate if (ls == 0) { 20970Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2098*8035SSreedhar.Chalamalasetti@Sun.COM "%s: Unable to build DN search for \"%s\"", 2099*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(dn)); 21000Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 21010Sstevel@tonic-gate goto addObjectClasses; 21020Sstevel@tonic-gate } 21030Sstevel@tonic-gate 21040Sstevel@tonic-gate nv = 0; 21050Sstevel@tonic-gate rvldap = ldapSearch(ls, &nv, 0, &lderr); 21060Sstevel@tonic-gate freeLdapSearch(ls); 21070Sstevel@tonic-gate if (rvldap == 0) { 21080Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2109*8035SSreedhar.Chalamalasetti@Sun.COM "%s: No data for DN search (\"%s\"); LDAP status %d", 2110*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(dn), lderr); 21110Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 21120Sstevel@tonic-gate goto addObjectClasses; 21130Sstevel@tonic-gate } 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate /* 21160Sstevel@tonic-gate * Find the indices of the 'objectClass' attribute 21170Sstevel@tonic-gate * in 'rvldap' and 'rv'. 21180Sstevel@tonic-gate */ 21190Sstevel@tonic-gate for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) { 21200Sstevel@tonic-gate if (rvldap->attrName[i] != 0 && 2121*8035SSreedhar.Chalamalasetti@Sun.COM strcasecmp("objectClass", rvldap->attrName[i]) == 0) { 21220Sstevel@tonic-gate ocrvldap = i; 21230Sstevel@tonic-gate break; 21240Sstevel@tonic-gate } 21250Sstevel@tonic-gate } 21260Sstevel@tonic-gate for (i = 0, ocrv = -1; i < rv->numAttrs; i++) { 21270Sstevel@tonic-gate if (rv->attrName[i] != 0 && 2128*8035SSreedhar.Chalamalasetti@Sun.COM strcasecmp("objectClass", rv->attrName[i]) == 0) { 21290Sstevel@tonic-gate ocrv = i; 21300Sstevel@tonic-gate break; 21310Sstevel@tonic-gate } 21320Sstevel@tonic-gate } 21330Sstevel@tonic-gate 21340Sstevel@tonic-gate /* 21350Sstevel@tonic-gate * Remove those object classes that already exist 21360Sstevel@tonic-gate * in LDAP (i.e., in 'rvldap') from 'rv'. 21370Sstevel@tonic-gate */ 21380Sstevel@tonic-gate if (ocrv >= 0 && ocrvldap >= 0) { 21390Sstevel@tonic-gate for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) { 21400Sstevel@tonic-gate removeSingleValue(&rv->attrVal[ocrv], 2141*8035SSreedhar.Chalamalasetti@Sun.COM rvldap->attrVal[ocrvldap].val[i].value, 2142*8035SSreedhar.Chalamalasetti@Sun.COM rvldap->attrVal[ocrvldap].val[i].length); 21430Sstevel@tonic-gate } 21440Sstevel@tonic-gate /* 21450Sstevel@tonic-gate * If no 'objectClass' values left in 'rv', delete 21460Sstevel@tonic-gate * 'objectClass' from 'rv'. 21470Sstevel@tonic-gate */ 21480Sstevel@tonic-gate if (rv->attrVal[ocrv].numVals == 0) 21490Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 21500Sstevel@tonic-gate } 21510Sstevel@tonic-gate 21520Sstevel@tonic-gate /* 21530Sstevel@tonic-gate * 'rv' now contains the update we want to make, with just the 21540Sstevel@tonic-gate * object class(es) that need to be added. Fall through to the 21550Sstevel@tonic-gate * actual LDAP modify operation. 21560Sstevel@tonic-gate */ 21570Sstevel@tonic-gate freeRuleValue(rvldap, 1); 21580Sstevel@tonic-gate 21590Sstevel@tonic-gate addObjectClasses: 21600Sstevel@tonic-gate 21610Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 1); 21620Sstevel@tonic-gate if (mods == 0) { 21630Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 21640Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 21650Sstevel@tonic-gate "%s: Unable to create LDAP modify changes with object classes for %s", 2166*8035SSreedhar.Chalamalasetti@Sun.COM myself, NIL(dn)); 21670Sstevel@tonic-gate goto cleanup; 21680Sstevel@tonic-gate } 21690Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 21700Sstevel@tonic-gate if (msgid != -1) { 21710Sstevel@tonic-gate tv = (*lc)->modifyTimeout; 21720Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 21730Sstevel@tonic-gate if (stat == 0) { 21740Sstevel@tonic-gate stat = LDAP_TIMEOUT; 21750Sstevel@tonic-gate } else if (stat == -1) { 21760Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2177*8035SSreedhar.Chalamalasetti@Sun.COM LDAP_OPT_ERROR_NUMBER, &stat); 21780Sstevel@tonic-gate } else { 21790Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL, 2180*8035SSreedhar.Chalamalasetti@Sun.COM NULL, &referralsp, NULL, 0); 21810Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 21820Sstevel@tonic-gate stat = lderr; 21830Sstevel@tonic-gate stat = ldap_result2error((*lc)->ld, msg, 0); 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate } else { 21860Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER, 2187*8035SSreedhar.Chalamalasetti@Sun.COM &stat); 21880Sstevel@tonic-gate } 21890Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 2190*8035SSreedhar.Chalamalasetti@Sun.COM stat == LDAP_REFERRAL && referralsp != NULL) { 21910Sstevel@tonic-gate releaseCon(*lc, stat); 21920Sstevel@tonic-gate if (msg != NULL) 21930Sstevel@tonic-gate (void) ldap_msgfree(msg); 21940Sstevel@tonic-gate msg = NULL; 21950Sstevel@tonic-gate *lc = findReferralCon(referralsp, &stat); 21960Sstevel@tonic-gate ldap_value_free(referralsp); 21970Sstevel@tonic-gate referralsp = NULL; 21980Sstevel@tonic-gate if (*lc == NULL) 21990Sstevel@tonic-gate goto cleanup; 22000Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 22010Sstevel@tonic-gate if (msgid == -1) { 22020Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2203*8035SSreedhar.Chalamalasetti@Sun.COM LDAP_OPT_ERROR_NUMBER, &stat); 22040Sstevel@tonic-gate goto cleanup; 22050Sstevel@tonic-gate } 22060Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 22070Sstevel@tonic-gate if (stat == 0) { 22080Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22090Sstevel@tonic-gate } else if (stat == -1) { 22100Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2211*8035SSreedhar.Chalamalasetti@Sun.COM LDAP_OPT_ERROR_NUMBER, &stat); 22120Sstevel@tonic-gate } else { 22130Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, 2214*8035SSreedhar.Chalamalasetti@Sun.COM NULL, NULL, NULL, NULL, 0); 22150Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 22160Sstevel@tonic-gate stat = lderr; 22170Sstevel@tonic-gate } 22180Sstevel@tonic-gate } 22190Sstevel@tonic-gate cleanup: 22200Sstevel@tonic-gate if (mods != 0) 22210Sstevel@tonic-gate freeLdapMod(mods); 22220Sstevel@tonic-gate freeRuleValue(rv, 1); 22230Sstevel@tonic-gate return (stat); 22240Sstevel@tonic-gate } 22250Sstevel@tonic-gate 22260Sstevel@tonic-gate /* 22270Sstevel@tonic-gate * Modify the specified 'dn' per the attribute names/values in 'rv'. 22280Sstevel@tonic-gate * If 'rv' is NULL, we attempt to delete the entire entry. 22290Sstevel@tonic-gate * 22300Sstevel@tonic-gate * The 'objClassAttrs' parameter is needed if the entry must be added 22310Sstevel@tonic-gate * (i.e., created), or a modify fails with an object class violation. 22320Sstevel@tonic-gate * 22330Sstevel@tonic-gate * If 'addFirst' is set, we try an add before a modify; modify before 22340Sstevel@tonic-gate * add otherwise (ignored if we're deleting). 22350Sstevel@tonic-gate */ 22360Sstevel@tonic-gate int 22370Sstevel@tonic-gate ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, 22380Sstevel@tonic-gate int addFirst) { 22390Sstevel@tonic-gate int stat, add = 0; 22400Sstevel@tonic-gate LDAPMod **mods = 0; 22410Sstevel@tonic-gate __nis_ldap_conn_t *lc; 22420Sstevel@tonic-gate struct timeval tv; 22430Sstevel@tonic-gate LDAPMessage *msg = 0; 22440Sstevel@tonic-gate char *myself = "ldapModify"; 22450Sstevel@tonic-gate int msgid; 22460Sstevel@tonic-gate int lderr; 22470Sstevel@tonic-gate char **referralsp = NULL; 22480Sstevel@tonic-gate bool_t delete = FALSE; 22490Sstevel@tonic-gate 22500Sstevel@tonic-gate if (dn == 0) 22510Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 22540Sstevel@tonic-gate return (stat); 22550Sstevel@tonic-gate 22560Sstevel@tonic-gate if (rv == 0) { 22570Sstevel@tonic-gate delete = TRUE; 22580Sstevel@tonic-gate /* Simple case: if rv == 0, try to delete the entire entry */ 22590Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 22600Sstevel@tonic-gate if (msgid == -1) { 22610Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 22620Sstevel@tonic-gate &stat); 22630Sstevel@tonic-gate goto cleanup; 22640Sstevel@tonic-gate } 22650Sstevel@tonic-gate tv = lc->deleteTimeout; 22660Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 22670Sstevel@tonic-gate 22680Sstevel@tonic-gate if (stat == 0) { 22690Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22700Sstevel@tonic-gate } else if (stat == -1) { 22710Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 22720Sstevel@tonic-gate &stat); 22730Sstevel@tonic-gate } else { 22740Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 22750Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 22760Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 22770Sstevel@tonic-gate stat = lderr; 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 22800Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 22810Sstevel@tonic-gate releaseCon(lc, stat); 22820Sstevel@tonic-gate if (msg != NULL) 22830Sstevel@tonic-gate (void) ldap_msgfree(msg); 22840Sstevel@tonic-gate msg = NULL; 22850Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 22860Sstevel@tonic-gate ldap_value_free(referralsp); 22870Sstevel@tonic-gate if (lc == NULL) 22880Sstevel@tonic-gate goto cleanup; 22890Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 22900Sstevel@tonic-gate if (msgid == -1) { 22910Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 22920Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 22930Sstevel@tonic-gate goto cleanup; 22940Sstevel@tonic-gate } 22950Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 22960Sstevel@tonic-gate if (stat == 0) { 22970Sstevel@tonic-gate stat = LDAP_TIMEOUT; 22980Sstevel@tonic-gate } else if (stat == -1) { 22990Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23000Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23010Sstevel@tonic-gate } else { 23020Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 23030Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 23040Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23050Sstevel@tonic-gate stat = lderr; 23060Sstevel@tonic-gate } 23070Sstevel@tonic-gate } 23080Sstevel@tonic-gate /* No such object means someone else has done our job */ 23090Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) 23100Sstevel@tonic-gate stat = LDAP_SUCCESS; 23110Sstevel@tonic-gate } else { 23120Sstevel@tonic-gate if (addFirst) { 23130Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 23140Sstevel@tonic-gate lc = NULL; 23150Sstevel@tonic-gate if (stat != LDAP_ALREADY_EXISTS) 23160Sstevel@tonic-gate goto cleanup; 23170Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 23180Sstevel@tonic-gate return (stat); 23190Sstevel@tonic-gate } 23200Sstevel@tonic-gate 23210Sstevel@tonic-gate /* 23220Sstevel@tonic-gate * First try the modify without specifying object classes 23230Sstevel@tonic-gate * (i.e., assume they're already present). 23240Sstevel@tonic-gate */ 23250Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 0); 23260Sstevel@tonic-gate if (mods == 0) { 23270Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 23280Sstevel@tonic-gate goto cleanup; 23290Sstevel@tonic-gate } 23300Sstevel@tonic-gate 23310Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 23320Sstevel@tonic-gate if (msgid == -1) { 23330Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 23340Sstevel@tonic-gate &stat); 23350Sstevel@tonic-gate goto cleanup; 23360Sstevel@tonic-gate } 23370Sstevel@tonic-gate tv = lc->modifyTimeout; 23380Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 23390Sstevel@tonic-gate if (stat == 0) { 23400Sstevel@tonic-gate stat = LDAP_TIMEOUT; 23410Sstevel@tonic-gate } else if (stat == -1) { 23420Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 23430Sstevel@tonic-gate &stat); 23440Sstevel@tonic-gate } else { 23450Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 23460Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 23470Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23480Sstevel@tonic-gate stat = lderr; 23490Sstevel@tonic-gate } 23500Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 23510Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 23520Sstevel@tonic-gate releaseCon(lc, stat); 23530Sstevel@tonic-gate if (msg != NULL) 23540Sstevel@tonic-gate (void) ldap_msgfree(msg); 23550Sstevel@tonic-gate msg = NULL; 23560Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 23570Sstevel@tonic-gate ldap_value_free(referralsp); 23580Sstevel@tonic-gate referralsp = NULL; 23590Sstevel@tonic-gate if (lc == NULL) 23600Sstevel@tonic-gate goto cleanup; 23610Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 23620Sstevel@tonic-gate if (msgid == -1) { 23630Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23640Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23650Sstevel@tonic-gate goto cleanup; 23660Sstevel@tonic-gate } 23670Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 23680Sstevel@tonic-gate if (stat == 0) { 23690Sstevel@tonic-gate stat = LDAP_TIMEOUT; 23700Sstevel@tonic-gate } else if (stat == -1) { 23710Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 23720Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 23730Sstevel@tonic-gate } else { 23740Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 23750Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 23760Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 23770Sstevel@tonic-gate stat = lderr; 23780Sstevel@tonic-gate } 23790Sstevel@tonic-gate } 23800Sstevel@tonic-gate 23810Sstevel@tonic-gate /* 23820Sstevel@tonic-gate * If the modify failed with an object class violation, 23830Sstevel@tonic-gate * the most probable reason is that at least on of the 23840Sstevel@tonic-gate * attributes we're modifying didn't exist before, and 23850Sstevel@tonic-gate * neither did its object class. So, try the modify again, 23860Sstevel@tonic-gate * but add the object classes this time. 23870Sstevel@tonic-gate */ 23880Sstevel@tonic-gate if (stat == LDAP_OBJECT_CLASS_VIOLATION && 23890Sstevel@tonic-gate objClassAttrs != 0) { 23900Sstevel@tonic-gate freeLdapMod(mods); 23910Sstevel@tonic-gate mods = 0; 23920Sstevel@tonic-gate stat = ldapModifyObjectClass(&lc, dn, rv, 23930Sstevel@tonic-gate objClassAttrs); 23940Sstevel@tonic-gate } 23950Sstevel@tonic-gate 23960Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_ATTRIBUTE) { 23970Sstevel@tonic-gate /* 23980Sstevel@tonic-gate * If there was at least one attribute delete, then 23990Sstevel@tonic-gate * the cause of this error could be that said attribute 24000Sstevel@tonic-gate * didn't exist in LDAP. So, do things the slow way, 24010Sstevel@tonic-gate * and try to delete one attribute at a time. 24020Sstevel@tonic-gate */ 24030Sstevel@tonic-gate int d, numDelete, st; 24040Sstevel@tonic-gate __nis_rule_value_t *rvt; 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate for (d = 0, numDelete = 0; d < rv->numAttrs; d++) { 24070Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) 24080Sstevel@tonic-gate numDelete++; 24090Sstevel@tonic-gate } 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate /* If there's just one, we've already tried */ 24120Sstevel@tonic-gate if (numDelete <= 1) 24130Sstevel@tonic-gate goto cleanup; 24140Sstevel@tonic-gate 24150Sstevel@tonic-gate /* Make a copy of the rule value */ 24160Sstevel@tonic-gate rvt = initRuleValue(1, rv); 24170Sstevel@tonic-gate if (rvt == 0) 24180Sstevel@tonic-gate goto cleanup; 24190Sstevel@tonic-gate 24200Sstevel@tonic-gate /* 24210Sstevel@tonic-gate * Remove all delete attributes from the tmp 24220Sstevel@tonic-gate * rule value. 24230Sstevel@tonic-gate */ 24240Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 24250Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) { 24260Sstevel@tonic-gate delAttrFromRuleValue(rvt, 24270Sstevel@tonic-gate rv->attrName[d]); 24280Sstevel@tonic-gate } 24290Sstevel@tonic-gate } 24300Sstevel@tonic-gate 24310Sstevel@tonic-gate /* 24320Sstevel@tonic-gate * Now put the attributes back in one by one, and 24330Sstevel@tonic-gate * invoke ourselves. 24340Sstevel@tonic-gate */ 24350Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 24360Sstevel@tonic-gate if (rv->attrVal[d].numVals >= 0) 24370Sstevel@tonic-gate continue; 24380Sstevel@tonic-gate st = addAttr2RuleValue(rv->attrVal[d].type, 24390Sstevel@tonic-gate rv->attrName[d], 0, 0, rvt); 24400Sstevel@tonic-gate if (st != 0) { 24410Sstevel@tonic-gate logmsg(MSG_NOMEM, LOG_ERR, 24420Sstevel@tonic-gate "%s: Error deleting \"%s\" for \"%s\"", 24430Sstevel@tonic-gate NIL(rv->attrName[d]), NIL(dn)); 24440Sstevel@tonic-gate stat = LDAP_NO_MEMORY; 24450Sstevel@tonic-gate freeRuleValue(rvt, 1); 24460Sstevel@tonic-gate goto cleanup; 24470Sstevel@tonic-gate } 24480Sstevel@tonic-gate stat = ldapModify(dn, rvt, objClassAttrs, 0); 24490Sstevel@tonic-gate if (stat != LDAP_SUCCESS && 24500Sstevel@tonic-gate stat != LDAP_NO_SUCH_ATTRIBUTE) { 24510Sstevel@tonic-gate freeRuleValue(rvt, 1); 24520Sstevel@tonic-gate goto cleanup; 24530Sstevel@tonic-gate } 24540Sstevel@tonic-gate delAttrFromRuleValue(rvt, rv->attrName[d]); 24550Sstevel@tonic-gate } 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate /* 24580Sstevel@tonic-gate * If we got here, then all attributes that should 24590Sstevel@tonic-gate * be deleted either have been, or didn't exist. For 24600Sstevel@tonic-gate * our purposes, the latter is as good as the former. 24610Sstevel@tonic-gate */ 24620Sstevel@tonic-gate stat = LDAP_SUCCESS; 24630Sstevel@tonic-gate freeRuleValue(rvt, 1); 24640Sstevel@tonic-gate } 24650Sstevel@tonic-gate 24660Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) { 24670Sstevel@tonic-gate /* 24680Sstevel@tonic-gate * Entry doesn't exist, so try an ldap_add(). If the 24690Sstevel@tonic-gate * ldap_add() also fails, that could be because someone 24700Sstevel@tonic-gate * else added it between our modify and add operations. 24710Sstevel@tonic-gate * If so, we consider that foreign add to be 24720Sstevel@tonic-gate * authoritative (meaning we don't retry our modify). 24730Sstevel@tonic-gate * 24740Sstevel@tonic-gate * Also, if all modify operations specified by 'mods' 24750Sstevel@tonic-gate * are deletes, LDAP_NO_SUCH_OBJECT is a kind of 24760Sstevel@tonic-gate * success; we certainly don't want to create the 24770Sstevel@tonic-gate * entry. 24780Sstevel@tonic-gate */ 24790Sstevel@tonic-gate int allDelete; 24800Sstevel@tonic-gate LDAPMod **m; 24810Sstevel@tonic-gate 24820Sstevel@tonic-gate for (m = mods, allDelete = 1; *m != 0 && allDelete; 24830Sstevel@tonic-gate m++) { 24840Sstevel@tonic-gate if (((*m)->mod_op & LDAP_MOD_DELETE) == 0) 24850Sstevel@tonic-gate allDelete = 0; 24860Sstevel@tonic-gate } 24870Sstevel@tonic-gate 24880Sstevel@tonic-gate add = 1; 24890Sstevel@tonic-gate 24900Sstevel@tonic-gate if (allDelete) { 24910Sstevel@tonic-gate stat = LDAP_SUCCESS; 24920Sstevel@tonic-gate } else if (objClassAttrs == 0) { 24930Sstevel@tonic-gate /* Now we need it, so this is fatal */ 24940Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 24950Sstevel@tonic-gate } else { 24960Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 24970Sstevel@tonic-gate lc = NULL; 24980Sstevel@tonic-gate } 24990Sstevel@tonic-gate } 25000Sstevel@tonic-gate } 25010Sstevel@tonic-gate 25020Sstevel@tonic-gate cleanup: 25030Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 25040Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 25050Sstevel@tonic-gate "%s(0x%x (%s), \"%s\") => %d (%s)\n", 25060Sstevel@tonic-gate !delete ? (add ? "ldap_add" : "ldap_modify") : 25070Sstevel@tonic-gate "ldap_delete", 25080Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 25090Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 25100Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 25110Sstevel@tonic-gate } 25120Sstevel@tonic-gate 25130Sstevel@tonic-gate releaseCon(lc, stat); 25140Sstevel@tonic-gate freeLdapMod(mods); 25150Sstevel@tonic-gate if (msg != 0) 25160Sstevel@tonic-gate (void) ldap_msgfree(msg); 25170Sstevel@tonic-gate 25180Sstevel@tonic-gate return (stat); 25190Sstevel@tonic-gate } 25200Sstevel@tonic-gate 25210Sstevel@tonic-gate /* 25220Sstevel@tonic-gate * Create the entry specified by 'dn' to have the values per 'rv'. 25230Sstevel@tonic-gate * The 'objClassAttrs' are the extra object classes we need when 25240Sstevel@tonic-gate * creating an entry. 25250Sstevel@tonic-gate * 25260Sstevel@tonic-gate * If 'lc' is non-NULL, we use that connection; otherwise, we find 25270Sstevel@tonic-gate * our own. CAUTION: This connection will be released on return. Regardless 25280Sstevel@tonic-gate * of return value, this connection should not subsequently used by the 25290Sstevel@tonic-gate * caller. 25300Sstevel@tonic-gate * 25310Sstevel@tonic-gate * Returns an LDAP status. 25320Sstevel@tonic-gate */ 25330Sstevel@tonic-gate int 25340Sstevel@tonic-gate ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) { 25350Sstevel@tonic-gate int stat; 25360Sstevel@tonic-gate LDAPMod **mods = 0; 25370Sstevel@tonic-gate struct timeval tv; 25380Sstevel@tonic-gate LDAPMessage *msg = 0; 25390Sstevel@tonic-gate __nis_ldap_conn_t *lc = lcv; 25400Sstevel@tonic-gate int msgid; 25410Sstevel@tonic-gate int lderr; 25420Sstevel@tonic-gate char **referralsp = NULL; 25430Sstevel@tonic-gate 25440Sstevel@tonic-gate if (dn == 0 || rv == 0 || objClassAttrs == 0) { 25450Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 25460Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 25470Sstevel@tonic-gate } 25480Sstevel@tonic-gate 25490Sstevel@tonic-gate if (lc == 0) { 25500Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 25510Sstevel@tonic-gate return (stat); 25520Sstevel@tonic-gate } 25530Sstevel@tonic-gate 25540Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 25550Sstevel@tonic-gate if (rv == 0) { 25560Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 25570Sstevel@tonic-gate goto cleanup; 25580Sstevel@tonic-gate } 25590Sstevel@tonic-gate 25600Sstevel@tonic-gate mods = search2LdapMod(rv, 1, 0); 25610Sstevel@tonic-gate if (mods == 0) { 25620Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 25630Sstevel@tonic-gate goto cleanup; 25640Sstevel@tonic-gate } 25650Sstevel@tonic-gate 25660Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 25670Sstevel@tonic-gate if (msgid == -1) { 25680Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 25690Sstevel@tonic-gate goto cleanup; 25700Sstevel@tonic-gate } 25710Sstevel@tonic-gate tv = lc->addTimeout; 25720Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 25730Sstevel@tonic-gate if (stat == 0) { 25740Sstevel@tonic-gate stat = LDAP_TIMEOUT; 25750Sstevel@tonic-gate } else if (stat == -1) { 25760Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 25770Sstevel@tonic-gate } else { 25780Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL, 25790Sstevel@tonic-gate &referralsp, NULL, 0); 25800Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 25810Sstevel@tonic-gate stat = lderr; 25820Sstevel@tonic-gate } 25830Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL && 25840Sstevel@tonic-gate referralsp != NULL) { 25850Sstevel@tonic-gate releaseCon(lc, stat); 25860Sstevel@tonic-gate if (msg != NULL) 25870Sstevel@tonic-gate (void) ldap_msgfree(msg); 25880Sstevel@tonic-gate msg = NULL; 25890Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 25900Sstevel@tonic-gate ldap_value_free(referralsp); 25910Sstevel@tonic-gate if (lc == NULL) 25920Sstevel@tonic-gate goto cleanup; 25930Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 25940Sstevel@tonic-gate if (msgid == -1) { 25950Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 25960Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 25970Sstevel@tonic-gate goto cleanup; 25980Sstevel@tonic-gate } 25990Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 26000Sstevel@tonic-gate if (stat == 0) { 26010Sstevel@tonic-gate stat = LDAP_TIMEOUT; 26020Sstevel@tonic-gate } else if (stat == -1) { 26030Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 26040Sstevel@tonic-gate &stat); 26050Sstevel@tonic-gate } else { 26060Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 26070Sstevel@tonic-gate NULL, NULL, NULL, 0); 26080Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 26090Sstevel@tonic-gate stat = lderr; 26100Sstevel@tonic-gate } 26110Sstevel@tonic-gate } 26120Sstevel@tonic-gate 26130Sstevel@tonic-gate cleanup: 26140Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 26150Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 26160Sstevel@tonic-gate "ldap_add(0x%x (%s), \"%s\") => %d (%s)\n", 26170Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 26180Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 26190Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 26200Sstevel@tonic-gate } 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate releaseCon(lc, stat); 26230Sstevel@tonic-gate freeLdapMod(mods); 26240Sstevel@tonic-gate if (msg != 0) 26250Sstevel@tonic-gate (void) ldap_msgfree(msg); 26260Sstevel@tonic-gate 26270Sstevel@tonic-gate return (stat); 26280Sstevel@tonic-gate } 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate /* 26310Sstevel@tonic-gate * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'. 26320Sstevel@tonic-gate * Returns an LDAP error status. 26330Sstevel@tonic-gate */ 26340Sstevel@tonic-gate int 26350Sstevel@tonic-gate ldapChangeDN(char *oldDn, char *dn) { 26360Sstevel@tonic-gate int stat; 26370Sstevel@tonic-gate __nis_ldap_conn_t *lc; 26380Sstevel@tonic-gate int i, j, lo, ln; 26390Sstevel@tonic-gate char *rdn; 26400Sstevel@tonic-gate int msgid; 26410Sstevel@tonic-gate int lderr; 26420Sstevel@tonic-gate struct timeval tv; 26430Sstevel@tonic-gate LDAPMessage *msg = 0; 26440Sstevel@tonic-gate char **referralsp = NULL; 26450Sstevel@tonic-gate char *myself = "ldapChangeDN"; 26460Sstevel@tonic-gate 26470Sstevel@tonic-gate if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0) 26480Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 26490Sstevel@tonic-gate 26500Sstevel@tonic-gate if (strcasecmp(oldDn, dn) == 0) 26510Sstevel@tonic-gate return (LDAP_SUCCESS); 26520Sstevel@tonic-gate 26530Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 26540Sstevel@tonic-gate return (stat); 26550Sstevel@tonic-gate 26560Sstevel@tonic-gate rdn = sdup(myself, T, dn); 26570Sstevel@tonic-gate if (rdn == 0) { 26580Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 26590Sstevel@tonic-gate return (LDAP_NO_MEMORY); 26600Sstevel@tonic-gate } 26610Sstevel@tonic-gate 26620Sstevel@tonic-gate /* Compare old and new DN from the end */ 26630Sstevel@tonic-gate for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) { 26640Sstevel@tonic-gate if (tolower(oldDn[i]) != tolower(rdn[j])) { 26650Sstevel@tonic-gate /* 26660Sstevel@tonic-gate * Terminate 'rdn' after this character in order 26670Sstevel@tonic-gate * to snip off the portion of the new DN that is 26680Sstevel@tonic-gate * the same as the old DN. What remains in 'rdn' 26690Sstevel@tonic-gate * is the relative DN. 26700Sstevel@tonic-gate */ 26710Sstevel@tonic-gate rdn[j+1] = '\0'; 26720Sstevel@tonic-gate break; 26730Sstevel@tonic-gate } 26740Sstevel@tonic-gate } 26750Sstevel@tonic-gate 26760Sstevel@tonic-gate stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid); 26770Sstevel@tonic-gate 26780Sstevel@tonic-gate if (msgid != -1) { 26790Sstevel@tonic-gate tv = lc->modifyTimeout; 26800Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 26810Sstevel@tonic-gate if (stat == 0) { 26820Sstevel@tonic-gate stat = LDAP_TIMEOUT; 26830Sstevel@tonic-gate } else if (stat == -1) { 26840Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 26850Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 26860Sstevel@tonic-gate } else { 26870Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 26880Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 26890Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 26900Sstevel@tonic-gate stat = lderr; 26910Sstevel@tonic-gate stat = ldap_result2error(lc->ld, msg, 0); 26920Sstevel@tonic-gate } 26930Sstevel@tonic-gate } else { 26940Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 26950Sstevel@tonic-gate &stat); 26960Sstevel@tonic-gate } 26970Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 26980Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 26990Sstevel@tonic-gate releaseCon(lc, stat); 27000Sstevel@tonic-gate if (msg != NULL) 27010Sstevel@tonic-gate (void) ldap_msgfree(msg); 27020Sstevel@tonic-gate msg = NULL; 27030Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 27040Sstevel@tonic-gate ldap_value_free(referralsp); 27050Sstevel@tonic-gate referralsp = NULL; 27060Sstevel@tonic-gate if (lc == NULL) 27070Sstevel@tonic-gate goto cleanup; 27080Sstevel@tonic-gate msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, 27090Sstevel@tonic-gate &msgid); 27100Sstevel@tonic-gate if (msgid == -1) { 27110Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 27120Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 27130Sstevel@tonic-gate goto cleanup; 27140Sstevel@tonic-gate } 27150Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 27160Sstevel@tonic-gate if (stat == 0) { 27170Sstevel@tonic-gate stat = LDAP_TIMEOUT; 27180Sstevel@tonic-gate } else if (stat == -1) { 27190Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 27200Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 27210Sstevel@tonic-gate } else { 27220Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 27230Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 27240Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 27250Sstevel@tonic-gate stat = lderr; 27260Sstevel@tonic-gate } 27270Sstevel@tonic-gate } 27280Sstevel@tonic-gate 27290Sstevel@tonic-gate cleanup: 27300Sstevel@tonic-gate if (msg != NULL) 27310Sstevel@tonic-gate (void) ldap_msgfree(msg); 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate #if 1 27340Sstevel@tonic-gate fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n", 27350Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 27360Sstevel@tonic-gate ldap_err2string(stat)); 27370Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 27380Sstevel@tonic-gate "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s", 27390Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 27400Sstevel@tonic-gate ldap_err2string(stat)); 27410Sstevel@tonic-gate #endif 27420Sstevel@tonic-gate 27430Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) { 27440Sstevel@tonic-gate /* 27450Sstevel@tonic-gate * Fine from our point of view, since all we want to do 27460Sstevel@tonic-gate * is to make sure that an update to the new DN doesn't 27470Sstevel@tonic-gate * leave the old entry around. 27480Sstevel@tonic-gate */ 27490Sstevel@tonic-gate stat = LDAP_SUCCESS; 27500Sstevel@tonic-gate } 27510Sstevel@tonic-gate 27520Sstevel@tonic-gate releaseCon(lc, stat); 27530Sstevel@tonic-gate sfree(rdn); 27540Sstevel@tonic-gate 27550Sstevel@tonic-gate return (stat); 27560Sstevel@tonic-gate } 2757