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