1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #include <lber.h> 31*0Sstevel@tonic-gate #include <ldap.h> 32*0Sstevel@tonic-gate #include <string.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include "ldap_util.h" 35*0Sstevel@tonic-gate #include "ldap_op.h" 36*0Sstevel@tonic-gate #include "ldap_attr.h" 37*0Sstevel@tonic-gate #include "ldap_ldap.h" 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate static __nis_value_t * 41*0Sstevel@tonic-gate evalMappingElement(__nis_mapping_element_t *e, __nis_rule_value_t *rvIn) { 42*0Sstevel@tonic-gate __nis_rule_value_t *rv = rvIn; 43*0Sstevel@tonic-gate int freeRv = 0; 44*0Sstevel@tonic-gate __nis_value_t *val; 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate if (rv == 0) { 47*0Sstevel@tonic-gate rv = initRuleValue(1, 0); 48*0Sstevel@tonic-gate if (rv == 0) 49*0Sstevel@tonic-gate return (0); 50*0Sstevel@tonic-gate freeRv = 1; 51*0Sstevel@tonic-gate } 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate val = getMappingElement(e, mit_any, rv, NULL); 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate if (freeRv) 56*0Sstevel@tonic-gate freeRuleValue(rv, 1); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate return (val); 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate __nis_value_t * 62*0Sstevel@tonic-gate lookupLDAP(__nis_search_triple_t *t, char *attrName, __nis_rule_value_t *rv, 63*0Sstevel@tonic-gate __nis_object_dn_t *def, int *np_ldap_stat) { 64*0Sstevel@tonic-gate __nis_value_t *val, *eVal = 0; 65*0Sstevel@tonic-gate char *base, *filter; 66*0Sstevel@tonic-gate __nis_ldap_search_t *ls; 67*0Sstevel@tonic-gate char *attrs[2]; 68*0Sstevel@tonic-gate int scope, i, stat, nrv = 0, freeBase = 0; 69*0Sstevel@tonic-gate char *myself = "lookupLDAP"; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate if (t == 0 || slen(attrName) <= 0) 72*0Sstevel@tonic-gate return (0); 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate if (t->element != 0) { 75*0Sstevel@tonic-gate /* Evaluate t->element to get the t->attrs value */ 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate eVal = evalMappingElement(t->element, rv); 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate if (eVal == 0) 80*0Sstevel@tonic-gate return (0); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate if (eVal->type != vt_string || eVal->numVals <= 0) { 83*0Sstevel@tonic-gate freeValue(eVal, 1); 84*0Sstevel@tonic-gate { 85*0Sstevel@tonic-gate char *ename = "<unknown>"; 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate eVal = evalMappingElement(t->element, 0); 88*0Sstevel@tonic-gate if (eVal != 0 && eVal->type == vt_string && 89*0Sstevel@tonic-gate eVal->numVals == 1 && 90*0Sstevel@tonic-gate eVal->val[0].length > 0 && 91*0Sstevel@tonic-gate eVal->val[0].value != 0) 92*0Sstevel@tonic-gate ename = eVal->val[0].value; 93*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 94*0Sstevel@tonic-gate "%s: %s: unable to evaluate filter expression \"%s\"", 95*0Sstevel@tonic-gate myself, attrName, ename); 96*0Sstevel@tonic-gate freeValue(eVal, 1); 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate return (0); 99*0Sstevel@tonic-gate } 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate filter = eVal->val[0].value; 102*0Sstevel@tonic-gate } else { 103*0Sstevel@tonic-gate filter = t->attrs; 104*0Sstevel@tonic-gate } 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate if (slen(t->base) > 0) { 107*0Sstevel@tonic-gate base = appendBase(t->base, (def != 0) ? def->read.base : 0, 108*0Sstevel@tonic-gate &stat, 0); 109*0Sstevel@tonic-gate if (stat != 0) { 110*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 111*0Sstevel@tonic-gate "%s: %s: error appending \"%s\" to \"%s\"", 112*0Sstevel@tonic-gate myself, attrName, NIL(def->read.base), 113*0Sstevel@tonic-gate NIL(t->base)); 114*0Sstevel@tonic-gate return (0); 115*0Sstevel@tonic-gate } 116*0Sstevel@tonic-gate freeBase = 1; 117*0Sstevel@tonic-gate } else { 118*0Sstevel@tonic-gate if (def == 0 || def->read.scope == LDAP_SCOPE_UNKNOWN || 119*0Sstevel@tonic-gate slen(def->read.base) <= 0) { 120*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 121*0Sstevel@tonic-gate "%s: %s: no supplied or default search base", 122*0Sstevel@tonic-gate myself, attrName); 123*0Sstevel@tonic-gate freeValue(eVal, 1); 124*0Sstevel@tonic-gate return (0); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate base = def->read.base; 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate if (slen(filter) > 0) 130*0Sstevel@tonic-gate scope = t->scope; 131*0Sstevel@tonic-gate else 132*0Sstevel@tonic-gate scope = LDAP_SCOPE_BASE; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate attrs[0] = attrName; 135*0Sstevel@tonic-gate attrs[1] = 0; 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate ls = buildLdapSearch(base, scope, 0, 0, filter, attrs, 0, 0); 138*0Sstevel@tonic-gate if (ls == 0) { 139*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 140*0Sstevel@tonic-gate "%s: %s: error building LDAP search information for \"%s?%s?%s\"", 141*0Sstevel@tonic-gate myself, attrName, NIL(base), getScope(scope), 142*0Sstevel@tonic-gate NIL(filter)); 143*0Sstevel@tonic-gate freeValue(eVal, 1); 144*0Sstevel@tonic-gate if (freeBase) 145*0Sstevel@tonic-gate sfree(base); 146*0Sstevel@tonic-gate return (0); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate rv = ldapSearch(ls, &nrv, 0, &stat); 150*0Sstevel@tonic-gate freeLdapSearch(ls); 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate /* 153*0Sstevel@tonic-gate * If ldapSearch returns LDAP_NO_SUCH_OBJECT, then entry that 154*0Sstevel@tonic-gate * looked for is not there in LDAP, so return NP_LDAP_NO_VALUE 155*0Sstevel@tonic-gate * in np_ldap_stat. 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate if (np_ldap_stat != NULL && stat == LDAP_NO_SUCH_OBJECT) 159*0Sstevel@tonic-gate *np_ldap_stat = NP_LDAP_NO_VALUE; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (rv == 0) { 162*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, 163*0Sstevel@tonic-gate (stat == LDAP_NO_SUCH_OBJECT)?LOG_DEBUG:LOG_ERR, 164*0Sstevel@tonic-gate "%s: %s: LDAP error %d (%s) for \"%s?%s?%s\"", 165*0Sstevel@tonic-gate myself, attrName, stat, ldap_err2string(stat), 166*0Sstevel@tonic-gate NIL(base), getScope(scope), NIL(filter)); 167*0Sstevel@tonic-gate if (freeBase) 168*0Sstevel@tonic-gate sfree(base); 169*0Sstevel@tonic-gate freeValue(eVal, 1); 170*0Sstevel@tonic-gate return (0); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate if (freeBase) 174*0Sstevel@tonic-gate sfree(base); 175*0Sstevel@tonic-gate freeValue(eVal, 1); 176*0Sstevel@tonic-gate eVal = 0; 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate for (i = 0, val = 0; i < nrv; i++) { 179*0Sstevel@tonic-gate int j; 180*0Sstevel@tonic-gate for (j = 0; j < rv[i].numAttrs; j++) { 181*0Sstevel@tonic-gate if (strcasecmp(attrName, rv[i].attrName[j]) == 0) { 182*0Sstevel@tonic-gate eVal = concatenateValues(val, 183*0Sstevel@tonic-gate &rv[i].attrVal[j]); 184*0Sstevel@tonic-gate freeValue(val, 1); 185*0Sstevel@tonic-gate if (eVal == 0) { 186*0Sstevel@tonic-gate freeRuleValue(rv, nrv); 187*0Sstevel@tonic-gate return (0); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate val = eVal; 190*0Sstevel@tonic-gate break; 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate freeRuleValue(rv, nrv); 196*0Sstevel@tonic-gate return (val); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate /* 200*0Sstevel@tonic-gate * Store 'val' at the LDAP location indicated by 'item'. As usual, 201*0Sstevel@tonic-gate * val->numVals == -1 indicates deletion. 202*0Sstevel@tonic-gate * 203*0Sstevel@tonic-gate * The 'index' and 'numIndexes' parameters are used as follows: 204*0Sstevel@tonic-gate * 205*0Sstevel@tonic-gate * index < 0 || index >= numIndexes 206*0Sstevel@tonic-gate * Illegal 207*0Sstevel@tonic-gate * 208*0Sstevel@tonic-gate * index >= val->numVals 209*0Sstevel@tonic-gate * Store val->val[val->numVals-1] 210*0Sstevel@tonic-gate * 211*0Sstevel@tonic-gate * item->repeat == 0 || index < numIndexes 212*0Sstevel@tonic-gate * Store val->val[index] 213*0Sstevel@tonic-gate * 214*0Sstevel@tonic-gate * Else (repeat != 0 && index == numIndexes-1) 215*0Sstevel@tonic-gate * Store val->val[index...val->numVals-1] 216*0Sstevel@tonic-gate * 217*0Sstevel@tonic-gate * 'defDN' should be the default object DN specification, primarily 218*0Sstevel@tonic-gate * used when the item search triple is invalid. Also, the defDN->write.base 219*0Sstevel@tonic-gate * value is appended to the item search base if the latter is empty, or ends 220*0Sstevel@tonic-gate * in a comma. 221*0Sstevel@tonic-gate * 222*0Sstevel@tonic-gate * If the item search triple is invalid, 'dn' must contain the DN(s) 223*0Sstevel@tonic-gate * of the LDAP entry to be modified. If the search triple is valid, 224*0Sstevel@tonic-gate * the DN(s) is(are) either: 225*0Sstevel@tonic-gate * Derived via an LDAP search on the search triple 'attrs' or 226*0Sstevel@tonic-gate * 'element' fields, or (if neither of those fields is set) 227*0Sstevel@tonic-gate * assumed to be the search triple base. 228*0Sstevel@tonic-gate * 229*0Sstevel@tonic-gate * Returns LDAP_SUCCESS when successful, or an appropriate LDAP 230*0Sstevel@tonic-gate * error status otherwise. 231*0Sstevel@tonic-gate */ 232*0Sstevel@tonic-gate int 233*0Sstevel@tonic-gate storeLDAP(__nis_mapping_item_t *item, int index, int numIndexes, 234*0Sstevel@tonic-gate __nis_value_t *val, __nis_object_dn_t *defDN, 235*0Sstevel@tonic-gate char **dn, int numDN) { 236*0Sstevel@tonic-gate __nis_ldap_search_t ls; 237*0Sstevel@tonic-gate int stat, i, ix, six, nix; 238*0Sstevel@tonic-gate int freeDN = 0; 239*0Sstevel@tonic-gate char *locDN[1]; 240*0Sstevel@tonic-gate __nis_rule_value_t *rv; 241*0Sstevel@tonic-gate char *defBase = 0; 242*0Sstevel@tonic-gate char *myself = "storeLDAP"; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (item == 0 || item->type != mit_ldap || item->name == 0 || 245*0Sstevel@tonic-gate index < 0 || index >= numIndexes || 246*0Sstevel@tonic-gate val == 0 || val->numVals < -1 || val->numVals == 0) 247*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate if (defDN != 0 && slen(defDN->write.base) > 0) 250*0Sstevel@tonic-gate defBase = defDN->write.base; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate ls.numFilterComps = 0; 253*0Sstevel@tonic-gate ls.filterComp = 0; 254*0Sstevel@tonic-gate ls.numAttrs = 0; 255*0Sstevel@tonic-gate ls.attrs = 0; 256*0Sstevel@tonic-gate ls.isDN = 0; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) { 259*0Sstevel@tonic-gate /* If 'defDN' is NULL, we don't know where to write */ 260*0Sstevel@tonic-gate if (defDN == 0) 261*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 262*0Sstevel@tonic-gate /* 263*0Sstevel@tonic-gate * Check if we're supposed to write. Since we want the 264*0Sstevel@tonic-gate * admin to be able to use the nisplusLDAPobjectDN attribute 265*0Sstevel@tonic-gate * as an on/off switch, we don't flag failure as an error. 266*0Sstevel@tonic-gate */ 267*0Sstevel@tonic-gate if (defDN != 0 && defDN->write.scope == LDAP_SCOPE_UNKNOWN) { 268*0Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_INFO, 269*0Sstevel@tonic-gate "%s: write not enabled for \"%s\"", 270*0Sstevel@tonic-gate myself, NIL(item->name)); 271*0Sstevel@tonic-gate return (LDAP_SUCCESS); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate } else { 274*0Sstevel@tonic-gate /* 275*0Sstevel@tonic-gate * Attempt to get a DN from the search triple. 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate if (slen(item->searchSpec.triple.base) > 0) 279*0Sstevel@tonic-gate ls.base = item->searchSpec.triple.base; 280*0Sstevel@tonic-gate else 281*0Sstevel@tonic-gate ls.base = defBase; 282*0Sstevel@tonic-gate ls.base = appendBase(ls.base, defBase, &stat, 0); 283*0Sstevel@tonic-gate if (stat != 0) 284*0Sstevel@tonic-gate return (0); 285*0Sstevel@tonic-gate ls.scope = item->searchSpec.triple.scope; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * If the search triple specifies a filter, we use the 289*0Sstevel@tonic-gate * base, scope and filter to get an entry to supply the 290*0Sstevel@tonic-gate * DN. Otherwise, the triple.base is assumed to be the DN. 291*0Sstevel@tonic-gate */ 292*0Sstevel@tonic-gate if (slen(item->searchSpec.triple.attrs) > 0 || 293*0Sstevel@tonic-gate item->searchSpec.triple.element != 0) { 294*0Sstevel@tonic-gate __nis_value_t *eVal = 0; 295*0Sstevel@tonic-gate __nis_rule_value_t *rvDN; 296*0Sstevel@tonic-gate int nv = 0; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate if (item->searchSpec.triple.element != 0) { 299*0Sstevel@tonic-gate eVal = evalMappingElement( 300*0Sstevel@tonic-gate item->searchSpec.triple.element, 0); 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (eVal == 0) { 303*0Sstevel@tonic-gate sfree(ls.base); 304*0Sstevel@tonic-gate return (0); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate if (eVal->type != vt_string || 308*0Sstevel@tonic-gate eVal->numVals <= 0) { 309*0Sstevel@tonic-gate sfree(ls.base); 310*0Sstevel@tonic-gate freeValue(eVal, 1); 311*0Sstevel@tonic-gate return (0); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate ls.filter = eVal->val[0].value; 315*0Sstevel@tonic-gate } else { 316*0Sstevel@tonic-gate ls.filter = item->searchSpec.triple.attrs; 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate rvDN = ldapSearch(&ls, &nv, 0, &stat); 320*0Sstevel@tonic-gate sfree(ls.base); 321*0Sstevel@tonic-gate freeValue(eVal, 1); 322*0Sstevel@tonic-gate if (rvDN == 0 || nv <= 0) 323*0Sstevel@tonic-gate return (stat); 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /* Look for DNs */ 326*0Sstevel@tonic-gate dn = findDNs(myself, rvDN, nv, 0, &numDN); 327*0Sstevel@tonic-gate freeRuleValue(rvDN, nv); 328*0Sstevel@tonic-gate if (dn == 0 || numDN <= 0) { 329*0Sstevel@tonic-gate freeDNs(dn, numDN); 330*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 331*0Sstevel@tonic-gate } 332*0Sstevel@tonic-gate freeDN = 1; 333*0Sstevel@tonic-gate } else if (slen(item->searchSpec.triple.base) > 0) { 334*0Sstevel@tonic-gate locDN[0] = item->searchSpec.triple.base; 335*0Sstevel@tonic-gate dn = locDN; 336*0Sstevel@tonic-gate numDN = 1; 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate } 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* We must have at least one DN to continue */ 341*0Sstevel@tonic-gate if (dn == 0 || numDN < 1) { 342*0Sstevel@tonic-gate if (freeDN) 343*0Sstevel@tonic-gate freeDNs(dn, numDN); 344*0Sstevel@tonic-gate return (LDAP_PARAM_ERROR); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate if (val->numVals > 0) { 348*0Sstevel@tonic-gate /* Make a rule-value describing the modification */ 349*0Sstevel@tonic-gate rv = am(myself, sizeof (*rv)); 350*0Sstevel@tonic-gate if (rv == 0) 351*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 352*0Sstevel@tonic-gate rv->attrName = am(myself, sizeof (rv->attrName[0])); 353*0Sstevel@tonic-gate rv->attrVal = am(myself, sizeof (rv->attrVal[0])); 354*0Sstevel@tonic-gate if (rv->attrName == 0 || rv->attrVal == 0) { 355*0Sstevel@tonic-gate if (freeDN) 356*0Sstevel@tonic-gate freeDNs(dn, numDN); 357*0Sstevel@tonic-gate freeRuleValue(rv, 1); 358*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * What's the start index in val->val[], and how many elements 363*0Sstevel@tonic-gate * should we copy ? 364*0Sstevel@tonic-gate */ 365*0Sstevel@tonic-gate if (index < val->numVals) 366*0Sstevel@tonic-gate six = index; 367*0Sstevel@tonic-gate else 368*0Sstevel@tonic-gate six = val->numVals - 1; 369*0Sstevel@tonic-gate if (item->repeat && index == (numIndexes - 1)) 370*0Sstevel@tonic-gate nix = 1 + (six - (val->numVals - 1)); 371*0Sstevel@tonic-gate else 372*0Sstevel@tonic-gate nix = 1; 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate rv->attrName[0] = sdup(myself, T, item->name); 375*0Sstevel@tonic-gate rv->attrVal[0].val = am(myself, 376*0Sstevel@tonic-gate nix * sizeof (rv->attrVal[0].val[0])); 377*0Sstevel@tonic-gate if (rv->attrName[0] == 0 || rv->attrVal[0].val == 0) { 378*0Sstevel@tonic-gate if (freeDN) 379*0Sstevel@tonic-gate freeDNs(dn, numDN); 380*0Sstevel@tonic-gate freeRuleValue(rv, 1); 381*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate rv->numAttrs = 1; 384*0Sstevel@tonic-gate for (ix = six; ix < nix; ix++) { 385*0Sstevel@tonic-gate rv->attrVal[0].numVals++; 386*0Sstevel@tonic-gate rv->attrVal[0].val[ix-six].value = 387*0Sstevel@tonic-gate am(myself, val->val[ix].length); 388*0Sstevel@tonic-gate if (rv->attrVal[0].val[ix-six].value == 0 && 389*0Sstevel@tonic-gate val->val[ix].value != 0) { 390*0Sstevel@tonic-gate if (freeDN) 391*0Sstevel@tonic-gate freeDNs(dn, numDN); 392*0Sstevel@tonic-gate freeRuleValue(rv, 1); 393*0Sstevel@tonic-gate return (LDAP_NO_MEMORY); 394*0Sstevel@tonic-gate } 395*0Sstevel@tonic-gate rv->attrVal[0].val[ix-six].length = 396*0Sstevel@tonic-gate val->val[ix].length; 397*0Sstevel@tonic-gate if (rv->attrVal[0].val[ix-six].length > 0) { 398*0Sstevel@tonic-gate (void) memcpy(rv->attrVal[0].val[ix-six].value, 399*0Sstevel@tonic-gate val->val[ix].value, 400*0Sstevel@tonic-gate rv->attrVal[0].val[ix-six].length); 401*0Sstevel@tonic-gate } 402*0Sstevel@tonic-gate } 403*0Sstevel@tonic-gate rv->attrVal[0].type = val->type; 404*0Sstevel@tonic-gate } else { 405*0Sstevel@tonic-gate /* 406*0Sstevel@tonic-gate * We already rejected val->numvals < -1 and val->numVals == 0 407*0Sstevel@tonic-gate * in the initial sanity check, so it must be -1. This means 408*0Sstevel@tonic-gate * deletion, which we indicate to ldapModify() by supplying 409*0Sstevel@tonic-gate * a NULL rule-value pointer. 410*0Sstevel@tonic-gate */ 411*0Sstevel@tonic-gate rv = 0; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* For each DN */ 415*0Sstevel@tonic-gate for (i = 0; i < numDN; i++) { 416*0Sstevel@tonic-gate stat = ldapModify(dn[i], rv, item->searchSpec.triple.attrs, 0); 417*0Sstevel@tonic-gate if (stat != LDAP_SUCCESS) 418*0Sstevel@tonic-gate break; 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate if (freeDN) 422*0Sstevel@tonic-gate freeDNs(dn, numDN); 423*0Sstevel@tonic-gate freeRuleValue(rv, 1); 424*0Sstevel@tonic-gate 425*0Sstevel@tonic-gate return (stat); 426*0Sstevel@tonic-gate } 427