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 * 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 * 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 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