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