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 #include <lber.h>
     30 #include <ldap.h>
     31 #include <strings.h>
     32 #include <errno.h>
     33 
     34 #include "nisdb_mt.h"
     35 
     36 #include "ldap_util.h"
     37 #include "ldap_op.h"
     38 #include "ldap_ruleval.h"
     39 #include "ldap_attr.h"
     40 #include "ldap_val.h"
     41 #include "ldap_nisplus.h"
     42 #include "ldap_ldap.h"
     43 
     44 extern int yp2ldap;
     45 
     46 
     47 __nis_mapping_format_t *
     48 cloneMappingFormat(__nis_mapping_format_t *m) {
     49 	__nis_mapping_format_t	*new;
     50 	int			i, nf, err;
     51 	char			*myself = "cloneMappingFormat";
     52 
     53 	if (m == 0)
     54 		return (0);
     55 
     56 	for (nf = 0; m[nf].type != mmt_end; nf++);
     57 	nf++;
     58 
     59 	new = am(myself, nf * sizeof (new[0]));
     60 	if (new == 0)
     61 		return (0);
     62 
     63 	/* Copy the whole array */
     64 	memcpy(new, m, nf * sizeof (new[0]));
     65 
     66 	/* Make copies of allocated stuff */
     67 	for (i = 0, err = 0; i < nf; i++) {
     68 		switch (m[i].type) {
     69 		case mmt_string:
     70 			new[i].match.string = sdup(myself, T,
     71 							m[i].match.string);
     72 			if (new[i].match.string == 0 && m[i].match.string != 0)
     73 				err++;
     74 			break;
     75 		case mmt_single:
     76 			new[i].match.single.lo =
     77 				am(myself, m[i].match.single.numRange *
     78 					sizeof (new[i].match.single.lo[0]));
     79 			new[i].match.single.hi =
     80 				am(myself, m[i].match.single.numRange *
     81 					sizeof (new[i].match.single.hi[0]));
     82 			if (new[i].match.single.lo != 0)
     83 				memcpy(new[i].match.single.lo,
     84 					m[i].match.single.lo,
     85 					m[i].match.single.numRange);
     86 			else if (m[i].match.single.lo != 0)
     87 				err++;
     88 			if (new[i].match.single.hi != 0)
     89 				memcpy(new[i].match.single.hi,
     90 					m[i].match.single.hi,
     91 					m[i].match.single.numRange);
     92 			else if (m[i].match.single.hi != 0)
     93 				err++;
     94 			break;
     95 		case mmt_berstring:
     96 			new[i].match.berString = sdup(myself, T,
     97 							m[i].match.berString);
     98 			if (new[i].match.berString == 0 &&
     99 					m[i].match.berString != 0)
    100 				err++;
    101 			break;
    102 		case mmt_item:
    103 		case mmt_limit:
    104 		case mmt_any:
    105 		case mmt_begin:
    106 		case mmt_end:
    107 		default:
    108 			break;
    109 		}
    110 	}
    111 
    112 	/* If there were memory allocation errors, free the copy */
    113 	if (err > 0) {
    114 		freeMappingFormat(new);
    115 		new = 0;
    116 	}
    117 
    118 	return (new);
    119 }
    120 
    121 void
    122 freeMappingFormat(__nis_mapping_format_t *m) {
    123 	int	i;
    124 
    125 	if (m == 0)
    126 		return;
    127 
    128 	for (i = 0; m[i].type != mmt_end; i++) {
    129 		switch (m[i].type) {
    130 		case mmt_string:
    131 			sfree(m[i].match.string);
    132 			break;
    133 		case mmt_single:
    134 			sfree(m[i].match.single.lo);
    135 			sfree(m[i].match.single.hi);
    136 			break;
    137 		case mmt_berstring:
    138 			sfree(m[i].match.berString);
    139 			break;
    140 		case mmt_item:
    141 		case mmt_limit:
    142 		case mmt_any:
    143 		case mmt_begin:
    144 		case mmt_end:
    145 		default:
    146 			break;
    147 		}
    148 	}
    149 
    150 	free(m);
    151 }
    152 
    153 
    154 void
    155 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) {
    156 	int	i;
    157 	char	*myself = "copyIndex";
    158 
    159 	if (old == 0 || new == 0) {
    160 		*err = EINVAL;
    161 		return;
    162 	}
    163 
    164 	for (i = 0; i < old->numIndexes; i++) {
    165 		new->name[i] = sdup(myself, T, old->name[i]);
    166 		if (new->name[i] == 0 && old->name[i] != 0) {
    167 			*err = ENOMEM;
    168 			return;
    169 		}
    170 		new->value[i] = cloneMappingFormat(old->value[i]);
    171 		if (new->value[i] == 0 && old->value[i] != 0) {
    172 			*err = ENOMEM;
    173 			return;
    174 		}
    175 	}
    176 
    177 	new->numIndexes = old->numIndexes;
    178 }
    179 
    180 __nis_index_t *
    181 cloneIndex(__nis_index_t *old) {
    182 	char		*myself = "cloneIndex";
    183 	int		err = 0;
    184 	__nis_index_t	*new = am(myself, sizeof (*new));
    185 
    186 	if (old == 0)
    187 		return (0);
    188 
    189 	if (new != 0) {
    190 		copyIndex(old, new, &err);
    191 		if (err != 0) {
    192 			freeIndex(new, 1);
    193 			new = 0;
    194 		}
    195 	}
    196 
    197 	return (new);
    198 }
    199 
    200 void
    201 freeIndex(__nis_index_t *old, bool_t doFree) {
    202 	int	i;
    203 
    204 	if (old == 0)
    205 		return;
    206 
    207 	for (i = 0; i < old->numIndexes; i++) {
    208 		sfree(old->name[i]);
    209 		freeMappingFormat(old->value[i]);
    210 	}
    211 
    212 	if (doFree)
    213 		free(old);
    214 }
    215 
    216 char **
    217 cloneName(char **name, int numNames) {
    218 	char	**new;
    219 	int	i;
    220 	char	*myself = "cloneName";
    221 
    222 	if (name == 0 || numNames <= 0)
    223 		return (0);
    224 
    225 	new = am(myself, numNames * sizeof (new[0]));
    226 	if (new == 0)
    227 		return (0);
    228 
    229 	for (i = 0; i < numNames; i++) {
    230 		if (name[i] != 0) {
    231 			new[i] = sdup(myself, T, name[i]);
    232 			if (new[i] == 0) {
    233 				for (i--; i >= 0; i--) {
    234 					sfree(new[i]);
    235 				}
    236 				sfree(new);
    237 				return (0);
    238 			}
    239 		} else {
    240 			new[i] = 0;
    241 		}
    242 	}
    243 
    244 	return (new);
    245 }
    246 
    247 void
    248 freeValue(__nis_value_t *val, int count) {
    249 	int	c, i;
    250 
    251 	if (val == 0)
    252 		return;
    253 
    254 	for (c = 0; c < count; c++) {
    255 		if (val[c].val != 0) {
    256 			for (i = 0; i < val[c].numVals; i++) {
    257 				sfree(val[c].val[i].value);
    258 			}
    259 			free(val[c].val);
    260 		}
    261 	}
    262 
    263 	free(val);
    264 }
    265 
    266 __nis_value_t *
    267 cloneValue(__nis_value_t *val, int count) {
    268 	__nis_value_t	*n;
    269 	int		c, i;
    270 	char		*myself = "cloneValue";
    271 
    272 	if (count <= 0 || val == 0)
    273 		return (0);
    274 
    275 	n = am(myself, count * sizeof (*n));
    276 	if (n == 0)
    277 		return (0);
    278 
    279 	for (c = 0; c < count; c++) {
    280 		n[c].type = val[c].type;
    281 		n[c].repeat = val[c].repeat;
    282 		n[c].numVals = val[c].numVals;
    283 		if (n[c].numVals > 0) {
    284 			n[c].val = am(myself, n[c].numVals *
    285 						sizeof (n[c].val[0]));
    286 			if (n[c].val == 0) {
    287 				freeValue(n, c);
    288 				return (0);
    289 			}
    290 		} else {
    291 			n[c].val = 0;
    292 		}
    293 		for (i = 0; i < n[c].numVals; i++) {
    294 			int	amlen = val[c].val[i].length;
    295 
    296 			/*
    297 			 * The functions that create string values try to
    298 			 * make sure that there's a NUL at the end. However,
    299 			 * both NIS+ and LDAP have a tendency to store strings
    300 			 * without a NUL, so the value length may not include
    301 			 * the NUL (even though it's there). In order to
    302 			 * preserve that NUL, we add a byte to the length if
    303 			 * the type is vt_string, and there isn't already a
    304 			 * NUL at the end. The memory allocation function
    305 			 * (am()) will take care of actually putting the NUL
    306 			 * in place, since it allocates zero-initialized
    307 			 * memory.
    308 			 */
    309 			n[c].val[i].length = val[c].val[i].length;
    310 			if (n[c].type == vt_string && amlen > 0 &&
    311 				((char *)val[c].val[i].value)[amlen-1] !=
    312 					'\0') {
    313 				amlen++;
    314 			}
    315 			n[c].val[i].value = am(myself, amlen);
    316 			if (amlen > 0 && n[c].val[i].value == 0) {
    317 				freeValue(n, c);
    318 				return (0);
    319 			}
    320 			memcpy(n[c].val[i].value, val[c].val[i].value,
    321 				n[c].val[i].length);
    322 		}
    323 	}
    324 
    325 	return (n);
    326 }
    327 
    328 /* Define LBER_USE_DER per ber_decode(3LDAP) */
    329 #ifndef	LBER_USE_DER
    330 #define	LBER_USE_DER	0x01
    331 #endif	/* LBER_USE_DER */
    332 
    333 /*
    334  * Return a copy of 'valIn' where each value has been replaced by the
    335  * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged.
    336  */
    337 __nis_value_t *
    338 berEncode(__nis_value_t *valIn, char *berstring) {
    339 	char		*myself = "berEncode";
    340 	__nis_value_t	*val;
    341 	int		i;
    342 
    343 	if (valIn == 0 || berstring == 0)
    344 		return (0);
    345 
    346 	val = cloneValue(valIn, 1);
    347 	if (val == 0)
    348 		return (0);
    349 
    350 	for (i = 0; i < val->numVals; i++) {
    351 		BerElement	*ber = ber_alloc();
    352 		struct berval	*bv = 0;
    353 		int		ret;
    354 
    355 		if (ber == 0) {
    356 			logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL",
    357 				myself);
    358 			freeValue(val, 1);
    359 			return (0);
    360 		}
    361 
    362 		if ((strcmp("b", berstring) == 0 ||
    363 				strcmp("i", berstring) == 0)) {
    364 			if (val->val[i].length >= sizeof (int)) {
    365 				ret = ber_printf(ber, berstring,
    366 					*((int *)(val->val[i].value)));
    367 			} else {
    368 				ret = -1;
    369 			}
    370 		} else if (strcmp("B", berstring) == 0) {
    371 			ret = ber_printf(ber, berstring,
    372 				val->val[i].value,
    373 				val->val[i].length * 8);
    374 		} else if (strcmp("n", berstring) == 0) {
    375 			ret = ber_printf(ber, berstring);
    376 		} else if (strcmp("o", berstring) == 0) {
    377 			ret = ber_printf(ber, berstring,
    378 				val->val[i].value, val->val[i].length);
    379 		} else if (strcmp("s", berstring) == 0) {
    380 			char	*str = am(myself, val->val[i].length + 1);
    381 
    382 			if (str != 0) {
    383 				ret = ber_printf(ber, berstring, str);
    384 				free(str);
    385 			} else {
    386 				ret = -1;
    387 			}
    388 		} else {
    389 			ret = -1;
    390 		}
    391 
    392 		if (ret == -1) {
    393 			reportError(NPL_BERENCODE, "%s: BER encoding error",
    394 					myself);
    395 			ber_free(ber, 1);
    396 			freeValue(val, 1);
    397 			return (0);
    398 		}
    399 
    400 		if (ber_flatten(ber, &bv) != 0 || bv == 0) {
    401 			reportError(NPL_BERENCODE, "%s: ber_flatten() error",
    402 					myself);
    403 			ber_free(ber, 1);
    404 			freeValue(val, 1);
    405 			return (0);
    406 		}
    407 
    408 		sfree(val->val[i].value);
    409 		val->val[i].length = bv->bv_len;
    410 		val->val[i].value = bv->bv_val;
    411 
    412 		ber_free(ber, 1);
    413 	}
    414 
    415 	val->type = vt_ber;
    416 
    417 	return (val);
    418 }
    419 
    420 __nis_value_t *
    421 berDecode(__nis_value_t *valIn, char *berstring) {
    422 	__nis_value_t	*val;
    423 	int		i;
    424 	char		*myself = "berDecode";
    425 
    426 	if (valIn == 0 || berstring == 0)
    427 		return (0);
    428 
    429 	val = cloneValue(valIn, 1);
    430 	if (val == 0)
    431 		return (0);
    432 
    433 	for (i = 0; i < val->numVals; i++) {
    434 		void		*v = 0;
    435 		int		ret, len = 0;
    436 		struct berval	bv;
    437 		BerElement	*ber;
    438 
    439 		if (val->val[i].value == 0 || val->val[i].length <= 0)
    440 			continue;
    441 
    442 		bv.bv_val = val->val[i].value;
    443 		bv.bv_len = val->val[i].length;
    444 		ber = ber_init(&bv);
    445 		if (ber == 0) {
    446 			reportError(NPL_BERDECODE, "%s: ber_init() error",
    447 				myself);
    448 			freeValue(val, 1);
    449 			return (0);
    450 		}
    451 
    452 		if ((strcmp("b", berstring) == 0 ||
    453 				strcmp("i", berstring) == 0)) {
    454 			len = sizeof (int);
    455 			v = am(myself, len);
    456 			if (v != 0) {
    457 				ret = ber_scanf(ber, berstring, v);
    458 			} else {
    459 				ret = -1;
    460 			}
    461 		} else if (strcmp("B", berstring) == 0) {
    462 			long	llen;
    463 
    464 			ret = ber_scanf(ber, berstring, &v, &llen);
    465 			if (ret != -1) {
    466 				len = llen/8;
    467 			}
    468 		} else if (strcmp("n", berstring) == 0) {
    469 			ret = 0;
    470 		} else if (strcmp("o", berstring) == 0) {
    471 			struct berval	*bv = am(myself, sizeof (*bv));
    472 
    473 			if (bv != 0) {
    474 				ret = ber_scanf(ber, "O", &bv);
    475 				if (ret != -1 && bv != 0) {
    476 					v = bv->bv_val;
    477 					len = bv->bv_len;
    478 				} else {
    479 					ret = -1;
    480 				}
    481 				/* Only free 'bv' itself */
    482 				free(bv);
    483 			} else {
    484 				ret = -1;
    485 			}
    486 		} else if (strcmp("s", berstring) == 0) {
    487 			ret = ber_scanf(ber, "a", &v);
    488 			if (ret != -1) {
    489 				len = slen(v);
    490 			}
    491 		} else {
    492 			ret = -1;
    493 		}
    494 
    495 		if (ret == -1) {
    496 			reportError(NPL_BERDECODE, "%s: BER decoding error",
    497 					myself);
    498 			freeValue(val, 1);
    499 			return (0);
    500 		}
    501 
    502 		/* Free the old value, and replace it with the decoded one */
    503 		sfree(val->val[i].value);
    504 		val->val[i].value = v;
    505 		val->val[i].length = len;
    506 	}
    507 
    508 	return (val);
    509 }
    510 
    511 /*
    512  * Return the value of the specified item.
    513  */
    514 __nis_value_t *
    515 getMappingItemVal(__nis_mapping_item_t *item, __nis_mapping_item_type_t native,
    516 		__nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
    517 	__nis_value_t				*val = 0, *nameVal, *exVal = 0;
    518 	int					numName, caseInsens, cmp;
    519 	int					i, j, k;
    520 	char					**name;
    521 	enum {rvOnly, rvThenLookup, lookupOnly}	check;
    522 	unsigned char				fromldap = '\0';
    523 
    524 	if (item == 0)
    525 		return (0);
    526 
    527 	/*
    528 	 * First, we decide if we should look for the value in 'rv',
    529 	 * directly from NIS+/LDAP, or both.
    530 	 */
    531 	switch (item->type) {
    532 	case mit_nisplus:
    533 		/* Do we have a valid index/object spec ? */
    534 		if (item->searchSpec.obj.index.numIndexes <= 0 &&
    535 				item->searchSpec.obj.name == 0) {
    536 			/*
    537 			 * No valid index/object. If we have a rule-value,
    538 			 * use it. Otherwise, return error.
    539 			 */
    540 			if (rv != 0) {
    541 				name = rv->colName;
    542 				nameVal = rv->colVal;
    543 				numName = rv->numColumns;
    544 				caseInsens = 0;
    545 				check = rvOnly;
    546 			} else {
    547 				return (0);
    548 			}
    549 		} else {
    550 			/*
    551 			 * Valid index, so skip the rule-value and do
    552 			 * a direct NIS+ lookup.
    553 			 */
    554 			check = lookupOnly;
    555 		}
    556 		break;
    557 	case mit_ldap:
    558 		if (rv != 0) {
    559 			name = rv->attrName;
    560 			nameVal = rv->attrVal;
    561 			numName = rv->numAttrs;
    562 			caseInsens = 1;
    563 			fromldap = '1';
    564 		}
    565 		/* Do we have a valid triple ? */
    566 		if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) {
    567 			/*
    568 			 * No valid triple. If we have a rule-value, use it.
    569 			 * Otherwise, return error.
    570 			 */
    571 			if (rv != 0) {
    572 				check = rvOnly;
    573 			} else {
    574 				return (0);
    575 			}
    576 		} else if (item->searchSpec.triple.base == 0 &&
    577 				item->searchSpec.triple.scope ==
    578 					LDAP_SCOPE_ONELEVEL &&
    579 				item->searchSpec.triple.attrs == 0 &&
    580 				item->searchSpec.triple.element == 0) {
    581 			/*
    582 			 * We have a valid triple, but it points to the
    583 			 * current LDAP container. Thus, first look in
    584 			 * the rule-value; if that fails, perform a direct
    585 			 * LDAP lookup.
    586 			 */
    587 			if (rv != 0) {
    588 				check = rvThenLookup;
    589 			} else {
    590 				check = lookupOnly;
    591 			}
    592 		} else {
    593 			/*
    594 			 * Valid triple, and it's not the current container
    595 			 * (at least not in the trivial sense). Hence, do
    596 			 * a direct LDAP lookup.
    597 			 */
    598 			check = lookupOnly;
    599 		}
    600 		break;
    601 	default:
    602 		return (0);
    603 	}
    604 
    605 	/* Check the rule-value */
    606 	if (check == rvOnly || check == rvThenLookup) {
    607 		for (i = 0; i < numName; i++) {
    608 			if (caseInsens)
    609 				cmp = strcasecmp(item->name, name[i]);
    610 			else
    611 				cmp = strcmp(item->name, name[i]);
    612 			if (cmp == 0) {
    613 				if (nameVal[i].numVals <= 0)
    614 					break;
    615 				if (berstring == 0) {
    616 					val = cloneValue(&nameVal[i], 1);
    617 				} else if (yp2ldap && berstring[0] == 'a') {
    618 					val = cloneValue(&nameVal[i], 1);
    619 				} else {
    620 					val = berDecode(&nameVal[i],
    621 						berstring);
    622 				}
    623 				if (val != 0) {
    624 					val->repeat = item->repeat;
    625 					/*
    626 					 * If value for nis+ column is
    627 					 * passed with value, val is
    628 					 * manipulated in cloneValue().
    629 					 * To decide whether there are
    630 					 * enough nis+ column values
    631 					 * for rule to produce a value,
    632 					 * we need nis+ column values
    633 					 * as well as nis_mapping_element
    634 					 * from the rule. If we are here,
    635 					 * it indicates that the 'val has
    636 					 * an valid value for the column
    637 					 * item-> name. So set
    638 					 * NP_LDAP_MAP_SUCCESS
    639 					 * to np_ldap-stat.
    640 					 */
    641 
    642 					if (np_ldap_stat != NULL)
    643 						*np_ldap_stat =
    644 							NP_LDAP_MAP_SUCCESS;
    645 				}
    646 				break;
    647 			}
    648 		}
    649 	}
    650 
    651 	/* Do a direct lookup ? */
    652 	if (val == 0 && (check == rvThenLookup || check == lookupOnly)) {
    653 		if (item->type == mit_nisplus) {
    654 			val = lookupNisPlus(&item->searchSpec.obj, item->name,
    655 						rv);
    656 		} else if (item->type == mit_ldap) {
    657 			int	err = 0;
    658 			__nis_search_triple_t	triple;
    659 			char			*baseDN;
    660 
    661 			/*
    662 			 * If item->searchSpec.triple.base is NULL, or ends
    663 			 * in a comma, append the current search base from
    664 			 * the TSD (put there by an upper layer).
    665 			 *
    666 			 * Special case for N2L mode:
    667 			 * if item->searchSpec.triple.base ends in a comma,
    668 			 * the current domain Context is used.
    669 			 */
    670 			if (yp2ldap && item->searchSpec.triple.base &&
    671 				strlen(item->searchSpec.triple.base) > 0) {
    672 				baseDN = __nisdb_get_tsd()->domainContext;
    673 			} else {
    674 				baseDN = __nisdb_get_tsd()->searchBase;
    675 			}
    676 			triple.base = appendBase(item->searchSpec.triple.base,
    677 				baseDN, &err, 0);
    678 			if (err == 0) {
    679 				triple.scope = item->searchSpec.triple.scope;
    680 				triple.attrs = item->searchSpec.triple.attrs;
    681 				triple.element =
    682 					item->searchSpec.triple.element;
    683 				val = lookupLDAP(&triple, item->name, rv, 0,
    684 					np_ldap_stat);
    685 				fromldap = '1';
    686 			} else {
    687 				val = 0;
    688 			}
    689 			sfree(triple.base);
    690 		}
    691 	}
    692 
    693 
    694 	/* Special processing for NIS to LDAP mode */
    695 	if (yp2ldap && val != 0) {
    696 
    697 		/*
    698 		 * Escape special chars from dn before sending to DIT,
    699 		 * provided val is not ldap-based
    700 		 */
    701 		if (fromldap == '\0' && __nisdb_get_tsd()->escapeFlag == '1') {
    702 			if (escapeSpecialChars(val) < 0) {
    703 				freeValue(val, 1);
    704 				return (0);
    705 			}
    706 		} else if (__nisdb_get_tsd()->escapeFlag == '2') {
    707 			/* Remove escape chars from data received from DIT */
    708 			(void) removeEscapeChars(val);
    709 		}
    710 
    711 		/*
    712 		 * Remove from 'val', any values obtained using
    713 		 * the 'removespec' syntax
    714 		 */
    715 
    716 		/* Obtain exVal */
    717 		if (item->exItem)
    718 			exVal = getMappingItemVal(item->exItem, native, rv,
    719 			    berstring, NULL);
    720 
    721 		/* delete */
    722 		if (exVal != 0) {
    723 			for (i = 0; i < val->numVals; ) {
    724 				for (j = 0; j < exVal->numVals; j++) {
    725 					if (sstrncmp(val->val[i].value,
    726 							exVal->val[j].value,
    727 							MAX(val->val[i].length,
    728 							exVal->val[j].length))
    729 							== 0)
    730 						break;
    731 				}
    732 				if (j < exVal->numVals) {
    733 					sfree(val->val[i].value);
    734 					val->val[i].value = 0;
    735 					val->val[i].length = 0;
    736 					for (k = i; k < val->numVals - 1; k++) {
    737 						val->val[k] = val->val[k + 1];
    738 						val->val[k + 1].value = 0;
    739 						val->val[k + 1].length = 0;
    740 					}
    741 					val->numVals--;
    742 				} else
    743 					i++;
    744 			}
    745 
    746 			freeValue(exVal, 1);
    747 
    748 			/*
    749 			 * If val->numVals <= 0, then we have no val to
    750 			 * return. So free up stuff.
    751 			 */
    752 			if (val->numVals <= 0) {
    753 				free(val->val);
    754 				val->val = 0;
    755 				free(val);
    756 				return (0);
    757 			}
    758 		}
    759 	}
    760 
    761 	return (val);
    762 }
    763 
    764 __nis_value_t *
    765 getMappingFormat(__nis_mapping_format_t *f, __nis_rule_value_t *rv,
    766 			__nis_format_arg_t at, void *a, int *numArg) {
    767 	char		*myself = "getMappingFormat";
    768 	__nis_value_t	*val = 0;
    769 	__nis_buffer_t	b = {0, 0};
    770 	int		i;
    771 
    772 	if (f == 0)
    773 		return (0);
    774 
    775 	if (rv == 0) {
    776 		val = am(myself, sizeof (*val));
    777 		if (val == 0)
    778 			return (0);
    779 
    780 		switch (f->type) {
    781 		case mmt_item:
    782 			bp2buf(myself, &b, "%%s");
    783 			break;
    784 		case mmt_string:
    785 			bp2buf(myself, &b, "%s", NIL(f->match.string));
    786 			break;
    787 		case mmt_single:
    788 			bp2buf(myself, &b, "[");
    789 			for (i = 0; i < f->match.single.numRange; i++) {
    790 				if (f->match.single.lo[i] ==
    791 						f->match.single.hi[i])
    792 					bp2buf(myself, &b, "%c",
    793 						f->match.single.lo[i]);
    794 				else
    795 					bp2buf(myself, &b, "%c-%c",
    796 						f->match.single.lo[i],
    797 						f->match.single.hi[i]);
    798 			}
    799 			bp2buf(myself, &b, "]");
    800 			break;
    801 		case mmt_limit:
    802 			break;
    803 		case mmt_any:
    804 			bp2buf(myself, &b, "*");
    805 			break;
    806 		case mmt_berstring:
    807 			bp2buf(myself, &b, "%s", NIL(f->match.berString));
    808 			break;
    809 		case mmt_begin:
    810 		case mmt_end:
    811 			bp2buf(myself, &b, "\"");
    812 			break;
    813 		default:
    814 			bp2buf(myself, &b, "<unknown>");
    815 		}
    816 		val->type = vt_string;
    817 		val->numVals = 1;
    818 		val->val = am(myself, sizeof (val->val[0]));
    819 		if (val->val == 0) {
    820 			sfree(val);
    821 			return (0);
    822 		}
    823 		val->val[0].value = b.buf;
    824 		val->val[0].length = b.len;
    825 	} else {
    826 		switch (f->type) {
    827 		case mmt_item:
    828 		case mmt_berstring:
    829 			if (a != 0) {
    830 				if (at == fa_item) {
    831 					val = getMappingItemVal(
    832 						(__nis_mapping_item_t *)a,
    833 						mit_any, rv,
    834 		(f->type == mmt_berstring) ? f->match.berString : 0, NULL);
    835 					if (numArg != 0)
    836 						(*numArg)++;
    837 				} else {
    838 					val = cloneValue(
    839 						(__nis_value_t *)a, 1);
    840 					if (numArg != 0)
    841 						(*numArg)++;
    842 				}
    843 			}
    844 			break;
    845 		case mmt_string:
    846 			val = am(myself, sizeof (*val));
    847 			if (val == 0)
    848 				return (0);
    849 			val->type = vt_string;
    850 			val->numVals = 1;
    851 			val->val = am(myself, sizeof (val->val[0]));
    852 			if (val->val == 0) {
    853 				sfree(val);
    854 				return (0);
    855 			}
    856 			val->val[0].value = sdup(myself, T, f->match.string);
    857 			val->val[0].length = strlen(val->val[0].value);
    858 			break;
    859 		case mmt_single:
    860 		case mmt_limit:
    861 		case mmt_any:
    862 		case mmt_begin:
    863 		case mmt_end:
    864 			/* Not an error, so return an empty value */
    865 			val = am(myself, sizeof (*val));
    866 			if (val == 0)
    867 				return (0);
    868 			val->type = vt_string;
    869 			val->numVals = 0;
    870 			val->val = 0;
    871 			break;
    872 		default:
    873 			/* Do nothing */
    874 			val = 0;
    875 			break;
    876 		}
    877 	}
    878 	return (val);
    879 }
    880 
    881 /*
    882  * Used when evaluating an expression. Typically, the value of the
    883  * expression so far will be kept in 'v1', and 'v2' is the value
    884  * of the current component of the expression. In the general case,
    885  * both will be multi-valued, and the result is an "explosion"
    886  * resulting in N*M new values (if 'v1' had N values, and 'v2'
    887  * M ditto).
    888  *
    889  * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"},
    890  * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl",
    891  * "efgh", "efij", "efkl"}.
    892  *
    893  * There are special cases when v1->repeat and/or v2->repeat are set.
    894  * Repeat mostly makes sense with single values; for example, if
    895  * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result
    896  * is {"x=1", "x=2", "x=3"}.
    897  *
    898  * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's
    899  * not clear if there's a useful application for this, but the code's
    900  * there for the sake of orthogonality.
    901  */
    902 __nis_value_t *
    903 explodeValues(__nis_value_t *v1, __nis_value_t *v2) {
    904 	int		i1, i2, n, nv;
    905 	__nis_value_t	*v;
    906 	__nis_buffer_t	b = {0, 0};
    907 	char		*myself = "explodeValues";
    908 
    909 	if (v1 == 0 || v1->numVals <= 0)
    910 		return (cloneValue(v2, 1));
    911 	if (v2 == 0 || v2->numVals <= 0)
    912 		return (cloneValue(v1, 1));
    913 
    914 	/*
    915 	 * XXX What should we do if (v1->type != v2->type) ?
    916 	 * Policy: Just explode anyway, even though the result is
    917 	 * unlikely to be very useful.
    918 	 */
    919 
    920 	v = am(myself, sizeof (*v));
    921 	if (v == 0)
    922 		return (0);
    923 
    924 	if (!v1->repeat && !v2->repeat)
    925 		nv = v1->numVals * v2->numVals;
    926 	else if (v1->repeat && !v2->repeat)
    927 		nv = v2->numVals;
    928 	else if (!v1->repeat && v2->repeat)
    929 		nv = v1->numVals;
    930 	else /* v1->repeat && v2->repeat */
    931 		nv = 1;
    932 
    933 	v->val = am(myself, nv * sizeof (v->val[0]));
    934 	if (v->val == 0) {
    935 		free(v);
    936 		return (0);
    937 	}
    938 
    939 	/*
    940 	 * Four different cases, depending on the 'repeat' flags.
    941 	 */
    942 	if (!v1->repeat && !v2->repeat) {
    943 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
    944 			for (i2 = 0; i2 < v2->numVals; i2++) {
    945 				if (v1->type == vt_string)
    946 					sbc2buf(myself, v1->val[i1].value,
    947 						v1->val[i1].length,
    948 						&b);
    949 				else
    950 					bc2buf(myself, v1->val[i1].value,
    951 						v1->val[i1].length,
    952 						&b);
    953 				if (v2->type == vt_string)
    954 					sbc2buf(myself, v2->val[i2].value,
    955 						v2->val[i2].length,
    956 						&b);
    957 				else
    958 					bc2buf(myself, v2->val[i2].value,
    959 						v2->val[i2].length,
    960 						&b);
    961 				v->val[n].value = b.buf;
    962 				v->val[n].length = b.len;
    963 				n++;
    964 				b.buf = 0;
    965 				b.len = 0;
    966 			}
    967 		}
    968 	} else if (v1->repeat && !v2->repeat) {
    969 		for (i2 = 0; i2 < v2->numVals; i2++) {
    970 			for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
    971 				if (v1->type == vt_string)
    972 					sbc2buf(myself, v1->val[i1].value,
    973 						v1->val[i1].length,
    974 						&b);
    975 				else
    976 					bc2buf(myself, v1->val[i1].value,
    977 						v1->val[i1].length,
    978 						&b);
    979 				if (v2->type == vt_string)
    980 					sbc2buf(myself, v2->val[i2].value,
    981 						v2->val[i2].length,
    982 						&b);
    983 				else
    984 					bc2buf(myself, v2->val[i2].value,
    985 						v2->val[i2].length,
    986 						&b);
    987 			}
    988 			v->val[n].value = b.buf;
    989 			v->val[n].length = b.len;
    990 			n++;
    991 			b.buf = 0;
    992 			b.len = 0;
    993 		}
    994 	} else if (!v1->repeat && v2->repeat) {
    995 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
    996 			for (i2 = 0; i2 < v2->numVals; i2++) {
    997 				if (v1->type == vt_string)
    998 					sbc2buf(myself, v1->val[i1].value,
    999 						v1->val[i1].length,
   1000 						&b);
   1001 				else
   1002 					bc2buf(myself, v1->val[i1].value,
   1003 						v1->val[i1].length,
   1004 						&b);
   1005 				if (v2->type == vt_string)
   1006 					sbc2buf(myself, v2->val[i2].value,
   1007 						v2->val[i2].length,
   1008 						&b);
   1009 				else
   1010 					bc2buf(myself, v2->val[i2].value,
   1011 						v2->val[i2].length,
   1012 						&b);
   1013 			}
   1014 			v->val[n].value = b.buf;
   1015 			v->val[n].length = b.len;
   1016 			n++;
   1017 			b.buf = 0;
   1018 			b.len = 0;
   1019 		}
   1020 	} else { /* v1->repeat && v2->repeat */
   1021 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
   1022 			for (i2 = 0; i2 < v2->numVals; i2++) {
   1023 				if (v1->type == vt_string)
   1024 					sbc2buf(myself, v1->val[i1].value,
   1025 						v1->val[i1].length,
   1026 						&b);
   1027 				else
   1028 					bc2buf(myself, v1->val[i1].value,
   1029 						v1->val[i1].length,
   1030 						&b);
   1031 				if (v2->type == vt_string)
   1032 					sbc2buf(myself, v2->val[i2].value,
   1033 						v2->val[i2].length,
   1034 						&b);
   1035 				else
   1036 					bc2buf(myself, v2->val[i2].value,
   1037 						v2->val[i2].length,
   1038 						&b);
   1039 			}
   1040 		}
   1041 		v->val[n].value = b.buf;
   1042 		v->val[n].length = b.len;
   1043 		n++;
   1044 		b.buf = 0;
   1045 		b.len = 0;
   1046 	}
   1047 
   1048 #ifdef	NISDB_LDAP_DEBUG
   1049 	/* Sanity check */
   1050 	if (n != nv)
   1051 		abort();
   1052 #endif	/* NISD__LDAP_DEBUG */
   1053 
   1054 	v->type = (v1->type == vt_string) ?
   1055 			((v2->type == vt_string) ?
   1056 				vt_string : vt_ber) : vt_ber;
   1057 	v->repeat = 0;
   1058 	v->numVals = n;
   1059 
   1060 	return (v);
   1061 }
   1062 
   1063 __nis_value_t *
   1064 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv,
   1065 			__nis_format_arg_t at, int numArgs, void *arg) {
   1066 	int			i, ia = 0;
   1067 	__nis_value_t		*val, *v = 0;
   1068 	bool_t			moreFormat = (a != 0);
   1069 	bool_t			moreArgs = (numArgs > 0);
   1070 
   1071 	while (moreFormat && (arg == 0 || ia < numArgs)) {
   1072 		for (i = 0; moreFormat; i++) {
   1073 			moreFormat = (a[i].type != mmt_end);
   1074 			if (at == fa_item) {
   1075 				__nis_mapping_item_t *item = arg;
   1076 				val = getMappingFormat(&a[i], rv, at,
   1077 					((item != 0) ? &item[ia] : 0), &ia);
   1078 			} else {
   1079 				__nis_value_t **ival = arg;
   1080 				val = getMappingFormat(&a[i], rv, at,
   1081 					((ival != 0) ? ival[ia] : 0), &ia);
   1082 			}
   1083 			if (val != 0) {
   1084 				__nis_value_t	*new = explodeValues(v, val);
   1085 
   1086 				freeValue(v, 1);
   1087 				freeValue(val, 1);
   1088 				if (new == 0)
   1089 					return (0);
   1090 
   1091 				v = new;
   1092 			} else {
   1093 				freeValue(v, 1);
   1094 				return (0);
   1095 			}
   1096 			/*
   1097 			 * If we run out of arguments, but still have format
   1098 			 * remaining, repeat the last argument. Keep track of
   1099 			 * the fact that we've really consumed all arguments.
   1100 			 */
   1101 			if (moreFormat &&