mirror of
https://github.com/samba-team/samba.git
synced 2025-01-14 19:24:43 +03:00
51d5ddecc6
an attribute as only appearing in searches that explicitly name it. It will be used for attributes like nTSecurityDescriptor (This used to be commit f5cd3d733b71368ea652f8a4d653d87f45ff983f)
273 lines
6.4 KiB
C
273 lines
6.4 KiB
C
/*
|
|
ldb database library
|
|
|
|
Copyright (C) Andrew Tridgell 2004
|
|
|
|
** NOTE! The following LGPL license applies to the ldb
|
|
** library. This does NOT imply that all of Samba is released
|
|
** under the LGPL
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Name: ldb
|
|
*
|
|
* Component: ldb tdb cache functions
|
|
*
|
|
* Description: cache special records in a ldb/tdb
|
|
*
|
|
* Author: Andrew Tridgell
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "ldb/ldb_tdb/ldb_tdb.h"
|
|
|
|
/*
|
|
initialise the baseinfo record
|
|
*/
|
|
static int ltdb_baseinfo_init(struct ldb_context *ldb)
|
|
{
|
|
struct ltdb_private *ltdb = ldb->private_data;
|
|
struct ldb_message msg;
|
|
struct ldb_message_element el;
|
|
struct ldb_val val;
|
|
int ret;
|
|
|
|
ltdb->sequence_number = 0;
|
|
|
|
msg.num_elements = 1;
|
|
msg.elements = ⪙
|
|
msg.dn = ldb_strdup(ldb, LTDB_BASEINFO);
|
|
if (!msg.dn) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
el.name = ldb_strdup(ldb, LTDB_SEQUENCE_NUMBER);
|
|
if (!el.name) {
|
|
ldb_free(ldb, msg.dn);
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
el.values = &val;
|
|
el.num_values = 1;
|
|
el.flags = 0;
|
|
val.data = ldb_strdup(ldb, "0");
|
|
if (!val.data) {
|
|
ldb_free(ldb, el.name);
|
|
ldb_free(ldb, msg.dn);
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
val.length = 1;
|
|
|
|
ret = ltdb_store(ldb, &msg, TDB_INSERT);
|
|
|
|
ldb_free(ldb, msg.dn);
|
|
ldb_free(ldb, el.name);
|
|
ldb_free(ldb, val.data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
free any cache records
|
|
*/
|
|
void ltdb_cache_free(struct ldb_context *ldb)
|
|
{
|
|
struct ltdb_private *ltdb = ldb->private_data;
|
|
struct ldb_alloc_ops alloc = ldb->alloc_ops;
|
|
ldb->alloc_ops.alloc = NULL;
|
|
|
|
ltdb->sequence_number = 0;
|
|
ltdb_search_dn1_free(ldb, <db->cache.baseinfo);
|
|
ltdb_search_dn1_free(ldb, <db->cache.indexlist);
|
|
ltdb_search_dn1_free(ldb, <db->cache.subclasses);
|
|
ltdb_search_dn1_free(ldb, <db->cache.attributes);
|
|
|
|
ldb_free(ldb, ltdb->cache.last_attribute.name);
|
|
memset(<db->cache, 0, sizeof(ltdb->cache));
|
|
|
|
ldb->alloc_ops = alloc;
|
|
}
|
|
|
|
/*
|
|
load the cache records
|
|
*/
|
|
int ltdb_cache_load(struct ldb_context *ldb)
|
|
{
|
|
struct ltdb_private *ltdb = ldb->private_data;
|
|
double seq;
|
|
struct ldb_alloc_ops alloc = ldb->alloc_ops;
|
|
|
|
ldb->alloc_ops.alloc = NULL;
|
|
|
|
ltdb_search_dn1_free(ldb, <db->cache.baseinfo);
|
|
|
|
if (ltdb_search_dn1(ldb, LTDB_BASEINFO, <db->cache.baseinfo) == -1) {
|
|
goto failed;
|
|
}
|
|
|
|
/* possibly initialise the baseinfo */
|
|
if (!ltdb->cache.baseinfo.dn) {
|
|
if (ltdb_baseinfo_init(ldb) != 0) {
|
|
goto failed;
|
|
}
|
|
if (ltdb_search_dn1(ldb, LTDB_BASEINFO, <db->cache.baseinfo) != 1) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
/* if the current internal sequence number is the same as the one
|
|
in the database then assume the rest of the cache is OK */
|
|
seq = ldb_msg_find_double(<db->cache.baseinfo, LTDB_SEQUENCE_NUMBER, 0);
|
|
if (seq == ltdb->sequence_number) {
|
|
goto done;
|
|
}
|
|
ltdb->sequence_number = seq;
|
|
|
|
ldb_free(ldb, ltdb->cache.last_attribute.name);
|
|
memset(<db->cache.last_attribute, 0, sizeof(ltdb->cache.last_attribute));
|
|
|
|
ltdb_search_dn1_free(ldb, <db->cache.indexlist);
|
|
ltdb_search_dn1_free(ldb, <db->cache.subclasses);
|
|
ltdb_search_dn1_free(ldb, <db->cache.attributes);
|
|
|
|
if (ltdb_search_dn1(ldb, LTDB_INDEXLIST, <db->cache.indexlist) == -1) {
|
|
goto failed;
|
|
}
|
|
if (ltdb_search_dn1(ldb, LTDB_SUBCLASSES, <db->cache.subclasses) == -1) {
|
|
goto failed;
|
|
}
|
|
if (ltdb_search_dn1(ldb, LTDB_ATTRIBUTES, <db->cache.attributes) == -1) {
|
|
goto failed;
|
|
}
|
|
|
|
done:
|
|
ldb->alloc_ops = alloc;
|
|
return 0;
|
|
|
|
failed:
|
|
ldb->alloc_ops = alloc;
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
increase the sequence number to indicate a database change
|
|
*/
|
|
int ltdb_increase_sequence_number(struct ldb_context *ldb)
|
|
{
|
|
struct ltdb_private *ltdb = ldb->private_data;
|
|
struct ldb_message msg;
|
|
struct ldb_message_element el;
|
|
struct ldb_val val;
|
|
char *s = NULL;
|
|
int ret;
|
|
|
|
ldb_asprintf(ldb, &s, "%.0f", ltdb->sequence_number+1);
|
|
if (!s) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
msg.num_elements = 1;
|
|
msg.elements = ⪙
|
|
msg.dn = ldb_strdup(ldb, LTDB_BASEINFO);
|
|
el.name = ldb_strdup(ldb, LTDB_SEQUENCE_NUMBER);
|
|
el.values = &val;
|
|
el.num_values = 1;
|
|
el.flags = LDB_FLAG_MOD_REPLACE;
|
|
val.data = s;
|
|
val.length = strlen(s);
|
|
|
|
ret = ltdb_modify_internal(ldb, &msg);
|
|
|
|
ldb_free(ldb, s);
|
|
ldb_free(ldb, msg.dn);
|
|
ldb_free(ldb, el.name);
|
|
|
|
if (ret == 0) {
|
|
ltdb->sequence_number += 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
return the attribute flags from the @ATTRIBUTES record
|
|
for the given attribute
|
|
*/
|
|
int ltdb_attribute_flags(struct ldb_context *ldb, const char *attr_name)
|
|
{
|
|
struct ltdb_private *ltdb = ldb->private_data;
|
|
const char *attrs;
|
|
const struct {
|
|
const char *name;
|
|
int value;
|
|
} names[] = {
|
|
{ "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
|
|
{ "INTEGER", LTDB_FLAG_INTEGER },
|
|
{ "WILDCARD", LTDB_FLAG_WILDCARD },
|
|
{ "HIDDEN", LTDB_FLAG_HIDDEN },
|
|
{ NULL, 0}
|
|
};
|
|
size_t len;
|
|
int i, ret=0;
|
|
struct ldb_alloc_ops alloc = ldb->alloc_ops;
|
|
|
|
if (ltdb->cache.last_attribute.name &&
|
|
ldb_attr_cmp(ltdb->cache.last_attribute.name, attr_name) == 0) {
|
|
return ltdb->cache.last_attribute.flags;
|
|
}
|
|
|
|
/* objectclass is a special default case */
|
|
if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
|
|
ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
|
|
}
|
|
|
|
attrs = ldb_msg_find_string(<db->cache.attributes, attr_name, NULL);
|
|
|
|
if (!attrs) {
|
|
return ret;
|
|
}
|
|
|
|
/* we avoid using strtok and friends due to their nasty
|
|
interface. This is a little trickier, but much nicer
|
|
from a C interface point of view */
|
|
while ((len = strcspn(attrs, " ,")) > 0) {
|
|
for (i=0;names[i].name;i++) {
|
|
if (strncmp(names[i].name, attrs, len) == 0 &&
|
|
names[i].name[len] == 0) {
|
|
ret |= names[i].value;
|
|
}
|
|
}
|
|
attrs += len;
|
|
attrs += strspn(attrs, " ,");
|
|
}
|
|
|
|
ldb->alloc_ops.alloc = NULL;
|
|
|
|
ldb_free(ldb, ltdb->cache.last_attribute.name);
|
|
|
|
ltdb->cache.last_attribute.name = ldb_strdup(ldb, attr_name);
|
|
ltdb->cache.last_attribute.flags = ret;
|
|
|
|
ldb->alloc_ops = alloc;
|
|
|
|
return ret;
|
|
}
|