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 *
evalMappingElement(__nis_mapping_element_t * e,__nis_rule_value_t * rvIn)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 *
lookupLDAP(__nis_search_triple_t * t,char * attrName,__nis_rule_value_t * rv,__nis_object_dn_t * def,int * np_ldap_stat)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
storeLDAP(__nis_mapping_item_t * item,int index,int numIndexes,__nis_value_t * val,__nis_object_dn_t * defDN,char ** dn,int numDN)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