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.
34 #include "ldap_util.h"
36 #include "ldap_attr.h"
37 #include "ldap_ldap.h"
38 #include "ldap_ruleval.h"
42 * Free an array of 'count' rule-value elements.
45 freeRuleValue(__nis_rule_value_t
*rv
, int count
) {
51 for (n
= 0; n
< count
; n
++) {
53 if (rv
[n
].colName
!= 0) {
54 for (i
= 0; i
< rv
[n
].numColumns
; i
++) {
55 sfree(rv
[n
].colName
[i
]);
59 if (rv
[n
].colVal
!= 0) {
60 for (i
= 0; i
< rv
[n
].numColumns
; i
++) {
61 for (j
= 0; j
< rv
[n
].colVal
[i
].numVals
; j
++) {
62 sfree(rv
[n
].colVal
[i
].val
[j
].value
);
64 if (rv
[n
].colVal
[i
].numVals
> 0)
65 sfree(rv
[n
].colVal
[i
].val
);
70 if (rv
[n
].attrName
!= 0) {
71 for (i
= 0; i
< rv
[n
].numAttrs
; i
++) {
72 sfree(rv
[n
].attrName
[i
]);
76 if (rv
[n
].attrVal
!= 0) {
77 for (i
= 0; i
< rv
[n
].numAttrs
; i
++) {
78 for (j
= 0; j
< rv
[n
].attrVal
[i
].numVals
;
80 sfree(rv
[n
].attrVal
[i
].val
[j
].value
);
82 if (rv
[n
].attrVal
[i
].numVals
> 0)
83 sfree(rv
[n
].attrVal
[i
].val
);
93 * Return an array of 'count' __nis_rule_value_t elements, initialized
94 * to be copies of 'rvIn' if supplied; empty otherwise.
97 initRuleValue(int count
, __nis_rule_value_t
*rvIn
) {
98 return (growRuleValue(0, count
, 0, rvIn
));
101 static const __nis_rule_value_t rvZero
= {0};
104 * Grow 'old' from 'oldCount' to 'newCount' elements, initialize the
105 * new portion to 'rvIn' (empty if not supplied), and return a pointer
106 * to the result. Following a call to this function, the caller must
107 * refer only to the returned array, not to 'old'.
110 growRuleValue(int oldCount
, int newCount
, __nis_rule_value_t
*old
,
111 __nis_rule_value_t
*rvIn
) {
112 __nis_rule_value_t
*rv
;
114 char *myself
= "growRuleValue";
116 if (newCount
<= 0 || newCount
<= oldCount
)
125 rvIn
= (__nis_rule_value_t
*)&rvZero
;
127 rv
= realloc(old
, newCount
* sizeof (rv
[0]));
129 logmsg(MSG_NOMEM
, LOG_ERR
,
130 "%s: realloc(%d ((%d+%d)*%d)) => 0",
131 myself
, (oldCount
+newCount
) * sizeof (rv
[0]),
132 oldCount
, newCount
, sizeof (rv
[0]));
133 freeRuleValue(old
, oldCount
);
137 (void) memset(&rv
[oldCount
], 0, (newCount
-oldCount
)*sizeof (rv
[0]));
139 for (i
= oldCount
; i
< newCount
; i
++) {
140 rv
[i
].numColumns
= rvIn
->numColumns
;
141 if (rv
[i
].numColumns
> 0) {
142 rv
[i
].colName
= cloneName(rvIn
->colName
,
144 rv
[i
].colVal
= cloneValue(rvIn
->colVal
,
147 if (rv
[i
].numColumns
> 0 &&
148 (rv
[i
].colName
== 0 || rv
[i
].colVal
== 0)) {
149 freeRuleValue(rv
, i
);
152 rv
[i
].numAttrs
= rvIn
->numAttrs
;
153 rv
[i
].attrName
= cloneName(rvIn
->attrName
, rv
[i
].numAttrs
);
154 rv
[i
].attrVal
= cloneValue(rvIn
->attrVal
, rv
[i
].numAttrs
);
155 if (rv
[i
].numAttrs
> 0 &&
156 (rv
[i
].attrName
== 0 || rv
[i
].attrVal
== 0)) {
157 freeRuleValue(rv
, i
);
166 * Merge the source rule-value 's' into the target rule-value 't'.
167 * If successful, unless 's' is a sub-set of 't', 't' will be changed
168 * on exit, and will contain the values from 's' as well.
171 mergeRuleValue(__nis_rule_value_t
*t
, __nis_rule_value_t
*s
) {
179 for (i
= 0; i
< s
->numColumns
; i
++) {
180 for (j
= 0; j
< s
->colVal
[i
].numVals
; j
++) {
181 if (addCol2RuleValue(s
->colVal
[i
].type
, s
->colName
[i
],
182 s
->colVal
[i
].val
[j
].value
,
183 s
->colVal
[i
].val
[j
].length
,
189 for (i
= 0; i
< s
->numAttrs
; i
++) {
190 for (j
= 0; j
< s
->attrVal
[i
].numVals
; j
++) {
191 if (addAttr2RuleValue(s
->attrVal
[i
].type
,
193 s
->attrVal
[i
].val
[j
].value
,
194 s
->attrVal
[i
].val
[j
].length
,
204 addVal2RuleValue(char *msg
, int caseSens
, int snipNul
, __nis_value_type_t type
,
205 char *name
, void *value
, int valueLen
,
206 int *numP
, char ***inNameP
, __nis_value_t
**inValP
) {
207 int i
, j
, copyLen
= valueLen
;
208 __nis_single_value_t
*v
;
209 char **inName
= *inNameP
;
210 __nis_value_t
*inVal
= *inValP
;
212 int (*comp
)(const char *s1
, const char *s2
);
213 char *myself
= "addVal2RuleValue";
215 /* Internal function, so assume arguments OK */
220 /* Should we match the 'inName' value case sensitive or not ? */
227 * String-valued NIS+ entries count the concluding NUL in the
228 * length, while LDAP entries don't. In order to support this,
229 * we implement the following for vt_string value types:
231 * If the last byte of the value isn't a NUL, add one to the
232 * allocated length, so that there always is a NUL after the
233 * value, making it safe to pass to strcmp() etc.
235 * If 'snipNul' is set (presumably meaning we're inserting a
236 * value derived from a NIS+ entry), and the last byte of the
237 * value already is a NUL, decrement the length to be copied by
238 * one. This (a) doesn't count the NUL in the value length, but
239 * (b) still leaves a NUL following the value.
241 * In N2L, for all cases we set 'copyLen' to the number of non-0
242 * characters in 'value'.
244 if (type
== vt_string
&& valueLen
> 0) {
245 char *charval
= value
;
247 if (charval
[valueLen
-1] != '\0')
249 else if (yp2ldap
|| snipNul
)
251 } else if (valueLen
== 0) {
253 * If the 'value' pointer is non-NULL, we create a zero-
254 * length value with one byte allocated. This takes care
260 /* If we already have values for this attribute, add another one */
261 for (i
= 0; i
< num
; i
++) {
262 if ((*comp
)(inName
[i
], name
) == 0) {
265 * Our caller often doesn't know the type of the
266 * value; this happens because the type (vt_string
267 * or vt_ber) is determined by the format in the
268 * rule sets, and we may be invoked as a preparation
269 * for evaluating the rules. Hence, we only use the
270 * supplied 'type' if we need to create a value.
271 * Otherwise, we accept mixed types.
273 * Strings are OK in any case, since we always make
274 * sure to have a zero byte at the end of any value,
278 if (inVal
[i
].numVals
< 0) {
280 * Used to indicate deletion of attribute,
281 * so we honor that and don't add a value.
287 * If 'value' is NULL, we should delete, so
288 * remove any existing values, and set the
289 * 'numVals' field to -1.
292 for (j
= 0; j
< inVal
[i
].numVals
; j
++) {
293 sfree(inVal
[i
].val
[j
].value
);
297 inVal
[i
].numVals
= -1;
301 /* Is the value a duplicate ? */
302 for (j
= 0; j
< inVal
[i
].numVals
; j
++) {
303 if (copyLen
== inVal
[i
].val
[j
].length
&&
304 memcmp(value
, inVal
[i
].val
[j
].value
,
309 if (j
< inVal
[i
].numVals
)
312 /* Not a duplicate, so add the name/value pair */
313 v
= realloc(inVal
[i
].val
,
314 (inVal
[i
].numVals
+1) *
315 sizeof (inVal
[i
].val
[0]));
319 v
[inVal
[i
].numVals
].length
= copyLen
;
320 v
[inVal
[i
].numVals
].value
= am(msg
, valueLen
);
321 if (v
[inVal
[i
].numVals
].value
== 0 &&
326 memcpy(v
[inVal
[i
].numVals
].value
, value
, copyLen
);
333 /* No previous value for this attribute */
336 * value == 0 means deletion, in which case we create a
337 * __nis_value_t with the numVals field set to -1.
340 if ((v
= am(msg
, sizeof (*v
))) == 0)
343 v
->value
= am(msg
, valueLen
);
344 if (v
->value
== 0 && value
!= 0) {
348 memcpy(v
->value
, value
, copyLen
);
351 inVal
= realloc(inVal
, (num
+1)*sizeof (inVal
[0]));
361 inName
= realloc(inName
,
362 (num
+1)*sizeof (inName
[0]));
363 if (inName
== 0 || (inName
[num
] =
364 sdup(msg
, T
, name
)) == 0) {
371 inVal
[num
].type
= type
;
372 inVal
[num
].repeat
= 0;
374 inVal
[num
].numVals
= 1;
377 inVal
[num
].numVals
= -1;
387 addAttr2RuleValue(__nis_value_type_t type
, char *name
, void *value
,
388 int valueLen
, __nis_rule_value_t
*rv
) {
389 char *myself
= "addAttr2RuleValue";
391 if (name
== 0 || rv
== 0)
394 return (addVal2RuleValue(myself
, 0, 0, type
, name
, value
, valueLen
,
395 &rv
->numAttrs
, &rv
->attrName
, &rv
->attrVal
));
399 addSAttr2RuleValue(char *name
, char *value
, __nis_rule_value_t
*rv
) {
400 return (addAttr2RuleValue(vt_string
, name
, value
, slen(value
), rv
));
404 addCol2RuleValue(__nis_value_type_t type
, char *name
, void *value
,
405 int valueLen
, __nis_rule_value_t
*rv
) {
406 char *myself
= "addCol2RuleValue";
408 if (name
== 0 || rv
== 0)
411 return (addVal2RuleValue(myself
, 1, 1, type
, name
, value
, valueLen
,
412 &rv
->numColumns
, &rv
->colName
, &rv
->colVal
));
416 addSCol2RuleValue(char *name
, char *value
, __nis_rule_value_t
*rv
) {
417 return (addCol2RuleValue(vt_string
, name
, value
, slen(value
), rv
));
421 * Given a table mapping, a NIS+ DB query, and (optionally) an existing
422 * and compatible __nis_rule_value_t, return a new __nis_rule_value_t
423 * with the values from the query added.
426 buildNisPlusRuleValue(__nis_table_mapping_t
*t
, db_query
*q
,
427 __nis_rule_value_t
*rv
) {
430 if (t
== 0 || q
== 0)
433 rv
= initRuleValue(1, rv
);
437 for (i
= 0; i
< q
->components
.components_len
; i
++) {
439 /* Ignore out-of-range column index */
440 if (q
->components
.components_val
[i
].which_index
>=
445 * Add the query value. A NULL value indicates deletion,
446 * but addCol2RuleValue() takes care of that for us.
448 if (addCol2RuleValue(vt_string
,
449 t
->column
[q
->components
.components_val
[i
].
451 q
->components
.components_val
[i
].index_value
->
452 itemvalue
.itemvalue_val
,
453 q
->components
.components_val
[i
].index_value
->
454 itemvalue
.itemvalue_len
, rv
) != 0) {
455 freeRuleValue(rv
, 1);
466 * Given a LHS rule 'rl', return an array containing the item names,
467 * and the number of elements in the array in '*numItems'.
469 * If there are 'me_match' __nis_mapping_element_t's, we use the
470 * supplied '*rval' (if any) to derive values for the items in
471 * the 'me_match', and add the values thus derived to '*rval' (in
472 * which case the '*rval' pointer will change; the old '*rval'
475 __nis_mapping_item_t
*
476 buildLvalue(__nis_mapping_rlhs_t
*rl
, __nis_value_t
**rval
, int *numItems
) {
477 __nis_value_t
*val
, *r
;
478 __nis_mapping_item_t
*item
= 0;
479 int i
, n
, ni
= 0, nv
= 0;
491 /* If there is more than one element, we concatenate the items */
492 for (i
= 0; i
< rl
->numElements
; i
++) {
493 __nis_mapping_element_t
*e
= &rl
->element
[i
];
494 __nis_mapping_item_t
*olditem
, *tmpitem
= 0;
499 tmpitem
= cloneItem(&e
->element
.item
);
503 * Obtain values for the items in the 'me_match'
506 tmp
= matchMappingItem(e
->element
.match
.fmt
, r
, &nv
,
511 for (n
= 0; n
< nv
; n
++) {
512 r
= concatenateValues(val
, tmp
[n
]);
514 freeValue(tmp
[n
], 1);
517 for (n
++; n
< nv
; n
++) {
518 freeValue(tmp
[n
], 1);
525 if (repeat
&& val
!= 0)
526 val
->repeat
= repeat
;
529 for (n
= 0; n
< e
->element
.match
.numItems
;
532 item
= concatenateMappingItem(item
, ni
,
533 &e
->element
.match
.item
[n
]);
534 freeMappingItem(olditem
, ni
);
547 /* These shouldn't show up on the LHS; ignore */
553 item
= concatenateMappingItem(item
, ni
, tmpitem
);
554 freeMappingItem(olditem
, ni
);
555 freeMappingItem(tmpitem
, 1);
571 buildRvalue(__nis_mapping_rlhs_t
*rl
, __nis_mapping_item_type_t native
,
572 __nis_rule_value_t
*rv
, int *stat
) {
573 __nis_value_t
*val
, *vold
= 0, *vnew
;
575 char *myself
= "buildRvalue";
577 if (rl
== 0 || rl
->numElements
<= 0) {
579 * No RHS indicates deletion, as does a __nis_value_t
580 * with numVals == -1, so we return such a creature.
582 val
= am(myself
, sizeof (*val
));
584 val
->type
= vt_string
;
590 /* If there is more than one element, we concatenate the values */
591 for (i
= 0; i
< rl
->numElements
; i
++) {
592 vnew
= getMappingElement(&rl
->element
[i
], native
, rv
, stat
);
593 val
= concatenateValues(vold
, vnew
);
602 * Derive values for the LDAP attributes specified by the rule 'r',
603 * and add them to the rule-value 'rv'.
605 * If 'doAssign' is set, out-of-context assignments are performed,
609 addLdapRuleValue(__nis_table_mapping_t
*t
,
610 __nis_mapping_rule_t
*r
,
611 __nis_mapping_item_type_t lnative
,
612 __nis_mapping_item_type_t rnative
,
613 __nis_rule_value_t
*rv
,
614 int doAssign
, int *stat
) {
616 __nis_value_t
*rval
, *lval
;
617 __nis_mapping_item_t
*litem
;
621 char *myself
= "addLdapRuleValue";
624 /* Do we have the required values ? */
629 * Establish appropriate search base. For rnative == mit_nisplus,
630 * we're deriving LDAP attribute values from NIS+ columns; in other
631 * words, we're writing to LDAP, and should use the write.base value.
633 __nisdb_get_tsd()->searchBase
= (rnative
== mit_nisplus
) ?
634 t
->objectDN
->write
.base
: t
->objectDN
->read
.base
;
636 /* Set escapeFlag if LHS is "dn" to escape special chars */
637 if (yp2ldap
&& r
->lhs
.numElements
== 1 &&
638 r
->lhs
.element
->type
== me_item
&&
639 r
->lhs
.element
->element
.item
.type
== mit_ldap
&&
640 strcasecmp(r
->lhs
.element
->element
.item
.name
, "dn") == 0) {
641 __nisdb_get_tsd()->escapeFlag
= '1';
644 /* Build the RHS value */
645 rval
= buildRvalue(&r
->rhs
, rnative
, rv
, stat
);
647 /* Reset escapeFlag */
648 __nisdb_get_tsd()->escapeFlag
= '\0';
654 * Special case: If we got no value for the RHS (presumably because
655 * we're missing one or more item values), we don't produce an lval.
656 * Note that this isn't the same thing as an empty value, which we
657 * faithfully try to transmit to LDAP.
659 if (rval
->numVals
== 1 && rval
->val
[0].value
== 0) {
664 /* Obtain the LHS item names */
665 litem
= buildLvalue(&r
->lhs
, &rval
, &numItems
);
671 /* Get string representations of the LHS item names */
673 for (i
= 0; i
< numItems
; i
++) {
674 __nis_value_t
*tmpval
, *old
;
676 tmpval
= getMappingItem(&litem
[i
], lnative
, 0, 0, NULL
);
679 * If the LHS item is out-of-context, we do the
680 * assignment right here.
682 if (doAssign
&& litem
[i
].type
== mit_ldap
&&
683 litem
[i
].searchSpec
.triple
.scope
!=
684 LDAP_SCOPE_UNKNOWN
&&
685 slen(litem
[i
].searchSpec
.triple
.base
) > 0 &&
686 (slen(litem
[i
].searchSpec
.triple
.attrs
) > 0 ||
687 litem
[i
].searchSpec
.triple
.element
!= 0)) {
691 dn
= findDNs(myself
, rv
, 1,
692 t
->objectDN
->write
.base
,
695 stat
= storeLDAP(&litem
[i
], i
, numItems
, rval
,
696 t
->objectDN
, dn
, numDN
);
697 if (stat
!= LDAP_SUCCESS
) {
698 char *iname
= "<unknown>";
701 tmpval
->numVals
== 1)
702 iname
= tmpval
->val
[0].value
;
703 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
704 "%s: LDAP store \"%s\": %s",
706 ldap_err2string(stat
));
709 freeValue(tmpval
, 1);
714 lval
= concatenateValues(old
, tmpval
);
715 freeValue(tmpval
, 1);
719 /* Don't need the LHS items themselves anymore */
720 freeMappingItem(litem
, numItems
);
723 * If we don't have an 'lval' (probably because all litem[i]:s
724 * were out-of-context assignments), we're done.
726 if (lval
== 0 || lval
->numVals
<= 0) {
732 for (i
= 0, j
= 0; i
< lval
->numVals
; i
++) {
733 /* Special case: rval->numVals < 0 means deletion */
734 if (rval
->numVals
< 0) {
735 (void) addAttr2RuleValue(rval
->type
,
736 lval
->val
[i
].value
, 0, 0, rv
);
739 /* If we're out of values, repeat the last one */
740 if (j
>= rval
->numVals
)
741 j
= (rval
->numVals
> 0) ? rval
->numVals
-1 : 0;
742 for (; j
< rval
->numVals
; j
++) {
744 * If this is the 'dn', and the value ends in a
745 * comma, append the appropriate search base.
747 if (strcasecmp("dn", lval
->val
[i
].value
) == 0 &&
748 lastChar(&rval
->val
[j
]) == ',' &&
749 t
->objectDN
->write
.scope
!=
750 LDAP_SCOPE_UNKNOWN
) {
754 nval
= appendString2SingleVal(
755 t
->objectDN
->write
.base
, &rval
->val
[j
],
757 if (nval
!= 0 && nlen
>= 0) {
758 sfree(rval
->val
[j
].value
);
759 rval
->val
[j
].value
= nval
;
760 rval
->val
[j
].length
= nlen
;
763 (void) addAttr2RuleValue(rval
->type
,
764 lval
->val
[i
].value
, rval
->val
[j
].value
,
765 rval
->val
[j
].length
, rv
);
767 * If the lval is multi-valued, go on to the
768 * other values; otherwise, quit (but increment
769 * the 'rval' value index).
786 * Remove the indicated attribute, and any values for it, from the
790 delAttrFromRuleValue(__nis_rule_value_t
*rv
, char *attrName
) {
793 if (rv
== 0 || attrName
== 0)
796 for (i
= 0; i
< rv
->numAttrs
; i
++) {
797 if (strcasecmp(attrName
, rv
->attrName
[i
]) == 0) {
800 for (j
= 0; j
< rv
->attrVal
[i
].numVals
; j
++)
801 sfree(rv
->attrVal
[i
].val
[j
].value
);
802 if (rv
->attrVal
[i
].numVals
> 0)
803 sfree(rv
->attrVal
[i
].val
);
805 sfree(rv
->attrName
[i
]);
807 /* Move up the rest of the attribute names/values */
808 for (j
= i
+1; j
< rv
->numAttrs
; j
++) {
809 rv
->attrName
[j
-1] = rv
->attrName
[j
];
810 rv
->attrVal
[j
-1] = rv
->attrVal
[j
];
821 * Remove the indicated column, and any values for it, from the
825 delColFromRuleValue(__nis_rule_value_t
*rv
, char *colName
) {
828 if (rv
== 0 || colName
== 0)
831 for (i
= 0; i
< rv
->numColumns
; i
++) {
832 if (strcmp(colName
, rv
->colName
[i
]) == 0) {
835 for (j
= 0; j
< rv
->colVal
[i
].numVals
; j
++)
836 sfree(rv
->colVal
[i
].val
[j
].value
);
837 if (rv
->colVal
[i
].numVals
> 0)
838 sfree(rv
->colVal
[i
].val
);
840 sfree(rv
->colName
[i
]);
842 /* Move up the rest of the column names/values */
843 for (j
= i
+1; j
< rv
->numColumns
; j
++) {
844 rv
->colName
[j
-1] = rv
->colName
[j
];
845 rv
->colVal
[j
-1] = rv
->colVal
[j
];
856 * Add the write-mode object classes specified by 'objClassAttrs' to the
858 * If there's an error, 'rv' is deleted, and NULL returned.
861 addObjectClasses(__nis_rule_value_t
*rv
, char *objClassAttrs
) {
862 char *filter
= 0, **fc
= 0;
866 * Expect to only use this for existing rule-values, so rv == 0 is
873 * If 'objClassAttrs' is NULL, we trivially have nothing to do.
874 * Assume the caller knows what it's doing, and return success.
876 if (objClassAttrs
== 0)
880 * Make an AND-filter of the object classes, and split into
881 * components. (Yes, this is a bit round-about, but leverages
882 * existing functions.)
884 filter
= makeFilter(objClassAttrs
);
886 freeRuleValue(rv
, 1);
890 fc
= makeFilterComp(filter
, &nfc
);
891 if (fc
== 0 || nfc
<= 0) {
893 freeRuleValue(rv
, 1);
897 /* Add the objectClass attributes to the rule-value */
898 for (i
= 0; i
< nfc
; i
++) {
902 /* Skip if not of the "name=value" form */
903 if ((value
= strchr(name
, '=')) == 0)
909 /* Skip if the attribute name isn't "objectClass" */
910 if (strcasecmp("objectClass", name
) != 0)
913 if (addSAttr2RuleValue(name
, value
, rv
) != 0) {
915 freeFilterComp(fc
, nfc
);
916 freeRuleValue(rv
, 1);
922 freeFilterComp(fc
, nfc
);
929 valString(__nis_value_t
*val
) {
932 if (val
== 0 || val
->type
!= vt_string
)
935 for (i
= 0; i
< val
->numVals
; i
++) {
936 /* Look for a non-NULL, non-zero length value */
937 if (val
->val
[i
].value
!= 0 && val
->val
[i
].length
> 0) {
938 char *v
= val
->val
[i
].value
;
941 * Check that there's a NUL at the end. True,
942 * if there isn't, we may be looking beyond
943 * allocated memory. However, we would have done
944 * so in any case when the supposed string was
945 * traversed (printed, etc.), very possibly by
946 * a lot more than one byte. So, it's better to
947 * take a small risk here than a large one later.
949 if (v
[val
->val
[i
].length
-1] == '\0' ||
950 v
[val
->val
[i
].length
] == '\0')
959 findVal(char *name
, __nis_rule_value_t
*rv
, __nis_mapping_item_type_t type
) {
962 if (type
== mit_nisplus
) {
963 for (i
= 0; i
< rv
->numColumns
; i
++) {
964 if (rv
->colName
[i
] == 0)
966 if (strcmp(name
, rv
->colName
[i
]) == 0) {
967 return (valString(&rv
->colVal
[i
]));
970 } else if (type
== mit_ldap
) {
971 for (i
= 0; i
< rv
->numAttrs
; i
++) {
972 if (rv
->attrName
[i
] == 0)
974 if (strcasecmp(name
, rv
->attrName
[i
]) == 0) {
975 return (valString(&rv
->attrVal
[i
]));
983 static char *norv
= "<NIL>";
984 static char *unknown
= "<unknown>";
987 * Attempt to derive a string identifying the rule-value 'rv'. The
988 * returned string is a pointer, either into 'rv', or to static
989 * storage, and must not be freed.
992 rvId(__nis_rule_value_t
*rv
, __nis_mapping_item_type_t type
) {
998 if (rv
->numColumns
> 0 && type
== mit_nisplus
) {
1000 * Look for a column called "cname" or "name".
1001 * If that fails, try "key" or "alias".
1003 if ((v
= findVal("cname", rv
, type
)) != 0)
1005 else if ((v
= findVal("name", rv
, type
)) != 0)
1007 else if ((v
= findVal("key", rv
, type
)) != 0)
1009 else if ((v
= findVal("alias", rv
, type
)) != 0)
1011 } else if (rv
->numAttrs
> 0 && type
== mit_ldap
) {
1013 * Look for "dn", or "cn".
1015 if ((v
= findVal("dn", rv
, type
)) != 0)
1017 else if ((v
= findVal("cn", rv
, type
)) != 0)
1025 * Merge the rule-values with the same DN into one. Each rule-value
1026 * in the returned array will have unique 'dn'. On entry, *numVals
1027 * contains the number of rule-values in 'rv'. On exit, it contains
1028 * the number of rule-values in the returned array or -1 on error.
1030 __nis_rule_value_t
*
1031 mergeRuleValueWithSameDN(__nis_rule_value_t
*rv
, int *numVals
) {
1032 __nis_rule_value_t
*rvq
= 0;
1040 for (i
= 0; i
< *numVals
; i
++) {
1041 if ((dn
= findVal("dn", &rv
[i
], mit_ldap
)) != 0) {
1042 for (j
= 0; j
< count
; j
++) {
1043 if ((odn
= findVal("dn", &rvq
[j
],
1045 /* case sensitive compare */
1046 if (strcmp(dn
, odn
) != 0)
1048 if (mergeRuleValue(&rvq
[j
],
1050 freeRuleValue(rvq
, count
);
1056 freeRuleValue(rvq
, count
);
1061 /* if no match, then add it to the rulevalue array */
1063 rvq
= growRuleValue(count
, count
+ 1, rvq
,