10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*11262SRajagopal.Andra@Sun.COM * Common Development and Distribution License (the "License"). 6*11262SRajagopal.Andra@Sun.COM * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*11262SRajagopal.Andra@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate 270Sstevel@tonic-gate #include <strings.h> 280Sstevel@tonic-gate #include <string.h> 290Sstevel@tonic-gate #include <lber.h> 300Sstevel@tonic-gate #include <ldap.h> 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include "db_item_c.h" 330Sstevel@tonic-gate 340Sstevel@tonic-gate #include "nisdb_mt.h" 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include "ldap_util.h" 370Sstevel@tonic-gate #include "ldap_structs.h" 380Sstevel@tonic-gate #include "ldap_val.h" 390Sstevel@tonic-gate #include "ldap_ruleval.h" 400Sstevel@tonic-gate #include "ldap_op.h" 410Sstevel@tonic-gate #include "ldap_nisdbquery.h" 420Sstevel@tonic-gate #include "ldap_attr.h" 430Sstevel@tonic-gate #include "ldap_xdr.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate 460Sstevel@tonic-gate item * 470Sstevel@tonic-gate buildItem(int len, void *value) { 480Sstevel@tonic-gate char *myself = "buildItem"; 490Sstevel@tonic-gate item *i = am(myself, sizeof (*i)); 500Sstevel@tonic-gate int mlen = len; 510Sstevel@tonic-gate 520Sstevel@tonic-gate if (i == 0) 530Sstevel@tonic-gate return (0); 540Sstevel@tonic-gate 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * To this function, a NULL value, or a length less than or equal 570Sstevel@tonic-gate * zero means an item with no value. Hence, buildItem(0, 0) is 580Sstevel@tonic-gate * _not_ the right way to create index_value == 0 to indicate 590Sstevel@tonic-gate * deletion. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate if (value == 0 || len <= 0) { 620Sstevel@tonic-gate i->itemvalue.itemvalue_len = 0; 630Sstevel@tonic-gate i->itemvalue.itemvalue_val = 0; 640Sstevel@tonic-gate return (i); 650Sstevel@tonic-gate } 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * NIS+ usually stores the terminating NUL for strings, so we add 690Sstevel@tonic-gate * it here just in case. This means we usually waste a byte for 700Sstevel@tonic-gate * binary column values... 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate if (len > 0 && ((char *)value)[len-1] != '\0') 730Sstevel@tonic-gate mlen++; 740Sstevel@tonic-gate 750Sstevel@tonic-gate i->itemvalue.itemvalue_len = len; 760Sstevel@tonic-gate i->itemvalue.itemvalue_val = am(myself, mlen); 770Sstevel@tonic-gate if (mlen > 0 && i->itemvalue.itemvalue_val == 0) { 780Sstevel@tonic-gate free(i); 790Sstevel@tonic-gate return (0); 800Sstevel@tonic-gate } 810Sstevel@tonic-gate memcpy(i->itemvalue.itemvalue_val, value, len); 820Sstevel@tonic-gate 830Sstevel@tonic-gate return (i); 840Sstevel@tonic-gate } 850Sstevel@tonic-gate 860Sstevel@tonic-gate void 870Sstevel@tonic-gate freeItem(item *i) { 880Sstevel@tonic-gate if (i != 0) { 890Sstevel@tonic-gate sfree(i->itemvalue.itemvalue_val); 900Sstevel@tonic-gate free(i); 910Sstevel@tonic-gate } 920Sstevel@tonic-gate } 930Sstevel@tonic-gate 940Sstevel@tonic-gate void 950Sstevel@tonic-gate freeQcomp(db_qcomp *qc, int doFree) { 960Sstevel@tonic-gate 970Sstevel@tonic-gate if (qc == 0) 980Sstevel@tonic-gate return; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate freeItem(qc->index_value); 1010Sstevel@tonic-gate if (doFree) 1020Sstevel@tonic-gate free(qc); 1030Sstevel@tonic-gate } 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate db_query * 1060Sstevel@tonic-gate buildQuery(int num_components, db_qcomp *components) { 1070Sstevel@tonic-gate char *myself = "buildQuery"; 1080Sstevel@tonic-gate db_query *q = am(myself, sizeof (*q)); 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate if (q == 0) 1110Sstevel@tonic-gate return (0); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate q->components.components_len = num_components; 1140Sstevel@tonic-gate q->components.components_val = components; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate return (q); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * Clone a db_query. The 'numComps' parameter can be used to specify 1210Sstevel@tonic-gate * the number of db_qcomp's to allocate (in the 'components.components_val' 1220Sstevel@tonic-gate * array), if 'components.components_len' hasn't yet reached its expected 1230Sstevel@tonic-gate * maximum value. 1240Sstevel@tonic-gate */ 1250Sstevel@tonic-gate db_query * 1260Sstevel@tonic-gate cloneQuery(db_query *old, int numComps) { 1270Sstevel@tonic-gate db_query *new; 1280Sstevel@tonic-gate int i; 1290Sstevel@tonic-gate char *myself = "cloneQuery"; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate if (old == 0) 1320Sstevel@tonic-gate return (0); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate new = am(myself, sizeof (*new)); 1350Sstevel@tonic-gate if (new == 0) 1360Sstevel@tonic-gate return (0); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate if (old->components.components_len > numComps) 1390Sstevel@tonic-gate numComps = old->components.components_len; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate new->components.components_val = am(myself, 1420Sstevel@tonic-gate sizeof (new->components.components_val[0]) * 1430Sstevel@tonic-gate numComps); 1440Sstevel@tonic-gate if (numComps > 0 && new->components.components_val == 0) { 1450Sstevel@tonic-gate free(new); 1460Sstevel@tonic-gate return (0); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate for (i = 0; i < old->components.components_len; i++) { 1500Sstevel@tonic-gate item *it; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate if (old->components.components_val[i].index_value == 0) { 1530Sstevel@tonic-gate new->components.components_val[i].index_value = 0; 1540Sstevel@tonic-gate new->components.components_val[i].which_index = 1550Sstevel@tonic-gate old->components.components_val[i].which_index; 1560Sstevel@tonic-gate continue; 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate it = buildItem(old->components.components_val[i].index_value-> 1600Sstevel@tonic-gate itemvalue.itemvalue_len, 1610Sstevel@tonic-gate old->components.components_val[i].index_value-> 1620Sstevel@tonic-gate itemvalue.itemvalue_val); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate if (it == 0) { 1650Sstevel@tonic-gate new->components.components_len = i + 1; 1660Sstevel@tonic-gate freeQuery(new); 1670Sstevel@tonic-gate return (0); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate new->components.components_val[i].index_value = it; 1710Sstevel@tonic-gate new->components.components_val[i].which_index = 1720Sstevel@tonic-gate old->components.components_val[i].which_index; 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate new->components.components_len = old->components.components_len; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate return (new); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate void 1810Sstevel@tonic-gate freeQuery(db_query *q) { 1820Sstevel@tonic-gate int i; 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate if (q == 0) 1850Sstevel@tonic-gate return; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate for (i = 0; i < q->components.components_len; i++) { 1880Sstevel@tonic-gate freeItem(q->components.components_val[i].index_value); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate sfree(q->components.components_val); 1920Sstevel@tonic-gate sfree(q); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate void 1960Sstevel@tonic-gate freeQueries(db_query **q, int numQ) { 1970Sstevel@tonic-gate int i; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate if (q == 0) 2000Sstevel@tonic-gate return; 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate for (i = 0; i < numQ; i++) 2030Sstevel@tonic-gate freeQuery(q[i]); 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate sfree(q); 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * Given an array index[0..num-1] of pointers to strings of the form 2100Sstevel@tonic-gate * "name=value", create the corresponding db_queries. "name=" indicates 2110Sstevel@tonic-gate * deletion, which results in a db_query component where index_value == 0. 2120Sstevel@tonic-gate * 2130Sstevel@tonic-gate * The __nis_table_mapping_t structure is used to translate column 2140Sstevel@tonic-gate * names to indices. 2150Sstevel@tonic-gate * 2160Sstevel@tonic-gate * If 'rvP' is non-NULL, the searchable columns from the 'index' 2170Sstevel@tonic-gate * name/value pairs are used to retrieve copies of the corresponding NIS+ 2180Sstevel@tonic-gate * entries, and '*rvP' is initialized with the current entry values 2190Sstevel@tonic-gate * and object attributes. Names/values supplied in 'index' override 2200Sstevel@tonic-gate * those from existing NIS+ entries. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate db_query ** 2230Sstevel@tonic-gate createQuery(int num, char **index, __nis_table_mapping_t *t, 2240Sstevel@tonic-gate __nis_rule_value_t **rvP, int *numVals) { 2250Sstevel@tonic-gate db_query **q; 2260Sstevel@tonic-gate db_qcomp *qc; 2270Sstevel@tonic-gate int i, j, n, a, nv, niv, stat, sinum; 2280Sstevel@tonic-gate __nis_rule_value_t *rvq; 2290Sstevel@tonic-gate __nis_buffer_t b = {0, 0}; 2300Sstevel@tonic-gate char *table = 0; 2310Sstevel@tonic-gate char *myself = "createQuery"; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate rvq = initRuleValue(1, 0); 2340Sstevel@tonic-gate if (rvq == 0) 2350Sstevel@tonic-gate return (0); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (numVals == 0) 2380Sstevel@tonic-gate numVals = &nv; 2390Sstevel@tonic-gate *numVals = 0; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate if (rvP != 0) { 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Try to obtain a copy of the table object, in order to 2440Sstevel@tonic-gate * determine the searchable columns. A failure isn't 2450Sstevel@tonic-gate * necessarily fatal; we just try to compose the entire 2460Sstevel@tonic-gate * LDAP data from the col=val pairs. 2470Sstevel@tonic-gate */ 2480Sstevel@tonic-gate table = fullObjName(F, t->objName); 2490Sstevel@tonic-gate if (table == 0) { 2500Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 2510Sstevel@tonic-gate "%s: Error converting \"%s\" to FQ object name", 2520Sstevel@tonic-gate myself, NIL(t->objName)); 2530Sstevel@tonic-gate freeRuleValue(rvq, 1); 2540Sstevel@tonic-gate return (0); 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate /* Create a rule-value from the col=val pairs */ 2590Sstevel@tonic-gate for (n = 0; n < num; n++) { 2600Sstevel@tonic-gate char *name; 2610Sstevel@tonic-gate char *value; 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate if ((value = strchr(index[n], '=')) == 0) { 2640Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2650Sstevel@tonic-gate "%s: no '=' in \"%s\"", 2660Sstevel@tonic-gate myself, index[n]); 2670Sstevel@tonic-gate continue; 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate *value = '\0'; 2710Sstevel@tonic-gate value++; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate for (a = 0; a < t->numColumns; a++) { 2740Sstevel@tonic-gate if (strcmp(index[n], t->column[a]) == 0) { 2750Sstevel@tonic-gate int i, len = slen(value)+1; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate /* Add col=val pair to 'rvq' */ 2780Sstevel@tonic-gate if (addSCol2RuleValue(index[n], value, rvq)) { 2790Sstevel@tonic-gate freeRuleValue(rvq, 1); 2800Sstevel@tonic-gate sfree(table); 2810Sstevel@tonic-gate return (0); 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate break; 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate if (a >= t->numColumns) { 2880Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_WARNING, 2890Sstevel@tonic-gate "%s: Ignoring unknown column \"%s\"", 2900Sstevel@tonic-gate myself, NIL(index[n])); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate * Find out if any of the columns specified via the 'index' 2960Sstevel@tonic-gate * array are multi-valued. 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate for (n = 0, niv = 1; n < rvq->numColumns; n++) { 2990Sstevel@tonic-gate if (rvq->colVal[n].numVals > 1) 3000Sstevel@tonic-gate niv *= rvq->colVal[n].numVals; 3010Sstevel@tonic-gate } 3020Sstevel@tonic-gate 303*11262SRajagopal.Andra@Sun.COM *numVals = 1; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate sfree(b.buf); 3060Sstevel@tonic-gate sfree(table); 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (rvq->numColumns <= 0) { 3090Sstevel@tonic-gate freeRuleValue(rvq, *numVals); 3100Sstevel@tonic-gate *numVals = 0; 3110Sstevel@tonic-gate return (0); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * If any column name was repeated in the col=val pairs (but with 3160Sstevel@tonic-gate * different values), 'rvq' will have one or more multi-valued 3170Sstevel@tonic-gate * column values. We now convert those into an array of rule-values 3180Sstevel@tonic-gate * where every column is single-valued. 3190Sstevel@tonic-gate * 3200Sstevel@tonic-gate * Since we want all combinations of column values, the number 3210Sstevel@tonic-gate * of array elements is the product of all column value counts. 3220Sstevel@tonic-gate * 3230Sstevel@tonic-gate * There are four possible combinations of 'index' and NIS+ data: 3240Sstevel@tonic-gate * 3250Sstevel@tonic-gate * (1) Only single-valued 'index' columns, and at most one NIS+ 3260Sstevel@tonic-gate * entry, so 'rvq' is complete, and '*numVals' == 1. 3270Sstevel@tonic-gate * 3280Sstevel@tonic-gate * (2) Single-valued 'index' columns, but multiple NIS+ entries. 3290Sstevel@tonic-gate * '*numVals' reflects the number of NIS+ entries, and no 3300Sstevel@tonic-gate * expansion of 'index' column values to array elements is 3310Sstevel@tonic-gate * needed. 3320Sstevel@tonic-gate * 3330Sstevel@tonic-gate * (3) At least one multi-valued 'index', and multiple NIS+ 3340Sstevel@tonic-gate * entries. We already rejected the NIS+ data for this case 3350Sstevel@tonic-gate * above, so it is in fact equivalent to case (4). 3360Sstevel@tonic-gate * 3370Sstevel@tonic-gate * (4) At least one multi-valued 'index', but at most one NIS+ 3380Sstevel@tonic-gate * entry. This is the case where we must expand the multi-valued 3390Sstevel@tonic-gate * columns to multiple array elements. 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate if (niv > 1 && *numVals == 1) { 3420Sstevel@tonic-gate __nis_rule_value_t *rv; 3430Sstevel@tonic-gate int repeat; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * By using initRuleValue() to create 'rv', and make each 3470Sstevel@tonic-gate * element a clone of 'rvq', we save a lot of code. The 3480Sstevel@tonic-gate * down side is that 'rv' only really needs one element 3490Sstevel@tonic-gate * for each rv[].colVal[].val array, but we know that at 3500Sstevel@tonic-gate * least one rvq->colVal[].val array has more than one 3510Sstevel@tonic-gate * element. Hence, making 'rv' a clone of 'rvq' will waste 3520Sstevel@tonic-gate * memory. 3530Sstevel@tonic-gate * 3540Sstevel@tonic-gate * However, we believe this waste is acceptable, because 3550Sstevel@tonic-gate * we expect that 'niv' will be small. Also, we are executing 3560Sstevel@tonic-gate * in the context of a utility command, not in a daemon. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate rv = initRuleValue(niv, rvq); 3590Sstevel@tonic-gate if (rv == 0) { 3600Sstevel@tonic-gate freeRuleValue(rvq, 1); 3610Sstevel@tonic-gate *numVals = 0; 3620Sstevel@tonic-gate return (0); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * For each column value in 'rvq', copy to the appropriate 3670Sstevel@tonic-gate * place in 'rv', so that the end result is that all 3680Sstevel@tonic-gate * combinations of values are enumerated, and each 3690Sstevel@tonic-gate * 'rv[n].colVal[i]' is single-valued. 3700Sstevel@tonic-gate * 3710Sstevel@tonic-gate * We do this by traversing the rv[] array 'rvq->numColumns' 3720Sstevel@tonic-gate * times, where each traversal 'i' works on the values 3730Sstevel@tonic-gate * for rvq->colVal[i]. A repeat factor 'repeat' starts out 3740Sstevel@tonic-gate * at '1', and is multiplied by 'rvq->colVal[i].numVals' 3750Sstevel@tonic-gate * at the end of each traversal. Every value 3760Sstevel@tonic-gate * rvq->colVal[i].val[j] is repeated 'repeat' times. 3770Sstevel@tonic-gate * 3780Sstevel@tonic-gate * This algorithm works by regarding the rv[] array as 3790Sstevel@tonic-gate * an I-dimensional array (I = rvq->numColumns), where 3800Sstevel@tonic-gate * each dimension 'i' corresponds to the values for 3810Sstevel@tonic-gate * rvq->colVal[i]. The I-dimensional array is stored 3820Sstevel@tonic-gate * in column-major order. 3830Sstevel@tonic-gate * 3840Sstevel@tonic-gate * Since the 'rv' elements start out as copies of 'rvq', 3850Sstevel@tonic-gate * we achieve the "copy" of the 'rvq' column values by 3860Sstevel@tonic-gate * deleting those we don't want from the 'rv' elements. 3870Sstevel@tonic-gate */ 3880Sstevel@tonic-gate for (i = 0, repeat = 1; i < rvq->numColumns; i++) { 3890Sstevel@tonic-gate int r, k; 3900Sstevel@tonic-gate for (n = 0, j = 0, r = 0; n < niv; n++) { 3910Sstevel@tonic-gate /* 3920Sstevel@tonic-gate * Free all but element 'j' of the 3930Sstevel@tonic-gate * rv[n].colVal[i].val array. 3940Sstevel@tonic-gate */ 3950Sstevel@tonic-gate for (k = 0; k < rv[n].colVal[i].numVals; k++) { 3960Sstevel@tonic-gate /* Leave element 'j' in place */ 3970Sstevel@tonic-gate if (k == j) 3980Sstevel@tonic-gate continue; 3990Sstevel@tonic-gate sfree(rv[n].colVal[i].val[k]. 4000Sstevel@tonic-gate value); 4010Sstevel@tonic-gate } 4020Sstevel@tonic-gate rv[n].colVal[i].numVals = 1; 4030Sstevel@tonic-gate /* Move element 'j' to zero */ 4040Sstevel@tonic-gate if (j != 0) 4050Sstevel@tonic-gate rv[n].colVal[i].val[0] = 4060Sstevel@tonic-gate rv[n].colVal[i].val[j]; 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate /* 4090Sstevel@tonic-gate * Increment the repeat index 'r'. If >= 4100Sstevel@tonic-gate * 'repeat', reset 'r' and increment the 4110Sstevel@tonic-gate * value index 'j'. If 'j' >= 4120Sstevel@tonic-gate * rvq->colVal[i].numVals, start over on 4130Sstevel@tonic-gate * the column values for column 'i' (i.e., 4140Sstevel@tonic-gate * reset 'j' to zero). 4150Sstevel@tonic-gate */ 4160Sstevel@tonic-gate r += 1; 4170Sstevel@tonic-gate if (r >= repeat) { 4180Sstevel@tonic-gate r = 0; 4190Sstevel@tonic-gate j += 1; 4200Sstevel@tonic-gate if (j >= rvq->colVal[i].numVals) 4210Sstevel@tonic-gate j = 0; 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate repeat *= rvq->colVal[i].numVals; 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate *numVals = niv; 4280Sstevel@tonic-gate freeRuleValue(rvq, 1); 4290Sstevel@tonic-gate rvq = rv; 4300Sstevel@tonic-gate rv = 0; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate q = am(myself, *numVals * sizeof (q[0])); 4340Sstevel@tonic-gate if (q == 0) { 4350Sstevel@tonic-gate freeRuleValue(rvq, *numVals); 4360Sstevel@tonic-gate return (0); 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate /* 4400Sstevel@tonic-gate * Create queries from the rvq[] array. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate for (a = 0; a < *numVals; a++) { 4430Sstevel@tonic-gate int nn, err = 0; 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate qc = am(myself, rvq[a].numColumns * sizeof (*qc)); 4460Sstevel@tonic-gate if (qc != 0) { 4470Sstevel@tonic-gate for (nn = 0, i = 0; i < rvq[a].numColumns; i++) { 4480Sstevel@tonic-gate for (j = 0; j < t->numColumns; j++) { 4490Sstevel@tonic-gate if (strcmp(rvq[a].colName[i], 4500Sstevel@tonic-gate t->column[j]) == 0) { 4510Sstevel@tonic-gate break; 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate if (j >= t->numColumns) 4550Sstevel@tonic-gate continue; 4560Sstevel@tonic-gate qc[nn].which_index = j; 4570Sstevel@tonic-gate if (rvq[a].colVal[i].numVals > 0) { 4580Sstevel@tonic-gate qc[nn].index_value = buildItem( 4590Sstevel@tonic-gate rvq[a].colVal[i].val[0].length, 4600Sstevel@tonic-gate rvq[a].colVal[i].val[0].value); 4610Sstevel@tonic-gate if (qc[nn].index_value == 0) 4620Sstevel@tonic-gate err++; 4630Sstevel@tonic-gate } else { 4640Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 4650Sstevel@tonic-gate "%s: No values for [%d]%s", 4660Sstevel@tonic-gate myself, a, rvq[a].colName[i]); 4670Sstevel@tonic-gate err++; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate nn++; 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate if (err == 0) 4720Sstevel@tonic-gate q[a] = buildQuery(nn, qc); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate if (err > 0 || q[a] == 0) { 4750Sstevel@tonic-gate freeQueries(q, a); 4760Sstevel@tonic-gate for (a = 0; a < nn; a++) 4770Sstevel@tonic-gate freeQcomp(&qc[a], F); 4780Sstevel@tonic-gate sfree(qc); 4790Sstevel@tonic-gate freeRuleValue(rvq, *numVals); 4800Sstevel@tonic-gate return (0); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate if (rvP != 0) { 4850Sstevel@tonic-gate *rvP = rvq; 4860Sstevel@tonic-gate } else { 4870Sstevel@tonic-gate freeRuleValue(rvq, 1); 4880Sstevel@tonic-gate *numVals = 0; 4890Sstevel@tonic-gate } 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate return (q); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate 4940Sstevel@tonic-gate void 4950Sstevel@tonic-gate printQuery(db_query *q, __nis_table_mapping_t *t) { 4960Sstevel@tonic-gate int i, mc = -1; 4970Sstevel@tonic-gate char *myself = "printQuery"; 4980Sstevel@tonic-gate char *val[NIS_MAXCOLUMNS]; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate if (q == 0) 5010Sstevel@tonic-gate return; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate (void) memset(val, 0, sizeof (val)); 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate /* 5060Sstevel@tonic-gate * Collect the values, which may be out of order in 'q'. 5070Sstevel@tonic-gate * Remember the largest index. 5080Sstevel@tonic-gate */ 5090Sstevel@tonic-gate for (i = 0; i < q->components.components_len; i++) { 5100Sstevel@tonic-gate int ix = q->components.components_val[i].which_index; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate if (ix >= NIS_MAXCOLUMNS || 5130Sstevel@tonic-gate (t != 0 && ix >= t->numColumns)) 5140Sstevel@tonic-gate continue; 5150Sstevel@tonic-gate if (ix > mc) 5160Sstevel@tonic-gate mc = ix; 5170Sstevel@tonic-gate val[ix] = q->components.components_val[i].index_value-> 5180Sstevel@tonic-gate itemvalue.itemvalue_val; 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate /* Print the values we collected */ 5220Sstevel@tonic-gate for (i = 0; i <= mc; i++) { 5230Sstevel@tonic-gate p2buf(myself, "%s%s", (i != 0 ? " " : ""), 5240Sstevel@tonic-gate (val[i] != 0 ? val[i] : "")); 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate /* If we printed anything, add a newline */ 5270Sstevel@tonic-gate if (mc >= 0) 5280Sstevel@tonic-gate p2buf(myself, "\n"); 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate /* 5320Sstevel@tonic-gate * Verify that the db_query's 'q' and 'fq' match, in the sense that if 5330Sstevel@tonic-gate * they both have a value for a certain index, the values are the same. 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate int 5360Sstevel@tonic-gate verifyQueryMatch(db_query *q, db_query *fq) { 5370Sstevel@tonic-gate int i, j, match; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate if (fq == 0) 5400Sstevel@tonic-gate return (1); 5410Sstevel@tonic-gate 5420Sstevel@tonic-gate if (q == 0) 5430Sstevel@tonic-gate return ((fq == 0) ? 1 : 0); 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate for (i = 0, match = 1; match && i < q->components.components_len; 5460Sstevel@tonic-gate i++) { 5470Sstevel@tonic-gate for (j = 0; j < fq->components.components_len; j++) { 5480Sstevel@tonic-gate int len, flen; 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* Same index ? */ 5510Sstevel@tonic-gate if (q->components.components_val[i].which_index != 5520Sstevel@tonic-gate fq->components.components_val[j]. 5530Sstevel@tonic-gate which_index) 5540Sstevel@tonic-gate continue; 5550Sstevel@tonic-gate /* 5560Sstevel@tonic-gate * If one 'index_value' is NULL, the other one must 5570Sstevel@tonic-gate * be NULL as well. 5580Sstevel@tonic-gate */ 5590Sstevel@tonic-gate if (q->components.components_val[i].index_value == 0) { 5600Sstevel@tonic-gate if (fq->components.components_val[j]. 5610Sstevel@tonic-gate index_value == 0) 5620Sstevel@tonic-gate continue; 5630Sstevel@tonic-gate else { 5640Sstevel@tonic-gate match = 0; 5650Sstevel@tonic-gate break; 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate if (fq->components.components_val[j].index_value == 5690Sstevel@tonic-gate 0) { 5700Sstevel@tonic-gate match = 0; 5710Sstevel@tonic-gate break; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate /* Same value lengths ? */ 5740Sstevel@tonic-gate len = q->components.components_val[i].index_value-> 5750Sstevel@tonic-gate itemvalue.itemvalue_len; 5760Sstevel@tonic-gate flen = fq->components.components_val[j].index_value-> 5770Sstevel@tonic-gate itemvalue.itemvalue_len; 5780Sstevel@tonic-gate if (len != flen) { 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * There's a twist here: the input query 5810Sstevel@tonic-gate * may well _not_ count a concluding NUL 5820Sstevel@tonic-gate * in a string value, while the output 5830Sstevel@tonic-gate * usually will. So, if the difference in 5840Sstevel@tonic-gate * length is one, and the "extra" byte is 5850Sstevel@tonic-gate * a zero-valued one, we accept equality. 5860Sstevel@tonic-gate * 'q' is assumed to be the output, and 5870Sstevel@tonic-gate * 'fq' the input. 5880Sstevel@tonic-gate */ 5890Sstevel@tonic-gate if (!(len > 0 && len == (flen+1) && 5900Sstevel@tonic-gate q->components.components_val[i]. 5910Sstevel@tonic-gate index_value-> 5920Sstevel@tonic-gate itemvalue.itemvalue_val[len-1] == 0)) { 5930Sstevel@tonic-gate match = 0; 5940Sstevel@tonic-gate break; 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate /* Same value ? */ 5980Sstevel@tonic-gate if (memcmp(q->components.components_val[i].index_value-> 5990Sstevel@tonic-gate itemvalue.itemvalue_val, 6000Sstevel@tonic-gate fq->components.components_val[j].index_value-> 6010Sstevel@tonic-gate itemvalue.itemvalue_val, 6020Sstevel@tonic-gate flen) != 0) { 6030Sstevel@tonic-gate match = 0; 6040Sstevel@tonic-gate break; 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate } 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate return (match); 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate /* 6130Sstevel@tonic-gate * Remove those queries in 'q' that don't match t->index. 6140Sstevel@tonic-gate * Returns a pointer to the filtered array, which could be 6150Sstevel@tonic-gate * a compacted version of the original, or a new copy; in 6160Sstevel@tonic-gate * the latter case, the original will have been freed. 6170Sstevel@tonic-gate * 6180Sstevel@tonic-gate * Filtered/removed db_query's are freed. 6190Sstevel@tonic-gate */ 6200Sstevel@tonic-gate db_query ** 6210Sstevel@tonic-gate filterQuery(__nis_table_mapping_t *t, db_query **q, db_query *qin, 6220Sstevel@tonic-gate __nis_obj_attr_t ***objAttr, int *numQueries) { 6230Sstevel@tonic-gate db_query **new; 6240Sstevel@tonic-gate __nis_obj_attr_t **attr; 6250Sstevel@tonic-gate int i, nq, nn; 6260Sstevel@tonic-gate char *myself = "filterQuery"; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate if ((t == 0 && qin == 0) || q == 0 || 6290Sstevel@tonic-gate numQueries == 0 || *numQueries <= 0) 6300Sstevel@tonic-gate return (q); 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate nq = *numQueries; 6330Sstevel@tonic-gate new = am(myself, nq * sizeof (new[0])); 6340Sstevel@tonic-gate if (objAttr != 0) 6350Sstevel@tonic-gate attr = am(myself, nq * sizeof (attr[0])); 6360Sstevel@tonic-gate else 6370Sstevel@tonic-gate attr = 0; 6380Sstevel@tonic-gate if (new == 0 || (objAttr != 0 && attr == 0)) { 6390Sstevel@tonic-gate sfree(new); 6400Sstevel@tonic-gate freeQueries(q, nq); 6410Sstevel@tonic-gate sfree(attr); 6420Sstevel@tonic-gate if (objAttr != 0) { 6430Sstevel@tonic-gate freeObjAttr(*objAttr, nq); 6440Sstevel@tonic-gate *objAttr = 0; 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate *numQueries = -1; 6470Sstevel@tonic-gate return (0); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate for (i = 0, nn = 0; i < nq; i++) { 6510Sstevel@tonic-gate int retain = 1; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate if (t != 0) 6540Sstevel@tonic-gate retain = verifyIndexMatch(t, q[i], 0, 0, 0); 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate if (retain && qin != 0) 6570Sstevel@tonic-gate retain = verifyQueryMatch(q[i], qin); 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (retain) { 6600Sstevel@tonic-gate new[nn] = q[i]; 6610Sstevel@tonic-gate if (objAttr != 0) 6620Sstevel@tonic-gate attr[nn] = (*objAttr)[i]; 6630Sstevel@tonic-gate nn++; 6640Sstevel@tonic-gate } else { 6650Sstevel@tonic-gate freeQuery(q[i]); 6660Sstevel@tonic-gate q[i] = 0; 6670Sstevel@tonic-gate if (objAttr != 0) { 6680Sstevel@tonic-gate freeSingleObjAttr((*objAttr)[i]); 6690Sstevel@tonic-gate (*objAttr)[i] = 0; 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate } 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate /* All q[i]'s are either in 'new', or have been deleted */ 6750Sstevel@tonic-gate free(q); 6760Sstevel@tonic-gate if (objAttr != 0) { 6770Sstevel@tonic-gate sfree(*objAttr); 6780Sstevel@tonic-gate *objAttr = attr; 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate *numQueries = nn; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate return (new); 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate db_query ** 6870Sstevel@tonic-gate createNisPlusEntry(__nis_table_mapping_t *t, __nis_rule_value_t *rv, 6880Sstevel@tonic-gate db_query *qin, __nis_obj_attr_t ***objAttr, 6890Sstevel@tonic-gate int *numQueries) { 6900Sstevel@tonic-gate db_query **query = 0; 6910Sstevel@tonic-gate int r, i, j, ir; 6920Sstevel@tonic-gate __nis_value_t *rval, *lval; 6930Sstevel@tonic-gate __nis_mapping_item_t *litem; 6940Sstevel@tonic-gate int numItems; 6950Sstevel@tonic-gate int nq, iqc; 6960Sstevel@tonic-gate __nis_obj_attr_t **attr = 0; 6970Sstevel@tonic-gate char **dn = 0; 6980Sstevel@tonic-gate int numDN = 0; 6990Sstevel@tonic-gate char *myself = "createNisPlusEntry"; 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate if (t == 0 || t->objectDN == 0 || rv == 0) 7020Sstevel@tonic-gate return (0); 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate /* Establish default, per-thread, search base */ 7050Sstevel@tonic-gate __nisdb_get_tsd()->searchBase = t->objectDN->read.base; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate for (r = 0, nq = 0; r < t->numRulesFromLDAP; r++) { 7080Sstevel@tonic-gate int nrq, ntq, err; 7090Sstevel@tonic-gate db_query **newq; 7100Sstevel@tonic-gate __nis_obj_attr_t **newattr; 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate rval = buildRvalue(&t->ruleFromLDAP[r]->rhs, 7130Sstevel@tonic-gate mit_ldap, rv, NULL); 7140Sstevel@tonic-gate if (rval == 0) 7150Sstevel@tonic-gate continue; 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate litem = buildLvalue(&t->ruleFromLDAP[r]->lhs, &rval, 7180Sstevel@tonic-gate &numItems); 7190Sstevel@tonic-gate if (litem == 0) { 7200Sstevel@tonic-gate freeValue(rval, 1); 7210Sstevel@tonic-gate /* XXX Should this be a fatal error ? */ 7220Sstevel@tonic-gate continue; 7230Sstevel@tonic-gate } 7240Sstevel@tonic-gate 7250Sstevel@tonic-gate lval = 0; 7260Sstevel@tonic-gate for (i = 0; i < numItems; i++) { 7270Sstevel@tonic-gate __nis_value_t *tmpval, *old; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate tmpval = getMappingItem(&litem[i], 7300Sstevel@tonic-gate mit_nisplus, 0, 0, NULL); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * If the LHS specifies an out-of-context LDAP or 7340Sstevel@tonic-gate * NIS+ item, we do the update right here. We 7350Sstevel@tonic-gate * don't add any values to 'lval'; instead, we 7360Sstevel@tonic-gate * skip to the next item. (However, we still 7370Sstevel@tonic-gate * get a string representation of the LHS in case 7380Sstevel@tonic-gate * we need to report an error.) 7390Sstevel@tonic-gate */ 740*11262SRajagopal.Andra@Sun.COM if (litem[i].type == mit_ldap) { 7410Sstevel@tonic-gate int stat; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate if (dn == 0) 7440Sstevel@tonic-gate dn = findDNs(myself, rv, 1, 7450Sstevel@tonic-gate t->objectDN->write.base, 7460Sstevel@tonic-gate &numDN); 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate stat = storeLDAP(&litem[i], i, numItems, rval, 7490Sstevel@tonic-gate t->objectDN, dn, numDN); 7500Sstevel@tonic-gate if (stat != LDAP_SUCCESS) { 7510Sstevel@tonic-gate char *iname = "<unknown>"; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate if (tmpval != 0 && 7540Sstevel@tonic-gate tmpval->numVals == 1) 7550Sstevel@tonic-gate iname = tmpval->val[0].value; 7560Sstevel@tonic-gate logmsg(MSG_NOTIMECHECK, LOG_ERR, 7570Sstevel@tonic-gate "%s: LDAP store \"%s\": %s", 7580Sstevel@tonic-gate myself, iname, 7590Sstevel@tonic-gate ldap_err2string(stat)); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate freeValue(tmpval, 1); 7630Sstevel@tonic-gate continue; 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate 7660Sstevel@tonic-gate old = lval; 7670Sstevel@tonic-gate lval = concatenateValues(old, tmpval); 7680Sstevel@tonic-gate freeValue(tmpval, 1); 7690Sstevel@tonic-gate freeValue(old, 1); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate freeMappingItem(litem, numItems); 7730Sstevel@tonic-gate if (lval == 0 || lval->numVals <= 0 || rval->numVals <= 0) { 7740Sstevel@tonic-gate freeValue(lval, 1); 7750Sstevel@tonic-gate freeValue(rval, 1); 7760Sstevel@tonic-gate continue; 7770Sstevel@tonic-gate } 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate /* 7800Sstevel@tonic-gate * We now have a number of possible cases. The notation 7810Sstevel@tonic-gate * used in the table is: 7820Sstevel@tonic-gate * 7830Sstevel@tonic-gate * single A single value (numVals == 1) 7840Sstevel@tonic-gate * single/rep A single value with repeat == 1 7850Sstevel@tonic-gate * multi[N] N values 7860Sstevel@tonic-gate * multi[N]/rep M values with repeat == 1 7870Sstevel@tonic-gate * (M) M resulting db_query's 7880Sstevel@tonic-gate * 7890Sstevel@tonic-gate * lval \ rval single single/rep multi[N] multi[N]/rep 7900Sstevel@tonic-gate * single (1) (1) (1) (1) 7910Sstevel@tonic-gate * single/rep (1) (1) (N) (N) 7920Sstevel@tonic-gate * multi[M] (1) (1) (1) 1+(N-1)/M 7930Sstevel@tonic-gate * multi[M]/rep (1) (1) (1) 1+(N-1)/M 7940Sstevel@tonic-gate * 7950Sstevel@tonic-gate * Of course, we already have 'nq' db_query's from previous 7960Sstevel@tonic-gate * rules, so the resulting number of queries is max(1,nq) 7970Sstevel@tonic-gate * times the numbers in the table above. 7980Sstevel@tonic-gate */ 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* The number of queries resulting from the current rule */ 8010Sstevel@tonic-gate if (rval->numVals > 1) { 8020Sstevel@tonic-gate if (lval->numVals == 1 && lval->repeat) 8030Sstevel@tonic-gate nrq = rval->numVals; 8040Sstevel@tonic-gate else if (lval->numVals > 1 && rval->repeat) 8050Sstevel@tonic-gate nrq = 1 + ((rval->numVals-1)/lval->numVals); 8060Sstevel@tonic-gate else 8070Sstevel@tonic-gate nrq = 1; 8080Sstevel@tonic-gate } else { 8090Sstevel@tonic-gate nrq = 1; 8100Sstevel@tonic-gate } 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate /* Total number of queries after adding the current rule */ 8130Sstevel@tonic-gate if (nq <= 0) 8140Sstevel@tonic-gate ntq = nrq; 8150Sstevel@tonic-gate else 8160Sstevel@tonic-gate ntq = nq * nrq; 8170Sstevel@tonic-gate 8180Sstevel@tonic-gate if (ntq > nq) { 8190Sstevel@tonic-gate newq = realloc(query, ntq * sizeof (query[0])); 8200Sstevel@tonic-gate newattr = realloc(attr, ntq * sizeof (attr[0])); 8210Sstevel@tonic-gate if (newq == 0 || newattr == 0) { 8220Sstevel@tonic-gate logmsg(MSG_NOMEM, LOG_ERR, 8230Sstevel@tonic-gate "%s: realloc(%d) => NULL", 8240Sstevel@tonic-gate myself, ntq * sizeof (query[0])); 8250Sstevel@tonic-gate freeValue(lval, 1); 8260Sstevel@tonic-gate freeValue(rval, 1); 8270Sstevel@tonic-gate freeQueries(query, nq); 8280Sstevel@tonic-gate freeObjAttr(attr, nq); 8290Sstevel@tonic-gate sfree(newq); 8300Sstevel@tonic-gate freeDNs(dn, numDN); 8310Sstevel@tonic-gate return (0); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate query = newq; 8340Sstevel@tonic-gate attr = newattr; 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate /* 8380Sstevel@tonic-gate * Copy/clone the existing queries to the new array, 8390Sstevel@tonic-gate * remembering that realloc() has done the first 'nq' 8400Sstevel@tonic-gate * ones. 8410Sstevel@tonic-gate * 8420Sstevel@tonic-gate * If there's an error (probably memory allocation), we 8430Sstevel@tonic-gate * still go through the rest of the array, so that it's 8440Sstevel@tonic-gate * simple to free the elements when we clean up. 8450Sstevel@tonic-gate */ 8460Sstevel@tonic-gate for (i = 1, err = 0; i < nrq; i++) { 8470Sstevel@tonic-gate for (j = 0; j < nq; j++) { 8480Sstevel@tonic-gate query[(nq*i)+j] = cloneQuery(query[j], 8490Sstevel@tonic-gate t->numColumns); 8500Sstevel@tonic-gate if (query[(nq*i)+j] == 0 && 8510Sstevel@tonic-gate query[j] != 0) 8520Sstevel@tonic-gate err++; 8530Sstevel@tonic-gate attr[(nq*i)+j] = cloneObjAttr(attr[j]); 8540Sstevel@tonic-gate if (attr[(nq*i)+j] == 0 && 8550Sstevel@tonic-gate attr[j] != 0) 8560Sstevel@tonic-gate err++; 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate } 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate if (err > 0) { 8610Sstevel@tonic-gate freeValue(lval, 1); 8620Sstevel@tonic-gate freeValue(rval, 1); 8630Sstevel@tonic-gate freeQueries(query, ntq); 8640Sstevel@tonic-gate freeObjAttr(attr, ntq); 8650Sstevel@tonic-gate freeDNs(dn, numDN); 8660Sstevel@tonic-gate return (0); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate /* 8700Sstevel@tonic-gate * Special case if nq == 0 (i.e., the first time we 8710Sstevel@tonic-gate * allocated db_query's). If so, we now allocate empty 8720Sstevel@tonic-gate * db_qcomp arrays, which simplifies subsequent 8730Sstevel@tonic-gate * copying of values. 8740Sstevel@tonic-gate */ 8750Sstevel@tonic-gate if (nq <= 0) { 8760Sstevel@tonic-gate (void) memset(query, 0, ntq * sizeof (query[0])); 8770Sstevel@tonic-gate (void) memset(attr, 0, ntq * sizeof (attr[0])); 8780Sstevel@tonic-gate for (i = 0, err = 0; i < ntq; i++) { 8790Sstevel@tonic-gate query[i] = am(myself, sizeof (*query[i])); 8800Sstevel@tonic-gate if (query[i] == 0) { 8810Sstevel@tonic-gate err++; 8820Sstevel@tonic-gate break; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate query[i]->components.components_val = 8850Sstevel@tonic-gate am(myself, t->numColumns * 8860Sstevel@tonic-gate sizeof (query[i]->components.components_val[0])); 8870Sstevel@tonic-gate if (query[i]->components.components_val == 0) { 8880Sstevel@tonic-gate err++; 8890Sstevel@tonic-gate break; 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate query[i]->components.components_len = 0; 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate if (err > 0) { 8940Sstevel@tonic-gate freeValue(lval, 1); 8950Sstevel@tonic-gate freeValue(rval, 1); 8960Sstevel@tonic-gate freeQueries(query, ntq); 8970Sstevel@tonic-gate freeObjAttr(attr, ntq); 8980Sstevel@tonic-gate freeDNs(dn, numDN); 8990Sstevel@tonic-gate return (0); 9000Sstevel@tonic-gate } 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate /* Now we're ready to add the new values */ 9040Sstevel@tonic-gate for (i = 0, ir = 0; i < lval->numVals; i++) { 9050Sstevel@tonic-gate char *oaName = 0; 9060Sstevel@tonic-gate int index; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* Find column index */ 9090Sstevel@tonic-gate for (index = 0; index < t->numColumns; 9100Sstevel@tonic-gate index++) { 9110Sstevel@tonic-gate if (strncmp(t->column[index], 9120Sstevel@tonic-gate lval->val[i].value, 9130Sstevel@tonic-gate lval->val[i].length) == 0) 9140Sstevel@tonic-gate break; 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate if (index >= t->numColumns) { 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * Could be one of the special object 9190Sstevel@tonic-gate * attributes. 9200Sstevel@tonic-gate */ 9210Sstevel@tonic-gate oaName = isObjAttr(&lval->val[i]); 9220Sstevel@tonic-gate if (oaName == 0) 9230Sstevel@tonic-gate continue; 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate for (j = i*nrq; j < (i+1)*nrq; j++) { 9270Sstevel@tonic-gate int k; 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate /* If we're out of values, repeat last one */ 9300Sstevel@tonic-gate ir = (j < rval->numVals) ? 9310Sstevel@tonic-gate j : rval->numVals - 1; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate /* 9340Sstevel@tonic-gate * Step through the query array, adding 9350Sstevel@tonic-gate * the new value every 'nrq' queries, and 9360Sstevel@tonic-gate * starting at 'query[j % nrq]'. 9370Sstevel@tonic-gate */ 9380Sstevel@tonic-gate for (k = j % nrq, err = 0; k < ntq; k += nrq) { 9390Sstevel@tonic-gate int ic, c; 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate if (oaName != 0) { 9420Sstevel@tonic-gate int fail = setObjAttrField( 9430Sstevel@tonic-gate oaName, 9440Sstevel@tonic-gate &rval->val[ir], 9450Sstevel@tonic-gate &attr[k]); 9460Sstevel@tonic-gate if (fail) { 9470Sstevel@tonic-gate err++; 9480Sstevel@tonic-gate break; 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate continue; 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate ic = query[k]->components. 9540Sstevel@tonic-gate components_len; 9550Sstevel@tonic-gate /* 9560Sstevel@tonic-gate * If we've already filled this 9570Sstevel@tonic-gate * query, the new value is a dup 9580Sstevel@tonic-gate * which we'll ignore. 9590Sstevel@tonic-gate */ 9600Sstevel@tonic-gate if (ic >= t->numColumns) 9610Sstevel@tonic-gate continue; 9620Sstevel@tonic-gate 9630Sstevel@tonic-gate /* 9640Sstevel@tonic-gate * Do we already have a value for 9650Sstevel@tonic-gate * this 'index' ? 9660Sstevel@tonic-gate */ 9670Sstevel@tonic-gate for (c = 0; c < ic; c++) { 9680Sstevel@tonic-gate if (query[k]->components. 9690Sstevel@tonic-gate components_val[c]. 9700Sstevel@tonic-gate which_index == index) 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate /* If no previous value, add it */ 9750Sstevel@tonic-gate if (c >= ic) { 9760Sstevel@tonic-gate int l; 9770Sstevel@tonic-gate char *v; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate query[k]->components. 9800Sstevel@tonic-gate components_val[ic]. 9810Sstevel@tonic-gate which_index = index; 9820Sstevel@tonic-gate l = rval->val[ir].length; 9830Sstevel@tonic-gate v = rval->val[ir].value; 9840Sstevel@tonic-gate if (rval->type == vt_string && 9850Sstevel@tonic-gate l > 0 && 9860Sstevel@tonic-gate v[l-1] != '\0' && 9870Sstevel@tonic-gate v[l] == '\0') 9880Sstevel@tonic-gate l++; 9890Sstevel@tonic-gate query[k]->components. 9900Sstevel@tonic-gate components_val[ic]. 9910Sstevel@tonic-gate index_value = 9920Sstevel@tonic-gate buildItem(l, v); 9930Sstevel@tonic-gate if (query[k]-> 9940Sstevel@tonic-gate components. 9950Sstevel@tonic-gate components_val[ic]. 9960Sstevel@tonic-gate index_value == 0) { 9970Sstevel@tonic-gate err++; 9980Sstevel@tonic-gate break; 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate query[k]->components. 10010Sstevel@tonic-gate components_len++; 10020Sstevel@tonic-gate } 10030Sstevel@tonic-gate } 10040Sstevel@tonic-gate if (err > 0) { 10050Sstevel@tonic-gate freeValue(lval, 1); 10060Sstevel@tonic-gate freeValue(rval, 1); 10070Sstevel@tonic-gate freeQueries(query, ntq); 10080Sstevel@tonic-gate freeObjAttr(attr, ntq); 10090Sstevel@tonic-gate freeDNs(dn, numDN); 10100Sstevel@tonic-gate return (0); 10110Sstevel@tonic-gate } 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate freeValue(lval, 1); 10150Sstevel@tonic-gate freeValue(rval, 1); 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate nq = ntq; 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate 10200Sstevel@tonic-gate freeDNs(dn, numDN); 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate if (nq <= 0) { 10230Sstevel@tonic-gate sfree(query); 10240Sstevel@tonic-gate query = 0; 10250Sstevel@tonic-gate } 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate /* Should we filter on index or input query ? */ 10280Sstevel@tonic-gate if (query != 0) { 10290Sstevel@tonic-gate if (t->index.numIndexes > 0) 10300Sstevel@tonic-gate query = filterQuery(t, query, qin, &attr, &nq); 10310Sstevel@tonic-gate else if (qin != 0) 10320Sstevel@tonic-gate query = filterQuery(0, query, qin, &attr, &nq); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (query != 0 && numQueries != 0) 10360Sstevel@tonic-gate *numQueries = nq; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate if (objAttr != 0) 10390Sstevel@tonic-gate *objAttr = attr; 10400Sstevel@tonic-gate else 10410Sstevel@tonic-gate freeObjAttr(attr, nq); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate return (query); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate /* 10460Sstevel@tonic-gate * Given a table mapping and a rule-value, convert to an array of 10470Sstevel@tonic-gate * (db_query *), using the fromLDAP ruleset. 10480Sstevel@tonic-gate * 10490Sstevel@tonic-gate * On entry, '*numQueries' holds the number of elements in the 'rv' 10500Sstevel@tonic-gate * array. On exit, it holds the number of (db_query *)'s in the return 10510Sstevel@tonic-gate * value array. 10520Sstevel@tonic-gate */ 10530Sstevel@tonic-gate db_query ** 10540Sstevel@tonic-gate ruleValue2Query(__nis_table_mapping_t *t, __nis_rule_value_t *rv, 10550Sstevel@tonic-gate db_query *qin, __nis_obj_attr_t ***objAttr, int *numQueries) { 10560Sstevel@tonic-gate db_query **q = 0, ***qp = 0; 10570Sstevel@tonic-gate int i, nqp, nq, *nnp = 0, nv; 10580Sstevel@tonic-gate __nis_obj_attr_t **attr = 0, ***atp = 0; 10590Sstevel@tonic-gate char *myself = "ruleValue2Query"; 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate if (t == 0 || rv == 0 || numQueries == 0) 10630Sstevel@tonic-gate return (0); 10640Sstevel@tonic-gate 10650Sstevel@tonic-gate nv = *numQueries; 10660Sstevel@tonic-gate if (nv <= 0) 10670Sstevel@tonic-gate return (0); 10680Sstevel@tonic-gate 10690Sstevel@tonic-gate /* 10700Sstevel@tonic-gate * 'qp' is an array of (db_query **), and we get one element for 10710Sstevel@tonic-gate * each call to createNisPlusEntry(); i.e., one for each rule-value. 10720Sstevel@tonic-gate * 10730Sstevel@tonic-gate * 'nnp[i]' is the count of (db_query *) in each 'qp[i]'. 10740Sstevel@tonic-gate */ 10750Sstevel@tonic-gate qp = am(myself, nv * sizeof (*qp)); 10760Sstevel@tonic-gate nnp = am(myself, nv * sizeof (*nnp)); 10770Sstevel@tonic-gate atp = am(myself, nv * sizeof (*atp)); 10780Sstevel@tonic-gate if (qp == 0 || nnp == 0 || atp == 0) { 10790Sstevel@tonic-gate sfree(qp); 10800Sstevel@tonic-gate sfree(nnp); 10810Sstevel@tonic-gate sfree(atp); 10820Sstevel@tonic-gate return (0); 10830Sstevel@tonic-gate } 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate for (i = 0, nq = 0, nqp = 0; i < nv; i++) { 10860Sstevel@tonic-gate qp[nqp] = createNisPlusEntry(t, &rv[i], qin, &atp[nqp], 10870Sstevel@tonic-gate &nnp[nqp]); 10880Sstevel@tonic-gate /* If we fail, abort (XXX??? or continue ???) */ 10890Sstevel@tonic-gate if (qp[nqp] == 0) 10900Sstevel@tonic-gate goto cleanup; 10910Sstevel@tonic-gate nq += nnp[nqp]; 10920Sstevel@tonic-gate nqp++; 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* If we didn't get any (db_query **)'s, return failure */ 10960Sstevel@tonic-gate if (nqp == 0 || nq <= 0) 10970Sstevel@tonic-gate goto cleanup; 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate q = am(myself, nq * sizeof (q[0])); 11000Sstevel@tonic-gate attr = am(myself, nq * sizeof (attr[0])); 11010Sstevel@tonic-gate if (q == 0 || attr == 0) { 11020Sstevel@tonic-gate nq = 0; 11030Sstevel@tonic-gate goto cleanup; 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* Convert 'qp' to an array of (db_query *)'s */ 11070Sstevel@tonic-gate for (i = 0, nq = 0; i < nqp; i++) { 11080Sstevel@tonic-gate (void) memcpy(&q[nq], qp[i], nnp[i] * sizeof (qp[i][0])); 11090Sstevel@tonic-gate (void) memcpy(&attr[nq], atp[i], nnp[i] * sizeof (atp[i][0])); 11100Sstevel@tonic-gate nq += nnp[i]; 11110Sstevel@tonic-gate free(qp[i]); 11120Sstevel@tonic-gate free(atp[i]); 11130Sstevel@tonic-gate } 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate *numQueries = nq; 11160Sstevel@tonic-gate if (objAttr != 0) 11170Sstevel@tonic-gate *objAttr = attr; 11180Sstevel@tonic-gate else 11190Sstevel@tonic-gate freeObjAttr(attr, nq); 11200Sstevel@tonic-gate 11210Sstevel@tonic-gate /* Make sure 'cleanup' doesn't free the db_query pointers */ 11220Sstevel@tonic-gate nqp = 0; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate cleanup: 11250Sstevel@tonic-gate for (i = 0; i < nqp; i++) { 11260Sstevel@tonic-gate freeQueries(qp[i], nnp[i]); 11270Sstevel@tonic-gate sfree(atp[i]); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate sfree(qp); 11300Sstevel@tonic-gate sfree(nnp); 11310Sstevel@tonic-gate sfree(atp); 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate return (q); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate db_query * 11370Sstevel@tonic-gate pseudoEntryObj2Query(entry_obj *e, nis_object *tobj, __nis_rule_value_t *rv) { 11380Sstevel@tonic-gate db_query *qbuf; 11390Sstevel@tonic-gate db_qcomp *qcbuf; 11400Sstevel@tonic-gate int nc, i; 11410Sstevel@tonic-gate __nis_rule_value_t *rvt = 0; 11420Sstevel@tonic-gate char *myself = "pseudoEntryObj2Query"; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate nc = e->en_cols.en_cols_len - 1; 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate if (e == 0 || nc < 0 || nc > NIS_MAXCOLUMNS) 11470Sstevel@tonic-gate return (0); 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* 11500Sstevel@tonic-gate * If 'rvP' is non-NULL, build a rule value from the pseudo- 11510Sstevel@tonic-gate * nis_object in e->en_cols.en_cols_val[0]. 11520Sstevel@tonic-gate */ 11530Sstevel@tonic-gate if (rv != 0) { 11540Sstevel@tonic-gate nis_object *o; 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate o = unmakePseudoEntryObj(e, tobj); 11570Sstevel@tonic-gate if (o == 0) 11580Sstevel@tonic-gate return (0); 11590Sstevel@tonic-gate rvt = addObjAttr2RuleValue(o, 0); 11600Sstevel@tonic-gate nis_destroy_object(o); 11610Sstevel@tonic-gate if (rvt == 0) 11620Sstevel@tonic-gate return (0); 11630Sstevel@tonic-gate } 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate qbuf = am(myself, sizeof (*qbuf)); 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * If there are no columns (other than the pseudo-entry object), 11680Sstevel@tonic-gate * we're done. 11690Sstevel@tonic-gate */ 11700Sstevel@tonic-gate if (nc == 0) 11710Sstevel@tonic-gate return (qbuf); 11720Sstevel@tonic-gate 11730Sstevel@tonic-gate qcbuf = am(myself, nc * sizeof (*qcbuf)); 11740Sstevel@tonic-gate if (qcbuf == 0) { 11750Sstevel@tonic-gate sfree(qcbuf); 11760Sstevel@tonic-gate if (rvt != 0) 11770Sstevel@tonic-gate freeRuleValue(rvt, 1); 11780Sstevel@tonic-gate return (0); 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate /* 11820Sstevel@tonic-gate * Build the db_query, remembering that e->en_cols.en_cols_val[0] 11830Sstevel@tonic-gate * is the pseudo-nis_object. 11840Sstevel@tonic-gate */ 11850Sstevel@tonic-gate qbuf->components.components_val = qcbuf; 11860Sstevel@tonic-gate qbuf->components.components_len = nc; 11870Sstevel@tonic-gate for (i = 0; i < nc; i++) { 11880Sstevel@tonic-gate qcbuf[i].which_index = i; 11890Sstevel@tonic-gate qcbuf[i].index_value = buildItem( 11900Sstevel@tonic-gate e->en_cols.en_cols_val[i+1].ec_value.ec_value_len, 11910Sstevel@tonic-gate e->en_cols.en_cols_val[i+1].ec_value.ec_value_val); 11920Sstevel@tonic-gate if (qcbuf[i].index_value == 0) { 11930Sstevel@tonic-gate freeQuery(qbuf); 11940Sstevel@tonic-gate if (rvt != 0) 11950Sstevel@tonic-gate freeRuleValue(rvt, 1); 11960Sstevel@tonic-gate return (0); 11970Sstevel@tonic-gate } 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate 12000Sstevel@tonic-gate if (rvt != 0) { 12010Sstevel@tonic-gate *rv = *rvt; 12020Sstevel@tonic-gate sfree(rvt); 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate return (qbuf); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate 12080Sstevel@tonic-gate /* 12090Sstevel@tonic-gate * Given an input query 'q', and a db_query work buffer 'qbuf', return 12100Sstevel@tonic-gate * a pointer to a query with one component corresponding to component 12110Sstevel@tonic-gate * 'index' in 'q'. 12120Sstevel@tonic-gate * 12130Sstevel@tonic-gate * Note that no memory is allocated, and that the returned query has 12140Sstevel@tonic-gate * pointers into 'q'. 12150Sstevel@tonic-gate */ 12160Sstevel@tonic-gate db_query * 12170Sstevel@tonic-gate queryFromComponent(db_query *q, int index, db_query *qbuf) { 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate if (q == 0 || index < 0 || index >= q->components.components_len || 12200Sstevel@tonic-gate qbuf == 0) 12210Sstevel@tonic-gate return (0); 12220Sstevel@tonic-gate 12230Sstevel@tonic-gate qbuf->components.components_len = 1; 12240Sstevel@tonic-gate qbuf->components.components_val = &q->components.components_val[index]; 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate return (qbuf); 12270Sstevel@tonic-gate } 1228