ldap_ruleval.c revision a87701e9837f8a9ee9e4c4d3186295c0e29f743f
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2015 Gary Mills
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <lber.h>
#include <ldap.h>
#include <strings.h>
#include "nisdb_mt.h"
#include "ldap_util.h"
#include "ldap_val.h"
#include "ldap_attr.h"
#include "ldap_ldap.h"
#include "ldap_ruleval.h"
/*
* Free an array of 'count' rule-value elements.
*/
void
freeRuleValue(__nis_rule_value_t *rv, int count) {
int n, i, j;
if (rv == 0)
return;
for (n = 0; n < count; n++) {
if (rv[n].colName != 0) {
for (i = 0; i < rv[n].numColumns; i++) {
sfree(rv[n].colName[i]);
}
free(rv[n].colName);
}
if (rv[n].colVal != 0) {
for (i = 0; i < rv[n].numColumns; i++) {
for (j = 0; j < rv[n].colVal[i].numVals; j++) {
sfree(rv[n].colVal[i].val[j].value);
}
if (rv[n].colVal[i].numVals > 0)
sfree(rv[n].colVal[i].val);
}
free(rv[n].colVal);
}
if (rv[n].attrName != 0) {
for (i = 0; i < rv[n].numAttrs; i++) {
sfree(rv[n].attrName[i]);
}
free(rv[n].attrName);
}
if (rv[n].attrVal != 0) {
for (i = 0; i < rv[n].numAttrs; i++) {
for (j = 0; j < rv[n].attrVal[i].numVals;
j++) {
sfree(rv[n].attrVal[i].val[j].value);
}
if (rv[n].attrVal[i].numVals > 0)
sfree(rv[n].attrVal[i].val);
}
free(rv[n].attrVal);
}
}
sfree(rv);
}
/*
* Return an array of 'count' __nis_rule_value_t elements, initialized
* to be copies of 'rvIn' if supplied; empty otherwise.
*/
__nis_rule_value_t *
initRuleValue(int count, __nis_rule_value_t *rvIn) {
return (growRuleValue(0, count, 0, rvIn));
}
static const __nis_rule_value_t rvZero = {0};
/*
* Grow 'old' from 'oldCount' to 'newCount' elements, initialize the
* new portion to 'rvIn' (empty if not supplied), and return a pointer
* to the result. Following a call to this function, the caller must
* refer only to the returned array, not to 'old'.
*/
__nis_rule_value_t *
growRuleValue(int oldCount, int newCount, __nis_rule_value_t *old,
__nis_rule_value_t *rvIn) {
__nis_rule_value_t *rv;
int i;
char *myself = "growRuleValue";
if (newCount <= 0 || newCount <= oldCount)
return (old);
if (oldCount <= 0) {
oldCount = 0;
old = 0;
}
if (rvIn == 0)
rvIn = (__nis_rule_value_t *)&rvZero;
rv = realloc(old, newCount * sizeof (rv[0]));
if (rv == 0) {
logmsg(MSG_NOMEM, LOG_ERR,
"%s: realloc(%d ((%d+%d)*%d)) => 0",
myself, (oldCount+newCount) * sizeof (rv[0]),
oldCount, newCount, sizeof (rv[0]));
freeRuleValue(old, oldCount);
return (0);
}
(void) memset(&rv[oldCount], 0, (newCount-oldCount)*sizeof (rv[0]));
for (i = oldCount; i < newCount; i++) {
rv[i].numColumns = rvIn->numColumns;
if (rv[i].numColumns > 0) {
rv[i].colName = cloneName(rvIn->colName,
rv[i].numColumns);
rv[i].colVal = cloneValue(rvIn->colVal,
rv[i].numColumns);
}
if (rv[i].numColumns > 0 &&
(rv[i].colName == 0 || rv[i].colVal == 0)) {
freeRuleValue(rv, i);
return (0);
}
rv[i].numAttrs = rvIn->numAttrs;
rv[i].attrName = cloneName(rvIn->attrName, rv[i].numAttrs);
rv[i].attrVal = cloneValue(rvIn->attrVal, rv[i].numAttrs);
if (rv[i].numAttrs > 0 &&
(rv[i].attrName == 0 || rv[i].attrVal == 0)) {
freeRuleValue(rv, i);
return (0);
}
}
return (rv);
}
/*
* Merge the source rule-value 's' into the target rule-value 't'.
* If successful, unless 's' is a sub-set of 't', 't' will be changed
* on exit, and will contain the values from 's' as well.
*/
int
mergeRuleValue(__nis_rule_value_t *t, __nis_rule_value_t *s) {
int i, j;
if (s == 0)
return (0);
else if (t == 0)
return (-1);
for (i = 0; i < s->numColumns; i++) {
for (j = 0; j < s->colVal[i].numVals; j++) {
if (addCol2RuleValue(s->colVal[i].type, s->colName[i],
s->colVal[i].val[j].value,
s->colVal[i].val[j].length,
t))
return (-1);
}
}
for (i = 0; i < s->numAttrs; i++) {
for (j = 0; j < s->attrVal[i].numVals; j++) {
if (addAttr2RuleValue(s->attrVal[i].type,
s->attrName[i],
s->attrVal[i].val[j].value,
s->attrVal[i].val[j].length,
t))
return (-1);
}
}
return (0);
}
static int
addVal2RuleValue(char *msg, int caseSens, int snipNul, __nis_value_type_t type,
char *name, void *value, int valueLen,
int *numP, char ***inNameP, __nis_value_t **inValP) {
int i, j, copyLen = valueLen;
__nis_single_value_t *v;
char **inName = *inNameP;
__nis_value_t *inVal = *inValP;
int num = *numP;
int (*comp)(const char *s1, const char *s2);
char *myself = "addVal2RuleValue";
/* Internal function, so assume arguments OK */
if (msg == 0)
msg = myself;
/* Should we match the 'inName' value case sensitive or not ? */
if (caseSens)
comp = strcmp;
else
comp = strcasecmp;
/*
* String-valued NIS+ entries count the concluding NUL in the
* length, while LDAP entries don't. In order to support this,
* we implement the following for vt_string value types:
*
* If the last byte of the value isn't a NUL, add one to the
* allocated length, so that there always is a NUL after the
* value, making it safe to pass to strcmp() etc.
*
* If 'snipNul' is set (presumably meaning we're inserting a
* value derived from a NIS+ entry), and the last byte of the
* value already is a NUL, decrement the length to be copied by
* one. This (a) doesn't count the NUL in the value length, but
* (b) still leaves a NUL following the value.
*
* In N2L, for all cases we set 'copyLen' to the number of non-0
* characters in 'value'.
*/
if (type == vt_string && valueLen > 0) {
char *charval = value;
if (charval[valueLen-1] != '\0')
valueLen += 1;
else if (yp2ldap || snipNul)
copyLen -= 1;
} else if (valueLen == 0) {
/*
* If the 'value' pointer is non-NULL, we create a zero-
* length value with one byte allocated. This takes care
* of empty strings.
*/
valueLen += 1;
}
/* If we already have values for this attribute, add another one */
for (i = 0; i < num; i++) {
if ((*comp)(inName[i], name) == 0) {
/*
* Our caller often doesn't know the type of the
* value; this happens because the type (vt_string
* or vt_ber) is determined by the format in the
* rule sets, and we may be invoked as a preparation
* for evaluating the rules. Hence, we only use the
* supplied 'type' if we need to create a value.
* Otherwise, we accept mixed types.
*
* Strings are OK in any case, since we always make
* sure to have a zero byte at the end of any value,
* whatever the type.
*/
if (inVal[i].numVals < 0) {
/*
* Used to indicate deletion of attribute,
* so we honor that and don't add a value.
*/
return (0);
}
/*
* If 'value' is NULL, we should delete, so
* remove any existing values, and set the
* 'numVals' field to -1.
*/
if (value == 0) {
for (j = 0; j < inVal[i].numVals; j++) {
sfree(inVal[i].val[j].value);
}
sfree(inVal[i].val);
inVal[i].val = 0;
inVal[i].numVals = -1;
return (0);
}
/* Is the value a duplicate ? */
for (j = 0; j < inVal[i].numVals; j++) {
if (copyLen == inVal[i].val[j].length &&
memcmp(value, inVal[i].val[j].value,
copyLen) == 0) {
break;
}
}
if (j < inVal[i].numVals)
return (0);
/* Not a duplicate, so add the name/value pair */
v = realloc(inVal[i].val,
(inVal[i].numVals+1) *
sizeof (inVal[i].val[0]));
if (v == 0)
return (-1);
inVal[i].val = v;
v[inVal[i].numVals].length = copyLen;
v[inVal[i].numVals].value = am(msg, valueLen);
if (v[inVal[i].numVals].value == 0 &&
value != 0) {
sfree(v);
return (-1);
}
memcpy(v[inVal[i].numVals].value, value, copyLen);
inVal[i].numVals++;
return (0);
}
}
/* No previous value for this attribute */
/*
* value == 0 means deletion, in which case we create a
* __nis_value_t with the numVals field set to -1.
*/
if (value != 0) {
if ((v = am(msg, sizeof (*v))) == 0)
return (-1);
v->length = copyLen;
v->value = am(msg, valueLen);
if (v->value == 0 && value != 0) {
sfree(v);
return (-1);
}
memcpy(v->value, value, copyLen);
}
inVal = realloc(inVal, (num+1)*sizeof (inVal[0]));
if (inVal == 0) {
if (value != 0) {
sfree(v->value);
sfree(v);
}
return (-1);
}
*inValP = inVal;
inName = realloc(inName,
(num+1)*sizeof (inName[0]));
if (inName == 0 || (inName[num] =
sdup(msg, T, name)) == 0) {
sfree(v->value);
sfree(v);
return (-1);
}
*inNameP = inName;
inVal[num].type = type;
inVal[num].repeat = 0;
if (value != 0) {
inVal[num].numVals = 1;
inVal[num].val = v;
} else {
inVal[num].numVals = -1;
inVal[num].val = 0;
}
*numP += 1;
return (0);
}
int
addAttr2RuleValue(__nis_value_type_t type, char *name, void *value,
int valueLen, __nis_rule_value_t *rv) {
char *myself = "addAttr2RuleValue";
if (name == 0 || rv == 0)
return (-1);
return (addVal2RuleValue(myself, 0, 0, type, name, value, valueLen,
&rv->numAttrs, &rv->attrName, &rv->attrVal));
}
int
addSAttr2RuleValue(char *name, char *value, __nis_rule_value_t *rv) {
return (addAttr2RuleValue(vt_string, name, value, slen(value), rv));
}
int
addCol2RuleValue(__nis_value_type_t type, char *name, void *value,
int valueLen, __nis_rule_value_t *rv) {
char *myself = "addCol2RuleValue";
if (name == 0 || rv == 0)
return (-1);
return (addVal2RuleValue(myself, 1, 1, type, name, value, valueLen,
&rv->numColumns, &rv->colName, &rv->colVal));
}
int
addSCol2RuleValue(char *name, char *value, __nis_rule_value_t *rv) {
return (addCol2RuleValue(vt_string, name, value, slen(value), rv));
}
/*
* Given a table mapping, a NIS+ DB query, and (optionally) an existing
* and compatible __nis_rule_value_t, return a new __nis_rule_value_t
* with the values from the query added.
*/
__nis_rule_value_t *
buildNisPlusRuleValue(__nis_table_mapping_t *t, db_query *q,
__nis_rule_value_t *rv) {
int i;
if (t == 0 || q == 0)
return (0);
rv = initRuleValue(1, rv);
if (rv == 0)
return (0);
for (i = 0; i < q->components.components_len; i++) {
/* Ignore out-of-range column index */
if (q->components.components_val[i].which_index >=
t->numColumns)
continue;
/*
* Add the query value. A NULL value indicates deletion,
* but addCol2RuleValue() takes care of that for us.
*/
if (addCol2RuleValue(vt_string,
t->column[q->components.components_val[i].
which_index],
q->components.components_val[i].index_value->
itemvalue.itemvalue_val,
q->components.components_val[i].index_value->
itemvalue.itemvalue_len, rv) != 0) {
freeRuleValue(rv, 1);
rv = 0;
break;
}
}
return (rv);
}
/*
* Given a LHS rule 'rl', return an array containing the item names,
* and the number of elements in the array in '*numItems'.
*
* If there are 'me_match' __nis_mapping_element_t's, we use the
* supplied '*rval' (if any) to derive values for the items in
* the 'me_match', and add the values thus derived to '*rval' (in
* which case the '*rval' pointer will change; the old '*rval'
* is deleted).
*/
__nis_mapping_item_t *
buildLvalue(__nis_mapping_rlhs_t *rl, __nis_value_t **rval, int *numItems) {
__nis_value_t *val, *r;
__nis_mapping_item_t *item = 0;
int i, n, ni = 0, nv = 0;
int repeat = 0;
if (rl == 0)
return (0);
if (rval != 0) {
r = *rval;
repeat = r->repeat;
} else
r = 0;
/* If there is more than one element, we concatenate the items */
for (i = 0; i < rl->numElements; i++) {
__nis_mapping_element_t *e = &rl->element[i];
__nis_mapping_item_t *olditem, *tmpitem = 0;
__nis_value_t **tmp;
switch (e->type) {
case me_item:
tmpitem = cloneItem(&e->element.item);
break;
case me_match:
/*
* Obtain values for the items in the 'me_match'
* element.
*/
tmp = matchMappingItem(e->element.match.fmt, r, &nv,
0, 0);
if (tmp != 0) {
freeValue(r, 1);
val = 0;
for (n = 0; n < nv; n++) {
r = concatenateValues(val, tmp[n]);
freeValue(val, 1);
freeValue(tmp[n], 1);
val = r;
if (val == 0) {
for (n++; n < nv; n++) {
freeValue(tmp[n], 1);
}
break;
}
}
free(tmp);
if (rval != 0) {
if (repeat && val != 0)
val->repeat = repeat;
*rval = val;
}
for (n = 0; n < e->element.match.numItems;
n++) {
olditem = item;
item = concatenateMappingItem(item, ni,
&e->element.match.item[n]);
freeMappingItem(olditem, ni);
if (item == 0) {
ni = 0;
break;
}
ni++;
}
}
break;
case me_print:
case me_split:
case me_extract:
default:
/* These shouldn't show up on the LHS; ignore */
break;
}
if (tmpitem != 0) {
olditem = item;
item = concatenateMappingItem(item, ni, tmpitem);
freeMappingItem(olditem, ni);
freeMappingItem(tmpitem, 1);
ni++;
if (item == 0) {
ni = 0;
break;
}
}
}
if (numItems != 0)
*numItems = ni;
return (item);
}
__nis_value_t *
buildRvalue(__nis_mapping_rlhs_t *rl, __nis_mapping_item_type_t native,
__nis_rule_value_t *rv, int *stat) {
__nis_value_t *val, *vold = 0, *vnew;
int i;
char *myself = "buildRvalue";
if (rl == 0 || rl->numElements <= 0) {
/*
* No RHS indicates deletion, as does a __nis_value_t
* with numVals == -1, so we return such a creature.
*/
val = am(myself, sizeof (*val));
if (val != 0) {
val->type = vt_string;
val->numVals = -1;
}
return (val);
}
/* If there is more than one element, we concatenate the values */
for (i = 0; i < rl->numElements; i++) {
vnew = getMappingElement(&rl->element[i], native, rv, stat);
val = concatenateValues(vold, vnew);
freeValue(vnew, 1);
freeValue(vold, 1);
vold = val;
}
return (val);
}
/*
* Derive values for the LDAP attributes specified by the rule 'r',
* and add them to the rule-value 'rv'.
*
* If 'doAssign' is set, out-of-context assignments are performed,
* otherwise not.
*/
__nis_rule_value_t *
addLdapRuleValue(__nis_table_mapping_t *t,
__nis_mapping_rule_t *r,
__nis_mapping_item_type_t lnative,
__nis_mapping_item_type_t rnative,
__nis_rule_value_t *rv,
int doAssign, int *stat) {
int i, j;
__nis_value_t *rval, *lval;
__nis_mapping_item_t *litem;
int numItems;
char **dn = 0;
int numDN = 0;
char *myself = "addLdapRuleValue";
/* Do we have the required values ? */
if (rv == 0)
return (0);
/*
* Establish appropriate search base. For rnative == mit_nisplus,
* we're deriving LDAP attribute values from NIS+ columns; in other
* words, we're writing to LDAP, and should use the write.base value.
*/
__nisdb_get_tsd()->searchBase = (rnative == mit_nisplus) ?
t->objectDN->write.base : t->objectDN->read.base;
/* Set escapeFlag if LHS is "dn" to escape special chars */
if (yp2ldap && r->lhs.numElements == 1 &&
r->lhs.element->type == me_item &&
r->lhs.element->element.item.type == mit_ldap &&
strcasecmp(r->lhs.element->element.item.name, "dn") == 0) {
__nisdb_get_tsd()->escapeFlag = '1';
}
/* Build the RHS value */
rval = buildRvalue(&r->rhs, rnative, rv, stat);
/* Reset escapeFlag */
__nisdb_get_tsd()->escapeFlag = '\0';
if (rval == 0)
return (rv);
/*
* Special case: If we got no value for the RHS (presumably because
* we're missing one or more item values), we don't produce an lval.
* Note that this isn't the same thing as an empty value, which we
* faithfully try to transmit to LDAP.
*/
if (rval->numVals == 1 && rval->val[0].value == 0) {
freeValue(rval, 1);
return (rv);
}
/* Obtain the LHS item names */
litem = buildLvalue(&r->lhs, &rval, &numItems);
if (litem == 0) {
freeValue(rval, 1);
return (rv);
}
/* Get string representations of the LHS item names */
lval = 0;
for (i = 0; i < numItems; i++) {
__nis_value_t *tmpval, *old;
tmpval = getMappingItem(&litem[i], lnative, 0, 0, NULL);
/*
* If the LHS item is out-of-context, we do the
* assignment right here.
*/
if (doAssign && litem[i].type == mit_ldap &&
litem[i].searchSpec.triple.scope !=
LDAP_SCOPE_UNKNOWN &&
slen(litem[i].searchSpec.triple.base) > 0 &&
(slen(litem[i].searchSpec.triple.attrs) > 0 ||
litem[i].searchSpec.triple.element != 0)) {
int stat;
if (dn == 0)
dn = findDNs(myself, rv, 1,
t->objectDN->write.base,
&numDN);
stat = storeLDAP(&litem[i], i, numItems, rval,
t->objectDN, dn, numDN);
if (stat != LDAP_SUCCESS) {
char *iname = "<unknown>";
if (tmpval != 0 &&
tmpval->numVals == 1)
iname = tmpval->val[0].value;
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: LDAP store \"%s\": %s",
myself, iname,
ldap_err2string(stat));
}
freeValue(tmpval, 1);
continue;
}
old = lval;
lval = concatenateValues(old, tmpval);
freeValue(tmpval, 1);
freeValue(old, 1);
}
/* Don't need the LHS items themselves anymore */
freeMappingItem(litem, numItems);
/*
* If we don't have an 'lval' (probably because all litem[i]:s
* were out-of-context assignments), we're done.
*/
if (lval == 0 || lval->numVals <= 0) {
freeValue(lval, 1);
freeValue(rval, 1);
return (rv);
}
for (i = 0, j = 0; i < lval->numVals; i++) {
/* Special case: rval->numVals < 0 means deletion */
if (rval->numVals < 0) {
(void) addAttr2RuleValue(rval->type,
lval->val[i].value, 0, 0, rv);
continue;
}
/* If we're out of values, repeat the last one */
if (j >= rval->numVals)
j = (rval->numVals > 0) ? rval->numVals-1 : 0;
for (; j < rval->numVals; j++) {
/*
* If this is the 'dn', and the value ends in a
* comma, append the appropriate search base.
*/
if (strcasecmp("dn", lval->val[i].value) == 0 &&
lastChar(&rval->val[j]) == ',' &&
t->objectDN->write.scope !=
LDAP_SCOPE_UNKNOWN) {
void *nval;
int nlen = -1;
nval = appendString2SingleVal(
t->objectDN->write.base, &rval->val[j],
&nlen);
if (nval != 0 && nlen >= 0) {
sfree(rval->val[j].value);
rval->val[j].value = nval;
rval->val[j].length = nlen;
}
}
(void) addAttr2RuleValue(rval->type,
lval->val[i].value, rval->val[j].value,
rval->val[j].length, rv);
/*
* If the lval is multi-valued, go on to the
* other values; otherwise, quit (but increment
* the 'rval' value index).
*/
if (!lval->repeat) {
j++;
break;
}
}
}
/* Clean up */
freeValue(lval, 1);
freeValue(rval, 1);
return (rv);
}
/*
* Remove the indicated attribute, and any values for it, from the
* rule-value.
*/
void
delAttrFromRuleValue(__nis_rule_value_t *rv, char *attrName) {
int i;
if (rv == 0 || attrName == 0)
return;
for (i = 0; i < rv->numAttrs; i++) {
if (strcasecmp(attrName, rv->attrName[i]) == 0) {
int j;
for (j = 0; j < rv->attrVal[i].numVals; j++)
sfree(rv->attrVal[i].val[j].value);
if (rv->attrVal[i].numVals > 0)
sfree(rv->attrVal[i].val);
sfree(rv->attrName[i]);
/* Move up the rest of the attribute names/values */
for (j = i+1; j < rv->numAttrs; j++) {
rv->attrName[j-1] = rv->attrName[j];
rv->attrVal[j-1] = rv->attrVal[j];
}
rv->numAttrs -= 1;
break;
}
}
}
/*
* Remove the indicated column, and any values for it, from the
* rule-value.
*/
void
delColFromRuleValue(__nis_rule_value_t *rv, char *colName) {
int i;
if (rv == 0 || colName == 0)
return;
for (i = 0; i < rv->numColumns; i++) {
if (strcmp(colName, rv->colName[i]) == 0) {
int j;
for (j = 0; j < rv->colVal[i].numVals; j++)
sfree(rv->colVal[i].val[j].value);
if (rv->colVal[i].numVals > 0)
sfree(rv->colVal[i].val);
sfree(rv->colName[i]);
/* Move up the rest of the column names/values */
for (j = i+1; j < rv->numColumns; j++) {
rv->colName[j-1] = rv->colName[j];
rv->colVal[j-1] = rv->colVal[j];
}
rv->numColumns -= 1;
break;
}
}
}
/*
* Add the write-mode object classes specified by 'objClassAttrs' to the
* rule-value 'rv'.
* If there's an error, 'rv' is deleted, and NULL returned.
*/
__nis_rule_value_t *
addObjectClasses(__nis_rule_value_t *rv, char *objClassAttrs) {
char *filter = 0, **fc = 0;
int i, nfc = 0;
/*
* Expect to only use this for existing rule-values, so rv == 0 is
* an error.
*/
if (rv == 0)
return (0);
/*
* If 'objClassAttrs' is NULL, we trivially have nothing to do.
* Assume the caller knows what it's doing, and return success.
*/
if (objClassAttrs == 0)
return (rv);
/*
* Make an AND-filter of the object classes, and split into
* components. (Yes, this is a bit round-about, but leverages
* existing functions.)
*/
filter = makeFilter(objClassAttrs);
if (filter == 0) {
freeRuleValue(rv, 1);
return (0);
}
fc = makeFilterComp(filter, &nfc);
if (fc == 0 || nfc <= 0) {
free(filter);
freeRuleValue(rv, 1);
return (0);
}
/* Add the objectClass attributes to the rule-value */
for (i = 0; i < nfc; i++) {
char *name, *value;
name = fc[i];
/* Skip if not of the "name=value" form */
if ((value = strchr(name, '=')) == 0)
continue;
*value = '\0';
value++;
/* Skip if the attribute name isn't "objectClass" */
if (strcasecmp("objectClass", name) != 0)
continue;
if (addSAttr2RuleValue(name, value, rv) != 0) {
free(filter);
freeFilterComp(fc, nfc);
freeRuleValue(rv, 1);
return (0);
}
}
free(filter);
freeFilterComp(fc, nfc);
return (rv);
}
static char *
valString(__nis_value_t *val) {
int i;
if (val == 0 || val->type != vt_string)
return (0);
for (i = 0; i < val->numVals; i++) {
/* Look for a non-NULL, non-zero length value */
if (val->val[i].value != 0 && val->val[i].length > 0) {
char *v = val->val[i].value;
/*
* Check that there's a NUL at the end. True,
* if there isn't, we may be looking beyond
* allocated memory. However, we would have done
* so in any case when the supposed string was
* traversed (printed, etc.), very possibly by
* a lot more than one byte. So, it's better to
* take a small risk here than a large one later.
*/
if (v[val->val[i].length-1] == '\0' ||
v[val->val[i].length] == '\0')
return (v);
}
}
return (0);
}
char *
findVal(char *name, __nis_rule_value_t *rv, __nis_mapping_item_type_t type) {
int i;
if (type == mit_nisplus) {
for (i = 0; i < rv->numColumns; i++) {
if (rv->colName[i] == 0)
continue;
if (strcmp(name, rv->colName[i]) == 0) {
return (valString(&rv->colVal[i]));
}
}
} else if (type == mit_ldap) {
for (i = 0; i < rv->numAttrs; i++) {
if (rv->attrName[i] == 0)
continue;
if (strcasecmp(name, rv->attrName[i]) == 0) {
return (valString(&rv->attrVal[i]));
}
}
}
return (0);
}
static char *norv = "<NIL>";
static char *unknown = "<unknown>";
/*
* Attempt to derive a string identifying the rule-value 'rv'. The
* returned string is a pointer, either into 'rv', or to static
* storage, and must not be freed.
*/
char *
rvId(__nis_rule_value_t *rv, __nis_mapping_item_type_t type) {
char *v;
if (rv == 0)
return (norv);
if (rv->numColumns > 0 && type == mit_nisplus) {
/*
* Look for a column called "cname" or "name".
* If that fails, try "key" or "alias".
*/
if ((v = findVal("cname", rv, type)) != 0)
return (v);
else if ((v = findVal("name", rv, type)) != 0)
return (v);
else if ((v = findVal("key", rv, type)) != 0)
return (v);
else if ((v = findVal("alias", rv, type)) != 0)
return (v);
} else if (rv->numAttrs > 0 && type == mit_ldap) {
/*
* Look for "dn", or "cn".
*/
if ((v = findVal("dn", rv, type)) != 0)
return (v);
else if ((v = findVal("cn", rv, type)) != 0)
return (v);
}
return (unknown);
}
/*
* Merge the rule-values with the same DN into one. Each rule-value
* in the returned array will have unique 'dn'. On entry, *numVals
* contains the number of rule-values in 'rv'. On exit, it contains
* the number of rule-values in the returned array or -1 on error.
*/
__nis_rule_value_t *
mergeRuleValueWithSameDN(__nis_rule_value_t *rv, int *numVals) {
__nis_rule_value_t *rvq = 0;
char *dn, *odn;
int count = 0;
int i, j;
if (numVals == 0)
return (0);
for (i = 0; i < *numVals; i++) {
if ((dn = findVal("dn", &rv[i], mit_ldap)) != 0) {
for (j = 0; j < count; j++) {
if ((odn = findVal("dn", &rvq[j],
mit_ldap)) != 0) {
/* case sensitive compare */
if (strcmp(dn, odn) != 0)
continue;
if (mergeRuleValue(&rvq[j],
&rv[i]) == -1) {
freeRuleValue(rvq, count);
*numVals = -1;
return (0);
}
break;
} else {
freeRuleValue(rvq, count);
*numVals = -1;
return (0);
}
}
/* if no match, then add it to the rulevalue array */
if (j == count) {
rvq = growRuleValue(count, count + 1, rvq,
&rv[i]);
if (rvq == 0) {
*numVals = -1;
return (0);
}
count++;
}
}
}
*numVals = count;
return (rvq);
}