1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <synch.h> 30*0Sstevel@tonic-gate #include <strings.h> 31*0Sstevel@tonic-gate #include <sys/time.h> 32*0Sstevel@tonic-gate #include <ctype.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include "ldap_op.h" 35*0Sstevel@tonic-gate #include "ldap_util.h" 36*0Sstevel@tonic-gate #include "ldap_structs.h" 37*0Sstevel@tonic-gate #include "ldap_ruleval.h" 38*0Sstevel@tonic-gate #include "ldap_attr.h" 39*0Sstevel@tonic-gate #include "ldap_print.h" 40*0Sstevel@tonic-gate #include "ldap_glob.h" 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #include "nis_parse_ldap_conf.h" 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate #ifndef LDAPS_PORT 45*0Sstevel@tonic-gate #define LDAPS_PORT 636 46*0Sstevel@tonic-gate #endif 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate * Build one of our internal LDAP search structures, containing copies of 50*0Sstevel@tonic-gate * the supplied input. return NULL in case of error. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * If 'filter' is NULL, build an AND-filter using the filter components. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate __nis_ldap_search_t * 55*0Sstevel@tonic-gate buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp, 56*0Sstevel@tonic-gate char *filter, char **attrs, int attrsonly, int isDN) { 57*0Sstevel@tonic-gate __nis_ldap_search_t *ls; 58*0Sstevel@tonic-gate char **a; 59*0Sstevel@tonic-gate int i, na, err = 0; 60*0Sstevel@tonic-gate char *myself = "buildLdapSearch"; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate ls = am(myself, sizeof (*ls)); 63*0Sstevel@tonic-gate if (ls == 0) 64*0Sstevel@tonic-gate return (0); 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate ls->base = sdup(myself, T, base); 67*0Sstevel@tonic-gate if (ls->base == 0 && base != 0) 68*0Sstevel@tonic-gate err++; 69*0Sstevel@tonic-gate ls->scope = scope; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate if (filterComp != 0 && numFilterComps > 0) { 72*0Sstevel@tonic-gate ls->filterComp = am(myself, numFilterComps * 73*0Sstevel@tonic-gate sizeof (ls->filterComp[0])); 74*0Sstevel@tonic-gate if (ls->filterComp == 0) { 75*0Sstevel@tonic-gate err++; 76*0Sstevel@tonic-gate numFilterComps = 0; 77*0Sstevel@tonic-gate } 78*0Sstevel@tonic-gate for (i = 0; i < numFilterComps; i++) { 79*0Sstevel@tonic-gate ls->filterComp[i] = sdup(myself, T, filterComp[i]); 80*0Sstevel@tonic-gate if (ls->filterComp[i] == 0 && filterComp[i] != 0) 81*0Sstevel@tonic-gate err++; 82*0Sstevel@tonic-gate } 83*0Sstevel@tonic-gate ls->numFilterComps = numFilterComps; 84*0Sstevel@tonic-gate if (filter == 0) { 85*0Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 86*0Sstevel@tonic-gate ls->filterComp); 87*0Sstevel@tonic-gate if (ls->filter == 0) 88*0Sstevel@tonic-gate err++; 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate } else { 91*0Sstevel@tonic-gate ls->filterComp = 0; 92*0Sstevel@tonic-gate ls->numFilterComps = 0; 93*0Sstevel@tonic-gate ls->filter = sdup(myself, T, filter); 94*0Sstevel@tonic-gate if (ls->filter == 0 && filter != 0) 95*0Sstevel@tonic-gate err++; 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate if (attrs != 0) { 99*0Sstevel@tonic-gate for (na = 0, a = attrs; *a != 0; a++, na++); 100*0Sstevel@tonic-gate ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0])); 101*0Sstevel@tonic-gate if (ls->attrs != 0) { 102*0Sstevel@tonic-gate for (i = 0; i < na; i++) { 103*0Sstevel@tonic-gate ls->attrs[i] = sdup(myself, T, attrs[i]); 104*0Sstevel@tonic-gate if (ls->attrs[i] == 0 && attrs[i] != 0) 105*0Sstevel@tonic-gate err++; 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate ls->attrs[na] = 0; 108*0Sstevel@tonic-gate ls->numAttrs = na; 109*0Sstevel@tonic-gate } else { 110*0Sstevel@tonic-gate err++; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate } else { 113*0Sstevel@tonic-gate ls->attrs = 0; 114*0Sstevel@tonic-gate ls->numAttrs = 0; 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate ls->attrsonly = attrsonly; 118*0Sstevel@tonic-gate ls->isDN = isDN; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (err > 0) { 121*0Sstevel@tonic-gate freeLdapSearch(ls); 122*0Sstevel@tonic-gate ls = 0; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate return (ls); 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate void 129*0Sstevel@tonic-gate freeLdapSearch(__nis_ldap_search_t *ls) { 130*0Sstevel@tonic-gate int i; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate if (ls == 0) 133*0Sstevel@tonic-gate return; 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate sfree(ls->base); 136*0Sstevel@tonic-gate if (ls->filterComp != 0) { 137*0Sstevel@tonic-gate for (i = 0; i < ls->numFilterComps; i++) { 138*0Sstevel@tonic-gate sfree(ls->filterComp[i]); 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate sfree(ls->filterComp); 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate sfree(ls->filter); 143*0Sstevel@tonic-gate if (ls->attrs != 0) { 144*0Sstevel@tonic-gate for (i = 0; i < ls->numAttrs; i++) { 145*0Sstevel@tonic-gate sfree(ls->attrs[i]); 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate sfree(ls->attrs); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate free(ls); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate /* 154*0Sstevel@tonic-gate * Given a table mapping, and a rule/value pointer, 155*0Sstevel@tonic-gate * return an LDAP search structure with values suitable for use 156*0Sstevel@tonic-gate * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value 157*0Sstevel@tonic-gate * may be modified. 158*0Sstevel@tonic-gate * 159*0Sstevel@tonic-gate * If dn != 0 and *dn == 0, the function attemps to return a pointer 160*0Sstevel@tonic-gate * to the DN. This may necessitate an ldapSearch, if the rule set doesn't 161*0Sstevel@tonic-gate * produce a DN directly. 162*0Sstevel@tonic-gate * 163*0Sstevel@tonic-gate * if dn == 0, and the rule set produces a DN as well as other attribute/ 164*0Sstevel@tonic-gate * value pairs, the function returns an LDAP search structure with the 165*0Sstevel@tonic-gate * DN only. 166*0Sstevel@tonic-gate * 167*0Sstevel@tonic-gate * If 'fromLDAP' is set, the caller wants base/scope/filter from 168*0Sstevel@tonic-gate * t->objectDN->read; otherwise, from t->objectDN->write. 169*0Sstevel@tonic-gate * 170*0Sstevel@tonic-gate * If 'rv' is NULL, the caller wants an enumeration of the container. 171*0Sstevel@tonic-gate * 172*0Sstevel@tonic-gate * Note that this function only creates a search structure for 't' itself; 173*0Sstevel@tonic-gate * if there are alternative mappings for the table, those must be handled 174*0Sstevel@tonic-gate * by our caller. 175*0Sstevel@tonic-gate */ 176*0Sstevel@tonic-gate __nis_ldap_search_t * 177*0Sstevel@tonic-gate createLdapRequest(__nis_table_mapping_t *t, 178*0Sstevel@tonic-gate __nis_rule_value_t *rv, char **dn, int fromLDAP, 179*0Sstevel@tonic-gate int *res, __nis_object_dn_t *obj_dn) { 180*0Sstevel@tonic-gate int i, j; 181*0Sstevel@tonic-gate __nis_ldap_search_t *ls = 0; 182*0Sstevel@tonic-gate char **locDN; 183*0Sstevel@tonic-gate int numLocDN, stat = 0, count = 0; 184*0Sstevel@tonic-gate char *myself = "createLdapRequest"; 185*0Sstevel@tonic-gate __nis_object_dn_t *objectDN = NULL; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate if (t == 0) 188*0Sstevel@tonic-gate return (0); 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if (obj_dn == NULL) 191*0Sstevel@tonic-gate objectDN = t->objectDN; 192*0Sstevel@tonic-gate else 193*0Sstevel@tonic-gate objectDN = obj_dn; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if (rv == 0) { 196*0Sstevel@tonic-gate char *base; 197*0Sstevel@tonic-gate char *filter; 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate if (fromLDAP) { 200*0Sstevel@tonic-gate base = objectDN->read.base; 201*0Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 202*0Sstevel@tonic-gate } else { 203*0Sstevel@tonic-gate base = objectDN->write.base; 204*0Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate /* Create request to enumerate container */ 208*0Sstevel@tonic-gate ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter, 209*0Sstevel@tonic-gate 0, 0, 0); 210*0Sstevel@tonic-gate sfree(filter); 211*0Sstevel@tonic-gate return (ls); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate for (i = 0; i < t->numRulesToLDAP; i++) { 215*0Sstevel@tonic-gate rv = addLdapRuleValue(t, t->ruleToLDAP[i], 216*0Sstevel@tonic-gate mit_ldap, mit_nisplus, rv, !fromLDAP, &stat); 217*0Sstevel@tonic-gate if (rv == 0) 218*0Sstevel@tonic-gate return (0); 219*0Sstevel@tonic-gate if (stat == NP_LDAP_RULES_NO_VALUE) 220*0Sstevel@tonic-gate count++; 221*0Sstevel@tonic-gate stat = 0; 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * If none of the rules produced a value despite 226*0Sstevel@tonic-gate * having enough NIS+ columns, return error. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate if (rv->numAttrs == 0 && count > 0) { 229*0Sstevel@tonic-gate *res = NP_LDAP_RULES_NO_VALUE; 230*0Sstevel@tonic-gate return (0); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * 'rv' now contains everything we know about the attributes and 235*0Sstevel@tonic-gate * values. Build an LDAP search structure from it. 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate /* Look for a single-valued DN */ 239*0Sstevel@tonic-gate locDN = findDNs(myself, rv, 1, 240*0Sstevel@tonic-gate fromLDAP ? objectDN->read.base : 241*0Sstevel@tonic-gate objectDN->write.base, 242*0Sstevel@tonic-gate &numLocDN); 243*0Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 244*0Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 245*0Sstevel@tonic-gate *dn = locDN[0]; 246*0Sstevel@tonic-gate sfree(locDN); 247*0Sstevel@tonic-gate } else { 248*0Sstevel@tonic-gate char *filter; 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate if (fromLDAP) 251*0Sstevel@tonic-gate filter = makeFilter(objectDN->read.attrs); 252*0Sstevel@tonic-gate else 253*0Sstevel@tonic-gate filter = makeFilter(objectDN->write.attrs); 254*0Sstevel@tonic-gate ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0, 255*0Sstevel@tonic-gate filter, 0, 0, 1); 256*0Sstevel@tonic-gate sfree(filter); 257*0Sstevel@tonic-gate freeDNs(locDN, numLocDN); 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate } else { 260*0Sstevel@tonic-gate freeDNs(locDN, numLocDN); 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate if (ls != 0) { 264*0Sstevel@tonic-gate ls->useCon = 1; 265*0Sstevel@tonic-gate return (ls); 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate /* 269*0Sstevel@tonic-gate * No DN, or caller wanted a search structure with the non-DN 270*0Sstevel@tonic-gate * attributes. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate /* Initialize search structure */ 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate char *filter = (fromLDAP) ? 276*0Sstevel@tonic-gate makeFilter(objectDN->read.attrs) : 277*0Sstevel@tonic-gate makeFilter(objectDN->write.attrs); 278*0Sstevel@tonic-gate char **ofc; 279*0Sstevel@tonic-gate int nofc = 0; 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate ofc = makeFilterComp(filter, &nofc); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (filter != 0 && ofc == 0) { 284*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 285*0Sstevel@tonic-gate "%s: Unable to break filter into components: \"%s\"", 286*0Sstevel@tonic-gate myself, NIL(filter)); 287*0Sstevel@tonic-gate sfree(filter); 288*0Sstevel@tonic-gate return (0); 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (fromLDAP) 292*0Sstevel@tonic-gate ls = buildLdapSearch(objectDN->read.base, 293*0Sstevel@tonic-gate objectDN->read.scope, 294*0Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 295*0Sstevel@tonic-gate else 296*0Sstevel@tonic-gate ls = buildLdapSearch(objectDN->write.base, 297*0Sstevel@tonic-gate objectDN->write.scope, 298*0Sstevel@tonic-gate nofc, ofc, 0, 0, 0, 0); 299*0Sstevel@tonic-gate sfree(filter); 300*0Sstevel@tonic-gate freeFilterComp(ofc, nofc); 301*0Sstevel@tonic-gate if (ls == 0) 302*0Sstevel@tonic-gate return (0); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* Build and add the filter components */ 306*0Sstevel@tonic-gate for (i = 0; i < rv->numAttrs; i++) { 307*0Sstevel@tonic-gate /* Skip DN */ 308*0Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 309*0Sstevel@tonic-gate continue; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate /* Skip vt_ber values */ 312*0Sstevel@tonic-gate if (rv->attrVal[i].type == vt_ber) 313*0Sstevel@tonic-gate continue; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 316*0Sstevel@tonic-gate __nis_buffer_t b = {0, 0}; 317*0Sstevel@tonic-gate char **tmpComp; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate bp2buf(myself, &b, "%s=%s", 320*0Sstevel@tonic-gate rv->attrName[i], rv->attrVal[i].val[j].value); 321*0Sstevel@tonic-gate tmpComp = addFilterComp(b.buf, ls->filterComp, 322*0Sstevel@tonic-gate &ls->numFilterComps); 323*0Sstevel@tonic-gate if (tmpComp == 0) { 324*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 325*0Sstevel@tonic-gate "%s: Unable to add filter component \"%s\"", 326*0Sstevel@tonic-gate myself, NIL(b.buf)); 327*0Sstevel@tonic-gate sfree(b.buf); 328*0Sstevel@tonic-gate freeLdapSearch(ls); 329*0Sstevel@tonic-gate return (0); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate ls->filterComp = tmpComp; 332*0Sstevel@tonic-gate sfree(b.buf); 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate if (ls->numFilterComps > 0) { 337*0Sstevel@tonic-gate sfree(ls->filter); 338*0Sstevel@tonic-gate ls->filter = concatenateFilterComps(ls->numFilterComps, 339*0Sstevel@tonic-gate ls->filterComp); 340*0Sstevel@tonic-gate if (ls->filter == 0) { 341*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 342*0Sstevel@tonic-gate "%s: Unable to concatenate filter components", 343*0Sstevel@tonic-gate myself); 344*0Sstevel@tonic-gate freeLdapSearch(ls); 345*0Sstevel@tonic-gate return (0); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate if (dn != 0 && *dn == 0) { 350*0Sstevel@tonic-gate /* 351*0Sstevel@tonic-gate * The caller wants a DN, but we didn't get one from the 352*0Sstevel@tonic-gate * the rule set. We have an 'ls', so use it to ldapSearch() 353*0Sstevel@tonic-gate * for an entry from which we can extract the DN. 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate __nis_rule_value_t *rvtmp; 356*0Sstevel@tonic-gate char **locDN; 357*0Sstevel@tonic-gate int nv = 0, numLocDN; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate rvtmp = ldapSearch(ls, &nv, 0, 0); 360*0Sstevel@tonic-gate locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN); 361*0Sstevel@tonic-gate if (locDN != 0 && numLocDN == 1) { 362*0Sstevel@tonic-gate *dn = locDN[0]; 363*0Sstevel@tonic-gate sfree(locDN); 364*0Sstevel@tonic-gate } else { 365*0Sstevel@tonic-gate freeDNs(locDN, numLocDN); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate freeRuleValue(rvtmp, nv); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate ls->useCon = 1; 371*0Sstevel@tonic-gate return (ls); 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate int ldapConnAttemptRetryTimeout = 60; /* seconds */ 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate typedef struct { 377*0Sstevel@tonic-gate LDAP *ld; 378*0Sstevel@tonic-gate mutex_t mutex; /* Mutex for update of structure */ 379*0Sstevel@tonic-gate pthread_t owner; /* Thread holding mutex */ 380*0Sstevel@tonic-gate mutex_t rcMutex; /* Mutex for refCount */ 381*0Sstevel@tonic-gate int refCount; /* Reference count */ 382*0Sstevel@tonic-gate int isBound; /* Is connection open and usable ? */ 383*0Sstevel@tonic-gate time_t retryTime; /* When should open be retried */ 384*0Sstevel@tonic-gate int status; /* Status of last operation */ 385*0Sstevel@tonic-gate int doDis; /* To be disconnected if refCount==0 */ 386*0Sstevel@tonic-gate int doDel; /* To be deleted if refCount zero */ 387*0Sstevel@tonic-gate int onList; /* True if on the 'ldapCon' list */ 388*0Sstevel@tonic-gate char *sp; /* server string */ 389*0Sstevel@tonic-gate char *who; 390*0Sstevel@tonic-gate char *cred; 391*0Sstevel@tonic-gate auth_method_t method; 392*0Sstevel@tonic-gate int port; 393*0Sstevel@tonic-gate struct timeval bindTimeout; 394*0Sstevel@tonic-gate struct timeval searchTimeout; 395*0Sstevel@tonic-gate struct timeval modifyTimeout; 396*0Sstevel@tonic-gate struct timeval addTimeout; 397*0Sstevel@tonic-gate struct timeval deleteTimeout; 398*0Sstevel@tonic-gate int simplePage; /* Can do simple-page */ 399*0Sstevel@tonic-gate int vlv; /* Can do VLV */ 400*0Sstevel@tonic-gate uint_t batchFrom; /* # entries read in one operation */ 401*0Sstevel@tonic-gate void *next; 402*0Sstevel@tonic-gate } __nis_ldap_conn_t; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * List of connections, 'ldapCon', protected by an RW lock. 406*0Sstevel@tonic-gate * 407*0Sstevel@tonic-gate * The following locking scheme is used: 408*0Sstevel@tonic-gate * 409*0Sstevel@tonic-gate * (1) Find a connection structure to use to talk to LDAP 410*0Sstevel@tonic-gate * Rlock list 411*0Sstevel@tonic-gate * Locate structure 412*0Sstevel@tonic-gate * Acquire 'mutex' 413*0Sstevel@tonic-gate * Acquire 'rcMutex' 414*0Sstevel@tonic-gate * update refCount 415*0Sstevel@tonic-gate * Release 'rcMutex' 416*0Sstevel@tonic-gate * release 'mutex' 417*0Sstevel@tonic-gate * Unlock list 418*0Sstevel@tonic-gate * Use structure 419*0Sstevel@tonic-gate * Release structure when done 420*0Sstevel@tonic-gate * (2) Insert/delete structure(s) on/from list 421*0Sstevel@tonic-gate * Wlock list 422*0Sstevel@tonic-gate * Insert/delete structure; if deleting, must 423*0Sstevel@tonic-gate * acquire 'mutex', and 'rcMutex' (in that order), 424*0Sstevel@tonic-gate * and 'refCount' must be zero. 425*0Sstevel@tonic-gate * Unlock list 426*0Sstevel@tonic-gate * (3) Modify structure 427*0Sstevel@tonic-gate * Find structure 428*0Sstevel@tonic-gate * Acquire 'mutex' 429*0Sstevel@tonic-gate * Modify (except refCount) 430*0Sstevel@tonic-gate * Release 'mutex' 431*0Sstevel@tonic-gate * Release structure 432*0Sstevel@tonic-gate */ 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate __nis_ldap_conn_t *ldapCon = 0; 435*0Sstevel@tonic-gate __nis_ldap_conn_t *ldapReferralCon = 0; 436*0Sstevel@tonic-gate static rwlock_t ldapConLock = DEFAULTRWLOCK; 437*0Sstevel@tonic-gate static rwlock_t referralConLock = DEFAULTRWLOCK; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate void 440*0Sstevel@tonic-gate exclusiveLC(__nis_ldap_conn_t *lc) { 441*0Sstevel@tonic-gate pthread_t me = pthread_self(); 442*0Sstevel@tonic-gate int stat; 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate if (lc == 0) 445*0Sstevel@tonic-gate return; 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 448*0Sstevel@tonic-gate if (stat == EBUSY && lc->owner != me) 449*0Sstevel@tonic-gate mutex_lock(&lc->mutex); 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate lc->owner = me; 452*0Sstevel@tonic-gate } 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate /* Return 1 if mutex held by this thread, 0 otherwise */ 455*0Sstevel@tonic-gate int 456*0Sstevel@tonic-gate assertExclusive(__nis_ldap_conn_t *lc) { 457*0Sstevel@tonic-gate pthread_t me; 458*0Sstevel@tonic-gate int stat; 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (lc == 0) 461*0Sstevel@tonic-gate return (0); 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate stat = mutex_trylock(&lc->mutex); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate if (stat == 0) { 466*0Sstevel@tonic-gate mutex_unlock(&lc->mutex); 467*0Sstevel@tonic-gate return (0); 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate me = pthread_self(); 471*0Sstevel@tonic-gate if (stat != EBUSY || lc->owner != me) 472*0Sstevel@tonic-gate return (0); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate return (1); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate void 478*0Sstevel@tonic-gate releaseLC(__nis_ldap_conn_t *lc) { 479*0Sstevel@tonic-gate pthread_t me = pthread_self(); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate if (lc == 0 || lc->owner != me) 482*0Sstevel@tonic-gate return; 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate lc->owner = 0; 485*0Sstevel@tonic-gate (void) mutex_unlock(&lc->mutex); 486*0Sstevel@tonic-gate } 487*0Sstevel@tonic-gate 488*0Sstevel@tonic-gate void 489*0Sstevel@tonic-gate incrementRC(__nis_ldap_conn_t *lc) { 490*0Sstevel@tonic-gate if (lc == 0) 491*0Sstevel@tonic-gate return; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 494*0Sstevel@tonic-gate lc->refCount++; 495*0Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate void 499*0Sstevel@tonic-gate decrementRC(__nis_ldap_conn_t *lc) { 500*0Sstevel@tonic-gate if (lc == 0) 501*0Sstevel@tonic-gate return; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate (void) mutex_lock(&lc->rcMutex); 504*0Sstevel@tonic-gate if (lc->refCount > 0) 505*0Sstevel@tonic-gate lc->refCount--; 506*0Sstevel@tonic-gate (void) mutex_unlock(&lc->rcMutex); 507*0Sstevel@tonic-gate } 508*0Sstevel@tonic-gate 509*0Sstevel@tonic-gate /* Accept a server/port indication, and call ldap_init() */ 510*0Sstevel@tonic-gate static LDAP * 511*0Sstevel@tonic-gate ldapInit(char *srv, int port, bool_t use_ssl) { 512*0Sstevel@tonic-gate LDAP *ld; 513*0Sstevel@tonic-gate int ldapVersion = LDAP_VERSION3; 514*0Sstevel@tonic-gate int derefOption = LDAP_DEREF_ALWAYS; 515*0Sstevel@tonic-gate int timelimit = proxyInfo.search_time_limit; 516*0Sstevel@tonic-gate int sizelimit = proxyInfo.search_size_limit; 517*0Sstevel@tonic-gate char *myself = "ldapInit"; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate if (srv == 0) 520*0Sstevel@tonic-gate return (0); 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate if (use_ssl) { 523*0Sstevel@tonic-gate ld = ldapssl_init(srv, port, 1); 524*0Sstevel@tonic-gate } else { 525*0Sstevel@tonic-gate ld = ldap_init(srv, port); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate if (ld != 0) { 529*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, 530*0Sstevel@tonic-gate &ldapVersion); 531*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption); 532*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 533*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit); 534*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit); 535*0Sstevel@tonic-gate (void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate return (ld); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /* 542*0Sstevel@tonic-gate * Bind the specified LDAP structure per the supplied authentication. 543*0Sstevel@tonic-gate * Note: tested with none, simple, and digest_md5. May or may not 544*0Sstevel@tonic-gate * work with other authentication methods, mostly depending on whether 545*0Sstevel@tonic-gate * or not 'who' and 'cred' contain sufficient information. 546*0Sstevel@tonic-gate */ 547*0Sstevel@tonic-gate static int 548*0Sstevel@tonic-gate ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method, 549*0Sstevel@tonic-gate struct timeval timeout) { 550*0Sstevel@tonic-gate int ret; 551*0Sstevel@tonic-gate LDAP *ld; 552*0Sstevel@tonic-gate char *myself = "ldapBind"; 553*0Sstevel@tonic-gate 554*0Sstevel@tonic-gate if (ldP == 0 || (ld = *ldP) == 0) 555*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate if (method == none) { 558*0Sstevel@tonic-gate /* No ldap_bind() required (or even possible) */ 559*0Sstevel@tonic-gate ret = LDAP_SUCCESS; 560*0Sstevel@tonic-gate } else if (method == simple) { 561*0Sstevel@tonic-gate struct timeval tv; 562*0Sstevel@tonic-gate LDAPMessage *msg = 0; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate tv = timeout; 565*0Sstevel@tonic-gate ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE); 566*0Sstevel@tonic-gate if (ret != -1) { 567*0Sstevel@tonic-gate ret = ldap_result(ld, ret, 0, &tv, &msg); 568*0Sstevel@tonic-gate if (ret == 0) { 569*0Sstevel@tonic-gate ret = LDAP_TIMEOUT; 570*0Sstevel@tonic-gate } else if (ret == -1) { 571*0Sstevel@tonic-gate (void) ldap_get_option(ld, 572*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, 573*0Sstevel@tonic-gate &ret); 574*0Sstevel@tonic-gate } else { 575*0Sstevel@tonic-gate ret = ldap_result2error(ld, msg, 0); 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate if (msg != 0) 578*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 579*0Sstevel@tonic-gate } else { 580*0Sstevel@tonic-gate (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, 581*0Sstevel@tonic-gate &ret); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate } else if (method == cram_md5) { 584*0Sstevel@tonic-gate /* Note: there is only a synchronous call for cram-md5 */ 585*0Sstevel@tonic-gate struct berval ber_cred; 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 588*0Sstevel@tonic-gate ber_cred.bv_val = cred; 589*0Sstevel@tonic-gate ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL); 590*0Sstevel@tonic-gate } else if (method == digest_md5) { 591*0Sstevel@tonic-gate /* Note: there is only a synchronous call for digest-md5 */ 592*0Sstevel@tonic-gate struct berval ber_cred; 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate ber_cred.bv_len = strlen(cred); 595*0Sstevel@tonic-gate ber_cred.bv_val = cred; 596*0Sstevel@tonic-gate ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL, 597*0Sstevel@tonic-gate NULL); 598*0Sstevel@tonic-gate } else { 599*0Sstevel@tonic-gate ret = LDAP_AUTH_METHOD_NOT_SUPPORTED; 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate if (ret != LDAP_SUCCESS) { 603*0Sstevel@tonic-gate (void) ldap_unbind_s(ld); 604*0Sstevel@tonic-gate *ldP = 0; 605*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 606*0Sstevel@tonic-gate "%s: Unable to bind as: %s: %s", 607*0Sstevel@tonic-gate myself, who, ldap_err2string(ret)); 608*0Sstevel@tonic-gate } 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate return (ret); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* 614*0Sstevel@tonic-gate * Free 'lc' and all related memory. Caller must hold the exclusive lock. 615*0Sstevel@tonic-gate * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't 616*0Sstevel@tonic-gate * try to use the structure pointer in any way. 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate static int 619*0Sstevel@tonic-gate freeCon(__nis_ldap_conn_t *lc) { 620*0Sstevel@tonic-gate char *myself = "freeCon"; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate if (!assertExclusive(lc)) 623*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate incrementRC(lc); 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate /* Must be unused, unbound, and not on the 'ldapCon' list */ 628*0Sstevel@tonic-gate if (lc->onList || lc->refCount != 1 || lc->isBound) { 629*0Sstevel@tonic-gate lc->doDel++; 630*0Sstevel@tonic-gate decrementRC(lc); 631*0Sstevel@tonic-gate return (LDAP_BUSY); 632*0Sstevel@tonic-gate } 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate sfree(lc->sp); 635*0Sstevel@tonic-gate sfree(lc->who); 636*0Sstevel@tonic-gate sfree(lc->cred); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate /* Delete structure with both mutex:es held */ 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate free(lc); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 643*0Sstevel@tonic-gate } 644*0Sstevel@tonic-gate 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'. 647*0Sstevel@tonic-gate * 648*0Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 649*0Sstevel@tonic-gate * the structure in any way. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate static int 652*0Sstevel@tonic-gate disconnectCon(__nis_ldap_conn_t *lc) { 653*0Sstevel@tonic-gate int stat; 654*0Sstevel@tonic-gate char *myself = "disconnectCon"; 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate if (lc == 0) 657*0Sstevel@tonic-gate return (LDAP_SUCCESS); 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate if (!assertExclusive(lc)) 660*0Sstevel@tonic-gate return (LDAP_UNAVAILABLE); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate if (lc->doDis) { 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* Increment refCount to protect against interference */ 665*0Sstevel@tonic-gate incrementRC(lc); 666*0Sstevel@tonic-gate /* refCount must be one (i.e., just us) */ 667*0Sstevel@tonic-gate if (lc->refCount != 1) { 668*0Sstevel@tonic-gate /* 669*0Sstevel@tonic-gate * In use; already marked for disconnect, 670*0Sstevel@tonic-gate * so do nothing. 671*0Sstevel@tonic-gate */ 672*0Sstevel@tonic-gate decrementRC(lc); 673*0Sstevel@tonic-gate return (LDAP_BUSY); 674*0Sstevel@tonic-gate } 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate stat = ldap_unbind_s(lc->ld); 677*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 678*0Sstevel@tonic-gate lc->ld = 0; 679*0Sstevel@tonic-gate lc->isBound = 0; 680*0Sstevel@tonic-gate lc->doDis = 0; 681*0Sstevel@tonic-gate /* Reset simple page and vlv indication */ 682*0Sstevel@tonic-gate lc->simplePage = 0; 683*0Sstevel@tonic-gate lc->vlv = 0; 684*0Sstevel@tonic-gate } else if (verbose) { 685*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 686*0Sstevel@tonic-gate "%s: ldap_unbind_s() => %d (%s)", 687*0Sstevel@tonic-gate myself, stat, ldap_err2string(stat)); 688*0Sstevel@tonic-gate } 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate decrementRC(lc); 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate if (lc->doDel) { 694*0Sstevel@tonic-gate if (LDAP_UNAVAILABLE == freeCon(lc)) 695*0Sstevel@tonic-gate stat = LDAP_UNAVAILABLE; 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate 698*0Sstevel@tonic-gate return (stat); 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate /* 702*0Sstevel@tonic-gate * controlSupported will determine for a given connection whether a set 703*0Sstevel@tonic-gate * of controls is supported or not. The input parameters: 704*0Sstevel@tonic-gate * lc The connection 705*0Sstevel@tonic-gate * ctrl A an array of OID strings, the terminal string should be NULL 706*0Sstevel@tonic-gate * The returned values if LDAP_SUCCESS is returned: 707*0Sstevel@tonic-gate * supported A caller supplied array which will be set to TRUE or 708*0Sstevel@tonic-gate * FALSE depending on whether the corresponding control 709*0Sstevel@tonic-gate * is reported as supported. 710*0Sstevel@tonic-gate * Returns LDAP_SUCCESS if the supportedControl attribute is read. 711*0Sstevel@tonic-gate */ 712*0Sstevel@tonic-gate 713*0Sstevel@tonic-gate static int 714*0Sstevel@tonic-gate controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) { 715*0Sstevel@tonic-gate LDAPMessage *res, *e; 716*0Sstevel@tonic-gate char *attr[2], *a, **val; 717*0Sstevel@tonic-gate int stat, i; 718*0Sstevel@tonic-gate BerElement *ber = 0; 719*0Sstevel@tonic-gate char *myself = "controlSupported"; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate attr[0] = "supportedControl"; 722*0Sstevel@tonic-gate attr[1] = 0; 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)", 725*0Sstevel@tonic-gate attr, 0, &lc->searchTimeout, &res); 726*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 727*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 728*0Sstevel@tonic-gate "%s: Unable to retrieve supported control information for %s: %s", 729*0Sstevel@tonic-gate myself, NIL(lc->sp), ldap_err2string(stat)); 730*0Sstevel@tonic-gate return (stat); 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate e = ldap_first_entry(lc->ld, res); 734*0Sstevel@tonic-gate if (e != 0) { 735*0Sstevel@tonic-gate a = ldap_first_attribute(lc->ld, e, &ber); 736*0Sstevel@tonic-gate if (a != 0) { 737*0Sstevel@tonic-gate val = ldap_get_values(lc->ld, e, a); 738*0Sstevel@tonic-gate if (val == 0) { 739*0Sstevel@tonic-gate ldap_memfree(a); 740*0Sstevel@tonic-gate if (ber != 0) 741*0Sstevel@tonic-gate ber_free(ber, 0); 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate if (e == 0 || a == 0 || val == 0) { 746*0Sstevel@tonic-gate ldap_msgfree(res); 747*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 748*0Sstevel@tonic-gate "%s: Unable to get root DSE for %s", 749*0Sstevel@tonic-gate myself, NIL(lc->sp)); 750*0Sstevel@tonic-gate return (LDAP_OPERATIONS_ERROR); 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate while (*ctrl != NULL) { 754*0Sstevel@tonic-gate *supported = FALSE; 755*0Sstevel@tonic-gate for (i = 0; val[i] != 0; i++) { 756*0Sstevel@tonic-gate if (strstr(val[i], *ctrl) != 0) { 757*0Sstevel@tonic-gate *supported = TRUE; 758*0Sstevel@tonic-gate break; 759*0Sstevel@tonic-gate } 760*0Sstevel@tonic-gate } 761*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 762*0Sstevel@tonic-gate "%s: %s: %s: %s", 763*0Sstevel@tonic-gate myself, NIL(lc->sp), NIL(*ctrl), 764*0Sstevel@tonic-gate *supported ? "enabled" : "disabled"); 765*0Sstevel@tonic-gate ctrl++; 766*0Sstevel@tonic-gate supported++; 767*0Sstevel@tonic-gate } 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate ldap_value_free(val); 770*0Sstevel@tonic-gate ldap_memfree(a); 771*0Sstevel@tonic-gate if (ber != 0) 772*0Sstevel@tonic-gate ber_free(ber, 0); 773*0Sstevel@tonic-gate ldap_msgfree(res); 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate return (stat); 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate /* 779*0Sstevel@tonic-gate * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex', 780*0Sstevel@tonic-gate * and the refCount must be zero. 781*0Sstevel@tonic-gate * 782*0Sstevel@tonic-gate * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch 783*0Sstevel@tonic-gate * the structure in any way. 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate static int 786*0Sstevel@tonic-gate connectCon(__nis_ldap_conn_t *lc, int check_ctrl) { 787*0Sstevel@tonic-gate struct timeval tp; 788*0Sstevel@tonic-gate int stat; 789*0Sstevel@tonic-gate bool_t supported[2] = {FALSE, FALSE}; 790*0Sstevel@tonic-gate char *ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE, 791*0Sstevel@tonic-gate LDAP_CONTROL_VLVREQUEST, 792*0Sstevel@tonic-gate NULL}; 793*0Sstevel@tonic-gate 794*0Sstevel@tonic-gate if (lc == 0) 795*0Sstevel@tonic-gate return (LDAP_SUCCESS); 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate if (!assertExclusive(lc)) 798*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate incrementRC(lc); 801*0Sstevel@tonic-gate if (lc->refCount != 1) { 802*0Sstevel@tonic-gate /* 803*0Sstevel@tonic-gate * Don't want to step on structure when it's used by someone 804*0Sstevel@tonic-gate * else. 805*0Sstevel@tonic-gate */ 806*0Sstevel@tonic-gate decrementRC(lc); 807*0Sstevel@tonic-gate return (LDAP_BUSY); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate (void) gettimeofday(&tp, 0); 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate if (lc->ld != 0) { 813*0Sstevel@tonic-gate /* Try to disconnect */ 814*0Sstevel@tonic-gate lc->doDis++; 815*0Sstevel@tonic-gate decrementRC(lc); 816*0Sstevel@tonic-gate /* disconnctCon() will do the delete if required */ 817*0Sstevel@tonic-gate stat = disconnectCon(lc); 818*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) 819*0Sstevel@tonic-gate return (stat); 820*0Sstevel@tonic-gate incrementRC(lc); 821*0Sstevel@tonic-gate if (lc->refCount != 1 || lc->ld != 0) { 822*0Sstevel@tonic-gate decrementRC(lc); 823*0Sstevel@tonic-gate return (lc->ld != 0) ? LDAP_SUCCESS : 824*0Sstevel@tonic-gate LDAP_BUSY; 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate } else if (tp.tv_sec < lc->retryTime) { 827*0Sstevel@tonic-gate /* Too early to retry connect */ 828*0Sstevel@tonic-gate decrementRC(lc); 829*0Sstevel@tonic-gate return (LDAP_SERVER_DOWN); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate /* Set new retry time in case we fail below */ 833*0Sstevel@tonic-gate lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout; 834*0Sstevel@tonic-gate 835*0Sstevel@tonic-gate lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls); 836*0Sstevel@tonic-gate if (lc->ld == 0) { 837*0Sstevel@tonic-gate decrementRC(lc); 838*0Sstevel@tonic-gate return (LDAP_LOCAL_ERROR); 839*0Sstevel@tonic-gate } 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method, 842*0Sstevel@tonic-gate lc->bindTimeout); 843*0Sstevel@tonic-gate if (lc->status == LDAP_SUCCESS) { 844*0Sstevel@tonic-gate lc->isBound = 1; 845*0Sstevel@tonic-gate lc->retryTime = 0; 846*0Sstevel@tonic-gate if (check_ctrl) { 847*0Sstevel@tonic-gate (void) controlSupported(lc, ctrl, supported); 848*0Sstevel@tonic-gate lc->simplePage = supported[0]; 849*0Sstevel@tonic-gate lc->vlv = supported[1]; 850*0Sstevel@tonic-gate lc->batchFrom = 50000; 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate decrementRC(lc); 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate return (stat); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate /* 860*0Sstevel@tonic-gate * Find and return a connection believed to be OK. 861*0Sstevel@tonic-gate */ 862*0Sstevel@tonic-gate static __nis_ldap_conn_t * 863*0Sstevel@tonic-gate findCon(int *stat) { 864*0Sstevel@tonic-gate __nis_ldap_conn_t *lc; 865*0Sstevel@tonic-gate int ldapStat; 866*0Sstevel@tonic-gate char *myself = "findCon"; 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate if (stat == 0) 869*0Sstevel@tonic-gate stat = &ldapStat; 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate if (ldapCon == 0) { 874*0Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 875*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 876*0Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 877*0Sstevel@tonic-gate proxyInfo.proxy_dn, 878*0Sstevel@tonic-gate proxyInfo.proxy_passwd, 879*0Sstevel@tonic-gate proxyInfo.auth_method)) != 880*0Sstevel@tonic-gate LDAP_SUCCESS) 881*0Sstevel@tonic-gate return (0); 882*0Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 886*0Sstevel@tonic-gate exclusiveLC(lc); 887*0Sstevel@tonic-gate if (!lc->isBound) { 888*0Sstevel@tonic-gate *stat = connectCon(lc, 1); 889*0Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 890*0Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 891*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 892*0Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 893*0Sstevel@tonic-gate myself, NIL(lc->sp), 894*0Sstevel@tonic-gate ldap_err2string(*stat)); 895*0Sstevel@tonic-gate releaseLC(lc); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate continue; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 900*0Sstevel@tonic-gate *stat = disconnectCon(lc); 901*0Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 902*0Sstevel@tonic-gate releaseLC(lc); 903*0Sstevel@tonic-gate continue; 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate incrementRC(lc); 906*0Sstevel@tonic-gate releaseLC(lc); 907*0Sstevel@tonic-gate break; 908*0Sstevel@tonic-gate } 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 911*0Sstevel@tonic-gate 912*0Sstevel@tonic-gate return (lc); 913*0Sstevel@tonic-gate } 914*0Sstevel@tonic-gate 915*0Sstevel@tonic-gate /* Release connection; decrements ref count for the connection */ 916*0Sstevel@tonic-gate static void 917*0Sstevel@tonic-gate releaseCon(__nis_ldap_conn_t *lc, int status) { 918*0Sstevel@tonic-gate int stat; 919*0Sstevel@tonic-gate 920*0Sstevel@tonic-gate if (lc == 0) 921*0Sstevel@tonic-gate return; 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate exclusiveLC(lc); 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate lc->status = status; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate decrementRC(lc); 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate if (lc->doDis) 930*0Sstevel@tonic-gate stat = disconnectCon(lc); 931*0Sstevel@tonic-gate else 932*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate if (stat != LDAP_UNAVAILABLE) 935*0Sstevel@tonic-gate releaseLC(lc); 936*0Sstevel@tonic-gate } 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate static __nis_ldap_conn_t * 939*0Sstevel@tonic-gate createCon(char *sp, char *who, char *cred, auth_method_t method, int port) { 940*0Sstevel@tonic-gate __nis_ldap_conn_t *lc; 941*0Sstevel@tonic-gate char *myself = "createCon"; 942*0Sstevel@tonic-gate char *r; 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate if (sp == 0) 945*0Sstevel@tonic-gate return (0); 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate lc = am(myself, sizeof (*lc)); 948*0Sstevel@tonic-gate if (lc == 0) 949*0Sstevel@tonic-gate return (0); 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate (void) mutex_init(&lc->mutex, 0, 0); 952*0Sstevel@tonic-gate (void) mutex_init(&lc->rcMutex, 0, 0); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate /* If we need to delete 'lc', freeCon() wants the mutex held */ 955*0Sstevel@tonic-gate exclusiveLC(lc); 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate lc->sp = sdup(myself, T, sp); 958*0Sstevel@tonic-gate if (lc->sp == 0) { 959*0Sstevel@tonic-gate (void) freeCon(lc); 960*0Sstevel@tonic-gate return (0); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate if ((r = strchr(lc->sp, ']')) != 0) { 964*0Sstevel@tonic-gate /* 965*0Sstevel@tonic-gate * IPv6 address. Does libldap want this with the 966*0Sstevel@tonic-gate * '[' and ']' left in place ? Assume so for now. 967*0Sstevel@tonic-gate */ 968*0Sstevel@tonic-gate r = strchr(r, ':'); 969*0Sstevel@tonic-gate } else { 970*0Sstevel@tonic-gate r = strchr(lc->sp, ':'); 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate if (r != NULL) { 974*0Sstevel@tonic-gate *r++ = '\0'; 975*0Sstevel@tonic-gate port = atoi(r); 976*0Sstevel@tonic-gate } else if (port == 0) 977*0Sstevel@tonic-gate port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT; 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate if (who != 0) { 980*0Sstevel@tonic-gate lc->who = sdup(myself, T, who); 981*0Sstevel@tonic-gate if (lc->who == 0) { 982*0Sstevel@tonic-gate (void) freeCon(lc); 983*0Sstevel@tonic-gate return (0); 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate if (cred != 0) { 988*0Sstevel@tonic-gate lc->cred = sdup(myself, T, cred); 989*0Sstevel@tonic-gate if (lc->cred == 0) { 990*0Sstevel@tonic-gate (void) freeCon(lc); 991*0Sstevel@tonic-gate return (0); 992*0Sstevel@tonic-gate } 993*0Sstevel@tonic-gate } 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate lc->method = method; 996*0Sstevel@tonic-gate lc->port = port; 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate lc->bindTimeout = proxyInfo.bind_timeout; 999*0Sstevel@tonic-gate lc->searchTimeout = proxyInfo.search_timeout; 1000*0Sstevel@tonic-gate lc->modifyTimeout = proxyInfo.modify_timeout; 1001*0Sstevel@tonic-gate lc->addTimeout = proxyInfo.add_timeout; 1002*0Sstevel@tonic-gate lc->deleteTimeout = proxyInfo.delete_timeout; 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate /* All other fields OK at zero */ 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate releaseLC(lc); 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate return (lc); 1009*0Sstevel@tonic-gate } 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate static int 1012*0Sstevel@tonic-gate setupConList(char *serverList, char *who, char *cred, auth_method_t method) { 1013*0Sstevel@tonic-gate char *sls, *sl, *s, *e; 1014*0Sstevel@tonic-gate __nis_ldap_conn_t *lc, *tmp; 1015*0Sstevel@tonic-gate char *myself = "setupConList"; 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate if (serverList == 0) 1018*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate (void) rw_wrlock(&ldapConLock); 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate if (ldapCon != 0) { 1023*0Sstevel@tonic-gate /* Assume we've already been called and done the set-up */ 1024*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1025*0Sstevel@tonic-gate return (LDAP_SUCCESS); 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate /* Work on a copy of 'serverList' */ 1029*0Sstevel@tonic-gate sl = sls = sdup(myself, T, serverList); 1030*0Sstevel@tonic-gate if (sl == 0) { 1031*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1032*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate /* Remove leading white space */ 1036*0Sstevel@tonic-gate for (0; *sl == ' ' || *sl == '\t'; sl++); 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate /* Create connection for each server on the list */ 1039*0Sstevel@tonic-gate for (s = sl; *s != '\0'; s = e+1) { 1040*0Sstevel@tonic-gate int l; 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate /* Find end of server/port token */ 1043*0Sstevel@tonic-gate for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++); 1044*0Sstevel@tonic-gate if (*e != '\0') 1045*0Sstevel@tonic-gate *e = '\0'; 1046*0Sstevel@tonic-gate else 1047*0Sstevel@tonic-gate e--; 1048*0Sstevel@tonic-gate l = slen(s); 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate if (l > 0) { 1051*0Sstevel@tonic-gate lc = createCon(s, who, cred, method, 0); 1052*0Sstevel@tonic-gate if (lc == 0) { 1053*0Sstevel@tonic-gate free(sls); 1054*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1055*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate lc->onList = 1; 1058*0Sstevel@tonic-gate if (ldapCon == 0) { 1059*0Sstevel@tonic-gate ldapCon = lc; 1060*0Sstevel@tonic-gate } else { 1061*0Sstevel@tonic-gate /* Insert at end of list */ 1062*0Sstevel@tonic-gate for (tmp = ldapCon; tmp->next != 0; 1063*0Sstevel@tonic-gate tmp = tmp->next); 1064*0Sstevel@tonic-gate tmp->next = lc; 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate free(sls); 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate return (LDAP_SUCCESS); 1074*0Sstevel@tonic-gate } 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate static bool_t 1077*0Sstevel@tonic-gate is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp) 1078*0Sstevel@tonic-gate { 1079*0Sstevel@tonic-gate return (strcasecmp(ludpp->lud_host, lc->sp) == 0 && 1080*0Sstevel@tonic-gate ludpp->lud_port == lc->port); 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate static __nis_ldap_conn_t * 1084*0Sstevel@tonic-gate find_connection_from_list(__nis_ldap_conn_t *list, 1085*0Sstevel@tonic-gate LDAPURLDesc *ludpp, int *stat) 1086*0Sstevel@tonic-gate { 1087*0Sstevel@tonic-gate int ldapStat; 1088*0Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 1089*0Sstevel@tonic-gate if (stat == 0) 1090*0Sstevel@tonic-gate stat = &ldapStat; 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate *stat = LDAP_SUCCESS; 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate for (lc = list; lc != 0; lc = lc->next) { 1095*0Sstevel@tonic-gate exclusiveLC(lc); 1096*0Sstevel@tonic-gate if (is_same_connection(lc, ludpp)) { 1097*0Sstevel@tonic-gate if (!lc->isBound) { 1098*0Sstevel@tonic-gate *stat = connectCon(lc, 1); 1099*0Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 1100*0Sstevel@tonic-gate releaseLC(lc); 1101*0Sstevel@tonic-gate continue; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate } else if (lc->doDis || lc->doDel) { 1104*0Sstevel@tonic-gate (void) disconnectCon(lc); 1105*0Sstevel@tonic-gate releaseLC(lc); 1106*0Sstevel@tonic-gate continue; 1107*0Sstevel@tonic-gate } 1108*0Sstevel@tonic-gate incrementRC(lc); 1109*0Sstevel@tonic-gate releaseLC(lc); 1110*0Sstevel@tonic-gate break; 1111*0Sstevel@tonic-gate } 1112*0Sstevel@tonic-gate releaseLC(lc); 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate return (lc); 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate static __nis_ldap_conn_t * 1118*0Sstevel@tonic-gate findReferralCon(char **referralsp, int *stat) 1119*0Sstevel@tonic-gate { 1120*0Sstevel@tonic-gate __nis_ldap_conn_t *lc = NULL; 1121*0Sstevel@tonic-gate __nis_ldap_conn_t *tmp; 1122*0Sstevel@tonic-gate int ldapStat; 1123*0Sstevel@tonic-gate int i; 1124*0Sstevel@tonic-gate LDAPURLDesc *ludpp = NULL; 1125*0Sstevel@tonic-gate char *myself = "findReferralCon"; 1126*0Sstevel@tonic-gate 1127*0Sstevel@tonic-gate if (stat == 0) 1128*0Sstevel@tonic-gate stat = &ldapStat; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate *stat = LDAP_SUCCESS; 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate /* 1133*0Sstevel@tonic-gate * We have the referral lock - to prevent multiple 1134*0Sstevel@tonic-gate * threads from creating a referred connection simultaneously 1135*0Sstevel@tonic-gate * 1136*0Sstevel@tonic-gate * Note that this code assumes that the ldapCon list is a 1137*0Sstevel@tonic-gate * static list - that it has previously been created 1138*0Sstevel@tonic-gate * (otherwise we wouldn't have gotten a referral) and that 1139*0Sstevel@tonic-gate * it will neither grow or shrink - elements may have new 1140*0Sstevel@tonic-gate * connections or unbound. If this assumption is no longer valid, 1141*0Sstevel@tonic-gate * the locking needs to be reworked. 1142*0Sstevel@tonic-gate */ 1143*0Sstevel@tonic-gate (void) rw_rdlock(&referralConLock); 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 1146*0Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 1147*0Sstevel@tonic-gate continue; 1148*0Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 1149*0Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 1150*0Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 1151*0Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 1152*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1153*0Sstevel@tonic-gate continue; 1154*0Sstevel@tonic-gate } 1155*0Sstevel@tonic-gate } else { 1156*0Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 1157*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1158*0Sstevel@tonic-gate continue; 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate } 1161*0Sstevel@tonic-gate #endif 1162*0Sstevel@tonic-gate 1163*0Sstevel@tonic-gate /* Determine if we already have a connection to the server */ 1164*0Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 1165*0Sstevel@tonic-gate if (lc == NULL) 1166*0Sstevel@tonic-gate lc = find_connection_from_list(ldapCon, ludpp, stat); 1167*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1168*0Sstevel@tonic-gate if (lc != NULL) { 1169*0Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 1170*0Sstevel@tonic-gate return (lc); 1171*0Sstevel@tonic-gate } 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate for (i = 0; referralsp[i] != NULL; i++) { 1175*0Sstevel@tonic-gate if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS) 1176*0Sstevel@tonic-gate continue; 1177*0Sstevel@tonic-gate /* Ignore referrals if not at the appropriate tls level */ 1178*0Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE 1179*0Sstevel@tonic-gate if (ludpp->lud_options & LDAP_URL_OPT_SECURE) { 1180*0Sstevel@tonic-gate if (proxyInfo.tls_method != ssl_tls) { 1181*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1182*0Sstevel@tonic-gate continue; 1183*0Sstevel@tonic-gate } 1184*0Sstevel@tonic-gate } else { 1185*0Sstevel@tonic-gate if (proxyInfo.tls_method != no_tls) { 1186*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1187*0Sstevel@tonic-gate continue; 1188*0Sstevel@tonic-gate } 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate #endif 1191*0Sstevel@tonic-gate lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn, 1192*0Sstevel@tonic-gate proxyInfo.proxy_passwd, 1193*0Sstevel@tonic-gate proxyInfo.auth_method, 1194*0Sstevel@tonic-gate ludpp->lud_port); 1195*0Sstevel@tonic-gate if (lc == 0) { 1196*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1197*0Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 1198*0Sstevel@tonic-gate *stat = LDAP_NO_MEMORY; 1199*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1200*0Sstevel@tonic-gate "%s: Could not connect to host: %s", 1201*0Sstevel@tonic-gate myself, NIL(ludpp->lud_host)); 1202*0Sstevel@tonic-gate return (NULL); 1203*0Sstevel@tonic-gate } 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate lc->onList = 1; 1206*0Sstevel@tonic-gate if (ldapReferralCon == 0) { 1207*0Sstevel@tonic-gate ldapReferralCon = lc; 1208*0Sstevel@tonic-gate } else { 1209*0Sstevel@tonic-gate /* Insert at end of list */ 1210*0Sstevel@tonic-gate for (tmp = ldapReferralCon; tmp->next != 0; 1211*0Sstevel@tonic-gate tmp = tmp->next) {} 1212*0Sstevel@tonic-gate tmp->next = lc; 1213*0Sstevel@tonic-gate } 1214*0Sstevel@tonic-gate lc = find_connection_from_list(ldapReferralCon, ludpp, stat); 1215*0Sstevel@tonic-gate ldap_free_urldesc(ludpp); 1216*0Sstevel@tonic-gate if (lc != NULL) 1217*0Sstevel@tonic-gate break; 1218*0Sstevel@tonic-gate } 1219*0Sstevel@tonic-gate (void) rw_unlock(&referralConLock); 1220*0Sstevel@tonic-gate if (lc == NULL) { 1221*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1222*0Sstevel@tonic-gate "%s: Could not find a connection to %s, ...", 1223*0Sstevel@tonic-gate myself, NIL(referralsp[0])); 1224*0Sstevel@tonic-gate } 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate return (lc); 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate /* 1230*0Sstevel@tonic-gate * Find and return a connection believed to be OK and ensure children 1231*0Sstevel@tonic-gate * will never use parent's connection. 1232*0Sstevel@tonic-gate */ 1233*0Sstevel@tonic-gate static __nis_ldap_conn_t * 1234*0Sstevel@tonic-gate findYPCon(__nis_ldap_search_t *ls, int *stat) { 1235*0Sstevel@tonic-gate __nis_ldap_conn_t *lc, *newlc; 1236*0Sstevel@tonic-gate int ldapStat, newstat; 1237*0Sstevel@tonic-gate char *myself = "findYPCon"; 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate if (stat == 0) 1240*0Sstevel@tonic-gate stat = &ldapStat; 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate if (ldapCon == 0) { 1245*0Sstevel@tonic-gate /* Probably first call; try to set up the connection list */ 1246*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1247*0Sstevel@tonic-gate if ((*stat = setupConList(proxyInfo.default_servers, 1248*0Sstevel@tonic-gate proxyInfo.proxy_dn, 1249*0Sstevel@tonic-gate proxyInfo.proxy_passwd, 1250*0Sstevel@tonic-gate proxyInfo.auth_method)) != 1251*0Sstevel@tonic-gate LDAP_SUCCESS) 1252*0Sstevel@tonic-gate return (0); 1253*0Sstevel@tonic-gate (void) rw_rdlock(&ldapConLock); 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate for (lc = ldapCon; lc != 0; lc = lc->next) { 1257*0Sstevel@tonic-gate exclusiveLC(lc); 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate if (lc->isBound && (lc->doDis || lc->doDel)) { 1260*0Sstevel@tonic-gate *stat = disconnectCon(lc); 1261*0Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) 1262*0Sstevel@tonic-gate releaseLC(lc); 1263*0Sstevel@tonic-gate continue; 1264*0Sstevel@tonic-gate } 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate /* 1267*0Sstevel@tonic-gate * Use a new connection for all cases except when 1268*0Sstevel@tonic-gate * requested by the main thread in the parent ypserv 1269*0Sstevel@tonic-gate * process. 1270*0Sstevel@tonic-gate */ 1271*0Sstevel@tonic-gate if (ls->useCon == 0) { 1272*0Sstevel@tonic-gate newlc = createCon(lc->sp, lc->who, lc->cred, 1273*0Sstevel@tonic-gate lc->method, lc->port); 1274*0Sstevel@tonic-gate if (!newlc) { 1275*0Sstevel@tonic-gate releaseLC(lc); 1276*0Sstevel@tonic-gate continue; 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate if (lc->ld != 0) { 1279*0Sstevel@tonic-gate newlc->simplePage = lc->simplePage; 1280*0Sstevel@tonic-gate newlc->vlv = lc->vlv; 1281*0Sstevel@tonic-gate newlc->batchFrom = lc->batchFrom; 1282*0Sstevel@tonic-gate } 1283*0Sstevel@tonic-gate releaseLC(lc); 1284*0Sstevel@tonic-gate exclusiveLC(newlc); 1285*0Sstevel@tonic-gate newstat = connectCon(newlc, 0); 1286*0Sstevel@tonic-gate if (newstat != LDAP_SUCCESS) { 1287*0Sstevel@tonic-gate if (newstat != LDAP_UNAVAILABLE) { 1288*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1289*0Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 1290*0Sstevel@tonic-gate myself, NIL(newlc->sp), 1291*0Sstevel@tonic-gate ldap_err2string(*stat)); 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate (void) freeCon(newlc); 1294*0Sstevel@tonic-gate newlc = 0; 1295*0Sstevel@tonic-gate continue; 1296*0Sstevel@tonic-gate } 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate /* 1299*0Sstevel@tonic-gate * No need to put newlc on the ldapCon list as this 1300*0Sstevel@tonic-gate * connection will be freed after use. 1301*0Sstevel@tonic-gate */ 1302*0Sstevel@tonic-gate newlc->onList = 0; 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate lc = newlc; 1305*0Sstevel@tonic-gate } else if (!lc->isBound) { 1306*0Sstevel@tonic-gate *stat = connectCon(lc, 1); 1307*0Sstevel@tonic-gate if (*stat != LDAP_SUCCESS) { 1308*0Sstevel@tonic-gate if (*stat != LDAP_UNAVAILABLE) { 1309*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1310*0Sstevel@tonic-gate "%s: Cannot open connection to LDAP server (%s): %s", 1311*0Sstevel@tonic-gate myself, NIL(lc->sp), 1312*0Sstevel@tonic-gate ldap_err2string(*stat)); 1313*0Sstevel@tonic-gate releaseLC(lc); 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate continue; 1316*0Sstevel@tonic-gate } 1317*0Sstevel@tonic-gate } 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate incrementRC(lc); 1320*0Sstevel@tonic-gate releaseLC(lc); 1321*0Sstevel@tonic-gate break; 1322*0Sstevel@tonic-gate } 1323*0Sstevel@tonic-gate 1324*0Sstevel@tonic-gate (void) rw_unlock(&ldapConLock); 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate return (lc); 1327*0Sstevel@tonic-gate } 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate #define SORTKEYLIST "cn uid" 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate /* 1332*0Sstevel@tonic-gate * Perform an LDAP search operation per 'ls', adding the result(s) to 1333*0Sstevel@tonic-gate * a copy of the 'rvIn' structure; the copy becomes the return value. 1334*0Sstevel@tonic-gate * The caller must deallocate both 'rvIn' and the result, if any. 1335*0Sstevel@tonic-gate * 1336*0Sstevel@tonic-gate * On entry, '*numValues' contains a hint regarding the expected 1337*0Sstevel@tonic-gate * number of entries. Zero is the same as one, and negative values 1338*0Sstevel@tonic-gate * imply no information. This is used to decide whether or not to 1339*0Sstevel@tonic-gate * try an indexed search. 1340*0Sstevel@tonic-gate * 1341*0Sstevel@tonic-gate * On successful (non-NULL) return, '*numValues' contains the number 1342*0Sstevel@tonic-gate * of __nis_rule_value_t elements in the returned array, and '*stat' 1343*0Sstevel@tonic-gate * the LDAP operations status. 1344*0Sstevel@tonic-gate */ 1345*0Sstevel@tonic-gate __nis_rule_value_t * 1346*0Sstevel@tonic-gate ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn, 1347*0Sstevel@tonic-gate int *ldapStat) { 1348*0Sstevel@tonic-gate __nis_rule_value_t *rv = 0; 1349*0Sstevel@tonic-gate int stat, numEntries, numVals, tnv, done, lprEc; 1350*0Sstevel@tonic-gate LDAPMessage *msg = 0, *m; 1351*0Sstevel@tonic-gate __nis_ldap_conn_t *lc; 1352*0Sstevel@tonic-gate struct timeval tv, start, now; 1353*0Sstevel@tonic-gate LDAPsortkey **sortKeyList = 0; 1354*0Sstevel@tonic-gate LDAPControl *ctrls[3], *sortCtrl = 0, *vlvCtrl = 0; 1355*0Sstevel@tonic-gate LDAPControl **retCtrls = 0; 1356*0Sstevel@tonic-gate LDAPVirtualList vList; 1357*0Sstevel@tonic-gate struct berval *spCookie = 0; 1358*0Sstevel@tonic-gate int doVLV = 0; 1359*0Sstevel@tonic-gate int doSP = 0; 1360*0Sstevel@tonic-gate long index; 1361*0Sstevel@tonic-gate char *myself = "ldapSearch"; 1362*0Sstevel@tonic-gate bool_t follow_referral = 1363*0Sstevel@tonic-gate proxyInfo.follow_referral == follow; 1364*0Sstevel@tonic-gate int doIndex = 1; 1365*0Sstevel@tonic-gate char **referralsp = NULL; 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate if (ldapStat == 0) 1368*0Sstevel@tonic-gate ldapStat = &stat; 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate if (ls == 0) { 1371*0Sstevel@tonic-gate *ldapStat = LDAP_PARAM_ERROR; 1372*0Sstevel@tonic-gate return (0); 1373*0Sstevel@tonic-gate } 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate if (yp2ldap) { 1376*0Sstevel@tonic-gate /* make sure the parent's connection is not used by child */ 1377*0Sstevel@tonic-gate if ((lc = findYPCon(ls, ldapStat)) == 0) { 1378*0Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 1379*0Sstevel@tonic-gate return (0); 1380*0Sstevel@tonic-gate } 1381*0Sstevel@tonic-gate } else { 1382*0Sstevel@tonic-gate if ((lc = findCon(ldapStat)) == 0) { 1383*0Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 1384*0Sstevel@tonic-gate return (0); 1385*0Sstevel@tonic-gate } 1386*0Sstevel@tonic-gate } 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate if (numValues != 0 && (*numValues == 0 || *numValues == 1)) 1389*0Sstevel@tonic-gate doIndex = 0; 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate retry_new_conn: 1392*0Sstevel@tonic-gate /* Prefer VLV over simple page, and SP over nothing */ 1393*0Sstevel@tonic-gate if (doIndex && lc->vlv) { 1394*0Sstevel@tonic-gate stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST); 1395*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 1396*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1397*0Sstevel@tonic-gate "%s: Error creating sort keylist: %s", 1398*0Sstevel@tonic-gate myself, ldap_err2string(stat)); 1399*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1400*0Sstevel@tonic-gate *ldapStat = stat; 1401*0Sstevel@tonic-gate rv = 0; 1402*0Sstevel@tonic-gate goto retry_noVLV; 1403*0Sstevel@tonic-gate } 1404*0Sstevel@tonic-gate stat = ldap_create_sort_control(lc->ld, sortKeyList, 1, 1405*0Sstevel@tonic-gate &sortCtrl); 1406*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 1407*0Sstevel@tonic-gate vList.ldvlist_before_count = 0; 1408*0Sstevel@tonic-gate vList.ldvlist_after_count = lc->batchFrom - 1; 1409*0Sstevel@tonic-gate vList.ldvlist_attrvalue = 0; 1410*0Sstevel@tonic-gate vList.ldvlist_extradata = 0; 1411*0Sstevel@tonic-gate index = 1; 1412*0Sstevel@tonic-gate doVLV = 1; 1413*0Sstevel@tonic-gate } else { 1414*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 1415*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1416*0Sstevel@tonic-gate "%s: Error creating VLV sort control: %s", 1417*0Sstevel@tonic-gate myself, ldap_err2string(stat)); 1418*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1419*0Sstevel@tonic-gate *ldapStat = stat; 1420*0Sstevel@tonic-gate rv = 0; 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate } 1423*0Sstevel@tonic-gate 1424*0Sstevel@tonic-gate retry_noVLV: 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate if (doIndex && !doVLV && lc->simplePage) { 1427*0Sstevel@tonic-gate spCookie = am(myself, sizeof (*spCookie)); 1428*0Sstevel@tonic-gate if (spCookie != 0 && 1429*0Sstevel@tonic-gate (spCookie->bv_val = sdup(myself, T, "")) != 0) { 1430*0Sstevel@tonic-gate spCookie->bv_len = 0; 1431*0Sstevel@tonic-gate doSP = 1; 1432*0Sstevel@tonic-gate } else { 1433*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1434*0Sstevel@tonic-gate "%s: No memory for simple page cookie; using un-paged LDAP search", 1435*0Sstevel@tonic-gate myself); 1436*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1437*0Sstevel@tonic-gate *ldapStat = stat; 1438*0Sstevel@tonic-gate rv = 0; 1439*0Sstevel@tonic-gate goto cleanup; 1440*0Sstevel@tonic-gate } 1441*0Sstevel@tonic-gate } 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate if (!doVLV && !doSP) 1444*0Sstevel@tonic-gate ctrls[0] = ctrls[1] = 0; 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate numVals = 0; 1447*0Sstevel@tonic-gate done = 0; 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate if (ls->timeout.tv_sec || ls->timeout.tv_usec) { 1450*0Sstevel@tonic-gate tv = ls->timeout; 1451*0Sstevel@tonic-gate } else { 1452*0Sstevel@tonic-gate tv = lc->searchTimeout; 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate (void) gettimeofday(&start, 0); 1455*0Sstevel@tonic-gate 1456*0Sstevel@tonic-gate do { 1457*0Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 1458*0Sstevel@tonic-gate if (doVLV && ls->base != LDAP_SCOPE_BASE) { 1459*0Sstevel@tonic-gate vList.ldvlist_index = index; 1460*0Sstevel@tonic-gate vList.ldvlist_size = 0; 1461*0Sstevel@tonic-gate if (vlvCtrl != 0) 1462*0Sstevel@tonic-gate ldap_control_free(vlvCtrl); 1463*0Sstevel@tonic-gate stat = ldap_create_virtuallist_control(lc->ld, 1464*0Sstevel@tonic-gate &vList, &vlvCtrl); 1465*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 1466*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 1467*0Sstevel@tonic-gate &stat); 1468*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1469*0Sstevel@tonic-gate "%s: Error creating VLV at index %ld: %s", 1470*0Sstevel@tonic-gate myself, index, ldap_err2string(stat)); 1471*0Sstevel@tonic-gate *ldapStat = stat; 1472*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1473*0Sstevel@tonic-gate rv = 0; 1474*0Sstevel@tonic-gate goto cleanup; 1475*0Sstevel@tonic-gate } 1476*0Sstevel@tonic-gate ctrls[0] = sortCtrl; 1477*0Sstevel@tonic-gate ctrls[1] = vlvCtrl; 1478*0Sstevel@tonic-gate ctrls[2] = 0; 1479*0Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 1480*0Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 1481*0Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 1482*0Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 1483*0Sstevel@tonic-gate /* don't do vlv or simple page for base level searches */ 1484*0Sstevel@tonic-gate } else if (doSP && ls->base != LDAP_SCOPE_BASE) { 1485*0Sstevel@tonic-gate if (ctrls[0] != 0) 1486*0Sstevel@tonic-gate ldap_control_free(ctrls[0]); 1487*0Sstevel@tonic-gate stat = ldap_create_page_control(lc->ld, 1488*0Sstevel@tonic-gate lc->batchFrom, spCookie, 0, &ctrls[0]); 1489*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 1490*0Sstevel@tonic-gate ber_bvfree(spCookie); 1491*0Sstevel@tonic-gate spCookie = 0; 1492*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 1493*0Sstevel@tonic-gate &stat); 1494*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1495*0Sstevel@tonic-gate "%s: Simple page error: %s", 1496*0Sstevel@tonic-gate myself, ldap_err2string(stat)); 1497*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1498*0Sstevel@tonic-gate *ldapStat = stat; 1499*0Sstevel@tonic-gate rv = 0; 1500*0Sstevel@tonic-gate goto cleanup; 1501*0Sstevel@tonic-gate } 1502*0Sstevel@tonic-gate ctrls[1] = 0; 1503*0Sstevel@tonic-gate stat = ldap_search_ext_s(lc->ld, ls->base, 1504*0Sstevel@tonic-gate ls->scope, ls->filter, ls->attrs, 1505*0Sstevel@tonic-gate ls->attrsonly, ctrls, 0, &tv, 1506*0Sstevel@tonic-gate proxyInfo.search_size_limit, &msg); 1507*0Sstevel@tonic-gate } else { 1508*0Sstevel@tonic-gate stat = ldap_search_st(lc->ld, ls->base, ls->scope, 1509*0Sstevel@tonic-gate ls->filter, ls->attrs, ls->attrsonly, 1510*0Sstevel@tonic-gate &tv, &msg); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 1513*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate if (stat == LDAP_SERVER_DOWN) { 1516*0Sstevel@tonic-gate lc->doDis++; 1517*0Sstevel@tonic-gate releaseCon(lc, stat); 1518*0Sstevel@tonic-gate lc = (yp2ldap)?findYPCon(ls, ldapStat): 1519*0Sstevel@tonic-gate findCon(ldapStat); 1520*0Sstevel@tonic-gate if (lc == 0) { 1521*0Sstevel@tonic-gate *ldapStat = LDAP_SERVER_DOWN; 1522*0Sstevel@tonic-gate rv = 0; 1523*0Sstevel@tonic-gate goto cleanup; 1524*0Sstevel@tonic-gate } 1525*0Sstevel@tonic-gate goto retry_new_conn; 1526*0Sstevel@tonic-gate } 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate if (stat == LDAP_REFERRAL && follow_referral) { 1529*0Sstevel@tonic-gate (void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL, 1530*0Sstevel@tonic-gate &referralsp, NULL, 0); 1531*0Sstevel@tonic-gate if (referralsp != NULL) { 1532*0Sstevel@tonic-gate /* We support at most one level of referrals */ 1533*0Sstevel@tonic-gate follow_referral = FALSE; 1534*0Sstevel@tonic-gate releaseCon(lc, stat); 1535*0Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 1536*0Sstevel@tonic-gate ldap_value_free(referralsp); 1537*0Sstevel@tonic-gate if (lc == NULL) { 1538*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1539*0Sstevel@tonic-gate rv = 0; 1540*0Sstevel@tonic-gate *ldapStat = stat; 1541*0Sstevel@tonic-gate goto cleanup; 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 1544*0Sstevel@tonic-gate goto retry_new_conn; 1545*0Sstevel@tonic-gate } 1546*0Sstevel@tonic-gate } 1547*0Sstevel@tonic-gate *ldapStat = stat; 1548*0Sstevel@tonic-gate 1549*0Sstevel@tonic-gate if (*ldapStat == LDAP_NO_SUCH_OBJECT) { 1550*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1551*0Sstevel@tonic-gate rv = 0; 1552*0Sstevel@tonic-gate goto cleanup; 1553*0Sstevel@tonic-gate } else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) { 1554*0Sstevel@tonic-gate /* 1555*0Sstevel@tonic-gate * The LDAP server (at least Netscape 4.x) can return 1556*0Sstevel@tonic-gate * LDAP_INSUFFICIENT_ACCESS when VLV is supported, 1557*0Sstevel@tonic-gate * but not for the bind DN specified. So, just in 1558*0Sstevel@tonic-gate * case, we clean up, and try again without VLV. 1559*0Sstevel@tonic-gate */ 1560*0Sstevel@tonic-gate doVLV = 0; 1561*0Sstevel@tonic-gate if (msg != 0) { 1562*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 1563*0Sstevel@tonic-gate msg = 0; 1564*0Sstevel@tonic-gate } 1565*0Sstevel@tonic-gate if (ctrls[0] != 0) { 1566*0Sstevel@tonic-gate ldap_control_free(ctrls[0]); 1567*0Sstevel@tonic-gate ctrls[0] = 0; 1568*0Sstevel@tonic-gate } 1569*0Sstevel@tonic-gate if (ctrls[1] != 0) { 1570*0Sstevel@tonic-gate ldap_control_free(ctrls[1]); 1571*0Sstevel@tonic-gate ctrls[1] = 0; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING, 1574*0Sstevel@tonic-gate "%s: VLV insufficient access from server %s; retrying without VLV", 1575*0Sstevel@tonic-gate myself, NIL(lc->sp)); 1576*0Sstevel@tonic-gate goto retry_noVLV; 1577*0Sstevel@tonic-gate } else if (*ldapStat != LDAP_SUCCESS) { 1578*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1579*0Sstevel@tonic-gate "ldap_search(0x%x,\n\t\"%s\",\n\t %d,", 1580*0Sstevel@tonic-gate lc->ld, NIL(ls->base), ls->scope); 1581*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1582*0Sstevel@tonic-gate "\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)", 1583*0Sstevel@tonic-gate NIL(ls->filter), ls->attrs, ls->attrsonly, 1584*0Sstevel@tonic-gate *ldapStat, ldap_err2string(stat)); 1585*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1586*0Sstevel@tonic-gate rv = 0; 1587*0Sstevel@tonic-gate goto cleanup; 1588*0Sstevel@tonic-gate } 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate numEntries = ldap_count_entries(lc->ld, msg); 1591*0Sstevel@tonic-gate if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) { 1592*0Sstevel@tonic-gate /* 1593*0Sstevel@tonic-gate * This is a bit weird, but the server (or, at least, 1594*0Sstevel@tonic-gate * ldap_search_ext()) can sometimes return 1595*0Sstevel@tonic-gate * LDAP_SUCCESS and no entries when it didn't 1596*0Sstevel@tonic-gate * find what we were looking for. Seems it ought to 1597*0Sstevel@tonic-gate * return LDAP_NO_SUCH_OBJECT or some such. 1598*0Sstevel@tonic-gate */ 1599*0Sstevel@tonic-gate freeRuleValue(rv, numVals); 1600*0Sstevel@tonic-gate rv = 0; 1601*0Sstevel@tonic-gate *ldapStat = LDAP_NO_SUCH_OBJECT; 1602*0Sstevel@tonic-gate goto cleanup; 1603*0Sstevel@tonic-gate } 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate tnv = numVals + numEntries; 1606*0Sstevel@tonic-gate if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) { 1607*0Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 1608*0Sstevel@tonic-gate goto cleanup; 1609*0Sstevel@tonic-gate } 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate for (m = ldap_first_entry(lc->ld, msg); m != 0; 1612*0Sstevel@tonic-gate m = ldap_next_entry(lc->ld, m), numVals++) { 1613*0Sstevel@tonic-gate char *nm; 1614*0Sstevel@tonic-gate BerElement *ber = 0; 1615*0Sstevel@tonic-gate 1616*0Sstevel@tonic-gate if (numVals > tnv) { 1617*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 1618*0Sstevel@tonic-gate "%s: Inconsistent LDAP entry count > %d", 1619*0Sstevel@tonic-gate myself, numEntries); 1620*0Sstevel@tonic-gate break; 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate nm = ldap_get_dn(lc->ld, m); 1624*0Sstevel@tonic-gate if (nm == 0 || addSAttr2RuleValue("dn", nm, 1625*0Sstevel@tonic-gate &rv[numVals])) { 1626*0Sstevel@tonic-gate sfree(nm); 1627*0Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 1628*0Sstevel@tonic-gate freeRuleValue(rv, tnv); 1629*0Sstevel@tonic-gate rv = 0; 1630*0Sstevel@tonic-gate goto cleanup; 1631*0Sstevel@tonic-gate } 1632*0Sstevel@tonic-gate sfree(nm); 1633*0Sstevel@tonic-gate 1634*0Sstevel@tonic-gate for (nm = ldap_first_attribute(lc->ld, m, &ber); 1635*0Sstevel@tonic-gate nm != 0; 1636*0Sstevel@tonic-gate nm = ldap_next_attribute(lc->ld, m, ber)) { 1637*0Sstevel@tonic-gate struct berval **val; 1638*0Sstevel@tonic-gate int i, nv; 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate val = ldap_get_values_len(lc->ld, m, nm); 1641*0Sstevel@tonic-gate nv = (val == 0) ? 0 : 1642*0Sstevel@tonic-gate ldap_count_values_len(val); 1643*0Sstevel@tonic-gate for (i = 0; i < nv; i++) { 1644*0Sstevel@tonic-gate /* 1645*0Sstevel@tonic-gate * Since we don't know if the value is 1646*0Sstevel@tonic-gate * BER-encoded or not, we mark it as a 1647*0Sstevel@tonic-gate * string. All is well as long as we 1648*0Sstevel@tonic-gate * don't insist on 'vt_ber' when 1649*0Sstevel@tonic-gate * interpreting. 1650*0Sstevel@tonic-gate */ 1651*0Sstevel@tonic-gate if (addAttr2RuleValue(vt_string, nm, 1652*0Sstevel@tonic-gate val[i]->bv_val, 1653*0Sstevel@tonic-gate val[i]->bv_len, 1654*0Sstevel@tonic-gate &rv[numVals])) { 1655*0Sstevel@tonic-gate if (ber != 0) 1656*0Sstevel@tonic-gate ber_free(ber, 0); 1657*0Sstevel@tonic-gate ldap_value_free_len(val); 1658*0Sstevel@tonic-gate *ldapStat = LDAP_NO_MEMORY; 1659*0Sstevel@tonic-gate freeRuleValue(rv, tnv); 1660*0Sstevel@tonic-gate rv = 0; 1661*0Sstevel@tonic-gate goto cleanup; 1662*0Sstevel@tonic-gate } 1663*0Sstevel@tonic-gate } 1664*0Sstevel@tonic-gate /* 1665*0Sstevel@tonic-gate * XXX the ldap_first_attribute(3LDAP) man 1666*0Sstevel@tonic-gate * page says that the ldap_first_attribute/ 1667*0Sstevel@tonic-gate * ldap_next_attribute should be treated as 1668*0Sstevel@tonic-gate * static, but the libldap.so.4 code mallocs 1669*0Sstevel@tonic-gate * (and it's not TSD). So, in order to avoid 1670*0Sstevel@tonic-gate * a leak, we free the return value. 1671*0Sstevel@tonic-gate */ 1672*0Sstevel@tonic-gate ldap_memfree(nm); 1673*0Sstevel@tonic-gate if (val != 0) 1674*0Sstevel@tonic-gate ldap_value_free_len(val); 1675*0Sstevel@tonic-gate } 1676*0Sstevel@tonic-gate /* 1677*0Sstevel@tonic-gate * XXX ldap_next_attribute(3LDAP) says that the 'ber' 1678*0Sstevel@tonic-gate * pointer is freed when it returns NULL, but that's 1679*0Sstevel@tonic-gate * not implemented in the libldap.so.4 code, so we 1680*0Sstevel@tonic-gate * free it here in order to avoid a memory leak. 1681*0Sstevel@tonic-gate */ 1682*0Sstevel@tonic-gate if (ber != 0) 1683*0Sstevel@tonic-gate ber_free(ber, 0); 1684*0Sstevel@tonic-gate } 1685*0Sstevel@tonic-gate 1686*0Sstevel@tonic-gate if (numVals != tnv) { 1687*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 1688*0Sstevel@tonic-gate "%s: Inconsistent LDAP entry count, found = %d, expected %d", 1689*0Sstevel@tonic-gate myself, numVals, tnv); 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate if (doVLV) { 1693*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 1694*0Sstevel@tonic-gate &retCtrls, 0); 1695*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 1696*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 1697*0Sstevel@tonic-gate &stat); 1698*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1699*0Sstevel@tonic-gate "%s: VLV parse result error: %s", 1700*0Sstevel@tonic-gate myself, ldap_err2string(stat)); 1701*0Sstevel@tonic-gate *ldapStat = stat; 1702*0Sstevel@tonic-gate freeRuleValue(rv, tnv); 1703*0Sstevel@tonic-gate rv = 0; 1704*0Sstevel@tonic-gate goto cleanup; 1705*0Sstevel@tonic-gate } 1706*0Sstevel@tonic-gate if (retCtrls != 0) { 1707*0Sstevel@tonic-gate unsigned long targetPosP = 0; 1708*0Sstevel@tonic-gate unsigned long listSize = 0; 1709*0Sstevel@tonic-gate 1710*0Sstevel@tonic-gate stat = ldap_parse_virtuallist_control(lc->ld, 1711*0Sstevel@tonic-gate retCtrls, &targetPosP, &listSize, 1712*0Sstevel@tonic-gate &lprEc); 1713*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 1714*0Sstevel@tonic-gate index = targetPosP + lc->batchFrom; 1715*0Sstevel@tonic-gate if (index >= listSize) 1716*0Sstevel@tonic-gate done = 1; 1717*0Sstevel@tonic-gate } 1718*0Sstevel@tonic-gate ldap_controls_free(retCtrls); 1719*0Sstevel@tonic-gate retCtrls = 0; 1720*0Sstevel@tonic-gate } else { 1721*0Sstevel@tonic-gate done = 1; 1722*0Sstevel@tonic-gate } 1723*0Sstevel@tonic-gate } else if (doSP) { 1724*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0, 1725*0Sstevel@tonic-gate &retCtrls, 0); 1726*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 1727*0Sstevel@tonic-gate ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 1728*0Sstevel@tonic-gate &stat); 1729*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 1730*0Sstevel@tonic-gate "%s: Simple page parse result error: %s", 1731*0Sstevel@tonic-gate myself, ldap_err2string(stat)); 1732*0Sstevel@tonic-gate *ldapStat = stat; 1733*0Sstevel@tonic-gate freeRuleValue(rv, tnv); 1734*0Sstevel@tonic-gate rv = 0; 1735*0Sstevel@tonic-gate goto cleanup; 1736*0Sstevel@tonic-gate } 1737*0Sstevel@tonic-gate if (retCtrls != 0) { 1738*0Sstevel@tonic-gate unsigned int count; 1739*0Sstevel@tonic-gate 1740*0Sstevel@tonic-gate if (spCookie != 0) { 1741*0Sstevel@tonic-gate ber_bvfree(spCookie); 1742*0Sstevel@tonic-gate spCookie = 0; 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate stat = ldap_parse_page_control(lc->ld, 1745*0Sstevel@tonic-gate retCtrls, &count, &spCookie); 1746*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) { 1747*0Sstevel@tonic-gate if (spCookie == 0 || 1748*0Sstevel@tonic-gate spCookie->bv_val == 0 || 1749*0Sstevel@tonic-gate spCookie->bv_len == 0) 1750*0Sstevel@tonic-gate done = 1; 1751*0Sstevel@tonic-gate } 1752*0Sstevel@tonic-gate ldap_controls_free(retCtrls); 1753*0Sstevel@tonic-gate retCtrls = 0; 1754*0Sstevel@tonic-gate } else { 1755*0Sstevel@tonic-gate done = 1; 1756*0Sstevel@tonic-gate } 1757*0Sstevel@tonic-gate } else { 1758*0Sstevel@tonic-gate done = 1; 1759*0Sstevel@tonic-gate } 1760*0Sstevel@tonic-gate 1761*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 1762*0Sstevel@tonic-gate msg = 0; 1763*0Sstevel@tonic-gate 1764*0Sstevel@tonic-gate /* 1765*0Sstevel@tonic-gate * If we're using VLV or SP, the timeout should apply 1766*0Sstevel@tonic-gate * to all calls as an aggregate, so we need to reduce 1767*0Sstevel@tonic-gate * 'tv' with the time spent on this chunk of data. 1768*0Sstevel@tonic-gate */ 1769*0Sstevel@tonic-gate if (!done) { 1770*0Sstevel@tonic-gate struct timeval tmp; 1771*0Sstevel@tonic-gate 1772*0Sstevel@tonic-gate (void) gettimeofday(&now, 0); 1773*0Sstevel@tonic-gate tmp = now; 1774*0Sstevel@tonic-gate now.tv_sec -= start.tv_sec; 1775*0Sstevel@tonic-gate now.tv_usec -= start.tv_usec; 1776*0Sstevel@tonic-gate if (now.tv_usec < 0) { 1777*0Sstevel@tonic-gate now.tv_usec += 1000000; 1778*0Sstevel@tonic-gate now.tv_sec -= 1; 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate tv.tv_sec -= now.tv_sec; 1781*0Sstevel@tonic-gate tv.tv_usec -= now.tv_usec; 1782*0Sstevel@tonic-gate if (tv.tv_usec < 0) { 1783*0Sstevel@tonic-gate tv.tv_usec += 1000000; 1784*0Sstevel@tonic-gate tv.tv_sec -= 1; 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate if (tv.tv_sec < 0) { 1787*0Sstevel@tonic-gate *ldapStat = LDAP_TIMEOUT; 1788*0Sstevel@tonic-gate freeRuleValue(rv, tnv); 1789*0Sstevel@tonic-gate rv = 0; 1790*0Sstevel@tonic-gate goto cleanup; 1791*0Sstevel@tonic-gate } 1792*0Sstevel@tonic-gate start = tmp; 1793*0Sstevel@tonic-gate } 1794*0Sstevel@tonic-gate 1795*0Sstevel@tonic-gate } while (!done); 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate if (numValues != 0) 1798*0Sstevel@tonic-gate *numValues = numVals; 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate cleanup: 1801*0Sstevel@tonic-gate if (NULL != lc) { 1802*0Sstevel@tonic-gate if (yp2ldap && ls->useCon == 0) { 1803*0Sstevel@tonic-gate /* Disconnect and free the connection */ 1804*0Sstevel@tonic-gate lc->doDis++; 1805*0Sstevel@tonic-gate lc->doDel++; 1806*0Sstevel@tonic-gate releaseCon(lc, stat); 1807*0Sstevel@tonic-gate releaseLC(lc); 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate } else { 1810*0Sstevel@tonic-gate releaseCon(lc, stat); 1811*0Sstevel@tonic-gate } 1812*0Sstevel@tonic-gate } 1813*0Sstevel@tonic-gate if (msg != 0) 1814*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 1815*0Sstevel@tonic-gate if (ctrls[0] != 0) 1816*0Sstevel@tonic-gate ldap_control_free(ctrls[0]); 1817*0Sstevel@tonic-gate if (ctrls[1] != 0) 1818*0Sstevel@tonic-gate ldap_control_free(ctrls[1]); 1819*0Sstevel@tonic-gate if (spCookie != 0) 1820*0Sstevel@tonic-gate ber_bvfree(spCookie); 1821*0Sstevel@tonic-gate if (sortKeyList != 0) 1822*0Sstevel@tonic-gate ldap_free_sort_keylist(sortKeyList); 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate return (rv); 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate static void 1828*0Sstevel@tonic-gate freeLdapModEntry(LDAPMod *m) { 1829*0Sstevel@tonic-gate 1830*0Sstevel@tonic-gate if (m == 0) 1831*0Sstevel@tonic-gate return; 1832*0Sstevel@tonic-gate 1833*0Sstevel@tonic-gate sfree(m->mod_type); 1834*0Sstevel@tonic-gate if ((m->mod_op & LDAP_MOD_BVALUES) == 0) { 1835*0Sstevel@tonic-gate char **v = m->mod_values; 1836*0Sstevel@tonic-gate 1837*0Sstevel@tonic-gate if (v != 0) { 1838*0Sstevel@tonic-gate while (*v != 0) { 1839*0Sstevel@tonic-gate sfree(*v); 1840*0Sstevel@tonic-gate v++; 1841*0Sstevel@tonic-gate } 1842*0Sstevel@tonic-gate free(m->mod_values); 1843*0Sstevel@tonic-gate } 1844*0Sstevel@tonic-gate } else { 1845*0Sstevel@tonic-gate struct berval **b = m->mod_bvalues; 1846*0Sstevel@tonic-gate 1847*0Sstevel@tonic-gate if (b != 0) { 1848*0Sstevel@tonic-gate while (*b != 0) { 1849*0Sstevel@tonic-gate sfree((*b)->bv_val); 1850*0Sstevel@tonic-gate free(*b); 1851*0Sstevel@tonic-gate b++; 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate free(m->mod_bvalues); 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate free(m); 1858*0Sstevel@tonic-gate } 1859*0Sstevel@tonic-gate 1860*0Sstevel@tonic-gate static void 1861*0Sstevel@tonic-gate freeLdapMod(LDAPMod **mods) { 1862*0Sstevel@tonic-gate LDAPMod *m, **org = mods; 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate if (mods == 0) 1865*0Sstevel@tonic-gate return; 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate while ((m = *mods) != 0) { 1868*0Sstevel@tonic-gate freeLdapModEntry(m); 1869*0Sstevel@tonic-gate mods++; 1870*0Sstevel@tonic-gate } 1871*0Sstevel@tonic-gate 1872*0Sstevel@tonic-gate free(org); 1873*0Sstevel@tonic-gate } 1874*0Sstevel@tonic-gate 1875*0Sstevel@tonic-gate /* 1876*0Sstevel@tonic-gate * Convert a rule-value structure to the corresponding LDAPMod. 1877*0Sstevel@tonic-gate * If 'add' is set, attributes/values are added; object classes 1878*0Sstevel@tonic-gate * are also added. If 'add' is cleared, attributes/values are modified, 1879*0Sstevel@tonic-gate * and 'oc' controls whether or not object classes are added. 1880*0Sstevel@tonic-gate */ 1881*0Sstevel@tonic-gate LDAPMod ** 1882*0Sstevel@tonic-gate search2LdapMod(__nis_rule_value_t *rv, int add, int oc) { 1883*0Sstevel@tonic-gate LDAPMod **mods; 1884*0Sstevel@tonic-gate int i, j, nm; 1885*0Sstevel@tonic-gate char *myself = "search2LdapMod"; 1886*0Sstevel@tonic-gate 1887*0Sstevel@tonic-gate if (rv == 0 || rv->numAttrs <= 0) 1888*0Sstevel@tonic-gate return (0); 1889*0Sstevel@tonic-gate 1890*0Sstevel@tonic-gate mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0])); 1891*0Sstevel@tonic-gate if (mods == 0) 1892*0Sstevel@tonic-gate return (0); 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate for (i = 0, nm = 0; i < rv->numAttrs; i++) { 1895*0Sstevel@tonic-gate int isOc; 1896*0Sstevel@tonic-gate /* 1897*0Sstevel@tonic-gate * If we're creating an LDAPMod array for an add operation, 1898*0Sstevel@tonic-gate * just skip attributes that should be deleted. 1899*0Sstevel@tonic-gate */ 1900*0Sstevel@tonic-gate if (add && rv->attrVal[i].numVals < 0) 1901*0Sstevel@tonic-gate continue; 1902*0Sstevel@tonic-gate 1903*0Sstevel@tonic-gate /* 1904*0Sstevel@tonic-gate * Skip DN; it's specified separately to ldap_modify() 1905*0Sstevel@tonic-gate * and ldap_add(), and mustn't appear among the 1906*0Sstevel@tonic-gate * attributes to be modified/added. 1907*0Sstevel@tonic-gate */ 1908*0Sstevel@tonic-gate if (strcasecmp("dn", rv->attrName[i]) == 0) 1909*0Sstevel@tonic-gate continue; 1910*0Sstevel@tonic-gate 1911*0Sstevel@tonic-gate /* 1912*0Sstevel@tonic-gate * If modifying, and 'oc' is off, skip object class 1913*0Sstevel@tonic-gate * attributes. 1914*0Sstevel@tonic-gate */ 1915*0Sstevel@tonic-gate isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0); 1916*0Sstevel@tonic-gate if (!add && !oc && isOc) 1917*0Sstevel@tonic-gate continue; 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate mods[nm] = am(myself, sizeof (*mods[nm])); 1920*0Sstevel@tonic-gate if (mods[nm] == 0) { 1921*0Sstevel@tonic-gate freeLdapMod(mods); 1922*0Sstevel@tonic-gate return (0); 1923*0Sstevel@tonic-gate } 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate /* 'mod_type' is the attribute name */ 1926*0Sstevel@tonic-gate mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]); 1927*0Sstevel@tonic-gate if (mods[nm]->mod_type == 0) { 1928*0Sstevel@tonic-gate freeLdapMod(mods); 1929*0Sstevel@tonic-gate return (0); 1930*0Sstevel@tonic-gate } 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate /* 1933*0Sstevel@tonic-gate * numVals < 0 means attribute and all values should 1934*0Sstevel@tonic-gate * be deleted. 1935*0Sstevel@tonic-gate */ 1936*0Sstevel@tonic-gate if (rv->attrVal[i].numVals < 0) { 1937*0Sstevel@tonic-gate mods[nm]->mod_op = LDAP_MOD_DELETE; 1938*0Sstevel@tonic-gate mods[nm]->mod_values = 0; 1939*0Sstevel@tonic-gate nm++; 1940*0Sstevel@tonic-gate continue; 1941*0Sstevel@tonic-gate } 1942*0Sstevel@tonic-gate 1943*0Sstevel@tonic-gate /* objectClass attributes always added */ 1944*0Sstevel@tonic-gate mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE); 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate if (rv->attrVal[i].type == vt_string) { 1947*0Sstevel@tonic-gate /* 1948*0Sstevel@tonic-gate * mods[]->mod_values is a NULL-terminated array 1949*0Sstevel@tonic-gate * of (char *)'s. 1950*0Sstevel@tonic-gate */ 1951*0Sstevel@tonic-gate mods[nm]->mod_values = am(myself, 1952*0Sstevel@tonic-gate (rv->attrVal[i].numVals + 1) * 1953*0Sstevel@tonic-gate sizeof (mods[nm]->mod_values[0])); 1954*0Sstevel@tonic-gate if (mods[nm]->mod_values == 0) { 1955*0Sstevel@tonic-gate freeLdapMod(mods); 1956*0Sstevel@tonic-gate return (0); 1957*0Sstevel@tonic-gate } 1958*0Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 1959*0Sstevel@tonic-gate /* 1960*0Sstevel@tonic-gate * Just in case the string isn't NUL 1961*0Sstevel@tonic-gate * terminated, add one byte to the 1962*0Sstevel@tonic-gate * allocated length; am() will initialize 1963*0Sstevel@tonic-gate * the buffer to zero. 1964*0Sstevel@tonic-gate */ 1965*0Sstevel@tonic-gate mods[nm]->mod_values[j] = am(myself, 1966*0Sstevel@tonic-gate rv->attrVal[i].val[j].length + 1); 1967*0Sstevel@tonic-gate if (mods[nm]->mod_values[j] == 0) { 1968*0Sstevel@tonic-gate freeLdapMod(mods); 1969*0Sstevel@tonic-gate return (0); 1970*0Sstevel@tonic-gate } 1971*0Sstevel@tonic-gate memcpy(mods[nm]->mod_values[j], 1972*0Sstevel@tonic-gate rv->attrVal[i].val[j].value, 1973*0Sstevel@tonic-gate rv->attrVal[i].val[j].length); 1974*0Sstevel@tonic-gate } 1975*0Sstevel@tonic-gate } else { 1976*0Sstevel@tonic-gate mods[nm]->mod_op |= LDAP_MOD_BVALUES; 1977*0Sstevel@tonic-gate mods[nm]->mod_bvalues = am(myself, 1978*0Sstevel@tonic-gate (rv->attrVal[i].numVals+1) * 1979*0Sstevel@tonic-gate sizeof (mods[nm]->mod_bvalues[0])); 1980*0Sstevel@tonic-gate if (mods[nm]->mod_bvalues == 0) { 1981*0Sstevel@tonic-gate freeLdapMod(mods); 1982*0Sstevel@tonic-gate return (0); 1983*0Sstevel@tonic-gate } 1984*0Sstevel@tonic-gate for (j = 0; j < rv->attrVal[i].numVals; j++) { 1985*0Sstevel@tonic-gate mods[nm]->mod_bvalues[j] = am(myself, 1986*0Sstevel@tonic-gate sizeof (*mods[nm]->mod_bvalues[j])); 1987*0Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j] == 0) { 1988*0Sstevel@tonic-gate freeLdapMod(mods); 1989*0Sstevel@tonic-gate return (0); 1990*0Sstevel@tonic-gate } 1991*0Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_val = am(myself, 1992*0Sstevel@tonic-gate rv->attrVal[i].val[j].length); 1993*0Sstevel@tonic-gate if (mods[nm]->mod_bvalues[j]->bv_val == 0) { 1994*0Sstevel@tonic-gate freeLdapMod(mods); 1995*0Sstevel@tonic-gate return (0); 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len = 1998*0Sstevel@tonic-gate rv->attrVal[i].val[j].length; 1999*0Sstevel@tonic-gate memcpy(mods[nm]->mod_bvalues[j]->bv_val, 2000*0Sstevel@tonic-gate rv->attrVal[i].val[j].value, 2001*0Sstevel@tonic-gate mods[nm]->mod_bvalues[j]->bv_len); 2002*0Sstevel@tonic-gate } 2003*0Sstevel@tonic-gate } 2004*0Sstevel@tonic-gate nm++; 2005*0Sstevel@tonic-gate } 2006*0Sstevel@tonic-gate 2007*0Sstevel@tonic-gate return (mods); 2008*0Sstevel@tonic-gate } 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate /* 2011*0Sstevel@tonic-gate * Remove 'value' from 'val'. If value==0, remove the entire 2012*0Sstevel@tonic-gate * __nis_single_value_t array from 'val'. 2013*0Sstevel@tonic-gate */ 2014*0Sstevel@tonic-gate static void 2015*0Sstevel@tonic-gate removeSingleValue(__nis_value_t *val, void *value, int length) { 2016*0Sstevel@tonic-gate int i; 2017*0Sstevel@tonic-gate 2018*0Sstevel@tonic-gate if (val == 0) 2019*0Sstevel@tonic-gate return; 2020*0Sstevel@tonic-gate 2021*0Sstevel@tonic-gate if (value == 0) { 2022*0Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 2023*0Sstevel@tonic-gate sfree(val->val[i].value); 2024*0Sstevel@tonic-gate } 2025*0Sstevel@tonic-gate sfree(val->val); 2026*0Sstevel@tonic-gate val->val = 0; 2027*0Sstevel@tonic-gate val->numVals = 0; 2028*0Sstevel@tonic-gate return; 2029*0Sstevel@tonic-gate } 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate for (i = 0; i < val->numVals; i++) { 2032*0Sstevel@tonic-gate if (val->val[i].value == 0 || (val->val[i].length != length)) 2033*0Sstevel@tonic-gate continue; 2034*0Sstevel@tonic-gate if (memcmp(val->val[i].value, value, length) != 0) 2035*0Sstevel@tonic-gate continue; 2036*0Sstevel@tonic-gate sfree(val->val[i].value); 2037*0Sstevel@tonic-gate if (i != (val->numVals - 1)) { 2038*0Sstevel@tonic-gate (void) memmove(&val->val[i], &val->val[i+1], 2039*0Sstevel@tonic-gate (val->numVals - 1 - i) * sizeof (val->val[0])); 2040*0Sstevel@tonic-gate } 2041*0Sstevel@tonic-gate val->numVals -= 1; 2042*0Sstevel@tonic-gate break; 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate } 2045*0Sstevel@tonic-gate 2046*0Sstevel@tonic-gate /* 2047*0Sstevel@tonic-gate * Helper function for LdapModify 2048*0Sstevel@tonic-gate * When a modify operation fails with an object class violation, 2049*0Sstevel@tonic-gate * the most probable reason is that the attributes we're modifying are new, 2050*0Sstevel@tonic-gate * and the needed object class are not present. So, try the modify again, 2051*0Sstevel@tonic-gate * but add the object classes this time. 2052*0Sstevel@tonic-gate */ 2053*0Sstevel@tonic-gate 2054*0Sstevel@tonic-gate static int 2055*0Sstevel@tonic-gate ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn, 2056*0Sstevel@tonic-gate __nis_rule_value_t *rvIn, char *objClassAttrs) 2057*0Sstevel@tonic-gate { 2058*0Sstevel@tonic-gate LDAPMod **mods = 0; 2059*0Sstevel@tonic-gate int msgid; 2060*0Sstevel@tonic-gate int lderr; 2061*0Sstevel@tonic-gate struct timeval tv; 2062*0Sstevel@tonic-gate int stat; 2063*0Sstevel@tonic-gate LDAPMessage *msg = 0; 2064*0Sstevel@tonic-gate char **referralsp = NULL; 2065*0Sstevel@tonic-gate __nis_rule_value_t *rv, *rvldap; 2066*0Sstevel@tonic-gate __nis_ldap_search_t *ls; 2067*0Sstevel@tonic-gate int i, ocrv, ocrvldap, nv; 2068*0Sstevel@tonic-gate char *oc[2] = { "objectClass", 0}; 2069*0Sstevel@tonic-gate char *myself = "ldapModifyObjectClass"; 2070*0Sstevel@tonic-gate 2071*0Sstevel@tonic-gate rv = initRuleValue(1, rvIn); 2072*0Sstevel@tonic-gate if (rv == 0) 2073*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 2076*0Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 2077*0Sstevel@tonic-gate if (rv == 0) { 2078*0Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 2079*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2080*0Sstevel@tonic-gate "%s: addObjectClasses failed for %s", 2081*0Sstevel@tonic-gate myself, NIL(dn)); 2082*0Sstevel@tonic-gate goto cleanup; 2083*0Sstevel@tonic-gate } 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate /* 2086*0Sstevel@tonic-gate * Before adding the object classes whole-sale, try retrieving 2087*0Sstevel@tonic-gate * the entry specified by the 'dn'. If it exists, we filter out 2088*0Sstevel@tonic-gate * those object classes that already are present in LDAP from our 2089*0Sstevel@tonic-gate * update. 2090*0Sstevel@tonic-gate */ 2091*0Sstevel@tonic-gate ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*", 2092*0Sstevel@tonic-gate oc, 0, 1); 2093*0Sstevel@tonic-gate if (ls == 0) { 2094*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2095*0Sstevel@tonic-gate "%s: Unable to build DN search for \"%s\"", 2096*0Sstevel@tonic-gate myself, NIL(dn)); 2097*0Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 2098*0Sstevel@tonic-gate goto addObjectClasses; 2099*0Sstevel@tonic-gate } 2100*0Sstevel@tonic-gate 2101*0Sstevel@tonic-gate nv = 0; 2102*0Sstevel@tonic-gate rvldap = ldapSearch(ls, &nv, 0, &lderr); 2103*0Sstevel@tonic-gate freeLdapSearch(ls); 2104*0Sstevel@tonic-gate if (rvldap == 0) { 2105*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2106*0Sstevel@tonic-gate "%s: No data for DN search (\"%s\"); LDAP status %d", 2107*0Sstevel@tonic-gate myself, NIL(dn), lderr); 2108*0Sstevel@tonic-gate /* Fall through to try just adding the object classes */ 2109*0Sstevel@tonic-gate goto addObjectClasses; 2110*0Sstevel@tonic-gate } 2111*0Sstevel@tonic-gate 2112*0Sstevel@tonic-gate /* 2113*0Sstevel@tonic-gate * Find the indices of the 'objectClass' attribute 2114*0Sstevel@tonic-gate * in 'rvldap' and 'rv'. 2115*0Sstevel@tonic-gate */ 2116*0Sstevel@tonic-gate for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) { 2117*0Sstevel@tonic-gate if (rvldap->attrName[i] != 0 && 2118*0Sstevel@tonic-gate strcasecmp("objectClass", rvldap->attrName[i]) == 0) { 2119*0Sstevel@tonic-gate ocrvldap = i; 2120*0Sstevel@tonic-gate break; 2121*0Sstevel@tonic-gate } 2122*0Sstevel@tonic-gate } 2123*0Sstevel@tonic-gate for (i = 0, ocrv = -1; i < rv->numAttrs; i++) { 2124*0Sstevel@tonic-gate if (rv->attrName[i] != 0 && 2125*0Sstevel@tonic-gate strcasecmp("objectClass", rv->attrName[i]) == 0) { 2126*0Sstevel@tonic-gate ocrv = i; 2127*0Sstevel@tonic-gate break; 2128*0Sstevel@tonic-gate } 2129*0Sstevel@tonic-gate } 2130*0Sstevel@tonic-gate 2131*0Sstevel@tonic-gate /* 2132*0Sstevel@tonic-gate * Remove those object classes that already exist 2133*0Sstevel@tonic-gate * in LDAP (i.e., in 'rvldap') from 'rv'. 2134*0Sstevel@tonic-gate */ 2135*0Sstevel@tonic-gate if (ocrv >= 0 && ocrvldap >= 0) { 2136*0Sstevel@tonic-gate for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) { 2137*0Sstevel@tonic-gate removeSingleValue(&rv->attrVal[ocrv], 2138*0Sstevel@tonic-gate rvldap->attrVal[ocrvldap].val[i].value, 2139*0Sstevel@tonic-gate rvldap->attrVal[ocrvldap].val[i].length); 2140*0Sstevel@tonic-gate } 2141*0Sstevel@tonic-gate /* 2142*0Sstevel@tonic-gate * If no 'objectClass' values left in 'rv', delete 2143*0Sstevel@tonic-gate * 'objectClass' from 'rv'. 2144*0Sstevel@tonic-gate */ 2145*0Sstevel@tonic-gate if (rv->attrVal[ocrv].numVals == 0) 2146*0Sstevel@tonic-gate delAttrFromRuleValue(rv, "objectClass"); 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate /* 2150*0Sstevel@tonic-gate * 'rv' now contains the update we want to make, with just the 2151*0Sstevel@tonic-gate * object class(es) that need to be added. Fall through to the 2152*0Sstevel@tonic-gate * actual LDAP modify operation. 2153*0Sstevel@tonic-gate */ 2154*0Sstevel@tonic-gate freeRuleValue(rvldap, 1); 2155*0Sstevel@tonic-gate 2156*0Sstevel@tonic-gate addObjectClasses: 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 1); 2159*0Sstevel@tonic-gate if (mods == 0) { 2160*0Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 2161*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2162*0Sstevel@tonic-gate "%s: Unable to create LDAP modify changes with object classes for %s", 2163*0Sstevel@tonic-gate myself, NIL(dn)); 2164*0Sstevel@tonic-gate goto cleanup; 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 2167*0Sstevel@tonic-gate if (msgid != -1) { 2168*0Sstevel@tonic-gate tv = (*lc)->modifyTimeout; 2169*0Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 2170*0Sstevel@tonic-gate if (stat == 0) { 2171*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2172*0Sstevel@tonic-gate } else if (stat == -1) { 2173*0Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2174*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2175*0Sstevel@tonic-gate } else { 2176*0Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL, 2177*0Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 2178*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2179*0Sstevel@tonic-gate stat = lderr; 2180*0Sstevel@tonic-gate stat = ldap_result2error((*lc)->ld, msg, 0); 2181*0Sstevel@tonic-gate } 2182*0Sstevel@tonic-gate } else { 2183*0Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER, 2184*0Sstevel@tonic-gate &stat); 2185*0Sstevel@tonic-gate } 2186*0Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 2187*0Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 2188*0Sstevel@tonic-gate releaseCon(*lc, stat); 2189*0Sstevel@tonic-gate if (msg != NULL) 2190*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2191*0Sstevel@tonic-gate msg = NULL; 2192*0Sstevel@tonic-gate *lc = findReferralCon(referralsp, &stat); 2193*0Sstevel@tonic-gate ldap_value_free(referralsp); 2194*0Sstevel@tonic-gate referralsp = NULL; 2195*0Sstevel@tonic-gate if (*lc == NULL) 2196*0Sstevel@tonic-gate goto cleanup; 2197*0Sstevel@tonic-gate msgid = ldap_modify((*lc)->ld, dn, mods); 2198*0Sstevel@tonic-gate if (msgid == -1) { 2199*0Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2200*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2201*0Sstevel@tonic-gate goto cleanup; 2202*0Sstevel@tonic-gate } 2203*0Sstevel@tonic-gate stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg); 2204*0Sstevel@tonic-gate if (stat == 0) { 2205*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2206*0Sstevel@tonic-gate } else if (stat == -1) { 2207*0Sstevel@tonic-gate (void) ldap_get_option((*lc)->ld, 2208*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2209*0Sstevel@tonic-gate } else { 2210*0Sstevel@tonic-gate stat = ldap_parse_result((*lc)->ld, msg, &lderr, 2211*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 2212*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2213*0Sstevel@tonic-gate stat = lderr; 2214*0Sstevel@tonic-gate } 2215*0Sstevel@tonic-gate } 2216*0Sstevel@tonic-gate cleanup: 2217*0Sstevel@tonic-gate if (mods != 0) 2218*0Sstevel@tonic-gate freeLdapMod(mods); 2219*0Sstevel@tonic-gate freeRuleValue(rv, 1); 2220*0Sstevel@tonic-gate return (stat); 2221*0Sstevel@tonic-gate } 2222*0Sstevel@tonic-gate 2223*0Sstevel@tonic-gate /* 2224*0Sstevel@tonic-gate * Modify the specified 'dn' per the attribute names/values in 'rv'. 2225*0Sstevel@tonic-gate * If 'rv' is NULL, we attempt to delete the entire entry. 2226*0Sstevel@tonic-gate * 2227*0Sstevel@tonic-gate * The 'objClassAttrs' parameter is needed if the entry must be added 2228*0Sstevel@tonic-gate * (i.e., created), or a modify fails with an object class violation. 2229*0Sstevel@tonic-gate * 2230*0Sstevel@tonic-gate * If 'addFirst' is set, we try an add before a modify; modify before 2231*0Sstevel@tonic-gate * add otherwise (ignored if we're deleting). 2232*0Sstevel@tonic-gate */ 2233*0Sstevel@tonic-gate int 2234*0Sstevel@tonic-gate ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, 2235*0Sstevel@tonic-gate int addFirst) { 2236*0Sstevel@tonic-gate int stat, add = 0; 2237*0Sstevel@tonic-gate LDAPMod **mods = 0; 2238*0Sstevel@tonic-gate __nis_ldap_conn_t *lc; 2239*0Sstevel@tonic-gate struct timeval tv; 2240*0Sstevel@tonic-gate LDAPMessage *msg = 0; 2241*0Sstevel@tonic-gate char *myself = "ldapModify"; 2242*0Sstevel@tonic-gate int msgid; 2243*0Sstevel@tonic-gate int lderr; 2244*0Sstevel@tonic-gate char **referralsp = NULL; 2245*0Sstevel@tonic-gate bool_t delete = FALSE; 2246*0Sstevel@tonic-gate 2247*0Sstevel@tonic-gate if (dn == 0) 2248*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 2249*0Sstevel@tonic-gate 2250*0Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 2251*0Sstevel@tonic-gate return (stat); 2252*0Sstevel@tonic-gate 2253*0Sstevel@tonic-gate if (rv == 0) { 2254*0Sstevel@tonic-gate delete = TRUE; 2255*0Sstevel@tonic-gate /* Simple case: if rv == 0, try to delete the entire entry */ 2256*0Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 2257*0Sstevel@tonic-gate if (msgid == -1) { 2258*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2259*0Sstevel@tonic-gate &stat); 2260*0Sstevel@tonic-gate goto cleanup; 2261*0Sstevel@tonic-gate } 2262*0Sstevel@tonic-gate tv = lc->deleteTimeout; 2263*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2264*0Sstevel@tonic-gate 2265*0Sstevel@tonic-gate if (stat == 0) { 2266*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2267*0Sstevel@tonic-gate } else if (stat == -1) { 2268*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2269*0Sstevel@tonic-gate &stat); 2270*0Sstevel@tonic-gate } else { 2271*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 2272*0Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 2273*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2274*0Sstevel@tonic-gate stat = lderr; 2275*0Sstevel@tonic-gate } 2276*0Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 2277*0Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 2278*0Sstevel@tonic-gate releaseCon(lc, stat); 2279*0Sstevel@tonic-gate if (msg != NULL) 2280*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2281*0Sstevel@tonic-gate msg = NULL; 2282*0Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 2283*0Sstevel@tonic-gate ldap_value_free(referralsp); 2284*0Sstevel@tonic-gate if (lc == NULL) 2285*0Sstevel@tonic-gate goto cleanup; 2286*0Sstevel@tonic-gate msgid = ldap_delete(lc->ld, dn); 2287*0Sstevel@tonic-gate if (msgid == -1) { 2288*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2289*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2290*0Sstevel@tonic-gate goto cleanup; 2291*0Sstevel@tonic-gate } 2292*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2293*0Sstevel@tonic-gate if (stat == 0) { 2294*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2295*0Sstevel@tonic-gate } else if (stat == -1) { 2296*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2297*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2298*0Sstevel@tonic-gate } else { 2299*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 2300*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 2301*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2302*0Sstevel@tonic-gate stat = lderr; 2303*0Sstevel@tonic-gate } 2304*0Sstevel@tonic-gate } 2305*0Sstevel@tonic-gate /* No such object means someone else has done our job */ 2306*0Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) 2307*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 2308*0Sstevel@tonic-gate } else { 2309*0Sstevel@tonic-gate if (addFirst) { 2310*0Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 2311*0Sstevel@tonic-gate lc = NULL; 2312*0Sstevel@tonic-gate if (stat != LDAP_ALREADY_EXISTS) 2313*0Sstevel@tonic-gate goto cleanup; 2314*0Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 2315*0Sstevel@tonic-gate return (stat); 2316*0Sstevel@tonic-gate } 2317*0Sstevel@tonic-gate 2318*0Sstevel@tonic-gate /* 2319*0Sstevel@tonic-gate * First try the modify without specifying object classes 2320*0Sstevel@tonic-gate * (i.e., assume they're already present). 2321*0Sstevel@tonic-gate */ 2322*0Sstevel@tonic-gate mods = search2LdapMod(rv, 0, 0); 2323*0Sstevel@tonic-gate if (mods == 0) { 2324*0Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 2325*0Sstevel@tonic-gate goto cleanup; 2326*0Sstevel@tonic-gate } 2327*0Sstevel@tonic-gate 2328*0Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 2329*0Sstevel@tonic-gate if (msgid == -1) { 2330*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2331*0Sstevel@tonic-gate &stat); 2332*0Sstevel@tonic-gate goto cleanup; 2333*0Sstevel@tonic-gate } 2334*0Sstevel@tonic-gate tv = lc->modifyTimeout; 2335*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2336*0Sstevel@tonic-gate if (stat == 0) { 2337*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2338*0Sstevel@tonic-gate } else if (stat == -1) { 2339*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2340*0Sstevel@tonic-gate &stat); 2341*0Sstevel@tonic-gate } else { 2342*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 2343*0Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 2344*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2345*0Sstevel@tonic-gate stat = lderr; 2346*0Sstevel@tonic-gate } 2347*0Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 2348*0Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 2349*0Sstevel@tonic-gate releaseCon(lc, stat); 2350*0Sstevel@tonic-gate if (msg != NULL) 2351*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2352*0Sstevel@tonic-gate msg = NULL; 2353*0Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 2354*0Sstevel@tonic-gate ldap_value_free(referralsp); 2355*0Sstevel@tonic-gate referralsp = NULL; 2356*0Sstevel@tonic-gate if (lc == NULL) 2357*0Sstevel@tonic-gate goto cleanup; 2358*0Sstevel@tonic-gate msgid = ldap_modify(lc->ld, dn, mods); 2359*0Sstevel@tonic-gate if (msgid == -1) { 2360*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2361*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2362*0Sstevel@tonic-gate goto cleanup; 2363*0Sstevel@tonic-gate } 2364*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2365*0Sstevel@tonic-gate if (stat == 0) { 2366*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2367*0Sstevel@tonic-gate } else if (stat == -1) { 2368*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2369*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2370*0Sstevel@tonic-gate } else { 2371*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 2372*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 2373*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2374*0Sstevel@tonic-gate stat = lderr; 2375*0Sstevel@tonic-gate } 2376*0Sstevel@tonic-gate } 2377*0Sstevel@tonic-gate 2378*0Sstevel@tonic-gate /* 2379*0Sstevel@tonic-gate * If the modify failed with an object class violation, 2380*0Sstevel@tonic-gate * the most probable reason is that at least on of the 2381*0Sstevel@tonic-gate * attributes we're modifying didn't exist before, and 2382*0Sstevel@tonic-gate * neither did its object class. So, try the modify again, 2383*0Sstevel@tonic-gate * but add the object classes this time. 2384*0Sstevel@tonic-gate */ 2385*0Sstevel@tonic-gate if (stat == LDAP_OBJECT_CLASS_VIOLATION && 2386*0Sstevel@tonic-gate objClassAttrs != 0) { 2387*0Sstevel@tonic-gate freeLdapMod(mods); 2388*0Sstevel@tonic-gate mods = 0; 2389*0Sstevel@tonic-gate stat = ldapModifyObjectClass(&lc, dn, rv, 2390*0Sstevel@tonic-gate objClassAttrs); 2391*0Sstevel@tonic-gate } 2392*0Sstevel@tonic-gate 2393*0Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_ATTRIBUTE) { 2394*0Sstevel@tonic-gate /* 2395*0Sstevel@tonic-gate * If there was at least one attribute delete, then 2396*0Sstevel@tonic-gate * the cause of this error could be that said attribute 2397*0Sstevel@tonic-gate * didn't exist in LDAP. So, do things the slow way, 2398*0Sstevel@tonic-gate * and try to delete one attribute at a time. 2399*0Sstevel@tonic-gate */ 2400*0Sstevel@tonic-gate int d, numDelete, st; 2401*0Sstevel@tonic-gate __nis_rule_value_t *rvt; 2402*0Sstevel@tonic-gate 2403*0Sstevel@tonic-gate for (d = 0, numDelete = 0; d < rv->numAttrs; d++) { 2404*0Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) 2405*0Sstevel@tonic-gate numDelete++; 2406*0Sstevel@tonic-gate } 2407*0Sstevel@tonic-gate 2408*0Sstevel@tonic-gate /* If there's just one, we've already tried */ 2409*0Sstevel@tonic-gate if (numDelete <= 1) 2410*0Sstevel@tonic-gate goto cleanup; 2411*0Sstevel@tonic-gate 2412*0Sstevel@tonic-gate /* Make a copy of the rule value */ 2413*0Sstevel@tonic-gate rvt = initRuleValue(1, rv); 2414*0Sstevel@tonic-gate if (rvt == 0) 2415*0Sstevel@tonic-gate goto cleanup; 2416*0Sstevel@tonic-gate 2417*0Sstevel@tonic-gate /* 2418*0Sstevel@tonic-gate * Remove all delete attributes from the tmp 2419*0Sstevel@tonic-gate * rule value. 2420*0Sstevel@tonic-gate */ 2421*0Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 2422*0Sstevel@tonic-gate if (rv->attrVal[d].numVals < 0) { 2423*0Sstevel@tonic-gate delAttrFromRuleValue(rvt, 2424*0Sstevel@tonic-gate rv->attrName[d]); 2425*0Sstevel@tonic-gate } 2426*0Sstevel@tonic-gate } 2427*0Sstevel@tonic-gate 2428*0Sstevel@tonic-gate /* 2429*0Sstevel@tonic-gate * Now put the attributes back in one by one, and 2430*0Sstevel@tonic-gate * invoke ourselves. 2431*0Sstevel@tonic-gate */ 2432*0Sstevel@tonic-gate for (d = 0; d < rv->numAttrs; d++) { 2433*0Sstevel@tonic-gate if (rv->attrVal[d].numVals >= 0) 2434*0Sstevel@tonic-gate continue; 2435*0Sstevel@tonic-gate st = addAttr2RuleValue(rv->attrVal[d].type, 2436*0Sstevel@tonic-gate rv->attrName[d], 0, 0, rvt); 2437*0Sstevel@tonic-gate if (st != 0) { 2438*0Sstevel@tonic-gate logmsg(MSG_NOMEM, LOG_ERR, 2439*0Sstevel@tonic-gate "%s: Error deleting \"%s\" for \"%s\"", 2440*0Sstevel@tonic-gate NIL(rv->attrName[d]), NIL(dn)); 2441*0Sstevel@tonic-gate stat = LDAP_NO_MEMORY; 2442*0Sstevel@tonic-gate freeRuleValue(rvt, 1); 2443*0Sstevel@tonic-gate goto cleanup; 2444*0Sstevel@tonic-gate } 2445*0Sstevel@tonic-gate stat = ldapModify(dn, rvt, objClassAttrs, 0); 2446*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS && 2447*0Sstevel@tonic-gate stat != LDAP_NO_SUCH_ATTRIBUTE) { 2448*0Sstevel@tonic-gate freeRuleValue(rvt, 1); 2449*0Sstevel@tonic-gate goto cleanup; 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate delAttrFromRuleValue(rvt, rv->attrName[d]); 2452*0Sstevel@tonic-gate } 2453*0Sstevel@tonic-gate 2454*0Sstevel@tonic-gate /* 2455*0Sstevel@tonic-gate * If we got here, then all attributes that should 2456*0Sstevel@tonic-gate * be deleted either have been, or didn't exist. For 2457*0Sstevel@tonic-gate * our purposes, the latter is as good as the former. 2458*0Sstevel@tonic-gate */ 2459*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 2460*0Sstevel@tonic-gate freeRuleValue(rvt, 1); 2461*0Sstevel@tonic-gate } 2462*0Sstevel@tonic-gate 2463*0Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) { 2464*0Sstevel@tonic-gate /* 2465*0Sstevel@tonic-gate * Entry doesn't exist, so try an ldap_add(). If the 2466*0Sstevel@tonic-gate * ldap_add() also fails, that could be because someone 2467*0Sstevel@tonic-gate * else added it between our modify and add operations. 2468*0Sstevel@tonic-gate * If so, we consider that foreign add to be 2469*0Sstevel@tonic-gate * authoritative (meaning we don't retry our modify). 2470*0Sstevel@tonic-gate * 2471*0Sstevel@tonic-gate * Also, if all modify operations specified by 'mods' 2472*0Sstevel@tonic-gate * are deletes, LDAP_NO_SUCH_OBJECT is a kind of 2473*0Sstevel@tonic-gate * success; we certainly don't want to create the 2474*0Sstevel@tonic-gate * entry. 2475*0Sstevel@tonic-gate */ 2476*0Sstevel@tonic-gate int allDelete; 2477*0Sstevel@tonic-gate LDAPMod **m; 2478*0Sstevel@tonic-gate 2479*0Sstevel@tonic-gate for (m = mods, allDelete = 1; *m != 0 && allDelete; 2480*0Sstevel@tonic-gate m++) { 2481*0Sstevel@tonic-gate if (((*m)->mod_op & LDAP_MOD_DELETE) == 0) 2482*0Sstevel@tonic-gate allDelete = 0; 2483*0Sstevel@tonic-gate } 2484*0Sstevel@tonic-gate 2485*0Sstevel@tonic-gate add = 1; 2486*0Sstevel@tonic-gate 2487*0Sstevel@tonic-gate if (allDelete) { 2488*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 2489*0Sstevel@tonic-gate } else if (objClassAttrs == 0) { 2490*0Sstevel@tonic-gate /* Now we need it, so this is fatal */ 2491*0Sstevel@tonic-gate stat = LDAP_PARAM_ERROR; 2492*0Sstevel@tonic-gate } else { 2493*0Sstevel@tonic-gate stat = ldapAdd(dn, rv, objClassAttrs, lc); 2494*0Sstevel@tonic-gate lc = NULL; 2495*0Sstevel@tonic-gate } 2496*0Sstevel@tonic-gate } 2497*0Sstevel@tonic-gate } 2498*0Sstevel@tonic-gate 2499*0Sstevel@tonic-gate cleanup: 2500*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 2501*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2502*0Sstevel@tonic-gate "%s(0x%x (%s), \"%s\") => %d (%s)\n", 2503*0Sstevel@tonic-gate !delete ? (add ? "ldap_add" : "ldap_modify") : 2504*0Sstevel@tonic-gate "ldap_delete", 2505*0Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 2506*0Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 2507*0Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 2508*0Sstevel@tonic-gate } 2509*0Sstevel@tonic-gate 2510*0Sstevel@tonic-gate releaseCon(lc, stat); 2511*0Sstevel@tonic-gate freeLdapMod(mods); 2512*0Sstevel@tonic-gate if (msg != 0) 2513*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2514*0Sstevel@tonic-gate 2515*0Sstevel@tonic-gate return (stat); 2516*0Sstevel@tonic-gate } 2517*0Sstevel@tonic-gate 2518*0Sstevel@tonic-gate /* 2519*0Sstevel@tonic-gate * Create the entry specified by 'dn' to have the values per 'rv'. 2520*0Sstevel@tonic-gate * The 'objClassAttrs' are the extra object classes we need when 2521*0Sstevel@tonic-gate * creating an entry. 2522*0Sstevel@tonic-gate * 2523*0Sstevel@tonic-gate * If 'lc' is non-NULL, we use that connection; otherwise, we find 2524*0Sstevel@tonic-gate * our own. CAUTION: This connection will be released on return. Regardless 2525*0Sstevel@tonic-gate * of return value, this connection should not subsequently used by the 2526*0Sstevel@tonic-gate * caller. 2527*0Sstevel@tonic-gate * 2528*0Sstevel@tonic-gate * Returns an LDAP status. 2529*0Sstevel@tonic-gate */ 2530*0Sstevel@tonic-gate int 2531*0Sstevel@tonic-gate ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) { 2532*0Sstevel@tonic-gate int stat; 2533*0Sstevel@tonic-gate LDAPMod **mods = 0; 2534*0Sstevel@tonic-gate struct timeval tv; 2535*0Sstevel@tonic-gate LDAPMessage *msg = 0; 2536*0Sstevel@tonic-gate __nis_ldap_conn_t *lc = lcv; 2537*0Sstevel@tonic-gate int msgid; 2538*0Sstevel@tonic-gate int lderr; 2539*0Sstevel@tonic-gate char **referralsp = NULL; 2540*0Sstevel@tonic-gate 2541*0Sstevel@tonic-gate if (dn == 0 || rv == 0 || objClassAttrs == 0) { 2542*0Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 2543*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 2544*0Sstevel@tonic-gate } 2545*0Sstevel@tonic-gate 2546*0Sstevel@tonic-gate if (lc == 0) { 2547*0Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 2548*0Sstevel@tonic-gate return (stat); 2549*0Sstevel@tonic-gate } 2550*0Sstevel@tonic-gate 2551*0Sstevel@tonic-gate rv = addObjectClasses(rv, objClassAttrs); 2552*0Sstevel@tonic-gate if (rv == 0) { 2553*0Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 2554*0Sstevel@tonic-gate goto cleanup; 2555*0Sstevel@tonic-gate } 2556*0Sstevel@tonic-gate 2557*0Sstevel@tonic-gate mods = search2LdapMod(rv, 1, 0); 2558*0Sstevel@tonic-gate if (mods == 0) { 2559*0Sstevel@tonic-gate stat = LDAP_OPERATIONS_ERROR; 2560*0Sstevel@tonic-gate goto cleanup; 2561*0Sstevel@tonic-gate } 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 2564*0Sstevel@tonic-gate if (msgid == -1) { 2565*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 2566*0Sstevel@tonic-gate goto cleanup; 2567*0Sstevel@tonic-gate } 2568*0Sstevel@tonic-gate tv = lc->addTimeout; 2569*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2570*0Sstevel@tonic-gate if (stat == 0) { 2571*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2572*0Sstevel@tonic-gate } else if (stat == -1) { 2573*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat); 2574*0Sstevel@tonic-gate } else { 2575*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL, 2576*0Sstevel@tonic-gate &referralsp, NULL, 0); 2577*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2578*0Sstevel@tonic-gate stat = lderr; 2579*0Sstevel@tonic-gate } 2580*0Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL && 2581*0Sstevel@tonic-gate referralsp != NULL) { 2582*0Sstevel@tonic-gate releaseCon(lc, stat); 2583*0Sstevel@tonic-gate if (msg != NULL) 2584*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2585*0Sstevel@tonic-gate msg = NULL; 2586*0Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 2587*0Sstevel@tonic-gate ldap_value_free(referralsp); 2588*0Sstevel@tonic-gate if (lc == NULL) 2589*0Sstevel@tonic-gate goto cleanup; 2590*0Sstevel@tonic-gate msgid = ldap_add(lc->ld, dn, mods); 2591*0Sstevel@tonic-gate if (msgid == -1) { 2592*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2593*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2594*0Sstevel@tonic-gate goto cleanup; 2595*0Sstevel@tonic-gate } 2596*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2597*0Sstevel@tonic-gate if (stat == 0) { 2598*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2599*0Sstevel@tonic-gate } else if (stat == -1) { 2600*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2601*0Sstevel@tonic-gate &stat); 2602*0Sstevel@tonic-gate } else { 2603*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 2604*0Sstevel@tonic-gate NULL, NULL, NULL, 0); 2605*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2606*0Sstevel@tonic-gate stat = lderr; 2607*0Sstevel@tonic-gate } 2608*0Sstevel@tonic-gate } 2609*0Sstevel@tonic-gate 2610*0Sstevel@tonic-gate cleanup: 2611*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 2612*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 2613*0Sstevel@tonic-gate "ldap_add(0x%x (%s), \"%s\") => %d (%s)\n", 2614*0Sstevel@tonic-gate lc != NULL ? lc->ld : 0, 2615*0Sstevel@tonic-gate lc != NULL ? NIL(lc->sp) : "nil", 2616*0Sstevel@tonic-gate dn, stat, ldap_err2string(stat)); 2617*0Sstevel@tonic-gate } 2618*0Sstevel@tonic-gate 2619*0Sstevel@tonic-gate releaseCon(lc, stat); 2620*0Sstevel@tonic-gate freeLdapMod(mods); 2621*0Sstevel@tonic-gate if (msg != 0) 2622*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2623*0Sstevel@tonic-gate 2624*0Sstevel@tonic-gate return (stat); 2625*0Sstevel@tonic-gate } 2626*0Sstevel@tonic-gate 2627*0Sstevel@tonic-gate /* 2628*0Sstevel@tonic-gate * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'. 2629*0Sstevel@tonic-gate * Returns an LDAP error status. 2630*0Sstevel@tonic-gate */ 2631*0Sstevel@tonic-gate int 2632*0Sstevel@tonic-gate ldapChangeDN(char *oldDn, char *dn) { 2633*0Sstevel@tonic-gate int stat; 2634*0Sstevel@tonic-gate __nis_ldap_conn_t *lc; 2635*0Sstevel@tonic-gate int i, j, lo, ln; 2636*0Sstevel@tonic-gate char *rdn; 2637*0Sstevel@tonic-gate int msgid; 2638*0Sstevel@tonic-gate int lderr; 2639*0Sstevel@tonic-gate struct timeval tv; 2640*0Sstevel@tonic-gate LDAPMessage *msg = 0; 2641*0Sstevel@tonic-gate char **referralsp = NULL; 2642*0Sstevel@tonic-gate char *myself = "ldapChangeDN"; 2643*0Sstevel@tonic-gate 2644*0Sstevel@tonic-gate if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0) 2645*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 2646*0Sstevel@tonic-gate 2647*0Sstevel@tonic-gate if (strcasecmp(oldDn, dn) == 0) 2648*0Sstevel@tonic-gate return (LDAP_SUCCESS); 2649*0Sstevel@tonic-gate 2650*0Sstevel@tonic-gate if ((lc = findCon(&stat)) == 0) 2651*0Sstevel@tonic-gate return (stat); 2652*0Sstevel@tonic-gate 2653*0Sstevel@tonic-gate rdn = sdup(myself, T, dn); 2654*0Sstevel@tonic-gate if (rdn == 0) { 2655*0Sstevel@tonic-gate releaseCon(lc, LDAP_SUCCESS); 2656*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 2657*0Sstevel@tonic-gate } 2658*0Sstevel@tonic-gate 2659*0Sstevel@tonic-gate /* Compare old and new DN from the end */ 2660*0Sstevel@tonic-gate for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) { 2661*0Sstevel@tonic-gate if (tolower(oldDn[i]) != tolower(rdn[j])) { 2662*0Sstevel@tonic-gate /* 2663*0Sstevel@tonic-gate * Terminate 'rdn' after this character in order 2664*0Sstevel@tonic-gate * to snip off the portion of the new DN that is 2665*0Sstevel@tonic-gate * the same as the old DN. What remains in 'rdn' 2666*0Sstevel@tonic-gate * is the relative DN. 2667*0Sstevel@tonic-gate */ 2668*0Sstevel@tonic-gate rdn[j+1] = '\0'; 2669*0Sstevel@tonic-gate break; 2670*0Sstevel@tonic-gate } 2671*0Sstevel@tonic-gate } 2672*0Sstevel@tonic-gate 2673*0Sstevel@tonic-gate stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid); 2674*0Sstevel@tonic-gate 2675*0Sstevel@tonic-gate if (msgid != -1) { 2676*0Sstevel@tonic-gate tv = lc->modifyTimeout; 2677*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2678*0Sstevel@tonic-gate if (stat == 0) { 2679*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2680*0Sstevel@tonic-gate } else if (stat == -1) { 2681*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2682*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2683*0Sstevel@tonic-gate } else { 2684*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, 2685*0Sstevel@tonic-gate NULL, &referralsp, NULL, 0); 2686*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2687*0Sstevel@tonic-gate stat = lderr; 2688*0Sstevel@tonic-gate stat = ldap_result2error(lc->ld, msg, 0); 2689*0Sstevel@tonic-gate } 2690*0Sstevel@tonic-gate } else { 2691*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, 2692*0Sstevel@tonic-gate &stat); 2693*0Sstevel@tonic-gate } 2694*0Sstevel@tonic-gate if (proxyInfo.follow_referral == follow && 2695*0Sstevel@tonic-gate stat == LDAP_REFERRAL && referralsp != NULL) { 2696*0Sstevel@tonic-gate releaseCon(lc, stat); 2697*0Sstevel@tonic-gate if (msg != NULL) 2698*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2699*0Sstevel@tonic-gate msg = NULL; 2700*0Sstevel@tonic-gate lc = findReferralCon(referralsp, &stat); 2701*0Sstevel@tonic-gate ldap_value_free(referralsp); 2702*0Sstevel@tonic-gate referralsp = NULL; 2703*0Sstevel@tonic-gate if (lc == NULL) 2704*0Sstevel@tonic-gate goto cleanup; 2705*0Sstevel@tonic-gate msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, 2706*0Sstevel@tonic-gate &msgid); 2707*0Sstevel@tonic-gate if (msgid == -1) { 2708*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2709*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2710*0Sstevel@tonic-gate goto cleanup; 2711*0Sstevel@tonic-gate } 2712*0Sstevel@tonic-gate stat = ldap_result(lc->ld, msgid, 0, &tv, &msg); 2713*0Sstevel@tonic-gate if (stat == 0) { 2714*0Sstevel@tonic-gate stat = LDAP_TIMEOUT; 2715*0Sstevel@tonic-gate } else if (stat == -1) { 2716*0Sstevel@tonic-gate (void) ldap_get_option(lc->ld, 2717*0Sstevel@tonic-gate LDAP_OPT_ERROR_NUMBER, &stat); 2718*0Sstevel@tonic-gate } else { 2719*0Sstevel@tonic-gate stat = ldap_parse_result(lc->ld, msg, &lderr, 2720*0Sstevel@tonic-gate NULL, NULL, NULL, NULL, 0); 2721*0Sstevel@tonic-gate if (stat == LDAP_SUCCESS) 2722*0Sstevel@tonic-gate stat = lderr; 2723*0Sstevel@tonic-gate } 2724*0Sstevel@tonic-gate } 2725*0Sstevel@tonic-gate 2726*0Sstevel@tonic-gate cleanup: 2727*0Sstevel@tonic-gate if (msg != NULL) 2728*0Sstevel@tonic-gate (void) ldap_msgfree(msg); 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate #if 1 2731*0Sstevel@tonic-gate fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n", 2732*0Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 2733*0Sstevel@tonic-gate ldap_err2string(stat)); 2734*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2735*0Sstevel@tonic-gate "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s", 2736*0Sstevel@tonic-gate myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn), 2737*0Sstevel@tonic-gate ldap_err2string(stat)); 2738*0Sstevel@tonic-gate #endif 2739*0Sstevel@tonic-gate 2740*0Sstevel@tonic-gate if (stat == LDAP_NO_SUCH_OBJECT) { 2741*0Sstevel@tonic-gate /* 2742*0Sstevel@tonic-gate * Fine from our point of view, since all we want to do 2743*0Sstevel@tonic-gate * is to make sure that an update to the new DN doesn't 2744*0Sstevel@tonic-gate * leave the old entry around. 2745*0Sstevel@tonic-gate */ 2746*0Sstevel@tonic-gate stat = LDAP_SUCCESS; 2747*0Sstevel@tonic-gate } 2748*0Sstevel@tonic-gate 2749*0Sstevel@tonic-gate releaseCon(lc, stat); 2750*0Sstevel@tonic-gate sfree(rdn); 2751*0Sstevel@tonic-gate 2752*0Sstevel@tonic-gate return (stat); 2753*0Sstevel@tonic-gate } 2754