Home | History | Annotate | Download | only in libnisdb
      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