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