xref: /illumos-gate/usr/src/lib/libnisdb/ldap_val.c (revision f78cdc34af236a6199dd9e21376f4a46348c0d56)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2015 Gary Mills
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <lber.h>
29 #include <ldap.h>
30 #include <strings.h>
31 #include <errno.h>
32 
33 #include "nisdb_mt.h"
34 
35 #include "ldap_util.h"
36 #include "ldap_op.h"
37 #include "ldap_ruleval.h"
38 #include "ldap_attr.h"
39 #include "ldap_val.h"
40 #include "ldap_ldap.h"
41 
42 extern int yp2ldap;
43 
44 
45 __nis_mapping_format_t *
46 cloneMappingFormat(__nis_mapping_format_t *m) {
47 	__nis_mapping_format_t	*new;
48 	int			i, nf, err;
49 	char			*myself = "cloneMappingFormat";
50 
51 	if (m == 0)
52 		return (0);
53 
54 	for (nf = 0; m[nf].type != mmt_end; nf++);
55 	nf++;
56 
57 	new = am(myself, nf * sizeof (new[0]));
58 	if (new == 0)
59 		return (0);
60 
61 	/* Copy the whole array */
62 	memcpy(new, m, nf * sizeof (new[0]));
63 
64 	/* Make copies of allocated stuff */
65 	for (i = 0, err = 0; i < nf; i++) {
66 		switch (m[i].type) {
67 		case mmt_string:
68 			new[i].match.string = sdup(myself, T,
69 							m[i].match.string);
70 			if (new[i].match.string == 0 && m[i].match.string != 0)
71 				err++;
72 			break;
73 		case mmt_single:
74 			new[i].match.single.lo =
75 				am(myself, m[i].match.single.numRange *
76 					sizeof (new[i].match.single.lo[0]));
77 			new[i].match.single.hi =
78 				am(myself, m[i].match.single.numRange *
79 					sizeof (new[i].match.single.hi[0]));
80 			if (new[i].match.single.lo != 0)
81 				memcpy(new[i].match.single.lo,
82 					m[i].match.single.lo,
83 					m[i].match.single.numRange);
84 			else if (m[i].match.single.lo != 0)
85 				err++;
86 			if (new[i].match.single.hi != 0)
87 				memcpy(new[i].match.single.hi,
88 					m[i].match.single.hi,
89 					m[i].match.single.numRange);
90 			else if (m[i].match.single.hi != 0)
91 				err++;
92 			break;
93 		case mmt_berstring:
94 			new[i].match.berString = sdup(myself, T,
95 							m[i].match.berString);
96 			if (new[i].match.berString == 0 &&
97 					m[i].match.berString != 0)
98 				err++;
99 			break;
100 		case mmt_item:
101 		case mmt_limit:
102 		case mmt_any:
103 		case mmt_begin:
104 		case mmt_end:
105 		default:
106 			break;
107 		}
108 	}
109 
110 	/* If there were memory allocation errors, free the copy */
111 	if (err > 0) {
112 		freeMappingFormat(new);
113 		new = 0;
114 	}
115 
116 	return (new);
117 }
118 
119 void
120 freeMappingFormat(__nis_mapping_format_t *m) {
121 	int	i;
122 
123 	if (m == 0)
124 		return;
125 
126 	for (i = 0; m[i].type != mmt_end; i++) {
127 		switch (m[i].type) {
128 		case mmt_string:
129 			sfree(m[i].match.string);
130 			break;
131 		case mmt_single:
132 			sfree(m[i].match.single.lo);
133 			sfree(m[i].match.single.hi);
134 			break;
135 		case mmt_berstring:
136 			sfree(m[i].match.berString);
137 			break;
138 		case mmt_item:
139 		case mmt_limit:
140 		case mmt_any:
141 		case mmt_begin:
142 		case mmt_end:
143 		default:
144 			break;
145 		}
146 	}
147 
148 	free(m);
149 }
150 
151 
152 void
153 copyIndex(__nis_index_t *old, __nis_index_t *new, int *err) {
154 	int	i;
155 	char	*myself = "copyIndex";
156 
157 	if (old == 0 || new == 0) {
158 		*err = EINVAL;
159 		return;
160 	}
161 
162 	for (i = 0; i < old->numIndexes; i++) {
163 		new->name[i] = sdup(myself, T, old->name[i]);
164 		if (new->name[i] == 0 && old->name[i] != 0) {
165 			*err = ENOMEM;
166 			return;
167 		}
168 		new->value[i] = cloneMappingFormat(old->value[i]);
169 		if (new->value[i] == 0 && old->value[i] != 0) {
170 			*err = ENOMEM;
171 			return;
172 		}
173 	}
174 
175 	new->numIndexes = old->numIndexes;
176 }
177 
178 __nis_index_t *
179 cloneIndex(__nis_index_t *old) {
180 	char		*myself = "cloneIndex";
181 	int		err = 0;
182 	__nis_index_t	*new = am(myself, sizeof (*new));
183 
184 	if (old == 0)
185 		return (0);
186 
187 	if (new != 0) {
188 		copyIndex(old, new, &err);
189 		if (err != 0) {
190 			freeIndex(new, 1);
191 			new = 0;
192 		}
193 	}
194 
195 	return (new);
196 }
197 
198 void
199 freeIndex(__nis_index_t *old, bool_t doFree) {
200 	int	i;
201 
202 	if (old == 0)
203 		return;
204 
205 	for (i = 0; i < old->numIndexes; i++) {
206 		sfree(old->name[i]);
207 		freeMappingFormat(old->value[i]);
208 	}
209 
210 	if (doFree)
211 		free(old);
212 }
213 
214 char **
215 cloneName(char **name, int numNames) {
216 	char	**new;
217 	int	i;
218 	char	*myself = "cloneName";
219 
220 	if (name == 0 || numNames <= 0)
221 		return (0);
222 
223 	new = am(myself, numNames * sizeof (new[0]));
224 	if (new == 0)
225 		return (0);
226 
227 	for (i = 0; i < numNames; i++) {
228 		if (name[i] != 0) {
229 			new[i] = sdup(myself, T, name[i]);
230 			if (new[i] == 0) {
231 				for (i--; i >= 0; i--) {
232 					sfree(new[i]);
233 				}
234 				sfree(new);
235 				return (0);
236 			}
237 		} else {
238 			new[i] = 0;
239 		}
240 	}
241 
242 	return (new);
243 }
244 
245 void
246 freeValue(__nis_value_t *val, int count) {
247 	int	c, i;
248 
249 	if (val == 0)
250 		return;
251 
252 	for (c = 0; c < count; c++) {
253 		if (val[c].val != 0) {
254 			for (i = 0; i < val[c].numVals; i++) {
255 				sfree(val[c].val[i].value);
256 			}
257 			free(val[c].val);
258 		}
259 	}
260 
261 	free(val);
262 }
263 
264 __nis_value_t *
265 cloneValue(__nis_value_t *val, int count) {
266 	__nis_value_t	*n;
267 	int		c, i;
268 	char		*myself = "cloneValue";
269 
270 	if (count <= 0 || val == 0)
271 		return (0);
272 
273 	n = am(myself, count * sizeof (*n));
274 	if (n == 0)
275 		return (0);
276 
277 	for (c = 0; c < count; c++) {
278 		n[c].type = val[c].type;
279 		n[c].repeat = val[c].repeat;
280 		n[c].numVals = val[c].numVals;
281 		if (n[c].numVals > 0) {
282 			n[c].val = am(myself, n[c].numVals *
283 						sizeof (n[c].val[0]));
284 			if (n[c].val == 0) {
285 				freeValue(n, c);
286 				return (0);
287 			}
288 		} else {
289 			n[c].val = 0;
290 		}
291 		for (i = 0; i < n[c].numVals; i++) {
292 			int	amlen = val[c].val[i].length;
293 
294 			/*
295 			 * The functions that create string values try to
296 			 * make sure that there's a NUL at the end. However,
297 			 * both NIS+ and LDAP have a tendency to store strings
298 			 * without a NUL, so the value length may not include
299 			 * the NUL (even though it's there). In order to
300 			 * preserve that NUL, we add a byte to the length if
301 			 * the type is vt_string, and there isn't already a
302 			 * NUL at the end. The memory allocation function
303 			 * (am()) will take care of actually putting the NUL
304 			 * in place, since it allocates zero-initialized
305 			 * memory.
306 			 */
307 			n[c].val[i].length = val[c].val[i].length;
308 			if (n[c].type == vt_string && amlen > 0 &&
309 				((char *)val[c].val[i].value)[amlen-1] !=
310 					'\0') {
311 				amlen++;
312 			}
313 			n[c].val[i].value = am(myself, amlen);
314 			if (amlen > 0 && n[c].val[i].value == 0) {
315 				freeValue(n, c);
316 				return (0);
317 			}
318 			memcpy(n[c].val[i].value, val[c].val[i].value,
319 				n[c].val[i].length);
320 		}
321 	}
322 
323 	return (n);
324 }
325 
326 /* Define LBER_USE_DER per ber_decode(3LDAP) */
327 #ifndef	LBER_USE_DER
328 #define	LBER_USE_DER	0x01
329 #endif	/* LBER_USE_DER */
330 
331 /*
332  * Return a copy of 'valIn' where each value has been replaced by the
333  * BER encoded equivalent specified by 'berstring'. 'valIn' is unchanged.
334  */
335 __nis_value_t *
336 berEncode(__nis_value_t *valIn, char *berstring) {
337 	char		*myself = "berEncode";
338 	__nis_value_t	*val;
339 	int		i;
340 
341 	if (valIn == 0 || berstring == 0)
342 		return (0);
343 
344 	val = cloneValue(valIn, 1);
345 	if (val == 0)
346 		return (0);
347 
348 	for (i = 0; i < val->numVals; i++) {
349 		BerElement	*ber = ber_alloc();
350 		struct berval	*bv = 0;
351 		int		ret;
352 
353 		if (ber == 0) {
354 			logmsg(MSG_NOMEM, LOG_ERR, "%s: ber_alloc() => NULL",
355 				myself);
356 			freeValue(val, 1);
357 			return (0);
358 		}
359 
360 		if ((strcmp("b", berstring) == 0 ||
361 				strcmp("i", berstring) == 0)) {
362 			if (val->val[i].length >= sizeof (int)) {
363 				ret = ber_printf(ber, berstring,
364 					*((int *)(val->val[i].value)));
365 			} else {
366 				ret = -1;
367 			}
368 		} else if (strcmp("B", berstring) == 0) {
369 			ret = ber_printf(ber, berstring,
370 				val->val[i].value,
371 				val->val[i].length * 8);
372 		} else if (strcmp("n", berstring) == 0) {
373 			ret = ber_printf(ber, berstring);
374 		} else if (strcmp("o", berstring) == 0) {
375 			ret = ber_printf(ber, berstring,
376 				val->val[i].value, val->val[i].length);
377 		} else if (strcmp("s", berstring) == 0) {
378 			char	*str = am(myself, val->val[i].length + 1);
379 
380 			if (str != 0) {
381 				ret = ber_printf(ber, berstring, str);
382 				free(str);
383 			} else {
384 				ret = -1;
385 			}
386 		} else {
387 			ret = -1;
388 		}
389 
390 		if (ret == -1) {
391 			reportError(NPL_BERENCODE, "%s: BER encoding error",
392 					myself);
393 			ber_free(ber, 1);
394 			freeValue(val, 1);
395 			return (0);
396 		}
397 
398 		if (ber_flatten(ber, &bv) != 0 || bv == 0) {
399 			reportError(NPL_BERENCODE, "%s: ber_flatten() error",
400 					myself);
401 			ber_free(ber, 1);
402 			freeValue(val, 1);
403 			return (0);
404 		}
405 
406 		sfree(val->val[i].value);
407 		val->val[i].length = bv->bv_len;
408 		val->val[i].value = bv->bv_val;
409 
410 		ber_free(ber, 1);
411 	}
412 
413 	val->type = vt_ber;
414 
415 	return (val);
416 }
417 
418 __nis_value_t *
419 berDecode(__nis_value_t *valIn, char *berstring) {
420 	__nis_value_t	*val;
421 	int		i;
422 	char		*myself = "berDecode";
423 
424 	if (valIn == 0 || berstring == 0)
425 		return (0);
426 
427 	val = cloneValue(valIn, 1);
428 	if (val == 0)
429 		return (0);
430 
431 	for (i = 0; i < val->numVals; i++) {
432 		void		*v = 0;
433 		int		ret, len = 0;
434 		struct berval	bv;
435 		BerElement	*ber;
436 
437 		if (val->val[i].value == 0 || val->val[i].length <= 0)
438 			continue;
439 
440 		bv.bv_val = val->val[i].value;
441 		bv.bv_len = val->val[i].length;
442 		ber = ber_init(&bv);
443 		if (ber == 0) {
444 			reportError(NPL_BERDECODE, "%s: ber_init() error",
445 				myself);
446 			freeValue(val, 1);
447 			return (0);
448 		}
449 
450 		if ((strcmp("b", berstring) == 0 ||
451 				strcmp("i", berstring) == 0)) {
452 			len = sizeof (int);
453 			v = am(myself, len);
454 			if (v != 0) {
455 				ret = ber_scanf(ber, berstring, v);
456 			} else {
457 				ret = -1;
458 			}
459 		} else if (strcmp("B", berstring) == 0) {
460 			long	llen;
461 
462 			ret = ber_scanf(ber, berstring, &v, &llen);
463 			if (ret != -1) {
464 				len = llen/8;
465 			}
466 		} else if (strcmp("n", berstring) == 0) {
467 			ret = 0;
468 		} else if (strcmp("o", berstring) == 0) {
469 			struct berval	*bv = am(myself, sizeof (*bv));
470 
471 			if (bv != 0) {
472 				ret = ber_scanf(ber, "O", &bv);
473 				if (ret != -1 && bv != 0) {
474 					v = bv->bv_val;
475 					len = bv->bv_len;
476 				} else {
477 					ret = -1;
478 				}
479 				/* Only free 'bv' itself */
480 				free(bv);
481 			} else {
482 				ret = -1;
483 			}
484 		} else if (strcmp("s", berstring) == 0) {
485 			ret = ber_scanf(ber, "a", &v);
486 			if (ret != -1) {
487 				len = slen(v);
488 			}
489 		} else {
490 			ret = -1;
491 		}
492 
493 		if (ret == -1) {
494 			reportError(NPL_BERDECODE, "%s: BER decoding error",
495 					myself);
496 			freeValue(val, 1);
497 			return (0);
498 		}
499 
500 		/* Free the old value, and replace it with the decoded one */
501 		sfree(val->val[i].value);
502 		val->val[i].value = v;
503 		val->val[i].length = len;
504 	}
505 
506 	return (val);
507 }
508 
509 /*
510  * Return the value of the specified item.
511  */
512 __nis_value_t *
513 getMappingItemVal(__nis_mapping_item_t *item, __nis_mapping_item_type_t native,
514 		__nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
515 	__nis_value_t				*val = 0, *nameVal, *exVal = 0;
516 	int					numName, caseInsens, cmp;
517 	int					i, j, k;
518 	char					**name;
519 	enum {rvOnly, rvThenLookup, lookupOnly}	check;
520 	unsigned char				fromldap = '\0';
521 
522 	if (item == 0)
523 		return (0);
524 
525 	/*
526 	 * First, we decide if we should look for the value in 'rv',
527 	 * directly from NIS+/LDAP, or both.
528 	 */
529 	switch (item->type) {
530 	case mit_nisplus:
531 		/* Do we have a valid index/object spec ? */
532 		if (item->searchSpec.obj.index.numIndexes <= 0 &&
533 				item->searchSpec.obj.name == 0) {
534 			/*
535 			 * No valid index/object. If we have a rule-value,
536 			 * use it. Otherwise, return error.
537 			 */
538 			if (rv != 0) {
539 				name = rv->colName;
540 				nameVal = rv->colVal;
541 				numName = rv->numColumns;
542 				caseInsens = 0;
543 				check = rvOnly;
544 			} else {
545 				return (0);
546 			}
547 		} else {
548 			/*
549 			 * Valid index, so skip the rule-value and do
550 			 * a direct NIS+ lookup.
551 			 */
552 			check = lookupOnly;
553 		}
554 		break;
555 	case mit_ldap:
556 		if (rv != 0) {
557 			name = rv->attrName;
558 			nameVal = rv->attrVal;
559 			numName = rv->numAttrs;
560 			caseInsens = 1;
561 			fromldap = '1';
562 		}
563 		/* Do we have a valid triple ? */
564 		if (item->searchSpec.triple.scope == LDAP_SCOPE_UNKNOWN) {
565 			/*
566 			 * No valid triple. If we have a rule-value, use it.
567 			 * Otherwise, return error.
568 			 */
569 			if (rv != 0) {
570 				check = rvOnly;
571 			} else {
572 				return (0);
573 			}
574 		} else if (item->searchSpec.triple.base == 0 &&
575 				item->searchSpec.triple.scope ==
576 					LDAP_SCOPE_ONELEVEL &&
577 				item->searchSpec.triple.attrs == 0 &&
578 				item->searchSpec.triple.element == 0) {
579 			/*
580 			 * We have a valid triple, but it points to the
581 			 * current LDAP container. Thus, first look in
582 			 * the rule-value; if that fails, perform a direct
583 			 * LDAP lookup.
584 			 */
585 			if (rv != 0) {
586 				check = rvThenLookup;
587 			} else {
588 				check = lookupOnly;
589 			}
590 		} else {
591 			/*
592 			 * Valid triple, and it's not the current container
593 			 * (at least not in the trivial sense). Hence, do
594 			 * a direct LDAP lookup.
595 			 */
596 			check = lookupOnly;
597 		}
598 		break;
599 	default:
600 		return (0);
601 	}
602 
603 	/* Check the rule-value */
604 	if (check == rvOnly || check == rvThenLookup) {
605 		for (i = 0; i < numName; i++) {
606 			if (caseInsens)
607 				cmp = strcasecmp(item->name, name[i]);
608 			else
609 				cmp = strcmp(item->name, name[i]);
610 			if (cmp == 0) {
611 				if (nameVal[i].numVals <= 0)
612 					break;
613 				if (berstring == 0) {
614 					val = cloneValue(&nameVal[i], 1);
615 				} else if (yp2ldap && berstring[0] == 'a') {
616 					val = cloneValue(&nameVal[i], 1);
617 				} else {
618 					val = berDecode(&nameVal[i],
619 						berstring);
620 				}
621 				if (val != 0) {
622 					val->repeat = item->repeat;
623 					/*
624 					 * If value for nis+ column is
625 					 * passed with value, val is
626 					 * manipulated in cloneValue().
627 					 * To decide whether there are
628 					 * enough nis+ column values
629 					 * for rule to produce a value,
630 					 * we need nis+ column values
631 					 * as well as nis_mapping_element
632 					 * from the rule. If we are here,
633 					 * it indicates that the 'val has
634 					 * an valid value for the column
635 					 * item-> name. So set
636 					 * NP_LDAP_MAP_SUCCESS
637 					 * to np_ldap-stat.
638 					 */
639 
640 					if (np_ldap_stat != NULL)
641 						*np_ldap_stat =
642 							NP_LDAP_MAP_SUCCESS;
643 				}
644 				break;
645 			}
646 		}
647 	}
648 
649 	/* Do a direct lookup ? */
650 	if (val == 0 && (check == rvThenLookup || check == lookupOnly)) {
651 		if (item->type == mit_ldap) {
652 			int	err = 0;
653 			__nis_search_triple_t	triple;
654 			char			*baseDN;
655 
656 			/*
657 			 * If item->searchSpec.triple.base is NULL, or ends
658 			 * in a comma, append the current search base from
659 			 * the TSD (put there by an upper layer).
660 			 *
661 			 * Special case for N2L mode:
662 			 * if item->searchSpec.triple.base ends in a comma,
663 			 * the current domain Context is used.
664 			 */
665 			if (yp2ldap && item->searchSpec.triple.base &&
666 				strlen(item->searchSpec.triple.base) > 0) {
667 				baseDN = __nisdb_get_tsd()->domainContext;
668 			} else {
669 				baseDN = __nisdb_get_tsd()->searchBase;
670 			}
671 			triple.base = appendBase(item->searchSpec.triple.base,
672 				baseDN, &err, 0);
673 			if (err == 0) {
674 				triple.scope = item->searchSpec.triple.scope;
675 				triple.attrs = item->searchSpec.triple.attrs;
676 				triple.element =
677 					item->searchSpec.triple.element;
678 				val = lookupLDAP(&triple, item->name, rv, 0,
679 					np_ldap_stat);
680 				fromldap = '1';
681 			} else {
682 				val = 0;
683 			}
684 			sfree(triple.base);
685 		}
686 	}
687 
688 
689 	/* Special processing for NIS to LDAP mode */
690 	if (yp2ldap && val != 0) {
691 
692 		/*
693 		 * Escape special chars from dn before sending to DIT,
694 		 * provided val is not ldap-based
695 		 */
696 		if (fromldap == '\0' && __nisdb_get_tsd()->escapeFlag == '1') {
697 			if (escapeSpecialChars(val) < 0) {
698 				freeValue(val, 1);
699 				return (0);
700 			}
701 		} else if (__nisdb_get_tsd()->escapeFlag == '2') {
702 			/* Remove escape chars from data received from DIT */
703 			(void) removeEscapeChars(val);
704 		}
705 
706 		/*
707 		 * Remove from 'val', any values obtained using
708 		 * the 'removespec' syntax
709 		 */
710 
711 		/* Obtain exVal */
712 		if (item->exItem)
713 			exVal = getMappingItemVal(item->exItem, native, rv,
714 			    berstring, NULL);
715 
716 		/* delete */
717 		if (exVal != 0) {
718 			for (i = 0; i < val->numVals; ) {
719 				for (j = 0; j < exVal->numVals; j++) {
720 					if (sstrncmp(val->val[i].value,
721 							exVal->val[j].value,
722 							MAX(val->val[i].length,
723 							exVal->val[j].length))
724 							== 0)
725 						break;
726 				}
727 				if (j < exVal->numVals) {
728 					sfree(val->val[i].value);
729 					val->val[i].value = 0;
730 					val->val[i].length = 0;
731 					for (k = i; k < val->numVals - 1; k++) {
732 						val->val[k] = val->val[k + 1];
733 						val->val[k + 1].value = 0;
734 						val->val[k + 1].length = 0;
735 					}
736 					val->numVals--;
737 				} else
738 					i++;
739 			}
740 
741 			freeValue(exVal, 1);
742 
743 			/*
744 			 * If val->numVals <= 0, then we have no val to
745 			 * return. So free up stuff.
746 			 */
747 			if (val->numVals <= 0) {
748 				free(val->val);
749 				val->val = 0;
750 				free(val);
751 				return (0);
752 			}
753 		}
754 	}
755 
756 	return (val);
757 }
758 
759 __nis_value_t *
760 getMappingFormat(__nis_mapping_format_t *f, __nis_rule_value_t *rv,
761 			__nis_format_arg_t at, void *a, int *numArg) {
762 	char		*myself = "getMappingFormat";
763 	__nis_value_t	*val = 0;
764 	__nis_buffer_t	b = {0, 0};
765 	int		i;
766 
767 	if (f == 0)
768 		return (0);
769 
770 	if (rv == 0) {
771 		val = am(myself, sizeof (*val));
772 		if (val == 0)
773 			return (0);
774 
775 		switch (f->type) {
776 		case mmt_item:
777 			bp2buf(myself, &b, "%%s");
778 			break;
779 		case mmt_string:
780 			bp2buf(myself, &b, "%s", NIL(f->match.string));
781 			break;
782 		case mmt_single:
783 			bp2buf(myself, &b, "[");
784 			for (i = 0; i < f->match.single.numRange; i++) {
785 				if (f->match.single.lo[i] ==
786 						f->match.single.hi[i])
787 					bp2buf(myself, &b, "%c",
788 						f->match.single.lo[i]);
789 				else
790 					bp2buf(myself, &b, "%c-%c",
791 						f->match.single.lo[i],
792 						f->match.single.hi[i]);
793 			}
794 			bp2buf(myself, &b, "]");
795 			break;
796 		case mmt_limit:
797 			break;
798 		case mmt_any:
799 			bp2buf(myself, &b, "*");
800 			break;
801 		case mmt_berstring:
802 			bp2buf(myself, &b, "%s", NIL(f->match.berString));
803 			break;
804 		case mmt_begin:
805 		case mmt_end:
806 			bp2buf(myself, &b, "\"");
807 			break;
808 		default:
809 			bp2buf(myself, &b, "<unknown>");
810 		}
811 		val->type = vt_string;
812 		val->numVals = 1;
813 		val->val = am(myself, sizeof (val->val[0]));
814 		if (val->val == 0) {
815 			sfree(val);
816 			return (0);
817 		}
818 		val->val[0].value = b.buf;
819 		val->val[0].length = b.len;
820 	} else {
821 		switch (f->type) {
822 		case mmt_item:
823 		case mmt_berstring:
824 			if (a != 0) {
825 				if (at == fa_item) {
826 					val = getMappingItemVal(
827 						(__nis_mapping_item_t *)a,
828 						mit_any, rv,
829 		(f->type == mmt_berstring) ? f->match.berString : 0, NULL);
830 					if (numArg != 0)
831 						(*numArg)++;
832 				} else {
833 					val = cloneValue(
834 						(__nis_value_t *)a, 1);
835 					if (numArg != 0)
836 						(*numArg)++;
837 				}
838 			}
839 			break;
840 		case mmt_string:
841 			val = am(myself, sizeof (*val));
842 			if (val == 0)
843 				return (0);
844 			val->type = vt_string;
845 			val->numVals = 1;
846 			val->val = am(myself, sizeof (val->val[0]));
847 			if (val->val == 0) {
848 				sfree(val);
849 				return (0);
850 			}
851 			val->val[0].value = sdup(myself, T, f->match.string);
852 			val->val[0].length = strlen(val->val[0].value);
853 			break;
854 		case mmt_single:
855 		case mmt_limit:
856 		case mmt_any:
857 		case mmt_begin:
858 		case mmt_end:
859 			/* Not an error, so return an empty value */
860 			val = am(myself, sizeof (*val));
861 			if (val == 0)
862 				return (0);
863 			val->type = vt_string;
864 			val->numVals = 0;
865 			val->val = 0;
866 			break;
867 		default:
868 			/* Do nothing */
869 			val = 0;
870 			break;
871 		}
872 	}
873 	return (val);
874 }
875 
876 /*
877  * Used when evaluating an expression. Typically, the value of the
878  * expression so far will be kept in 'v1', and 'v2' is the value
879  * of the current component of the expression. In the general case,
880  * both will be multi-valued, and the result is an "explosion"
881  * resulting in N*M new values (if 'v1' had N values, and 'v2'
882  * M ditto).
883  *
884  * For example, if v1 = {"ab", "cd", "ef"}, and v2 = {"gh", "ij", "kl"},
885  * the result will be {"abgh", "abij", "abkl", "cdgh", "cdij", "cdkl",
886  * "efgh", "efij", "efkl"}.
887  *
888  * There are special cases when v1->repeat and/or v2->repeat are set.
889  * Repeat mostly makes sense with single values; for example, if
890  * v1 = {"x="} with repeat on, and v2 = {"1", "2", "3"}, the result
891  * is {"x=1", "x=2", "x=3"}.
892  *
893  * The result if v2 also had repeat on would be {"x=1x=2x=3"}. It's
894  * not clear if there's a useful application for this, but the code's
895  * there for the sake of orthogonality.
896  */
897 __nis_value_t *
898 explodeValues(__nis_value_t *v1, __nis_value_t *v2) {
899 	int		i1, i2, n, nv;
900 	__nis_value_t	*v;
901 	__nis_buffer_t	b = {0, 0};
902 	char		*myself = "explodeValues";
903 
904 	if (v1 == 0 || v1->numVals <= 0)
905 		return (cloneValue(v2, 1));
906 	if (v2 == 0 || v2->numVals <= 0)
907 		return (cloneValue(v1, 1));
908 
909 	/*
910 	 * XXX What should we do if (v1->type != v2->type) ?
911 	 * Policy: Just explode anyway, even though the result is
912 	 * unlikely to be very useful.
913 	 */
914 
915 	v = am(myself, sizeof (*v));
916 	if (v == 0)
917 		return (0);
918 
919 	if (!v1->repeat && !v2->repeat)
920 		nv = v1->numVals * v2->numVals;
921 	else if (v1->repeat && !v2->repeat)
922 		nv = v2->numVals;
923 	else if (!v1->repeat && v2->repeat)
924 		nv = v1->numVals;
925 	else /* v1->repeat && v2->repeat */
926 		nv = 1;
927 
928 	v->val = am(myself, nv * sizeof (v->val[0]));
929 	if (v->val == 0) {
930 		free(v);
931 		return (0);
932 	}
933 
934 	/*
935 	 * Four different cases, depending on the 'repeat' flags.
936 	 */
937 	if (!v1->repeat && !v2->repeat) {
938 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
939 			for (i2 = 0; i2 < v2->numVals; i2++) {
940 				if (v1->type == vt_string)
941 					sbc2buf(myself, v1->val[i1].value,
942 						v1->val[i1].length,
943 						&b);
944 				else
945 					bc2buf(myself, v1->val[i1].value,
946 						v1->val[i1].length,
947 						&b);
948 				if (v2->type == vt_string)
949 					sbc2buf(myself, v2->val[i2].value,
950 						v2->val[i2].length,
951 						&b);
952 				else
953 					bc2buf(myself, v2->val[i2].value,
954 						v2->val[i2].length,
955 						&b);
956 				v->val[n].value = b.buf;
957 				v->val[n].length = b.len;
958 				n++;
959 				b.buf = 0;
960 				b.len = 0;
961 			}
962 		}
963 	} else if (v1->repeat && !v2->repeat) {
964 		for (i2 = 0; i2 < v2->numVals; i2++) {
965 			for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
966 				if (v1->type == vt_string)
967 					sbc2buf(myself, v1->val[i1].value,
968 						v1->val[i1].length,
969 						&b);
970 				else
971 					bc2buf(myself, v1->val[i1].value,
972 						v1->val[i1].length,
973 						&b);
974 				if (v2->type == vt_string)
975 					sbc2buf(myself, v2->val[i2].value,
976 						v2->val[i2].length,
977 						&b);
978 				else
979 					bc2buf(myself, v2->val[i2].value,
980 						v2->val[i2].length,
981 						&b);
982 			}
983 			v->val[n].value = b.buf;
984 			v->val[n].length = b.len;
985 			n++;
986 			b.buf = 0;
987 			b.len = 0;
988 		}
989 	} else if (!v1->repeat && v2->repeat) {
990 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
991 			for (i2 = 0; i2 < v2->numVals; i2++) {
992 				if (v1->type == vt_string)
993 					sbc2buf(myself, v1->val[i1].value,
994 						v1->val[i1].length,
995 						&b);
996 				else
997 					bc2buf(myself, v1->val[i1].value,
998 						v1->val[i1].length,
999 						&b);
1000 				if (v2->type == vt_string)
1001 					sbc2buf(myself, v2->val[i2].value,
1002 						v2->val[i2].length,
1003 						&b);
1004 				else
1005 					bc2buf(myself, v2->val[i2].value,
1006 						v2->val[i2].length,
1007 						&b);
1008 			}
1009 			v->val[n].value = b.buf;
1010 			v->val[n].length = b.len;
1011 			n++;
1012 			b.buf = 0;
1013 			b.len = 0;
1014 		}
1015 	} else { /* v1->repeat && v2->repeat */
1016 		for (i1 = 0, n = 0; i1 < v1->numVals; i1++) {
1017 			for (i2 = 0; i2 < v2->numVals; i2++) {
1018 				if (v1->type == vt_string)
1019 					sbc2buf(myself, v1->val[i1].value,
1020 						v1->val[i1].length,
1021 						&b);
1022 				else
1023 					bc2buf(myself, v1->val[i1].value,
1024 						v1->val[i1].length,
1025 						&b);
1026 				if (v2->type == vt_string)
1027 					sbc2buf(myself, v2->val[i2].value,
1028 						v2->val[i2].length,
1029 						&b);
1030 				else
1031 					bc2buf(myself, v2->val[i2].value,
1032 						v2->val[i2].length,
1033 						&b);
1034 			}
1035 		}
1036 		v->val[n].value = b.buf;
1037 		v->val[n].length = b.len;
1038 		n++;
1039 		b.buf = 0;
1040 		b.len = 0;
1041 	}
1042 
1043 #ifdef	NISDB_LDAP_DEBUG
1044 	/* Sanity check */
1045 	if (n != nv)
1046 		abort();
1047 #endif	/* NISD__LDAP_DEBUG */
1048 
1049 	v->type = (v1->type == vt_string) ?
1050 			((v2->type == vt_string) ?
1051 				vt_string : vt_ber) : vt_ber;
1052 	v->repeat = 0;
1053 	v->numVals = n;
1054 
1055 	return (v);
1056 }
1057 
1058 __nis_value_t *
1059 getMappingFormatArray(__nis_mapping_format_t *a, __nis_rule_value_t *rv,
1060 			__nis_format_arg_t at, int numArgs, void *arg) {
1061 	int			i, ia = 0;
1062 	__nis_value_t		*val, *v = 0;
1063 	bool_t			moreFormat = (a != 0);
1064 	bool_t			moreArgs = (numArgs > 0);
1065 
1066 	while (moreFormat && (arg == 0 || ia < numArgs)) {
1067 		for (i = 0; moreFormat; i++) {
1068 			moreFormat = (a[i].type != mmt_end);
1069 			if (at == fa_item) {
1070 				__nis_mapping_item_t *item = arg;
1071 				val = getMappingFormat(&a[i], rv, at,
1072 					((item != 0) ? &item[ia] : 0), &ia);
1073 			} else {
1074 				__nis_value_t **ival = arg;
1075 				val = getMappingFormat(&a[i], rv, at,
1076 					((ival != 0) ? ival[ia] : 0), &ia);
1077 			}
1078 			if (val != 0) {
1079 				__nis_value_t	*new = explodeValues(v, val);
1080 
1081 				freeValue(v, 1);
1082 				freeValue(val, 1);
1083 				if (new == 0)
1084 					return (0);
1085 
1086 				v = new;
1087 			} else {
1088 				freeValue(v, 1);
1089 				return (0);
1090 			}
1091 			/*
1092 			 * If we run out of arguments, but still have format
1093 			 * remaining, repeat the last argument. Keep track of
1094 			 * the fact that we've really consumed all arguments.
1095 			 */
1096 			if (moreFormat && ia >= numArgs) {
1097 				ia = (numArgs > 0) ? numArgs - 1 : 0;
1098 				moreArgs = FALSE;
1099 			}
1100 		}
1101 		/*
1102 		 * We've run out of format, so if we still have arguments
1103 		 * left, start over on the format.
1104 		 */
1105 		if (ia < numArgs && moreArgs) {
1106 			/*
1107 			 * However, if we didn't consume any arguments going
1108 			 * through the format once, abort to avoid an infinite
1109 			 * loop.
1110 			 */
1111 			if (numArgs > 0 && ia <= 0) {
1112 				freeValue(v, 1);
1113 				return (0);
1114 			}
1115 			moreFormat = 1;
1116 		}
1117 	}
1118 
1119 	return (v);
1120 }
1121 
1122 /*
1123  * Returns a string representation (such as "[name=foo, value=bar]")
1124  * of a nis_index_t.
1125  */
1126 char *
1127 getIndex(__nis_index_t *i, int *len) {
1128 	int		n;
1129 	__nis_buffer_t	b = {0, 0};
1130 	char		*myself = "getIndex";
1131 
1132 	if (i == 0)
1133 		return (0);
1134 
1135 	if (i->numIndexes > 0) {
1136 		bp2buf(myself, &b, "[");
1137 		for (n = 0; n < i->numIndexes; n++) {
1138 			__nis_value_t	*val;
1139 			int		j;
1140 
1141 			val = getMappingFormatArray(i->value[n],
1142 						0, fa_any, 0, 0);
1143 			if (n > 0)
1144 				bp2buf(myself, &b, ", ");
1145 			bp2buf(myself, &b, "%s=", i->name[n]);
1146 			if (val != 0) {
1147 				for (j = 0; j < val->numVals; j++) {
1148 					bc2buf(myself, val->val[j].value,
1149 						val->val[j].length, &b);
1150 				}
1151 			} else {
1152 				bp2buf(myself, &b, "<no-vals>");
1153 			}
1154 			freeValue(val, 1);
1155 		}
1156 		bp2buf(myself, &b, "]");
1157 	}
1158 	if (len != 0)
1159 		*len = b.len;
1160 	return (b.buf);
1161 }
1162 
1163 char *
1164 getObjSpec(__nis_obj_spec_t *o, int *len) {
1165 	__nis_buffer_t	b = {0, 0};
1166 	char		*myself = "getObjSpec";
1167 
1168 	if (o == 0)
1169 		return (0);
1170 
1171 	b.buf = getIndex(&o->index, &b.len);
1172 	sbc2buf(myself, o->name, slen(o->name), &b);
1173 	if (len != 0)
1174 		*len = b.len;
1175 	return (b.buf);
1176 }
1177 
1178 /*
1179  * Returns a string representation of the LDAP scope. Note that the
1180  * returned value is a static entity, and must be copied by the
1181  * caller (but, obviously, must not be freed).
1182  */
1183 char *
1184 getScope(int scope) {
1185 	switch (scope) {
1186 	case LDAP_SCOPE_BASE:
1187 		return ("base");
1188 	case LDAP_SCOPE_ONELEVEL:
1189 		return ("one");
1190 	case LDAP_SCOPE_SUBTREE:
1191 		return ("sub");
1192 	default:
1193 		return ("one");
1194 	}
1195 }
1196 
1197 /*
1198  * Return a string representation of an LDAP search triple (such as
1199  * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1200  */
1201 char *
1202 getSearchTriple(__nis_search_triple_t *s, int *len) {
1203 	__nis_buffer_t	b = {0, 0};
1204 	char		*a;
1205 	int		l;
1206 	char		*myself = "getSearchTriple";
1207 
1208 	/* If the scope is LDAP_SCOPE_UNKNOWN, the search triple is unused */
1209 	if (s == 0 || s->scope == LDAP_SCOPE_UNKNOWN) {
1210 		if (len != 0)
1211 			*len = 0;
1212 		return (0);
1213 	}
1214 
1215 	if (s->base != 0)
1216 		sbc2buf(myself, s->base, slen(s->base), &b);
1217 	if (!(s->scope == LDAP_SCOPE_ONELEVEL &&
1218 			(s->base == 0 || s->base[0] == '\0'))) {
1219 		bp2buf(myself, &b, "?%s?", getScope(s->scope));
1220 	}
1221 	if ((l = slen(s->attrs)) > 0) {
1222 		/*
1223 		 * Remove white space from the filter/attribute list.
1224 		 * The parser usually keeps any white space from the
1225 		 * config file (or LDAP/command line), but we don't
1226 		 * want it.
1227 		 */
1228 		a = am(myself, l+1);
1229 		if (a != 0) {
1230 			int	i, la;
1231 
1232 			for (i = 0, la = 0; i < l; i++) {
1233 				if (s->attrs[i] != ' ' &&
1234 						s->attrs[i] != '\t')
1235 					a[la++] = s->attrs[i];
1236 			}
1237 			sbc2buf(myself, a, la, &b);
1238 			sfree(a);
1239 		} else {
1240 			sbc2buf(myself, s->attrs, slen(s->attrs), &b);
1241 		}
1242 	}
1243 
1244 	if (len != 0)
1245 		*len = b.len;
1246 	return (b.buf);
1247 }
1248 
1249 __nis_value_t *
1250 getMappingItem(__nis_mapping_item_t *i, __nis_mapping_item_type_t native,
1251 		__nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
1252 	char		*myself = "getMappingItem";
1253 	__nis_value_t	*val = 0;
1254 	__nis_buffer_t	b = {0, 0};
1255 	int		len = 0;
1256 	char		*buf;
1257 
1258 	if (i == 0)
1259 		return (0);
1260 
1261 	if (rv != 0)
1262 		return (getMappingItemVal(i, native, rv, berstring,
1263 			np_ldap_stat));
1264 
1265 	val = am(myself, sizeof (*val));
1266 	if (val == 0)
1267 		return (0);
1268 
1269 	switch (i->type) {
1270 	case mit_nisplus:
1271 		if (native != mit_nisplus)
1272 			bp2buf(myself, &b, "nis+:");
1273 		bp2buf(myself, &b, "%s", NIL(i->name));
1274 		buf = getObjSpec(&i->searchSpec.obj, &len);
1275 		if (buf != 0 && len > 0) {
1276 			bc2buf(myself, ":", 1, &b);
1277 			sbc2buf(myself, buf, len, &b);
1278 		}
1279 		sfree(buf);
1280 		val->type = vt_string;
1281 		val->repeat = i->repeat;
1282 		val->numVals = 1;
1283 		val->val = am(myself, sizeof (val->val[0]));
1284 		if (val->val == 0) {
1285 			sfree(b.buf);
1286 			free(val);
1287 			return (0);
1288 		}
1289 		val->val[0].value = b.buf;
1290 		val->val[0].length = b.len;
1291 		break;
1292 	case mit_ldap:
1293 		if (native != mit_ldap)
1294 			bp2buf(myself, &b, "ldap:");
1295 		bp2buf(myself, &b, "%s", NIL(i->name));
1296 		buf = getSearchTriple(&i->searchSpec.triple, &len);
1297 		if (buf != 0 && len > 0) {
1298 			bc2buf(myself, ":", 1, &b);
1299 			sbc2buf(myself, buf, len, &b);
1300 		}
1301 		sfree(buf);
1302 		val->type = vt_string;
1303 		val->repeat = i->repeat;
1304 		val->numVals = 1;
1305 		val->val = am(myself, sizeof (val->val[0]));
1306 		if (val->val == 0) {
1307 			sfree(b.buf);
1308 			free(val);
1309 			return (0);
1310 		}
1311 		val->val[0].value = b.buf;
1312 		val->val[0].length = b.len;
1313 		break;
1314 	default:
1315 		p2buf(myself, "<unknown>:");
1316 		p2buf(myself, "%s", NIL(i->name));
1317 		break;
1318 	}
1319 
1320 	return (val);
1321 }
1322 
1323 void
1324 copyObjSpec(__nis_obj_spec_t *old, __nis_obj_spec_t *new, int *err) {
1325 	char	*myself = "copyObjSpec";
1326 
1327 	if (old == 0 || new == 0) {
1328 		*err = EINVAL;
1329 		return;
1330 	}
1331 
1332 	if (new->index.name == 0) {
1333 		new->index.name = am(myself, old->index.numIndexes *
1334 						sizeof (new->index.name[0]));
1335 		if (old->index.numIndexes > 0 && new->index.name == 0) {
1336 			*err = ENOMEM;
1337 			return;
1338 		}
1339 		new->index.value = am(myself, old->index.numIndexes *
1340 						sizeof (new->index.value[0]));
1341 		if (old->index.numIndexes > 0 && new->index.value == 0) {
1342 			*err = ENOMEM;
1343 			return;
1344 		}
1345 	}
1346 	new->name = sdup(myself, T, old->name);
1347 	if (new->name == 0 && old->name != 0) {
1348 		*err = ENOMEM;
1349 		return;
1350 	}
1351 	copyIndex(&old->index, &new->index, err);
1352 }
1353 
1354 __nis_obj_spec_t *
1355 cloneObjSpec(__nis_obj_spec_t *old) {
1356 	char			*myself = "cloneObjSpec";
1357 	int			err = 0;
1358 	__nis_obj_spec_t	*new = am(myself, sizeof (*new));
1359 
1360 	if (new != 0) {
1361 		copyObjSpec(old, new, &err);
1362 		if (err != 0) {
1363 			freeObjSpec(new, 1);
1364 			new = 0;
1365 		}
1366 	}
1367 
1368 	return (new);
1369 }
1370 
1371 void
1372 freeObjSpec(__nis_obj_spec_t *old, bool_t doFree) {
1373 
1374 	if (old == 0)
1375 		return;
1376 
1377 	sfree(old->name);
1378 	freeIndex(&old->index, FALSE);
1379 	if (doFree)
1380 		free(old);
1381 }
1382 
1383 void
1384 copySearchTriple(__nis_search_triple_t *old, __nis_search_triple_t *new,
1385 		int *err) {
1386 	char			*myself = "copySearchTriple";
1387 
1388 	*err = 0;
1389 
1390 	if (old == 0 || new == 0) {
1391 		*err = EINVAL;
1392 		return;
1393 	}
1394 
1395 	if (old->base != NULL)
1396 		new->base = sdup(myself, T, old->base);
1397 	else
1398 		new->base = NULL;
1399 	if (old->attrs != NULL)
1400 		new->attrs = sdup(myself, T, old->attrs);
1401 	else
1402 		new->attrs = NULL;
1403 	if ((new->base == 0 && old->base != 0) ||
1404 			(new->attrs == 0 && old->attrs != 0)) {
1405 		sfree(new->base);
1406 		new->base = 0;
1407 		sfree(new->attrs);
1408 		new->attrs = 0;
1409 		*err = ENOMEM;
1410 		return;
1411 	}
1412 	new->scope = old->scope;
1413 	/*
1414 	 * XXX Really should have a cloneMappingElement() function.
1415 	 * However, since whatever the 'element' field points to
1416 	 * is allocated at parse time, and never is freed or modified,
1417 	 * it's sufficient to copy the pointer value.
1418 	 */
1419 	new->element = old->element;
1420 }
1421 
1422 __nis_search_triple_t *
1423 cloneSearchTriple(__nis_search_triple_t *old) {
1424 	char			*myself = "cloneSearchTriple";
1425 	int			err = 0;
1426 	__nis_search_triple_t	*new = am(myself, sizeof (*new));
1427 
1428 	if (new != 0) {
1429 		copySearchTriple(old, new, &err);
1430 		if (err != 0) {
1431 			freeSearchTriple(new, 1);
1432 			new = 0;
1433 		}
1434 	}
1435 
1436 	return (new);
1437 }
1438 
1439 void
1440 freeSearchTriple(__nis_search_triple_t *old, bool_t doFree) {
1441 
1442 	if (old == 0)
1443 		return;
1444 
1445 	sfree(old->base);
1446 	sfree(old->attrs);
1447 	/*
1448 	 * Since we only copied the element pointer when this structure
1449 	 * was created, we don't free old->element.
1450 	 */
1451 	if (doFree)
1452 		free(old);
1453 }
1454 
1455 void
1456 copyTripleOrObj(__nis_mapping_item_type_t type,
1457 		__nis_triple_or_obj_t *old, __nis_triple_or_obj_t *new,
1458 		int *err) {
1459 
1460 	*err = 0;
1461 
1462 	if (old == 0 || new == 0) {
1463 		*err = EINVAL;
1464 		return;
1465 	}
1466 
1467 	if (type == mit_nisplus) {
1468 		copyObjSpec(&old->obj, &new->obj, err);
1469 	} else if (type == mit_ldap) {
1470 		copySearchTriple(&old->triple, &new->triple, err);
1471 	}
1472 }
1473 
1474 __nis_triple_or_obj_t *
1475 cloneTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old) {
1476 	char			*myself = "cloneTripleOrObj";
1477 	int			err = 0;
1478 	__nis_triple_or_obj_t	*new = am(myself, sizeof (*new));
1479 
1480 	if (new != 0) {
1481 		copyTripleOrObj(type, old, new, &err);
1482 		if (err != 0) {
1483 			freeTripleOrObj(type, new, 1);
1484 			new = 0;
1485 		}
1486 	}
1487 
1488 	return (new);
1489 }
1490 
1491 void
1492 freeTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old,
1493 		bool_t doFree) {
1494 
1495 	if (old == 0)
1496 		return;
1497 
1498 	if (type == mit_nisplus)
1499 		freeObjSpec(&old->obj, doFree);
1500 	else if (type == mit_ldap)
1501 		freeSearchTriple(&old->triple, doFree);
1502 
1503 	if (doFree)
1504 		free(old);
1505 }
1506 
1507 void
1508 copyItem(__nis_mapping_item_t *old, __nis_mapping_item_t *new, int *err) {
1509 
1510 	*err = 0;
1511 
1512 	if (old == 0 || new == 0) {
1513 		*err = EINVAL;
1514 		return;
1515 	}
1516 
1517 	new->type = old->type;
1518 	new->repeat = old->repeat;
1519 	if (old->name != 0) {
1520 		new->name = strdup(old->name);
1521 		if (new->name == 0) {
1522 			*err = ENOMEM;
1523 			return;
1524 		}
1525 	} else {
1526 		new->name = 0;
1527 	}
1528 	if (old->type == mit_nisplus || old->type == mit_ldap)
1529 		copyTripleOrObj(old->type, &old->searchSpec, &new->searchSpec,
1530 				err);
1531 	else
1532 		memset(&new->searchSpec, 0, sizeof (new->searchSpec));
1533 }
1534 
1535 __nis_mapping_item_t *
1536 cloneItem(__nis_mapping_item_t *old) {
1537 	__nis_mapping_item_t	*new;
1538 	int			err = 0;
1539 	char			*myself = "cloneItem";
1540 
1541 	if (old == 0)
1542 		return (0);
1543 
1544 	new = am(myself, sizeof (*new));
1545 	if (new == 0)
1546 		return (0);
1547 
1548 	copyItem(old, new, &err);
1549 	if (err != 0) {
1550 		freeMappingItem(new, 1);
1551 		return (0);
1552 	}
1553 
1554 	return (new);
1555 }
1556 
1557 void
1558 freeMappingItem(__nis_mapping_item_t *item, int numItems) {
1559 	int	i;
1560 
1561 	if (item == 0)
1562 		return;
1563 
1564 	for (i = 0; i < numItems; i++) {
1565 		sfree(item[i].name);
1566 		freeTripleOrObj(item[i].type, &item[i].searchSpec, FALSE);
1567 	}
1568 	sfree(item);
1569 }
1570 
1571 __nis_mapping_item_t *
1572 concatenateMappingItem(__nis_mapping_item_t *old, int numItems,
1573 		__nis_mapping_item_t *cat) {
1574 	__nis_mapping_item_t	*new;
1575 	int			i, err = 0;
1576 	char			*myself = "concatenateMappingItem";
1577 
1578 	if (old == 0 || numItems < 1)
1579 		return (cloneItem(cat));
1580 
1581 	new = am(myself, (numItems + 1) * sizeof (*new));
1582 	if (new == 0)
1583 		return (0);
1584 
1585 	for (i = 0; i < numItems; i++) {
1586 		copyItem(&old[i], &new[i], &err);
1587 		if (err != 0) {
1588 			freeMappingItem(new, i);
1589 			return (0);
1590 		}
1591 	}
1592 	copyItem(cat, &new[numItems], &err);
1593 	if (err != 0) {
1594 		freeMappingItem(new, numItems);
1595 		new = 0;
1596 	}
1597 
1598 	return (new);
1599 }
1600 
1601 __nis_value_t *
1602 concatenateValues(__nis_value_t *v1, __nis_value_t *v2) {
1603 	int		i, n, a;
1604 	__nis_value_t	*v;
1605 	char		*myself = "concatenateValues";
1606 
1607 	if (v1 == 0 || v1->numVals <= 0)
1608 		return (cloneValue(v2, 1));
1609 	if (v2 == 0 || v2->numVals <= 0)
1610 		return (cloneValue(v1, 1));
1611 
1612 	if (v1->type != v2->type)
1613 		return (0);
1614 
1615 	n = v1->numVals + v2->numVals;
1616 	v = am(myself, sizeof (*v));
1617 	if (v == 0)
1618 		return (0);
1619 	v->val = am(myself, n * sizeof (v->val[0]));
1620 	if (v->val == 0) {
1621 		free(v);
1622 		return (0);
1623 	}
1624 	v->type = v1->type;
1625 	v->numVals = 0;
1626 
1627 	for (a = 0; a < 2; a++) {
1628 		__nis_single_value_t	*val = (a == 0) ? v1->val : v2->val;
1629 		int			numv = (a == 0) ? v1->numVals :
1630 							v2->numVals;
1631 		for (i = 0; i < numv; i++) {
1632 			int	clen, alen = val[i].length;
1633 
1634 			clen = alen;
1635 
1636 			/*
1637 			 * Make sure there's a NUL at the end of a string,
1638 			 * but avoid adding to the allocated length if there's
1639 			 * already a NUL at the end.
1640 			 */
1641 			if (alen > 0 && v->type == vt_string &&
1642 					((char *)val[i].value)[alen-1] != '\0')
1643 				alen += 1;
1644 			v->val[v->numVals].value = am(myself, alen);
1645 			if (v->val[v->numVals].value == 0) {
1646 				freeValue(v, 1);
1647 				return (0);
1648 			}
1649 			memcpy(v->val[v->numVals].value, val[i].value, clen);
1650 			v->val[v->numVals].length = val[i].length;
1651 			v->numVals++;
1652 		}
1653 	}
1654 
1655 	return (v);
1656 }
1657 
1658 __nis_value_t *
1659 splitMappingItem(__nis_mapping_item_t *item, char delim,
1660 		__nis_rule_value_t *rv) {
1661 	__nis_value_t		*val = getMappingItem(item, mit_any,
1662 			rv, 0, NULL);
1663 	__nis_single_value_t	*nval;
1664 	int			i, n, nv;
1665 
1666 	if (val == 0)
1667 		return (0);
1668 	else if (delim == 0 || val->val == 0 || val->numVals <= 0 ||
1669 			val->type != vt_string) {
1670 		freeValue(val, 1);
1671 		return (0);
1672 	}
1673 
1674 	nval = val->val;
1675 	nv = val->numVals;
1676 	val->repeat = FALSE;
1677 	val->val = 0;
1678 	val->numVals = 0;
1679 
1680 	/* In N2L, space and tab delimiters are treated the same */
1681 	if (yp2ldap && delim == '\t')
1682 		delim = ' ';
1683 
1684 	/* If the item has multiple values, we split each one independently */
1685 	for (i = 0; i < nv; i++) {
1686 		char			*str;
1687 		int			s, e;
1688 		char			*newstr;
1689 		__nis_single_value_t	*newval;
1690 
1691 		if (yp2ldap && delim == ' ')
1692 			nval[i].value = trimWhiteSpaces(nval[i].value,
1693 							&nval[i].length, 1);
1694 
1695 		str = nval[i].value;
1696 
1697 		if (nval[i].value == 0)
1698 			continue;
1699 
1700 		for (s = 0; s < nval[i].length; s = e+1) {
1701 			/* Find the next delimiter, or end-of-string */
1702 			for (e = s; str[e] != '\0' && str[e] != delim; e++);
1703 			/*
1704 			 * 'str[e]' is either a delimiter, or the concluding
1705 			 * NUL. Make sure it's NUL.
1706 			 */
1707 			str[e] = '\0';
1708 			/* Add to val->val */
1709 			newstr = strdup(&str[s]);
1710 			newval = realloc(val->val,
1711 					(val->numVals+1) *
1712 						sizeof (val->val[0]));
1713 			if (newval != 0)
1714 				val->val = newval;
1715 			if (newstr == 0 || newval == 0) {
1716 				freeValue(val, 1);
1717 				for (n = i; n < nv; n++) {
1718 					sfree(nval[n].value);
1719 				}
1720 				free(nval);
1721 				sfree(newstr);
1722 				return (0);
1723 			}
1724 			val->val[val->numVals].value = newstr;
1725 			val->val[val->numVals].length = strlen(newstr) + 1;
1726 			val->numVals++;
1727 		}
1728 		free(nval[i].value);
1729 		nval[i].value = 0;
1730 	}
1731 	/* Already freed the nval[i].value's as we traversed nval */
1732 	free(nval);
1733 
1734 	return (val);
1735 }
1736 
1737 /*
1738  * Match the format spec 'f[curf]' to the input value string 'str'.
1739  *
1740  * If successful, returns the updated position in the value string 'str'.
1741  * Otherwise, NULL is returned.
1742  *
1743  * curf		Current index (i.e., the one we should look at) in 'f'
1744  * nf		Number of elements in 'f', including 'mmt_end'
1745  * str		The value string we're scanning
1746  * val		Pointer to where an item value (if any) should be returned
1747  *		Set to NULL if not an 'mmt_item'.
1748  * fmtstart	If non-zero on entry, skip characters in 'str' until we find
1749  *		the f[curf].type data, if doing so makes any sense. On exit,
1750  *		set to the start of the fmt element data (which will be 'str',
1751  *		unless we did skip characters)
1752  * sepset	List of separators
1753  */
1754 char *
1755 scanMappingFormat(__nis_mapping_format_t *f, int curf, int nf, char *str,
1756 		char **val, char **fmtstart, char *sepset) {
1757 	char	*mstr, *next, *start = 0, *tmpstr;
1758 	int	i, len;
1759 	bool_t	match;
1760 	char	*myself = "scanMappingFormat";
1761 	/* N2L variables */
1762 	int	af, skipspaces = 0;
1763 	bool_t	ipaddr = FALSE;
1764 	char	*spacestr = " ", *emptystr = "";
1765 
1766 
1767 	if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1768 		return (0);
1769 
1770 	/*
1771 	 * If separator list is NULL (which will be the case for
1772 	 * nis+2ldap), then simply use empty string
1773 	 */
1774 	if (sepset == 0)
1775 		sepset = emptystr;
1776 
1777 	if (curf >= nf) {
1778 		/* OK if the string also is exhausted */
1779 		if (strchr(sepset, *str) != 0)
1780 			return (str);
1781 		else
1782 			return (0);
1783 	}
1784 
1785 	switch (f[curf].type) {
1786 	case mmt_berstring:
1787 		if (f[curf].match.berString[0] != 'a') {
1788 			/* Not a matchable element */
1789 			return (0);
1790 		}
1791 
1792 		/*
1793 		 * If here, it means it's an IP address (N2L case)
1794 		 * So continue processing as if it was mmt_item
1795 		 */
1796 		ipaddr = TRUE;
1797 		/* FALLTHROUGH */
1798 	case mmt_item:
1799 		/*
1800 		 * In order to find the end of the item value, we must look
1801 		 * ahead and determine the start of the next formatting element.
1802 		 * If successful, 'next' will be the start of the fmt element
1803 		 * after the next one; we don't care about that, other than to
1804 		 * check for error.
1805 		 *
1806 		 * Since an item match is somewhat like an any match, in that
1807 		 * we don't know a priori if the first occurence of the next
1808 		 * element really is the one we want, we have to scan ahead
1809 		 * until we've reached the end.
1810 		 */
1811 		tmpstr = str;
1812 		while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1813 				&start, sepset)) != 0) {
1814 			char	*tmp = next;
1815 			int	cf;
1816 
1817 			for (cf = curf+2; cf < nf; cf++) {
1818 				tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1819 					0, sepset);
1820 				if (tmp == 0)
1821 					break;
1822 			}
1823 			if (tmp == 0) {
1824 				tmpstr = next;
1825 			} else if (strchr(sepset, *tmp) != 0) {
1826 				break;
1827 			} else {
1828 				return (0);
1829 			}
1830 
1831 		}
1832 		if (next == 0 || start == 0)
1833 			return (0);
1834 
1835 		if (val != 0) {
1836 			len = (int)((long)start - (long)str);
1837 			*val = am(myself, len + 1);
1838 			if (*val == 0)
1839 				return (0);
1840 			memcpy(*val, str, len);
1841 			(*val)[len] = '\0';
1842 
1843 			if (ipaddr == TRUE) {
1844 				/*
1845 				 * In N2L, we need to check if *val is truly an
1846 				 * IP address
1847 				 */
1848 				af = checkIPaddress(*val, len, &tmpstr);
1849 
1850 				if (af == -2) {
1851 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1852 						"%s:Internal error while "
1853 						"processing IPaddress %s",
1854 						myself, *val);
1855 					sfree(*val);
1856 					return (0);
1857 				} else if (af == -1) {
1858 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1859 						"%s:%s is not an IP address",
1860 						myself, *val);
1861 					sfree(*val);
1862 					return (0);
1863 				} else if (af == 0) {
1864 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1865 						"%s:IP address %s is not "
1866 						"supported by rfc2307bis",
1867 						myself, *val);
1868 					sfree(*val);
1869 					return (0);
1870 				} else if (sstrncmp(*val, tmpstr, len) != 0) {
1871 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1872 						"%s:IPaddress %s converted "
1873 						"to %s", myself, *val, tmpstr);
1874 				}
1875 
1876 				sfree(*val);
1877 				*val = tmpstr;
1878 			}
1879 		}
1880 
1881 		if (fmtstart != 0)
1882 			*fmtstart = str;
1883 
1884 		return (start);
1885 
1886 	case mmt_string:
1887 		if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1888 			/*
1889 			 * Count this as a successful match of an empty
1890 			 * string.
1891 			 */
1892 			if (fmtstart != 0)
1893 				*fmtstart = str;
1894 			return (str);
1895 		}
1896 
1897 		/*
1898 		 * In N2L, if the format string 'mstr' contains only
1899 		 * whitespaces (spaces and tabs), then it should
1900 		 * match one or more whitespaces from the input
1901 		 * string 'str'.
1902 		 */
1903 		if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1904 				mstr = spacestr;
1905 				skipspaces = 1;
1906 				next = str + strcspn(str, " \t");
1907 				/*
1908 				 * Even if there is no whitespace in 'str',
1909 				 * it's OK. This is to allow formats like
1910 				 * "%s %s %s" to match inputs like "foo bar".
1911 				 */
1912 				if (*next == '\0')
1913 					mstr = emptystr;
1914 		} else {
1915 			/* No match string in 'str' => failure */
1916 			if ((next = strstr(str, mstr)) == 0)
1917 				return (0);
1918 		}
1919 
1920 		/* If 'fmtstart' == 0, we require 'next' == 'str' */
1921 		if (fmtstart == 0 && next != str)
1922 			return (0);
1923 		/* Success; save start of match string if requested */
1924 		if (fmtstart != 0)
1925 			*fmtstart = next;
1926 		/* Update position in the value string */
1927 		str = (char *)((long)next + (long)strlen(mstr));
1928 
1929 		/* Skip whitespaces for N2L */
1930 		if (skipspaces == 1)
1931 			for (; *str == ' ' || *str == '\t'; str++);
1932 
1933 		return (str);
1934 
1935 	case mmt_single:
1936 		if (fmtstart != 0) {
1937 			match = FALSE;
1938 			/* Skip ahead until we match */
1939 			for (next = str; *next != '\0'; next++) {
1940 				unsigned char	*lo = f[curf].match.single.lo;
1941 				unsigned char	*hi = f[curf].match.single.hi;
1942 
1943 				for (i = 0; i < f[curf].match.single.numRange;
1944 						i++) {
1945 					if (*next >= lo[i] && *next <= hi[i]) {
1946 						match = TRUE;
1947 						break;
1948 					}
1949 				}
1950 				if (match)
1951 					break;
1952 			}
1953 			if (!match)
1954 				return (0);
1955 			*fmtstart = next;
1956 			str = next;
1957 		} else {
1958 			match = FALSE;
1959 			for (i = 0; i < f[curf].match.single.numRange; i++) {
1960 				if (*str >= f[curf].match.single.lo[i] &&
1961 					*str <= f[curf].match.single.hi[i]) {
1962 					match = TRUE;
1963 					break;
1964 				}
1965 			}
1966 			if (!match)
1967 				return (0);
1968 		}
1969 		/* Step over the matched character */
1970 		str++;
1971 		return (str);
1972 
1973 	case mmt_any:
1974 		/*
1975 		 * Look ahead to find the beginning of the next element.
1976 		 * Because a wildcard-match isn't necessarily uniquely
1977 		 * determined until we've reached the end, we then continue
1978 		 * to scan ahead.
1979 		 */
1980 		while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1981 						&start, sepset)) != 0) {
1982 			char	*tmp = next;
1983 			int	cf;
1984 
1985 			for (cf = curf+2; cf < nf; cf++) {
1986 				tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1987 					0, sepset);
1988 				if (tmp == 0)
1989 					break;
1990 			}
1991 			if (tmp == 0) {
1992 				str = next;
1993 			} else if (*tmp == '\0') {
1994 				break;
1995 			} else {
1996 				return (0);
1997 			}
1998 		}
1999 		if (next == 0 || start == 0)
2000 			return (0);
2001 
2002 		if (fmtstart != 0)
2003 			*fmtstart = str;
2004 
2005 		return (start);
2006 
2007 	case mmt_limit:
2008 		if (f[curf].match.limit == eos) {
2009 			if (fmtstart != 0) {
2010 				/* Skip to the end */
2011 				str = str + strcspn(str, sepset);
2012 				*fmtstart = str;
2013 			} else if (strchr(sepset, *str) == 0) {
2014 				return (0);
2015 			}
2016 		}
2017 		return (str);
2018 
2019 	case mmt_begin:
2020 		if (fmtstart != 0)
2021 			*fmtstart = str;
2022 		return (str);
2023 
2024 	case mmt_end:
2025 		if (fmtstart != 0) {
2026 			/* Skip to the end */
2027 			str = str + strcspn(str, sepset);
2028 			*fmtstart = str;
2029 			return (str);
2030 		}
2031 		/* No skipping, so we must be at the end of the value */
2032 		if (strchr(sepset, *str) == 0)
2033 			return (0);
2034 		return (str);
2035 
2036 	default:
2037 		break;
2038 	}
2039 
2040 	return (0);
2041 }
2042 
2043 /*
2044  * Verify that the string 'str' matches the mapping format array 'f'.
2045  * Returns 1 in case of a match, 0 otherwise.
2046  */
2047 int
2048 verifyMappingMatch(__nis_mapping_format_t *f, char *str) {
2049 	int			n, nf;
2050 	__nis_mapping_format_t	*ftmp;
2051 
2052 	/* Count the number of format elements in the format */
2053 	for (nf = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2054 		nf++;
2055 	}
2056 	/* Count the mmt_end as well */
2057 	nf++;
2058 
2059 	for (n = 0; n < nf; n++) {
2060 		str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2061 		if (str == 0)
2062 			break;
2063 	}
2064 
2065 	return ((str != 0) ? 1 : 0);
2066 }
2067 
2068 /*
2069  * Perform a match operation. For example, given the rule
2070  *	("{%s}%s", auth_name, public_data)=nisPublicKey
2071  * and assuming that 'nisPublicKey' has the value "{dh640-0}abcdef12345",
2072  * assign "dh640-0" to 'auth_name' and "abcdef12345" to 'public_data'.
2073  *
2074  * Note that this function doesn't perform the actual assignment. Rather,
2075  * it returns an array of __nis_value_t's, with element zero of the value
2076  * array being the new value of the first matched item, element one the
2077  * value of the second matched item, etc. In the example above, we'd
2078  * return a value array with two elements.
2079  *
2080  * If there is more than one input value (inVal->numVals > 1), the
2081  * output array elements will also be multi-valued.
2082  *
2083  * f		The match format
2084  * inVal	Input value(s)
2085  * numVal	Number of elements in the output value array
2086  * sepset	List of separators
2087  * outstr	Points to the updated position upto which the
2088  *		input string has been matched
2089  */
2090 __nis_value_t **
2091 matchMappingItem(__nis_mapping_format_t *f, __nis_value_t *inVal,
2092 		int *numVals, char *sepset, char **outstr) {
2093 	__nis_value_t		**v = 0;
2094 	int			i, n, ni, numItems, nf;
2095 	char			*str, *valstr;
2096 	__nis_mapping_format_t	*ftmp;
2097 	char			*myself = "matchMappingItem";
2098 
2099 	if (f == 0 ||
2100 		inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2101 		return (0);
2102 
2103 	/* Count the number of format elements and items in the format */
2104 	for (nf = numItems = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2105 		nf++;
2106 
2107 		/*
2108 		 * Count mmt_item and mmt_berstring (used by N2L to
2109 		 * represent address %a)
2110 		 */
2111 		if (ftmp->type == mmt_item)
2112 				numItems++;
2113 		else if (ftmp->type == mmt_berstring && ftmp->match.berString &&
2114 				ftmp->match.berString[0] == 'a')
2115 				numItems++;
2116 	}
2117 	/* Count the mmt_end as well */
2118 	nf++;
2119 
2120 	/*
2121 	 * If no items, there will be no values. This isn't exactly an error
2122 	 * from the limited point of view of this function, so we return a
2123 	 * __nis_value_t with zero values.
2124 	 */
2125 	if (numItems <= 0) {
2126 		v = am(myself, sizeof (v[0]));
2127 		if (v == 0)
2128 			return (0);
2129 		v[0] = am(myself, sizeof (*v[0]));
2130 		if (v[0] == 0) {
2131 			sfree(v);
2132 			return (0);
2133 		}
2134 		v[0]->type = vt_string;
2135 		v[0]->numVals = 0;
2136 		v[0]->val = 0;
2137 		if (numVals != 0)
2138 			*numVals = 1;
2139 		return (v);
2140 	}
2141 
2142 	/* Allocate and initialize the return array */
2143 	v = am(myself, numItems * sizeof (v[0]));
2144 	if (v == 0)
2145 		return (0);
2146 	for (n = 0; n < numItems; n++) {
2147 		v[n] = am(myself, sizeof (*v[n]));
2148 		if (v[n] == 0) {
2149 			int	j;
2150 
2151 			for (j = 0; j < n; j++)
2152 				freeValue(v[j], 1);
2153 			sfree(v);
2154 			return (0);
2155 		}
2156 		v[n]->type = vt_string;
2157 		v[n]->numVals = 0;
2158 		v[n]->val = am(myself, inVal->numVals * sizeof (v[n]->val[0]));
2159 		if (v[n]->val == 0) {
2160 			int	j;
2161 
2162 			for (j = 0; j < n; j++)
2163 				freeValue(v[j], 1);
2164 			sfree(v);
2165 			return (0);
2166 		}
2167 		for (i = 0; i < inVal->numVals; i++) {
2168 			v[n]->val[i].length = 0;
2169 			v[n]->val[i].value = 0;
2170 		}
2171 	}
2172 
2173 	/* For each input value, perform the match operation */
2174 	for (i = 0; i < inVal->numVals; i++) {
2175 		str = inVal->val[i].value;
2176 		if (str == 0)
2177 			continue;
2178 		for (n = 0, ni = 0; n < nf; n++) {
2179 			valstr = 0;
2180 			str = scanMappingFormat(f, n, nf, str, &valstr,
2181 				0, sepset);
2182 			if (str == 0)
2183 				break;
2184 			if (valstr != 0 && ni < numItems &&
2185 					v[ni]->numVals < inVal->numVals) {
2186 				v[ni]->val[v[ni]->numVals].value = valstr;
2187 				v[ni]->val[v[ni]->numVals].length =
2188 							strlen(valstr) + 1;
2189 				v[ni]->numVals++;
2190 				ni++;
2191 			} else if (valstr != 0) {
2192 				sfree(valstr);
2193 			}
2194 		}
2195 		if (str == 0) {
2196 			for (n = 0; n < numItems; n++)
2197 				freeValue(v[n], 1);
2198 			sfree(v);
2199 			return (0);
2200 		}
2201 	}
2202 
2203 	if (numVals != 0)
2204 		*numVals = numItems;
2205 
2206 	/*
2207 	 * Update the return string upto the point it has been matched
2208 	 * This string will be used by the N2L code in its next call
2209 	 * to this function
2210 	 */
2211 	if (outstr != 0)
2212 		*outstr = str;
2213 
2214 	return (v);
2215 }
2216 
2217 /*
2218  * Perform an extract operation. For example, given the expression
2219  *	(name, "%s.*")
2220  * and assuming 'name' is an item with the value "some.thing", the
2221  * value returned by the extract is "some".
2222  */
2223 __nis_value_t *
2224 extractMappingItem(__nis_mapping_item_t *item, __nis_mapping_format_t *f,
2225 		__nis_rule_value_t *rv, int *stat) {
2226 	__nis_value_t		*val = getMappingItem(item, mit_any,
2227 			rv, 0, stat);
2228 	__nis_single_value_t	*nval;
2229 	int			i, n, nv, nf;
2230 	__nis_mapping_format_t	*ftmp;
2231 
2232 	if (val == 0)
2233 		return (0);
2234 	else if (f == 0 || rv == 0 || val->val == 0 ||
2235 			val->numVals <= 0 || val->type != vt_string) {
2236 		freeValue(val, 1);
2237 		return (0);
2238 	}
2239 
2240 	/* Sanity check the format; it must have one and only one mmt_item */
2241 	{
2242 		int	numitem;
2243 
2244 		for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2245 				ftmp++) {
2246 			nf++;
2247 			if (ftmp->type == mmt_item)
2248 				numitem++;
2249 		}
2250 		/* Count the mmt_end as well */
2251 		nf++;
2252 		if (numitem != 1) {
2253 			freeValue(val, 1);
2254 			return (0);
2255 		}
2256 	}
2257 
2258 	nval = val->val;
2259 	nv = val->numVals;
2260 	val->repeat = FALSE;
2261 	val->val = 0;
2262 	val->numVals = 0;
2263 
2264 	/* If the item has multiple values, we extract each one independently */
2265 	for (i = 0; i < nv; i++) {
2266 		char			*str = nval[i].value;
2267 		char			*newstr = 0;
2268 		__nis_single_value_t	*newval;
2269 
2270 		if (nval[i].value == 0)
2271 			continue;
2272 
2273 		/*
2274 		 * We match the whole string, even if we find a value for
2275 		 * the item before exhausting all format elements. By doing
2276 		 * this, we ensure that the string really matches the complete
2277 		 * format specification.
2278 		 */
2279 		for (n = 0; n < nf; n++) {
2280 			str = scanMappingFormat(f, n, nf, str, &newstr, 0, 0);
2281 			if (str == 0)
2282 				break;
2283 		}
2284 
2285 		/*
2286 		 * *str should now be NUL, meaning we've reached the end of
2287 		 * the string (value), and it completely matched the format.
2288 		 * If 'str' is NULL, there was an error, and if 'newstr' is
2289 		 * 0, we somehow failed to obtain a value.
2290 		 */
2291 		if (str == 0 || *str != '\0' || newstr == 0 ||
2292 				(newval = realloc(val->val,
2293 					(val->numVals+1) *
2294 					sizeof (val->val[0]))) == 0) {
2295 			freeValue(val, 1);
2296 			for (n = 0; n < nv; n++) {
2297 				sfree(nval[n].value);
2298 			}
2299 			free(nval);
2300 			sfree(newstr);
2301 			return (0);
2302 		}
2303 
2304 		val->val = newval;
2305 		val->val[val->numVals].value = newstr;
2306 		val->val[val->numVals].length = strlen(newstr) + 1;
2307 		val->numVals++;
2308 
2309 		free(nval[i].value);
2310 		nval[i].value = 0;
2311 	}
2312 	free(nval);
2313 
2314 	return (val);
2315 }
2316 
2317 /*
2318  * For each value in 'val', remove the last character, provided that
2319  * it matches 'elide'.
2320  */
2321 void
2322 stringElide(__nis_value_t *val, char elide) {
2323 
2324 	if (val != 0 && val->type == vt_string) {
2325 		int	i;
2326 
2327 		for (i = 0; i < val->numVals; i++) {
2328 			int	end = val->val[i].length;
2329 			char	*str = val->val[i].value;
2330 
2331 			if (str == 0 || end <= 0)
2332 				continue;
2333 
2334 			/*
2335 			 * If the NUL was counted in the length, step back
2336 			 * over it.
2337 			 */
2338 			if (str[end-1] == '\0')
2339 				end--;
2340 			if (end > 0 && str[end-1] == elide) {
2341 				str[end-1] = '\0';
2342 				val->val[i].length--;
2343 			}
2344 		}
2345 	}
2346 }
2347 
2348 /*
2349  * Obtain the value for the mapping sub-element 'e', given the input
2350  * rule-value 'rv'.
2351  */
2352 __nis_value_t *
2353 getMappingSubElement(__nis_mapping_sub_element_t *e,
2354 	__nis_rule_value_t *rv, int *np_ldap_stat) {
2355 	__nis_value_t	*val;
2356 
2357 	if (e == 0)
2358 		return (0);
2359 
2360 	switch (e->type) {
2361 	case me_item:
2362 		val = getMappingItem(&e->element.item, mit_any, rv, 0,
2363 			np_ldap_stat);
2364 		break;
2365 	case me_print:
2366 		val = getMappingFormatArray(e->element.print.fmt, rv,
2367 						fa_item,
2368 						e->element.print.numItems,
2369 						e->element.print.item);
2370 		if (e->element.print.doElide)
2371 			stringElide(val, e->element.print.elide);
2372 		break;
2373 	case me_split:
2374 		val = splitMappingItem(&e->element.split.item,
2375 					e->element.split.delim,
2376 					rv);
2377 		break;
2378 	case me_extract:
2379 		val = extractMappingItem(&e->element.extract.item,
2380 					e->element.extract.fmt,
2381 					rv, np_ldap_stat);
2382 		break;
2383 	case me_match:
2384 	default:
2385 		val = 0;
2386 		break;
2387 	}
2388 
2389 	return (val);
2390 }
2391 
2392 /*
2393  * Obtain the value of the mapping element 'e', given the input rule-
2394  * value 'rv'. The 'native' mapping type is used when 'rv' is NULL,
2395  * and the result is a string representation of the mapping element;
2396  * in that case, items of the 'native' type are printed without their
2397  * type designation ("nis+" or "ldap").
2398  */
2399 __nis_value_t *
2400 getMappingElement(__nis_mapping_element_t *e, __nis_mapping_item_type_t native,
2401 		__nis_rule_value_t *rv, int *stat) {
2402 	__nis_value_t	*val, **tv;
2403 	int		i, success = 0, novalue = 0;
2404 	int *np_ldap_stat;
2405 	char		*myself = "getMappingElement";
2406 
2407 	switch (e->type) {
2408 	case me_item:
2409 		val = getMappingItem(&e->element.item, native, rv, 0, NULL);
2410 		break;
2411 	case me_print:
2412 		tv = am(myself, e->element.print.numSubElements *
2413 			sizeof (tv[0]));
2414 		np_ldap_stat = am(myself,
2415 			e->element.print.numSubElements * sizeof (int));
2416 		if ((e->element.print.numSubElements > 0) &&
2417 				(tv == 0 || np_ldap_stat == 0)) {
2418 			val = 0;
2419 			sfree(tv);
2420 			sfree(np_ldap_stat);
2421 			break;
2422 		}
2423 		for (i = 0; i < e->element.print.numSubElements; i++) {
2424 			np_ldap_stat[i] = 0;
2425 			tv[i] = getMappingSubElement(
2426 				&e->element.print.subElement[i],
2427 				rv, &np_ldap_stat[i]);
2428 		}
2429 		/*
2430 		 * if we get NP_LDAP_NO_VALUE to any of the subelement
2431 		 * and we get NP_LDAP_MAP_SUCCESS to all other subelement
2432 		 * then we had enough nis+ column values which can
2433 		 * produce value for this rule, but didn't. So return
2434 		 * NP_LDAP_RULES_NO_VALUE to indicate to proceed to
2435 		 * next database id.
2436 		 */
2437 		for (i = 0; i < e->element.print.numSubElements; i++) {
2438 			if (np_ldap_stat[i] == NP_LDAP_MAP_SUCCESS)
2439 				success++;
2440 			if (np_ldap_stat[i] == NP_LDAP_NO_VALUE)
2441 				novalue++;
2442 		}
2443 		if (stat != NULL && novalue > 0 &&
2444 				((novalue+success) ==
2445 					e->element.print.numSubElements))
2446 					    *stat = NP_LDAP_RULES_NO_VALUE;
2447 		val = getMappingFormatArray(e->element.print.fmt, rv,
2448 						fa_value,
2449 						e->element.print.numSubElements,
2450 						tv);
2451 		for (i = 0; i < e->element.print.numSubElements; i++) {
2452 			freeValue(tv[i], 1);
2453 		}
2454 		sfree(tv);
2455 		sfree(np_ldap_stat);
2456 		if (e->element.print.doElide)
2457 			stringElide(val, e->element.print.elide);
2458 		break;
2459 	case me_split:
2460 		val = splitMappingItem(&e->element.split.item,
2461 					e->element.split.delim,
2462 					rv);
2463 		break;
2464 	case me_match:
2465 		/*
2466 		 * A match doesn't produce an assignable value per se,
2467 		 * so we shouldn't get one here.
2468 		 */
2469 		val = 0;
2470 		break;
2471 	case me_extract:
2472 		val = extractMappingItem(&e->element.extract.item,
2473 					e->element.extract.fmt,
2474 					rv, NULL);
2475 		break;
2476 	default:
2477 		val = 0;
2478 		break;
2479 	}
2480 
2481 	return (val);
2482 }
2483