#include <sys/types.h>
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "ldapd.h"
#include "log.h"
static int
index_attribute(struct namespace *ns, char *attr, struct btval *dn,
struct ber_element *a)
{
int dnsz, rc;
char *s, *t;
struct ber_element *v;
struct btval key, val;
assert(ns);
assert(ns->indx_txn);
assert(attr);
assert(dn);
assert(a);
assert(a->be_next);
memset(&val, 0, sizeof(val));
log_debug("indexing %.*s on %s", (int)dn->size, (char *)dn->data, attr);
dnsz = dn->size - strlen(ns->suffix);
for (v = a->be_next->be_sub; v; v = v->be_next) {
if (ober_get_string(v, &s) != 0)
continue;
memset(&key, 0, sizeof(key));
key.size = asprintf(&t, "%s=%s,%.*s", attr, s, dnsz,
(char *)dn->data);
if (key.size == (size_t)-1)
return -1;
key.data = t;
normalize_dn(key.data);
rc = btree_txn_put(NULL, ns->indx_txn, &key, &val,
BT_NOOVERWRITE);
free(t);
if (rc == -1 && errno != EEXIST)
return -1;
}
return 0;
}
static int
index_rdn_key(struct namespace *ns, struct btval *dn, struct btval *key)
{
int dnsz, rdnsz, pdnsz;
char *t, *parent_dn;
memset(key, 0, sizeof(*key));
dnsz = dn->size - strlen(ns->suffix);
if (dnsz-- == 0)
return -1;
parent_dn = memchr(dn->data, ',', dnsz);
if (parent_dn == NULL) {
rdnsz = dnsz;
pdnsz = 0;
parent_dn = "";
} else {
rdnsz = parent_dn - (char *)dn->data;
pdnsz = dnsz - rdnsz - 1;
++parent_dn;
}
if (asprintf(&t, "@%.*s,%.*s", pdnsz, parent_dn, rdnsz,
(char *)dn->data) == -1)
return -1;
normalize_dn(t);
key->data = t;
key->size = strlen(t);
key->free_data = 1;
return 0;
}
static int
index_rdn(struct namespace *ns, struct btval *dn)
{
struct btval key, val;
int rc;
memset(&val, 0, sizeof(val));
assert(ns);
assert(ns->indx_txn);
assert(dn);
if (index_rdn_key(ns, dn, &key) < 0)
return 0;
log_debug("indexing rdn on %.*s", (int)key.size, (char *)key.data);
rc = btree_txn_put(NULL, ns->indx_txn, &key, &val, BT_NOOVERWRITE);
btval_reset(&key);
if (rc == -1 && errno != EEXIST)
return -1;
return 0;
}
static int
unindex_attribute(struct namespace *ns, char *attr, struct btval *dn,
struct ber_element *a)
{
int dnsz, rc;
char *s, *t;
struct ber_element *v;
struct btval key;
assert(ns);
assert(ns->indx_txn);
assert(attr);
assert(dn);
assert(a);
assert(a->be_next);
log_debug("unindexing %.*s on %s",
(int)dn->size, (char *)dn->data, attr);
dnsz = dn->size - strlen(ns->suffix);
for (v = a->be_next->be_sub; v; v = v->be_next) {
if (ober_get_string(v, &s) != 0)
continue;
memset(&key, 0, sizeof(key));
key.size = asprintf(&t, "%s=%s,%.*s", attr, s, dnsz,
(char *)dn->data);
key.data = t;
normalize_dn(key.data);
rc = btree_txn_del(NULL, ns->indx_txn, &key, NULL);
free(t);
if (rc == BT_FAIL && errno != ENOENT)
return -1;
}
return 0;
}
int
index_entry(struct namespace *ns, struct btval *dn, struct ber_element *elm)
{
struct ber_element *a;
struct attr_index *ai;
assert(ns);
assert(dn);
assert(elm);
TAILQ_FOREACH(ai, &ns->indices, next) {
a = ldap_get_attribute(elm, ai->attr);
if (a && index_attribute(ns, ai->attr, dn, a) < 0)
return -1;
}
return index_rdn(ns, dn);
}
static int
unindex_rdn(struct namespace *ns, struct btval *dn)
{
int rc;
struct btval key;
assert(ns);
assert(ns->indx_txn);
assert(dn);
if (index_rdn_key(ns, dn, &key) < 0)
return 0;
log_debug("unindexing rdn on %.*s", (int)key.size, (char *)key.data);
rc = btree_txn_del(NULL, ns->indx_txn, &key, NULL);
btval_reset(&key);
if (rc == BT_FAIL && errno != ENOENT)
return -1;
return 0;
}
int
unindex_entry(struct namespace *ns, struct btval *dn, struct ber_element *elm)
{
struct ber_element *a;
struct attr_index *ai;
assert(ns);
assert(dn);
assert(elm);
TAILQ_FOREACH(ai, &ns->indices, next) {
a = ldap_get_attribute(elm, ai->attr);
if (a && unindex_attribute(ns, ai->attr, dn, a) < 0)
return -1;
}
return unindex_rdn(ns, dn);
}
int
index_to_dn(struct namespace *ns, struct btval *indx, struct btval *dn)
{
char *rdn, *parent_rdn, indxtype, *dst;
int rdn_sz, prdn_sz;
indxtype = ((char *)indx->data)[0];
if (indxtype == '@') {
rdn = memrchr(indx->data, ',', indx->size);
if (rdn++ == NULL)
return -1;
rdn_sz = indx->size - (rdn - (char *)indx->data);
parent_rdn = (char *)indx->data + 1;
prdn_sz = rdn - parent_rdn - 1;
dn->size = indx->size + strlen(ns->suffix);
if (prdn_sz == 0)
dn->size--;
if ((dn->data = malloc(dn->size)) == NULL) {
log_warn("conn_search: malloc");
return -1;
}
dst = dn->data;
bcopy(rdn, dst, rdn_sz);
dst += rdn_sz;
*dst++ = ',';
bcopy(parent_rdn, dst, prdn_sz);
dst += prdn_sz;
if (prdn_sz > 0)
*dst++ = ',';
bcopy(ns->suffix, dst, strlen(ns->suffix));
} else {
rdn = memchr(indx->data, ',', indx->size);
if (rdn++ == NULL)
return -1;
rdn_sz = indx->size - (rdn - (char *)indx->data);
dn->size = rdn_sz + strlen(ns->suffix);
if ((dn->data = malloc(dn->size)) == NULL) {
log_warn("index_to_dn: malloc");
return -1;
}
bcopy(rdn, dn->data, rdn_sz);
bcopy(ns->suffix, (char *)dn->data + rdn_sz,
strlen(ns->suffix));
}
dn->free_data = 1;
return 0;
}