dit_access_utils.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* DESCRIPTION: Contains dit_access interface support functions.
*/
#include <sys/systeminfo.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/systeminfo.h>
#include <unistd.h>
#include <stdlib.h>
#include <syslog.h>
#include <ndbm.h>
#include <strings.h>
#include <errno.h>
#include "../ldap_util.h"
#include "../ldap_map.h"
#include "../ldap_parse.h"
#include "../ldap_structs.h"
#include "../ldap_val.h"
#include "../ldap_ruleval.h"
#include "../ldap_op.h"
#include "../ldap_attr.h"
#include "../ldap_nisdbquery.h"
#include "../nisdb_mt.h"
#include "shim.h"
#include "yptol.h"
#include "dit_access_utils.h"
/*
* Returns 'map,domain.'
*/
char *
getFullMapName(char *map, char *domain) {
char *myself = "getFullMapName";
char *objPath;
if (map == 0 || domain == 0) {
return (0);
}
objPath = scat(myself, T, scat(myself, F, map, ","),
scat(myself, F, domain, "."));
return (objPath);
}
/*
* Convert string to __nis_value_t
*/
__nis_value_t *stringToValue(char *dptr, int dsize) {
char *myself = "stringToValue";
char *emptystr = "";
__nis_value_t *val;
if ((val = am(myself, sizeof (*val))) == 0) {
return (0);
}
val->type = vt_string;
val->repeat = 0;
val->numVals = 1;
if ((val->val = am(myself, sizeof (val->val[0]))) == 0) {
sfree(val);
return (0);
}
/*
* Null strings or strings with length 0 are treated
* as empty strings with length 1
*/
if (dptr == 0 || dsize <= 0) {
dptr = emptystr;
dsize = 1;
}
val->val->length = dsize;
if (dptr[dsize - 1] != '\0') {
val->val->length = dsize + 1;
}
val->val->value = am(myself, val->val->length);
if (val->val->value == 0) {
freeValue(val, 1);
return (0);
}
(void) memcpy(val->val->value, dptr, dsize);
return (val);
}
/*
* Returns an array of rule-values corresponding to the
* splitfields.
*/
__nis_rule_value_t *
processSplitField(__nis_table_mapping_t *sf, __nis_value_t *inVal,
int *nv, int *statP) {
char *sepset;
__nis_rule_value_t *rvq;
__nis_mapping_format_t *ftmp;
__nis_value_t **valA, *tempVal;
int i, j, res, numVals, oldlen, count;
char *str, *oldstr;
char *myself = "processSplitField";
/* sf will be non NULL */
if (inVal == 0 || inVal->type != vt_string) {
*statP = MAP_PARAM_ERROR;
return (0);
}
/* Get the separator list */
sepset = sf->separatorStr;
/* Initialize rule-value */
rvq = 0;
count = 0;
if ((tempVal = stringToValue(inVal->val->value,
inVal->val->length)) == 0) {
*statP = MAP_NO_MEMORY;
return (0);
}
str = oldstr = tempVal->val->value;
oldlen = tempVal->val->length;
while (str) {
tempVal->val->value = str;
tempVal->val->length = strlen(str) + 1;
/* Loop to check which format matches str */
for (i = 0; i <= sf->numSplits; i++) {
valA = matchMappingItem(sf->e[i].element.match.fmt,
tempVal, &numVals, sepset, &str);
if (valA == 0) {
/* The format didn't match. Try the next one */
continue;
}
/*
* If we are here means we had a match.
* Each new set of values obtained from the match is
* added to a new rule-value. This is to preserve the
* the distinction between each set.
*/
rvq = growRuleValue(count, count + 1, rvq, 0);
if (rvq == 0) {
*statP = MAP_INTERNAL_ERROR;
for (j = 0; j < numVals; j++)
freeValue(valA[j], 1);
sfree(valA);
tempVal->val->value = oldstr;
tempVal->val->length = oldlen;
freeValue(tempVal, 1);
return (0);
}
count++;
for (j = 0; j < numVals; j++) {
res = addCol2RuleValue(vt_string,
sf->e[i].element.match.item[j].name,
valA[j]->val->value,
valA[j]->val->length,
&rvq[count - 1]);
if (res == -1) {
*statP = MAP_INTERNAL_ERROR;
for (; j < numVals; j++)
freeValue(valA[j], 1);
sfree(valA);
tempVal->val->value = oldstr;
tempVal->val->length = oldlen;
freeValue(tempVal, 1);
freeRuleValue(rvq, count);
return (0);
}
freeValue(valA[j], 1);
}
sfree(valA);
/*
* Since we had a match, break out of this loop
* to parse remainder of str
*/
break;
}
/* Didn't find any match, so get out of the loop */
if (i > sf->numSplits) {
str = 0;
break;
}
/* Skip the separators before looping back */
if (str) {
str = str + strspn(str, sepset);
if (*str == '\0')
break;
}
}
tempVal->val->value = oldstr;
tempVal->val->length = oldlen;
freeValue(tempVal, 1);
if (str == 0) {
freeRuleValue(rvq, count);
return (0);
}
if (nv != 0)
*nv = count;
return (rvq);
}
/*
* Convert the datum to an array of RuleValues
*/
__nis_rule_value_t *
datumToRuleValue(datum *key, datum *value, __nis_table_mapping_t *t,
int *nv, char *domain, bool_t readonly, int *statP) {
__nis_rule_value_t *rvq, *subrvq, *newrvq;
__nis_value_t *val;
__nis_value_t **valA;
__nis_table_mapping_t *sf;
int valueLen, comLen, numVals, nr, count = 1;
int i, j, k, l, af;
char *ipaddr, *ipvalue;
/* At this point, 't' is always non NULL */
/* Initialize rule-value */
if ((rvq = initRuleValue(1, 0)) == 0) {
*statP = MAP_INTERNAL_ERROR;
return (0);
}
/* Add domainname to rule-value */
if (addCol2RuleValue(vt_string, N2LDOMAIN, domain, strlen(domain),
rvq)) {
freeRuleValue(rvq, 1);
*statP = MAP_INTERNAL_ERROR;
return (0);
}
/* Handle key */
if (key != 0) {
/* Add field=value pair for N2LKEY */
i = addCol2RuleValue(vt_string, N2LKEY, key->dptr, key->dsize,
rvq);
/* For readonly, add field=value pair for N2LSEARCHKEY */
if (readonly == TRUE && i == 0) {
i = addCol2RuleValue(vt_string, N2LSEARCHKEY, key->dptr,
key->dsize, rvq);
}
if (i) {
freeRuleValue(rvq, 1);
*statP = MAP_INTERNAL_ERROR;
return (0);
}
/* Add field=value pairs for IP addresses */
if (checkIPaddress(key->dptr, key->dsize, &ipaddr) > 0) {
/* If key is IPaddress, use preferred format */
ipvalue = ipaddr;
valueLen = strlen(ipaddr);
i = addCol2RuleValue(vt_string, N2LIPKEY, ipvalue,
valueLen, rvq);
} else {
/* If not, use original value for N2LSEARCHIPKEY */
ipaddr = 0;
ipvalue = key->dptr;
valueLen = key->dsize;
i = 0;
}
if (readonly == TRUE && i == 0) {
i = addCol2RuleValue(vt_string, N2LSEARCHIPKEY, ipvalue,
valueLen, rvq);
}
sfree(ipaddr);
if (i) {
freeRuleValue(rvq, 1);
*statP = MAP_INTERNAL_ERROR;
return (0);
}
}
/* Handle datum value */
if (value != 0 && t->e) {
valueLen = value->dsize;
/*
* Extract the comment, if any, and add it to
* the rule-value.
*/
if (t->commentChar != '\0') {
/*
* We loop on value->dsize because value->dptr
* may not be NULL-terminated.
*/
for (i = 0; i < value->dsize; i++) {
if (value->dptr[i] == t->commentChar) {
valueLen = i;
comLen = value->dsize - i - 1;
if (comLen == 0)
break;
if (addCol2RuleValue(vt_string,
N2LCOMMENT, value->dptr + i + 1,
comLen, rvq)) {
freeRuleValue(rvq, 1);
*statP = MAP_INTERNAL_ERROR;
return (0);
}
break;
}
}
}
/* Skip trailing whitespaces */
for (; valueLen > 0 && (value->dptr[valueLen - 1] == ' ' ||
value->dptr[valueLen - 1] == '\t'); valueLen--);
/*
* At this point valueLen is the effective length of
* the data. Convert value into __nis_value_t so that
* we can use the matchMappingItem function to break it
* into fields.
*/
if ((val = stringToValue(value->dptr, valueLen)) == 0) {
freeRuleValue(rvq, 1);
*statP = MAP_NO_MEMORY;
return (0);
}
/* Perform namefield match */
valA = matchMappingItem(t->e->element.match.fmt, val,
&numVals, 0, 0);
if (valA == 0) {
freeValue(val, 1);
freeRuleValue(rvq, 1);
*statP = MAP_NAMEFIELD_MATCH_ERROR;
return (0);
}
/* We don't need val anymore, so free it */
freeValue(val, 1);
/*
* Since matchMappingItem only returns us an array of
* __nis_value_t's, we need to associate each value
* in the array with the corresponding item name.
* This code assumes that numVals will be less than or
* equal to the number of item names associated with
* the format.
* These name=value pairs are added to rvq.
*/
for (i = 0, *statP = SUCCESS; i < numVals; i++) {
for (j = 0; j < count; j++) {
if (addCol2RuleValue(vt_string,
t->e->element.match.item[i].name,
valA[i]->val->value,
valA[i]->val->length, &rvq[j])) {
*statP = MAP_INTERNAL_ERROR;
break;
}
}
if (*statP == MAP_INTERNAL_ERROR)
break;
/*
* Check if splitField exists for the field.
* Since splitfields are also stored as mapping
* structures, we need to get the hash table entry
* corresponding to the splitfield name
*/
sf = mappingFromMap(t->e->element.match.item[i].name,
domain, statP);
if (*statP == MAP_NO_MEMORY)
break;
*statP = SUCCESS;
if (sf == 0)
continue;
/*
* Process and add splitFields to rule-value rvq
*/
subrvq = processSplitField(sf, valA[i], &nr, statP);
if (subrvq == 0) {
/* statP would have been set */
break;
}
/*
* We merge 'count' rule-values in rvq with 'nr'
* rule-values from subrvq to give us a whopping
* 'count * nr' rule-values
*/
/* Initialize the new rule-value array */
if ((newrvq = initRuleValue(count * nr, 0)) == 0) {
*statP = MAP_INTERNAL_ERROR;
freeRuleValue(subrvq, nr);
break;
}
for (j = 0, l = 0; j < nr; j++) {
for (k = 0; k < count; k++, l++) {
if ((mergeRuleValue(&newrvq[l],
&rvq[k]) == -1) ||
(mergeRuleValue(
&newrvq[l],
&subrvq[j]) == -1)) {
*statP = MAP_INTERNAL_ERROR;
for (i = 0; i < numVals; i++)
freeValue(valA[i], 1);
sfree(valA);
freeRuleValue(rvq, count);
freeRuleValue(newrvq,
count * nr);
freeRuleValue(subrvq, nr);
return (0);
}
}
}
freeRuleValue(rvq, count);
rvq = newrvq;
count = l;
freeRuleValue(subrvq, nr);
}
/* We don't need valA anymore, so free it */
for (i = 0; i < numVals; i++)
freeValue(valA[i], 1);
sfree(valA);
if (*statP != SUCCESS) {
freeRuleValue(rvq, count);
return (0);
}
} /* if value */
if (nv != 0)
*nv = count;
return (rvq);
}
/*
* Generate name=values pairs for splitfield names
*
* Consider Example:
* nisLDAPnameFields club:
* ("%s %s %s", name, code, members)
* nisLDAPsplitField members:
* ("(%s,%s,%s)", host, user, domain),
* ("%s", group)
* On entry,
* - rv is an array of numVals rule-values each containing
* name=value pairs for names occuring in nisLDAPsplitField.
* (i.e host, user, domain, group)
* - trv contains name=value pairs for names occuring in
* nisLDAPnameFields. (i.e name, code but not members)
*
* For every name in nisLDAPnamefields that is a splitfield,
* this function applies the data in rv to the corresponding
* splitfield formats (accessed thru t), to generate a single
* string value for the corresponding splitfield (members).
* This new name=value pair is then added to trv.
* Besides, any uninitialized namefield names are set to empty strings.
*/
suc_code
addSplitFieldValues(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
__nis_rule_value_t *trv, int numVals, char *domain) {
__nis_table_mapping_t *sf;
__nis_value_t *val;
int i, j, k, nitems, res, statP;
char *str, *tempstr;
char delim[2] = {0, 0};
char *emptystr = "";
char *myself = "addSplitFieldValues";
if (trv == 0)
return (MAP_INTERNAL_ERROR);
if (t->e == 0)
return (SUCCESS);
nitems = t->e->element.match.numItems;
/*
* Procedure:
* - Check each name in nisLDAPnamefield
* - if it's a splifield, construct its value and add it to trv
* - if not, check if it has a value
* - if not, add empty string
*/
for (i = 0, sf = 0; i < nitems; i++) {
if (rv) {
/*
* str will eventually contain the single string
* value for the corresponding splitfield.
* No point initializing str if rv == 0 because
* splitfield cannot be constructed without rv.
* So, only initialized here.
*/
str = 0;
/* Check if it's a splitfield name */
sf = mappingFromMap(t->e->element.match.item[i].name,
domain, &statP);
/*
* Return only incase of memory allocation failure.
* The other error case (MAP_NO_MAPPING_EXISTS),
* indicates that the item name is not a splitfieldname
* i.e it's a namefieldname. This case is handled by
* the following if (sf == 0)
*/
if (statP == MAP_NO_MEMORY)
return (statP);
}
if (sf == 0) {
/*
* Not a splitfield name. Verify if it has a value
*/
if (findVal(t->e->element.match.item[i].name,
trv, mit_nisplus) == 0) {
/* if not, use empty string */
res = addCol2RuleValue(vt_string,
t->e->element.match.item[i].name,
emptystr, 0, trv);
if (res == -1) {
return (MAP_INTERNAL_ERROR);
}
}
/*
* If rv == 0 then sf == 0 so we will continue here
* i.e. does not matter that str is not yet set up.
*/
continue;
}
/* Code to construct a single value */
/* Use the first separator character as the delimiter */
delim[0] = sf->separatorStr[0];
for (j = 0; j < numVals; j++) {
/* sf->numSplits is zero-based */
for (k = 0; k <= sf->numSplits; k++) {
val = getMappingFormatArray(
sf->e[k].element.match.fmt, &rv[j],
fa_item,
sf->e[k].element.match.numItems,
sf->e[k].element.match.item);
if (val == 0)
continue;
if (val->numVals > 0) {
if (str) {
tempstr = scat(myself,
0, str, delim);
sfree(str);
if (tempstr)
str = tempstr;
else {
freeValue(val, 1);
return (MAP_NO_MEMORY);
}
}
tempstr = scat(myself, 0, str,
val->val->value);
sfree(str);
if (tempstr)
str = tempstr;
else {
freeValue(val, 1);
return (MAP_NO_MEMORY);
}
}
freeValue(val, 1);
}
}
if (str == 0)
str = emptystr;
res = addCol2RuleValue(vt_string,
t->e->element.match.item[i].name,
str, strlen(str), trv);
if (str != emptystr)
sfree(str);
if (res == -1) {
return (MAP_INTERNAL_ERROR);
}
}
return (SUCCESS);
}
/*
* Updates 'rv' with NIS name=value pairs suitable to
* construct datum from namefield information.
* Some part based on createNisPlusEntry (from ldap_nisdbquery.c)
* This code assumes that from a given LDAP entry, applying the
* mapping rules, would give us one or more NIS entries, differing
* only in key.
*/
suc_code
buildNISRuleValue(__nis_table_mapping_t *t, __nis_rule_value_t *rv,
char *domain) {
int r, i, j, k, l, index, nrq, res, len;
int numItems, splitname, count, statP;
__nis_value_t *rval;
__nis_mapping_item_t *litem;
__nis_mapping_rule_t *rl;
__nis_rule_value_t *rvq;
char *value, *emptystr = "";
statP = SUCCESS;
/* Initialize default base */
__nisdb_get_tsd()->searchBase = t->objectDN->read.base;
/* Initialize rule-value rvq */
rvq = 0;
count = 0;
/* Add domainname to rule-value */
if (addCol2RuleValue(vt_string, N2LDOMAIN, domain, strlen(domain),
rv)) {
return (MAP_INTERNAL_ERROR);
}
for (r = 0; r < t->numRulesFromLDAP; r++) {
rl = t->ruleFromLDAP[r];
/* Set escapeFlag if RHS is "dn" to remove escape chars */
if (rl->rhs.numElements == 1 &&
rl->rhs.element->type == me_item &&
rl->rhs.element->element.item.type == mit_ldap &&
strcasecmp(rl->rhs.element->element.item.name, "dn")
== 0) {
__nisdb_get_tsd()->escapeFlag = '2';
}
rval = buildRvalue(&rl->rhs, mit_ldap, rv, NULL);
/* Reset escapeFlag */
__nisdb_get_tsd()->escapeFlag = '\0';
if (rval == 0) {
continue;
}
if (rval->numVals <= 0) {
/* Treat as invalid */
freeValue(rval, 1);
continue;
}
litem = buildLvalue(&rl->lhs, &rval, &numItems);
if (litem == 0) {
/* This will take care of numItems == 0 */
freeValue(rval, 1);
continue;
}
if (rval->numVals > 1) {
if (numItems == 1 && litem->repeat)
nrq = rval->numVals;
else if (numItems > 1 && rval->repeat)
nrq = 1 + ((rval->numVals-1)/numItems);
else
nrq = 1;
} else
nrq = 1;
/* Set splitname if splitfield names are specified */
for (i = 0; i < numItems; i++) {
if (strcasecmp(litem[i].name, N2LKEY) == 0 ||
strcasecmp(litem[i].name, N2LIPKEY) == 0 ||
strcasecmp(litem[i].name, N2LCOMMENT) == 0)
continue;
for (j = 0; j < t->numColumns; j++) {
if (strcmp(litem[i].name, t->column[j]) == 0)
break;
}
if (j == t->numColumns)
break;
}
splitname = (i < numItems)?1:0;
for (j = 0; j < nrq; j++) {
if (splitname == 1) {
/*
* Put every value of splitfieldname in a new
* rule-value. Helps generating splitfields.
*/
rvq = growRuleValue(count, count + 1, rvq, 0);
if (rvq == 0) {
freeRuleValue(rvq, count);
freeValue(rval, 1);
freeMappingItem(litem, numItems);
return (MAP_INTERNAL_ERROR);
}
count++;
}
for (k = j % nrq, l = 0; l < numItems; k += nrq, l++) {
/* If we run out of values, use empty strings */
if (k >= rval->numVals) {
value = emptystr;
len = 0;
} else {
value = rval->val[k].value;
len = rval->val[k].length;
}
res = (splitname == 1)?addCol2RuleValue(
vt_string, litem[l].name, value,
len, &rvq[count - 1]):0;
if (res != -1)
res = addCol2RuleValue(vt_string,
litem[l].name, value, len, rv);
if (res == -1) {
freeRuleValue(rvq, count);
freeValue(rval, 1);
freeMappingItem(litem, numItems);
return (MAP_INTERNAL_ERROR);
}
}
}
freeValue(rval, 1);
rval = 0;
freeMappingItem(litem, numItems);
litem = 0;
numItems = 0;
} /* for r < t->numRulesFromLDAP */
statP = addSplitFieldValues(t, rvq, rv, count, domain);
if (rvq)
freeRuleValue(rvq, count);
if (verifyIndexMatch(t, 0, rv, 0, 0) == 0)
return (MAP_INDEXLIST_ERROR);
return (statP);
} /* end of buildNISRuleValue */
/*
* Convert rule-value to datum using namefield information
*/
datum *
ruleValueToDatum(__nis_table_mapping_t *t, __nis_rule_value_t *rv, int *statP) {
__nis_value_t *val;
datum *value;
char *str, *cstr, commentSep[3] = {' ', 0, 0};
char *myself = "ruleValueToDatum";
/* No error yet */
*statP = 0;
/* Return empty datum if no namefield information available */
if (t->e == 0) {
if ((value = am(myself, sizeof (*value))) == 0)
*statP = MAP_NO_MEMORY;
return (value);
}
val = getMappingFormatArray(t->e->element.match.fmt, rv,
fa_item, t->e->element.match.numItems,
t->e->element.match.item);
if (val && val->val && val->val->value) {
if ((value = am(myself, sizeof (*value))) == 0) {
*statP = MAP_NO_MEMORY;
freeValue(val, 1);
return (0);
}
/* Strip trailing whitespaces */
cstr = (char *)val->val->value + val->val->length;
for (; cstr >= (char *)val->val->value &&
(*cstr == ' ' || *cstr == '\t'); *cstr-- = '\0');
if (t->commentChar != '\0' &&
(str = findVal(N2LCOMMENT, rv, mit_nisplus)) != 0 &&
*str != '\0') {
commentSep[1] = t->commentChar;
cstr = scat(myself, F, commentSep, str);
if (cstr) {
value->dptr = scat(myself, F,
val->val->value, cstr);
sfree(cstr);
}
} else {
value->dptr = sdup(myself, T, val->val->value);
}
freeValue(val, 1);
if (value->dptr) {
value->dsize = strlen(value->dptr);
return (value);
} else {
*statP = MAP_NO_MEMORY;
sfree(value);
return (0);
}
}
*statP = MAP_NAMEFIELD_MATCH_ERROR;
return (0);
}
datum *
getKeyFromRuleValue(__nis_table_mapping_t *t, __nis_rule_value_t *rv, int *nv,
int *statP) {
int i, j;
datum *key = 0;
char *str;
char *myself = "getKeyFromRuleValue";
/* No error yet */
*statP = 0;
if (rv == 0 || nv == 0)
return (0);
for (i = 0; i < rv->numColumns; i++) {
if (rv->colName[i] == 0)
continue;
if (strcasecmp(N2LKEY, rv->colName[i]) == 0 ||
strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
if ((*nv = rv->colVal[i].numVals) == 0)
return (0);
if ((key = am(myself, sizeof (key[0]) * *nv)) == 0) {
*statP = MAP_NO_MEMORY;
return (0);
}
for (j = 0; j < *nv; j++) {
if ((str = rv->colVal[i].val[j].value) == 0) {
key[j].dsize = 0;
key[j].dptr = 0;
} else {
if (verifyIndexMatch(t, 0, 0,
rv->colName[i],
str) == 0) {
key[j].dsize = 0;
key[j].dptr = 0;
continue;
}
key[j].dsize = strlen(str);
key[j].dptr = am(myself,
key[j].dsize + 1);
if (key[j].dptr == 0) {
*statP = MAP_NO_MEMORY;
for (--j; j >= 0; j--)
sfree(key[j].dptr);
sfree(key);
return (0);
}
bcopy(str, key[j].dptr, key[j].dsize);
}
}
return (key);
}
}
return (0);
}
/*
* Get the mapping structure corresponding to `map,domain.'
*/
__nis_table_mapping_t *
mappingFromMap(char *map, char *domain, int *statP) {
char *mapPath;
__nis_table_mapping_t *t;
/* No error yet */
*statP = 0;
/* Construct map,domain. */
if ((mapPath = getFullMapName(map, domain)) == 0) {
*statP = MAP_NO_MEMORY;
return (0);
}
/* Get the hash table entry for the mapPath */
if ((t = __nis_find_item_mt(mapPath, &ldapMappingList, 1, 0))
== 0) {
*statP = MAP_NO_MAPPING_EXISTS;
}
sfree(mapPath);
return (t);
}
/*
* Verify at least one key value obtained from DIT matches the search key
* RETURNS: 1 MATCH
* 0 NO MATCH
* -1 NO KEY FOUND
*/
static int
verifyKey(char *key, __nis_rule_value_t *rv) {
int i, j;
char *sipkey, *str;
for (i = 0; i < rv->numColumns; i++) {
if (rv->colName[i] == 0)
continue;
if (strcasecmp(N2LKEY, rv->colName[i]) == 0) {
if (rv->colVal[i].val == 0)
return (0);
for (j = 0; j < rv->colVal[i].numVals; j++) {
str = (char *)rv->colVal[i].val[j].value;
if (str && strcmp(str, key) == 0)
return (1);
}
return (0);
} else if (strcasecmp(N2LIPKEY, rv->colName[i]) == 0) {
if (checkIPaddress(key, strlen(key), &sipkey) > 0) {
if (rv->colVal[i].val == 0)
return (0);
for (j = 0; j < rv->colVal[i].numVals; j++) {
str = rv->colVal[i].val[j].value;
if (str && strcmp(str, sipkey) == 0) {
sfree(sipkey);
return (1);
}
}
sfree(sipkey);
}
return (0);
}
}
return (-1);
}
/*
* Read (i.e get and map) a single NIS entry from the LDAP DIT
*/
bool_t
singleReadFromDIT(char *map, char *domain, datum *key, datum *value,
int *statP) {
__nis_table_mapping_t *t;
__nis_rule_value_t *rv_request = 0, *rv_result = 0;
__nis_ldap_search_t *ls;
__nis_object_dn_t *objectDN = NULL;
int i, rc, nr = 0, nv = 0;
datum *datval = 0;
char *skey, *str, *sipkey;
char *myself = "singleReadFromDIT";
*statP = SUCCESS;
if (!map || !domain || !key || !value) {
*statP = MAP_PARAM_ERROR;
return (FALSE);
}
/* Get the mapping information for the map */
if ((t = mappingFromMap(map, domain, statP)) == 0) {
/*
* No problem. We don't handle this map and domain. Maybe it's
* handled by a service other than NIS.
*/
return (FALSE);
}
/* NULL-terminated version of datum key for logging */
if ((skey = am(myself, key->dsize + 1)) == 0) {
*statP = MAP_NO_MEMORY;
return (FALSE);
}
(void) memcpy(skey, key->dptr, key->dsize);
if ((str = getFullMapName(map, domain)) == 0) {
*statP = MAP_NO_MEMORY;
return (FALSE);
}
/* For each alternate mapping */
for (; t != 0; t = t->next) {
/* Verify objName */
if (strcmp(str, t->objName) != 0) {
continue;
}
/* Verify if key matches the index */
if (verifyIndexMatch(t, 0, 0, N2LKEY, skey) == 0 ||
verifyIndexMatch(t, 0, 0, N2LIPKEY, skey) == 0)
continue;
/* Check if rulesFromLDAP are provided */
if (t->numRulesFromLDAP == 0) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: No rulesFromLDAP information available "
"for %s (%s)", myself, t->dbId, map);
continue;
}
/* Convert key into rule-value */
if ((rv_request = datumToRuleValue(key, 0, t, 0, domain, TRUE,
statP)) == 0) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Conversion error %d (NIS to name=value "
"pairs) for NIS key (%s) for %s (%s)",
myself, *statP, skey, t->dbId, map);
continue;
}
/* Convert rule-value into ldap request */
for (objectDN = t->objectDN; objectDN &&
objectDN->read.base;
objectDN = objectDN->next) {
ls = createLdapRequest(t, rv_request, 0, 1, NULL,
objectDN);
if (ls == 0) {
*statP = MAP_CREATE_LDAP_REQUEST_ERROR;
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Failed to create ldapSearch "
"request for "
"NIS key (%s) for %s (%s) "
"for base %s",
myself, skey, t->dbId, map,
objectDN->read.base);
continue;
}
ls->timeout.tv_sec = SINGLE_ACCESS_TIMEOUT_SEC;
ls->timeout.tv_usec = SINGLE_ACCESS_TIMEOUT_USEC;
/* Query LDAP */
nr = (ls->isDN)?0:-1;
rv_result = ldapSearch(ls, &nr, 0, statP);
freeLdapSearch(ls);
if (rv_result == 0) {
if (*statP == LDAP_NO_SUCH_OBJECT) {
/* Entry does not exist in */
/* the ldap server */
}
continue;
}
freeRuleValue(rv_request, 1);
rv_request = 0;
/* if result > 1, first match will be returned */
if (nr > 1) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: %d ldapSearch results "
"for NIS key (%s) "
"for %s (%s) for base %s. "
"First match will be returned ",
myself, nr, skey, t->dbId, map,
objectDN->read.base);
}
for (i = 0; i < nr; i++) {
/* Convert LDAP data to NIS equivalents */
*statP = buildNISRuleValue(t, &rv_result[i],
domain);
if (*statP == MAP_INDEXLIST_ERROR)
continue;
if (*statP != SUCCESS) {
logmsg(MSG_NOTIMECHECK, LOG_WARNING,
"%s: Conversion error %d (LDAP to "
"name=value pairs) for NIS key (%s) "
"for %s (%s) for base %s", myself,
*statP, skey,
t->dbId, map, objectDN->read.base);
continue;
}
/*
* Check if 'key' from the ldap result matches the key
* provided by our caller
*/
if ((rc = verifyKey(skey, &rv_result[i]))
== -1) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: Cannot verify key from ldap "
"result for NIS key (%s) for %s (%s) "
"for base %s",
myself, skey, t->dbId, map,
objectDN->read.base);
continue;
}
if (rc == 1) {
datval = ruleValueToDatum(t,
&rv_result[i], statP);
if (datval == 0) {
logmsg(MSG_NOTIMECHECK,
LOG_WARNING,
"%s: Conversion error %d "
"(name=value pairs to NIS) "
"for NIS key (%s) for %s (%s)"
" for base %s",
myself,
*statP, skey, t->dbId, map,
objectDN->read.base);
continue;
}
if (value) {
value->dptr = datval->dptr;
value->dsize = datval->dsize;
}
sfree(datval);
sfree(skey);
freeRuleValue(rv_result, nr);
rv_result = 0;
*statP = SUCCESS;
/* Free full map name */
sfree(str);
return (TRUE);
}
}
freeRuleValue(rv_result, nr);
rv_result = 0;
} /* end of for over objectDN */
if (rv_request != 0) {
freeRuleValue(rv_request, 1);
rv_request = 0;
}
if (rv_result != 0) {
freeRuleValue(rv_result, nr);
rv_result = 0;
}
}
sfree(skey);
*statP = MAP_NO_MATCHING_KEY;
/* Free full map name */
sfree(str);
return (FALSE);
}
/*
* Maps and writes a single NIS entry to the LDAP DIT
*/
int
singleWriteToDIT(char *map, char *domain, datum *key, datum *value,
bool_t replace) {
__nis_table_mapping_t *t;
__nis_rule_value_t *rv, *frv;
__nis_ldap_search_t *ls;
int statP = SUCCESS, flag;
int nv, nr, i, rc, collapse;
char *dn = 0, *skey, *svalue, *str;
char *myself = "singleWriteToDIT";
if (!map || !domain || !key || !value) {
return (MAP_PARAM_ERROR);
}
/* Return SUCCESS for empty or whitespace key */
for (i = 0; i < key->dsize && (key->dptr[i] == 0 ||
key->dptr[i] == ' ' || key->dptr[i] == '\t'); i++);
if (i >= key->dsize)
return (SUCCESS);
/* Get the mapping information for the map */
if ((t = mappingFromMap(map, domain, &statP)) == 0) {
/*
* No problem. We don't handle this map and domain. Maybe it's
* handled by a service other than NIS.
*/
return (statP);
}
/* NULL-terminated version of key and value for logging */
if ((skey = am(myself, key->dsize + 1)) == 0)
return (MAP_NO_MEMORY);
(void) memcpy(skey, key->dptr, key->dsize);
if ((svalue = am(myself, value->dsize + 1)) == 0) {
sfree(skey);
return (MAP_NO_MEMORY);
}
(void) memcpy(svalue, value->dptr, value->dsize);
if ((str = getFullMapName(map, domain)) == 0) {
sfree(skey);
sfree(svalue);
return (MAP_NO_MEMORY);
}
/* For each alternate mapping */
for (flag = 0; t != 0; t = t->next) {
/* Verify objName */
if (strcmp(str, t->objName) != 0) {
continue;
}
/* Verify if key matches the index */
if (verifyIndexMatch(t, 0, 0, N2LKEY, skey) == 0 ||
verifyIndexMatch(t, 0, 0, N2LIPKEY, skey) == 0)
continue;
/* Check the writespecs */
if (t->objectDN->write.base == 0) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: No baseDN in writespec. Write disabled "
"for %s (%s)", myself, t->dbId, map);
continue;
}
/* Check if rulesToLDAP are provided */
if (t->numRulesToLDAP == 0) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: No rulesToLDAP. Write disabled for "
"%s (%s)", myself, t->dbId, map);
continue;
}
/* Set flag to indicate write is enabled */
flag = 1;
/* Convert key and value into an array of rule-values */
if ((rv = datumToRuleValue(key, value, t, &nv, domain, FALSE,
&statP)) == 0) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Conversion error %d (NIS to name=value "
"pairs) for NIS data (key=%s, value=%s) "
"for %s (%s)",
myself, statP, skey, svalue, t->dbId, map);
sfree(skey);
sfree(svalue);
/* Free full map name */
sfree(str);
return (statP);
}
/* Convert NIS data to LDAP equivalents for each rule-value */
for (i = 0; i < nv; i++) {
/* Verify indexlist with name=value pairs */
if (verifyIndexMatch(t, 0, &rv[i], 0, 0) == 0)
break;
/* Create LDAP request and LDAP name=value pairs */
if ((ls = createLdapRequest(t, &rv[i],
0, 0, NULL, NULL)) == 0) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Conversion error (name=value pairs"
" to LDAP) for NIS data "
"(key=%s, value=%s) for %s (%s)",
myself, skey, svalue, t->dbId, map);
freeRuleValue(rv, nv);
sfree(skey);
sfree(svalue);
/* Free full map name */
sfree(str);
return (MAP_CREATE_LDAP_REQUEST_ERROR);
}
freeLdapSearch(ls);
/* printRuleValue(&rv[i]); */
}
/* If i < nv then this alternate mapping isn't the one */
if (i < nv)
continue;
/*
* Merge rule-values with the same DN so that we have
* one ldap write request for each DN
*/
nr = nv;
frv = mergeRuleValueWithSameDN(rv, &nr);
freeRuleValue(rv, nv);
if (frv == 0) {
if (nr == -1) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Unable to merge LDAP write "
"requests to same DN for NIS data "
"(key=%s, value=%s) for %s (%s)",
myself, skey, svalue, t->dbId, map);
statP = MAP_INTERNAL_ERROR;
} else if (nr == 0) {
logmsg(MSG_NOTIMECHECK, LOG_WARNING,
"%s: Cannot generate write DN due to "
"missing information for NIS data "
"(key=%s, value=%s) for %s (%s)",
myself, skey, svalue, t->dbId, map);
statP = MAP_NO_DN;
}
sfree(skey);
sfree(svalue);
/* Free full map name */
sfree(str);
return (statP);
}
/* Write to the LDAP server */
for (collapse = 0, i = 0; i < nr; i++) {
if ((dn = findVal("dn", &frv[i], mit_ldap)) != 0) {
if (replace == FALSE) {
/* ldap add */
rc = ldapAdd(dn, &frv[i],
t->objectDN->write.attrs, 0);
} else {
/* ldap modify with addFirst set */
rc = ldapModify(dn, &frv[i],
t->objectDN->write.attrs, 1);
}
/* if we get err=20, collapse and try again */
if (!collapse &&
(rc == LDAP_TYPE_OR_VALUE_EXISTS) &&
(collapseRuleValue(&frv[i]) == 1)) {
logmsg(MSG_NOTIMECHECK, LOG_WARNING,
"%s: Ignoring values differing "
"in case from NIS data (key=%s,"
" value=%s) for (dn: %s) for "
"%s (%s)", myself, skey,
svalue, dn, t->dbId, map);
collapse = 1;
i--;
continue;
}
collapse = 0;
if (rc != LDAP_SUCCESS) {
/* Log error */
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: %s error %d (%s) for "
"(dn: %s) for NIS data "
"(key=%s, value=%s) "
"for %s (%s)",
myself, (replace == TRUE) ?
"ldapModify" : "ldapAdd", rc,
ldap_err2string(rc), dn, skey,
svalue, t->dbId, map);
/* Dumping failed call may be useful */
/* printRuleValue(&frv[i]); */
/*
* Return the error code and let wrapper
* sort out if mapping should continue
* or abort.
*/
statP = rc;
sfree(skey);
sfree(svalue);
freeRuleValue(frv, nr);
/* Free full map name */
sfree(str);
return (statP);
}
}
}
freeRuleValue(frv, nr);
}
sfree(skey);
sfree(svalue);
/* Free full map name */
sfree(str);
return ((flag)?SUCCESS:MAP_WRITE_DISABLED);
}
suc_code
collapseRuleValue(__nis_rule_value_t *rv) {
int i, j, k, flag;
/* Using 'val' to appease cstyle's 80 chars/line limit */
__nis_value_t *val;
for (i = 0, flag = 0; i < rv->numAttrs; i++) {
val = &rv->attrVal[i];
for (j = 1; j < val->numVals; j++) {
for (k = 0; k < j; k++) {
if (val->val[j].length != val->val[k].length)
continue;
if (val->val[k].length == 0)
continue;
if (strncasecmp(val->val[j].value,
val->val[k].value,
val->val[j].length) != 0)
continue;
flag = 1;
sfree(val->val[j].value);
#ifdef ORDER_NOT_IMPORTANT
val->val[j--] = val->val[--val->numVals];
#else
/* Order needs to be maintained */
for (k = j + 1; k < val->numVals; k++)
val->val[k - 1] = val->val[k];
j--;
val->numVals--;
#endif
break;
}
}
}
return (flag);
}
/* ObjectClass lookup table */
static struct {
const char *attrType;
const char *objectClass;
} oc_lookup[] = {
{ "o", "objectclass=organization"},
{ "organizationname", "objectclass=organization"},
{ "2.5.4.10", "objectclass=organization"},
{ "ou", "objectclass=organizationalunit"},
{ "organizationalunitname", "objectclass=organizationalunit"},
{ "2.5.4.11", "objectclass=organizationalunit"},
{ "c", "objectclass=country"},
{ "countryname", "objectclass=country"},
{ "2.5.4.6", "objectclass=country"},
{ "dc", "objectclass=domain"},
{ "domaincomponent", "objectclass=domain"},
{ "0.9.2342.19200300.100.1.25", "objectclass=domain"},
{ "nismapname", "objectclass=nismap"},
{ "1.3.6.1.1.1.1.26", "objectclass=nismap"},
{ "automountmapname", "objectclass=automountmap"},
{ "1.3.6.1.1.1.1.31", "objectclass=automountmap"},
{ 0, 0}
};
/*
* Returns the name of the objectclass to which the object
* represented by the given 'rdn' will most likely belong to.
* The return value is in static memory so it should not be
* freed
*/
const char *
getObjectClass(char *rdn) {
char *attrtype, *p;
int len, i;
/* Skip leading whitespaces */
for (p = rdn; *p == ' ' || *p == '\t'; p++);
if (*p == '\0')
return (0);
attrtype = p;
/* Find '=' */
if ((p = strchr(attrtype, '=')) == 0 || p == attrtype ||
*(p - 1) == '\\')
return (0);
/*
* Skip trailing whitespaces in attrtype
* Don't worry, p won't decrease beyond attrtype
*/
for (--p; *p == ' ' || *p == '\t'; p--);
len = p - attrtype + 1;
for (i = 0; oc_lookup[i].attrType; i++)
if (!strncasecmp(oc_lookup[i].attrType, attrtype, len))
/* Check length is right */
if (len == strlen(oc_lookup[i].attrType))
return (oc_lookup[i].objectClass);
return (0);
}
/*
* Split 'dn' into rdn and parentdn based on the first
* occurrence of unescaped 'comma' or 'semicolon'. rdn
* lies on the LHS while parentdn lies on the RHS of the
* split. If none found, then an empty string ("") is
* assigned to parentdn
*/
int
splitDN(char *dn, char **rdn, char **parentdn) {
char *value, *name;
char *myself = "splitDN";
if ((name = sdup(myself, T, dn)) == 0)
return (-1);
for (value = name; *value != '\0'; value++) {
if (*value == ',' || *value == ';')
if (value == name || *(value - 1) != '\\')
break;
}
if (*value != '\0') {
*value = '\0';
value++;
} else
value = 0;
if (parentdn) {
if ((*parentdn = sdup(myself, T, value)) == 0) {
sfree(name);
return (-1);
}
}
if (rdn)
*rdn = name;
else
sfree(name);
return (1);
}
/*
* FUNCTION : makeNISObject()
*
* DESCRIPTION: Sets up a nis Object in the DIT.
*
* GIVEN :
* Case 1: Both 'domain' and 'dn' are non-NULL
* Create nisDomainObject with the given information
* Case 2: Only 'domain' is non-NULL
* Obtain the 'dn' from the nisLDAPdomainContext list
* Create nisDomainObject with the above information
* Case 3: Only 'dn' is non-NULL
* Create an object with the 'dn'
* Here we guess the objectclass attribute, based on
* oc_lookup table
* Case 4: Both 'domain' and 'dn' are NULL
* Error
*
* RETURNS : SUCCESS = It worked
* FAILURE = There was a problem.
*/
suc_code
makeNISObject(char *domain, char *dn) {
__nis_rule_value_t *rv;
__nis_ldap_search_t *ls;
int i, rc, nr, add_rc;
char *val;
char *myself = "makeNISObject";
if (!dn && !domain)
return (FAILURE);
/*
* If only 'domain' name is provided, then
* try to find dn from the nisLDAPdomainContext
* list generated by the parser
*/
if (!dn) {
for (i = 0; i < ypDomains.numDomains; i++) {
if (ypDomains.domainLabels[i] == 0)
continue;
if (strcasecmp(domain, ypDomains.domainLabels[i])
== 0) {
dn = ypDomains.domains[i];
break;
}
}
if (!dn)
return (FAILURE);
}
/*
* If only 'dn' is given, then it means that the
* caller simply wants to a create an entry for
* that 'dn'.
*
* If 'domain' is given, then check if the 'dn'
* has already been set up as a nis domain object.
* If not, see if we can make it become one.
*/
if (domain) {
/*
* Check to see if the nis domain object has
* already been set up
*/
ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0,
"objectclass=*", 0, 0, 0);
if (ls == 0) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Unable to create ldapSearch "
"request for dn: %s", myself, dn);
return (FAILURE);
}
nr = -1;
rv = ldapSearch(ls, &nr, 0, &rc);
freeLdapSearch(ls);
if (rc == LDAP_SUCCESS) {
val = findVal("nisDomain", rv, mit_ldap);
if (val != NULL) {
/*
* Yes, nis domain object found. Check
* to see if the domain names match.
* If so, we are done. If not, log
* a warning message, and return SUCCESS.
*/
if (strcasecmp(val, domain) == 0) {
freeRuleValue(rv, nr);
return (SUCCESS);
} else {
logmsg(MSG_NOTIMECHECK,
LOG_WARNING,
"%s: Entry (dn: %s) already "
"contains a nis domain name "
"(%s). The domain name (%s) "
"is not added.",
myself, dn, val, domain);
freeRuleValue(rv, nr);
return (SUCCESS);
}
} else {
freeRuleValue(rv, nr);
/*
* Entry for the 'dn' exists, but it
* is not a nis domain object yet.
* Add the nisDoamin attribute and
* the nisDomainObject objectclass to
* the entry.
*/
if ((rv = initRuleValue(1, 0)) == 0)
return (FAILURE);
if (addSAttr2RuleValue("nisDomain",
domain, rv) == -1) {
freeRuleValue(rv, 1);
return (FAILURE);
}
rc = ldapModify(dn, rv,
"objectclass=nisDomainObject",
0);
freeRuleValue(rv, 1);
if (rc == LDAP_SUCCESS) {
logmsg(MSG_NOTIMECHECK,
LOG_INFO,
"%s: entry (dn: %s) "
"modified to be an "
"nis domain object",
myself, dn);
return (SUCCESS);
} else {
logmsg(MSG_NOTIMECHECK,
LOG_ERR,
"%s: unable to modify "
"entry (dn: %s) to be "
"a nis domain object: "
"ldapModify error %d (%s)",
myself, dn, rc,
ldap_err2string(rc));
return (FAILURE);
}
}
} else { /* search for 'dn' failed */
freeRuleValue(rv, nr);
/*
* It is OK if no such object, otherwise
* log an error.
*/
if (rc != LDAP_NO_SUCH_OBJECT) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: unable to retrieve "
"entry (dn: %s): "
"ldapSearch error %d (%s)",
myself, dn, rc,
ldap_err2string(rc));
return (FAILURE);
}
}
/*
* If the 'dn' is actually the naming context of
* the DIT, we should be able to make it a nis domain
* object without worrying about missing parent
* entries. If unable to add the entry for the 'dn'
* due to missing parent entries, fall through
* to create them and then add the nis domain object.
*/
if (addNISObject(domain, dn, &add_rc) == SUCCESS)
return (SUCCESS);
else if (add_rc != LDAP_NO_SUCH_OBJECT)
return (FAILURE);
}
/* Create parent */
if (addParent(dn, NULL) == FAILURE)
return (FAILURE);
if (addNISObject(domain, dn, NULL) == FAILURE)
return (FAILURE);
return (SUCCESS);
}
suc_code
addParent(char *dn, char **attr) {
__nis_rule_value_t *rv;
__nis_ldap_search_t *ls;
int rc, nr;
char *parentdn = 0, *rdn = 0;
char *myself = "addParent";
/* Obtain parentdn */
if (splitDN(dn, &rdn, &parentdn) == -1)
return (FAILURE);
if (!parentdn) {
sfree(rdn);
return (FAILURE);
}
/* Check if parentdn exists */
ls = buildLdapSearch(parentdn, LDAP_SCOPE_BASE, 0, 0,
"objectclass=*", 0, 0, 0);
if (ls == 0) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Unable to create ldapSearch request for "
"parent (dn: %s) of (dn: %s)",
myself, parentdn, dn);
sfree(parentdn);
sfree(rdn);
return (FAILURE);
}
nr = -1;
rv = ldapSearch(ls, &nr, 0, &rc);
freeLdapSearch(ls);
freeRuleValue(rv, nr);
/* Create parent if it doesn't exists */
if (rc == LDAP_NO_SUCH_OBJECT) {
if (makeNISObject(0, parentdn) == FAILURE) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: Unable to create parent (dn: %s) of "
"(dn: %s) in the DIT", myself, parentdn, dn);
sfree(parentdn);
sfree(rdn);
return (FAILURE);
}
}
sfree(parentdn);
if (attr && rdn)
*attr = (char *)getObjectClass(rdn);
sfree(rdn);
return (SUCCESS);
}
/*
* FUNCTION : is_fatal_error()
*
* DESCRIPTION: Works out if a failed mapping operation should be retried.
*
* INPUTS : Result code from operation
*
* OUTPUTS : TRUE = Fatal error, don't retry.
* FALSE = Temporary error, retry.
*/
bool_t
is_fatal_error(int res)
{
if (0 > res)
/* An internal mapping error. Not going to go away. */
return (TRUE);
switch (res) {
case (LDAP_PROTOCOL_ERROR):
case (LDAP_TIMELIMIT_EXCEEDED):
case (LDAP_PARTIAL_RESULTS):
case (LDAP_BUSY):
case (LDAP_UNAVAILABLE):
case (LDAP_UNWILLING_TO_PERFORM):
case (LDAP_OTHER):
case (LDAP_SERVER_DOWN):
case (LDAP_LOCAL_ERROR):
case (LDAP_TIMEOUT):
case (LDAP_NO_MEMORY):
/* Probably worth a retry */
return (FALSE);
default:
return (TRUE);
}
}
/*
* FUNCTION : addNISObject()
*
* DESCRIPTION: Add a nis Object in the DIT.
*
* GIVEN :
* Case 1: 'dn' is NULL
* Error
* Case 2: 'domain' is non-NULL
* Create nisDomainObject with the given information
* Case 3: 'domain' is NULL
* Create an object with the 'dn'
* Here we guess the objectclass attribute, based on
* oc_lookup table
*
* RETURNS : SUCCESS = It worked
* FAILURE = There was a problem. If the ldap add
* operation failed, ldap_rc will be set
* to the ldap error code.
*/
suc_code
addNISObject(char *domain, char *dn, int *ldap_rc) {
__nis_rule_value_t *rv;
int rc;
char *objClassAttrs = NULL, *attrs;
char *value, *svalue, *rdn = NULL;
char *myself = "addNISObject";
if (!dn)
return (FAILURE);
if ((rv = initRuleValue(1, 0)) == 0)
return (FAILURE);
if (ldap_rc)
*ldap_rc = -1;
/*
* Add name=value pairs from RDN. Although this is not required
* for SunOne Directory Server, during openldap interoperabilty
* tests, it was found out that openldap server returned object
* class violation errors if MUST attributes were not specified
* explicitly.
*/
if (splitDN(dn, &rdn, 0) == -1)
return (FAILURE);
if (rdn != NULL) {
objClassAttrs = (char *)getObjectClass(rdn);
if (objClassAttrs == NULL) {
sfree(rdn);
return (FAILURE);
}
/*
* RDN can be composed of multiple name=value pairs
* concatenated by '+'. Hence, we need to determine each
* pair and add it to 'rv'
*/
for (value = rdn, svalue = NULL; *value != '\0'; value++) {
if (*value == '+') {
/* Make sure it's not escaped */
if (value == rdn || *(value - 1) != '\\') {
/*
* We are at the start of the new
* pair. 'svalue' now contains the
* value for the previous pair. Add
* the previous pair to 'rv'
*/
*value = '\0';
if (svalue &&
addSAttr2RuleValue(rdn, svalue, rv)
== -1) {
sfree(rdn);
freeRuleValue(rv, 1);
return (FAILURE);
}
svalue = NULL;
rdn = value + 1;
continue;
}
}
if (*value == '=') {
if (value == rdn || *(value - 1) != '\\') {
/*
* 'rdn' now contains the name.
* Whatever follows till the next
* unescaped '+' or '\0' is the
* value for this pair.
*/
*value = '\0';
svalue = value + 1;
continue;
}
}
}
/*
* End of String. Add the previous name=value pair to 'rv'
*/
if (svalue && addSAttr2RuleValue(rdn, svalue, rv) == -1) {
sfree(rdn);
freeRuleValue(rv, 1);
return (FAILURE);
}
sfree(rdn);
} else /* rdn == NULL */
return (FAILURE);
/* Create the entry */
if (domain) {
if (addSAttr2RuleValue("nisDomain", domain, rv) == -1) {
freeRuleValue(rv, 1);
return (FAILURE);
}
attrs = scat(myself, F, "objectclass=nisdomainobject,",
objClassAttrs);
if (!attrs) {
freeRuleValue(rv, 1);
return (FAILURE);
}
rc = ldapAdd(dn, rv, attrs, 0);
sfree(attrs);
} else {
rc = ldapAdd(dn, rv, objClassAttrs, 0);
}
if (rc == LDAP_SUCCESS)
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"%s: Entry (dn: %s) added to DIT",
myself, dn);
else if (rc == LDAP_ALREADY_EXISTS)
/* Treat this as success */
rc = LDAP_SUCCESS;
else
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"%s: ldapAdd error %d (%s) for (dn: %s)",
myself, rc, ldap_err2string(rc), dn);
freeRuleValue(rv, 1);
if (ldap_rc)
*ldap_rc = rc;
return ((rc == LDAP_SUCCESS)?SUCCESS:FAILURE);
}