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]
22 * Copyright 2015 Gary Mills
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
33 #include "db_item_c.h"
37 #include "ldap_util.h"
38 #include "ldap_structs.h"
40 #include "ldap_ruleval.h"
42 #include "ldap_nisdbquery.h"
43 #include "ldap_attr.h"
45 #include "ldap_ldap.h"
49 buildItem(int len
, void *value
) {
50 char *myself
= "buildItem";
51 item
*i
= am(myself
, sizeof (*i
));
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
63 if (value
== 0 || len
<= 0) {
64 i
->itemvalue
.itemvalue_len
= 0;
65 i
->itemvalue
.itemvalue_val
= 0;
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')
77 i
->itemvalue
.itemvalue_len
= len
;
78 i
->itemvalue
.itemvalue_val
= am(myself
, mlen
);
79 if (mlen
> 0 && i
->itemvalue
.itemvalue_val
== 0) {
83 memcpy(i
->itemvalue
.itemvalue_val
, value
, len
);
91 sfree(i
->itemvalue
.itemvalue_val
);
97 freeQcomp(db_qcomp
*qc
, int doFree
) {
102 freeItem(qc
->index_value
);
108 buildQuery(int num_components
, db_qcomp
*components
) {
109 char *myself
= "buildQuery";
110 db_query
*q
= am(myself
, sizeof (*q
));
115 q
->components
.components_len
= num_components
;
116 q
->components
.components_val
= components
;
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
128 cloneQuery(db_query
*old
, int numComps
) {
131 char *myself
= "cloneQuery";
136 new = am(myself
, sizeof (*new));
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]) *
146 if (numComps
> 0 && new->components
.components_val
== 0) {
151 for (i
= 0; i
< old
->components
.components_len
; i
++) {
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
;
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
);
167 new->components
.components_len
= i
+ 1;
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
;
183 freeQuery(db_query
*q
) {
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
);
198 freeQueries(db_query
**q
, int numQ
) {
204 for (i
= 0; i
< numQ
; i
++)
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
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.
225 createQuery(int num
, char **index
, __nis_table_mapping_t
*t
,
226 __nis_rule_value_t
**rvP
, int *numVals
) {
229 int i
, j
, n
, a
, nv
, niv
;
230 __nis_rule_value_t
*rvq
;
231 __nis_buffer_t b
= {0, 0};
233 char *myself
= "createQuery";
235 rvq
= initRuleValue(1, 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
);
252 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
253 "%s: Error converting \"%s\" to FQ object name",
254 myself
, NIL(t
->objName
));
255 freeRuleValue(rvq
, 1);
260 /* Create a rule-value from the col=val pairs */
261 for (n
= 0; n
< num
; n
++) {
264 if ((value
= strchr(index
[n
], '=')) == 0) {
265 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
266 "%s: no '=' in \"%s\"",
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);
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
;
308 if (rvq
->numColumns
<= 0) {
309 freeRuleValue(rvq
, *numVals
);
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
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
;
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
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
);
360 freeRuleValue(rvq
, 1);
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
++) {
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 */
399 sfree(rv
[n
].colVal
[i
].val
[k
].
402 rv
[n
].colVal
[i
].numVals
= 1;
403 /* Move element 'j' to zero */
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).
420 if (j
>= rvq
->colVal
[i
].numVals
)
424 repeat
*= rvq
->colVal
[i
].numVals
;
428 freeRuleValue(rvq
, 1);
433 q
= am(myself
, *numVals
* sizeof (q
[0]));
435 freeRuleValue(rvq
, *numVals
);
440 * Create queries from the rvq[] array.
442 for (a
= 0; a
< *numVals
; a
++) {
445 qc
= am(myself
, rvq
[a
].numColumns
* sizeof (*qc
));
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) {
454 if (j
>= t
->numColumns
)
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)
464 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
465 "%s: No values for [%d]%s",
466 myself
, a
, rvq
[a
].colName
[i
]);
472 q
[a
] = buildQuery(nn
, qc
);
474 if (err
> 0 || q
[a
] == 0) {
476 for (a
= 0; a
< nn
; a
++)
477 freeQcomp(&qc
[a
], F
);
479 freeRuleValue(rvq
, *numVals
);
487 freeRuleValue(rvq
, 1);
495 printQuery(db_query
*q
, __nis_table_mapping_t
*t
) {
497 char *myself
= "printQuery";
498 char *val
[NIS_MAXCOLUMNS
];
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
))
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 */
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
) {
543 return ((fq
== 0) ? 1 : 0);
545 for (i
= 0, match
= 1; match
&& i
< q
->components
.components_len
;
547 for (j
= 0; j
< fq
->components
.components_len
; j
++) {
551 if (q
->components
.components_val
[i
].which_index
!=
552 fq
->components
.components_val
[j
].
556 * If one 'index_value' is NULL, the other one must
559 if (q
->components
.components_val
[i
].index_value
== 0) {
560 if (fq
->components
.components_val
[j
].
568 if (fq
->components
.components_val
[j
].index_value
==
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
;
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
589 if (!(len
> 0 && len
== (flen
+1) &&
590 q
->components
.components_val
[i
].
592 itemvalue
.itemvalue_val
[len
-1] == 0)) {
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
,
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.
621 filterQuery(__nis_table_mapping_t
*t
, db_query
**q
, db_query
*qin
,
622 __nis_obj_attr_t
***objAttr
, int *numQueries
) {
624 __nis_obj_attr_t
**attr
;
626 char *myself
= "filterQuery";
628 if ((t
== 0 && qin
== 0) || q
== 0 ||
629 numQueries
== 0 || *numQueries
<= 0)
633 new = am(myself
, nq
* sizeof (new[0]));
635 attr
= am(myself
, nq
* sizeof (attr
[0]));
638 if (new == 0 || (objAttr
!= 0 && attr
== 0)) {
643 freeObjAttr(*objAttr
, nq
);
650 for (i
= 0, nn
= 0; i
< nq
; i
++) {
654 retain
= verifyIndexMatch(t
, q
[i
], 0, 0, 0);
656 if (retain
&& qin
!= 0)
657 retain
= verifyQueryMatch(q
[i
], qin
);
662 attr
[nn
] = (*objAttr
)[i
];
668 freeSingleObjAttr((*objAttr
)[i
]);
674 /* All q[i]'s are either in 'new', or have been deleted */
687 createNisPlusEntry(__nis_table_mapping_t
*t
, __nis_rule_value_t
*rv
,
688 db_query
*qin
, __nis_obj_attr_t
***objAttr
,
690 db_query
**query
= 0;
692 __nis_value_t
*rval
, *lval
;
693 __nis_mapping_item_t
*litem
;
696 __nis_obj_attr_t
**attr
= 0;
699 char *myself
= "createNisPlusEntry";
701 if (t
== 0 || t
->objectDN
== 0 || rv
== 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
++) {
710 __nis_obj_attr_t
**newattr
;
712 rval
= buildRvalue(&t
->ruleFromLDAP
[r
]->rhs
,
717 litem
= buildLvalue(&t
->ruleFromLDAP
[r
]->lhs
, &rval
,
721 /* XXX Should this be a fatal error ? */
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
) {
744 dn
= findDNs(myself
, rv
, 1,
745 t
->objectDN
->write
.base
,
748 stat
= storeLDAP(&litem
[i
], i
, numItems
, rval
,
749 t
->objectDN
, dn
, numDN
);
750 if (stat
!= LDAP_SUCCESS
) {
751 char *iname
= "<unknown>";
754 tmpval
->numVals
== 1)
755 iname
= tmpval
->val
[0].value
;
756 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
757 "%s: LDAP store \"%s\": %s",
759 ldap_err2string(stat
));
762 freeValue(tmpval
, 1);
767 lval
= concatenateValues(old
, tmpval
);
768 freeValue(tmpval
, 1);
772 freeMappingItem(litem
, numItems
);
773 if (lval
== 0 || lval
->numVals
<= 0 || rval
->numVals
<= 0) {
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
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
)
804 else if (lval
->numVals
> 1 && rval
->repeat
)
805 nrq
= 1 + ((rval
->numVals
-1)/lval
->numVals
);
812 /* Total number of queries after adding the current rule */
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]));
827 freeQueries(query
, nq
);
828 freeObjAttr(attr
, nq
);
838 * Copy/clone the existing queries to the new array,
839 * remembering that realloc() has done the first 'nq'
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
],
850 if (query
[(nq
*i
)+j
] == 0 &&
853 attr
[(nq
*i
)+j
] = cloneObjAttr(attr
[j
]);
854 if (attr
[(nq
*i
)+j
] == 0 &&
863 freeQueries(query
, ntq
);
864 freeObjAttr(attr
, ntq
);
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
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
]));
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) {
891 query
[i
]->components
.components_len
= 0;
896 freeQueries(query
, ntq
);
897 freeObjAttr(attr
, ntq
);
903 /* Now we're ready to add the new values */
904 for (i
= 0, ir
= 0; i
< lval
->numVals
; i
++) {
908 /* Find column index */
909 for (index
= 0; index
< t
->numColumns
;
911 if (strncmp(t
->column
[index
],
913 lval
->val
[i
].length
) == 0)
916 if (index
>= t
->numColumns
) {
918 * Could be one of the special object
921 oaName
= isObjAttr(&lval
->val
[i
]);
926 for (j
= i
*nrq
; j
< (i
+1)*nrq
; j
++) {
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
) {
942 int fail
= setObjAttrField(
953 ic
= query
[k
]->components
.
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
)
964 * Do we already have a value for
967 for (c
= 0; c
< ic
; c
++) {
968 if (query
[k
]->components
.
970 which_index
== index
)
974 /* If no previous value, add it */
979 query
[k
]->components
.
982 l
= rval
->val
[ir
].length
;
983 v
= rval
->val
[ir
].value
;
984 if (rval
->type
== vt_string
&&
989 query
[k
]->components
.
1000 query
[k
]->components
.
1007 freeQueries(query
, ntq
);
1008 freeObjAttr(attr
, ntq
);
1027 /* Should we filter on index or input query ? */
1029 if (t
->index
.numIndexes
> 0)
1030 query
= filterQuery(t
, query
, qin
, &attr
, &nq
);
1032 query
= filterQuery(0, query
, qin
, &attr
, &nq
);
1035 if (query
!= 0 && numQueries
!= 0)
1041 freeObjAttr(attr
, nq
);
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
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)
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) {
1085 for (i
= 0, nq
= 0, nqp
= 0; i
< nv
; i
++) {
1086 qp
[nqp
] = createNisPlusEntry(t
, &rv
[i
], qin
, &atp
[nqp
],
1088 /* If we fail, abort (XXX??? or continue ???) */
1095 /* If we didn't get any (db_query **)'s, return failure */
1096 if (nqp
== 0 || nq
<= 0)
1099 q
= am(myself
, nq
* sizeof (q
[0]));
1100 attr
= am(myself
, nq
* sizeof (attr
[0]));
1101 if (q
== 0 || attr
== 0) {
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]));
1119 freeObjAttr(attr
, nq
);
1121 /* Make sure 'cleanup' doesn't free the db_query pointers */
1125 for (i
= 0; i
< nqp
; i
++) {
1126 freeQueries(qp
[i
], nnp
[i
]);
1137 pseudoEntryObj2Query(entry_obj
*e
, nis_object
*tobj
, __nis_rule_value_t
*rv
) {
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
)
1150 * If 'rvP' is non-NULL, build a rule value from the pseudo-
1151 * nis_object in e->en_cols.en_cols_val[0].
1156 o
= unmakePseudoEntryObj(e
, tobj
);
1159 rvt
= addObjAttr2RuleValue(o
, 0);
1160 nis_destroy_object(o
);
1165 qbuf
= am(myself
, sizeof (*qbuf
));
1167 * If there are no columns (other than the pseudo-entry object),
1173 qcbuf
= am(myself
, nc
* sizeof (*qcbuf
));
1177 freeRuleValue(rvt
, 1);
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) {
1195 freeRuleValue(rvt
, 1);
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
1213 * Note that no memory is allocated, and that the returned query has
1214 * pointers into 'q'.
1217 queryFromComponent(db_query
*q
, int index
, db_query
*qbuf
) {
1219 if (q
== 0 || index
< 0 || index
>= q
->components
.components_len
||
1223 qbuf
->components
.components_len
= 1;
1224 qbuf
->components
.components_val
= &q
->components
.components_val
[index
];