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 <strings.h>
30*0Sstevel@tonic-gate #include <string.h>
31*0Sstevel@tonic-gate #include <lber.h>
32*0Sstevel@tonic-gate #include <ldap.h>
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include "db_item_c.h"
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate #include "nisdb_mt.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include "ldap_util.h"
39*0Sstevel@tonic-gate #include "ldap_structs.h"
40*0Sstevel@tonic-gate #include "ldap_val.h"
41*0Sstevel@tonic-gate #include "ldap_ruleval.h"
42*0Sstevel@tonic-gate #include "ldap_op.h"
43*0Sstevel@tonic-gate #include "ldap_nisdbquery.h"
44*0Sstevel@tonic-gate #include "ldap_attr.h"
45*0Sstevel@tonic-gate #include "ldap_nisplus.h"
46*0Sstevel@tonic-gate #include "ldap_xdr.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate item *
50*0Sstevel@tonic-gate buildItem(int len, void *value) {
51*0Sstevel@tonic-gate 	char	*myself = "buildItem";
52*0Sstevel@tonic-gate 	item	*i = am(myself, sizeof (*i));
53*0Sstevel@tonic-gate 	int	mlen = len;
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	if (i == 0)
56*0Sstevel@tonic-gate 		return (0);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate 	/*
59*0Sstevel@tonic-gate 	 * To this function, a NULL value, or a length less than or equal
60*0Sstevel@tonic-gate 	 * zero means an item with no value. Hence, buildItem(0, 0) is
61*0Sstevel@tonic-gate 	 * _not_ the right way to create index_value == 0 to indicate
62*0Sstevel@tonic-gate 	 * deletion.
63*0Sstevel@tonic-gate 	 */
64*0Sstevel@tonic-gate 	if (value == 0 || len <= 0) {
65*0Sstevel@tonic-gate 		i->itemvalue.itemvalue_len = 0;
66*0Sstevel@tonic-gate 		i->itemvalue.itemvalue_val = 0;
67*0Sstevel@tonic-gate 		return (i);
68*0Sstevel@tonic-gate 	}
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	/*
71*0Sstevel@tonic-gate 	 * NIS+ usually stores the terminating NUL for strings, so we add
72*0Sstevel@tonic-gate 	 * it here just in case. This means we usually waste a byte for
73*0Sstevel@tonic-gate 	 * binary column values...
74*0Sstevel@tonic-gate 	 */
75*0Sstevel@tonic-gate 	if (len > 0 && ((char *)value)[len-1] != '\0')
76*0Sstevel@tonic-gate 		mlen++;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	i->itemvalue.itemvalue_len = len;
79*0Sstevel@tonic-gate 	i->itemvalue.itemvalue_val = am(myself, mlen);
80*0Sstevel@tonic-gate 	if (mlen > 0 && i->itemvalue.itemvalue_val == 0) {
81*0Sstevel@tonic-gate 		free(i);
82*0Sstevel@tonic-gate 		return (0);
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate 	memcpy(i->itemvalue.itemvalue_val, value, len);
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	return (i);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate void
90*0Sstevel@tonic-gate freeItem(item *i) {
91*0Sstevel@tonic-gate 	if (i != 0) {
92*0Sstevel@tonic-gate 		sfree(i->itemvalue.itemvalue_val);
93*0Sstevel@tonic-gate 		free(i);
94*0Sstevel@tonic-gate 	}
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate void
98*0Sstevel@tonic-gate freeQcomp(db_qcomp *qc, int doFree) {
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	if (qc == 0)
101*0Sstevel@tonic-gate 		return;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	freeItem(qc->index_value);
104*0Sstevel@tonic-gate 	if (doFree)
105*0Sstevel@tonic-gate 		free(qc);
106*0Sstevel@tonic-gate }
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate db_query *
109*0Sstevel@tonic-gate buildQuery(int num_components, db_qcomp *components) {
110*0Sstevel@tonic-gate 	char		*myself = "buildQuery";
111*0Sstevel@tonic-gate 	db_query	*q = am(myself, sizeof (*q));
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	if (q == 0)
114*0Sstevel@tonic-gate 		return (0);
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	q->components.components_len = num_components;
117*0Sstevel@tonic-gate 	q->components.components_val = components;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 	return (q);
120*0Sstevel@tonic-gate }
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate /*
123*0Sstevel@tonic-gate  * Clone a db_query. The 'numComps' parameter can be used to specify
124*0Sstevel@tonic-gate  * the number of db_qcomp's to allocate (in the 'components.components_val'
125*0Sstevel@tonic-gate  * array), if 'components.components_len' hasn't yet reached its expected
126*0Sstevel@tonic-gate  * maximum value.
127*0Sstevel@tonic-gate  */
128*0Sstevel@tonic-gate db_query *
129*0Sstevel@tonic-gate cloneQuery(db_query *old, int numComps) {
130*0Sstevel@tonic-gate 	db_query	*new;
131*0Sstevel@tonic-gate 	int		i;
132*0Sstevel@tonic-gate 	char		*myself = "cloneQuery";
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	if (old == 0)
135*0Sstevel@tonic-gate 		return (0);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	new = am(myself, sizeof (*new));
138*0Sstevel@tonic-gate 	if (new == 0)
139*0Sstevel@tonic-gate 		return (0);
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	if (old->components.components_len > numComps)
142*0Sstevel@tonic-gate 		numComps = old->components.components_len;
143*0Sstevel@tonic-gate 
144*0Sstevel@tonic-gate 	new->components.components_val = am(myself,
145*0Sstevel@tonic-gate 				sizeof (new->components.components_val[0]) *
146*0Sstevel@tonic-gate 				numComps);
147*0Sstevel@tonic-gate 	if (numComps > 0 && new->components.components_val == 0) {
148*0Sstevel@tonic-gate 		free(new);
149*0Sstevel@tonic-gate 		return (0);
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	for (i = 0; i < old->components.components_len; i++) {
153*0Sstevel@tonic-gate 		item	*it;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 		if (old->components.components_val[i].index_value == 0) {
156*0Sstevel@tonic-gate 			new->components.components_val[i].index_value = 0;
157*0Sstevel@tonic-gate 			new->components.components_val[i].which_index =
158*0Sstevel@tonic-gate 				old->components.components_val[i].which_index;
159*0Sstevel@tonic-gate 			continue;
160*0Sstevel@tonic-gate 		}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 		it = buildItem(old->components.components_val[i].index_value->
163*0Sstevel@tonic-gate 					itemvalue.itemvalue_len,
164*0Sstevel@tonic-gate 				old->components.components_val[i].index_value->
165*0Sstevel@tonic-gate 					itemvalue.itemvalue_val);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 		if (it == 0) {
168*0Sstevel@tonic-gate 			new->components.components_len = i + 1;
169*0Sstevel@tonic-gate 			freeQuery(new);
170*0Sstevel@tonic-gate 			return (0);
171*0Sstevel@tonic-gate 		}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 		new->components.components_val[i].index_value = it;
174*0Sstevel@tonic-gate 		new->components.components_val[i].which_index =
175*0Sstevel@tonic-gate 			old->components.components_val[i].which_index;
176*0Sstevel@tonic-gate 	}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	new->components.components_len = old->components.components_len;
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	return (new);
181*0Sstevel@tonic-gate }
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate void
184*0Sstevel@tonic-gate freeQuery(db_query *q) {
185*0Sstevel@tonic-gate 	int	i;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	if (q == 0)
188*0Sstevel@tonic-gate 		return;
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	for (i = 0; i < q->components.components_len; i++) {
191*0Sstevel@tonic-gate 		freeItem(q->components.components_val[i].index_value);
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	sfree(q->components.components_val);
195*0Sstevel@tonic-gate 	sfree(q);
196*0Sstevel@tonic-gate }
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate void
199*0Sstevel@tonic-gate freeQueries(db_query **q, int numQ) {
200*0Sstevel@tonic-gate 	int	i;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	if (q == 0)
203*0Sstevel@tonic-gate 		return;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	for (i = 0; i < numQ; i++)
206*0Sstevel@tonic-gate 		freeQuery(q[i]);
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	sfree(q);
209*0Sstevel@tonic-gate }
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate /*
212*0Sstevel@tonic-gate  * Given an array index[0..num-1] of pointers to strings of the form
213*0Sstevel@tonic-gate  * "name=value", create the corresponding db_queries. "name=" indicates
214*0Sstevel@tonic-gate  * deletion, which results in a db_query component where index_value == 0.
215*0Sstevel@tonic-gate  *
216*0Sstevel@tonic-gate  * The __nis_table_mapping_t structure is used to translate column
217*0Sstevel@tonic-gate  * names to indices.
218*0Sstevel@tonic-gate  *
219*0Sstevel@tonic-gate  * If 'rvP' is non-NULL, the searchable columns from the 'index'
220*0Sstevel@tonic-gate  * name/value pairs are used to retrieve copies of the corresponding NIS+
221*0Sstevel@tonic-gate  * entries, and '*rvP' is initialized with the current entry values
222*0Sstevel@tonic-gate  * and object attributes. Names/values supplied in 'index' override
223*0Sstevel@tonic-gate  * those from existing NIS+ entries.
224*0Sstevel@tonic-gate  */
225*0Sstevel@tonic-gate db_query **
226*0Sstevel@tonic-gate createQuery(int num, char **index, __nis_table_mapping_t *t,
227*0Sstevel@tonic-gate 		__nis_rule_value_t **rvP, int *numVals) {
228*0Sstevel@tonic-gate 	db_query		**q;
229*0Sstevel@tonic-gate 	db_qcomp		*qc;
230*0Sstevel@tonic-gate 	int			i, j, n, a, nv, niv, stat, sinum;
231*0Sstevel@tonic-gate 	__nis_rule_value_t	*rvq;
232*0Sstevel@tonic-gate 	__nis_buffer_t		b = {0, 0};
233*0Sstevel@tonic-gate 	nis_result		*res = 0;
234*0Sstevel@tonic-gate 	char			*table = 0;
235*0Sstevel@tonic-gate 	char			*myself = "createQuery";
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	rvq = initRuleValue(1, 0);
238*0Sstevel@tonic-gate 	if (rvq == 0)
239*0Sstevel@tonic-gate 		return (0);
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	if (numVals == 0)
242*0Sstevel@tonic-gate 		numVals = &nv;
243*0Sstevel@tonic-gate 	*numVals = 0;
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	if (rvP != 0) {
246*0Sstevel@tonic-gate 		/*
247*0Sstevel@tonic-gate 		 * Try to obtain a copy of the table object, in order to
248*0Sstevel@tonic-gate 		 * determine the searchable columns. A failure isn't
249*0Sstevel@tonic-gate 		 * necessarily fatal; we just try to compose the entire
250*0Sstevel@tonic-gate 		 * LDAP data from the col=val pairs.
251*0Sstevel@tonic-gate 		 */
252*0Sstevel@tonic-gate 		table = fullObjName(F, t->objName);
253*0Sstevel@tonic-gate 		if (table == 0) {
254*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
255*0Sstevel@tonic-gate 				"%s: Error converting \"%s\" to FQ object name",
256*0Sstevel@tonic-gate 				myself, NIL(t->objName));
257*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
258*0Sstevel@tonic-gate 			return (0);
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 		stat = getNisPlusObj(table, myself, &res);
262*0Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS) {
263*0Sstevel@tonic-gate 			if (res->objects.objects_val->zo_data.zo_type !=
264*0Sstevel@tonic-gate 					NIS_TABLE_OBJ) {
265*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_WARNING,
266*0Sstevel@tonic-gate 					"%s: \"%s\" isn't a table object",
267*0Sstevel@tonic-gate 					myself, NIL(table));
268*0Sstevel@tonic-gate 				nis_freeresult(res);
269*0Sstevel@tonic-gate 				res = 0;
270*0Sstevel@tonic-gate 			}
271*0Sstevel@tonic-gate 		} else {
272*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
273*0Sstevel@tonic-gate 				"%s: Unable to retrieve \"%s\" object: %s",
274*0Sstevel@tonic-gate 				myself, NIL(table), ldap_err2string(stat));
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	/* Create a rule-value from the col=val pairs */
279*0Sstevel@tonic-gate 	for (n = 0; n < num; n++) {
280*0Sstevel@tonic-gate 		char	*name;
281*0Sstevel@tonic-gate 		char	*value;
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		if ((value = strchr(index[n], '=')) == 0) {
284*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
285*0Sstevel@tonic-gate 				"%s: no '=' in \"%s\"",
286*0Sstevel@tonic-gate 				myself, index[n]);
287*0Sstevel@tonic-gate 			continue;
288*0Sstevel@tonic-gate 		}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 		*value = '\0';
291*0Sstevel@tonic-gate 		value++;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 		for (a = 0; a < t->numColumns; a++) {
294*0Sstevel@tonic-gate 			if (strcmp(index[n], t->column[a]) == 0) {
295*0Sstevel@tonic-gate 				int		i, len = slen(value)+1;
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate 				/* Add col=val pair to 'rvq' */
298*0Sstevel@tonic-gate 				if (addSCol2RuleValue(index[n], value, rvq)) {
299*0Sstevel@tonic-gate 					freeRuleValue(rvq, 1);
300*0Sstevel@tonic-gate 					sfree(table);
301*0Sstevel@tonic-gate 					if (res != 0)
302*0Sstevel@tonic-gate 						nis_freeresult(res);
303*0Sstevel@tonic-gate 					return (0);
304*0Sstevel@tonic-gate 				}
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 				break;
307*0Sstevel@tonic-gate 			}
308*0Sstevel@tonic-gate 		}
309*0Sstevel@tonic-gate 		if (a >= t->numColumns) {
310*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
311*0Sstevel@tonic-gate 				"%s: Ignoring unknown column \"%s\"",
312*0Sstevel@tonic-gate 				myself, NIL(index[n]));
313*0Sstevel@tonic-gate 		}
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/*
317*0Sstevel@tonic-gate 	 * Find out if any of the columns specified via the 'index'
318*0Sstevel@tonic-gate 	 * array are multi-valued.
319*0Sstevel@tonic-gate 	 */
320*0Sstevel@tonic-gate 	for (n = 0, niv = 1; n < rvq->numColumns; n++) {
321*0Sstevel@tonic-gate 		if (rvq->colVal[n].numVals > 1)
322*0Sstevel@tonic-gate 			niv *= rvq->colVal[n].numVals;
323*0Sstevel@tonic-gate 	}
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate 	/*
326*0Sstevel@tonic-gate 	 * Generate a NIS+ query, provided that the following conditions
327*0Sstevel@tonic-gate 	 * are satisfied:
328*0Sstevel@tonic-gate 	 *
329*0Sstevel@tonic-gate 	 *	We were able to get information about the table, and
330*0Sstevel@tonic-gate 	 *
331*0Sstevel@tonic-gate 	 *	The col=val pairs include at least one searchable
332*0Sstevel@tonic-gate 	 *	column, and
333*0Sstevel@tonic-gate 	 *
334*0Sstevel@tonic-gate 	 *	At most one value was supplied for each searchable
335*0Sstevel@tonic-gate 	 *	column.
336*0Sstevel@tonic-gate 	 */
337*0Sstevel@tonic-gate 	if (res != 0 && rvq->numColumns > 0) {
338*0Sstevel@tonic-gate 		bp2buf(myself, &b, "[");
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 		for (n = 0, sinum = 0; n < rvq->numColumns; n++) {
341*0Sstevel@tonic-gate 			table_obj	*to = &(NIS_RES_OBJECT(res)->TA_data);
342*0Sstevel@tonic-gate 			table_col	*tc;
343*0Sstevel@tonic-gate 			int		si = -1;
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 			for (i = 0; i < to->ta_cols.ta_cols_len; i++) {
346*0Sstevel@tonic-gate 				tc = &to->ta_cols.ta_cols_val[i];
347*0Sstevel@tonic-gate 				if (strcmp(rvq->colName[n], tc->tc_name) == 0 &&
348*0Sstevel@tonic-gate 					(tc->tc_flags & TA_SEARCHABLE) != 0) {
349*0Sstevel@tonic-gate 					si = i;
350*0Sstevel@tonic-gate 					break;
351*0Sstevel@tonic-gate 				}
352*0Sstevel@tonic-gate 			}
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 			if (si >= 0) {
355*0Sstevel@tonic-gate 				if (rvq->colVal[n].numVals < 0)
356*0Sstevel@tonic-gate 					continue;
357*0Sstevel@tonic-gate 				if (rvq->colVal[n].numVals > 1) {
358*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
359*0Sstevel@tonic-gate 		"%s: Multi-valued column \"%s\" excluded from NIS+ search",
360*0Sstevel@tonic-gate 						myself, rvq->colName[n]);
361*0Sstevel@tonic-gate 					continue;
362*0Sstevel@tonic-gate 				}
363*0Sstevel@tonic-gate 				if (sinum == 0)
364*0Sstevel@tonic-gate 					bp2buf(myself, &b, "%s=%s",
365*0Sstevel@tonic-gate 						rvq->colName[n],
366*0Sstevel@tonic-gate 						rvq->colVal[n].val[0].value);
367*0Sstevel@tonic-gate 				else
368*0Sstevel@tonic-gate 					bp2buf(myself, &b, ",%s=%s",
369*0Sstevel@tonic-gate 						rvq->colName[n],
370*0Sstevel@tonic-gate 						rvq->colVal[n].val[0].value);
371*0Sstevel@tonic-gate 				sinum++;
372*0Sstevel@tonic-gate 			} else {
373*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
374*0Sstevel@tonic-gate 			"%s: \"%s\" not searchable; not included in NIS+ query",
375*0Sstevel@tonic-gate 					myself, index[n]);
376*0Sstevel@tonic-gate 			}
377*0Sstevel@tonic-gate 		}
378*0Sstevel@tonic-gate 		bp2buf(myself, &b, "]");
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		if (strcmp(b.buf, "[]") == 0) {
381*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
382*0Sstevel@tonic-gate 		"%s: No searchable column specified; skipping NIS+ query",
383*0Sstevel@tonic-gate 				myself);
384*0Sstevel@tonic-gate 			nis_freeresult(res);
385*0Sstevel@tonic-gate 			res = 0;
386*0Sstevel@tonic-gate 		}
387*0Sstevel@tonic-gate 	} else if (res != 0) {
388*0Sstevel@tonic-gate 		nis_freeresult(res);
389*0Sstevel@tonic-gate 		res = 0;
390*0Sstevel@tonic-gate 	}
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	/* Query NIS+ */
393*0Sstevel@tonic-gate 	if (res != 0) {
394*0Sstevel@tonic-gate 		__nis_rule_value_t	*rv;
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 		bp2buf(myself, &b, "%s", table);
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
399*0Sstevel@tonic-gate 			"%s: NIS+ query: %s", myself, NIL(b.buf));
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 		rv = getNisPlusEntrySimple(b.buf, numVals);
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 		/*
404*0Sstevel@tonic-gate 		 * Add values from the NIS+ entry to the ones passed in by
405*0Sstevel@tonic-gate 		 * our caller (in the form of col=value pairs).
406*0Sstevel@tonic-gate 		 */
407*0Sstevel@tonic-gate 		if (rv != 0 && *numVals > 1 && niv > 1) {
408*0Sstevel@tonic-gate 			/*
409*0Sstevel@tonic-gate 			 * Since we have both multi-valued columns in the
410*0Sstevel@tonic-gate 			 * 'index' array, _and_ multiple NIS+ matches, we
411*0Sstevel@tonic-gate 			 * don't know how to combine the two in a meaningful
412*0Sstevel@tonic-gate 			 * fashion. Ignore the NIS+ values, and use the
413*0Sstevel@tonic-gate 			 * 'index' array only.
414*0Sstevel@tonic-gate 			 */
415*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
416*0Sstevel@tonic-gate 	"%s: At least one multi-valued input column, and multiple NIS+ matches",
417*0Sstevel@tonic-gate 				myself);
418*0Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
419*0Sstevel@tonic-gate 				"%s: Ignoring NIS+ lookup results", myself);
420*0Sstevel@tonic-gate 			freeRuleValue(rv, *numVals);
421*0Sstevel@tonic-gate 			rv = 0;
422*0Sstevel@tonic-gate 			*numVals = 1;
423*0Sstevel@tonic-gate 		} else if (rv != 0 && *numVals > 0) {
424*0Sstevel@tonic-gate 			/*
425*0Sstevel@tonic-gate 			 * Since passed-in values override those from the
426*0Sstevel@tonic-gate 			 * NIS+ entries, we first need to delete the passed-in
427*0Sstevel@tonic-gate 			 * columns from the NIS+ data, and then add the
428*0Sstevel@tonic-gate 			 * passed-in columns/values.
429*0Sstevel@tonic-gate 			 */
430*0Sstevel@tonic-gate 			for (i = 0; i < rvq->numColumns; i++) {
431*0Sstevel@tonic-gate 				for (n = 0; n < *numVals; n++) {
432*0Sstevel@tonic-gate 					delColFromRuleValue(&rv[n],
433*0Sstevel@tonic-gate 						rvq->colName[i]);
434*0Sstevel@tonic-gate 					for (j = 0; j < rvq->colVal[i].numVals;
435*0Sstevel@tonic-gate 							j++) {
436*0Sstevel@tonic-gate 						if (addCol2RuleValue(
437*0Sstevel@tonic-gate 							rvq->colVal[i].type,
438*0Sstevel@tonic-gate 							rvq->colName[i],
439*0Sstevel@tonic-gate 							rvq->colVal[i].val[j].
440*0Sstevel@tonic-gate 								value,
441*0Sstevel@tonic-gate 							rvq->colVal[i].val[j].
442*0Sstevel@tonic-gate 								length,
443*0Sstevel@tonic-gate 							&rv[n])) {
444*0Sstevel@tonic-gate 							freeRuleValue(rv,
445*0Sstevel@tonic-gate 								*numVals);
446*0Sstevel@tonic-gate 							freeRuleValue(rvq, 1);
447*0Sstevel@tonic-gate 							sfree(b.buf);
448*0Sstevel@tonic-gate 							sfree(table);
449*0Sstevel@tonic-gate 							nis_freeresult(res);
450*0Sstevel@tonic-gate 							return (0);
451*0Sstevel@tonic-gate 						}
452*0Sstevel@tonic-gate 					}
453*0Sstevel@tonic-gate 				}
454*0Sstevel@tonic-gate 			}
455*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
456*0Sstevel@tonic-gate 			rvq = rv;
457*0Sstevel@tonic-gate 		} else {
458*0Sstevel@tonic-gate 			if (rv != 0) {
459*0Sstevel@tonic-gate 				/*
460*0Sstevel@tonic-gate 				 * Since we got here, '*numVals' <= 0,
461*0Sstevel@tonic-gate 				 * so it's unclear if it's safe to call
462*0Sstevel@tonic-gate 				 * freeRuleValue().
463*0Sstevel@tonic-gate 				 */
464*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_WARNING,
465*0Sstevel@tonic-gate 		"%s: getNisPlusEntrySimple() => non-NULL, but %d elements",
466*0Sstevel@tonic-gate 					myself, *numVals);
467*0Sstevel@tonic-gate 			} else
468*0Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
469*0Sstevel@tonic-gate 					"%s: No NIS+ data for \"%s\"",
470*0Sstevel@tonic-gate 					myself, b.buf);
471*0Sstevel@tonic-gate 			*numVals = 1;
472*0Sstevel@tonic-gate 		}
473*0Sstevel@tonic-gate 		nis_freeresult(res);
474*0Sstevel@tonic-gate 		res = 0;
475*0Sstevel@tonic-gate 	} else {
476*0Sstevel@tonic-gate 		*numVals = 1;
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	sfree(b.buf);
480*0Sstevel@tonic-gate 	sfree(table);
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 	if (rvq->numColumns <= 0) {
483*0Sstevel@tonic-gate 		freeRuleValue(rvq, *numVals);
484*0Sstevel@tonic-gate 		*numVals = 0;
485*0Sstevel@tonic-gate 		return (0);
486*0Sstevel@tonic-gate 	}
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	/*
489*0Sstevel@tonic-gate 	 * If any column name was repeated in the col=val pairs (but with
490*0Sstevel@tonic-gate 	 * different values), 'rvq' will have one or more multi-valued
491*0Sstevel@tonic-gate 	 * column values. We now convert those into an array of rule-values
492*0Sstevel@tonic-gate 	 * where every column is single-valued.
493*0Sstevel@tonic-gate 	 *
494*0Sstevel@tonic-gate 	 * Since we want all combinations of column values, the number
495*0Sstevel@tonic-gate 	 * of array elements is the product of all column value counts.
496*0Sstevel@tonic-gate 	 *
497*0Sstevel@tonic-gate 	 * There are four possible combinations of 'index' and NIS+ data:
498*0Sstevel@tonic-gate 	 *
499*0Sstevel@tonic-gate 	 * (1)	Only single-valued 'index' columns, and at most one NIS+
500*0Sstevel@tonic-gate 	 *	entry, so 'rvq' is complete, and '*numVals' == 1.
501*0Sstevel@tonic-gate 	 *
502*0Sstevel@tonic-gate 	 * (2)	Single-valued 'index' columns, but multiple NIS+ entries.
503*0Sstevel@tonic-gate 	 *	'*numVals' reflects the number of NIS+ entries, and no
504*0Sstevel@tonic-gate 	 *	expansion of 'index' column values to array elements is
505*0Sstevel@tonic-gate 	 *	needed.
506*0Sstevel@tonic-gate 	 *
507*0Sstevel@tonic-gate 	 * (3)	At least one multi-valued 'index', and multiple NIS+
508*0Sstevel@tonic-gate 	 *	entries. We already rejected the NIS+ data for this case
509*0Sstevel@tonic-gate 	 *	above, so it is in fact equivalent to case (4).
510*0Sstevel@tonic-gate 	 *
511*0Sstevel@tonic-gate 	 * (4)	At least one multi-valued 'index', but at most one NIS+
512*0Sstevel@tonic-gate 	 *	entry. This is the case where we must expand the multi-valued
513*0Sstevel@tonic-gate 	 *	columns to multiple array elements.
514*0Sstevel@tonic-gate 	 */
515*0Sstevel@tonic-gate 	if (niv > 1 && *numVals == 1) {
516*0Sstevel@tonic-gate 		__nis_rule_value_t	*rv;
517*0Sstevel@tonic-gate 		int			repeat;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 		/*
520*0Sstevel@tonic-gate 		 * By using initRuleValue() to create 'rv', and make each
521*0Sstevel@tonic-gate 		 * element a clone of 'rvq', we save a lot of code. The
522*0Sstevel@tonic-gate 		 * down side is that 'rv' only really needs one element
523*0Sstevel@tonic-gate 		 * for each rv[].colVal[].val array, but we know that at
524*0Sstevel@tonic-gate 		 * least one rvq->colVal[].val array has more than one
525*0Sstevel@tonic-gate 		 * element. Hence, making 'rv' a clone of 'rvq' will waste
526*0Sstevel@tonic-gate 		 * memory.
527*0Sstevel@tonic-gate 		 *
528*0Sstevel@tonic-gate 		 * However, we believe this waste is acceptable, because
529*0Sstevel@tonic-gate 		 * we expect that 'niv' will be small. Also, we are executing
530*0Sstevel@tonic-gate 		 * in the context of a utility command, not in a daemon.
531*0Sstevel@tonic-gate 		 */
532*0Sstevel@tonic-gate 		rv = initRuleValue(niv, rvq);
533*0Sstevel@tonic-gate 		if (rv == 0) {
534*0Sstevel@tonic-gate 			freeRuleValue(rvq, 1);
535*0Sstevel@tonic-gate 			*numVals = 0;
536*0Sstevel@tonic-gate 			return (0);
537*0Sstevel@tonic-gate 		}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 		/*
540*0Sstevel@tonic-gate 		 * For each column value in 'rvq', copy to the appropriate
541*0Sstevel@tonic-gate 		 * place in 'rv', so that the end result is that all
542*0Sstevel@tonic-gate 		 * combinations of values are enumerated, and each
543*0Sstevel@tonic-gate 		 * 'rv[n].colVal[i]' is single-valued.
544*0Sstevel@tonic-gate 		 *
545*0Sstevel@tonic-gate 		 * We do this by traversing the rv[] array 'rvq->numColumns'
546*0Sstevel@tonic-gate 		 * times, where each traversal 'i' works on the values
547*0Sstevel@tonic-gate 		 * for rvq->colVal[i]. A repeat factor 'repeat' starts out
548*0Sstevel@tonic-gate 		 * at '1', and is multiplied by 'rvq->colVal[i].numVals'
549*0Sstevel@tonic-gate 		 * at the end of each traversal. Every value
550*0Sstevel@tonic-gate 		 * rvq->colVal[i].val[j] is repeated 'repeat' times.
551*0Sstevel@tonic-gate 		 *
552*0Sstevel@tonic-gate 		 * This algorithm works by regarding the rv[] array as
553*0Sstevel@tonic-gate 		 * an I-dimensional array (I = rvq->numColumns), where
554*0Sstevel@tonic-gate 		 * each dimension 'i' corresponds to the values for
555*0Sstevel@tonic-gate 		 * rvq->colVal[i]. The I-dimensional array is stored
556*0Sstevel@tonic-gate 		 * in column-major order.
557*0Sstevel@tonic-gate 		 *
558*0Sstevel@tonic-gate 		 * Since the 'rv' elements start out as copies of 'rvq',
559*0Sstevel@tonic-gate 		 * we achieve the "copy" of the 'rvq' column values by
560*0Sstevel@tonic-gate 		 * deleting those we don't want from the 'rv' elements.
561*0Sstevel@tonic-gate 		 */
562*0Sstevel@tonic-gate 		for (i = 0, repeat = 1; i < rvq->numColumns; i++) {
563*0Sstevel@tonic-gate 			int	r, k;
564*0Sstevel@tonic-gate 			for (n = 0, j = 0, r = 0; n < niv; n++) {
565*0Sstevel@tonic-gate 				/*
566*0Sstevel@tonic-gate 				 * Free all but element 'j' of the
567*0Sstevel@tonic-gate 				 * rv[n].colVal[i].val array.
568*0Sstevel@tonic-gate 				 */
569*0Sstevel@tonic-gate 				for (k = 0; k < rv[n].colVal[i].numVals; k++) {
570*0Sstevel@tonic-gate 					/* Leave element 'j' in place */
571*0Sstevel@tonic-gate 					if (k == j)
572*0Sstevel@tonic-gate 						continue;
573*0Sstevel@tonic-gate 					sfree(rv[n].colVal[i].val[k].
574*0Sstevel@tonic-gate 						value);
575*0Sstevel@tonic-gate 				}
576*0Sstevel@tonic-gate 				rv[n].colVal[i].numVals = 1;
577*0Sstevel@tonic-gate 				/* Move element 'j' to zero */
578*0Sstevel@tonic-gate 				if (j != 0)
579*0Sstevel@tonic-gate 					rv[n].colVal[i].val[0] =
580*0Sstevel@tonic-gate 						rv[n].colVal[i].val[j];
581*0Sstevel@tonic-gate 
582*0Sstevel@tonic-gate 				/*
583*0Sstevel@tonic-gate 				 * Increment the repeat index 'r'. If >=
584*0Sstevel@tonic-gate 				 * 'repeat', reset 'r' and increment the
585*0Sstevel@tonic-gate 				 * value index 'j'. If 'j' >=
586*0Sstevel@tonic-gate 				 * rvq->colVal[i].numVals, start over on
587*0Sstevel@tonic-gate 				 * the column values for column 'i' (i.e.,
588*0Sstevel@tonic-gate 				 * reset 'j' to zero).
589*0Sstevel@tonic-gate 				 */
590*0Sstevel@tonic-gate 				r += 1;
591*0Sstevel@tonic-gate 				if (r >= repeat) {
592*0Sstevel@tonic-gate 					r = 0;
593*0Sstevel@tonic-gate 					j += 1;
594*0Sstevel@tonic-gate 					if (j >= rvq->colVal[i].numVals)
595*0Sstevel@tonic-gate 						j = 0;
596*0Sstevel@tonic-gate 				}
597*0Sstevel@tonic-gate 			}
598*0Sstevel@tonic-gate 			repeat *= rvq->colVal[i].numVals;
599*0Sstevel@tonic-gate 		}
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 		*numVals = niv;
602*0Sstevel@tonic-gate 		freeRuleValue(rvq, 1);
603*0Sstevel@tonic-gate 		rvq = rv;
604*0Sstevel@tonic-gate 		rv = 0;
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	q = am(myself, *numVals * sizeof (q[0]));
608*0Sstevel@tonic-gate 	if (q == 0) {
609*0Sstevel@tonic-gate 		freeRuleValue(rvq, *numVals);
610*0Sstevel@tonic-gate 		return (0);
611*0Sstevel@tonic-gate 	}
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 	/*
614*0Sstevel@tonic-gate 	 * Create queries from the rvq[] array.
615*0Sstevel@tonic-gate 	 */
616*0Sstevel@tonic-gate 	for (a = 0; a < *numVals; a++) {
617*0Sstevel@tonic-gate 		int	nn, err = 0;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 		qc = am(myself, rvq[a].numColumns * sizeof (*qc));
620*0Sstevel@tonic-gate 		if (qc != 0) {
621*0Sstevel@tonic-gate 			for (nn = 0, i = 0; i < rvq[a].numColumns; i++) {
622*0Sstevel@tonic-gate 				for (j = 0; j < t->numColumns; j++) {
623*0Sstevel@tonic-gate 					if (strcmp(rvq[a].colName[i],
624*0Sstevel@tonic-gate 							t->column[j]) == 0) {
625*0Sstevel@tonic-gate 						break;
626*0Sstevel@tonic-gate 					}
627*0Sstevel@tonic-gate 				}
628*0Sstevel@tonic-gate 				if (j >= t->numColumns)
629*0Sstevel@tonic-gate 					continue;
630*0Sstevel@tonic-gate 				qc[nn].which_index = j;
631*0Sstevel@tonic-gate 				if (rvq[a].colVal[i].numVals > 0) {
632*0Sstevel@tonic-gate 					qc[nn].index_value = buildItem(
633*0Sstevel@tonic-gate 						rvq[a].colVal[i].val[0].length,
634*0Sstevel@tonic-gate 						rvq[a].colVal[i].val[0].value);
635*0Sstevel@tonic-gate 					if (qc[nn].index_value == 0)
636*0Sstevel@tonic-gate 						err++;
637*0Sstevel@tonic-gate 				} else {
638*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
639*0Sstevel@tonic-gate 						"%s: No values for [%d]%s",
640*0Sstevel@tonic-gate 						myself, a, rvq[a].colName[i]);
641*0Sstevel@tonic-gate 					err++;
642*0Sstevel@tonic-gate 				}
643*0Sstevel@tonic-gate 				nn++;
644*0Sstevel@tonic-gate 			}
645*0Sstevel@tonic-gate 			if (err == 0)
646*0Sstevel@tonic-gate 				q[a] = buildQuery(nn, qc);
647*0Sstevel@tonic-gate 		}
648*0Sstevel@tonic-gate 		if (err > 0 || q[a] == 0) {
649*0Sstevel@tonic-gate 			freeQueries(q, a);
650*0Sstevel@tonic-gate 			for (a = 0; a < nn; a++)
651*0Sstevel@tonic-gate 				freeQcomp(&qc[a], F);
652*0Sstevel@tonic-gate 			sfree(qc);
653*0Sstevel@tonic-gate 			freeRuleValue(rvq, *numVals);
654*0Sstevel@tonic-gate 			return (0);
655*0Sstevel@tonic-gate 		}
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	if (rvP != 0) {
659*0Sstevel@tonic-gate 		*rvP = rvq;
660*0Sstevel@tonic-gate 	} else {
661*0Sstevel@tonic-gate 		freeRuleValue(rvq, 1);
662*0Sstevel@tonic-gate 		*numVals = 0;
663*0Sstevel@tonic-gate 	}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	return (q);
666*0Sstevel@tonic-gate }
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate void
669*0Sstevel@tonic-gate printQuery(db_query *q, __nis_table_mapping_t *t) {
670*0Sstevel@tonic-gate 	int	i, mc = -1;
671*0Sstevel@tonic-gate 	char	*myself = "printQuery";
672*0Sstevel@tonic-gate 	char	*val[NIS_MAXCOLUMNS];
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	if (q == 0)
675*0Sstevel@tonic-gate 		return;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	(void) memset(val, 0, sizeof (val));
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 	/*
680*0Sstevel@tonic-gate 	 * Collect the values, which may be out of order in 'q'.
681*0Sstevel@tonic-gate 	 * Remember the largest index.
682*0Sstevel@tonic-gate 	 */
683*0Sstevel@tonic-gate 	for (i = 0; i < q->components.components_len; i++) {
684*0Sstevel@tonic-gate 		int	ix = q->components.components_val[i].which_index;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		if (ix >= NIS_MAXCOLUMNS ||
687*0Sstevel@tonic-gate 				(t != 0 && ix >= t->numColumns))
688*0Sstevel@tonic-gate 			continue;
689*0Sstevel@tonic-gate 		if (ix > mc)
690*0Sstevel@tonic-gate 			mc = ix;
691*0Sstevel@tonic-gate 		val[ix] = q->components.components_val[i].index_value->
692*0Sstevel@tonic-gate 				itemvalue.itemvalue_val;
693*0Sstevel@tonic-gate 	}
694*0Sstevel@tonic-gate 
695*0Sstevel@tonic-gate 	/* Print the values we collected */
696*0Sstevel@tonic-gate 	for (i = 0; i <= mc; i++) {
697*0Sstevel@tonic-gate 		p2buf(myself, "%s%s", (i != 0 ? " " : ""),
698*0Sstevel@tonic-gate 			(val[i] != 0 ? val[i] : ""));
699*0Sstevel@tonic-gate 	}
700*0Sstevel@tonic-gate 	/* If we printed anything, add a newline */
701*0Sstevel@tonic-gate 	if (mc >= 0)
702*0Sstevel@tonic-gate 		p2buf(myself, "\n");
703*0Sstevel@tonic-gate }
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate /*
706*0Sstevel@tonic-gate  * Verify that the db_query's 'q' and 'fq' match, in the sense that if
707*0Sstevel@tonic-gate  * they both have a value for a certain index, the values are the same.
708*0Sstevel@tonic-gate  */
709*0Sstevel@tonic-gate int
710*0Sstevel@tonic-gate verifyQueryMatch(db_query *q, db_query *fq) {
711*0Sstevel@tonic-gate 	int	i, j, match;
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate 	if (fq == 0)
714*0Sstevel@tonic-gate 		return (1);
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 	if (q == 0)
717*0Sstevel@tonic-gate 		return ((fq == 0) ? 1 : 0);
718*0Sstevel@tonic-gate 
719*0Sstevel@tonic-gate 	for (i = 0, match = 1; match && i < q->components.components_len;
720*0Sstevel@tonic-gate 			i++) {
721*0Sstevel@tonic-gate 		for (j = 0; j < fq->components.components_len; j++) {
722*0Sstevel@tonic-gate 			int	len, flen;
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 			/* Same index ? */
725*0Sstevel@tonic-gate 			if (q->components.components_val[i].which_index !=
726*0Sstevel@tonic-gate 					fq->components.components_val[j].
727*0Sstevel@tonic-gate 						which_index)
728*0Sstevel@tonic-gate 				continue;
729*0Sstevel@tonic-gate 			/*
730*0Sstevel@tonic-gate 			 * If one 'index_value' is NULL, the other one must
731*0Sstevel@tonic-gate 			 * be NULL as well.
732*0Sstevel@tonic-gate 			 */
733*0Sstevel@tonic-gate 			if (q->components.components_val[i].index_value == 0) {
734*0Sstevel@tonic-gate 				if (fq->components.components_val[j].
735*0Sstevel@tonic-gate 						index_value == 0)
736*0Sstevel@tonic-gate 					continue;
737*0Sstevel@tonic-gate 				else {
738*0Sstevel@tonic-gate 					match = 0;
739*0Sstevel@tonic-gate 					break;
740*0Sstevel@tonic-gate 				}
741*0Sstevel@tonic-gate 			}
742*0Sstevel@tonic-gate 			if (fq->components.components_val[j].index_value ==
743*0Sstevel@tonic-gate 					0) {
744*0Sstevel@tonic-gate 				match = 0;
745*0Sstevel@tonic-gate 				break;
746*0Sstevel@tonic-gate 			}
747*0Sstevel@tonic-gate 			/* Same value lengths ? */
748*0Sstevel@tonic-gate 			len = q->components.components_val[i].index_value->
749*0Sstevel@tonic-gate 				itemvalue.itemvalue_len;
750*0Sstevel@tonic-gate 			flen = fq->components.components_val[j].index_value->
751*0Sstevel@tonic-gate 				itemvalue.itemvalue_len;
752*0Sstevel@tonic-gate 			if (len != flen) {
753*0Sstevel@tonic-gate 				/*
754*0Sstevel@tonic-gate 				 * There's a twist here: the input query
755*0Sstevel@tonic-gate 				 * may well _not_ count a concluding NUL
756*0Sstevel@tonic-gate 				 * in a string value, while the output
757*0Sstevel@tonic-gate 				 * usually will. So, if the difference in
758*0Sstevel@tonic-gate 				 * length is one, and the "extra" byte is
759*0Sstevel@tonic-gate 				 * a zero-valued one, we accept equality.
760*0Sstevel@tonic-gate 				 * 'q' is assumed to be the output, and
761*0Sstevel@tonic-gate 				 * 'fq' the input.
762*0Sstevel@tonic-gate 				 */
763*0Sstevel@tonic-gate 				if (!(len > 0 && len == (flen+1) &&
764*0Sstevel@tonic-gate 					q->components.components_val[i].
765*0Sstevel@tonic-gate 					index_value->
766*0Sstevel@tonic-gate 					itemvalue.itemvalue_val[len-1] == 0)) {
767*0Sstevel@tonic-gate 					match = 0;
768*0Sstevel@tonic-gate 					break;
769*0Sstevel@tonic-gate 				}
770*0Sstevel@tonic-gate 			}
771*0Sstevel@tonic-gate 			/* Same value ? */
772*0Sstevel@tonic-gate 			if (memcmp(q->components.components_val[i].index_value->
773*0Sstevel@tonic-gate 					itemvalue.itemvalue_val,
774*0Sstevel@tonic-gate 				fq->components.components_val[j].index_value->
775*0Sstevel@tonic-gate 					itemvalue.itemvalue_val,
776*0Sstevel@tonic-gate 					flen) != 0) {
777*0Sstevel@tonic-gate 				match = 0;
778*0Sstevel@tonic-gate 				break;
779*0Sstevel@tonic-gate 			}
780*0Sstevel@tonic-gate 		}
781*0Sstevel@tonic-gate 	}
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	return (match);
784*0Sstevel@tonic-gate }
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate /*
787*0Sstevel@tonic-gate  * Remove those queries in 'q' that don't match t->index.
788*0Sstevel@tonic-gate  * Returns a pointer to the filtered array, which could be
789*0Sstevel@tonic-gate  * a compacted version of the original, or a new copy; in
790*0Sstevel@tonic-gate  * the latter case, the original will have been freed.
791*0Sstevel@tonic-gate  *
792*0Sstevel@tonic-gate  * Filtered/removed db_query's are freed.
793*0Sstevel@tonic-gate  */
794*0Sstevel@tonic-gate db_query **
795*0Sstevel@tonic-gate filterQuery(__nis_table_mapping_t *t, db_query **q, db_query *qin,
796*0Sstevel@tonic-gate 		__nis_obj_attr_t ***objAttr, int *numQueries) {
797*0Sstevel@tonic-gate 	db_query		**new;
798*0Sstevel@tonic-gate 	__nis_obj_attr_t	**attr;
799*0Sstevel@tonic-gate 	int			i, nq, nn;
800*0Sstevel@tonic-gate 	char			*myself = "filterQuery";
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 	if ((t == 0 && qin == 0) || q == 0 ||
803*0Sstevel@tonic-gate 			numQueries == 0 || *numQueries <= 0)
804*0Sstevel@tonic-gate 		return (q);
805*0Sstevel@tonic-gate 
806*0Sstevel@tonic-gate 	nq = *numQueries;
807*0Sstevel@tonic-gate 	new = am(myself, nq * sizeof (new[0]));
808*0Sstevel@tonic-gate 	if (objAttr != 0)
809*0Sstevel@tonic-gate 		attr = am(myself, nq * sizeof (attr[0]));
810*0Sstevel@tonic-gate 	else
811*0Sstevel@tonic-gate 		attr = 0;
812*0Sstevel@tonic-gate 	if (new == 0 || (objAttr != 0 && attr == 0)) {
813*0Sstevel@tonic-gate 		sfree(new);
814*0Sstevel@tonic-gate 		freeQueries(q, nq);
815*0Sstevel@tonic-gate 		sfree(attr);
816*0Sstevel@tonic-gate 		if (objAttr != 0) {
817*0Sstevel@tonic-gate 			freeObjAttr(*objAttr, nq);
818*0Sstevel@tonic-gate 			*objAttr = 0;
819*0Sstevel@tonic-gate 		}
820*0Sstevel@tonic-gate 		*numQueries = -1;
821*0Sstevel@tonic-gate 		return (0);
822*0Sstevel@tonic-gate 	}
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 	for (i = 0, nn = 0; i < nq; i++) {
825*0Sstevel@tonic-gate 		int	retain = 1;
826*0Sstevel@tonic-gate 
827*0Sstevel@tonic-gate 		if (t != 0)
828*0Sstevel@tonic-gate 			retain = verifyIndexMatch(t, q[i], 0, 0, 0);
829*0Sstevel@tonic-gate 
830*0Sstevel@tonic-gate 		if (retain && qin != 0)
831*0Sstevel@tonic-gate 			retain = verifyQueryMatch(q[i], qin);
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 		if (retain) {
834*0Sstevel@tonic-gate 			new[nn] = q[i];
835*0Sstevel@tonic-gate 			if (objAttr != 0)
836*0Sstevel@tonic-gate 				attr[nn] = (*objAttr)[i];
837*0Sstevel@tonic-gate 			nn++;
838*0Sstevel@tonic-gate 		} else {
839*0Sstevel@tonic-gate 			freeQuery(q[i]);
840*0Sstevel@tonic-gate 			q[i] = 0;
841*0Sstevel@tonic-gate 			if (objAttr != 0) {
842*0Sstevel@tonic-gate 				freeSingleObjAttr((*objAttr)[i]);
843*0Sstevel@tonic-gate 				(*objAttr)[i] = 0;
844*0Sstevel@tonic-gate 			}
845*0Sstevel@tonic-gate 		}
846*0Sstevel@tonic-gate 	}
847*0Sstevel@tonic-gate 
848*0Sstevel@tonic-gate 	/* All q[i]'s are either in 'new', or have been deleted */
849*0Sstevel@tonic-gate 	free(q);
850*0Sstevel@tonic-gate 	if (objAttr != 0) {
851*0Sstevel@tonic-gate 		sfree(*objAttr);
852*0Sstevel@tonic-gate 		*objAttr = attr;
853*0Sstevel@tonic-gate 	}
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 	*numQueries = nn;
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	return (new);
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate db_query **
861*0Sstevel@tonic-gate createNisPlusEntry(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
862*0Sstevel@tonic-gate 			db_query *qin, __nis_obj_attr_t ***objAttr,
863*0Sstevel@tonic-gate 			int *numQueries) {
864*0Sstevel@tonic-gate 	db_query		**query = 0;
865*0Sstevel@tonic-gate 	int			r, i, j, ir;
866*0Sstevel@tonic-gate 	__nis_value_t		*rval, *lval;
867*0Sstevel@tonic-gate 	__nis_mapping_item_t	*litem;
868*0Sstevel@tonic-gate 	int			numItems;
869*0Sstevel@tonic-gate 	int			nq, iqc;
870*0Sstevel@tonic-gate 	__nis_obj_attr_t	**attr = 0;
871*0Sstevel@tonic-gate 	char			**dn = 0;
872*0Sstevel@tonic-gate 	int			numDN = 0;
873*0Sstevel@tonic-gate 	char			*myself = "createNisPlusEntry";
874*0Sstevel@tonic-gate 
875*0Sstevel@tonic-gate 	if (t == 0 || t->objectDN == 0 || rv == 0)
876*0Sstevel@tonic-gate 		return (0);
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 	/* Establish default, per-thread, search base */
879*0Sstevel@tonic-gate 	__nisdb_get_tsd()->searchBase = t->objectDN->read.base;
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	for (r = 0, nq = 0; r < t->numRulesFromLDAP; r++) {
882*0Sstevel@tonic-gate 		int			nrq, ntq, err;
883*0Sstevel@tonic-gate 		db_query		**newq;
884*0Sstevel@tonic-gate 		__nis_obj_attr_t	**newattr;
885*0Sstevel@tonic-gate 
886*0Sstevel@tonic-gate 		rval = buildRvalue(&t->ruleFromLDAP[r]->rhs,
887*0Sstevel@tonic-gate 			mit_ldap, rv, NULL);
888*0Sstevel@tonic-gate 		if (rval == 0)
889*0Sstevel@tonic-gate 			continue;
890*0Sstevel@tonic-gate 
891*0Sstevel@tonic-gate 		litem = buildLvalue(&t->ruleFromLDAP[r]->lhs, &rval,
892*0Sstevel@tonic-gate 					&numItems);
893*0Sstevel@tonic-gate 		if (litem == 0) {
894*0Sstevel@tonic-gate 			freeValue(rval, 1);
895*0Sstevel@tonic-gate 			/* XXX Should this be a fatal error ? */
896*0Sstevel@tonic-gate 			continue;
897*0Sstevel@tonic-gate 		}
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate 		lval = 0;
900*0Sstevel@tonic-gate 		for (i = 0; i < numItems; i++) {
901*0Sstevel@tonic-gate 			__nis_value_t	*tmpval, *old;
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 			tmpval = getMappingItem(&litem[i],
904*0Sstevel@tonic-gate 				mit_nisplus, 0, 0, NULL);
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 			/*
907*0Sstevel@tonic-gate 			 * If the LHS specifies an out-of-context LDAP or
908*0Sstevel@tonic-gate 			 * NIS+ item, we do the update right here. We
909*0Sstevel@tonic-gate 			 * don't add any values to 'lval'; instead, we
910*0Sstevel@tonic-gate 			 * skip to the next item. (However, we still
911*0Sstevel@tonic-gate 			 * get a string representation of the LHS in case
912*0Sstevel@tonic-gate 			 * we need to report an error.)
913*0Sstevel@tonic-gate 			 */
914*0Sstevel@tonic-gate 			if (litem[i].type == mit_nisplus &&
915*0Sstevel@tonic-gate 				litem[i].searchSpec.obj.index.numIndexes > 0) {
916*0Sstevel@tonic-gate 				int	err;
917*0Sstevel@tonic-gate 
918*0Sstevel@tonic-gate 				err = storeNisPlus(&litem[i], i, numItems,
919*0Sstevel@tonic-gate 							rv, t->objName, rval);
920*0Sstevel@tonic-gate 				if (err != NIS_SUCCESS) {
921*0Sstevel@tonic-gate 					char	*iname = "<unknown>";
922*0Sstevel@tonic-gate 
923*0Sstevel@tonic-gate 					if (tmpval != 0 &&
924*0Sstevel@tonic-gate 							tmpval->numVals == 1)
925*0Sstevel@tonic-gate 						iname = tmpval->val[0].value;
926*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
927*0Sstevel@tonic-gate 						"%s: NIS+ store \"%s\": %s",
928*0Sstevel@tonic-gate 						myself, iname,
929*0Sstevel@tonic-gate 						nis_sperrno(err));
930*0Sstevel@tonic-gate 				}
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 				freeValue(tmpval, 1);
933*0Sstevel@tonic-gate 				continue;
934*0Sstevel@tonic-gate 			} else if (litem[i].type == mit_ldap) {
935*0Sstevel@tonic-gate 				int	stat;
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 				if (dn == 0)
938*0Sstevel@tonic-gate 					dn = findDNs(myself, rv, 1,
939*0Sstevel@tonic-gate 						t->objectDN->write.base,
940*0Sstevel@tonic-gate 						&numDN);
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 				stat = storeLDAP(&litem[i], i, numItems, rval,
943*0Sstevel@tonic-gate 					t->objectDN, dn, numDN);
944*0Sstevel@tonic-gate 				if (stat != LDAP_SUCCESS) {
945*0Sstevel@tonic-gate 					char	*iname = "<unknown>";
946*0Sstevel@tonic-gate 
947*0Sstevel@tonic-gate 					if (tmpval != 0 &&
948*0Sstevel@tonic-gate 							tmpval->numVals == 1)
949*0Sstevel@tonic-gate 						iname = tmpval->val[0].value;
950*0Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
951*0Sstevel@tonic-gate 						"%s: LDAP store \"%s\": %s",
952*0Sstevel@tonic-gate 						myself, iname,
953*0Sstevel@tonic-gate 						ldap_err2string(stat));
954*0Sstevel@tonic-gate 				}
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 				freeValue(tmpval, 1);
957*0Sstevel@tonic-gate 				continue;
958*0Sstevel@tonic-gate 			}
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 			old = lval;
961*0Sstevel@tonic-gate 			lval = concatenateValues(old, tmpval);
962*0Sstevel@tonic-gate 			freeValue(tmpval, 1);
963*0Sstevel@tonic-gate 			freeValue(old, 1);
964*0Sstevel@tonic-gate 		}
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 		freeMappingItem(litem, numItems);
967*0Sstevel@tonic-gate 		if (lval == 0 || lval->numVals <= 0 || rval->numVals <= 0) {
968*0Sstevel@tonic-gate 			freeValue(lval, 1);
969*0Sstevel@tonic-gate 			freeValue(rval, 1);
970*0Sstevel@tonic-gate 			continue;
971*0Sstevel@tonic-gate 		}
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 		/*
974*0Sstevel@tonic-gate 		 * We now have a number of possible cases. The notation
975*0Sstevel@tonic-gate 		 * used in the table is:
976*0Sstevel@tonic-gate 		 *
977*0Sstevel@tonic-gate 		 *	single		A single value (numVals == 1)
978*0Sstevel@tonic-gate 		 *	single/rep	A single value with repeat == 1
979*0Sstevel@tonic-gate 		 *	multi[N]	N values
980*0Sstevel@tonic-gate 		 *	multi[N]/rep	M values with repeat == 1
981*0Sstevel@tonic-gate 		 *	(M)		M resulting db_query's
982*0Sstevel@tonic-gate 		 *
983*0Sstevel@tonic-gate 		 * lval \ rval	single	single/rep	multi[N] multi[N]/rep
984*0Sstevel@tonic-gate 		 * single	  (1)	    (1)		 (1)	    (1)
985*0Sstevel@tonic-gate 		 * single/rep	  (1)	    (1)		 (N)	    (N)
986*0Sstevel@tonic-gate 		 * multi[M]	  (1)	    (1)		 (1)	 1+(N-1)/M
987*0Sstevel@tonic-gate 		 * multi[M]/rep	  (1)	    (1)		 (1)	 1+(N-1)/M
988*0Sstevel@tonic-gate 		 *
989*0Sstevel@tonic-gate 		 * Of course, we already have 'nq' db_query's from previous
990*0Sstevel@tonic-gate 		 * rules, so the resulting number of queries is max(1,nq)
991*0Sstevel@tonic-gate 		 * times the numbers in the table above.
992*0Sstevel@tonic-gate 		 */
993*0Sstevel@tonic-gate 
994*0Sstevel@tonic-gate 		/* The number of queries resulting from the current rule */
995*0Sstevel@tonic-gate 		if (rval->numVals > 1) {
996*0Sstevel@tonic-gate 			if (lval->numVals == 1 && lval->repeat)
997*0Sstevel@tonic-gate 				nrq = rval->numVals;
998*0Sstevel@tonic-gate 			else if (lval->numVals > 1 && rval->repeat)
999*0Sstevel@tonic-gate 				nrq = 1 + ((rval->numVals-1)/lval->numVals);
1000*0Sstevel@tonic-gate 			else
1001*0Sstevel@tonic-gate 				nrq = 1;
1002*0Sstevel@tonic-gate 		} else {
1003*0Sstevel@tonic-gate 			nrq = 1;
1004*0Sstevel@tonic-gate 		}
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 		/* Total number of queries after adding the current rule */
1007*0Sstevel@tonic-gate 		if (nq <= 0)
1008*0Sstevel@tonic-gate 			ntq = nrq;
1009*0Sstevel@tonic-gate 		else
1010*0Sstevel@tonic-gate 			ntq = nq * nrq;
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 		if (ntq > nq) {
1013*0Sstevel@tonic-gate 			newq = realloc(query, ntq * sizeof (query[0]));
1014*0Sstevel@tonic-gate 			newattr = realloc(attr, ntq * sizeof (attr[0]));
1015*0Sstevel@tonic-gate 			if (newq == 0 || newattr == 0) {
1016*0Sstevel@tonic-gate 				logmsg(MSG_NOMEM, LOG_ERR,
1017*0Sstevel@tonic-gate 					"%s: realloc(%d) => NULL",
1018*0Sstevel@tonic-gate 					myself, ntq * sizeof (query[0]));
1019*0Sstevel@tonic-gate 				freeValue(lval, 1);
1020*0Sstevel@tonic-gate 				freeValue(rval, 1);
1021*0Sstevel@tonic-gate 				freeQueries(query, nq);
1022*0Sstevel@tonic-gate 				freeObjAttr(attr, nq);
1023*0Sstevel@tonic-gate 				sfree(newq);
1024*0Sstevel@tonic-gate 				freeDNs(dn, numDN);
1025*0Sstevel@tonic-gate 				return (0);
1026*0Sstevel@tonic-gate 			}
1027*0Sstevel@tonic-gate 			query = newq;
1028*0Sstevel@tonic-gate 			attr = newattr;
1029*0Sstevel@tonic-gate 		}
1030*0Sstevel@tonic-gate 
1031*0Sstevel@tonic-gate 		/*
1032*0Sstevel@tonic-gate 		 * Copy/clone the existing queries to the new array,
1033*0Sstevel@tonic-gate 		 * remembering that realloc() has done the first 'nq'
1034*0Sstevel@tonic-gate 		 * ones.
1035*0Sstevel@tonic-gate 		 *
1036*0Sstevel@tonic-gate 		 * If there's an error (probably memory allocation), we
1037*0Sstevel@tonic-gate 		 * still go through the rest of the array, so that it's
1038*0Sstevel@tonic-gate 		 * simple to free the elements when we clean up.
1039*0Sstevel@tonic-gate 		 */
1040*0Sstevel@tonic-gate 		for (i = 1, err = 0; i < nrq; i++) {
1041*0Sstevel@tonic-gate 			for (j = 0; j < nq; j++) {
1042*0Sstevel@tonic-gate 				query[(nq*i)+j] = cloneQuery(query[j],
1043*0Sstevel@tonic-gate 						t->numColumns);
1044*0Sstevel@tonic-gate 				if (query[(nq*i)+j] == 0 &&
1045*0Sstevel@tonic-gate 						query[j] != 0)
1046*0Sstevel@tonic-gate 					err++;
1047*0Sstevel@tonic-gate 				attr[(nq*i)+j] = cloneObjAttr(attr[j]);
1048*0Sstevel@tonic-gate 				if (attr[(nq*i)+j] == 0 &&
1049*0Sstevel@tonic-gate 						attr[j] != 0)
1050*0Sstevel@tonic-gate 					err++;
1051*0Sstevel@tonic-gate 			}
1052*0Sstevel@tonic-gate 		}
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 		if (err > 0) {
1055*0Sstevel@tonic-gate 			freeValue(lval, 1);
1056*0Sstevel@tonic-gate 			freeValue(rval, 1);
1057*0Sstevel@tonic-gate 			freeQueries(query, ntq);
1058*0Sstevel@tonic-gate 			freeObjAttr(attr, ntq);
1059*0Sstevel@tonic-gate 			freeDNs(dn, numDN);
1060*0Sstevel@tonic-gate 			return (0);
1061*0Sstevel@tonic-gate 		}
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate 		/*
1064*0Sstevel@tonic-gate 		 * Special case if nq == 0 (i.e., the first time we
1065*0Sstevel@tonic-gate 		 * allocated db_query's). If so, we now allocate empty
1066*0Sstevel@tonic-gate 		 * db_qcomp arrays, which simplifies subsequent
1067*0Sstevel@tonic-gate 		 * copying of values.
1068*0Sstevel@tonic-gate 		 */
1069*0Sstevel@tonic-gate 		if (nq <= 0) {
1070*0Sstevel@tonic-gate 			(void) memset(query, 0, ntq * sizeof (query[0]));
1071*0Sstevel@tonic-gate 			(void) memset(attr, 0, ntq * sizeof (attr[0]));
1072*0Sstevel@tonic-gate 			for (i = 0, err = 0; i < ntq; i++) {
1073*0Sstevel@tonic-gate 				query[i] = am(myself, sizeof (*query[i]));
1074*0Sstevel@tonic-gate 				if (query[i] == 0) {
1075*0Sstevel@tonic-gate 					err++;
1076*0Sstevel@tonic-gate 					break;
1077*0Sstevel@tonic-gate 				}
1078*0Sstevel@tonic-gate 				query[i]->components.components_val =
1079*0Sstevel@tonic-gate 					am(myself, t->numColumns *
1080*0Sstevel@tonic-gate 			sizeof (query[i]->components.components_val[0]));
1081*0Sstevel@tonic-gate 				if (query[i]->components.components_val == 0) {
1082*0Sstevel@tonic-gate 					err++;
1083*0Sstevel@tonic-gate 					break;
1084*0Sstevel@tonic-gate 				}
1085*0Sstevel@tonic-gate 				query[i]->components.components_len = 0;
1086*0Sstevel@tonic-gate 			}
1087*0Sstevel@tonic-gate 			if (err > 0) {
1088*0Sstevel@tonic-gate 				freeValue(lval, 1);
1089*0Sstevel@tonic-gate 				freeValue(rval, 1);
1090*0Sstevel@tonic-gate 				freeQueries(query, ntq);
1091*0Sstevel@tonic-gate 				freeObjAttr(attr, ntq);
1092*0Sstevel@tonic-gate 				freeDNs(dn, numDN);
1093*0Sstevel@tonic-gate 				return (0);
1094*0Sstevel@tonic-gate 			}
1095*0Sstevel@tonic-gate 		}
1096*0Sstevel@tonic-gate 
1097*0Sstevel@tonic-gate 		/* Now we're ready to add the new values */
1098*0Sstevel@tonic-gate 		for (i = 0, ir = 0; i < lval->numVals; i++) {
1099*0Sstevel@tonic-gate 			char	*oaName = 0;
1100*0Sstevel@tonic-gate 			int	index;
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate 			/* Find column index */
1103*0Sstevel@tonic-gate 			for (index = 0; index < t->numColumns;
1104*0Sstevel@tonic-gate 					index++) {
1105*0Sstevel@tonic-gate 				if (strncmp(t->column[index],
1106*0Sstevel@tonic-gate 						lval->val[i].value,
1107*0Sstevel@tonic-gate 					lval->val[i].length) == 0)
1108*0Sstevel@tonic-gate 					break;
1109*0Sstevel@tonic-gate 			}
1110*0Sstevel@tonic-gate 			if (index >= t->numColumns) {
1111*0Sstevel@tonic-gate 				/*
1112*0Sstevel@tonic-gate 				 * Could be one of the special object
1113*0Sstevel@tonic-gate 				 * attributes.
1114*0Sstevel@tonic-gate 				 */
1115*0Sstevel@tonic-gate 				oaName = isObjAttr(&lval->val[i]);
1116*0Sstevel@tonic-gate 				if (oaName == 0)
1117*0Sstevel@tonic-gate 					continue;
1118*0Sstevel@tonic-gate 			}
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate 			for (j = i*nrq; j < (i+1)*nrq; j++) {
1121*0Sstevel@tonic-gate 				int	k;
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate 				/* If we're out of values, repeat last one */
1124*0Sstevel@tonic-gate 				ir = (j < rval->numVals) ?
1125*0Sstevel@tonic-gate 					j : rval->numVals - 1;
1126*0Sstevel@tonic-gate 
1127*0Sstevel@tonic-gate 				/*
1128*0Sstevel@tonic-gate 				 * Step through the query array, adding
1129*0Sstevel@tonic-gate 				 * the new value every 'nrq' queries, and
1130*0Sstevel@tonic-gate 				 * starting at 'query[j % nrq]'.
1131*0Sstevel@tonic-gate 				 */
1132*0Sstevel@tonic-gate 				for (k = j % nrq, err = 0; k < ntq; k += nrq) {
1133*0Sstevel@tonic-gate 					int	ic, c;
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 					if (oaName != 0) {
1136*0Sstevel@tonic-gate 						int	fail = setObjAttrField(
1137*0Sstevel@tonic-gate 								oaName,
1138*0Sstevel@tonic-gate 								&rval->val[ir],
1139*0Sstevel@tonic-gate 								&attr[k]);
1140*0Sstevel@tonic-gate 						if (fail) {
1141*0Sstevel@tonic-gate 							err++;
1142*0Sstevel@tonic-gate 							break;
1143*0Sstevel@tonic-gate 						}
1144*0Sstevel@tonic-gate 						continue;
1145*0Sstevel@tonic-gate 					}
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate 					ic = query[k]->components.
1148*0Sstevel@tonic-gate 						components_len;
1149*0Sstevel@tonic-gate 					/*
1150*0Sstevel@tonic-gate 					 * If we've already filled this
1151*0Sstevel@tonic-gate 					 * query, the new value is a dup
1152*0Sstevel@tonic-gate 					 * which we'll ignore.
1153*0Sstevel@tonic-gate 					 */
1154*0Sstevel@tonic-gate 					if (ic >= t->numColumns)
1155*0Sstevel@tonic-gate 						continue;
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 					/*
1158*0Sstevel@tonic-gate 					 * Do we already have a value for
1159*0Sstevel@tonic-gate 					 * this 'index' ?
1160*0Sstevel@tonic-gate 					 */
1161*0Sstevel@tonic-gate 					for (c = 0; c < ic; c++) {
1162*0Sstevel@tonic-gate 						if (query[k]->components.
1163*0Sstevel@tonic-gate 							components_val[c].
1164*0Sstevel@tonic-gate 							which_index == index)
1165*0Sstevel@tonic-gate 							break;
1166*0Sstevel@tonic-gate 					}
1167*0Sstevel@tonic-gate 
1168*0Sstevel@tonic-gate 					/* If no previous value, add it */
1169*0Sstevel@tonic-gate 					if (c >= ic) {
1170*0Sstevel@tonic-gate 						int	l;
1171*0Sstevel@tonic-gate 						char	*v;
1172*0Sstevel@tonic-gate 
1173*0Sstevel@tonic-gate 						query[k]->components.
1174*0Sstevel@tonic-gate 							components_val[ic].
1175*0Sstevel@tonic-gate 							which_index = index;
1176*0Sstevel@tonic-gate 						l = rval->val[ir].length;
1177*0Sstevel@tonic-gate 						v = rval->val[ir].value;
1178*0Sstevel@tonic-gate 						if (rval->type == vt_string &&
1179*0Sstevel@tonic-gate 							l > 0 &&
1180*0Sstevel@tonic-gate 							v[l-1] != '\0' &&
1181*0Sstevel@tonic-gate 							v[l] == '\0')
1182*0Sstevel@tonic-gate 							l++;
1183*0Sstevel@tonic-gate 						query[k]->components.
1184*0Sstevel@tonic-gate 							components_val[ic].
1185*0Sstevel@tonic-gate 							index_value =
1186*0Sstevel@tonic-gate 							buildItem(l, v);
1187*0Sstevel@tonic-gate 						if (query[k]->
1188*0Sstevel@tonic-gate 							components.
1189*0Sstevel@tonic-gate 							components_val[ic].
1190*0Sstevel@tonic-gate 							index_value == 0) {
1191*0Sstevel@tonic-gate 							err++;
1192*0Sstevel@tonic-gate 							break;
1193*0Sstevel@tonic-gate 						}
1194*0Sstevel@tonic-gate 						query[k]->components.
1195*0Sstevel@tonic-gate 							components_len++;
1196*0Sstevel@tonic-gate 					}
1197*0Sstevel@tonic-gate 				}
1198*0Sstevel@tonic-gate 				if (err > 0) {
1199*0Sstevel@tonic-gate 					freeValue(lval, 1);
1200*0Sstevel@tonic-gate 					freeValue(rval, 1);
1201*0Sstevel@tonic-gate 					freeQueries(query, ntq);
1202*0Sstevel@tonic-gate 					freeObjAttr(attr, ntq);
1203*0Sstevel@tonic-gate 					freeDNs(dn, numDN);
1204*0Sstevel@tonic-gate 					return (0);
1205*0Sstevel@tonic-gate 				}
1206*0Sstevel@tonic-gate 			}
1207*0Sstevel@tonic-gate 		}
1208*0Sstevel@tonic-gate 		freeValue(lval, 1);
1209*0Sstevel@tonic-gate 		freeValue(rval, 1);
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate 		nq = ntq;
1212*0Sstevel@tonic-gate 	}
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	freeDNs(dn, numDN);
1215*0Sstevel@tonic-gate 
1216*0Sstevel@tonic-gate 	if (nq <= 0) {
1217*0Sstevel@tonic-gate 		sfree(query);
1218*0Sstevel@tonic-gate 		query = 0;
1219*0Sstevel@tonic-gate 	}
1220*0Sstevel@tonic-gate 
1221*0Sstevel@tonic-gate 	/* Should we filter on index or input query ? */
1222*0Sstevel@tonic-gate 	if (query != 0) {
1223*0Sstevel@tonic-gate 		if (t->index.numIndexes > 0)
1224*0Sstevel@tonic-gate 			query = filterQuery(t, query, qin, &attr, &nq);
1225*0Sstevel@tonic-gate 		else if (qin != 0)
1226*0Sstevel@tonic-gate 			query = filterQuery(0, query, qin, &attr, &nq);
1227*0Sstevel@tonic-gate 	}
1228*0Sstevel@tonic-gate 
1229*0Sstevel@tonic-gate 	if (query != 0 && numQueries != 0)
1230*0Sstevel@tonic-gate 		*numQueries = nq;
1231*0Sstevel@tonic-gate 
1232*0Sstevel@tonic-gate 	if (objAttr != 0)
1233*0Sstevel@tonic-gate 		*objAttr = attr;
1234*0Sstevel@tonic-gate 	else
1235*0Sstevel@tonic-gate 		freeObjAttr(attr, nq);
1236*0Sstevel@tonic-gate 
1237*0Sstevel@tonic-gate 	return (query);
1238*0Sstevel@tonic-gate }
1239*0Sstevel@tonic-gate /*
1240*0Sstevel@tonic-gate  * Given a table mapping and a rule-value, convert to an array of
1241*0Sstevel@tonic-gate  * (db_query *), using the fromLDAP ruleset.
1242*0Sstevel@tonic-gate  *
1243*0Sstevel@tonic-gate  * On entry, '*numQueries' holds the number of elements in the 'rv'
1244*0Sstevel@tonic-gate  * array. On exit, it holds the number of (db_query *)'s in the return
1245*0Sstevel@tonic-gate  * value array.
1246*0Sstevel@tonic-gate  */
1247*0Sstevel@tonic-gate db_query **
1248*0Sstevel@tonic-gate ruleValue2Query(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
1249*0Sstevel@tonic-gate 		db_query *qin, __nis_obj_attr_t ***objAttr, int *numQueries) {
1250*0Sstevel@tonic-gate 	db_query		**q = 0, ***qp = 0;
1251*0Sstevel@tonic-gate 	int			i, nqp, nq, *nnp = 0, nv;
1252*0Sstevel@tonic-gate 	__nis_obj_attr_t	**attr = 0, ***atp = 0;
1253*0Sstevel@tonic-gate 	char			*myself = "ruleValue2Query";
1254*0Sstevel@tonic-gate 
1255*0Sstevel@tonic-gate 
1256*0Sstevel@tonic-gate 	if (t == 0 || rv == 0 || numQueries == 0)
1257*0Sstevel@tonic-gate 		return (0);
1258*0Sstevel@tonic-gate 
1259*0Sstevel@tonic-gate 	nv = *numQueries;
1260*0Sstevel@tonic-gate 	if (nv <= 0)
1261*0Sstevel@tonic-gate 		return (0);
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 	/*
1264*0Sstevel@tonic-gate 	 * 'qp' is an array of (db_query **), and we get one element for
1265*0Sstevel@tonic-gate 	 * each call to createNisPlusEntry(); i.e., one for each rule-value.
1266*0Sstevel@tonic-gate 	 *
1267*0Sstevel@tonic-gate 	 * 'nnp[i]' is the count of (db_query *) in each 'qp[i]'.
1268*0Sstevel@tonic-gate 	 */
1269*0Sstevel@tonic-gate 	qp = am(myself, nv * sizeof (*qp));
1270*0Sstevel@tonic-gate 	nnp = am(myself, nv * sizeof (*nnp));
1271*0Sstevel@tonic-gate 	atp = am(myself, nv * sizeof (*atp));
1272*0Sstevel@tonic-gate 	if (qp == 0 || nnp == 0 || atp == 0) {
1273*0Sstevel@tonic-gate 		sfree(qp);
1274*0Sstevel@tonic-gate 		sfree(nnp);
1275*0Sstevel@tonic-gate 		sfree(atp);
1276*0Sstevel@tonic-gate 		return (0);
1277*0Sstevel@tonic-gate 	}
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	for (i = 0, nq = 0, nqp = 0; i < nv; i++) {
1280*0Sstevel@tonic-gate 		qp[nqp] = createNisPlusEntry(t, &rv[i], qin, &atp[nqp],
1281*0Sstevel@tonic-gate 						&nnp[nqp]);
1282*0Sstevel@tonic-gate 		/* If we fail, abort (XXX??? or continue ???) */
1283*0Sstevel@tonic-gate 		if (qp[nqp] == 0)
1284*0Sstevel@tonic-gate 			goto cleanup;
1285*0Sstevel@tonic-gate 		nq += nnp[nqp];
1286*0Sstevel@tonic-gate 		nqp++;
1287*0Sstevel@tonic-gate 	}
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate 	/* If we didn't get any (db_query **)'s, return failure */
1290*0Sstevel@tonic-gate 	if (nqp == 0 || nq <= 0)
1291*0Sstevel@tonic-gate 		goto cleanup;
1292*0Sstevel@tonic-gate 
1293*0Sstevel@tonic-gate 	q = am(myself, nq * sizeof (q[0]));
1294*0Sstevel@tonic-gate 	attr = am(myself, nq * sizeof (attr[0]));
1295*0Sstevel@tonic-gate 	if (q == 0 || attr == 0) {
1296*0Sstevel@tonic-gate 		nq = 0;
1297*0Sstevel@tonic-gate 		goto cleanup;
1298*0Sstevel@tonic-gate 	}
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 	/* Convert 'qp' to an array of (db_query *)'s */
1301*0Sstevel@tonic-gate 	for (i = 0, nq = 0; i < nqp; i++) {
1302*0Sstevel@tonic-gate 		(void) memcpy(&q[nq], qp[i], nnp[i] * sizeof (qp[i][0]));
1303*0Sstevel@tonic-gate 		(void) memcpy(&attr[nq], atp[i], nnp[i] * sizeof (atp[i][0]));
1304*0Sstevel@tonic-gate 		nq += nnp[i];
1305*0Sstevel@tonic-gate 		free(qp[i]);
1306*0Sstevel@tonic-gate 		free(atp[i]);
1307*0Sstevel@tonic-gate 	}
1308*0Sstevel@tonic-gate 
1309*0Sstevel@tonic-gate 	*numQueries = nq;
1310*0Sstevel@tonic-gate 	if (objAttr != 0)
1311*0Sstevel@tonic-gate 		*objAttr = attr;
1312*0Sstevel@tonic-gate 	else
1313*0Sstevel@tonic-gate 		freeObjAttr(attr, nq);
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 	/* Make sure 'cleanup' doesn't free the db_query pointers */
1316*0Sstevel@tonic-gate 	nqp = 0;
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate cleanup:
1319*0Sstevel@tonic-gate 	for (i = 0; i < nqp; i++) {
1320*0Sstevel@tonic-gate 		freeQueries(qp[i], nnp[i]);
1321*0Sstevel@tonic-gate 		sfree(atp[i]);
1322*0Sstevel@tonic-gate 	}
1323*0Sstevel@tonic-gate 	sfree(qp);
1324*0Sstevel@tonic-gate 	sfree(nnp);
1325*0Sstevel@tonic-gate 	sfree(atp);
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 	return (q);
1328*0Sstevel@tonic-gate }
1329*0Sstevel@tonic-gate 
1330*0Sstevel@tonic-gate db_query *
1331*0Sstevel@tonic-gate pseudoEntryObj2Query(entry_obj *e, nis_object *tobj, __nis_rule_value_t *rv) {
1332*0Sstevel@tonic-gate 	db_query		*qbuf;
1333*0Sstevel@tonic-gate 	db_qcomp		*qcbuf;
1334*0Sstevel@tonic-gate 	int			nc, i;
1335*0Sstevel@tonic-gate 	__nis_rule_value_t	*rvt = 0;
1336*0Sstevel@tonic-gate 	char			*myself = "pseudoEntryObj2Query";
1337*0Sstevel@tonic-gate 
1338*0Sstevel@tonic-gate 	nc = e->en_cols.en_cols_len - 1;
1339*0Sstevel@tonic-gate 
1340*0Sstevel@tonic-gate 	if (e == 0 || nc < 0 || nc > NIS_MAXCOLUMNS)
1341*0Sstevel@tonic-gate 		return (0);
1342*0Sstevel@tonic-gate 
1343*0Sstevel@tonic-gate 	/*
1344*0Sstevel@tonic-gate 	 * If 'rvP' is non-NULL, build a rule value from the pseudo-
1345*0Sstevel@tonic-gate 	 * nis_object in e->en_cols.en_cols_val[0].
1346*0Sstevel@tonic-gate 	 */
1347*0Sstevel@tonic-gate 	if (rv != 0) {
1348*0Sstevel@tonic-gate 		nis_object		*o;
1349*0Sstevel@tonic-gate 
1350*0Sstevel@tonic-gate 		o = unmakePseudoEntryObj(e, tobj);
1351*0Sstevel@tonic-gate 		if (o == 0)
1352*0Sstevel@tonic-gate 			return (0);
1353*0Sstevel@tonic-gate 		rvt = addObjAttr2RuleValue(o, 0);
1354*0Sstevel@tonic-gate 		nis_destroy_object(o);
1355*0Sstevel@tonic-gate 		if (rvt == 0)
1356*0Sstevel@tonic-gate 			return (0);
1357*0Sstevel@tonic-gate 	}
1358*0Sstevel@tonic-gate 
1359*0Sstevel@tonic-gate 	qbuf = am(myself, sizeof (*qbuf));
1360*0Sstevel@tonic-gate 	/*
1361*0Sstevel@tonic-gate 	 * If there are no columns (other than the pseudo-entry object),
1362*0Sstevel@tonic-gate 	 * we're done.
1363*0Sstevel@tonic-gate 	 */
1364*0Sstevel@tonic-gate 	if (nc == 0)
1365*0Sstevel@tonic-gate 		return (qbuf);
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	qcbuf = am(myself, nc * sizeof (*qcbuf));
1368*0Sstevel@tonic-gate 	if (qcbuf == 0) {
1369*0Sstevel@tonic-gate 		sfree(qcbuf);
1370*0Sstevel@tonic-gate 		if (rvt != 0)
1371*0Sstevel@tonic-gate 			freeRuleValue(rvt, 1);
1372*0Sstevel@tonic-gate 		return (0);
1373*0Sstevel@tonic-gate 	}
1374*0Sstevel@tonic-gate 
1375*0Sstevel@tonic-gate 	/*
1376*0Sstevel@tonic-gate 	 * Build the db_query, remembering that e->en_cols.en_cols_val[0]
1377*0Sstevel@tonic-gate 	 * is the pseudo-nis_object.
1378*0Sstevel@tonic-gate 	 */
1379*0Sstevel@tonic-gate 	qbuf->components.components_val = qcbuf;
1380*0Sstevel@tonic-gate 	qbuf->components.components_len = nc;
1381*0Sstevel@tonic-gate 	for (i = 0; i < nc; i++) {
1382*0Sstevel@tonic-gate 		qcbuf[i].which_index = i;
1383*0Sstevel@tonic-gate 		qcbuf[i].index_value = buildItem(
1384*0Sstevel@tonic-gate 			e->en_cols.en_cols_val[i+1].ec_value.ec_value_len,
1385*0Sstevel@tonic-gate 			e->en_cols.en_cols_val[i+1].ec_value.ec_value_val);
1386*0Sstevel@tonic-gate 		if (qcbuf[i].index_value == 0) {
1387*0Sstevel@tonic-gate 			freeQuery(qbuf);
1388*0Sstevel@tonic-gate 			if (rvt != 0)
1389*0Sstevel@tonic-gate 				freeRuleValue(rvt, 1);
1390*0Sstevel@tonic-gate 			return (0);
1391*0Sstevel@tonic-gate 		}
1392*0Sstevel@tonic-gate 	}
1393*0Sstevel@tonic-gate 
1394*0Sstevel@tonic-gate 	if (rvt != 0) {
1395*0Sstevel@tonic-gate 		*rv = *rvt;
1396*0Sstevel@tonic-gate 		sfree(rvt);
1397*0Sstevel@tonic-gate 	}
1398*0Sstevel@tonic-gate 
1399*0Sstevel@tonic-gate 	return (qbuf);
1400*0Sstevel@tonic-gate }
1401*0Sstevel@tonic-gate 
1402*0Sstevel@tonic-gate /*
1403*0Sstevel@tonic-gate  * Given an input query 'q', and a db_query work buffer 'qbuf', return
1404*0Sstevel@tonic-gate  * a pointer to a query with one component corresponding to component
1405*0Sstevel@tonic-gate  * 'index' in 'q'.
1406*0Sstevel@tonic-gate  *
1407*0Sstevel@tonic-gate  * Note that no memory is allocated, and that the returned query has
1408*0Sstevel@tonic-gate  * pointers into 'q'.
1409*0Sstevel@tonic-gate  */
1410*0Sstevel@tonic-gate db_query *
1411*0Sstevel@tonic-gate queryFromComponent(db_query *q, int index, db_query *qbuf) {
1412*0Sstevel@tonic-gate 
1413*0Sstevel@tonic-gate 	if (q == 0 || index < 0 || index >= q->components.components_len ||
1414*0Sstevel@tonic-gate 			qbuf == 0)
1415*0Sstevel@tonic-gate 		return (0);
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 	qbuf->components.components_len = 1;
1418*0Sstevel@tonic-gate 	qbuf->components.components_val = &q->components.components_val[index];
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 	return (qbuf);
1421*0Sstevel@tonic-gate }
1422