xref: /titanic_52/usr/src/lib/libnisdb/ldap_val.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
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 && ia >= numArgs) {
1102 				ia = (numArgs > 0) ? numArgs - 1 : 0;
1103 				moreArgs = FALSE;
1104 			}
1105 		}
1106 		/*
1107 		 * We've run out of format, so if we still have arguments
1108 		 * left, start over on the format.
1109 		 */
1110 		if (ia < numArgs && moreArgs) {
1111 			/*
1112 			 * However, if we didn't consume any arguments going
1113 			 * through the format once, abort to avoid an infinite
1114 			 * loop.
1115 			 */
1116 			if (numArgs > 0 && ia <= 0) {
1117 				freeValue(v, 1);
1118 				return (0);
1119 			}
1120 			moreFormat = 1;
1121 		}
1122 	}
1123 
1124 	return (v);
1125 }
1126 
1127 /*
1128  * Returns a string representation (such as "[name=foo, value=bar]")
1129  * of a nis_index_t.
1130  */
1131 char *
1132 getIndex(__nis_index_t *i, int *len) {
1133 	int		n;
1134 	__nis_buffer_t	b = {0, 0};
1135 	char		*myself = "getIndex";
1136 
1137 	if (i == 0)
1138 		return (0);
1139 
1140 	if (i->numIndexes > 0) {
1141 		bp2buf(myself, &b, "[");
1142 		for (n = 0; n < i->numIndexes; n++) {
1143 			__nis_value_t	*val;
1144 			int		j;
1145 
1146 			val = getMappingFormatArray(i->value[n],
1147 						0, fa_any, 0, 0);
1148 			if (n > 0)
1149 				bp2buf(myself, &b, ", ");
1150 			bp2buf(myself, &b, "%s=", i->name[n]);
1151 			if (val != 0) {
1152 				for (j = 0; j < val->numVals; j++) {
1153 					bc2buf(myself, val->val[j].value,
1154 						val->val[j].length, &b);
1155 				}
1156 			} else {
1157 				bp2buf(myself, &b, "<no-vals>");
1158 			}
1159 			freeValue(val, 1);
1160 		}
1161 		bp2buf(myself, &b, "]");
1162 	}
1163 	if (len != 0)
1164 		*len = b.len;
1165 	return (b.buf);
1166 }
1167 
1168 char *
1169 getObjSpec(__nis_obj_spec_t *o, int *len) {
1170 	__nis_buffer_t	b = {0, 0};
1171 	char		*myself = "getObjSpec";
1172 
1173 	if (o == 0)
1174 		return (0);
1175 
1176 	b.buf = getIndex(&o->index, &b.len);
1177 	sbc2buf(myself, o->name, slen(o->name), &b);
1178 	if (len != 0)
1179 		*len = b.len;
1180 	return (b.buf);
1181 }
1182 
1183 /*
1184  * Returns a string representation of the LDAP scope. Note that the
1185  * returned value is a static entity, and must be copied by the
1186  * caller (but, obviously, must not be freed).
1187  */
1188 char *
1189 getScope(int scope) {
1190 	switch (scope) {
1191 	case LDAP_SCOPE_BASE:
1192 		return ("base");
1193 	case LDAP_SCOPE_ONELEVEL:
1194 		return ("one");
1195 	case LDAP_SCOPE_SUBTREE:
1196 		return ("sub");
1197 	default:
1198 		return ("one");
1199 	}
1200 }
1201 
1202 /*
1203  * Return a string representation of an LDAP search triple (such as
1204  * "ou=Hosts,dc=eng,dc=sun,dc=com?one?cn=xyzzy").
1205  */
1206 char *
1207 getSearchTriple(__nis_search_triple_t *s, int *len) {
1208 	__nis_buffer_t	b = {0, 0};
1209 	char		*a;
1210 	int		l;
1211 	char		*myself = "getSearchTriple";
1212 
1213 	/* If the scope is LDAP_SCOPE_UNKNOWN, the search triple is unused */
1214 	if (s == 0 || s->scope == LDAP_SCOPE_UNKNOWN) {
1215 		if (len != 0)
1216 			*len = 0;
1217 		return (0);
1218 	}
1219 
1220 	if (s->base != 0)
1221 		sbc2buf(myself, s->base, slen(s->base), &b);
1222 	if (!(s->scope == LDAP_SCOPE_ONELEVEL &&
1223 			(s->base == 0 || s->base[0] == '\0'))) {
1224 		bp2buf(myself, &b, "?%s?", getScope(s->scope));
1225 	}
1226 	if ((l = slen(s->attrs)) > 0) {
1227 		/*
1228 		 * Remove white space from the filter/attribute list.
1229 		 * The parser usually keeps any white space from the
1230 		 * config file (or LDAP/command line), but we don't
1231 		 * want it.
1232 		 */
1233 		a = am(myself, l+1);
1234 		if (a != 0) {
1235 			int	i, la;
1236 
1237 			for (i = 0, la = 0; i < l; i++) {
1238 				if (s->attrs[i] != ' ' &&
1239 						s->attrs[i] != '\t')
1240 					a[la++] = s->attrs[i];
1241 			}
1242 			sbc2buf(myself, a, la, &b);
1243 			sfree(a);
1244 		} else {
1245 			sbc2buf(myself, s->attrs, slen(s->attrs), &b);
1246 		}
1247 	}
1248 
1249 	if (len != 0)
1250 		*len = b.len;
1251 	return (b.buf);
1252 }
1253 
1254 __nis_value_t *
1255 getMappingItem(__nis_mapping_item_t *i, __nis_mapping_item_type_t native,
1256 		__nis_rule_value_t *rv, char *berstring, int *np_ldap_stat) {
1257 	char		*myself = "getMappingItem";
1258 	__nis_value_t	*val = 0;
1259 	__nis_buffer_t	b = {0, 0};
1260 	int		len = 0;
1261 	char		*buf;
1262 
1263 	if (i == 0)
1264 		return (0);
1265 
1266 	if (rv != 0)
1267 		return (getMappingItemVal(i, native, rv, berstring,
1268 			np_ldap_stat));
1269 
1270 	val = am(myself, sizeof (*val));
1271 	if (val == 0)
1272 		return (0);
1273 
1274 	switch (i->type) {
1275 	case mit_nisplus:
1276 		if (native != mit_nisplus)
1277 			bp2buf(myself, &b, "nis+:");
1278 		bp2buf(myself, &b, "%s", NIL(i->name));
1279 		buf = getObjSpec(&i->searchSpec.obj, &len);
1280 		if (buf != 0 && len > 0) {
1281 			bc2buf(myself, ":", 1, &b);
1282 			sbc2buf(myself, buf, len, &b);
1283 		}
1284 		sfree(buf);
1285 		val->type = vt_string;
1286 		val->repeat = i->repeat;
1287 		val->numVals = 1;
1288 		val->val = am(myself, sizeof (val->val[0]));
1289 		if (val->val == 0) {
1290 			sfree(b.buf);
1291 			free(val);
1292 			return (0);
1293 		}
1294 		val->val[0].value = b.buf;
1295 		val->val[0].length = b.len;
1296 		break;
1297 	case mit_ldap:
1298 		if (native != mit_ldap)
1299 			bp2buf(myself, &b, "ldap:");
1300 		bp2buf(myself, &b, "%s", NIL(i->name));
1301 		buf = getSearchTriple(&i->searchSpec.triple, &len);
1302 		if (buf != 0 && len > 0) {
1303 			bc2buf(myself, ":", 1, &b);
1304 			sbc2buf(myself, buf, len, &b);
1305 		}
1306 		sfree(buf);
1307 		val->type = vt_string;
1308 		val->repeat = i->repeat;
1309 		val->numVals = 1;
1310 		val->val = am(myself, sizeof (val->val[0]));
1311 		if (val->val == 0) {
1312 			sfree(b.buf);
1313 			free(val);
1314 			return (0);
1315 		}
1316 		val->val[0].value = b.buf;
1317 		val->val[0].length = b.len;
1318 		break;
1319 	default:
1320 		p2buf(myself, "<unknown>:");
1321 		p2buf(myself, "%s", NIL(i->name));
1322 		break;
1323 	}
1324 
1325 	return (val);
1326 }
1327 
1328 void
1329 copyObjSpec(__nis_obj_spec_t *old, __nis_obj_spec_t *new, int *err) {
1330 	char	*myself = "copyObjSpec";
1331 
1332 	if (old == 0 || new == 0) {
1333 		*err = EINVAL;
1334 		return;
1335 	}
1336 
1337 	if (new->index.name == 0) {
1338 		new->index.name = am(myself, old->index.numIndexes *
1339 						sizeof (new->index.name[0]));
1340 		if (old->index.numIndexes > 0 && new->index.name == 0) {
1341 			*err = ENOMEM;
1342 			return;
1343 		}
1344 		new->index.value = am(myself, old->index.numIndexes *
1345 						sizeof (new->index.value[0]));
1346 		if (old->index.numIndexes > 0 && new->index.value == 0) {
1347 			*err = ENOMEM;
1348 			return;
1349 		}
1350 	}
1351 	new->name = sdup(myself, T, old->name);
1352 	if (new->name == 0 && old->name != 0) {
1353 		*err = ENOMEM;
1354 		return;
1355 	}
1356 	copyIndex(&old->index, &new->index, err);
1357 }
1358 
1359 __nis_obj_spec_t *
1360 cloneObjSpec(__nis_obj_spec_t *old) {
1361 	char			*myself = "cloneObjSpec";
1362 	int			err = 0;
1363 	__nis_obj_spec_t	*new = am(myself, sizeof (*new));
1364 
1365 	if (new != 0) {
1366 		copyObjSpec(old, new, &err);
1367 		if (err != 0) {
1368 			freeObjSpec(new, 1);
1369 			new = 0;
1370 		}
1371 	}
1372 
1373 	return (new);
1374 }
1375 
1376 void
1377 freeObjSpec(__nis_obj_spec_t *old, bool_t doFree) {
1378 
1379 	if (old == 0)
1380 		return;
1381 
1382 	sfree(old->name);
1383 	freeIndex(&old->index, FALSE);
1384 	if (doFree)
1385 		free(old);
1386 }
1387 
1388 void
1389 copySearchTriple(__nis_search_triple_t *old, __nis_search_triple_t *new,
1390 		int *err) {
1391 	char			*myself = "copySearchTriple";
1392 
1393 	*err = 0;
1394 
1395 	if (old == 0 || new == 0) {
1396 		*err = EINVAL;
1397 		return;
1398 	}
1399 
1400 	if (old->base != NULL)
1401 		new->base = sdup(myself, T, old->base);
1402 	else
1403 		new->base = NULL;
1404 	if (old->attrs != NULL)
1405 		new->attrs = sdup(myself, T, old->attrs);
1406 	else
1407 		new->attrs = NULL;
1408 	if ((new->base == 0 && old->base != 0) ||
1409 			(new->attrs == 0 && old->attrs != 0)) {
1410 		sfree(new->base);
1411 		new->base = 0;
1412 		sfree(new->attrs);
1413 		new->attrs = 0;
1414 		*err = ENOMEM;
1415 		return;
1416 	}
1417 	new->scope = old->scope;
1418 	/*
1419 	 * XXX Really should have a cloneMappingElement() function.
1420 	 * However, since whatever the 'element' field points to
1421 	 * is allocated at parse time, and never is freed or modified,
1422 	 * it's sufficient to copy the pointer value.
1423 	 */
1424 	new->element = old->element;
1425 }
1426 
1427 __nis_search_triple_t *
1428 cloneSearchTriple(__nis_search_triple_t *old) {
1429 	char			*myself = "cloneSearchTriple";
1430 	int			err = 0;
1431 	__nis_search_triple_t	*new = am(myself, sizeof (*new));
1432 
1433 	if (new != 0) {
1434 		copySearchTriple(old, new, &err);
1435 		if (err != 0) {
1436 			freeSearchTriple(new, 1);
1437 			new = 0;
1438 		}
1439 	}
1440 
1441 	return (new);
1442 }
1443 
1444 void
1445 freeSearchTriple(__nis_search_triple_t *old, bool_t doFree) {
1446 
1447 	if (old == 0)
1448 		return;
1449 
1450 	sfree(old->base);
1451 	sfree(old->attrs);
1452 	/*
1453 	 * Since we only copied the element pointer when this structure
1454 	 * was created, we don't free old->element.
1455 	 */
1456 	if (doFree)
1457 		free(old);
1458 }
1459 
1460 void
1461 copyTripleOrObj(__nis_mapping_item_type_t type,
1462 		__nis_triple_or_obj_t *old, __nis_triple_or_obj_t *new,
1463 		int *err) {
1464 
1465 	*err = 0;
1466 
1467 	if (old == 0 || new == 0) {
1468 		*err = EINVAL;
1469 		return;
1470 	}
1471 
1472 	if (type == mit_nisplus) {
1473 		copyObjSpec(&old->obj, &new->obj, err);
1474 	} else if (type == mit_ldap) {
1475 		copySearchTriple(&old->triple, &new->triple, err);
1476 	}
1477 }
1478 
1479 __nis_triple_or_obj_t *
1480 cloneTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old) {
1481 	char			*myself = "cloneTripleOrObj";
1482 	int			err = 0;
1483 	__nis_triple_or_obj_t	*new = am(myself, sizeof (*new));
1484 
1485 	if (new != 0) {
1486 		copyTripleOrObj(type, old, new, &err);
1487 		if (err != 0) {
1488 			freeTripleOrObj(type, new, 1);
1489 			new = 0;
1490 		}
1491 	}
1492 
1493 	return (new);
1494 }
1495 
1496 void
1497 freeTripleOrObj(__nis_mapping_item_type_t type, __nis_triple_or_obj_t *old,
1498 		bool_t doFree) {
1499 
1500 	if (old == 0)
1501 		return;
1502 
1503 	if (type == mit_nisplus)
1504 		freeObjSpec(&old->obj, doFree);
1505 	else if (type == mit_ldap)
1506 		freeSearchTriple(&old->triple, doFree);
1507 
1508 	if (doFree)
1509 		free(old);
1510 }
1511 
1512 void
1513 copyItem(__nis_mapping_item_t *old, __nis_mapping_item_t *new, int *err) {
1514 
1515 	*err = 0;
1516 
1517 	if (old == 0 || new == 0) {
1518 		*err = EINVAL;
1519 		return;
1520 	}
1521 
1522 	new->type = old->type;
1523 	new->repeat = old->repeat;
1524 	if (old->name != 0) {
1525 		new->name = strdup(old->name);
1526 		if (new->name == 0) {
1527 			*err = ENOMEM;
1528 			return;
1529 		}
1530 	} else {
1531 		new->name = 0;
1532 	}
1533 	if (old->type == mit_nisplus || old->type == mit_ldap)
1534 		copyTripleOrObj(old->type, &old->searchSpec, &new->searchSpec,
1535 				err);
1536 	else
1537 		memset(&new->searchSpec, 0, sizeof (new->searchSpec));
1538 }
1539 
1540 __nis_mapping_item_t *
1541 cloneItem(__nis_mapping_item_t *old) {
1542 	__nis_mapping_item_t	*new;
1543 	int			err = 0;
1544 	char			*myself = "cloneItem";
1545 
1546 	if (old == 0)
1547 		return (0);
1548 
1549 	new = am(myself, sizeof (*new));
1550 	if (new == 0)
1551 		return (0);
1552 
1553 	copyItem(old, new, &err);
1554 	if (err != 0) {
1555 		freeMappingItem(new, 1);
1556 		return (0);
1557 	}
1558 
1559 	return (new);
1560 }
1561 
1562 void
1563 freeMappingItem(__nis_mapping_item_t *item, int numItems) {
1564 	int	i;
1565 
1566 	if (item == 0)
1567 		return;
1568 
1569 	for (i = 0; i < numItems; i++) {
1570 		sfree(item[i].name);
1571 		freeTripleOrObj(item[i].type, &item[i].searchSpec, FALSE);
1572 	}
1573 	sfree(item);
1574 }
1575 
1576 __nis_mapping_item_t *
1577 concatenateMappingItem(__nis_mapping_item_t *old, int numItems,
1578 		__nis_mapping_item_t *cat) {
1579 	__nis_mapping_item_t	*new;
1580 	int			i, err = 0;
1581 	char			*myself = "concatenateMappingItem";
1582 
1583 	if (old == 0 || numItems < 1)
1584 		return (cloneItem(cat));
1585 
1586 	new = am(myself, (numItems + 1) * sizeof (*new));
1587 	if (new == 0)
1588 		return (0);
1589 
1590 	for (i = 0; i < numItems; i++) {
1591 		copyItem(&old[i], &new[i], &err);
1592 		if (err != 0) {
1593 			freeMappingItem(new, i);
1594 			return (0);
1595 		}
1596 	}
1597 	copyItem(cat, &new[numItems], &err);
1598 	if (err != 0) {
1599 		freeMappingItem(new, numItems);
1600 		new = 0;
1601 	}
1602 
1603 	return (new);
1604 }
1605 
1606 __nis_value_t *
1607 concatenateValues(__nis_value_t *v1, __nis_value_t *v2) {
1608 	int		i, n, a;
1609 	__nis_value_t	*v;
1610 	char		*myself = "concatenateValues";
1611 
1612 	if (v1 == 0 || v1->numVals <= 0)
1613 		return (cloneValue(v2, 1));
1614 	if (v2 == 0 || v2->numVals <= 0)
1615 		return (cloneValue(v1, 1));
1616 
1617 	if (v1->type != v2->type)
1618 		return (0);
1619 
1620 	n = v1->numVals + v2->numVals;
1621 	v = am(myself, sizeof (*v));
1622 	if (v == 0)
1623 		return (0);
1624 	v->val = am(myself, n * sizeof (v->val[0]));
1625 	if (v->val == 0) {
1626 		free(v);
1627 		return (0);
1628 	}
1629 	v->type = v1->type;
1630 	v->numVals = 0;
1631 
1632 	for (a = 0; a < 2; a++) {
1633 		__nis_single_value_t	*val = (a == 0) ? v1->val : v2->val;
1634 		int			numv = (a == 0) ? v1->numVals :
1635 							v2->numVals;
1636 		for (i = 0; i < numv; i++) {
1637 			int	clen, alen = val[i].length;
1638 
1639 			clen = alen;
1640 
1641 			/*
1642 			 * Make sure there's a NUL at the end of a string,
1643 			 * but avoid adding to the allocated length if there's
1644 			 * already a NUL at the end.
1645 			 */
1646 			if (alen > 0 && v->type == vt_string &&
1647 					((char *)val[i].value)[alen-1] != '\0')
1648 				alen += 1;
1649 			v->val[v->numVals].value = am(myself, alen);
1650 			if (v->val[v->numVals].value == 0) {
1651 				freeValue(v, 1);
1652 				return (0);
1653 			}
1654 			memcpy(v->val[v->numVals].value, val[i].value, clen);
1655 			v->val[v->numVals].length = val[i].length;
1656 			v->numVals++;
1657 		}
1658 	}
1659 
1660 	return (v);
1661 }
1662 
1663 __nis_value_t *
1664 splitMappingItem(__nis_mapping_item_t *item, char delim,
1665 		__nis_rule_value_t *rv) {
1666 	__nis_value_t		*val = getMappingItem(item, mit_any,
1667 			rv, 0, NULL);
1668 	__nis_single_value_t	*nval;
1669 	int			i, n, nv;
1670 
1671 	if (val == 0)
1672 		return (0);
1673 	else if (delim == 0 || val->val == 0 || val->numVals <= 0 ||
1674 			val->type != vt_string) {
1675 		freeValue(val, 1);
1676 		return (0);
1677 	}
1678 
1679 	nval = val->val;
1680 	nv = val->numVals;
1681 	val->repeat = FALSE;
1682 	val->val = 0;
1683 	val->numVals = 0;
1684 
1685 	/* In N2L, space and tab delimiters are treated the same */
1686 	if (yp2ldap && delim == '\t')
1687 		delim = ' ';
1688 
1689 	/* If the item has multiple values, we split each one independently */
1690 	for (i = 0; i < nv; i++) {
1691 		char			*str;
1692 		int			s, e;
1693 		char			*newstr;
1694 		__nis_single_value_t	*newval;
1695 
1696 		if (yp2ldap && delim == ' ')
1697 			nval[i].value = trimWhiteSpaces(nval[i].value,
1698 							&nval[i].length, 1);
1699 
1700 		str = nval[i].value;
1701 
1702 		if (nval[i].value == 0)
1703 			continue;
1704 
1705 		for (s = 0; s < nval[i].length; s = e+1) {
1706 			/* Find the next delimiter, or end-of-string */
1707 			for (e = s; str[e] != '\0' && str[e] != delim; e++);
1708 			/*
1709 			 * 'str[e]' is either a delimiter, or the concluding
1710 			 * NUL. Make sure it's NUL.
1711 			 */
1712 			str[e] = '\0';
1713 			/* Add to val->val */
1714 			newstr = strdup(&str[s]);
1715 			newval = realloc(val->val,
1716 					(val->numVals+1) *
1717 						sizeof (val->val[0]));
1718 			if (newval != 0)
1719 				val->val = newval;
1720 			if (newstr == 0 || newval == 0) {
1721 				freeValue(val, 1);
1722 				for (n = i; n < nv; n++) {
1723 					sfree(nval[n].value);
1724 				}
1725 				free(nval);
1726 				sfree(newstr);
1727 				return (0);
1728 			}
1729 			val->val[val->numVals].value = newstr;
1730 			val->val[val->numVals].length = strlen(newstr) + 1;
1731 			val->numVals++;
1732 		}
1733 		free(nval[i].value);
1734 		nval[i].value = 0;
1735 	}
1736 	/* Already freed the nval[i].value's as we traversed nval */
1737 	free(nval);
1738 
1739 	return (val);
1740 }
1741 
1742 /*
1743  * Match the format spec 'f[curf]' to the input value string 'str'.
1744  *
1745  * If successful, returns the updated position in the value string 'str'.
1746  * Otherwise, NULL is returned.
1747  *
1748  * curf		Current index (i.e., the one we should look at) in 'f'
1749  * nf		Number of elements in 'f', including 'mmt_end'
1750  * str		The value string we're scanning
1751  * val		Pointer to where an item value (if any) should be returned
1752  *		Set to NULL if not an 'mmt_item'.
1753  * fmtstart	If non-zero on entry, skip characters in 'str' until we find
1754  *		the f[curf].type data, if doing so makes any sense. On exit,
1755  *		set to the start of the fmt element data (which will be 'str',
1756  *		unless we did skip characters)
1757  * sepset	List of separators
1758  */
1759 char *
1760 scanMappingFormat(__nis_mapping_format_t *f, int curf, int nf, char *str,
1761 		char **val, char **fmtstart, char *sepset) {
1762 	char	*mstr, *next, *start = 0, *tmpstr;
1763 	int	i, len;
1764 	bool_t	match;
1765 	char	*myself = "scanMappingFormat";
1766 	/* N2L variables */
1767 	int	af, skipspaces = 0;
1768 	bool_t	ipaddr = FALSE;
1769 	char	*spacestr = " ", *emptystr = "";
1770 
1771 
1772 	if (f == 0 || curf < 0 || nf <= 0 || str == 0)
1773 		return (0);
1774 
1775 	/*
1776 	 * If separator list is NULL (which will be the case for
1777 	 * nis+2ldap), then simply use empty string
1778 	 */
1779 	if (sepset == 0)
1780 		sepset = emptystr;
1781 
1782 	if (curf >= nf) {
1783 		/* OK if the string also is exhausted */
1784 		if (strchr(sepset, *str) != 0)
1785 			return (str);
1786 		else
1787 			return (0);
1788 	}
1789 
1790 	switch (f[curf].type) {
1791 	case mmt_berstring:
1792 		if (f[curf].match.berString[0] != 'a') {
1793 			/* Not a matchable element */
1794 			return (0);
1795 		}
1796 
1797 		/*
1798 		 * If here, it means it's an IP address (N2L case)
1799 		 * So continue processing as if it was mmt_item
1800 		 */
1801 		ipaddr = TRUE;
1802 
1803 	case mmt_item:
1804 		/*
1805 		 * In order to find the end of the item value, we must look
1806 		 * ahead and determine the start of the next formatting element.
1807 		 * If successful, 'next' will be the start of the fmt element
1808 		 * after the next one; we don't care about that, other than to
1809 		 * check for error.
1810 		 *
1811 		 * Since an item match is somewhat like an any match, in that
1812 		 * we don't know a priori if the first occurence of the next
1813 		 * element really is the one we want, we have to scan ahead
1814 		 * until we've reached the end.
1815 		 */
1816 		tmpstr = str;
1817 		while ((next = scanMappingFormat(f, curf+1, nf, tmpstr, 0,
1818 				&start, sepset)) != 0) {
1819 			char	*tmp = next;
1820 			int	cf;
1821 
1822 			for (cf = curf+2; cf < nf; cf++) {
1823 				tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1824 					0, sepset);
1825 				if (tmp == 0)
1826 					break;
1827 			}
1828 			if (tmp == 0) {
1829 				tmpstr = next;
1830 			} else if (strchr(sepset, *tmp) != 0) {
1831 				break;
1832 			} else {
1833 				return (0);
1834 			}
1835 
1836 		}
1837 		if (next == 0 || start == 0)
1838 			return (0);
1839 
1840 		if (val != 0) {
1841 			len = (int)((long)start - (long)str);
1842 			*val = am(myself, len + 1);
1843 			if (*val == 0)
1844 				return (0);
1845 			memcpy(*val, str, len);
1846 			(*val)[len] = '\0';
1847 
1848 			if (ipaddr == TRUE) {
1849 				/*
1850 				 * In N2L, we need to check if *val is truly an
1851 				 * IP address
1852 				 */
1853 				af = checkIPaddress(*val, len, &tmpstr);
1854 
1855 				if (af == -2) {
1856 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1857 						"%s:Internal error while "
1858 						"processing IPaddress %s",
1859 						myself, *val);
1860 					sfree(*val);
1861 					return (0);
1862 				} else if (af == -1) {
1863 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1864 						"%s:%s is not an IP address",
1865 						myself, *val);
1866 					sfree(*val);
1867 					return (0);
1868 				} else if (af == 0) {
1869 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1870 						"%s:IP address %s is not "
1871 						"supported by rfc2307bis",
1872 						myself, *val);
1873 					sfree(*val);
1874 					return (0);
1875 				} else if (sstrncmp(*val, tmpstr, len) != 0) {
1876 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1877 						"%s:IPaddress %s converted "
1878 						"to %s", myself, *val, tmpstr);
1879 				}
1880 
1881 				sfree(*val);
1882 				*val = tmpstr;
1883 			}
1884 		}
1885 
1886 		if (fmtstart != 0)
1887 			*fmtstart = str;
1888 
1889 		return (start);
1890 
1891 	case mmt_string:
1892 		if ((mstr = f[curf].match.string) == 0 || *mstr == '\0') {
1893 			/*
1894 			 * Count this as a successful match of an empty
1895 			 * string.
1896 			 */
1897 			if (fmtstart != 0)
1898 				*fmtstart = str;
1899 			return (str);
1900 		}
1901 
1902 		/*
1903 		 * In N2L, if the format string 'mstr' contains only
1904 		 * whitespaces (spaces and tabs), then it should
1905 		 * match one or more whitespaces from the input
1906 		 * string 'str'.
1907 		 */
1908 		if (yp2ldap && strspn(mstr, " \t") == strlen(mstr)) {
1909 				mstr = spacestr;
1910 				skipspaces = 1;
1911 				next = str + strcspn(str, " \t");
1912 				/*
1913 				 * Even if there is no whitespace in 'str',
1914 				 * it's OK. This is to allow formats like
1915 				 * "%s %s %s" to match inputs like "foo bar".
1916 				 */
1917 				if (*next == '\0')
1918 					mstr = emptystr;
1919 		} else {
1920 			/* No match string in 'str' => failure */
1921 			if ((next = strstr(str, mstr)) == 0)
1922 				return (0);
1923 		}
1924 
1925 		/* If 'fmtstart' == 0, we require 'next' == 'str' */
1926 		if (fmtstart == 0 && next != str)
1927 			return (0);
1928 		/* Success; save start of match string if requested */
1929 		if (fmtstart != 0)
1930 			*fmtstart = next;
1931 		/* Update position in the value string */
1932 		str = (char *)((long)next + (long)strlen(mstr));
1933 
1934 		/* Skip whitespaces for N2L */
1935 		if (skipspaces == 1)
1936 			for (; *str == ' ' || *str == '\t'; str++);
1937 
1938 		return (str);
1939 
1940 	case mmt_single:
1941 		if (fmtstart != 0) {
1942 			match = FALSE;
1943 			/* Skip ahead until we match */
1944 			for (next = str; *next != '\0'; next++) {
1945 				unsigned char	*lo = f[curf].match.single.lo;
1946 				unsigned char	*hi = f[curf].match.single.hi;
1947 
1948 				for (i = 0; i < f[curf].match.single.numRange;
1949 						i++) {
1950 					if (*next >= lo[i] && *next <= hi[i]) {
1951 						match = TRUE;
1952 						break;
1953 					}
1954 				}
1955 				if (match)
1956 					break;
1957 			}
1958 			if (!match)
1959 				return (0);
1960 			*fmtstart = next;
1961 			str = next;
1962 		} else {
1963 			match = FALSE;
1964 			for (i = 0; i < f[curf].match.single.numRange; i++) {
1965 				if (*str >= f[curf].match.single.lo[i] &&
1966 					*str <= f[curf].match.single.hi[i]) {
1967 					match = TRUE;
1968 					break;
1969 				}
1970 			}
1971 			if (!match)
1972 				return (0);
1973 		}
1974 		/* Step over the matched character */
1975 		str++;
1976 		return (str);
1977 
1978 	case mmt_any:
1979 		/*
1980 		 * Look ahead to find the beginning of the next element.
1981 		 * Because a wildcard-match isn't necessarily uniquely
1982 		 * determined until we've reached the end, we then continue
1983 		 * to scan ahead.
1984 		 */
1985 		while ((next = scanMappingFormat(f, curf+1, nf, str, 0,
1986 						&start, sepset)) != 0) {
1987 			char	*tmp = next;
1988 			int	cf;
1989 
1990 			for (cf = curf+2; cf < nf; cf++) {
1991 				tmp = scanMappingFormat(f, cf, nf, tmp, 0,
1992 					0, sepset);
1993 				if (tmp == 0)
1994 					break;
1995 			}
1996 			if (tmp == 0) {
1997 				str = next;
1998 			} else if (*tmp == '\0') {
1999 				break;
2000 			} else {
2001 				return (0);
2002 			}
2003 		}
2004 		if (next == 0 || start == 0)
2005 			return (0);
2006 
2007 		if (fmtstart != 0)
2008 			*fmtstart = str;
2009 
2010 		return (start);
2011 
2012 	case mmt_limit:
2013 		if (f[curf].match.limit == eos) {
2014 			if (fmtstart != 0) {
2015 				/* Skip to the end */
2016 				str = str + strcspn(str, sepset);
2017 				*fmtstart = str;
2018 			} else if (strchr(sepset, *str) == 0) {
2019 				return (0);
2020 			}
2021 		}
2022 		return (str);
2023 
2024 	case mmt_begin:
2025 		if (fmtstart != 0)
2026 			*fmtstart = str;
2027 		return (str);
2028 
2029 	case mmt_end:
2030 		if (fmtstart != 0) {
2031 			/* Skip to the end */
2032 			str = str + strcspn(str, sepset);
2033 			*fmtstart = str;
2034 			return (str);
2035 		}
2036 		/* No skipping, so we must be at the end of the value */
2037 		if (strchr(sepset, *str) == 0)
2038 			return (0);
2039 		return (str);
2040 
2041 	default:
2042 		break;
2043 	}
2044 
2045 	return (0);
2046 }
2047 
2048 /*
2049  * Verify that the string 'str' matches the mapping format array 'f'.
2050  * Returns 1 in case of a match, 0 otherwise.
2051  */
2052 int
2053 verifyMappingMatch(__nis_mapping_format_t *f, char *str) {
2054 	int			n, nf;
2055 	__nis_mapping_format_t	*ftmp;
2056 
2057 	/* Count the number of format elements in the format */
2058 	for (nf = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2059 		nf++;
2060 	}
2061 	/* Count the mmt_end as well */
2062 	nf++;
2063 
2064 	for (n = 0; n < nf; n++) {
2065 		str = scanMappingFormat(f, n, nf, str, 0, 0, 0);
2066 		if (str == 0)
2067 			break;
2068 	}
2069 
2070 	return ((str != 0) ? 1 : 0);
2071 }
2072 
2073 /*
2074  * Perform a match operation. For example, given the rule
2075  *	("{%s}%s", auth_name, public_data)=nisPublicKey
2076  * and assuming that 'nisPublicKey' has the value "{dh640-0}abcdef12345",
2077  * assign "dh640-0" to 'auth_name' and "abcdef12345" to 'public_data'.
2078  *
2079  * Note that this function doesn't perform the actual assignment. Rather,
2080  * it returns an array of __nis_value_t's, with element zero of the value
2081  * array being the new value of the first matched item, element one the
2082  * value of the second matched item, etc. In the example above, we'd
2083  * return a value array with two elements.
2084  *
2085  * If there is more than one input value (inVal->numVals > 1), the
2086  * output array elements will also be multi-valued.
2087  *
2088  * f		The match format
2089  * inVal	Input value(s)
2090  * numVal	Number of elements in the output value array
2091  * sepset	List of separators
2092  * outstr	Points to the updated position upto which the
2093  *		input string has been matched
2094  */
2095 __nis_value_t **
2096 matchMappingItem(__nis_mapping_format_t *f, __nis_value_t *inVal,
2097 		int *numVals, char *sepset, char **outstr) {
2098 	__nis_value_t		**v = 0;
2099 	int			i, n, ni, numItems, nf, nv = 0;
2100 	char			*str, *valstr;
2101 	__nis_mapping_format_t	*ftmp;
2102 	char			*myself = "matchMappingItem";
2103 
2104 	if (f == 0 ||
2105 		inVal == 0 || inVal->numVals < 1 || inVal->type != vt_string)
2106 		return (0);
2107 
2108 	/* Count the number of format elements and items in the format */
2109 	for (nf = numItems = 0, ftmp = f; ftmp->type != mmt_end; ftmp++) {
2110 		nf++;
2111 
2112 		/*
2113 		 * Count mmt_item and mmt_berstring (used by N2L to
2114 		 * represent address %a)
2115 		 */
2116 		if (ftmp->type == mmt_item)
2117 				numItems++;
2118 		else if (ftmp->type == mmt_berstring && ftmp->match.berString &&
2119 				ftmp->match.berString[0] == 'a')
2120 				numItems++;
2121 	}
2122 	/* Count the mmt_end as well */
2123 	nf++;
2124 
2125 	/*
2126 	 * If no items, there will be no values. This isn't exactly an error
2127 	 * from the limited point of view of this function, so we return a
2128 	 * __nis_value_t with zero values.
2129 	 */
2130 	if (numItems <= 0) {
2131 		v = am(myself, sizeof (v[0]));
2132 		if (v == 0)
2133 			return (0);
2134 		v[0] = am(myself, sizeof (*v[0]));
2135 		if (v[0] == 0) {
2136 			sfree(v);
2137 			return (0);
2138 		}
2139 		v[0]->type = vt_string;
2140 		v[0]->numVals = 0;
2141 		v[0]->val = 0;
2142 		if (numVals != 0)
2143 			*numVals = 1;
2144 		return (v);
2145 	}
2146 
2147 	/* Allocate and initialize the return array */
2148 	v = am(myself, numItems * sizeof (v[0]));
2149 	if (v == 0)
2150 		return (0);
2151 	for (n = 0; n < numItems; n++) {
2152 		v[n] = am(myself, sizeof (*v[n]));
2153 		if (v[n] == 0) {
2154 			int	j;
2155 
2156 			for (j = 0; j < n; j++)
2157 				freeValue(v[j], 1);
2158 			sfree(v);
2159 			return (0);
2160 		}
2161 		v[n]->type = vt_string;
2162 		v[n]->numVals = 0;
2163 		v[n]->val = am(myself, inVal->numVals * sizeof (v[n]->val[0]));
2164 		if (v[n]->val == 0) {
2165 			int	j;
2166 
2167 			for (j = 0; j < n; j++)
2168 				freeValue(v[j], 1);
2169 			sfree(v);
2170 			return (0);
2171 		}
2172 		for (i = 0; i < inVal->numVals; i++) {
2173 			v[n]->val[i].length = 0;
2174 			v[n]->val[i].value = 0;
2175 		}
2176 	}
2177 
2178 	/* For each input value, perform the match operation */
2179 	for (i = 0; i < inVal->numVals; i++) {
2180 		str = inVal->val[i].value;
2181 		if (str == 0)
2182 			continue;
2183 		for (n = 0, ni = 0; n < nf; n++) {
2184 			valstr = 0;
2185 			str = scanMappingFormat(f, n, nf, str, &valstr,
2186 				0, sepset);
2187 			if (str == 0)
2188 				break;
2189 			if (valstr != 0 && ni < numItems &&
2190 					v[ni]->numVals < inVal->numVals) {
2191 				v[ni]->val[v[ni]->numVals].value = valstr;
2192 				v[ni]->val[v[ni]->numVals].length =
2193 							strlen(valstr) + 1;
2194 				v[ni]->numVals++;
2195 				ni++;
2196 			} else if (valstr != 0) {
2197 				sfree(valstr);
2198 			}
2199 		}
2200 		if (str == 0) {
2201 			for (n = 0; n < numItems; n++)
2202 				freeValue(v[n], 1);
2203 			sfree(v);
2204 			return (0);
2205 		}
2206 	}
2207 
2208 	if (numVals != 0)
2209 		*numVals = numItems;
2210 
2211 	/*
2212 	 * Update the return string upto the point it has been matched
2213 	 * This string will be used by the N2L code in its next call
2214 	 * to this function
2215 	 */
2216 	if (outstr != 0)
2217 		*outstr = str;
2218 
2219 	return (v);
2220 }
2221 
2222 /*
2223  * Perform an extract operation. For example, given the expression
2224  *	(name, "%s.*")
2225  * and assuming 'name' is an item with the value "some.thing", the
2226  * value returned by the extract is "some".
2227  */
2228 __nis_value_t *
2229 extractMappingItem(__nis_mapping_item_t *item, __nis_mapping_format_t *f,
2230 		__nis_rule_value_t *rv, int *stat) {
2231 	__nis_value_t		*val = getMappingItem(item, mit_any,
2232 			rv, 0, stat);
2233 	__nis_single_value_t	*nval;
2234 	int			i, n, nv, nf;
2235 	__nis_mapping_format_t	*ftmp;
2236 
2237 	if (val == 0)
2238 		return (0);
2239 	else if (f == 0 || rv == 0 || val->val == 0 ||
2240 			val->numVals <= 0 || val->type != vt_string) {
2241 		freeValue(val, 1);
2242 		return (0);
2243 	}
2244 
2245 	/* Sanity check the format; it must have one and only one mmt_item */
2246 	{
2247 		int	numitem;
2248 
2249 		for (nf = numitem = 0, ftmp = f; ftmp->type != mmt_end;
2250 				ftmp++) {
2251 			nf++;
2252 			if (ftmp->type == mmt_item)
2253 				numitem++;
2254 		}
2255 		/* Count the mmt_end as well */
2256 		nf++;
2257 		if (numitem != 1) {
2258 			freeValue(val, 1);
2259 			return (0);
2260 		}
2261 	}
2262 
2263 	nval = val->val;
2264 	nv = val->numVals;
2265 	val->repeat = FALSE;
2266 	val->val = 0;
2267 	val->numVals = 0;
2268 
2269 	/* If the item has multiple values, we extract each one independently */
2270 	for (i = 0; i < nv; i++) {
2271 		char			*str = nval[i].value;
2272 		char			*newstr = 0;
2273 		__nis_single_value_t	*newval;
2274 
2275 		if (nval[i].value == 0)
2276 			continue;
2277 
2278 		/*
2279 		 * We match the whole string, even if we find a value for
2280 		 * the item before exhausting all format elements. By doing
2281 		 * this, we ensure that the string really matches the complete
2282 		 * format specification.
2283 		 */
2284 		for (n = 0; n < nf; n++) {
2285 			str = scanMappingFormat(f, n, nf, str, &newstr, 0, 0);
2286 			if (str == 0)
2287 				break;
2288 		}
2289 
2290 		/*
2291 		 * *str should now be NUL, meaning we've reached the end of
2292 		 * the string (value), and it completely matched the format.
2293 		 * If 'str' is NULL, there was an error, and if 'newstr' is
2294 		 * 0, we somehow failed to obtain a value.
2295 		 */
2296 		if (str == 0 || *str != '\0' || newstr == 0 ||
2297 				(newval = realloc(val->val,
2298 					(val->numVals+1) *
2299 					sizeof (val->val[0]))) == 0) {
2300 			freeValue(val, 1);
2301 			for (n = 0; n < nv; n++) {
2302 				sfree(nval[n].value);
2303 			}
2304 			free(nval);
2305 			sfree(newstr);
2306 			return (0);
2307 		}
2308 
2309 		val->val = newval;
2310 		val->val[val->numVals].value = newstr;
2311 		val->val[val->numVals].length = strlen(newstr) + 1;
2312 		val->numVals++;
2313 
2314 		free(nval[i].value);
2315 		nval[i].value = 0;
2316 	}
2317 	free(nval);
2318 
2319 	return (val);
2320 }
2321 
2322 /*
2323  * For each value in 'val', remove the last character, provided that
2324  * it matches 'elide'.
2325  */
2326 void
2327 stringElide(__nis_value_t *val, char elide) {
2328 
2329 	if (val != 0 && val->type == vt_string) {
2330 		int	i;
2331 
2332 		for (i = 0; i < val->numVals; i++) {
2333 			int	end = val->val[i].length;
2334 			char	*str = val->val[i].value;
2335 
2336 			if (str == 0 || end <= 0)
2337 				continue;
2338 
2339 			/*
2340 			 * If the NUL was counted in the length, step back
2341 			 * over it.
2342 			 */
2343 			if (str[end-1] == '\0')
2344 				end--;
2345 			if (end > 0 && str[end-1] == elide) {
2346 				str[end-1] = '\0';
2347 				val->val[i].length--;
2348 			}
2349 		}
2350 	}
2351 }
2352 
2353 /*
2354  * Obtain the value for the mapping sub-element 'e', given the input
2355  * rule-value 'rv'.
2356  */
2357 __nis_value_t *
2358 getMappingSubElement(__nis_mapping_sub_element_t *e,
2359 	__nis_rule_value_t *rv, int *np_ldap_stat) {
2360 	__nis_value_t	*val;
2361 
2362 	if (e == 0)
2363 		return (0);
2364 
2365 	switch (e->type) {
2366 	case me_item:
2367 		val = getMappingItem(&e->element.item, mit_any, rv, 0,
2368 			np_ldap_stat);
2369 		break;
2370 	case me_print:
2371 		val = getMappingFormatArray(e->element.print.fmt, rv,
2372 						fa_item,
2373 						e->element.print.numItems,
2374 						e->element.print.item);
2375 		if (e->element.print.doElide)
2376 			stringElide(val, e->element.print.elide);
2377 		break;
2378 	case me_split:
2379 		val = splitMappingItem(&e->element.split.item,
2380 					e->element.split.delim,
2381 					rv);
2382 		break;
2383 	case me_extract:
2384 		val = extractMappingItem(&e->element.extract.item,
2385 					e->element.extract.fmt,
2386 					rv, np_ldap_stat);
2387 		break;
2388 	case me_match:
2389 	default:
2390 		val = 0;
2391 		break;
2392 	}
2393 
2394 	return (val);
2395 }
2396 
2397 /*
2398  * Obtain the value of the mapping element 'e', given the input rule-
2399  * value 'rv'. The 'native' mapping type is used when 'rv' is NULL,
2400  * and the result is a string representation of the mapping element;
2401  * in that case, items of the 'native' type are printed without their
2402  * type designation ("nis+" or "ldap").
2403  */
2404 __nis_value_t *
2405 getMappingElement(__nis_mapping_element_t *e, __nis_mapping_item_type_t native,
2406 		__nis_rule_value_t *rv, int *stat) {
2407 	__nis_value_t	*val, **tv;
2408 	int		i, success = 0, novalue = 0;
2409 	int *np_ldap_stat;
2410 	char		*myself = "getMappingElement";
2411 
2412 	switch (e->type) {
2413 	case me_item:
2414 		val = getMappingItem(&e->element.item, native, rv, 0, NULL);
2415 		break;
2416 	case me_print:
2417 		tv = am(myself, e->element.print.numSubElements *
2418 			sizeof (tv[0]));
2419 		np_ldap_stat = am(myself,
2420 			e->element.print.numSubElements * sizeof (int));
2421 		if ((e->element.print.numSubElements > 0) &&
2422 				(tv == 0 || np_ldap_stat == 0)) {
2423 			val = 0;
2424 			sfree(tv);
2425 			sfree(np_ldap_stat);
2426 			break;
2427 		}
2428 		for (i = 0; i < e->element.print.numSubElements; i++) {
2429 			np_ldap_stat[i] = 0;
2430 			tv[i] = getMappingSubElement(
2431 				&e->element.print.subElement[i],
2432 				rv, &np_ldap_stat[i]);
2433 		}
2434 		/*
2435 		 * if we get NP_LDAP_NO_VALUE to any of the subelement
2436 		 * and we get NP_LDAP_MAP_SUCCESS to all other subelement
2437 		 * then we had enough nis+ column values which can
2438 		 * produce value for this rule, but didn't. So return
2439 		 * NP_LDAP_RULES_NO_VALUE to indicate to proceed to
2440 		 * next database id.
2441 		 */
2442 		for (i = 0; i < e->element.print.numSubElements; i++) {
2443 			if (np_ldap_stat[i] == NP_LDAP_MAP_SUCCESS)
2444 				success++;
2445 			if (np_ldap_stat[i] == NP_LDAP_NO_VALUE)
2446 				novalue++;
2447 		}
2448 		if (stat != NULL && novalue > 0 &&
2449 				((novalue+success) ==
2450 					e->element.print.numSubElements))
2451 					    *stat = NP_LDAP_RULES_NO_VALUE;
2452 		val = getMappingFormatArray(e->element.print.fmt, rv,
2453 						fa_value,
2454 						e->element.print.numSubElements,
2455 						tv);
2456 		for (i = 0; i < e->element.print.numSubElements; i++) {
2457 			freeValue(tv[i], 1);
2458 		}
2459 		sfree(tv);
2460 		sfree(np_ldap_stat);
2461 		if (e->element.print.doElide)
2462 			stringElide(val, e->element.print.elide);
2463 		break;
2464 	case me_split:
2465 		val = splitMappingItem(&e->element.split.item,
2466 					e->element.split.delim,
2467 					rv);
2468 		break;
2469 	case me_match:
2470 		/*
2471 		 * A match doesn't produce an assignable value per se,
2472 		 * so we shouldn't get one here.
2473 		 */
2474 		val = 0;
2475 		break;
2476 	case me_extract:
2477 		val = extractMappingItem(&e->element.extract.item,
2478 					e->element.extract.fmt,
2479 					rv, NULL);
2480 		break;
2481 	default:
2482 		val = 0;
2483 		break;
2484 	}
2485 
2486 	return (val);
2487 }
2488