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