7910 l2arc_write_buffers() may write beyond target_sz
[unleashed.git] / usr / src / lib / libnisdb / ldap_nisdbquery.c
blob2688d9200e714516634be0701a80207361d3485b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2015 Gary Mills
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <strings.h>
29 #include <string.h>
30 #include <lber.h>
31 #include <ldap.h>
33 #include "db_item_c.h"
35 #include "nisdb_mt.h"
37 #include "ldap_util.h"
38 #include "ldap_structs.h"
39 #include "ldap_val.h"
40 #include "ldap_ruleval.h"
41 #include "ldap_op.h"
42 #include "ldap_nisdbquery.h"
43 #include "ldap_attr.h"
44 #include "ldap_xdr.h"
45 #include "ldap_ldap.h"
48 item *
49 buildItem(int len, void *value) {
50 char *myself = "buildItem";
51 item *i = am(myself, sizeof (*i));
52 int mlen = len;
54 if (i == 0)
55 return (0);
58 * To this function, a NULL value, or a length less than or equal
59 * zero means an item with no value. Hence, buildItem(0, 0) is
60 * _not_ the right way to create index_value == 0 to indicate
61 * deletion.
63 if (value == 0 || len <= 0) {
64 i->itemvalue.itemvalue_len = 0;
65 i->itemvalue.itemvalue_val = 0;
66 return (i);
70 * NIS+ usually stores the terminating NUL for strings, so we add
71 * it here just in case. This means we usually waste a byte for
72 * binary column values...
74 if (len > 0 && ((char *)value)[len-1] != '\0')
75 mlen++;
77 i->itemvalue.itemvalue_len = len;
78 i->itemvalue.itemvalue_val = am(myself, mlen);
79 if (mlen > 0 && i->itemvalue.itemvalue_val == 0) {
80 free(i);
81 return (0);
83 memcpy(i->itemvalue.itemvalue_val, value, len);
85 return (i);
88 void
89 freeItem(item *i) {
90 if (i != 0) {
91 sfree(i->itemvalue.itemvalue_val);
92 free(i);
96 void
97 freeQcomp(db_qcomp *qc, int doFree) {
99 if (qc == 0)
100 return;
102 freeItem(qc->index_value);
103 if (doFree)
104 free(qc);
107 db_query *
108 buildQuery(int num_components, db_qcomp *components) {
109 char *myself = "buildQuery";
110 db_query *q = am(myself, sizeof (*q));
112 if (q == 0)
113 return (0);
115 q->components.components_len = num_components;
116 q->components.components_val = components;
118 return (q);
122 * Clone a db_query. The 'numComps' parameter can be used to specify
123 * the number of db_qcomp's to allocate (in the 'components.components_val'
124 * array), if 'components.components_len' hasn't yet reached its expected
125 * maximum value.
127 db_query *
128 cloneQuery(db_query *old, int numComps) {
129 db_query *new;
130 int i;
131 char *myself = "cloneQuery";
133 if (old == 0)
134 return (0);
136 new = am(myself, sizeof (*new));
137 if (new == 0)
138 return (0);
140 if (old->components.components_len > numComps)
141 numComps = old->components.components_len;
143 new->components.components_val = am(myself,
144 sizeof (new->components.components_val[0]) *
145 numComps);
146 if (numComps > 0 && new->components.components_val == 0) {
147 free(new);
148 return (0);
151 for (i = 0; i < old->components.components_len; i++) {
152 item *it;
154 if (old->components.components_val[i].index_value == 0) {
155 new->components.components_val[i].index_value = 0;
156 new->components.components_val[i].which_index =
157 old->components.components_val[i].which_index;
158 continue;
161 it = buildItem(old->components.components_val[i].index_value->
162 itemvalue.itemvalue_len,
163 old->components.components_val[i].index_value->
164 itemvalue.itemvalue_val);
166 if (it == 0) {
167 new->components.components_len = i + 1;
168 freeQuery(new);
169 return (0);
172 new->components.components_val[i].index_value = it;
173 new->components.components_val[i].which_index =
174 old->components.components_val[i].which_index;
177 new->components.components_len = old->components.components_len;
179 return (new);
182 void
183 freeQuery(db_query *q) {
184 int i;
186 if (q == 0)
187 return;
189 for (i = 0; i < q->components.components_len; i++) {
190 freeItem(q->components.components_val[i].index_value);
193 sfree(q->components.components_val);
194 sfree(q);
197 void
198 freeQueries(db_query **q, int numQ) {
199 int i;
201 if (q == 0)
202 return;
204 for (i = 0; i < numQ; i++)
205 freeQuery(q[i]);
207 sfree(q);
211 * Given an array index[0..num-1] of pointers to strings of the form
212 * "name=value", create the corresponding db_queries. "name=" indicates
213 * deletion, which results in a db_query component where index_value == 0.
215 * The __nis_table_mapping_t structure is used to translate column
216 * names to indices.
218 * If 'rvP' is non-NULL, the searchable columns from the 'index'
219 * name/value pairs are used to retrieve copies of the corresponding NIS+
220 * entries, and '*rvP' is initialized with the current entry values
221 * and object attributes. Names/values supplied in 'index' override
222 * those from existing NIS+ entries.
224 db_query **
225 createQuery(int num, char **index, __nis_table_mapping_t *t,
226 __nis_rule_value_t **rvP, int *numVals) {
227 db_query **q;
228 db_qcomp *qc;
229 int i, j, n, a, nv, niv;
230 __nis_rule_value_t *rvq;
231 __nis_buffer_t b = {0, 0};
232 char *table = 0;
233 char *myself = "createQuery";
235 rvq = initRuleValue(1, 0);
236 if (rvq == 0)
237 return (0);
239 if (numVals == 0)
240 numVals = &nv;
241 *numVals = 0;
243 if (rvP != 0) {
245 * Try to obtain a copy of the table object, in order to
246 * determine the searchable columns. A failure isn't
247 * necessarily fatal; we just try to compose the entire
248 * LDAP data from the col=val pairs.
250 table = fullObjName(F, t->objName);
251 if (table == 0) {
252 logmsg(MSG_NOTIMECHECK, LOG_ERR,
253 "%s: Error converting \"%s\" to FQ object name",
254 myself, NIL(t->objName));
255 freeRuleValue(rvq, 1);
256 return (0);
260 /* Create a rule-value from the col=val pairs */
261 for (n = 0; n < num; n++) {
262 char *value;
264 if ((value = strchr(index[n], '=')) == 0) {
265 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
266 "%s: no '=' in \"%s\"",
267 myself, index[n]);
268 continue;
271 *value = '\0';
272 value++;
274 for (a = 0; a < t->numColumns; a++) {
275 if (strcmp(index[n], t->column[a]) == 0) {
277 /* Add col=val pair to 'rvq' */
278 if (addSCol2RuleValue(index[n], value, rvq)) {
279 freeRuleValue(rvq, 1);
280 sfree(table);
281 return (0);
284 break;
287 if (a >= t->numColumns) {
288 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
289 "%s: Ignoring unknown column \"%s\"",
290 myself, NIL(index[n]));
295 * Find out if any of the columns specified via the 'index'
296 * array are multi-valued.
298 for (n = 0, niv = 1; n < rvq->numColumns; n++) {
299 if (rvq->colVal[n].numVals > 1)
300 niv *= rvq->colVal[n].numVals;
303 *numVals = 1;
305 sfree(b.buf);
306 sfree(table);
308 if (rvq->numColumns <= 0) {
309 freeRuleValue(rvq, *numVals);
310 *numVals = 0;
311 return (0);
315 * If any column name was repeated in the col=val pairs (but with
316 * different values), 'rvq' will have one or more multi-valued
317 * column values. We now convert those into an array of rule-values
318 * where every column is single-valued.
320 * Since we want all combinations of column values, the number
321 * of array elements is the product of all column value counts.
323 * There are four possible combinations of 'index' and NIS+ data:
325 * (1) Only single-valued 'index' columns, and at most one NIS+
326 * entry, so 'rvq' is complete, and '*numVals' == 1.
328 * (2) Single-valued 'index' columns, but multiple NIS+ entries.
329 * '*numVals' reflects the number of NIS+ entries, and no
330 * expansion of 'index' column values to array elements is
331 * needed.
333 * (3) At least one multi-valued 'index', and multiple NIS+
334 * entries. We already rejected the NIS+ data for this case
335 * above, so it is in fact equivalent to case (4).
337 * (4) At least one multi-valued 'index', but at most one NIS+
338 * entry. This is the case where we must expand the multi-valued
339 * columns to multiple array elements.
341 if (niv > 1 && *numVals == 1) {
342 __nis_rule_value_t *rv;
343 int repeat;
346 * By using initRuleValue() to create 'rv', and make each
347 * element a clone of 'rvq', we save a lot of code. The
348 * down side is that 'rv' only really needs one element
349 * for each rv[].colVal[].val array, but we know that at
350 * least one rvq->colVal[].val array has more than one
351 * element. Hence, making 'rv' a clone of 'rvq' will waste
352 * memory.
354 * However, we believe this waste is acceptable, because
355 * we expect that 'niv' will be small. Also, we are executing
356 * in the context of a utility command, not in a daemon.
358 rv = initRuleValue(niv, rvq);
359 if (rv == 0) {
360 freeRuleValue(rvq, 1);
361 *numVals = 0;
362 return (0);
366 * For each column value in 'rvq', copy to the appropriate
367 * place in 'rv', so that the end result is that all
368 * combinations of values are enumerated, and each
369 * 'rv[n].colVal[i]' is single-valued.
371 * We do this by traversing the rv[] array 'rvq->numColumns'
372 * times, where each traversal 'i' works on the values
373 * for rvq->colVal[i]. A repeat factor 'repeat' starts out
374 * at '1', and is multiplied by 'rvq->colVal[i].numVals'
375 * at the end of each traversal. Every value
376 * rvq->colVal[i].val[j] is repeated 'repeat' times.
378 * This algorithm works by regarding the rv[] array as
379 * an I-dimensional array (I = rvq->numColumns), where
380 * each dimension 'i' corresponds to the values for
381 * rvq->colVal[i]. The I-dimensional array is stored
382 * in column-major order.
384 * Since the 'rv' elements start out as copies of 'rvq',
385 * we achieve the "copy" of the 'rvq' column values by
386 * deleting those we don't want from the 'rv' elements.
388 for (i = 0, repeat = 1; i < rvq->numColumns; i++) {
389 int r, k;
390 for (n = 0, j = 0, r = 0; n < niv; n++) {
392 * Free all but element 'j' of the
393 * rv[n].colVal[i].val array.
395 for (k = 0; k < rv[n].colVal[i].numVals; k++) {
396 /* Leave element 'j' in place */
397 if (k == j)
398 continue;
399 sfree(rv[n].colVal[i].val[k].
400 value);
402 rv[n].colVal[i].numVals = 1;
403 /* Move element 'j' to zero */
404 if (j != 0)
405 rv[n].colVal[i].val[0] =
406 rv[n].colVal[i].val[j];
409 * Increment the repeat index 'r'. If >=
410 * 'repeat', reset 'r' and increment the
411 * value index 'j'. If 'j' >=
412 * rvq->colVal[i].numVals, start over on
413 * the column values for column 'i' (i.e.,
414 * reset 'j' to zero).
416 r += 1;
417 if (r >= repeat) {
418 r = 0;
419 j += 1;
420 if (j >= rvq->colVal[i].numVals)
421 j = 0;
424 repeat *= rvq->colVal[i].numVals;
427 *numVals = niv;
428 freeRuleValue(rvq, 1);
429 rvq = rv;
430 rv = 0;
433 q = am(myself, *numVals * sizeof (q[0]));
434 if (q == 0) {
435 freeRuleValue(rvq, *numVals);
436 return (0);
440 * Create queries from the rvq[] array.
442 for (a = 0; a < *numVals; a++) {
443 int nn, err = 0;
445 qc = am(myself, rvq[a].numColumns * sizeof (*qc));
446 if (qc != 0) {
447 for (nn = 0, i = 0; i < rvq[a].numColumns; i++) {
448 for (j = 0; j < t->numColumns; j++) {
449 if (strcmp(rvq[a].colName[i],
450 t->column[j]) == 0) {
451 break;
454 if (j >= t->numColumns)
455 continue;
456 qc[nn].which_index = j;
457 if (rvq[a].colVal[i].numVals > 0) {
458 qc[nn].index_value = buildItem(
459 rvq[a].colVal[i].val[0].length,
460 rvq[a].colVal[i].val[0].value);
461 if (qc[nn].index_value == 0)
462 err++;
463 } else {
464 logmsg(MSG_NOTIMECHECK, LOG_ERR,
465 "%s: No values for [%d]%s",
466 myself, a, rvq[a].colName[i]);
467 err++;
469 nn++;
471 if (err == 0)
472 q[a] = buildQuery(nn, qc);
474 if (err > 0 || q[a] == 0) {
475 freeQueries(q, a);
476 for (a = 0; a < nn; a++)
477 freeQcomp(&qc[a], F);
478 sfree(qc);
479 freeRuleValue(rvq, *numVals);
480 return (0);
484 if (rvP != 0) {
485 *rvP = rvq;
486 } else {
487 freeRuleValue(rvq, 1);
488 *numVals = 0;
491 return (q);
494 void
495 printQuery(db_query *q, __nis_table_mapping_t *t) {
496 int i, mc = -1;
497 char *myself = "printQuery";
498 char *val[NIS_MAXCOLUMNS];
500 if (q == 0)
501 return;
503 (void) memset(val, 0, sizeof (val));
506 * Collect the values, which may be out of order in 'q'.
507 * Remember the largest index.
509 for (i = 0; i < q->components.components_len; i++) {
510 int ix = q->components.components_val[i].which_index;
512 if (ix >= NIS_MAXCOLUMNS ||
513 (t != 0 && ix >= t->numColumns))
514 continue;
515 if (ix > mc)
516 mc = ix;
517 val[ix] = q->components.components_val[i].index_value->
518 itemvalue.itemvalue_val;
521 /* Print the values we collected */
522 for (i = 0; i <= mc; i++) {
523 p2buf(myself, "%s%s", (i != 0 ? " " : ""),
524 (val[i] != 0 ? val[i] : ""));
526 /* If we printed anything, add a newline */
527 if (mc >= 0)
528 p2buf(myself, "\n");
532 * Verify that the db_query's 'q' and 'fq' match, in the sense that if
533 * they both have a value for a certain index, the values are the same.
536 verifyQueryMatch(db_query *q, db_query *fq) {
537 int i, j, match;
539 if (fq == 0)
540 return (1);
542 if (q == 0)
543 return ((fq == 0) ? 1 : 0);
545 for (i = 0, match = 1; match && i < q->components.components_len;
546 i++) {
547 for (j = 0; j < fq->components.components_len; j++) {
548 int len, flen;
550 /* Same index ? */
551 if (q->components.components_val[i].which_index !=
552 fq->components.components_val[j].
553 which_index)
554 continue;
556 * If one 'index_value' is NULL, the other one must
557 * be NULL as well.
559 if (q->components.components_val[i].index_value == 0) {
560 if (fq->components.components_val[j].
561 index_value == 0)
562 continue;
563 else {
564 match = 0;
565 break;
568 if (fq->components.components_val[j].index_value ==
569 0) {
570 match = 0;
571 break;
573 /* Same value lengths ? */
574 len = q->components.components_val[i].index_value->
575 itemvalue.itemvalue_len;
576 flen = fq->components.components_val[j].index_value->
577 itemvalue.itemvalue_len;
578 if (len != flen) {
580 * There's a twist here: the input query
581 * may well _not_ count a concluding NUL
582 * in a string value, while the output
583 * usually will. So, if the difference in
584 * length is one, and the "extra" byte is
585 * a zero-valued one, we accept equality.
586 * 'q' is assumed to be the output, and
587 * 'fq' the input.
589 if (!(len > 0 && len == (flen+1) &&
590 q->components.components_val[i].
591 index_value->
592 itemvalue.itemvalue_val[len-1] == 0)) {
593 match = 0;
594 break;
597 /* Same value ? */
598 if (memcmp(q->components.components_val[i].index_value->
599 itemvalue.itemvalue_val,
600 fq->components.components_val[j].index_value->
601 itemvalue.itemvalue_val,
602 flen) != 0) {
603 match = 0;
604 break;
609 return (match);
613 * Remove those queries in 'q' that don't match t->index.
614 * Returns a pointer to the filtered array, which could be
615 * a compacted version of the original, or a new copy; in
616 * the latter case, the original will have been freed.
618 * Filtered/removed db_query's are freed.
620 db_query **
621 filterQuery(__nis_table_mapping_t *t, db_query **q, db_query *qin,
622 __nis_obj_attr_t ***objAttr, int *numQueries) {
623 db_query **new;
624 __nis_obj_attr_t **attr;
625 int i, nq, nn;
626 char *myself = "filterQuery";
628 if ((t == 0 && qin == 0) || q == 0 ||
629 numQueries == 0 || *numQueries <= 0)
630 return (q);
632 nq = *numQueries;
633 new = am(myself, nq * sizeof (new[0]));
634 if (objAttr != 0)
635 attr = am(myself, nq * sizeof (attr[0]));
636 else
637 attr = 0;
638 if (new == 0 || (objAttr != 0 && attr == 0)) {
639 sfree(new);
640 freeQueries(q, nq);
641 sfree(attr);
642 if (objAttr != 0) {
643 freeObjAttr(*objAttr, nq);
644 *objAttr = 0;
646 *numQueries = -1;
647 return (0);
650 for (i = 0, nn = 0; i < nq; i++) {
651 int retain = 1;
653 if (t != 0)
654 retain = verifyIndexMatch(t, q[i], 0, 0, 0);
656 if (retain && qin != 0)
657 retain = verifyQueryMatch(q[i], qin);
659 if (retain) {
660 new[nn] = q[i];
661 if (objAttr != 0)
662 attr[nn] = (*objAttr)[i];
663 nn++;
664 } else {
665 freeQuery(q[i]);
666 q[i] = 0;
667 if (objAttr != 0) {
668 freeSingleObjAttr((*objAttr)[i]);
669 (*objAttr)[i] = 0;
674 /* All q[i]'s are either in 'new', or have been deleted */
675 free(q);
676 if (objAttr != 0) {
677 sfree(*objAttr);
678 *objAttr = attr;
681 *numQueries = nn;
683 return (new);
686 db_query **
687 createNisPlusEntry(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
688 db_query *qin, __nis_obj_attr_t ***objAttr,
689 int *numQueries) {
690 db_query **query = 0;
691 int r, i, j, ir;
692 __nis_value_t *rval, *lval;
693 __nis_mapping_item_t *litem;
694 int numItems;
695 int nq;
696 __nis_obj_attr_t **attr = 0;
697 char **dn = 0;
698 int numDN = 0;
699 char *myself = "createNisPlusEntry";
701 if (t == 0 || t->objectDN == 0 || rv == 0)
702 return (0);
704 /* Establish default, per-thread, search base */
705 __nisdb_get_tsd()->searchBase = t->objectDN->read.base;
707 for (r = 0, nq = 0; r < t->numRulesFromLDAP; r++) {
708 int nrq, ntq, err;
709 db_query **newq;
710 __nis_obj_attr_t **newattr;
712 rval = buildRvalue(&t->ruleFromLDAP[r]->rhs,
713 mit_ldap, rv, NULL);
714 if (rval == 0)
715 continue;
717 litem = buildLvalue(&t->ruleFromLDAP[r]->lhs, &rval,
718 &numItems);
719 if (litem == 0) {
720 freeValue(rval, 1);
721 /* XXX Should this be a fatal error ? */
722 continue;
725 lval = 0;
726 for (i = 0; i < numItems; i++) {
727 __nis_value_t *tmpval, *old;
729 tmpval = getMappingItem(&litem[i],
730 mit_nisplus, 0, 0, NULL);
733 * If the LHS specifies an out-of-context LDAP or
734 * NIS+ item, we do the update right here. We
735 * don't add any values to 'lval'; instead, we
736 * skip to the next item. (However, we still
737 * get a string representation of the LHS in case
738 * we need to report an error.)
740 if (litem[i].type == mit_ldap) {
741 int stat;
743 if (dn == 0)
744 dn = findDNs(myself, rv, 1,
745 t->objectDN->write.base,
746 &numDN);
748 stat = storeLDAP(&litem[i], i, numItems, rval,
749 t->objectDN, dn, numDN);
750 if (stat != LDAP_SUCCESS) {
751 char *iname = "<unknown>";
753 if (tmpval != 0 &&
754 tmpval->numVals == 1)
755 iname = tmpval->val[0].value;
756 logmsg(MSG_NOTIMECHECK, LOG_ERR,
757 "%s: LDAP store \"%s\": %s",
758 myself, iname,
759 ldap_err2string(stat));
762 freeValue(tmpval, 1);
763 continue;
766 old = lval;
767 lval = concatenateValues(old, tmpval);
768 freeValue(tmpval, 1);
769 freeValue(old, 1);
772 freeMappingItem(litem, numItems);
773 if (lval == 0 || lval->numVals <= 0 || rval->numVals <= 0) {
774 freeValue(lval, 1);
775 freeValue(rval, 1);
776 continue;
780 * We now have a number of possible cases. The notation
781 * used in the table is:
783 * single A single value (numVals == 1)
784 * single/rep A single value with repeat == 1
785 * multi[N] N values
786 * multi[N]/rep M values with repeat == 1
787 * (M) M resulting db_query's
789 * lval \ rval single single/rep multi[N] multi[N]/rep
790 * single (1) (1) (1) (1)
791 * single/rep (1) (1) (N) (N)
792 * multi[M] (1) (1) (1) 1+(N-1)/M
793 * multi[M]/rep (1) (1) (1) 1+(N-1)/M
795 * Of course, we already have 'nq' db_query's from previous
796 * rules, so the resulting number of queries is max(1,nq)
797 * times the numbers in the table above.
800 /* The number of queries resulting from the current rule */
801 if (rval->numVals > 1) {
802 if (lval->numVals == 1 && lval->repeat)
803 nrq = rval->numVals;
804 else if (lval->numVals > 1 && rval->repeat)
805 nrq = 1 + ((rval->numVals-1)/lval->numVals);
806 else
807 nrq = 1;
808 } else {
809 nrq = 1;
812 /* Total number of queries after adding the current rule */
813 if (nq <= 0)
814 ntq = nrq;
815 else
816 ntq = nq * nrq;
818 if (ntq > nq) {
819 newq = realloc(query, ntq * sizeof (query[0]));
820 newattr = realloc(attr, ntq * sizeof (attr[0]));
821 if (newq == 0 || newattr == 0) {
822 logmsg(MSG_NOMEM, LOG_ERR,
823 "%s: realloc(%d) => NULL",
824 myself, ntq * sizeof (query[0]));
825 freeValue(lval, 1);
826 freeValue(rval, 1);
827 freeQueries(query, nq);
828 freeObjAttr(attr, nq);
829 sfree(newq);
830 freeDNs(dn, numDN);
831 return (0);
833 query = newq;
834 attr = newattr;
838 * Copy/clone the existing queries to the new array,
839 * remembering that realloc() has done the first 'nq'
840 * ones.
842 * If there's an error (probably memory allocation), we
843 * still go through the rest of the array, so that it's
844 * simple to free the elements when we clean up.
846 for (i = 1, err = 0; i < nrq; i++) {
847 for (j = 0; j < nq; j++) {
848 query[(nq*i)+j] = cloneQuery(query[j],
849 t->numColumns);
850 if (query[(nq*i)+j] == 0 &&
851 query[j] != 0)
852 err++;
853 attr[(nq*i)+j] = cloneObjAttr(attr[j]);
854 if (attr[(nq*i)+j] == 0 &&
855 attr[j] != 0)
856 err++;
860 if (err > 0) {
861 freeValue(lval, 1);
862 freeValue(rval, 1);
863 freeQueries(query, ntq);
864 freeObjAttr(attr, ntq);
865 freeDNs(dn, numDN);
866 return (0);
870 * Special case if nq == 0 (i.e., the first time we
871 * allocated db_query's). If so, we now allocate empty
872 * db_qcomp arrays, which simplifies subsequent
873 * copying of values.
875 if (nq <= 0) {
876 (void) memset(query, 0, ntq * sizeof (query[0]));
877 (void) memset(attr, 0, ntq * sizeof (attr[0]));
878 for (i = 0, err = 0; i < ntq; i++) {
879 query[i] = am(myself, sizeof (*query[i]));
880 if (query[i] == 0) {
881 err++;
882 break;
884 query[i]->components.components_val =
885 am(myself, t->numColumns *
886 sizeof (query[i]->components.components_val[0]));
887 if (query[i]->components.components_val == 0) {
888 err++;
889 break;
891 query[i]->components.components_len = 0;
893 if (err > 0) {
894 freeValue(lval, 1);
895 freeValue(rval, 1);
896 freeQueries(query, ntq);
897 freeObjAttr(attr, ntq);
898 freeDNs(dn, numDN);
899 return (0);
903 /* Now we're ready to add the new values */
904 for (i = 0, ir = 0; i < lval->numVals; i++) {
905 char *oaName = 0;
906 int index;
908 /* Find column index */
909 for (index = 0; index < t->numColumns;
910 index++) {
911 if (strncmp(t->column[index],
912 lval->val[i].value,
913 lval->val[i].length) == 0)
914 break;
916 if (index >= t->numColumns) {
918 * Could be one of the special object
919 * attributes.
921 oaName = isObjAttr(&lval->val[i]);
922 if (oaName == 0)
923 continue;
926 for (j = i*nrq; j < (i+1)*nrq; j++) {
927 int k;
929 /* If we're out of values, repeat last one */
930 ir = (j < rval->numVals) ?
931 j : rval->numVals - 1;
934 * Step through the query array, adding
935 * the new value every 'nrq' queries, and
936 * starting at 'query[j % nrq]'.
938 for (k = j % nrq, err = 0; k < ntq; k += nrq) {
939 int ic, c;
941 if (oaName != 0) {
942 int fail = setObjAttrField(
943 oaName,
944 &rval->val[ir],
945 &attr[k]);
946 if (fail) {
947 err++;
948 break;
950 continue;
953 ic = query[k]->components.
954 components_len;
956 * If we've already filled this
957 * query, the new value is a dup
958 * which we'll ignore.
960 if (ic >= t->numColumns)
961 continue;
964 * Do we already have a value for
965 * this 'index' ?
967 for (c = 0; c < ic; c++) {
968 if (query[k]->components.
969 components_val[c].
970 which_index == index)
971 break;
974 /* If no previous value, add it */
975 if (c >= ic) {
976 int l;
977 char *v;
979 query[k]->components.
980 components_val[ic].
981 which_index = index;
982 l = rval->val[ir].length;
983 v = rval->val[ir].value;
984 if (rval->type == vt_string &&
985 l > 0 &&
986 v[l-1] != '\0' &&
987 v[l] == '\0')
988 l++;
989 query[k]->components.
990 components_val[ic].
991 index_value =
992 buildItem(l, v);
993 if (query[k]->
994 components.
995 components_val[ic].
996 index_value == 0) {
997 err++;
998 break;
1000 query[k]->components.
1001 components_len++;
1004 if (err > 0) {
1005 freeValue(lval, 1);
1006 freeValue(rval, 1);
1007 freeQueries(query, ntq);
1008 freeObjAttr(attr, ntq);
1009 freeDNs(dn, numDN);
1010 return (0);
1014 freeValue(lval, 1);
1015 freeValue(rval, 1);
1017 nq = ntq;
1020 freeDNs(dn, numDN);
1022 if (nq <= 0) {
1023 sfree(query);
1024 query = 0;
1027 /* Should we filter on index or input query ? */
1028 if (query != 0) {
1029 if (t->index.numIndexes > 0)
1030 query = filterQuery(t, query, qin, &attr, &nq);
1031 else if (qin != 0)
1032 query = filterQuery(0, query, qin, &attr, &nq);
1035 if (query != 0 && numQueries != 0)
1036 *numQueries = nq;
1038 if (objAttr != 0)
1039 *objAttr = attr;
1040 else
1041 freeObjAttr(attr, nq);
1043 return (query);
1046 * Given a table mapping and a rule-value, convert to an array of
1047 * (db_query *), using the fromLDAP ruleset.
1049 * On entry, '*numQueries' holds the number of elements in the 'rv'
1050 * array. On exit, it holds the number of (db_query *)'s in the return
1051 * value array.
1053 db_query **
1054 ruleValue2Query(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
1055 db_query *qin, __nis_obj_attr_t ***objAttr, int *numQueries) {
1056 db_query **q = 0, ***qp = 0;
1057 int i, nqp, nq, *nnp = 0, nv;
1058 __nis_obj_attr_t **attr = 0, ***atp = 0;
1059 char *myself = "ruleValue2Query";
1062 if (t == 0 || rv == 0 || numQueries == 0)
1063 return (0);
1065 nv = *numQueries;
1066 if (nv <= 0)
1067 return (0);
1070 * 'qp' is an array of (db_query **), and we get one element for
1071 * each call to createNisPlusEntry(); i.e., one for each rule-value.
1073 * 'nnp[i]' is the count of (db_query *) in each 'qp[i]'.
1075 qp = am(myself, nv * sizeof (*qp));
1076 nnp = am(myself, nv * sizeof (*nnp));
1077 atp = am(myself, nv * sizeof (*atp));
1078 if (qp == 0 || nnp == 0 || atp == 0) {
1079 sfree(qp);
1080 sfree(nnp);
1081 sfree(atp);
1082 return (0);
1085 for (i = 0, nq = 0, nqp = 0; i < nv; i++) {
1086 qp[nqp] = createNisPlusEntry(t, &rv[i], qin, &atp[nqp],
1087 &nnp[nqp]);
1088 /* If we fail, abort (XXX??? or continue ???) */
1089 if (qp[nqp] == 0)
1090 goto cleanup;
1091 nq += nnp[nqp];
1092 nqp++;
1095 /* If we didn't get any (db_query **)'s, return failure */
1096 if (nqp == 0 || nq <= 0)
1097 goto cleanup;
1099 q = am(myself, nq * sizeof (q[0]));
1100 attr = am(myself, nq * sizeof (attr[0]));
1101 if (q == 0 || attr == 0) {
1102 nq = 0;
1103 goto cleanup;
1106 /* Convert 'qp' to an array of (db_query *)'s */
1107 for (i = 0, nq = 0; i < nqp; i++) {
1108 (void) memcpy(&q[nq], qp[i], nnp[i] * sizeof (qp[i][0]));
1109 (void) memcpy(&attr[nq], atp[i], nnp[i] * sizeof (atp[i][0]));
1110 nq += nnp[i];
1111 free(qp[i]);
1112 free(atp[i]);
1115 *numQueries = nq;
1116 if (objAttr != 0)
1117 *objAttr = attr;
1118 else
1119 freeObjAttr(attr, nq);
1121 /* Make sure 'cleanup' doesn't free the db_query pointers */
1122 nqp = 0;
1124 cleanup:
1125 for (i = 0; i < nqp; i++) {
1126 freeQueries(qp[i], nnp[i]);
1127 sfree(atp[i]);
1129 sfree(qp);
1130 sfree(nnp);
1131 sfree(atp);
1133 return (q);
1136 db_query *
1137 pseudoEntryObj2Query(entry_obj *e, nis_object *tobj, __nis_rule_value_t *rv) {
1138 db_query *qbuf;
1139 db_qcomp *qcbuf;
1140 int nc, i;
1141 __nis_rule_value_t *rvt = 0;
1142 char *myself = "pseudoEntryObj2Query";
1144 nc = e->en_cols.en_cols_len - 1;
1146 if (e == 0 || nc < 0 || nc > NIS_MAXCOLUMNS)
1147 return (0);
1150 * If 'rvP' is non-NULL, build a rule value from the pseudo-
1151 * nis_object in e->en_cols.en_cols_val[0].
1153 if (rv != 0) {
1154 nis_object *o;
1156 o = unmakePseudoEntryObj(e, tobj);
1157 if (o == 0)
1158 return (0);
1159 rvt = addObjAttr2RuleValue(o, 0);
1160 nis_destroy_object(o);
1161 if (rvt == 0)
1162 return (0);
1165 qbuf = am(myself, sizeof (*qbuf));
1167 * If there are no columns (other than the pseudo-entry object),
1168 * we're done.
1170 if (nc == 0)
1171 return (qbuf);
1173 qcbuf = am(myself, nc * sizeof (*qcbuf));
1174 if (qcbuf == 0) {
1175 sfree(qcbuf);
1176 if (rvt != 0)
1177 freeRuleValue(rvt, 1);
1178 return (0);
1182 * Build the db_query, remembering that e->en_cols.en_cols_val[0]
1183 * is the pseudo-nis_object.
1185 qbuf->components.components_val = qcbuf;
1186 qbuf->components.components_len = nc;
1187 for (i = 0; i < nc; i++) {
1188 qcbuf[i].which_index = i;
1189 qcbuf[i].index_value = buildItem(
1190 e->en_cols.en_cols_val[i+1].ec_value.ec_value_len,
1191 e->en_cols.en_cols_val[i+1].ec_value.ec_value_val);
1192 if (qcbuf[i].index_value == 0) {
1193 freeQuery(qbuf);
1194 if (rvt != 0)
1195 freeRuleValue(rvt, 1);
1196 return (0);
1200 if (rvt != 0) {
1201 *rv = *rvt;
1202 sfree(rvt);
1205 return (qbuf);
1209 * Given an input query 'q', and a db_query work buffer 'qbuf', return
1210 * a pointer to a query with one component corresponding to component
1211 * 'index' in 'q'.
1213 * Note that no memory is allocated, and that the returned query has
1214 * pointers into 'q'.
1216 db_query *
1217 queryFromComponent(db_query *q, int index, db_query *qbuf) {
1219 if (q == 0 || index < 0 || index >= q->components.components_len ||
1220 qbuf == 0)
1221 return (0);
1223 qbuf->components.components_len = 1;
1224 qbuf->components.components_val = &q->components.components_val[index];
1226 return (qbuf);