#include "portable.h"
#include <stdio.h>
#include <ac/socket.h>
#include <ac/string.h>
#include "slap.h"
#include "back-netinfo.h"
static Attribute *dsattribute_to_attribute LDAP_P ((BackendDB *be, dsrecord *r, dsattribute *a, u_int32_t sel));
static dsattribute *attribute_to_dsattribute LDAP_P ((BackendDB *be, u_int32_t dsid, Attribute *attr, u_int32_t *sel));
u_int32_t ad_to_dsdata_type(AttributeDescription *ad)
{
u_int32_t type;
AttributeType *at = ad->ad_type;
char *printableType;
if (is_at_syntax(at, SLAPD_OCTETSTRING_SYNTAX) ||
slap_ad_is_binary(ad))
{
type = DataTypeBlob;
}
else if (is_at_syntax(at, SLAPD_DN_SYNTAX))
{
type = DataTypeDirectoryID;
}
else if (is_at_syntax(at, "1.3.6.1.4.1.1466.115.121.1.15"))
{
if (at->sat_equality != NULL &&
strcmp(at->sat_equality->smr_oid, "2.5.13.5") == 0)
type = DataTypeUTF8Str;
else
type = DataTypeCaseUTF8Str;
}
else
{
if (at->sat_equality != NULL &&
strcmp(at->sat_equality->smr_oid, "1.3.6.1.4.1.1466.109.114.1") == 0)
type = DataTypeCStr;
else
type = DataTypeCaseCStr;
}
switch (type)
{
case DataTypeBlob: printableType = "DataTypeBlob"; break;
case DataTypeDirectoryID: printableType = "DataTypeDirectoryID"; break;
case DataTypeUTF8Str: printableType = "DataTypeUTF8Str"; break;
case DataTypeCaseUTF8Str: printableType = "DataTypeCaseUTF8Str"; break;
case DataTypeCStr: printableType = "DataTypeCStr"; break;
case DataTypeCaseCStr: printableType = "DataTypeCaseCStr"; break;
default: printableType = "<unknown>"; break;
}
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "ad_to_dsdata_type %s %s\n", ad->ad_cname.bv_val, printableType));
#else
Debug(LDAP_DEBUG_TRACE, "<=> ad_to_dsdata_type attribute=%s type=%s\n", ad->ad_cname.bv_val, printableType, 0);
#endif
return type;
}
struct berval *dsdata_to_berval(struct berval *bv, dsdata *data)
{
bv->bv_len = data->length;
if (IsStringDataType(data->type))
{
bv->bv_len--;
}
bv->bv_val = ch_malloc(data->length);
memmove(bv->bv_val, data->data, data->length);
return bv;
}
struct berval *dsdata_to_berval_no_copy(struct berval *bv, dsdata *data)
{
bv->bv_len = data->length;
if (IsStringDataType(data->type))
{
bv->bv_len--;
}
bv->bv_val = data->data;
return bv;
}
dsdata *berval_to_dsdata(struct berval *bv, u_int32_t type)
{
dsdata *d;
if (IsStringDataType(type))
{
d = dsdata_alloc(bv->bv_len + 1);
assert(d != NULL);
d->type = type;
d->retain = 1;
memmove(d->data, bv->bv_val, bv->bv_len);
d->data[bv->bv_len] = '\0';
}
else
{
d = dsdata_new(type, bv->bv_len, bv->bv_val);
assert(d != NULL);
}
return d;
}
dsdata *berval_to_dsdata_no_copy(dsdata *dst, struct berval *bv, u_int32_t type)
{
if (IsStringDataType(type))
{
dst->length = bv->bv_len + 1;
}
else
{
dst->length = bv->bv_len;
}
dst->retain = 1;
dst->type = type;
dst->data = bv->bv_val;
return dst;
}
dsstatus dsrecord_to_entry(BackendDB *be, dsrecord *rec, Entry **pEntry)
{
Entry *ent;
Attribute *attr, **attrp;
int i;
dsstatus status;
ent = (Entry *)ch_calloc(1, sizeof(Entry));
ent->e_id = (ID)rec->dsid;
ent->e_bv.bv_val = NULL;
ent->e_ocflags = 0;
status = netinfo_back_global_dn(be, rec->dsid, &ent->e_name);
if (status != DSStatusOK)
{
ch_free(ent);
return status;
}
if (dnNormalize(0, NULL, NULL, &ent->e_name, &ent->e_nname, NULL) != LDAP_SUCCESS)
{
ch_free(ent->e_name.bv_val);
return DSStatusInvalidPath;
}
dsrecord_retain(rec);
ent->e_private = (void *)rec;
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "dsrecord_to_entry: dSID %u DN %s\n",
rec->dsid, ent->e_name.bv_val));
#else
Debug(LDAP_DEBUG_TRACE, "==> dsrecord_to_entry dsid=%u dn=%s\n", rec->dsid, ent->e_name.bv_val, 0);
#endif
ent->e_attrs = NULL;
attrp = &ent->e_attrs;
for (i = 0; i < rec->count; i++)
{
attr = dsattribute_to_attribute(be, rec, rec->attribute[i], SELECT_ATTRIBUTE);
if (attr == NULL)
continue;
*attrp = attr;
attrp = &attr->a_next;
}
for (i = 0; i < rec->meta_count; i++)
{
attr = dsattribute_to_attribute(be, rec, rec->meta_attribute[i], SELECT_META_ATTRIBUTE);
if (attr == NULL)
continue;
*attrp = attr;
attrp = &attr->a_next;
}
schemamap_add_objectclasses(be, SUPER(rec), ent);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dsrecord_to_entry: done\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== dsrecord_to_entry\n", 0, 0, 0);
#endif
*pEntry = ent;
return DSStatusOK;
}
dsstatus entry_to_dsrecord(BackendDB *be, u_int32_t super, Entry *e, dsrecord **pRecord)
{
dsrecord *rec;
Attribute *attr;
LDAPRDN rdn;
u_int32_t tmp, sel;
struct atmap map;
dsattribute *a;
struct berval _rdn;
char *p;
dsdata *rdnValue;
AttributeDescription *ad = NULL;
const char *text;
dsstatus status;
struct dsinfo *di = (struct dsinfo *)be->be_private;
if (dnExtractRdn(&e->e_name, &_rdn, NULL) != LDAP_SUCCESS)
{
return DSStatusInvalidPath;
}
if (ldap_str2rdn(_rdn.bv_val, &rdn, &p, LDAP_DN_FORMAT_LDAP) != LDAP_SUCCESS)
{
ch_free(_rdn.bv_val);
return DSStatusFailed;
}
ch_free(_rdn.bv_val);
if (slap_bv2ad(&rdn[0][0].la_attr, &ad, &text) != LDAP_SUCCESS)
{
ldap_rdnfree(rdn);
return DSStatusFailed;
}
status = schemamap_x500_to_ni_at(be, super, ad, &map);
if (status != DSStatusOK)
{
ldap_rdnfree(rdn);
return status;
}
status = (map.x500ToNiTransform)(be, &rdnValue, &rdn[0][0].la_value, map.type, map.x500ToNiArg);
if (status != DSStatusOK)
{
schemamap_atmap_release(&map);
ldap_rdnfree(rdn);
return status;
}
ldap_rdnfree(rdn);
if (map.selector == SELECT_META_ATTRIBUTE)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
return DSStatusFailed;
}
if ((slapMode & SLAP_TOOL_MODE) == 0)
{
dsrecord *query;
query = dsrecord_new();
if (query == NULL)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
return DSStatusFailed;
}
a = dsattribute_new(map.ni_key);
if (a == NULL)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
dsrecord_release(query);
return DSStatusFailed;
}
dsattribute_append(a, rdnValue);
dsrecord_append_attribute(query, a, SELECT_ATTRIBUTE);
dsattribute_release(a);
status = dsengine_pathmatch(di->engine, super, query, &tmp);
if (status != DSStatusInvalidPath)
{
if (status == DSStatusOK)
status = DSStatusDuplicateRecord;
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
dsrecord_release(query);
return status;
}
dsrecord_release(query);
}
rec = dsrecord_new();
if (rec == NULL)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
return DSStatusFailed;
}
if (dsdata_equal(map.ni_key, (dsdata *)&netinfo_back_name_name) == 0)
{
dsdata *rdnKey;
rdnKey = dsdata_copy((dsdata *)&netinfo_back_name_rdn);
a = dsattribute_new(rdnKey);
if (a == NULL)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
dsdata_release(rdnKey);
return DSStatusFailed;
}
dsdata_release(rdnKey);
dsattribute_append(a, map.ni_key);
dsrecord_append_attribute(rec, a, SELECT_META_ATTRIBUTE);
dsattribute_release(a);
}
for (attr = e->e_attrs; attr != NULL; attr = attr->a_next)
{
a = attribute_to_dsattribute(be, super, attr, &sel);
if (a == NULL)
continue;
dsrecord_append_attribute(rec, a, sel);
dsattribute_release(a);
}
a = dsrecord_attribute(rec, map.ni_key, SELECT_ATTRIBUTE);
if (a == NULL)
{
a = dsattribute_new(map.ni_key);
if (a == NULL)
{
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
return DSStatusFailed;
}
dsrecord_append_attribute(rec, a, SELECT_ATTRIBUTE);
}
else
{
u_int32_t index;
index = dsattribute_index(a, rdnValue);
if (index != IndexNull)
{
dsattribute_remove(a, index);
}
}
dsattribute_insert(a, rdnValue, 0);
schemamap_atmap_release(&map);
dsdata_release(rdnValue);
dsattribute_release(a);
*pRecord = rec;
return DSStatusOK;
}
dsstatus dsattribute_to_bervals(BackendDB *be, BerVarray *pvals, dsattribute *a, struct atmap *map)
{
int i, j;
BerVarray vals;
if (a->count == 0)
return DSStatusInvalidKey;
vals = (BerVarray)ch_calloc(a->count + 1, sizeof(struct berval));
for (i = 0, j = 0; i < a->count; i++)
{
if ((map->niToX500Transform)(be, &vals[j], a->value[i], map->niToX500Arg) != DSStatusOK)
continue;
j++;
}
if (j == 0)
{
ch_free(vals);
return DSStatusInvalidKey;
}
vals[j].bv_val = NULL;
vals[j].bv_len = 0;
*pvals = vals;
return DSStatusOK;
}
static Attribute *dsattribute_to_attribute(BackendDB *be, dsrecord *rec, dsattribute *a, u_int32_t sel)
{
Attribute *attr;
dsstatus status;
struct atmap map;
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "dsattribute_to_attribute: dSID %d NetInfo attribute %s\n", rec->dsid, dsdata_to_cstring(a->key)));
#else
Debug(LDAP_DEBUG_TRACE, "==> dsattribute_to_attribute rec=%d key=%s\n", rec->dsid, dsdata_to_cstring(a->key), 0);
#endif
status = schemamap_ni_to_x500_at(be, SUPER(rec), a->key, sel, &map);
if (status != DSStatusOK)
{
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dsattribute_to_attribute: could not map attribute\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== dsattribute_to_attribute: could not map attribute\n", 0, 0, 0);
#endif
return NULL;
}
attr = (Attribute *)ch_malloc(sizeof(Attribute));
attr->a_next = NULL;
attr->a_desc = map.x500;
if (dsattribute_to_bervals(be, &attr->a_vals, a, &map) != DSStatusOK)
{
ch_free(attr);
schemamap_atmap_release(&map);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dsattribute_to_attribute: no values\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== dsattribute_to_attribute no values\n", 0, 0, 0);
#endif
return NULL;
}
if ( a->count && attr->a_desc->ad_type->sat_equality &&
attr->a_desc->ad_type->sat_equality->smr_normalize ) {
int i;
attr->a_nvals = ch_malloc((a->count + 1)*sizeof(struct berval));
for ( i = 0; i < a->count; i++ ) {
attr->a_desc->ad_type->sat_equality->smr_normalize(
SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
attr->a_desc->ad_type->sat_syntax,
attr->a_desc->ad_type->sat_equality,
&attr->a_vals[i], &attr->a_nvals[i],
NULL );
}
attr->a_nvals[i].bv_val = NULL;
attr->a_nvals[i].bv_len = 0;
} else {
attr->a_nvals = attr->a_vals;
}
schemamap_atmap_release(&map);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dsattribute_to_attribute: X.500 attribute %s flags %d\n",
attr->a_desc->ad_cname.bv_val, attr->a_desc->ad_flags, 0));
#else
Debug(LDAP_DEBUG_TRACE, "<== dsattribute_to_attribute cname=%s flags=%d\n",
attr->a_desc->ad_cname.bv_val, attr->a_desc->ad_flags, 0);
#endif
return attr;
}
dsattribute *attribute_to_dsattribute(BackendDB *be, u_int32_t dsid, Attribute *attr, u_int32_t *sel)
{
dsstatus status;
dsattribute *a;
struct berval *bvp;
struct atmap map;
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "attribute_to_dsattribute: X.500 attribute %s dSID %u\n", attr->a_desc->ad_cname.bv_val, dsid));
#else
Debug(LDAP_DEBUG_TRACE, "==> attribute_to_dsattribute %s dsid=%u\n", attr->a_desc->ad_cname.bv_val, dsid, 0);
#endif
status = schemamap_x500_to_ni_at(be, dsid, attr->a_desc, &map);
if (status != DSStatusOK)
return NULL;
*sel = map.selector;
a = dsattribute_new(map.ni_key);
if (a == NULL)
{
schemamap_atmap_release(&map);
return NULL;
}
for (bvp = attr->a_vals; bvp->bv_val != NULL; bvp++)
{
dsdata *d;
status = (map.x500ToNiTransform)(be, &d, bvp, map.type, map.x500ToNiArg);
if (status != DSStatusOK)
continue;
dsattribute_append(a, d);
dsdata_release(d);
}
schemamap_atmap_release(&map);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "attribute_to_dsattribute: done\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== attribute_to_dsattribute\n", 0, 0, 0);
#endif
return a;
}
int dsstatus_to_ldap_err(dsstatus status)
{
switch (status)
{
case DSStatusOK:
return LDAP_SUCCESS;
case DSStatusInvalidStore:
case DSStatusNoFile:
return LDAP_UNAVAILABLE;
case DSStatusDuplicateRecord:
return LDAP_ALREADY_EXISTS;
case DSStatusNoRootRecord:
case DSStatusInvalidRecordID:
case DSStatusInvalidPath:
return LDAP_NO_SUCH_OBJECT;
case DSStatusPathNotLocal:
return LDAP_REFERRAL;
case DSStatusConstraintViolation:
return LDAP_CONSTRAINT_VIOLATION;
case DSStatusNamingViolation:
return LDAP_NAMING_VIOLATION;
case DSStatusObjectClassViolation:
return LDAP_OBJECT_CLASS_VIOLATION;
case DSStatusInvalidKey:
return LDAP_NO_SUCH_ATTRIBUTE;
case DSStatusAccessRestricted:
return LDAP_INVALID_CREDENTIALS;
case DSStatusReadRestricted:
case DSStatusWriteRestricted:
return LDAP_INSUFFICIENT_ACCESS;
case DSStatusReadFailed:
case DSStatusWriteFailed:
case DSStatusInvalidUpdate:
return LDAP_OPERATIONS_ERROR;
case DSStatusInvalidRecord:
case DSStatusNoData:
case DSStatusStaleRecord:
case DSStatusInvalidSessionMode:
case DSStatusInvalidSession:
return LDAP_UNWILLING_TO_PERFORM;
case DSStatusLocked:
return LDAP_BUSY;
case DSStatusFailed:
return LDAP_OTHER;
}
return LDAP_OTHER;
}
int netinfo_back_op_result( struct slap_op *op, struct slap_rep *rs,
dsstatus status)
{
int rc;
char *message, *statusMessage;
struct dsinfo *di = (struct dsinfo *)op->o_bd->be_private;
BerVarray refs;
refs = NULL;
if (status == DSStatusPathNotLocal)
{
if (di->parent != NULL)
refs = di->parent->refs;
else
status = DSStatusInvalidPath;
}
rc = dsstatus_to_ldap_err(status);
statusMessage = dsstatus_message(status);
message = ch_malloc(strlen(statusMessage) + sizeof("DSAXXXX: "));
sprintf(message, "DSA%04u: %s", status, statusMessage);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "netinfo_back_op_result: status %d\n", status));
#else
Debug(LDAP_DEBUG_TRACE, "==> netinfo_back_op_result dsstatus=%d rc=%d msg=%s\n",
status, rc, message);
#endif
send_ldap_result(op, rs);
ch_free(message);
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "netinfo_back_op_result: result code %d message %s\n", rc, message));
#else
Debug(LDAP_DEBUG_TRACE, "<== netinfo_back_op_result\n", 0, 0, 0);
#endif
return (status == DSStatusOK) ? 0 : -1;
}
dsstatus dnMakeLocal(BackendDB *be, struct berval *localDN, struct berval *ndn)
{
int i, where;
struct dsinfo *di = (struct dsinfo *)be->be_private;
struct berval *nsuffix;
assert(di->nsuffix.bv_val != NULL);
nsuffix = NULL;
if (ndn == NULL || ndn->bv_len == 0)
{
localDN->bv_val = NULL;
localDN->bv_len = 0;
return DSStatusOK;
}
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, ARGS, "dnMakeLocal DN %s\n", ndn->bv_val));
#else
Debug(LDAP_DEBUG_TRACE, "==> dnMakeLocal dn=%s\n", ndn->bv_val, 0, 0);
#endif
if (dnIsSuffix(ndn, &di->nsuffix))
{
nsuffix = &di->nsuffix;
}
else
{
for (i = 0; be->be_nsuffix[i].bv_val != NULL; i++)
{
if (be->be_nsuffix[i].bv_len > 0 && dnIsSuffix(ndn, &be->be_nsuffix[i]))
{
nsuffix = &be->be_nsuffix[i];
break;
}
}
}
if (nsuffix == NULL)
{
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dnMakeLocal: not local to store\n"));
#else
Debug(LDAP_DEBUG_TRACE, "<== dnMakeLocal (not local to store)\n", 0, 0, 0);
#endif
return DSStatusPathNotLocal;
}
if (nsuffix->bv_len == ndn->bv_len)
{
where = 0;
}
else if (nsuffix->bv_len > 0)
{
where = ndn->bv_len - nsuffix->bv_len - 1;
}
else
{
where = ndn->bv_len;
}
assert(where >= 0);
if (where == 0)
{
localDN->bv_val = NULL;
localDN->bv_len = 0;
}
else
{
localDN->bv_val = ch_malloc(where + 1);
AC_MEMCPY(localDN->bv_val, ndn->bv_val, where);
localDN->bv_val[where] = '\0';
localDN->bv_len = where;
}
#ifdef NEW_LOGGING
LDAP_LOG((BACK_NETINFO, INFO, "dnMakeLocal: DN %s normalized suffix %s\n", (localDN->bv_val ? localDN->bv_val : ""), nsuffix->bv_val));
#else
Debug(LDAP_DEBUG_TRACE, "<== dnMakeLocal dn=%s nsuffix=%s\n", (localDN->bv_val ? localDN->bv_val : ""), nsuffix->bv_val, 0);
#endif
return DSStatusOK;
}
dsstatus dnMakeGlobal(BackendDB *be, struct berval *globalDN, struct berval *localDN)
{
struct dsinfo *di = (struct dsinfo *)be->be_private;
assert(di->suffix.bv_val != NULL);
if (localDN->bv_len > 0)
{
if (di->suffix.bv_len > 0)
{
build_new_dn(globalDN, &di->suffix, localDN, NULL);
}
else
{
ber_dupbv(globalDN, localDN);
}
}
else
{
ber_dupbv(globalDN, &di->suffix);
}
return DSStatusOK;
}
dsstatus netinfo_back_global_dn(BackendDB *be, u_int32_t dsid, struct berval *globalDN)
{
dsstatus status;
struct berval localDN;
status = netinfo_back_local_dn(be, dsid, &localDN);
if (status != DSStatusOK)
return status;
status = dnMakeGlobal(be, globalDN, &localDN);
ch_free(localDN.bv_val);
return status;
}
dsstatus netinfo_back_local_dn(BackendDB *be, u_int32_t dsid, struct berval *localDN)
{
dsrecord *r = NULL;
dsstatus status;
struct dsinfo *di = (struct dsinfo *)be->be_private;
LDAPDN dn = NULL;
u_int32_t depth;
if (dsid == 0)
{
dn = NULL;
status = DSStatusOK;
goto out;
}
status = dsengine_fetch(di->engine, dsid, &r);
if (status != DSStatusOK)
{
goto out;
}
depth = 1;
while (r->dsid != 0)
{
dsrecord *parent;
dsdata *rdnKey, *rdnValue;
dsattribute *rdnSelector, *rdnAttribute;
LDAPRDN rdn;
LDAPAVA *ava;
struct atmap map;
char tmp[32];
struct berval *attrname = NULL;
rdnSelector = dsrecord_attribute(r, (dsdata *)&netinfo_back_name_rdn,
SELECT_META_ATTRIBUTE);
if (rdnSelector == NULL || rdnSelector->count == 0)
rdnKey = dsdata_retain((dsdata *)&netinfo_back_name_name);
else
rdnKey = dsdata_retain(rdnSelector->value[0]);
dsattribute_release(rdnSelector);
rdnAttribute = dsrecord_attribute(r, rdnKey, SELECT_ATTRIBUTE);
if (rdnAttribute == NULL)
{
rdnValue = NULL;
attrname = &netinfo_back_ad_dSID->ad_cname;
}
else
{
rdnValue = dsdata_retain(rdnAttribute->value[0]);
dsattribute_release(rdnAttribute);
status = schemamap_ni_to_x500_at(be, SUPER(r), rdnKey, SELECT_ATTRIBUTE, &map);
if (status != DSStatusOK)
{
dsdata_release(rdnKey);
dsdata_release(rdnValue);
goto out;
}
attrname = &map.x500->ad_cname;
}
dsdata_release(rdnKey);
assert(attrname != NULL);
ava = (LDAPAVA *)ch_malloc(sizeof(LDAPAVA) + attrname->bv_len + 1);
ava->la_private = NULL;
ava->la_flags = 0;
ava->la_attr.bv_len = attrname->bv_len;
ava->la_attr.bv_val = (char *)(ava + 1);
AC_MEMCPY(ava->la_attr.bv_val, attrname->bv_val, attrname->bv_len);
ava->la_attr.bv_val[attrname->bv_len] = '\0';
if (rdnValue == NULL)
{
snprintf(tmp, sizeof(tmp), "%u", r->dsid);
ava->la_value.bv_val = ch_strdup(tmp);
ava->la_value.bv_len = strlen(ava->la_value.bv_val);
ava->la_flags = LDAP_AVA_STRING;
}
else
{
status = (map.niToX500Transform)(be, &ava->la_value, rdnValue, map.niToX500Arg);
if (status != DSStatusOK)
{
dsdata_release(rdnValue);
ldapava_free(ava, NULL);
schemamap_atmap_release(&map);
goto out;
}
ava->la_flags = IsStringDataType(rdnValue->type) ? LDAP_AVA_STRING : LDAP_AVA_BINARY;
dsdata_release(rdnValue);
}
schemamap_atmap_release(&map);
status = dsengine_fetch(di->engine, r->super, &parent);
if (status != DSStatusOK)
{
ldapava_free(ava, NULL);
goto out;
}
dsrecord_release(r);
r = parent;
rdn = (LDAPRDN)ch_malloc(2 * sizeof(LDAPAVA *));
rdn[0] = ava;
rdn[1] = NULL;
dn = (LDAPDN)ch_realloc(dn, (depth + 1) * sizeof(LDAPRDN *));
(LDAPRDN *)(dn[depth - 1]) = rdn;
dn[depth] = NULL;
depth++;
}
out:
if (status == DSStatusOK)
{
int rc;
rc = ldap_dn2bv(dn, localDN, LDAP_DN_FORMAT_LDAPV3 | LDAP_DN_PRETTY);
if (rc != LDAP_SUCCESS)
status = DSStatusInvalidPath;
}
if (dn != NULL)
ldap_dnfree(dn);
if (r != NULL)
dsrecord_release(r);
return status;
}
dsstatus
netinfo_back_parse_dn(BackendDB *be, struct berval *path, dsrecord **pr)
{
dsrecord *r;
LDAPDN dn;
int i, max;
dsattribute *a;
struct dsinfo *di = (struct dsinfo *)be->be_private;
u_int32_t dsid;
dsstatus status = DSStatusOK;
if (ldap_bv2dn(path, &dn, LDAP_DN_FORMAT_LDAP) != LDAP_SUCCESS)
return DSStatusInvalidPath;
for (i = 0; dn[0][i] != NULL; i++)
;
max = i;
r = dsrecord_new();
if (r == NULL)
{
status = DSStatusFailed;
goto out;
}
if (max == 0)
{
status = DSStatusOK;
goto out;
}
max--;
dsid = 0;
for (i = max; i >= 0; i--)
{
dsdata *value;
dsrecord *query;
struct atmap map;
AttributeDescription *ad = NULL;
const char *text = NULL;
if (dn[i][1] != NULL)
{
status = DSStatusInvalidPath;
goto out;
}
if (slap_bv2ad(&dn[i][0][0].la_attr, &ad, &text) != LDAP_SUCCESS)
{
status = DSStatusInvalidKey;
goto out;
}
status = schemamap_x500_to_ni_at(be, dsid, ad, &map);
if (status != DSStatusOK)
{
goto out;
}
status = (map.x500ToNiTransform)(be, &value, &dn[i][0][0].la_value, DataTypeCaseUTF8Str, map.x500ToNiArg);
if (status != DSStatusOK)
{
schemamap_atmap_release(&map);
goto out;
}
a = dsattribute_new(map.ni_key);
if (a == NULL)
{
schemamap_atmap_release(&map);
status = DSStatusFailed;
goto out;
}
dsattribute_append(a, value);
dsdata_release(value);
dsrecord_append_attribute(r, a, SELECT_ATTRIBUTE);
schemamap_atmap_release(&map);
if (i != 0)
{
query = dsrecord_new();
if (query == NULL)
{
status = DSStatusFailed;
dsattribute_release(a);
goto out;
}
dsrecord_append_attribute(query, a, SELECT_ATTRIBUTE);
status = dsengine_pathmatch(di->engine, dsid, query, &dsid);
dsrecord_release(query);
}
dsattribute_release(a);
if (status != DSStatusOK)
goto out;
}
out:
ldap_dnfree(dn);
if (status != DSStatusOK)
dsrecord_release(r);
else
*pr = r;
return status;
}
dsstatus netinfo_back_dn_pathmatch(BackendDB *be, struct berval *ndn, u_int32_t *match)
{
dsstatus status;
struct dsinfo *di = (struct dsinfo *)be->be_private;
struct berval localDN;
dsrecord *path;
size_t n;
status = dnMakeLocal(be, &localDN, ndn);
if (status != DSStatusOK)
{
return status;
}
if (localDN.bv_len == 0)
{
*match = 0;
return DSStatusOK;
}
if (strncasecmp(localDN.bv_val, "dSID=", (n = (sizeof("dSID=") - 1))) == 0 ||
strncmp(localDN.bv_val, "1.3.6.1.4.1.5322.14.1.1=", (n = (sizeof("1.3.6.1.4.1.5322.14.1.1=") - 1))) == 0)
{
char *p = NULL;
*match = strtoul(localDN.bv_val + n, &p, 10);
if (p == NULL || (*p != ',' && *p != '\0'))
status = DSStatusInvalidPath;
ch_free(localDN.bv_val);
return status;
}
status = netinfo_back_parse_dn(be, &localDN, &path);
if (status == DSStatusOK)
{
status = dsengine_pathmatch(di->engine, 0, path, match);
dsrecord_release(path);
}
ch_free(localDN.bv_val);
return status;
}
dsstatus netinfo_back_dn_pathcreate(BackendDB *be, struct berval *ndn, u_int32_t *match)
{
dsstatus status;
struct dsinfo *di = (struct dsinfo *)be->be_private;
struct berval localDN;
dsrecord *path;
status = dnMakeLocal(be, &localDN, ndn);
if (status != DSStatusOK)
{
return status;
}
if (localDN.bv_len == 0)
{
*match = 0;
return DSStatusOK;
}
status = netinfo_back_parse_dn(be, &localDN, &path);
if (status == DSStatusOK)
{
status = dsengine_pathcreate(di->engine, 0, path, match);
dsrecord_release(path);
}
ch_free(localDN.bv_val);
return status;
}
dsstatus netinfo_back_send_referrals(struct slap_op *op,
struct slap_rep *rs, struct berval *nbase)
{
struct dsinfo *di = (struct dsinfo *)op->o_bd->be_private;
struct netinfo_referral **p;
#ifdef NO_NETINFO_REFERRALS
return DSStatusInvalidPath;
#endif
if (di->children == NULL)
return DSStatusInvalidPath;
if (get_manageDSAit(op))
return DSStatusInvalidPath;
for (p = di->children; *p != NULL; p++)
{
if (dnIsSuffix(nbase, &(*p)->nnc))
{
rs->sr_err = LDAP_REFERRAL;
rs->sr_ref = (*p)->refs;
rs->sr_matched = (*p)->nc.bv_val;
send_ldap_result(op, rs);
return DSStatusOK;
}
}
return DSStatusInvalidPath;
}
dsstatus netinfo_back_send_references(struct slap_op *op, struct slap_rep *rs, struct berval *relativeBase)
{
struct dsinfo *di = (struct dsinfo *)op->o_bd->be_private;
struct netinfo_referral *parent;
Entry *e;
int i;
BerVarray refs;
if (op->ors_scope == LDAP_SCOPE_BASE)
return DSStatusOK;
if (di->parent == NULL)
return DSStatusOK;
if (get_manageDSAit(op))
return DSStatusOK;
e = (Entry *)ch_calloc(1, sizeof(Entry));
e->e_attrs = NULL;
e->e_private = NULL;
e->e_id = NOID;
e->e_bv.bv_val = NULL;
e->e_ocflags = 0;
parent = di->parent;
if (relativeBase->bv_len == 0)
{
ber_dupbv(&e->e_name, &parent->nc);
}
else
{
if (parent->nc.bv_len > 0)
build_new_dn(&e->e_name, &parent->nc, relativeBase, NULL);
else
ber_dupbv(&e->e_name, relativeBase);
}
if (dnNormalize(0, NULL, NULL, &e->e_name, &e->e_nname, NULL) != LDAP_SUCCESS)
{
ch_free(e->e_name.bv_val);
return DSStatusInvalidPath;
}
refs = (BerVarray)ch_malloc((parent->count + 1) * sizeof(struct berval));
for (i = 0; i < parent->count; i++)
{
char *p;
assert(parent->refs[i].bv_val[parent->refs[i].bv_len - 1] == '/');
refs[i].bv_len = parent->refs[i].bv_len + e->e_name.bv_len +
sizeof("??XXX") - 1;
p = refs[i].bv_val = (char *)ch_malloc(refs[i].bv_len + 1);
AC_MEMCPY(p, parent->refs[i].bv_val, parent->refs[i].bv_len);
p += parent->refs[i].bv_len;
AC_MEMCPY(p, e->e_name.bv_val, e->e_name.bv_len);
p += e->e_name.bv_len;
if (op->ors_scope == LDAP_SCOPE_SUBTREE)
strcpy(p, "??sub");
else
strcpy(p, "??one");
}
refs[parent->count].bv_val = NULL;
refs[parent->count].bv_len = 0;
rs->sr_ref = refs;
send_search_reference(op, rs);
entry_free(e);
ber_bvarray_free(refs);
return DSStatusOK;
}
void netinfo_back_entry_free(Entry *ent)
{
assert(ent != NULL);
if (ent->e_private != NULL)
{
dsrecord_release((dsrecord *)ent->e_private);
ent->e_private = NULL;
}
entry_free(ent);
}
int netinfo_back_entry_release(
struct slap_op *op,
Entry *e,
int rw)
{
struct dsinfo *di = (struct dsinfo *)op->o_bd->be_private;
ENGINE_LOCK(di);
netinfo_back_entry_free(e);
ENGINE_UNLOCK(di);
return 0;
}