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