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