4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
35 #include "ldap_util.h"
37 #include "ldap_attr.h"
38 #include "ldap_ldap.h"
39 #include "ldap_nisplus.h"
40 #include "ldap_ruleval.h"
44 * Free an array of 'count' rule-value elements.
47 freeRuleValue(__nis_rule_value_t
*rv
, int count
) {
53 for (n
= 0; n
< count
; n
++) {
55 if (rv
[n
].colName
!= 0) {
56 for (i
= 0; i
< rv
[n
].numColumns
; i
++) {
57 sfree(rv
[n
].colName
[i
]);
61 if (rv
[n
].colVal
!= 0) {
62 for (i
= 0; i
< rv
[n
].numColumns
; i
++) {
63 for (j
= 0; j
< rv
[n
].colVal
[i
].numVals
; j
++) {
64 sfree(rv
[n
].colVal
[i
].val
[j
].value
);
66 if (rv
[n
].colVal
[i
].numVals
> 0)
67 sfree(rv
[n
].colVal
[i
].val
);
72 if (rv
[n
].attrName
!= 0) {
73 for (i
= 0; i
< rv
[n
].numAttrs
; i
++) {
74 sfree(rv
[n
].attrName
[i
]);
78 if (rv
[n
].attrVal
!= 0) {
79 for (i
= 0; i
< rv
[n
].numAttrs
; i
++) {
80 for (j
= 0; j
< rv
[n
].attrVal
[i
].numVals
;
82 sfree(rv
[n
].attrVal
[i
].val
[j
].value
);
84 if (rv
[n
].attrVal
[i
].numVals
> 0)
85 sfree(rv
[n
].attrVal
[i
].val
);
95 * Return an array of 'count' __nis_rule_value_t elements, initialized
96 * to be copies of 'rvIn' if supplied; empty otherwise.
99 initRuleValue(int count
, __nis_rule_value_t
*rvIn
) {
100 return (growRuleValue(0, count
, 0, rvIn
));
103 static const __nis_rule_value_t rvZero
= {0};
106 * Grow 'old' from 'oldCount' to 'newCount' elements, initialize the
107 * new portion to 'rvIn' (empty if not supplied), and return a pointer
108 * to the result. Following a call to this function, the caller must
109 * refer only to the returned array, not to 'old'.
112 growRuleValue(int oldCount
, int newCount
, __nis_rule_value_t
*old
,
113 __nis_rule_value_t
*rvIn
) {
114 __nis_rule_value_t
*rv
;
116 char *myself
= "growRuleValue";
118 if (newCount
<= 0 || newCount
<= oldCount
)
127 rvIn
= (__nis_rule_value_t
*)&rvZero
;
129 rv
= realloc(old
, newCount
* sizeof (rv
[0]));
131 logmsg(MSG_NOMEM
, LOG_ERR
,
132 "%s: realloc(%d ((%d+%d)*%d)) => 0",
133 myself
, (oldCount
+newCount
) * sizeof (rv
[0]),
134 oldCount
, newCount
, sizeof (rv
[0]));
135 freeRuleValue(old
, oldCount
);
139 (void) memset(&rv
[oldCount
], 0, (newCount
-oldCount
)*sizeof (rv
[0]));
141 for (i
= oldCount
; i
< newCount
; i
++) {
142 rv
[i
].numColumns
= rvIn
->numColumns
;
143 if (rv
[i
].numColumns
> 0) {
144 rv
[i
].colName
= cloneName(rvIn
->colName
,
146 rv
[i
].colVal
= cloneValue(rvIn
->colVal
,
149 if (rv
[i
].numColumns
> 0 &&
150 (rv
[i
].colName
== 0 || rv
[i
].colVal
== 0)) {
151 freeRuleValue(rv
, i
);
154 rv
[i
].numAttrs
= rvIn
->numAttrs
;
155 rv
[i
].attrName
= cloneName(rvIn
->attrName
, rv
[i
].numAttrs
);
156 rv
[i
].attrVal
= cloneValue(rvIn
->attrVal
, rv
[i
].numAttrs
);
157 if (rv
[i
].numAttrs
> 0 &&
158 (rv
[i
].attrName
== 0 || rv
[i
].attrVal
== 0)) {
159 freeRuleValue(rv
, i
);
168 * Merge the source rule-value 's' into the target rule-value 't'.
169 * If successful, unless 's' is a sub-set of 't', 't' will be changed
170 * on exit, and will contain the values from 's' as well.
173 mergeRuleValue(__nis_rule_value_t
*t
, __nis_rule_value_t
*s
) {
181 for (i
= 0; i
< s
->numColumns
; i
++) {
182 for (j
= 0; j
< s
->colVal
[i
].numVals
; j
++) {
183 if (addCol2RuleValue(s
->colVal
[i
].type
, s
->colName
[i
],
184 s
->colVal
[i
].val
[j
].value
,
185 s
->colVal
[i
].val
[j
].length
,
191 for (i
= 0; i
< s
->numAttrs
; i
++) {
192 for (j
= 0; j
< s
->attrVal
[i
].numVals
; j
++) {
193 if (addAttr2RuleValue(s
->attrVal
[i
].type
,
195 s
->attrVal
[i
].val
[j
].value
,
196 s
->attrVal
[i
].val
[j
].length
,
206 addVal2RuleValue(char *msg
, int caseSens
, int snipNul
, __nis_value_type_t type
,
207 char *name
, void *value
, int valueLen
,
208 int *numP
, char ***inNameP
, __nis_value_t
**inValP
) {
209 int i
, j
, copyLen
= valueLen
;
210 __nis_single_value_t
*v
;
211 char **inName
= *inNameP
;
212 __nis_value_t
*inVal
= *inValP
;
214 int (*comp
)(const char *s1
, const char *s2
);
215 char *myself
= "addVal2RuleValue";
217 /* Internal function, so assume arguments OK */
222 /* Should we match the 'inName' value case sensitive or not ? */
229 * String-valued NIS+ entries count the concluding NUL in the
230 * length, while LDAP entries don't. In order to support this,
231 * we implement the following for vt_string value types:
233 * If the last byte of the value isn't a NUL, add one to the
234 * allocated length, so that there always is a NUL after the
235 * value, making it safe to pass to strcmp() etc.
237 * If 'snipNul' is set (presumably meaning we're inserting a
238 * value derived from a NIS+ entry), and the last byte of the
239 * value already is a NUL, decrement the length to be copied by
240 * one. This (a) doesn't count the NUL in the value length, but
241 * (b) still leaves a NUL following the value.
243 * In N2L, for all cases we set 'copyLen' to the number of non-0
244 * characters in 'value'.
246 if (type
== vt_string
&& valueLen
> 0) {
247 char *charval
= value
;
249 if (charval
[valueLen
-1] != '\0')
251 else if (yp2ldap
|| snipNul
)
253 } else if (valueLen
== 0) {
255 * If the 'value' pointer is non-NULL, we create a zero-
256 * length value with one byte allocated. This takes care
262 /* If we already have values for this attribute, add another one */
263 for (i
= 0; i
< num
; i
++) {
264 if ((*comp
)(inName
[i
], name
) == 0) {
267 * Our caller often doesn't know the type of the
268 * value; this happens because the type (vt_string
269 * or vt_ber) is determined by the format in the
270 * rule sets, and we may be invoked as a preparation
271 * for evaluating the rules. Hence, we only use the
272 * supplied 'type' if we need to create a value.
273 * Otherwise, we accept mixed types.
275 * Strings are OK in any case, since we always make
276 * sure to have a zero byte at the end of any value,
280 if (inVal
[i
].numVals
< 0) {
282 * Used to indicate deletion of attribute,
283 * so we honor that and don't add a value.
289 * If 'value' is NULL, we should delete, so
290 * remove any existing values, and set the
291 * 'numVals' field to -1.
294 for (j
= 0; j
< inVal
[i
].numVals
; j
++) {
295 sfree(inVal
[i
].val
[j
].value
);
299 inVal
[i
].numVals
= -1;
303 /* Is the value a duplicate ? */
304 for (j
= 0; j
< inVal
[i
].numVals
; j
++) {
305 if (copyLen
== inVal
[i
].val
[j
].length
&&
306 memcmp(value
, inVal
[i
].val
[j
].value
,
311 if (j
< inVal
[i
].numVals
)
314 /* Not a duplicate, so add the name/value pair */
315 v
= realloc(inVal
[i
].val
,
316 (inVal
[i
].numVals
+1) *
317 sizeof (inVal
[i
].val
[0]));
321 v
[inVal
[i
].numVals
].length
= copyLen
;
322 v
[inVal
[i
].numVals
].value
= am(msg
, valueLen
);
323 if (v
[inVal
[i
].numVals
].value
== 0 &&
328 memcpy(v
[inVal
[i
].numVals
].value
, value
, copyLen
);
335 /* No previous value for this attribute */
338 * value == 0 means deletion, in which case we create a
339 * __nis_value_t with the numVals field set to -1.
342 if ((v
= am(msg
, sizeof (*v
))) == 0)
345 v
->value
= am(msg
, valueLen
);
346 if (v
->value
== 0 && value
!= 0) {
350 memcpy(v
->value
, value
, copyLen
);
353 inVal
= realloc(inVal
, (num
+1)*sizeof (inVal
[0]));
363 inName
= realloc(inName
,
364 (num
+1)*sizeof (inName
[0]));
365 if (inName
== 0 || (inName
[num
] =
366 sdup(msg
, T
, name
)) == 0) {
373 inVal
[num
].type
= type
;
374 inVal
[num
].repeat
= 0;
376 inVal
[num
].numVals
= 1;
379 inVal
[num
].numVals
= -1;
389 addAttr2RuleValue(__nis_value_type_t type
, char *name
, void *value
,
390 int valueLen
, __nis_rule_value_t
*rv
) {
391 char *myself
= "addAttr2RuleValue";
393 if (name
== 0 || rv
== 0)
396 return (addVal2RuleValue(myself
, 0, 0, type
, name
, value
, valueLen
,
397 &rv
->numAttrs
, &rv
->attrName
, &rv
->attrVal
));
401 addSAttr2RuleValue(char *name
, char *value
, __nis_rule_value_t
*rv
) {
402 return (addAttr2RuleValue(vt_string
, name
, value
, slen(value
), rv
));
406 addCol2RuleValue(__nis_value_type_t type
, char *name
, void *value
,
407 int valueLen
, __nis_rule_value_t
*rv
) {
408 char *myself
= "addCol2RuleValue";
410 if (name
== 0 || rv
== 0)
413 return (addVal2RuleValue(myself
, 1, 1, type
, name
, value
, valueLen
,
414 &rv
->numColumns
, &rv
->colName
, &rv
->colVal
));
418 addSCol2RuleValue(char *name
, char *value
, __nis_rule_value_t
*rv
) {
419 return (addCol2RuleValue(vt_string
, name
, value
, slen(value
), rv
));
423 * Given a table mapping, a NIS+ DB query, and (optionally) an existing
424 * and compatible __nis_rule_value_t, return a new __nis_rule_value_t
425 * with the values from the query added.
428 buildNisPlusRuleValue(__nis_table_mapping_t
*t
, db_query
*q
,
429 __nis_rule_value_t
*rv
) {
431 __nis_single_value_t
*sv
;
432 char *myself
= "buildNisPlusRuleValue";
434 if (t
== 0 || q
== 0)
437 rv
= initRuleValue(1, rv
);
441 for (i
= 0; i
< q
->components
.components_len
; i
++) {
446 /* Ignore out-of-range column index */
447 if (q
->components
.components_val
[i
].which_index
>=
452 * Add the query value. A NULL value indicates deletion,
453 * but addCol2RuleValue() takes care of that for us.
455 if (addCol2RuleValue(vt_string
,
456 t
->column
[q
->components
.components_val
[i
].
458 q
->components
.components_val
[i
].index_value
->
459 itemvalue
.itemvalue_val
,
460 q
->components
.components_val
[i
].index_value
->
461 itemvalue
.itemvalue_len
, rv
) != 0) {
462 freeRuleValue(rv
, 1);
473 * Given a LHS rule 'rl', return an array containing the item names,
474 * and the number of elements in the array in '*numItems'.
476 * If there are 'me_match' __nis_mapping_element_t's, we use the
477 * supplied '*rval' (if any) to derive values for the items in
478 * the 'me_match', and add the values thus derived to '*rval' (in
479 * which case the '*rval' pointer will change; the old '*rval'
482 __nis_mapping_item_t
*
483 buildLvalue(__nis_mapping_rlhs_t
*rl
, __nis_value_t
**rval
, int *numItems
) {
484 __nis_value_t
*val
, *r
;
485 __nis_mapping_item_t
*item
= 0;
486 int i
, n
, ni
= 0, nv
= 0;
498 /* If there is more than one element, we concatenate the items */
499 for (i
= 0; i
< rl
->numElements
; i
++) {
500 __nis_mapping_element_t
*e
= &rl
->element
[i
];
501 __nis_mapping_item_t
*olditem
, *tmpitem
= 0;
506 tmpitem
= cloneItem(&e
->element
.item
);
510 * Obtain values for the items in the 'me_match'
513 tmp
= matchMappingItem(e
->element
.match
.fmt
, r
, &nv
,
518 for (n
= 0; n
< nv
; n
++) {
519 r
= concatenateValues(val
, tmp
[n
]);
521 freeValue(tmp
[n
], 1);
524 for (n
++; n
< nv
; n
++) {
525 freeValue(tmp
[n
], 1);
532 if (repeat
&& val
!= 0)
533 val
->repeat
= repeat
;
536 for (n
= 0; n
< e
->element
.match
.numItems
;
539 item
= concatenateMappingItem(item
, ni
,
540 &e
->element
.match
.item
[n
]);
541 freeMappingItem(olditem
, ni
);
554 /* These shouldn't show up on the LHS; ignore */
560 item
= concatenateMappingItem(item
, ni
, tmpitem
);
561 freeMappingItem(olditem
, ni
);
562 freeMappingItem(tmpitem
, 1);
578 buildRvalue(__nis_mapping_rlhs_t
*rl
, __nis_mapping_item_type_t native
,
579 __nis_rule_value_t
*rv
, int *stat
) {
580 __nis_value_t
*val
, *vold
= 0, *vnew
;
582 char *myself
= "buildRvalue";
584 if (rl
== 0 || rl
->numElements
<= 0) {
586 * No RHS indicates deletion, as does a __nis_value_t
587 * with numVals == -1, so we return such a creature.
589 val
= am(myself
, sizeof (*val
));
591 val
->type
= vt_string
;
597 /* If there is more than one element, we concatenate the values */
598 for (i
= 0; i
< rl
->numElements
; i
++) {
599 vnew
= getMappingElement(&rl
->element
[i
], native
, rv
, stat
);
600 val
= concatenateValues(vold
, vnew
);
609 * Derive values for the LDAP attributes specified by the rule 'r',
610 * and add them to the rule-value 'rv'.
612 * If 'doAssign' is set, out-of-context assignments are performed,
616 addLdapRuleValue(__nis_table_mapping_t
*t
,
617 __nis_mapping_rule_t
*r
,
618 __nis_mapping_item_type_t lnative
,
619 __nis_mapping_item_type_t rnative
,
620 __nis_rule_value_t
*rv
,
621 int doAssign
, int *stat
) {
624 __nis_value_t
*rval
, *lval
;
625 __nis_buffer_t b
= {0, 0};
626 __nis_mapping_item_t
*litem
;
630 char *myself
= "addLdapRuleValue";
633 /* Do we have the required values ? */
638 * Establish appropriate search base. For rnative == mit_nisplus,
639 * we're deriving LDAP attribute values from NIS+ columns; in other
640 * words, we're writing to LDAP, and should use the write.base value.
642 __nisdb_get_tsd()->searchBase
= (rnative
== mit_nisplus
) ?
643 t
->objectDN
->write
.base
: t
->objectDN
->read
.base
;
645 /* Set escapeFlag if LHS is "dn" to escape special chars */
646 if (yp2ldap
&& r
->lhs
.numElements
== 1 &&
647 r
->lhs
.element
->type
== me_item
&&
648 r
->lhs
.element
->element
.item
.type
== mit_ldap
&&
649 strcasecmp(r
->lhs
.element
->element
.item
.name
, "dn") == 0) {
650 __nisdb_get_tsd()->escapeFlag
= '1';
653 /* Build the RHS value */
654 rval
= buildRvalue(&r
->rhs
, rnative
, rv
, stat
);
656 /* Reset escapeFlag */
657 __nisdb_get_tsd()->escapeFlag
= '\0';
663 * Special case: If we got no value for the RHS (presumably because
664 * we're missing one or more item values), we don't produce an lval.
665 * Note that this isn't the same thing as an empty value, which we
666 * faithfully try to transmit to LDAP.
668 if (rval
->numVals
== 1 && rval
->val
[0].value
== 0) {
673 /* Obtain the LHS item names */
674 litem
= buildLvalue(&r
->lhs
, &rval
, &numItems
);
680 /* Get string representations of the LHS item names */
682 for (i
= 0; i
< numItems
; i
++) {
683 __nis_value_t
*tmpval
, *old
;
685 tmpval
= getMappingItem(&litem
[i
], lnative
, 0, 0, NULL
);
688 * If the LHS item is out-of-context, we do the
689 * assignment right here.
691 if (doAssign
&& litem
[i
].type
== mit_nisplus
) {
694 err
= storeNisPlus(&litem
[i
], i
, numItems
,
695 rv
, t
->objName
, rval
);
696 if (err
!= NIS_SUCCESS
) {
697 char *iname
= "<unknown>";
700 tmpval
->numVals
== 1)
701 iname
= tmpval
->val
[0].value
;
702 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
703 "%s: NIS+ store \"%s\": %s",
708 freeValue(tmpval
, 1);
710 } else if (doAssign
&& litem
[i
].type
== mit_ldap
&&
711 litem
[i
].searchSpec
.triple
.scope
!=
712 LDAP_SCOPE_UNKNOWN
&&
713 slen(litem
[i
].searchSpec
.triple
.base
) > 0 &&
714 (slen(litem
[i
].searchSpec
.triple
.attrs
) > 0 ||
715 litem
[i
].searchSpec
.triple
.element
!= 0)) {
719 dn
= findDNs(myself
, rv
, 1,
720 t
->objectDN
->write
.base
,
723 stat
= storeLDAP(&litem
[i
], i
, numItems
, rval
,
724 t
->objectDN
, dn
, numDN
);
725 if (stat
!= LDAP_SUCCESS
) {
726 char *iname
= "<unknown>";
729 tmpval
->numVals
== 1)
730 iname
= tmpval
->val
[0].value
;
731 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
732 "%s: LDAP store \"%s\": %s",
734 ldap_err2string(stat
));
737 freeValue(tmpval
, 1);
742 lval
= concatenateValues(old
, tmpval
);
743 freeValue(tmpval
, 1);
747 /* Don't need the LHS items themselves anymore */
748 freeMappingItem(litem
, numItems
);
751 * If we don't have an 'lval' (probably because all litem[i]:s
752 * were out-of-context assignments), we're done.
754 if (lval
== 0 || lval
->numVals
<= 0) {
760 for (i
= 0, j
= 0; i
< lval
->numVals
; i
++) {
761 /* Special case: rval->numVals < 0 means deletion */
762 if (rval
->numVals
< 0) {
763 (void) addAttr2RuleValue(rval
->type
,
764 lval
->val
[i
].value
, 0, 0, rv
);
767 /* If we're out of values, repeat the last one */
768 if (j
>= rval
->numVals
)
769 j
= (rval
->numVals
> 0) ? rval
->numVals
-1 : 0;
770 for (0; j
< rval
->numVals
; j
++) {
772 * If this is the 'dn', and the value ends in a
773 * comma, append the appropriate search base.
775 if (strcasecmp("dn", lval
->val
[i
].value
) == 0 &&
776 lastChar(&rval
->val
[j
]) == ',' &&
777 t
->objectDN
->write
.scope
!=
778 LDAP_SCOPE_UNKNOWN
) {
782 nval
= appendString2SingleVal(
783 t
->objectDN
->write
.base
, &rval
->val
[j
],
785 if (nval
!= 0 && nlen
>= 0) {
786 sfree(rval
->val
[j
].value
);
787 rval
->val
[j
].value
= nval
;
788 rval
->val
[j
].length
= nlen
;
791 (void) addAttr2RuleValue(rval
->type
,
792 lval
->val
[i
].value
, rval
->val
[j
].value
,
793 rval
->val
[j
].length
, rv
);
795 * If the lval is multi-valued, go on to the
796 * other values; otherwise, quit (but increment
797 * the 'rval' value index).
814 * Remove the indicated attribute, and any values for it, from the
818 delAttrFromRuleValue(__nis_rule_value_t
*rv
, char *attrName
) {
821 if (rv
== 0 || attrName
== 0)
824 for (i
= 0; i
< rv
->numAttrs
; i
++) {
825 if (strcasecmp(attrName
, rv
->attrName
[i
]) == 0) {
828 for (j
= 0; j
< rv
->attrVal
[i
].numVals
; j
++)
829 sfree(rv
->attrVal
[i
].val
[j
].value
);
830 if (rv
->attrVal
[i
].numVals
> 0)
831 sfree(rv
->attrVal
[i
].val
);
833 sfree(rv
->attrName
[i
]);
835 /* Move up the rest of the attribute names/values */
836 for (j
= i
+1; j
< rv
->numAttrs
; j
++) {
837 rv
->attrName
[j
-1] = rv
->attrName
[j
];
838 rv
->attrVal
[j
-1] = rv
->attrVal
[j
];
849 * Remove the indicated column, and any values for it, from the
853 delColFromRuleValue(__nis_rule_value_t
*rv
, char *colName
) {
856 if (rv
== 0 || colName
== 0)
859 for (i
= 0; i
< rv
->numColumns
; i
++) {
860 if (strcmp(colName
, rv
->colName
[i
]) == 0) {
863 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++)
864 sfree(rv
->colVal
[i
].val
[j
].value
);
865 if (rv
->colVal
[i
].numVals
> 0)
866 sfree(rv
->colVal
[i
].val
);
868 sfree(rv
->colName
[i
]);
870 /* Move up the rest of the column names/values */
871 for (j
= i
+1; j
< rv
->numColumns
; j
++) {
872 rv
->colName
[j
-1] = rv
->colName
[j
];
873 rv
->colVal
[j
-1] = rv
->colVal
[j
];
884 * Add the write-mode object classes specified by 'objClassAttrs' to the
886 * If there's an error, 'rv' is deleted, and NULL returned.
889 addObjectClasses(__nis_rule_value_t
*rv
, char *objClassAttrs
) {
890 char *filter
= 0, **fc
= 0;
894 * Expect to only use this for existing rule-values, so rv == 0 is
901 * If 'objClassAttrs' is NULL, we trivially have nothing to do.
902 * Assume the caller knows what it's doing, and return success.
904 if (objClassAttrs
== 0)
908 * Make an AND-filter of the object classes, and split into
909 * components. (Yes, this is a bit round-about, but leverages
910 * existing functions.)
912 filter
= makeFilter(objClassAttrs
);
914 freeRuleValue(rv
, 1);
918 fc
= makeFilterComp(filter
, &nfc
);
919 if (fc
== 0 || nfc
<= 0) {
921 freeRuleValue(rv
, 1);
925 /* Add the objectClass attributes to the rule-value */
926 for (i
= 0; i
< nfc
; i
++) {
930 /* Skip if not of the "name=value" form */
931 if ((value
= strchr(name
, '=')) == 0)
937 /* Skip if the attribute name isn't "objectClass" */
938 if (strcasecmp("objectClass", name
) != 0)
941 if (addSAttr2RuleValue(name
, value
, rv
) != 0) {
943 freeFilterComp(fc
, nfc
);
944 freeRuleValue(rv
, 1);
950 freeFilterComp(fc
, nfc
);
957 valString(__nis_value_t
*val
) {
960 if (val
== 0 || val
->type
!= vt_string
)
963 for (i
= 0; i
< val
->numVals
; i
++) {
964 /* Look for a non-NULL, non-zero length value */
965 if (val
->val
[i
].value
!= 0 && val
->val
[i
].length
> 0) {
966 char *v
= val
->val
[i
].value
;
969 * Check that there's a NUL at the end. True,
970 * if there isn't, we may be looking beyond
971 * allocated memory. However, we would have done
972 * so in any case when the supposed string was
973 * traversed (printed, etc.), very possibly by
974 * a lot more than one byte. So, it's better to
975 * take a small risk here than a large one later.
977 if (v
[val
->val
[i
].length
-1] == '\0' ||
978 v
[val
->val
[i
].length
] == '\0')
987 findVal(char *name
, __nis_rule_value_t
*rv
, __nis_mapping_item_type_t type
) {
990 if (type
== mit_nisplus
) {
991 for (i
= 0; i
< rv
->numColumns
; i
++) {
992 if (rv
->colName
[i
] == 0)
994 if (strcmp(name
, rv
->colName
[i
]) == 0) {
995 return (valString(&rv
->colVal
[i
]));
998 } else if (type
== mit_ldap
) {
999 for (i
= 0; i
< rv
->numAttrs
; i
++) {
1000 if (rv
->attrName
[i
] == 0)
1002 if (strcasecmp(name
, rv
->attrName
[i
]) == 0) {
1003 return (valString(&rv
->attrVal
[i
]));
1011 static char *norv
= "<NIL>";
1012 static char *unknown
= "<unknown>";
1015 * Attempt to derive a string identifying the rule-value 'rv'. The
1016 * returned string is a pointer, either into 'rv', or to static
1017 * storage, and must not be freed.
1020 rvId(__nis_rule_value_t
*rv
, __nis_mapping_item_type_t type
) {
1026 if (rv
->numColumns
> 0 && type
== mit_nisplus
) {
1028 * Look for a column called "cname" or "name".
1029 * If that fails, try "key" or "alias".
1031 if ((v
= findVal("cname", rv
, type
)) != 0)
1033 else if ((v
= findVal("name", rv
, type
)) != 0)
1035 else if ((v
= findVal("key", rv
, type
)) != 0)
1037 else if ((v
= findVal("alias", rv
, type
)) != 0)
1039 } else if (rv
->numAttrs
> 0 && type
== mit_ldap
) {
1041 * Look for "dn", or "cn".
1043 if ((v
= findVal("dn", rv
, type
)) != 0)
1045 else if ((v
= findVal("cn", rv
, type
)) != 0)
1053 * Merge the rule-values with the same DN into one. Each rule-value
1054 * in the returned array will have unique 'dn'. On entry, *numVals
1055 * contains the number of rule-values in 'rv'. On exit, it contains
1056 * the number of rule-values in the returned array or -1 on error.
1058 __nis_rule_value_t
*
1059 mergeRuleValueWithSameDN(__nis_rule_value_t
*rv
, int *numVals
) {
1060 __nis_rule_value_t
*rvq
= 0;
1068 for (i
= 0; i
< *numVals
; i
++) {
1069 if ((dn
= findVal("dn", &rv
[i
], mit_ldap
)) != 0) {
1070 for (j
= 0; j
< count
; j
++) {
1071 if ((odn
= findVal("dn", &rvq
[j
],
1073 /* case sensitive compare */
1074 if (strcmp(dn
, odn
) != 0)
1076 if (mergeRuleValue(&rvq
[j
],
1078 freeRuleValue(rvq
, count
);
1084 freeRuleValue(rvq
, count
);
1089 /* if no match, then add it to the rulevalue array */
1091 rvq
= growRuleValue(count
, count
+ 1, rvq
,