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