mirror of
https://github.com/samba-team/samba.git
synced 2024-12-24 21:34:56 +03:00
make a more recent snapshot of ldb available to interested
people. Note that I decided to make it LGPL.
ldb is not finished yet, but enough of it is there for people to get
an idea of what it does, and quite a few simple tests work
(This used to be commit dc6f41f9e7
)
This commit is contained in:
parent
4aa785b1b2
commit
58d50a614f
43
source4/lib/ldb/Makefile.ldb
Normal file
43
source4/lib/ldb/Makefile.ldb
Normal file
@ -0,0 +1,43 @@
|
||||
CFLAGS=-Wall -g -Iinclude -I. -DSTANDALONE=1 -DUSE_MMAP=1
|
||||
OPENLDAP=/home/tridge/samba/openldap/prefix
|
||||
|
||||
LIB_FLAGS=-Llib -lldb -L$(OPENLDAP)/lib -lldap
|
||||
|
||||
TDB_OBJ=tdb/tdb.o tdb/spinlock.o
|
||||
|
||||
LDB_TDB_OBJ=ldb_tdb/ldb_match.o ldb_tdb/ldb_tdb.o \
|
||||
ldb_tdb/ldb_pack.o ldb_tdb/ldb_search.o ldb_tdb/ldb_index.o
|
||||
|
||||
LDB_LDAP_OBJ=ldb_ldap/ldb_ldap.o
|
||||
|
||||
COMMON_OBJ=common/ldb.o common/ldb_ldif.o common/util.o common/ldb_parse.o
|
||||
|
||||
OBJS = $(COMMON_OBJ) $(LDB_TDB_OBJ) $(TDB_OBJ) $(LDB_LDAP_OBJ)
|
||||
|
||||
LDB_LIB = lib/libldb.a
|
||||
|
||||
BINS = bin/ldbadd bin/ldbsearch bin/ldbdel
|
||||
|
||||
LIBS = $(LDB_LIB)($(OBJS))
|
||||
|
||||
all: $(BINS) $(LIBS)
|
||||
|
||||
lib/libldb.a: $(OBJS)
|
||||
|
||||
bin/ldbadd: tools/ldbadd.o $(LIBS)
|
||||
$(CC) -o bin/ldbadd tools/ldbadd.o $(LIB_FLAGS)
|
||||
|
||||
bin/ldbsearch: tools/ldbsearch.o $(LIBS)
|
||||
$(CC) -o bin/ldbsearch tools/ldbsearch.o $(LIB_FLAGS)
|
||||
|
||||
bin/ldbdel: tools/ldbdel.o $(LIBS)
|
||||
$(CC) -o bin/ldbdel tools/ldbdel.o $(LIB_FLAGS)
|
||||
|
||||
clean:
|
||||
rm -f */*.o *~ */*~ $(BINS) $(LDB_LIB)
|
||||
|
||||
proto:
|
||||
mkproto.pl */*.c > include/proto.h
|
||||
|
||||
etags:
|
||||
etags */*.[ch]
|
129
source4/lib/ldb/common/ldb.c
Normal file
129
source4/lib/ldb/common/ldb.c
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
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 core API
|
||||
*
|
||||
* Description: core API routines interfacing to ldb backends
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/*
|
||||
connect to a database. The URL can either be one of the following forms
|
||||
ldb://path
|
||||
ldapi://path
|
||||
|
||||
flags is made up of LDB_FLG_*
|
||||
|
||||
the options are passed uninterpreted to the backend, and are
|
||||
backend specific
|
||||
*/
|
||||
struct ldb_context *ldb_connect(const char *url, unsigned int flags,
|
||||
const char *options[])
|
||||
{
|
||||
|
||||
if (strncmp(url, "tdb:", 4) == 0) {
|
||||
return ltdb_connect(url, flags, options);
|
||||
}
|
||||
|
||||
if (strncmp(url, "ldap", 4) == 0) {
|
||||
return lldb_connect(url, flags, options);
|
||||
}
|
||||
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
close the connection to the database
|
||||
*/
|
||||
int ldb_close(struct ldb_context *ldb)
|
||||
{
|
||||
return ldb->ops->close(ldb);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
search the database given a LDAP-like search expression
|
||||
|
||||
return the number of records found, or -1 on error
|
||||
*/
|
||||
int ldb_search(struct ldb_context *ldb,
|
||||
const char *base,
|
||||
enum ldb_scope scope,
|
||||
const char *expression,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
return ldb->ops->search(ldb, base, scope, expression, attrs, res);
|
||||
}
|
||||
|
||||
/*
|
||||
free a set of messages returned by ldb_search
|
||||
*/
|
||||
int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
|
||||
{
|
||||
return ldb->ops->search_free(ldb, msgs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a record to the database. Will fail if a record with the given class and key
|
||||
already exists
|
||||
*/
|
||||
int ldb_add(struct ldb_context *ldb,
|
||||
const struct ldb_message *message)
|
||||
{
|
||||
return ldb->ops->add(ldb, message);
|
||||
}
|
||||
|
||||
/*
|
||||
modify the specified attributes of a record
|
||||
*/
|
||||
int ldb_modify(struct ldb_context *ldb,
|
||||
const struct ldb_message *message)
|
||||
{
|
||||
return ldb->ops->modify(ldb, message);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
delete a record from the database
|
||||
*/
|
||||
int ldb_delete(struct ldb_context *ldb, const char *dn)
|
||||
{
|
||||
return ldb->ops->delete(ldb, dn);
|
||||
}
|
||||
|
||||
/*
|
||||
return extended error information
|
||||
*/
|
||||
const char *ldb_errstring(struct ldb_context *ldb)
|
||||
{
|
||||
return ldb->ops->errstring(ldb);
|
||||
}
|
476
source4/lib/ldb/common/ldb_ldif.c
Normal file
476
source4/lib/ldb/common/ldb_ldif.c
Normal file
@ -0,0 +1,476 @@
|
||||
/*
|
||||
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: ldif routines
|
||||
*
|
||||
* Description: ldif pack/unpack routines
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/*
|
||||
this base64 decoder was taken from jitterbug (written by tridge).
|
||||
we might need to replace it with a new version
|
||||
*/
|
||||
static int base64_decode(char *s)
|
||||
{
|
||||
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i, n;
|
||||
unsigned char *d = (unsigned char *)s;
|
||||
char *p;
|
||||
|
||||
n=i=0;
|
||||
|
||||
while (*s && (p=strchr(b64,*s))) {
|
||||
idx = (int)(p - b64);
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
d[byte_offset] &= ~((1<<(8-bit_offset))-1);
|
||||
if (bit_offset < 3) {
|
||||
d[byte_offset] |= (idx << (2-bit_offset));
|
||||
n = byte_offset+1;
|
||||
} else {
|
||||
d[byte_offset] |= (idx >> (bit_offset-2));
|
||||
d[byte_offset+1] = 0;
|
||||
d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
|
||||
n = byte_offset+2;
|
||||
}
|
||||
s++; i++;
|
||||
}
|
||||
|
||||
if (*s && !p) {
|
||||
/* the only termination allowed */
|
||||
if (*s != '=') {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* null terminate */
|
||||
d[n] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
encode as base64
|
||||
caller frees
|
||||
*/
|
||||
char *ldb_base64_encode(const char *buf, int len)
|
||||
{
|
||||
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
unsigned char *d = (unsigned char *)buf;
|
||||
int bytes = (len*8 + 5)/6;
|
||||
char *out;
|
||||
|
||||
out = malloc(bytes+2);
|
||||
if (!out) return NULL;
|
||||
|
||||
for (i=0;i<bytes;i++) {
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
if (bit_offset < 3) {
|
||||
idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
|
||||
} else {
|
||||
idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
|
||||
if (byte_offset+1 < len) {
|
||||
idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
|
||||
}
|
||||
}
|
||||
out[i] = b64[idx];
|
||||
}
|
||||
|
||||
out[i++] = '=';
|
||||
out[i] = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
see if a buffer should be base64 encoded
|
||||
*/
|
||||
int ldb_should_b64_encode(const struct ldb_val *val)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p = val->data;
|
||||
|
||||
if (val->length == 0 || p[0] == ' ' || p[0] == ':') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i=0; i<val->length; i++) {
|
||||
if (!isprint(p[i]) || p[i] == '\n') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this macro is used to handle the return checking on fprintf_fn() */
|
||||
#define CHECK_RET do { if (ret < 0) return ret; total += ret; } while (0)
|
||||
|
||||
/*
|
||||
write a line folded string onto a file
|
||||
*/
|
||||
static int fold_string(int (*fprintf_fn)(void *, const char *, ...), void *private,
|
||||
const char *buf, size_t length, int start_pos)
|
||||
{
|
||||
int i;
|
||||
int total=0, ret;
|
||||
|
||||
for (i=0;i<length;i++) {
|
||||
ret = fprintf_fn(private, "%c", buf[i]);
|
||||
CHECK_RET;
|
||||
if (i != (length-1) && (i + start_pos) % 77 == 0) {
|
||||
ret = fprintf_fn(private, "\n ");
|
||||
CHECK_RET;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
encode as base64 to a file
|
||||
*/
|
||||
static int base64_encode_f(int (*fprintf_fn)(void *, const char *, ...), void *private,
|
||||
const char *buf, int len, int start_pos)
|
||||
{
|
||||
char *b = ldb_base64_encode(buf, len);
|
||||
int ret;
|
||||
|
||||
if (!b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = fold_string(fprintf_fn, private, b, strlen(b), start_pos);
|
||||
|
||||
free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
write to ldif, using a caller supplied write method
|
||||
*/
|
||||
int ldif_write(int (*fprintf_fn)(void *, const char *, ...),
|
||||
void *private,
|
||||
const struct ldb_message *msg)
|
||||
{
|
||||
int i;
|
||||
int total=0, ret;
|
||||
|
||||
ret = fprintf_fn(private, "dn: %s\n", msg->dn);
|
||||
CHECK_RET;
|
||||
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (ldb_should_b64_encode(&msg->elements[i].value)) {
|
||||
ret = fprintf_fn(private, "%s:: ", msg->elements[i].name);
|
||||
CHECK_RET;
|
||||
ret = base64_encode_f(fprintf_fn, private,
|
||||
msg->elements[i].value.data,
|
||||
msg->elements[i].value.length,
|
||||
strlen(msg->elements[i].name)+3);
|
||||
CHECK_RET;
|
||||
ret = fprintf_fn(private, "\n");
|
||||
CHECK_RET;
|
||||
} else {
|
||||
ret = fprintf_fn(private, "%s: ", msg->elements[i].name);
|
||||
CHECK_RET;
|
||||
ret = fold_string(fprintf_fn, private,
|
||||
msg->elements[i].value.data,
|
||||
msg->elements[i].value.length,
|
||||
strlen(msg->elements[i].name)+2);
|
||||
CHECK_RET;
|
||||
ret = fprintf_fn(private, "\n");
|
||||
CHECK_RET;
|
||||
}
|
||||
}
|
||||
ret = fprintf_fn(private,"\n");
|
||||
CHECK_RET;
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
#undef CHECK_RET
|
||||
|
||||
|
||||
/*
|
||||
pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
|
||||
this routine removes any RFC2849 continuations and comments
|
||||
|
||||
caller frees
|
||||
*/
|
||||
static char *next_chunk(int (*fgetc_fn)(void *), void *private)
|
||||
{
|
||||
size_t alloc_size=0, chunk_size = 0;
|
||||
char *chunk = NULL;
|
||||
int c;
|
||||
int in_comment = 0;
|
||||
|
||||
while ((c = fgetc_fn(private)) != EOF) {
|
||||
if (chunk_size == alloc_size) {
|
||||
char *c2;
|
||||
alloc_size += 1024;
|
||||
c2 = realloc_p(chunk, char, alloc_size);
|
||||
if (!c2) {
|
||||
free(chunk);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
chunk = c2;
|
||||
}
|
||||
|
||||
if (in_comment) {
|
||||
if (c == '\n') {
|
||||
in_comment = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle continuation lines - see RFC2849 */
|
||||
if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
|
||||
chunk_size--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* chunks are terminated by a double line-feed */
|
||||
if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
|
||||
chunk[chunk_size-1] = 0;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
|
||||
in_comment = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore leading blank lines */
|
||||
if (chunk_size == 0 && c == '\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
chunk[chunk_size++] = c;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
/* simple ldif attribute parser */
|
||||
static int next_attr(char **s, char **attr, struct ldb_val *value)
|
||||
{
|
||||
char *p;
|
||||
int base64_encoded = 0;
|
||||
|
||||
p = strchr(*s, ':');
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p++ = 0;
|
||||
|
||||
if (*p == ':') {
|
||||
base64_encoded = 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
*attr = *s;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
value->data = p;
|
||||
|
||||
p = strchr(p, '\n');
|
||||
|
||||
if (!p) {
|
||||
value->length = strlen((char *)value->data);
|
||||
*s = ((char *)value->data) + value->length;
|
||||
} else {
|
||||
value->length = p - (char *)value->data;
|
||||
*s = p+1;
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
if (base64_encoded) {
|
||||
int len = base64_decode(value->data);
|
||||
if (len == -1) {
|
||||
/* it wasn't valid base64 data */
|
||||
return -1;
|
||||
}
|
||||
value->length = len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
free a message from a ldif_read
|
||||
*/
|
||||
void ldif_read_free(struct ldb_message *msg)
|
||||
{
|
||||
if (msg->elements) free(msg->elements);
|
||||
if (msg->private) free(msg->private);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
read from a LDIF source, creating a ldb_message
|
||||
*/
|
||||
struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private)
|
||||
{
|
||||
struct ldb_message *msg;
|
||||
char *attr=NULL, *chunk=NULL, *s;
|
||||
struct ldb_val value;
|
||||
|
||||
value.data = NULL;
|
||||
|
||||
msg = malloc_p(struct ldb_message);
|
||||
if (!msg) return NULL;
|
||||
|
||||
msg->dn = NULL;
|
||||
msg->elements = NULL;
|
||||
msg->num_elements = 0;
|
||||
msg->private = NULL;
|
||||
|
||||
chunk = next_chunk(fgetc_fn, private);
|
||||
if (!chunk) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msg->private = chunk;
|
||||
s = chunk;
|
||||
|
||||
if (next_attr(&s, &attr, &value) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* first line must be a dn */
|
||||
if (strcmp(attr, "dn") != 0) {
|
||||
fprintf(stderr, "First line must be a dn not '%s'\n", attr);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msg->dn = value.data;
|
||||
|
||||
while (next_attr(&s, &attr, &value) == 0) {
|
||||
msg->elements = realloc_p(msg->elements,
|
||||
struct ldb_message_element,
|
||||
msg->num_elements+1);
|
||||
if (!msg->elements) {
|
||||
goto failed;
|
||||
}
|
||||
msg->elements[msg->num_elements].flags = 0;
|
||||
msg->elements[msg->num_elements].name = attr;
|
||||
msg->elements[msg->num_elements].value = value;
|
||||
msg->num_elements++;
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
failed:
|
||||
if (msg) ldif_read_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
a wrapper around ldif_read() for reading from FILE*
|
||||
*/
|
||||
struct ldif_read_file_state {
|
||||
FILE *f;
|
||||
};
|
||||
|
||||
static int fgetc_file(void *private)
|
||||
{
|
||||
struct ldif_read_file_state *state = private;
|
||||
return fgetc(state->f);
|
||||
}
|
||||
|
||||
struct ldb_message *ldif_read_file(FILE *f)
|
||||
{
|
||||
struct ldif_read_file_state state;
|
||||
state.f = f;
|
||||
return ldif_read(fgetc_file, &state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
a wrapper around ldif_read() for reading from const char*
|
||||
*/
|
||||
struct ldif_read_string_state {
|
||||
const char *s;
|
||||
};
|
||||
|
||||
static int fgetc_string(void *private)
|
||||
{
|
||||
struct ldif_read_string_state *state = private;
|
||||
if (state->s[0] != 0) {
|
||||
return *state->s++;
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
struct ldb_message *ldif_read_string(const char *s)
|
||||
{
|
||||
struct ldif_read_string_state state;
|
||||
state.s = s;
|
||||
return ldif_read(fgetc_string, &state);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
wrapper around ldif_write() for a file
|
||||
*/
|
||||
struct ldif_write_file_state {
|
||||
FILE *f;
|
||||
};
|
||||
|
||||
static int fprintf_file(void *private, const char *fmt, ...)
|
||||
{
|
||||
struct ldif_write_file_state *state = private;
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vfprintf(state->f, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ldif_write_file(FILE *f, const struct ldb_message *msg)
|
||||
{
|
||||
struct ldif_write_file_state state;
|
||||
state.f = f;
|
||||
return ldif_write(fprintf_file, &state, msg);
|
||||
}
|
460
source4/lib/ldb/common/ldb_parse.c
Normal file
460
source4/lib/ldb/common/ldb_parse.c
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
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 expression parsing
|
||||
*
|
||||
* Description: parse LDAP-like search expressions
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- add RFC2254 binary string handling
|
||||
- possibly add ~=, <= and >= handling
|
||||
- expand the test suite
|
||||
- add better parse error handling
|
||||
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/*
|
||||
a filter is defined by:
|
||||
<filter> ::= '(' <filtercomp> ')'
|
||||
<filtercomp> ::= <and> | <or> | <not> | <simple>
|
||||
<and> ::= '&' <filterlist>
|
||||
<or> ::= '|' <filterlist>
|
||||
<not> ::= '!' <filter>
|
||||
<filterlist> ::= <filter> | <filter> <filterlist>
|
||||
<simple> ::= <attributetype> <filtertype> <attributevalue>
|
||||
<filtertype> ::= '=' | '~=' | '<=' | '>='
|
||||
*/
|
||||
|
||||
/*
|
||||
return next token element. Caller frees
|
||||
*/
|
||||
static char *ldb_parse_lex(const char **s)
|
||||
{
|
||||
const char *p = *s;
|
||||
char *ret;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
*s = p;
|
||||
|
||||
if (*p == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strchr("()&|=!", *p)) {
|
||||
(*s) = p+1;
|
||||
ret = strndup(p, 1);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (*p && (isalnum(*p) || !strchr("()&|=!", *p))) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p == *s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = strndup(*s, p - *s);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
*s = p;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
find a matching close brace in a string
|
||||
*/
|
||||
static const char *match_brace(const char *s)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while (*s && (count != 0 || *s != ')')) {
|
||||
if (*s == '(') {
|
||||
count++;
|
||||
}
|
||||
if (*s == ')') {
|
||||
count--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (! *s) {
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static struct ldb_parse_tree *ldb_parse_filter(const char **s);
|
||||
|
||||
/*
|
||||
<simple> ::= <attributetype> <filtertype> <attributevalue>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_simple(const char *s)
|
||||
{
|
||||
char *eq, *val, *l;
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
l = ldb_parse_lex(&s);
|
||||
if (!l) {
|
||||
fprintf(stderr, "Unexpected end of expression\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strchr("()&|=", *l)) {
|
||||
fprintf(stderr, "Unexpected token '%s'\n", l);
|
||||
free(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eq = ldb_parse_lex(&s);
|
||||
if (!eq || strcmp(eq, "=") != 0) {
|
||||
fprintf(stderr, "Expected '='\n");
|
||||
free(l);
|
||||
if (eq) free(eq);
|
||||
return NULL;
|
||||
}
|
||||
free(eq);
|
||||
|
||||
val = ldb_parse_lex(&s);
|
||||
if (val && strchr("()&|=", *val)) {
|
||||
fprintf(stderr, "Unexpected token '%s'\n", val);
|
||||
free(l);
|
||||
if (val) free(val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = LDB_OP_SIMPLE;
|
||||
ret->u.simple.attr = l;
|
||||
ret->u.simple.value.data = val;
|
||||
ret->u.simple.value.length = val?strlen(val):0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse a filterlist
|
||||
<and> ::= '&' <filterlist>
|
||||
<or> ::= '|' <filterlist>
|
||||
<filterlist> ::= <filter> | <filter> <filterlist>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filterlist(enum ldb_parse_op op, const char *s)
|
||||
{
|
||||
struct ldb_parse_tree *ret, *next;
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = op;
|
||||
ret->u.list.num_elements = 1;
|
||||
ret->u.list.elements = malloc_p(struct ldb_parse_tree *);
|
||||
if (!ret->u.list.elements) {
|
||||
errno = ENOMEM;
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->u.list.elements[0] = ldb_parse_filter(&s);
|
||||
if (!ret->u.list.elements[0]) {
|
||||
free(ret->u.list.elements);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
while (*s && (next = ldb_parse_filter(&s))) {
|
||||
struct ldb_parse_tree **e;
|
||||
e = realloc_p(ret->u.list.elements,
|
||||
struct ldb_parse_tree *,
|
||||
ret->u.list.num_elements+1);
|
||||
if (!e) {
|
||||
errno = ENOMEM;
|
||||
ldb_parse_tree_free(next);
|
||||
ldb_parse_tree_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->u.list.elements = e;
|
||||
ret->u.list.elements[ret->u.list.num_elements] = next;
|
||||
ret->u.list.num_elements++;
|
||||
while (isspace(*s)) s++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
<not> ::= '!' <filter>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_not(const char *s)
|
||||
{
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = LDB_OP_NOT;
|
||||
ret->u.not.child = ldb_parse_filter(&s);
|
||||
if (!ret->u.not.child) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
parse a filtercomp
|
||||
<filtercomp> ::= <and> | <or> | <not> | <simple>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filtercomp(const char *s)
|
||||
{
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
switch (*s) {
|
||||
case '&':
|
||||
return ldb_parse_filterlist(LDB_OP_AND, s+1);
|
||||
|
||||
case '|':
|
||||
return ldb_parse_filterlist(LDB_OP_OR, s+1);
|
||||
|
||||
case '!':
|
||||
return ldb_parse_not(s+1);
|
||||
|
||||
case '(':
|
||||
case ')':
|
||||
fprintf(stderr, "Unexpected token '%c'\n", *s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ldb_parse_simple(s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
<filter> ::= '(' <filtercomp> ')'
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filter(const char **s)
|
||||
{
|
||||
char *l, *s2;
|
||||
const char *p, *p2;
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
l = ldb_parse_lex(s);
|
||||
if (!l) {
|
||||
fprintf(stderr, "Unexpected end of expression\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(l, "(") != 0) {
|
||||
free(l);
|
||||
fprintf(stderr, "Expected '('\n");
|
||||
return NULL;
|
||||
}
|
||||
free(l);
|
||||
|
||||
p = match_brace(*s);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Parse error - mismatched braces\n");
|
||||
return NULL;
|
||||
}
|
||||
p2 = p + 1;
|
||||
|
||||
s2 = strndup(*s, p - *s);
|
||||
if (!s2) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = ldb_parse_filtercomp(s2);
|
||||
free(s2);
|
||||
|
||||
*s = p2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
main parser entry point. Takes a search string and returns a parse tree
|
||||
|
||||
expression ::= <simple> | <filter>
|
||||
*/
|
||||
struct ldb_parse_tree *ldb_parse_tree(const char *s)
|
||||
{
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
if (*s == '(') {
|
||||
return ldb_parse_filter(&s);
|
||||
}
|
||||
|
||||
return ldb_parse_simple(s);
|
||||
}
|
||||
|
||||
/*
|
||||
free a parse tree returned from ldb_parse_tree()
|
||||
*/
|
||||
void ldb_parse_tree_free(struct ldb_parse_tree *tree)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
free(tree->u.simple.attr);
|
||||
if (tree->u.simple.value.data) free(tree->u.simple.value.data);
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
case LDB_OP_OR:
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
ldb_parse_tree_free(tree->u.list.elements[i]);
|
||||
}
|
||||
if (tree->u.list.elements) free(tree->u.list.elements);
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
ldb_parse_tree_free(tree->u.not.child);
|
||||
break;
|
||||
}
|
||||
|
||||
free(tree);
|
||||
}
|
||||
|
||||
#if TEST_PROGRAM
|
||||
/*
|
||||
return a string representation of a parse tree
|
||||
used for debugging
|
||||
*/
|
||||
static char *tree_string(struct ldb_parse_tree *tree)
|
||||
{
|
||||
char *s = NULL;
|
||||
char *s1, *s2;
|
||||
int i;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
asprintf(&s, "( %s = \"%s\" )", tree->u.simple.attr,
|
||||
(char *)tree->u.simple.value.data);
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
case LDB_OP_OR:
|
||||
asprintf(&s, "( %c", tree->operation==LDB_OP_AND?'&':'|');
|
||||
if (!s) return NULL;
|
||||
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
s1 = tree_string(tree->u.list.elements[i]);
|
||||
if (!s1) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
asprintf(&s2, "%s %s", s, s1);
|
||||
free(s);
|
||||
free(s1);
|
||||
s = s2;
|
||||
}
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
asprintf(&s2, "%s )", s);
|
||||
free(s);
|
||||
s = s2;
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
s1 = tree_string(tree->u.not.child);
|
||||
asprintf(&s, "( ! %s )", s1);
|
||||
free(s1);
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
print a tree
|
||||
*/
|
||||
static void print_tree(struct ldb_parse_tree *tree)
|
||||
{
|
||||
char *s = tree_string(tree);
|
||||
printf("%s\n", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char line[1000];
|
||||
int ret = 0;
|
||||
|
||||
while (fgets(line, sizeof(line)-1, stdin)) {
|
||||
struct ldb_parse_tree *tree;
|
||||
|
||||
if (line[strlen(line)-1] == '\n') {
|
||||
line[strlen(line)-1] = 0;
|
||||
}
|
||||
tree = ldb_parse_tree(line);
|
||||
if (!tree) {
|
||||
fprintf(stderr, "Failed to parse\n");
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
print_tree(tree);
|
||||
ldb_parse_tree_free(tree);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* TEST_PROGRAM */
|
||||
|
102
source4/lib/ldb/common/util.c
Normal file
102
source4/lib/ldb/common/util.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
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 utility functions
|
||||
*
|
||||
* Description: miscellanous utility functions for ldb
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
#define MAX_MALLOC_SIZE 0x7fffffff
|
||||
|
||||
/*
|
||||
realloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
void *realloc_array(void *ptr, size_t el_size, unsigned count)
|
||||
{
|
||||
if (count == 0 ||
|
||||
count >= MAX_MALLOC_SIZE/el_size) {
|
||||
return NULL;
|
||||
}
|
||||
if (!ptr) {
|
||||
return malloc(el_size * count);
|
||||
}
|
||||
return realloc(ptr, el_size * count);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
find an element in a list, using the given comparison function and
|
||||
assuming that the list is already sorted using comp_fn
|
||||
|
||||
return -1 if not found, or the index of the first occurance of needle if found
|
||||
*/
|
||||
int list_find(const void *needle,
|
||||
const void *base, size_t nmemb, size_t size, comparison_fn_t comp_fn)
|
||||
{
|
||||
const char *base_p = base;
|
||||
size_t min_i, max_i, test_i;
|
||||
|
||||
if (nmemb == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
min_i = 0;
|
||||
max_i = nmemb-1;
|
||||
|
||||
while (min_i < max_i) {
|
||||
size_t test_t;
|
||||
int r;
|
||||
|
||||
test_i = (min_i + max_i) / 2;
|
||||
r = comp_fn(needle, *(void **)(base_p + (size * test_i)));
|
||||
if (r == 0) {
|
||||
/* scan back for first element */
|
||||
while (test_t > 0 &&
|
||||
comp_fn(needle, *(void **)(base_p + (size * (test_i-1)))) == 0) {
|
||||
test_i--;
|
||||
}
|
||||
return test_i;
|
||||
}
|
||||
if (r == -1) {
|
||||
max_i = test_i - 1;
|
||||
}
|
||||
if (r == 1) {
|
||||
min_i = test_i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (comp_fn(needle, *(void **)(base_p + (size * min_i))) == 0) {
|
||||
return min_i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
41
source4/lib/ldb/docs/design.txt
Normal file
41
source4/lib/ldb/docs/design.txt
Normal file
@ -0,0 +1,41 @@
|
||||
The list of indexed fields
|
||||
--------------------------
|
||||
|
||||
dn=@INDEXLIST
|
||||
list of field names that are indexed
|
||||
|
||||
contains fields of type @IDXATTR which contain attriute names
|
||||
of indexed fields
|
||||
|
||||
|
||||
Data records
|
||||
------------
|
||||
|
||||
for each user record in the db there is:
|
||||
main record
|
||||
key: DN=dn
|
||||
data: packed attribute/value list
|
||||
|
||||
a index record for each indexed field in the record
|
||||
|
||||
|
||||
Index Records
|
||||
-------------
|
||||
|
||||
The index records contain the list of dn's that contain records
|
||||
matching the index key
|
||||
|
||||
All index records are of the form:
|
||||
dn=@INDEX:field:value
|
||||
|
||||
and contain fields of type @IDX which are the dns of the records
|
||||
that have that value for some attribute
|
||||
|
||||
|
||||
Search Expressions
|
||||
------------------
|
||||
|
||||
Very similar to LDAP search expressions, but does not allow ~=, <= or >=
|
||||
|
||||
attrib0 := (field=value)
|
||||
attrib := attrib0 | (attrib&&attrib) | (attrib||attrib) | !attrib
|
22
source4/lib/ldb/include/includes.h
Normal file
22
source4/lib/ldb/include/includes.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
a temporary includes file until I work on the ldb build system
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include "ldb.h"
|
||||
#include "ldb_parse.h"
|
||||
|
||||
#define malloc_p(type) (type *)malloc(sizeof(type))
|
||||
#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
|
||||
#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
|
||||
|
||||
#include "tdb/tdb.h"
|
||||
#include "proto.h"
|
204
source4/lib/ldb/include/ldb.h
Normal file
204
source4/lib/ldb/include/ldb.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
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 header
|
||||
*
|
||||
* Description: defines for base ldb API
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
/*
|
||||
major restrictions as compared to normal LDAP:
|
||||
|
||||
- no async calls.
|
||||
- each record must have a unique key field
|
||||
- the key must be representable as a NULL terminated C string and may not
|
||||
contain a comma or braces
|
||||
|
||||
major restrictions as compared to tdb:
|
||||
|
||||
- no explicit locking calls
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
an individual lump of data in a result comes in this format. The
|
||||
pointer will usually be to a UTF-8 string if the application is
|
||||
sensible, but it can be to anything you like, including binary data
|
||||
blobs of arbitrary size.
|
||||
*/
|
||||
struct ldb_val {
|
||||
unsigned int length;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* these flags are used in ldd_message_element.flags fields. The
|
||||
LDA_FLAGS_MOD_* flags are used in ldap_modify() calls to specify
|
||||
whether attributes are being added, deleted or modified */
|
||||
#define LDB_FLAG_MOD_MASK 0x3
|
||||
#define LDB_FLAG_MOD_ADD 1
|
||||
#define LDB_FLAG_MOD_REPLACE 2
|
||||
#define LDB_FLAG_MOD_DELETE 3
|
||||
|
||||
|
||||
/*
|
||||
results are given back as arrays of ldb_message_element
|
||||
*/
|
||||
struct ldb_message_element {
|
||||
unsigned int flags;
|
||||
char *name;
|
||||
struct ldb_val value;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
a ldb_message represents all or part of a record. It can contain an arbitrary
|
||||
number of elements.
|
||||
*/
|
||||
struct ldb_message {
|
||||
char *dn;
|
||||
unsigned int num_elements;
|
||||
struct ldb_message_element *elements;
|
||||
void *private; /* private to the backend */
|
||||
};
|
||||
|
||||
|
||||
enum ldb_scope {LDB_SCOPE_DEFAULT=-1,
|
||||
LDB_SCOPE_BASE=0,
|
||||
LDB_SCOPE_ONELEVEL=1,
|
||||
LDB_SCOPE_SUBTREE=2};
|
||||
|
||||
struct ldb_context;
|
||||
|
||||
/*
|
||||
the fuction type for the callback used in traversing the database
|
||||
*/
|
||||
typedef int (*ldb_traverse_fn)(struct ldb_context *, const struct ldb_message *);
|
||||
|
||||
|
||||
/*
|
||||
these function pointers define the operations that a ldb backend must perform
|
||||
they correspond exactly to the ldb_*() interface
|
||||
*/
|
||||
struct ldb_backend_ops {
|
||||
int (*close)(struct ldb_context *);
|
||||
int (*search)(struct ldb_context *, const char *, enum ldb_scope,
|
||||
const char *, const char *[], struct ldb_message ***);
|
||||
int (*search_free)(struct ldb_context *, struct ldb_message **);
|
||||
int (*add)(struct ldb_context *, const struct ldb_message *);
|
||||
int (*modify)(struct ldb_context *, const struct ldb_message *);
|
||||
int (*delete)(struct ldb_context *, const char *);
|
||||
const char * (*errstring)(struct ldb_context *);
|
||||
};
|
||||
|
||||
/*
|
||||
every ldb connection is started by establishing a ldb_context
|
||||
*/
|
||||
struct ldb_context {
|
||||
/* a private pointer for the backend to use */
|
||||
void *private;
|
||||
|
||||
/* the operations provided by the backend */
|
||||
const struct ldb_backend_ops *ops;
|
||||
};
|
||||
|
||||
|
||||
#define LDB_FLG_RDONLY 1
|
||||
|
||||
/*
|
||||
connect to a database. The URL can either be one of the following forms
|
||||
ldb://path
|
||||
ldapi://path
|
||||
|
||||
flags is made up of LDB_FLG_*
|
||||
|
||||
the options are passed uninterpreted to the backend, and are
|
||||
backend specific
|
||||
*/
|
||||
struct ldb_context *ldb_connect(const char *url, unsigned int flags,
|
||||
const char *options[]);
|
||||
|
||||
/*
|
||||
close the connection to the database
|
||||
*/
|
||||
int ldb_close(struct ldb_context *ldb);
|
||||
|
||||
|
||||
/*
|
||||
search the database given a LDAP-like search expression
|
||||
|
||||
return the number of records found, or -1 on error
|
||||
*/
|
||||
int ldb_search(struct ldb_context *ldb,
|
||||
const char *base,
|
||||
enum ldb_scope scope,
|
||||
const char *expression,
|
||||
const char *attrs[], struct ldb_message ***res);
|
||||
|
||||
/*
|
||||
free a set of messages returned by ldb_search
|
||||
*/
|
||||
int ldb_search_free(struct ldb_context *ldb, struct ldb_message **msgs);
|
||||
|
||||
|
||||
/*
|
||||
add a record to the database. Will fail if a record with the given class and key
|
||||
already exists
|
||||
*/
|
||||
int ldb_add(struct ldb_context *ldb,
|
||||
const struct ldb_message *message);
|
||||
|
||||
/*
|
||||
modify the specified attributes of a record
|
||||
*/
|
||||
int ldb_modify(struct ldb_context *ldb,
|
||||
const struct ldb_message *message);
|
||||
|
||||
/*
|
||||
delete a record from the database
|
||||
*/
|
||||
int ldb_delete(struct ldb_context *ldb, const char *dn);
|
||||
|
||||
|
||||
/*
|
||||
return extended error information from the last call
|
||||
*/
|
||||
const char *ldb_errstring(struct ldb_context *ldb);
|
||||
|
||||
/*
|
||||
ldif manipulation functions
|
||||
*/
|
||||
int ldif_write(int (*fprintf_fn)(void *, const char *, ...),
|
||||
void *private,
|
||||
const struct ldb_message *msg);
|
||||
void ldif_read_free(struct ldb_message *msg);
|
||||
struct ldb_message *ldif_read(int (*fgetc_fn)(void *), void *private);
|
||||
struct ldb_message *ldif_read_file(FILE *f);
|
||||
struct ldb_message *ldif_read_string(const char *s);
|
||||
int ldif_write_file(FILE *f, const struct ldb_message *msg);
|
53
source4/lib/ldb/include/ldb_parse.h
Normal file
53
source4/lib/ldb/include/ldb_parse.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
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 expression parse header
|
||||
*
|
||||
* Description: structure for expression parsing
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
|
||||
enum ldb_parse_op {LDB_OP_SIMPLE, LDB_OP_AND, LDB_OP_OR, LDB_OP_NOT};
|
||||
|
||||
struct ldb_parse_tree {
|
||||
enum ldb_parse_op operation;
|
||||
union {
|
||||
struct {
|
||||
char *attr;
|
||||
struct ldb_val value;
|
||||
} simple;
|
||||
struct {
|
||||
unsigned int num_elements;
|
||||
struct ldb_parse_tree **elements;
|
||||
} list;
|
||||
struct {
|
||||
struct ldb_parse_tree *child;
|
||||
} not;
|
||||
} u;
|
||||
};
|
524
source4/lib/ldb/ldb_ldap/ldb_ldap.c
Normal file
524
source4/lib/ldb/ldb_ldap/ldb_ldap.c
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
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 ldap backend
|
||||
*
|
||||
* Description: core files for LDAP backend
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb_ldap/ldb_ldap.h"
|
||||
|
||||
#if 0
|
||||
/*
|
||||
we don't need this right now, but will once we add more backend
|
||||
options
|
||||
*/
|
||||
|
||||
/*
|
||||
find an option in an option list (a null terminated list of strings)
|
||||
|
||||
this assumes the list is short. If it ever gets long then we really
|
||||
should do this in some smarter way
|
||||
*/
|
||||
static const char *lldb_option_find(const struct lldb_private *lldb, const char *name)
|
||||
{
|
||||
int i;
|
||||
size_t len = strlen(name);
|
||||
|
||||
if (!lldb->options) return NULL;
|
||||
|
||||
for (i=0;lldb->options[i];i++) {
|
||||
if (strncmp(lldb->options[i], name, len) == 0 &&
|
||||
lldb->options[i][len] == '=') {
|
||||
return &lldb->options[i][len+1];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
close/free the connection
|
||||
*/
|
||||
static int lldb_close(struct ldb_context *ldb)
|
||||
{
|
||||
int i, ret = 0;
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
|
||||
if (ldap_unbind(lldb->ldap) != LDAP_SUCCESS) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (lldb->options) {
|
||||
for (i=0;lldb->options[i];i++) {
|
||||
free(lldb->options[i]);
|
||||
}
|
||||
free(lldb->options);
|
||||
}
|
||||
free(lldb);
|
||||
free(ldb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
delete a record
|
||||
*/
|
||||
static int lldb_delete(struct ldb_context *ldb, const char *dn)
|
||||
{
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
int ret = 0;
|
||||
|
||||
lldb->last_rc = ldap_delete_s(lldb->ldap, dn);
|
||||
if (lldb->last_rc != LDAP_SUCCESS) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
free a search message
|
||||
*/
|
||||
static int lldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
|
||||
{
|
||||
int i;
|
||||
free(msg->dn);
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
free(msg->elements[i].name);
|
||||
if (msg->elements[i].value.data) {
|
||||
free(msg->elements[i].value.data);
|
||||
}
|
||||
}
|
||||
if (msg->elements) free(msg->elements);
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
free a search result
|
||||
*/
|
||||
static int lldb_search_free(struct ldb_context *ldb, struct ldb_message **res)
|
||||
{
|
||||
int i;
|
||||
for (i=0;res[i];i++) {
|
||||
if (lldb_msg_free(ldb, res[i]) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a single set of ldap message values to a ldb_message
|
||||
*/
|
||||
static int lldb_add_msg_attr(struct ldb_message *msg,
|
||||
const char *attr, struct berval **bval)
|
||||
{
|
||||
int count, i;
|
||||
struct ldb_message_element *el;
|
||||
|
||||
count = ldap_count_values_len(bval);
|
||||
|
||||
if (count <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
el = realloc_p(msg->elements, struct ldb_message_element,
|
||||
msg->num_elements + count);
|
||||
if (!el) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg->elements = el;
|
||||
|
||||
for (i=0;i<count;i++) {
|
||||
msg->elements[msg->num_elements].name = strdup(attr);
|
||||
if (!msg->elements[msg->num_elements].name) {
|
||||
return -1;
|
||||
}
|
||||
msg->elements[msg->num_elements].value.data = malloc(bval[i]->bv_len);
|
||||
if (!msg->elements[msg->num_elements].value.data) {
|
||||
free(msg->elements[msg->num_elements].name);
|
||||
return -1;
|
||||
}
|
||||
memcpy(msg->elements[msg->num_elements].value.data,
|
||||
bval[i]->bv_val, bval[i]->bv_len);
|
||||
msg->elements[msg->num_elements].value.length = bval[i]->bv_len;
|
||||
msg->num_elements++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
search for matching records
|
||||
*/
|
||||
static int lldb_search(struct ldb_context *ldb, const char *base,
|
||||
enum ldb_scope scope, const char *expression,
|
||||
const char **attrs, struct ldb_message ***res)
|
||||
{
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
int count, msg_count;
|
||||
LDAPMessage *ldapres, *msg;
|
||||
|
||||
lldb->last_rc = ldap_search_s(lldb->ldap, base, (int)scope,
|
||||
expression, attrs, 0, &ldapres);
|
||||
if (lldb->last_rc != LDAP_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = ldap_count_entries(lldb->ldap, ldapres);
|
||||
if (count == -1 || count == 0) {
|
||||
ldap_msgfree(ldapres);
|
||||
return count;
|
||||
}
|
||||
|
||||
(*res) = malloc_array_p(struct ldb_message *, count+1);
|
||||
if (! *res) {
|
||||
ldap_msgfree(ldapres);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*res)[0] = NULL;
|
||||
|
||||
msg_count = 0;
|
||||
|
||||
/* loop over all messages */
|
||||
for (msg=ldap_first_entry(lldb->ldap, ldapres);
|
||||
msg;
|
||||
msg=ldap_next_entry(lldb->ldap, msg)) {
|
||||
BerElement *berptr = NULL;
|
||||
char *attr, *dn;
|
||||
|
||||
if (msg_count == count) {
|
||||
/* hmm, got too many? */
|
||||
fprintf(stderr,"Too many messages?!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
(*res)[msg_count] = malloc_p(struct ldb_message);
|
||||
if (!(*res)[msg_count]) {
|
||||
goto failed;
|
||||
}
|
||||
(*res)[msg_count+1] = NULL;
|
||||
|
||||
dn = ldap_get_dn(lldb->ldap, msg);
|
||||
if (!dn) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
(*res)[msg_count]->dn = strdup(dn);
|
||||
ldap_memfree(dn);
|
||||
if (!(*res)[msg_count]->dn) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
(*res)[msg_count]->num_elements = 0;
|
||||
(*res)[msg_count]->elements = NULL;
|
||||
(*res)[msg_count]->private = NULL;
|
||||
|
||||
/* loop over all attributes */
|
||||
for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
|
||||
attr;
|
||||
attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
|
||||
struct berval **bval;
|
||||
bval = ldap_get_values_len(lldb->ldap, msg, attr);
|
||||
|
||||
if (bval) {
|
||||
lldb_add_msg_attr((*res)[msg_count], attr, bval);
|
||||
ldap_value_free_len(bval);
|
||||
}
|
||||
|
||||
ldap_memfree(attr);
|
||||
}
|
||||
if (berptr) ber_free(berptr, 0);
|
||||
|
||||
msg_count++;
|
||||
}
|
||||
|
||||
ldap_msgfree(ldapres);
|
||||
|
||||
return msg_count;
|
||||
|
||||
failed:
|
||||
if (*res) lldb_search_free(ldb, *res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
free a set of mods from lldb_msg_to_mods()
|
||||
*/
|
||||
static void lldb_mods_free(LDAPMod **mods)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (!mods) return;
|
||||
|
||||
for (i=0;mods[i];i++) {
|
||||
if (mods[i]->mod_vals.modv_bvals) {
|
||||
for (j=0;mods[i]->mod_vals.modv_bvals[j];j++) {
|
||||
free(mods[i]->mod_vals.modv_bvals[j]);
|
||||
}
|
||||
free(mods[i]->mod_vals.modv_bvals);
|
||||
}
|
||||
free(mods[i]);
|
||||
}
|
||||
free(mods);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
convert a ldb_message structure to a list of LDAPMod structures
|
||||
ready for ldap_add() or ldap_modify()
|
||||
*/
|
||||
static LDAPMod **lldb_msg_to_mods(const struct ldb_message *msg, int use_flags)
|
||||
{
|
||||
LDAPMod **mods;
|
||||
int i, num_vals, num_mods = 0;
|
||||
|
||||
/* allocate maximum number of elements needed */
|
||||
mods = malloc_array_p(LDAPMod *, msg->num_elements+1);
|
||||
if (!mods) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
mods[0] = NULL;
|
||||
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
|
||||
if (i > 0 &&
|
||||
(!use_flags ||
|
||||
(msg->elements[i].flags == msg->elements[i-1].flags)) &&
|
||||
strcmp(msg->elements[i].name, msg->elements[i-1].name) == 0) {
|
||||
struct berval **b;
|
||||
/* when attributes are repeated we need to extend the
|
||||
existing bvals array */
|
||||
b = realloc_p(mods[num_mods-1]->mod_vals.modv_bvals,
|
||||
struct berval *, num_vals+2);
|
||||
if (!b) {
|
||||
goto failed;
|
||||
}
|
||||
mods[num_mods-1]->mod_vals.modv_bvals = b;
|
||||
b[num_vals+1] = NULL;
|
||||
b[num_vals] = malloc_p(struct berval);
|
||||
if (!b[num_vals]) goto failed;
|
||||
b[num_vals]->bv_val = msg->elements[i].value.data;
|
||||
b[num_vals]->bv_len = msg->elements[i].value.length;
|
||||
num_vals++;
|
||||
continue;
|
||||
}
|
||||
|
||||
num_vals = 1;
|
||||
|
||||
mods[num_mods] = malloc_p(LDAPMod);
|
||||
if (!mods[num_mods]) {
|
||||
goto failed;
|
||||
}
|
||||
mods[num_mods+1] = NULL;
|
||||
mods[num_mods]->mod_op = LDAP_MOD_BVALUES;
|
||||
if (use_flags) {
|
||||
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
|
||||
case LDB_FLAG_MOD_ADD:
|
||||
mods[num_mods]->mod_op |= LDAP_MOD_ADD;
|
||||
break;
|
||||
case LDB_FLAG_MOD_DELETE:
|
||||
mods[num_mods]->mod_op |= LDAP_MOD_DELETE;
|
||||
break;
|
||||
case LDB_FLAG_MOD_REPLACE:
|
||||
mods[num_mods]->mod_op |= LDAP_MOD_REPLACE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mods[num_mods]->mod_type = msg->elements[i].name;
|
||||
mods[num_mods]->mod_vals.modv_bvals = malloc_array_p(struct berval *, 2);
|
||||
if (!mods[num_mods]->mod_vals.modv_bvals) {
|
||||
goto failed;
|
||||
}
|
||||
mods[num_mods]->mod_vals.modv_bvals[0] = malloc_p(struct berval);
|
||||
if (!mods[num_mods]->mod_vals.modv_bvals[0]) {
|
||||
goto failed;
|
||||
}
|
||||
mods[num_mods]->mod_vals.modv_bvals[0]->bv_val = msg->elements[i].value.data;
|
||||
mods[num_mods]->mod_vals.modv_bvals[0]->bv_len = msg->elements[i].value.length;
|
||||
mods[num_mods]->mod_vals.modv_bvals[1] = NULL;
|
||||
num_mods++;
|
||||
}
|
||||
|
||||
return mods;
|
||||
|
||||
failed:
|
||||
lldb_mods_free(mods);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a record
|
||||
*/
|
||||
static int lldb_add(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
LDAPMod **mods;
|
||||
int ret = 0;
|
||||
|
||||
mods = lldb_msg_to_mods(msg, 0);
|
||||
|
||||
lldb->last_rc = ldap_add_s(lldb->ldap, msg->dn, mods);
|
||||
if (lldb->last_rc != LDAP_SUCCESS) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
lldb_mods_free(mods);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
modify a record
|
||||
*/
|
||||
static int lldb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
LDAPMod **mods;
|
||||
int ret = 0;
|
||||
|
||||
mods = lldb_msg_to_mods(msg, 1);
|
||||
|
||||
lldb->last_rc = ldap_modify_s(lldb->ldap, msg->dn, mods);
|
||||
if (lldb->last_rc != LDAP_SUCCESS) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
lldb_mods_free(mods);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
return extended error information
|
||||
*/
|
||||
static const char *lldb_errstring(struct ldb_context *ldb)
|
||||
{
|
||||
struct lldb_private *lldb = ldb->private;
|
||||
return ldap_err2string(lldb->last_rc);
|
||||
}
|
||||
|
||||
|
||||
static const struct ldb_backend_ops lldb_ops = {
|
||||
lldb_close,
|
||||
lldb_search,
|
||||
lldb_search_free,
|
||||
lldb_add,
|
||||
lldb_modify,
|
||||
lldb_delete,
|
||||
lldb_errstring
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
connect to the database
|
||||
*/
|
||||
struct ldb_context *lldb_connect(const char *url,
|
||||
unsigned int flags,
|
||||
const char *options[])
|
||||
{
|
||||
struct ldb_context *ldb = NULL;
|
||||
struct lldb_private *lldb = NULL;
|
||||
int i;
|
||||
|
||||
ldb = malloc_p(struct ldb_context);
|
||||
if (!ldb) {
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lldb = malloc_p(struct lldb_private);
|
||||
if (!lldb) {
|
||||
free(ldb);
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lldb->ldap = NULL;
|
||||
lldb->options = NULL;
|
||||
|
||||
lldb->last_rc = ldap_initialize(&lldb->ldap, url);
|
||||
if (lldb->last_rc != LDAP_SUCCESS) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ldb->ops = &lldb_ops;
|
||||
ldb->private = lldb;
|
||||
|
||||
if (options) {
|
||||
/* take a copy of the options array, so we don't have to rely
|
||||
on the caller keeping it around (it might be dynamic) */
|
||||
for (i=0;options[i];i++) ;
|
||||
|
||||
lldb->options = malloc_array_p(char *, i+1);
|
||||
if (!lldb->options) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i=0;options[i];i++) {
|
||||
lldb->options[i+1] = NULL;
|
||||
lldb->options[i] = strdup(options[i]);
|
||||
if (!lldb->options[i]) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ldb;
|
||||
|
||||
failed:
|
||||
if (lldb && lldb->options) {
|
||||
for (i=0;lldb->options[i];i++) {
|
||||
free(lldb->options[i]);
|
||||
}
|
||||
free(lldb->options);
|
||||
}
|
||||
if (lldb && lldb->ldap) {
|
||||
ldap_unbind(lldb->ldap);
|
||||
}
|
||||
if (lldb) free(lldb);
|
||||
if (ldb) free(ldb);
|
||||
return NULL;
|
||||
}
|
8
source4/lib/ldb/ldb_ldap/ldb_ldap.h
Normal file
8
source4/lib/ldb/ldb_ldap/ldb_ldap.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include <ldap.h>
|
||||
|
||||
struct lldb_private {
|
||||
char **options;
|
||||
const char *basedn;
|
||||
LDAP *ldap;
|
||||
int last_rc;
|
||||
};
|
7
source4/lib/ldb/ldb_tdb/.cvsignore
Normal file
7
source4/lib/ldb/ldb_tdb/.cvsignore
Normal file
@ -0,0 +1,7 @@
|
||||
ldbadd
|
||||
ldbsearch
|
||||
ldbdel
|
||||
test.ldb
|
||||
TAGS
|
||||
.*~
|
||||
*.o
|
641
source4/lib/ldb/ldb_tdb/ldb_index.c
Normal file
641
source4/lib/ldb/ldb_tdb/ldb_index.c
Normal file
@ -0,0 +1,641 @@
|
||||
/*
|
||||
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 backend - indexing
|
||||
*
|
||||
* Description: indexing routines for ldb tdb backend
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct dn_list {
|
||||
unsigned int count;
|
||||
char **dn;
|
||||
};
|
||||
|
||||
/*
|
||||
free a struct dn_list
|
||||
*/
|
||||
static void dn_list_free(struct dn_list *list)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<list->count;i++) {
|
||||
free(list->dn[i]);
|
||||
}
|
||||
if (list->dn) free(list->dn);
|
||||
}
|
||||
|
||||
/*
|
||||
return the dn key to be used for an index
|
||||
caller frees
|
||||
*/
|
||||
static char *ldb_dn_key(const char *attr, const struct ldb_val *value)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
if (ldb_should_b64_encode(value)) {
|
||||
char *vstr = ldb_base64_encode(value->data, value->length);
|
||||
if (!vstr) return NULL;
|
||||
asprintf(&ret, "@INDEX:%s::%s", attr, vstr);
|
||||
free(vstr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
asprintf(&ret, "@INDEX:%s:%s", attr, (char *)value->data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
see if a attribute value is in the list of indexed attributes
|
||||
*/
|
||||
static int ldb_msg_find_idx(const struct ldb_message *msg, const char *attr)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (strcmp(msg->elements[i].name, "@IDXATTR") == 0 &&
|
||||
strcmp((char *)msg->elements[i].value.data, attr) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
return a list of dn's that might match a simple indexed search or
|
||||
*/
|
||||
static int ltdb_index_dn_simple(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list)
|
||||
{
|
||||
char *dn = NULL;
|
||||
int ret, i;
|
||||
struct ldb_message msg;
|
||||
|
||||
list->count = 0;
|
||||
list->dn = NULL;
|
||||
|
||||
/*
|
||||
if the value is a wildcard then we can't do a match via indexing
|
||||
*/
|
||||
if (ltdb_has_wildcard(&tree->u.simple.value)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if the attribute isn't in the list of indexed attributes then
|
||||
this node needs a full search */
|
||||
if (ldb_msg_find_idx(index_list, tree->u.simple.attr) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the attribute is indexed. Pull the list of DNs that match the
|
||||
search criterion */
|
||||
dn = ldb_dn_key(tree->u.simple.attr, &tree->u.simple.value);
|
||||
if (!dn) return -1;
|
||||
|
||||
ret = ltdb_search_dn1(ldb, dn, &msg);
|
||||
free(dn);
|
||||
if (ret == 0 || ret == -1) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
list->dn = malloc_array_p(char *, msg.num_elements);
|
||||
if (!list->dn) {
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
}
|
||||
|
||||
for (i=0;i<msg.num_elements;i++) {
|
||||
if (strcmp(msg.elements[i].name, "@IDX") != 0) {
|
||||
continue;
|
||||
}
|
||||
list->dn[list->count] =
|
||||
strdup((char *)msg.elements[i].value.data);
|
||||
if (!list->dn[list->count]) {
|
||||
dn_list_free(list);
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
return -1;
|
||||
}
|
||||
list->count++;
|
||||
}
|
||||
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
|
||||
qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t) strcmp);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
list intersection
|
||||
list = list & list2
|
||||
relies on the lists being sorted
|
||||
*/
|
||||
static int list_intersect(struct dn_list *list, const struct dn_list *list2)
|
||||
{
|
||||
struct dn_list list3;
|
||||
int i;
|
||||
|
||||
if (list->count == 0 || list2->count == 0) {
|
||||
/* 0 & X == 0 */
|
||||
dn_list_free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list3.dn = malloc_array_p(char *, list->count);
|
||||
if (!list3.dn) {
|
||||
dn_list_free(list);
|
||||
return -1;
|
||||
}
|
||||
list3.count = 0;
|
||||
|
||||
for (i=0;i<list->count;i++) {
|
||||
if (list_find(list->dn[i], list2->dn, list2->count,
|
||||
sizeof(char *), (comparison_fn_t)strcmp) != -1) {
|
||||
list3.dn[list3.count] = list->dn[i];
|
||||
list3.count++;
|
||||
} else {
|
||||
free(list->dn[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(list->dn);
|
||||
list->dn = list3.dn;
|
||||
list->count = list3.count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
list union
|
||||
list = list | list2
|
||||
relies on the lists being sorted
|
||||
*/
|
||||
static int list_union(struct dn_list *list, const struct dn_list *list2)
|
||||
{
|
||||
int i;
|
||||
char **d;
|
||||
unsigned int count = list->count;
|
||||
|
||||
if (list->count == 0 && list2->count == 0) {
|
||||
/* 0 | 0 == 0 */
|
||||
dn_list_free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
d = realloc_p(list->dn, char *, list->count + list2->count);
|
||||
if (!d) {
|
||||
dn_list_free(list);
|
||||
return -1;
|
||||
}
|
||||
list->dn = d;
|
||||
|
||||
for (i=0;i<list2->count;i++) {
|
||||
if (list_find(list2->dn[i], list->dn, count,
|
||||
sizeof(char *), (comparison_fn_t)strcmp) == -1) {
|
||||
list->dn[list->count] = strdup(list2->dn[i]);
|
||||
if (!list->dn[list->count]) {
|
||||
dn_list_free(list);
|
||||
return -1;
|
||||
}
|
||||
list->count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (list->count != count) {
|
||||
qsort(list->dn, list->count, sizeof(char *), (comparison_fn_t)strcmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltdb_index_dn(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list);
|
||||
|
||||
|
||||
/*
|
||||
OR two index results
|
||||
*/
|
||||
static int ltdb_index_dn_or(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = -1;
|
||||
list->dn = NULL;
|
||||
list->count = 0;
|
||||
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
struct dn_list list2;
|
||||
int v;
|
||||
v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
|
||||
|
||||
if (v == 0) {
|
||||
/* 0 || X == X */
|
||||
if (ret == -1) {
|
||||
ret = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (v == -1) {
|
||||
/* 1 || X == 1 */
|
||||
dn_list_free(list);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
ret = 1;
|
||||
*list = list2;
|
||||
} else {
|
||||
if (list_union(list, &list2) == -1) {
|
||||
dn_list_free(&list2);
|
||||
return -1;
|
||||
}
|
||||
dn_list_free(&list2);
|
||||
}
|
||||
}
|
||||
|
||||
if (list->count == 0) {
|
||||
dn_list_free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
NOT an index results
|
||||
*/
|
||||
static int ltdb_index_dn_not(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list)
|
||||
{
|
||||
/* the only way to do an indexed not would be if we could
|
||||
negate the not via another not or if we knew the total
|
||||
number of database elements so we could know that the
|
||||
existing expression covered the whole database.
|
||||
|
||||
instead, we just give up, and rely on a full index scan
|
||||
(unless an outer & manages to reduce the list)
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
AND two index results
|
||||
*/
|
||||
static int ltdb_index_dn_and(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = -1;
|
||||
list->dn = NULL;
|
||||
list->count = 0;
|
||||
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
struct dn_list list2;
|
||||
int v;
|
||||
v = ltdb_index_dn(ldb, tree->u.list.elements[i], index_list, &list2);
|
||||
|
||||
if (v == 0) {
|
||||
/* 0 && X == 0 */
|
||||
dn_list_free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
ret = 1;
|
||||
*list = list2;
|
||||
} else {
|
||||
if (list_intersect(list, &list2) == -1) {
|
||||
dn_list_free(&list2);
|
||||
return -1;
|
||||
}
|
||||
dn_list_free(&list2);
|
||||
}
|
||||
|
||||
if (list->count == 0) {
|
||||
if (list->dn) free(list->dn);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
return a list of dn's that might match a indexed search or
|
||||
-1 if an error. return 0 for no matches, or 1 for matches
|
||||
*/
|
||||
static int ltdb_index_dn(struct ldb_context *ldb,
|
||||
struct ldb_parse_tree *tree,
|
||||
const struct ldb_message *index_list,
|
||||
struct dn_list *list)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
ret = ltdb_index_dn_simple(ldb, tree, index_list, list);
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
ret = ltdb_index_dn_and(ldb, tree, index_list, list);
|
||||
break;
|
||||
|
||||
case LDB_OP_OR:
|
||||
ret = ltdb_index_dn_or(ldb, tree, index_list, list);
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
ret = ltdb_index_dn_not(ldb, tree, index_list, list);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
filter a candidate dn_list from an indexed search into a set of results
|
||||
extracting just the given attributes
|
||||
*/
|
||||
static int ldb_index_filter(struct ldb_context *ldb, struct ldb_parse_tree *tree,
|
||||
const char *base,
|
||||
enum ldb_scope scope,
|
||||
const struct dn_list *dn_list,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
int i;
|
||||
unsigned int count = 0;
|
||||
|
||||
for (i=0;i<dn_list->count;i++) {
|
||||
struct ldb_message msg;
|
||||
int ret;
|
||||
ret = ltdb_search_dn1(ldb, dn_list->dn[i], &msg);
|
||||
if (ret == 0) {
|
||||
/* the record has disappeared? yes, this can happen */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
/* an internal error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ldb_message_match(ldb, &msg, tree, base, scope) == 1) {
|
||||
ret = ltdb_add_attr_results(ldb, &msg, attrs, &count, res);
|
||||
}
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
search the database with a LDAP-like expression using indexes
|
||||
returns -1 if an indexed search is not possible, in which
|
||||
case the caller should call ltdb_search_full()
|
||||
*/
|
||||
int ltdb_search_indexed(struct ldb_context *ldb,
|
||||
const char *base,
|
||||
enum ldb_scope scope,
|
||||
struct ldb_parse_tree *tree,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
struct ldb_message index_list;
|
||||
struct dn_list dn_list;
|
||||
int ret;
|
||||
|
||||
/* find the list of indexed fields */
|
||||
ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
|
||||
if (ret != 1) {
|
||||
/* no index list? must do full search */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_index_dn(ldb, tree, &index_list, &dn_list);
|
||||
ltdb_search_dn1_free(ldb, &index_list);
|
||||
|
||||
if (ret == 1) {
|
||||
/* we've got a candidate list - now filter by the full tree
|
||||
and extract the needed attributes */
|
||||
ret = ldb_index_filter(ldb, tree, base, scope, &dn_list,
|
||||
attrs, res);
|
||||
dn_list_free(&dn_list);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
add an index entry for one message element
|
||||
*/
|
||||
static int ltdb_index_add1(struct ldb_context *ldb, const char *dn,
|
||||
struct ldb_message_element *el)
|
||||
{
|
||||
struct ldb_message msg;
|
||||
char *dn_key;
|
||||
int ret;
|
||||
struct ldb_message_element *el2;
|
||||
|
||||
dn_key = ldb_dn_key(el->name, &el->value);
|
||||
if (!dn_key) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_search_dn1(ldb, dn_key, &msg);
|
||||
if (ret == -1) {
|
||||
free(dn_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
msg.dn = dn_key;
|
||||
msg.num_elements = 0;
|
||||
msg.elements = NULL;
|
||||
msg.private = NULL;
|
||||
}
|
||||
|
||||
/* add another entry */
|
||||
el2 = realloc_p(msg.elements, struct ldb_message_element, msg.num_elements+1);
|
||||
if (!el2) {
|
||||
if (ret == 1) {
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
}
|
||||
free(dn_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.elements = el2;
|
||||
msg.elements[msg.num_elements].name = "@IDX";
|
||||
msg.elements[msg.num_elements].value.length = strlen(dn);
|
||||
msg.elements[msg.num_elements].value.data = dn;
|
||||
msg.num_elements++;
|
||||
|
||||
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
|
||||
|
||||
if (msg.num_elements == 1) {
|
||||
free(msg.elements);
|
||||
} else {
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
add the index entries for a new record
|
||||
return -1 on failure
|
||||
*/
|
||||
int ltdb_index_add(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
int ret, i;
|
||||
struct ldb_message index_list;
|
||||
|
||||
/* find the list of indexed fields */
|
||||
ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
|
||||
if (ret != 1) {
|
||||
/* no indexed fields or an error */
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
ret = ldb_msg_find_idx(&index_list, msg->elements[i].name);
|
||||
if (ret == -1) {
|
||||
continue;
|
||||
}
|
||||
ret = ltdb_index_add1(ldb, msg->dn, &msg->elements[i]);
|
||||
if (ret == -1) {
|
||||
ltdb_search_dn1_free(ldb, &index_list);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
delete an index entry for one message element
|
||||
*/
|
||||
static int ltdb_index_del1(struct ldb_context *ldb, const char *dn,
|
||||
struct ldb_message_element *el)
|
||||
{
|
||||
struct ldb_message msg;
|
||||
char *dn_key;
|
||||
int ret, i;
|
||||
|
||||
dn_key = ldb_dn_key(el->name, &el->value);
|
||||
if (!dn_key) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_search_dn1(ldb, dn_key, &msg);
|
||||
if (ret == -1) {
|
||||
free(dn_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* it wasn't indexed. Did we have an earlier error? If we did then
|
||||
its gone now */
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = ldb_msg_find_idx(&msg, dn);
|
||||
if (i == -1) {
|
||||
/* it ain't there. hmmm */
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i != msg.num_elements - 1) {
|
||||
memmove(&msg.elements[i], &msg.elements[i+1], sizeof(msg.elements[i]));
|
||||
}
|
||||
msg.num_elements--;
|
||||
|
||||
if (msg.num_elements == 0) {
|
||||
ret = ltdb_delete_noindex(ldb, dn_key);
|
||||
} else {
|
||||
ret = ltdb_store(ldb, &msg, TDB_REPLACE);
|
||||
}
|
||||
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
delete the index entries for a record
|
||||
return -1 on failure
|
||||
*/
|
||||
int ltdb_index_del(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
int ret, i;
|
||||
struct ldb_message index_list;
|
||||
|
||||
/* find the list of indexed fields */
|
||||
ret = ltdb_search_dn1(ldb, "@INDEXLIST", &index_list);
|
||||
if (ret != 1) {
|
||||
/* no indexed fields or an error */
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
ret = ldb_msg_find_idx(&index_list, msg->elements[i].name);
|
||||
if (ret == -1) {
|
||||
continue;
|
||||
}
|
||||
ret = ltdb_index_del1(ldb, msg->dn, &msg->elements[i]);
|
||||
if (ret == -1) {
|
||||
ltdb_search_dn1_free(ldb, &index_list);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
366
source4/lib/ldb/ldb_tdb/ldb_ldif.c
Normal file
366
source4/lib/ldb/ldb_tdb/ldb_ldif.c
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
ldif utilities for ldb
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/*
|
||||
this base64 decoder was taken from jitterbug (written by tridge).
|
||||
we might need to replace it with a new version
|
||||
*/
|
||||
static int base64_decode(char *s)
|
||||
{
|
||||
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i, n;
|
||||
unsigned char *d = (unsigned char *)s;
|
||||
char *p;
|
||||
|
||||
n=i=0;
|
||||
|
||||
while (*s && (p=strchr(b64,*s))) {
|
||||
idx = (int)(p - b64);
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
d[byte_offset] &= ~((1<<(8-bit_offset))-1);
|
||||
if (bit_offset < 3) {
|
||||
d[byte_offset] |= (idx << (2-bit_offset));
|
||||
n = byte_offset+1;
|
||||
} else {
|
||||
d[byte_offset] |= (idx >> (bit_offset-2));
|
||||
d[byte_offset+1] = 0;
|
||||
d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF;
|
||||
n = byte_offset+2;
|
||||
}
|
||||
s++; i++;
|
||||
}
|
||||
|
||||
if (*s && !p) {
|
||||
/* the only termination allowed */
|
||||
if (*s != '=') {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* null terminate */
|
||||
d[n] = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
encode as base64
|
||||
caller frees
|
||||
*/
|
||||
char *ldb_base64_encode(const char *buf, int len)
|
||||
{
|
||||
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
int bit_offset, byte_offset, idx, i;
|
||||
unsigned char *d = (unsigned char *)buf;
|
||||
int bytes = (len*8 + 5)/6;
|
||||
char *out;
|
||||
|
||||
out = malloc(bytes+2);
|
||||
if (!out) return NULL;
|
||||
|
||||
for (i=0;i<bytes;i++) {
|
||||
byte_offset = (i*6)/8;
|
||||
bit_offset = (i*6)%8;
|
||||
if (bit_offset < 3) {
|
||||
idx = (d[byte_offset] >> (2-bit_offset)) & 0x3F;
|
||||
} else {
|
||||
idx = (d[byte_offset] << (bit_offset-2)) & 0x3F;
|
||||
if (byte_offset+1 < len) {
|
||||
idx |= (d[byte_offset+1] >> (8-(bit_offset-2)));
|
||||
}
|
||||
}
|
||||
out[i] = b64[idx];
|
||||
}
|
||||
|
||||
out[i++] = '=';
|
||||
out[i] = 0;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
see if a buffer should be base64 encoded
|
||||
*/
|
||||
int ldb_should_b64_encode(const struct ldb_val *val)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p = val->data;
|
||||
|
||||
if (val->length == 0 || p[0] == ' ' || p[0] == ':') {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i=0; i<val->length; i++) {
|
||||
if (!isprint(p[i]) || p[i] == '\n') {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
encode as base64 to a file
|
||||
*/
|
||||
static int base64_encode_f(FILE *f, const char *buf, int len, int start_pos)
|
||||
{
|
||||
int i;
|
||||
char *b = ldb_base64_encode(buf, len);
|
||||
|
||||
if (!b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;b[i];i++) {
|
||||
fputc(b[i], f);
|
||||
if (b[i+1] && (i + start_pos) % 77 == 0) {
|
||||
fputc('\n', f);
|
||||
fputc(' ', f);
|
||||
}
|
||||
}
|
||||
free(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
write a line folded string onto a file
|
||||
*/
|
||||
static void fold_string(FILE *f, const char *buf, size_t length, int start_pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<length;i++) {
|
||||
fputc(buf[i], f);
|
||||
if (i != (length-1) && (i + start_pos) % 77 == 0) {
|
||||
fputc('\n', f);
|
||||
fputc(' ', f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
pull a ldif chunk, which is defined as a piece of data ending in \n\n or EOF
|
||||
this routine removes any RFC2849 continuations and comments
|
||||
|
||||
caller frees
|
||||
*/
|
||||
static char *next_chunk(FILE *f)
|
||||
{
|
||||
size_t alloc_size=0, chunk_size = 0;
|
||||
char *chunk = NULL;
|
||||
int c;
|
||||
int in_comment = 0;
|
||||
|
||||
while ((c = fgetc(f)) != EOF) {
|
||||
if (chunk_size == alloc_size) {
|
||||
char *c2;
|
||||
alloc_size += 1024;
|
||||
c2 = realloc_p(chunk, char, alloc_size);
|
||||
if (!c2) {
|
||||
free(chunk);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
chunk = c2;
|
||||
}
|
||||
|
||||
if (in_comment) {
|
||||
if (c == '\n') {
|
||||
in_comment = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle continuation lines - see RFC2849 */
|
||||
if (c == ' ' && chunk_size > 1 && chunk[chunk_size-1] == '\n') {
|
||||
chunk_size--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* chunks are terminated by a double line-feed */
|
||||
if (c == '\n' && chunk_size > 0 && chunk[chunk_size-1] == '\n') {
|
||||
chunk[chunk_size-1] = 0;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
if (c == '#' && (chunk_size == 0 || chunk[chunk_size-1] == '\n')) {
|
||||
in_comment = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
chunk[chunk_size++] = c;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
/* simple ldif attribute parser */
|
||||
static int next_attr(char **s, char **attr, struct ldb_val *value)
|
||||
{
|
||||
char *p;
|
||||
int base64_encoded = 0;
|
||||
|
||||
p = strchr(*s, ':');
|
||||
if (!p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*p++ = 0;
|
||||
|
||||
if (*p == ':') {
|
||||
base64_encoded = 1;
|
||||
p++;
|
||||
}
|
||||
|
||||
*attr = *s;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
|
||||
value->data = p;
|
||||
|
||||
p = strchr(p, '\n');
|
||||
|
||||
if (!p) {
|
||||
value->length = strlen((char *)value->data);
|
||||
*s = ((char *)value->data) + value->length;
|
||||
} else {
|
||||
value->length = p - (char *)value->data;
|
||||
*s = p+1;
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
if (base64_encoded) {
|
||||
int len = base64_decode(value->data);
|
||||
if (len == -1) {
|
||||
/* it wasn't valid base64 data */
|
||||
return -1;
|
||||
}
|
||||
value->length = len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
free a message from a ldif_read
|
||||
*/
|
||||
void ldif_read_free(struct ldb_message *msg)
|
||||
{
|
||||
if (msg->elements) free(msg->elements);
|
||||
if (msg->private) free(msg->private);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/*
|
||||
read from a LDIF file, creating a ldb_message
|
||||
*/
|
||||
struct ldb_message *ldif_read(FILE *f)
|
||||
{
|
||||
struct ldb_message *msg;
|
||||
char *attr=NULL, *chunk=NULL, *s;
|
||||
struct ldb_val value;
|
||||
|
||||
value.data = NULL;
|
||||
|
||||
msg = malloc_p(struct ldb_message);
|
||||
if (!msg) return NULL;
|
||||
|
||||
msg->dn = NULL;
|
||||
msg->elements = NULL;
|
||||
msg->num_elements = 0;
|
||||
msg->private = NULL;
|
||||
|
||||
chunk = next_chunk(f);
|
||||
if (!chunk) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msg->private = chunk;
|
||||
s = chunk;
|
||||
|
||||
if (next_attr(&s, &attr, &value) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* first line must be a dn */
|
||||
if (strcmp(attr, "dn") != 0) {
|
||||
fprintf(stderr, "First line must be a dn not '%s'\n", attr);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
msg->dn = value.data;
|
||||
|
||||
while (next_attr(&s, &attr, &value) == 0) {
|
||||
msg->elements = realloc_p(msg->elements,
|
||||
struct ldb_message_element,
|
||||
msg->num_elements+1);
|
||||
if (!msg->elements) {
|
||||
goto failed;
|
||||
}
|
||||
msg->elements[msg->num_elements].flags = 0;
|
||||
msg->elements[msg->num_elements].name = attr;
|
||||
msg->elements[msg->num_elements].value = value;
|
||||
msg->num_elements++;
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
||||
failed:
|
||||
if (msg) ldif_read_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
write to a ldif file
|
||||
*/
|
||||
void ldif_write(FILE *f, const struct ldb_message *msg)
|
||||
{
|
||||
int i;
|
||||
fprintf(f, "dn: %s\n", msg->dn);
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (ldb_should_b64_encode(&msg->elements[i].value)) {
|
||||
fprintf(f, "%s:: ", msg->elements[i].name);
|
||||
base64_encode_f(f,
|
||||
msg->elements[i].value.data,
|
||||
msg->elements[i].value.length,
|
||||
strlen(msg->elements[i].name)+3);
|
||||
fprintf(f, "\n");
|
||||
} else {
|
||||
fprintf(f, "%s: ", msg->elements[i].name);
|
||||
fold_string(f, msg->elements[i].value.data,
|
||||
msg->elements[i].value.length,
|
||||
strlen(msg->elements[i].name)+2);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
fprintf(f,"\n");
|
||||
}
|
176
source4/lib/ldb/ldb_tdb/ldb_match.c
Normal file
176
source4/lib/ldb/ldb_tdb/ldb_match.c
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
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 expression matching
|
||||
*
|
||||
* Description: ldb expression matching for tdb backend
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/*
|
||||
see if two ldb_val structures contain the same data
|
||||
return 1 for a match, 0 for a mis-match
|
||||
*/
|
||||
static int ldb_val_equal(struct ldb_val *v1, struct ldb_val *v2)
|
||||
{
|
||||
if (v1->length != v2->length) return 0;
|
||||
|
||||
if (v1->length == 0) return 1;
|
||||
|
||||
if (memcmp(v1->data, v2->data, v1->length) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
check if the scope matches in a search result
|
||||
*/
|
||||
static int scope_match(const char *dn, const char *base, enum ldb_scope scope)
|
||||
{
|
||||
size_t dn_len, base_len;
|
||||
|
||||
if (base == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
base_len = strlen(base);
|
||||
dn_len = strlen(dn);
|
||||
|
||||
if (strcmp(dn, base) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (base_len+1 >= dn_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (scope) {
|
||||
case LDB_SCOPE_BASE:
|
||||
break;
|
||||
|
||||
case LDB_SCOPE_ONELEVEL:
|
||||
if (strcmp(dn + (dn_len - base_len), base) == 0 &&
|
||||
dn[dn_len - base_len - 1] == ',' &&
|
||||
strchr(dn, ',') == &dn[dn_len - base_len - 1]) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LDB_SCOPE_SUBTREE:
|
||||
default:
|
||||
if (strcmp(dn + (dn_len - base_len), base) == 0 &&
|
||||
dn[dn_len - base_len - 1] == ',') {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
match a leaf node
|
||||
*/
|
||||
static int match_leaf(struct ldb_context *ldb,
|
||||
struct ldb_message *msg,
|
||||
struct ldb_parse_tree *tree,
|
||||
const char *base,
|
||||
enum ldb_scope scope)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!scope_match(msg->dn, base, scope)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(tree->u.simple.attr, "dn") == 0) {
|
||||
if (strcmp(tree->u.simple.value.data, "*") == 0) {
|
||||
return 1;
|
||||
}
|
||||
return strcmp(msg->dn, tree->u.simple.value.data) == 0;
|
||||
}
|
||||
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (strcmp(msg->elements[i].name, tree->u.simple.attr) == 0 &&
|
||||
(strcmp(tree->u.simple.value.data, "*") == 0 ||
|
||||
ldb_val_equal(&msg->elements[i].value, &tree->u.simple.value))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
return 0 if the given parse tree matches the given message. Assumes
|
||||
the message is in sorted order
|
||||
|
||||
return 1 if it matches, and 0 if it doesn't match
|
||||
|
||||
this is a recursive function, and does short-circuit evaluation
|
||||
*/
|
||||
int ldb_message_match(struct ldb_context *ldb,
|
||||
struct ldb_message *msg,
|
||||
struct ldb_parse_tree *tree,
|
||||
const char *base,
|
||||
enum ldb_scope scope)
|
||||
{
|
||||
int v, i;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
return ! ldb_message_match(ldb, msg, tree->u.not.child, base, scope);
|
||||
|
||||
case LDB_OP_AND:
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
|
||||
base, scope);
|
||||
if (!v) return 0;
|
||||
}
|
||||
return 1;
|
||||
|
||||
case LDB_OP_OR:
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
v = ldb_message_match(ldb, msg, tree->u.list.elements[i],
|
||||
base, scope);
|
||||
if (v) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return match_leaf(ldb, msg, tree, base, scope);
|
||||
}
|
174
source4/lib/ldb/ldb_tdb/ldb_pack.c
Normal file
174
source4/lib/ldb/ldb_tdb/ldb_pack.c
Normal file
@ -0,0 +1,174 @@
|
||||
/*
|
||||
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 pack/unpack
|
||||
*
|
||||
* Description: pack/unpack routines for ldb messages as key/value blobs
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb_tdb/ldb_tdb.h"
|
||||
|
||||
/* change this if the data format ever changes */
|
||||
#define LTDB_PACKING_FORMAT 0x26011966
|
||||
|
||||
/*
|
||||
pack a ldb message into a linear buffer in a TDB_DATA
|
||||
|
||||
caller frees the data buffer after use
|
||||
*/
|
||||
int ltdb_pack_data(struct ldb_context *ctx,
|
||||
const struct ldb_message *message,
|
||||
struct TDB_DATA *data)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
char *p;
|
||||
|
||||
/* work out how big it needs to be */
|
||||
size = 8;
|
||||
|
||||
for (i=0;i<message->num_elements;i++) {
|
||||
size += 1 + strlen(message->elements[i].name);
|
||||
size += 4 + message->elements[i].value.length + 1;
|
||||
}
|
||||
|
||||
/* allocate it */
|
||||
data->dptr = malloc(size);
|
||||
if (!data->dptr) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
data->dsize = size;
|
||||
|
||||
p = data->dptr;
|
||||
SIVAL(p, 0, LTDB_PACKING_FORMAT);
|
||||
SIVAL(p, 4, message->num_elements);
|
||||
p += 8;
|
||||
|
||||
for (i=0;i<message->num_elements;i++) {
|
||||
size_t len = strlen(message->elements[i].name);
|
||||
memcpy(p, message->elements[i].name, len+1);
|
||||
p += len + 1;
|
||||
SIVAL(p, 0, message->elements[i].value.length);
|
||||
memcpy(p+4, message->elements[i].value.data,
|
||||
message->elements[i].value.length);
|
||||
p[4+message->elements[i].value.length] = 0;
|
||||
p += 4 + message->elements[i].value.length + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
unpack a ldb message from a linear buffer in TDB_DATA
|
||||
|
||||
note that this does not fill in the class and key elements
|
||||
|
||||
caller frees. Memory for the elements[] array is malloced,
|
||||
but the memory for the elements is re-used from the TDB_DATA
|
||||
data. This means the caller only has to free the elements array
|
||||
*/
|
||||
int ltdb_unpack_data(struct ldb_context *ctx,
|
||||
const struct TDB_DATA *data,
|
||||
struct ldb_message *message)
|
||||
{
|
||||
char *p;
|
||||
unsigned int remaining;
|
||||
int i;
|
||||
|
||||
message->elements = NULL;
|
||||
|
||||
p = data->dptr;
|
||||
if (data->dsize < 4) {
|
||||
errno = EIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (IVAL(p, 0) != LTDB_PACKING_FORMAT) {
|
||||
/* this is where we will cope with upgrading the
|
||||
format if/when the format is ever changed */
|
||||
errno = EIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
message->num_elements = IVAL(p, 4);
|
||||
p += 8;
|
||||
|
||||
if (message->num_elements == 0) {
|
||||
message->elements = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* basic sanity check */
|
||||
remaining = data->dsize - 8;
|
||||
|
||||
if (message->num_elements > remaining / 6) {
|
||||
errno = EIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
message->elements = malloc_array_p(struct ldb_message_element,
|
||||
message->num_elements);
|
||||
|
||||
if (!message->elements) {
|
||||
errno = ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i=0;i<message->num_elements;i++) {
|
||||
size_t len;
|
||||
if (remaining < 6) {
|
||||
errno = EIO;
|
||||
goto failed;
|
||||
}
|
||||
len = strnlen(p, remaining-6);
|
||||
message->elements[i].name = p;
|
||||
remaining -= len + 1;
|
||||
p += len + 1;
|
||||
len = IVAL(p, 0);
|
||||
if (len > remaining-5) {
|
||||
errno = EIO;
|
||||
goto failed;
|
||||
}
|
||||
message->elements[i].value.length = len;
|
||||
message->elements[i].value.data = p+4;
|
||||
remaining -= len+4+1;
|
||||
p += len+4+1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
if (message->elements) {
|
||||
free(message->elements);
|
||||
}
|
||||
return -1;
|
||||
}
|
448
source4/lib/ldb/ldb_tdb/ldb_parse.c
Normal file
448
source4/lib/ldb/ldb_tdb/ldb_parse.c
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
parse a LDAP-like expression
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- add RFC2254 binary string handling
|
||||
- possibly add ~=, <= and >= handling
|
||||
- expand the test suite
|
||||
- add better parse error handling
|
||||
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/*
|
||||
a filter is defined by:
|
||||
<filter> ::= '(' <filtercomp> ')'
|
||||
<filtercomp> ::= <and> | <or> | <not> | <simple>
|
||||
<and> ::= '&' <filterlist>
|
||||
<or> ::= '|' <filterlist>
|
||||
<not> ::= '!' <filter>
|
||||
<filterlist> ::= <filter> | <filter> <filterlist>
|
||||
<simple> ::= <attributetype> <filtertype> <attributevalue>
|
||||
<filtertype> ::= '=' | '~=' | '<=' | '>='
|
||||
*/
|
||||
|
||||
/*
|
||||
return next token element. Caller frees
|
||||
*/
|
||||
static char *ldb_parse_lex(const char **s)
|
||||
{
|
||||
const char *p = *s;
|
||||
char *ret;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
*s = p;
|
||||
|
||||
if (*p == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strchr("()&|=!", *p)) {
|
||||
(*s) = p+1;
|
||||
ret = strndup(p, 1);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (*p && (isalnum(*p) || !strchr("()&|=!", *p))) {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (p == *s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = strndup(*s, p - *s);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
}
|
||||
|
||||
*s = p;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
find a matching close brace in a string
|
||||
*/
|
||||
static const char *match_brace(const char *s)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while (*s && (count != 0 || *s != ')')) {
|
||||
if (*s == '(') {
|
||||
count++;
|
||||
}
|
||||
if (*s == ')') {
|
||||
count--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
if (! *s) {
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static struct ldb_parse_tree *ldb_parse_filter(const char **s);
|
||||
|
||||
/*
|
||||
<simple> ::= <attributetype> <filtertype> <attributevalue>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_simple(const char *s)
|
||||
{
|
||||
char *eq, *val, *l;
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
l = ldb_parse_lex(&s);
|
||||
if (!l) {
|
||||
fprintf(stderr, "Unexpected end of expression\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strchr("()&|=", *l)) {
|
||||
fprintf(stderr, "Unexpected token '%s'\n", l);
|
||||
free(l);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eq = ldb_parse_lex(&s);
|
||||
if (!eq || strcmp(eq, "=") != 0) {
|
||||
fprintf(stderr, "Expected '='\n");
|
||||
free(l);
|
||||
if (eq) free(eq);
|
||||
return NULL;
|
||||
}
|
||||
free(eq);
|
||||
|
||||
val = ldb_parse_lex(&s);
|
||||
if (val && strchr("()&|=", *val)) {
|
||||
fprintf(stderr, "Unexpected token '%s'\n", val);
|
||||
free(l);
|
||||
if (val) free(val);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = LDB_OP_SIMPLE;
|
||||
ret->u.simple.attr = l;
|
||||
ret->u.simple.value.data = val;
|
||||
ret->u.simple.value.length = val?strlen(val):0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
parse a filterlist
|
||||
<and> ::= '&' <filterlist>
|
||||
<or> ::= '|' <filterlist>
|
||||
<filterlist> ::= <filter> | <filter> <filterlist>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filterlist(enum ldb_parse_op op, const char *s)
|
||||
{
|
||||
struct ldb_parse_tree *ret, *next;
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = op;
|
||||
ret->u.list.num_elements = 1;
|
||||
ret->u.list.elements = malloc_p(struct ldb_parse_tree *);
|
||||
if (!ret->u.list.elements) {
|
||||
errno = ENOMEM;
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->u.list.elements[0] = ldb_parse_filter(&s);
|
||||
if (!ret->u.list.elements[0]) {
|
||||
free(ret->u.list.elements);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
while (*s && (next = ldb_parse_filter(&s))) {
|
||||
struct ldb_parse_tree **e;
|
||||
e = realloc_p(ret->u.list.elements,
|
||||
struct ldb_parse_tree *,
|
||||
ret->u.list.num_elements+1);
|
||||
if (!e) {
|
||||
errno = ENOMEM;
|
||||
ldb_parse_tree_free(next);
|
||||
ldb_parse_tree_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->u.list.elements = e;
|
||||
ret->u.list.elements[ret->u.list.num_elements] = next;
|
||||
ret->u.list.num_elements++;
|
||||
while (isspace(*s)) s++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
<not> ::= '!' <filter>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_not(const char *s)
|
||||
{
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
ret = malloc_p(struct ldb_parse_tree);
|
||||
if (!ret) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->operation = LDB_OP_NOT;
|
||||
ret->u.not.child = ldb_parse_filter(&s);
|
||||
if (!ret->u.not.child) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
parse a filtercomp
|
||||
<filtercomp> ::= <and> | <or> | <not> | <simple>
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filtercomp(const char *s)
|
||||
{
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
switch (*s) {
|
||||
case '&':
|
||||
return ldb_parse_filterlist(LDB_OP_AND, s+1);
|
||||
|
||||
case '|':
|
||||
return ldb_parse_filterlist(LDB_OP_OR, s+1);
|
||||
|
||||
case '!':
|
||||
return ldb_parse_not(s+1);
|
||||
|
||||
case '(':
|
||||
case ')':
|
||||
fprintf(stderr, "Unexpected token '%c'\n", *s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ldb_parse_simple(s);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
<filter> ::= '(' <filtercomp> ')'
|
||||
*/
|
||||
static struct ldb_parse_tree *ldb_parse_filter(const char **s)
|
||||
{
|
||||
char *l, *s2;
|
||||
const char *p, *p2;
|
||||
struct ldb_parse_tree *ret;
|
||||
|
||||
l = ldb_parse_lex(s);
|
||||
if (!l) {
|
||||
fprintf(stderr, "Unexpected end of expression\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(l, "(") != 0) {
|
||||
free(l);
|
||||
fprintf(stderr, "Expected '('\n");
|
||||
return NULL;
|
||||
}
|
||||
free(l);
|
||||
|
||||
p = match_brace(*s);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Parse error - mismatched braces\n");
|
||||
return NULL;
|
||||
}
|
||||
p2 = p + 1;
|
||||
|
||||
s2 = strndup(*s, p - *s);
|
||||
if (!s2) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = ldb_parse_filtercomp(s2);
|
||||
free(s2);
|
||||
|
||||
*s = p2;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
main parser entry point. Takes a search string and returns a parse tree
|
||||
|
||||
expression ::= <simple> | <filter>
|
||||
*/
|
||||
struct ldb_parse_tree *ldb_parse_tree(const char *s)
|
||||
{
|
||||
while (isspace(*s)) s++;
|
||||
|
||||
if (*s == '(') {
|
||||
return ldb_parse_filter(&s);
|
||||
}
|
||||
|
||||
return ldb_parse_simple(s);
|
||||
}
|
||||
|
||||
/*
|
||||
free a parse tree returned from ldb_parse_tree()
|
||||
*/
|
||||
void ldb_parse_tree_free(struct ldb_parse_tree *tree)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
free(tree->u.simple.attr);
|
||||
if (tree->u.simple.value.data) free(tree->u.simple.value.data);
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
case LDB_OP_OR:
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
ldb_parse_tree_free(tree->u.list.elements[i]);
|
||||
}
|
||||
if (tree->u.list.elements) free(tree->u.list.elements);
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
ldb_parse_tree_free(tree->u.not.child);
|
||||
break;
|
||||
}
|
||||
|
||||
free(tree);
|
||||
}
|
||||
|
||||
#if TEST_PROGRAM
|
||||
/*
|
||||
return a string representation of a parse tree
|
||||
used for debugging
|
||||
*/
|
||||
static char *tree_string(struct ldb_parse_tree *tree)
|
||||
{
|
||||
char *s = NULL;
|
||||
char *s1, *s2;
|
||||
int i;
|
||||
|
||||
switch (tree->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
asprintf(&s, "( %s = \"%s\" )", tree->u.simple.attr,
|
||||
(char *)tree->u.simple.value.data);
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
case LDB_OP_OR:
|
||||
asprintf(&s, "( %c", tree->operation==LDB_OP_AND?'&':'|');
|
||||
if (!s) return NULL;
|
||||
|
||||
for (i=0;i<tree->u.list.num_elements;i++) {
|
||||
s1 = tree_string(tree->u.list.elements[i]);
|
||||
if (!s1) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
asprintf(&s2, "%s %s", s, s1);
|
||||
free(s);
|
||||
free(s1);
|
||||
s = s2;
|
||||
}
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
asprintf(&s2, "%s )", s);
|
||||
free(s);
|
||||
s = s2;
|
||||
break;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
s1 = tree_string(tree->u.not.child);
|
||||
asprintf(&s, "( ! %s )", s1);
|
||||
free(s1);
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
print a tree
|
||||
*/
|
||||
static void print_tree(struct ldb_parse_tree *tree)
|
||||
{
|
||||
char *s = tree_string(tree);
|
||||
printf("%s\n", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char line[1000];
|
||||
int ret = 0;
|
||||
|
||||
while (fgets(line, sizeof(line)-1, stdin)) {
|
||||
struct ldb_parse_tree *tree;
|
||||
|
||||
if (line[strlen(line)-1] == '\n') {
|
||||
line[strlen(line)-1] = 0;
|
||||
}
|
||||
tree = ldb_parse_tree(line);
|
||||
if (!tree) {
|
||||
fprintf(stderr, "Failed to parse\n");
|
||||
ret = 1;
|
||||
continue;
|
||||
}
|
||||
print_tree(tree);
|
||||
ldb_parse_tree_free(tree);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* TEST_PROGRAM */
|
||||
|
40
source4/lib/ldb/ldb_tdb/ldb_parse.h
Normal file
40
source4/lib/ldb/ldb_tdb/ldb_parse.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
parse a LDAP-like expression - header
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
enum ldb_parse_op {LDB_OP_SIMPLE, LDB_OP_AND, LDB_OP_OR, LDB_OP_NOT};
|
||||
|
||||
struct ldb_parse_tree {
|
||||
enum ldb_parse_op operation;
|
||||
union {
|
||||
struct {
|
||||
char *attr;
|
||||
struct ldb_val value;
|
||||
} simple;
|
||||
struct {
|
||||
unsigned int num_elements;
|
||||
struct ldb_parse_tree **elements;
|
||||
} list;
|
||||
struct {
|
||||
struct ldb_parse_tree *child;
|
||||
} not;
|
||||
} u;
|
||||
};
|
482
source4/lib/ldb/ldb_tdb/ldb_search.c
Normal file
482
source4/lib/ldb/ldb_tdb/ldb_search.c
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
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 search functions
|
||||
*
|
||||
* Description: functions to search ldb+tdb databases
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb_tdb/ldb_tdb.h"
|
||||
|
||||
/*
|
||||
free a message that has all parts separately allocated
|
||||
*/
|
||||
static void msg_free_all_parts(struct ldb_message *msg)
|
||||
{
|
||||
int i;
|
||||
if (msg->dn) free(msg->dn);
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (msg->elements[i].name) free(msg->elements[i].name);
|
||||
if (msg->elements[i].value.data) free(msg->elements[i].value.data);
|
||||
}
|
||||
free(msg->elements);
|
||||
free(msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
TODO: this should take advantage of the sorted nature of the message
|
||||
return index of the attribute, or -1 if not found
|
||||
*/
|
||||
int ldb_msg_find_attr(const struct ldb_message *msg, const char *attr)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (strcmp(msg->elements[i].name, attr) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
duplicate a ldb_val structure
|
||||
*/
|
||||
static struct ldb_val ldb_val_dup(const struct ldb_val *v)
|
||||
{
|
||||
struct ldb_val v2;
|
||||
v2.length = v->length;
|
||||
if (v->length == 0) {
|
||||
v2.data = NULL;
|
||||
return v2;
|
||||
}
|
||||
|
||||
/* the +1 is to cope with buggy C library routines like strndup
|
||||
that look one byte beyond */
|
||||
v2.data = malloc(v->length+1);
|
||||
if (!v2.data) {
|
||||
v2.length = 0;
|
||||
return v2;
|
||||
}
|
||||
|
||||
memcpy(v2.data, v->data, v->length);
|
||||
((char *)v2.data)[v->length] = 0;
|
||||
return v2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
add one element to a message
|
||||
*/
|
||||
static int msg_add_element(struct ldb_message *ret, const struct ldb_message_element *el)
|
||||
{
|
||||
struct ldb_message_element *e2;
|
||||
|
||||
e2 = realloc_p(ret->elements, struct ldb_message_element, ret->num_elements+1);
|
||||
if (!e2) {
|
||||
return -1;
|
||||
}
|
||||
ret->elements = e2;
|
||||
|
||||
e2[ret->num_elements].name = strdup(el->name);
|
||||
if (!e2[ret->num_elements].name) {
|
||||
return -1;
|
||||
}
|
||||
e2[ret->num_elements].value = ldb_val_dup(&el->value);
|
||||
if (e2[ret->num_elements].value.length != el->value.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret->num_elements++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
add all elements from one message into another
|
||||
*/
|
||||
static int msg_add_all_elements(struct ldb_message *ret,
|
||||
const struct ldb_message *msg)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
if (msg_add_element(ret, &msg->elements[i]) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
pull the specified list of attributes from a message
|
||||
*/
|
||||
static struct ldb_message *ltdb_pull_attrs(struct ldb_context *ldb,
|
||||
const struct ldb_message *msg,
|
||||
const char **attrs)
|
||||
{
|
||||
struct ldb_message *ret;
|
||||
int i;
|
||||
|
||||
ret = malloc_p(struct ldb_message);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->dn = strdup(msg->dn);
|
||||
if (!ret->dn) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->num_elements = 0;
|
||||
ret->elements = NULL;
|
||||
ret->private = NULL;
|
||||
|
||||
if (!attrs) {
|
||||
if (msg_add_all_elements(ret, msg) != 0) {
|
||||
msg_free_all_parts(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i=0;attrs[i];i++) {
|
||||
int j;
|
||||
|
||||
if (strcmp(attrs[i], "*") == 0) {
|
||||
if (msg_add_all_elements(ret, msg) != 0) {
|
||||
msg_free_all_parts(ret);
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
j = ldb_msg_find_attr(msg, attrs[i]);
|
||||
if (j == -1) {
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
if (msg_add_element(ret, &msg->elements[j]) != 0) {
|
||||
msg_free_all_parts(ret);
|
||||
return NULL;
|
||||
}
|
||||
} while (++j < msg->num_elements &&
|
||||
strcmp(attrs[i], msg->elements[j].name) == 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
see if a ldb_val is a wildcard
|
||||
*/
|
||||
int ltdb_has_wildcard(const struct ldb_val *val)
|
||||
{
|
||||
if (val->length == 1 && ((char *)val->data)[0] == '*') {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
free the results of a ltdb_search_dn1 search
|
||||
*/
|
||||
void ltdb_search_dn1_free(struct ldb_context *ldb, struct ldb_message *msg)
|
||||
{
|
||||
free(msg->dn);
|
||||
free(msg->private);
|
||||
if (msg->elements) free(msg->elements);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
search the database for a single simple dn, returning all attributes
|
||||
in a single message
|
||||
|
||||
return 1 on success, 0 on record-not-found and -1 on error
|
||||
*/
|
||||
int ltdb_search_dn1(struct ldb_context *ldb, const char *dn, struct ldb_message *msg)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
int ret;
|
||||
TDB_DATA tdb_key, tdb_data;
|
||||
|
||||
/* form the key */
|
||||
tdb_key = ltdb_key(dn);
|
||||
if (!tdb_key.dptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
|
||||
free(tdb_key.dptr);
|
||||
if (!tdb_data.dptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg->dn = strdup(dn);
|
||||
if (!msg->dn) {
|
||||
free(tdb_data.dptr);
|
||||
return -1;
|
||||
}
|
||||
msg->private = tdb_data.dptr;
|
||||
msg->num_elements = 0;
|
||||
msg->elements = NULL;
|
||||
|
||||
ret = ltdb_unpack_data(ldb, &tdb_data, msg);
|
||||
if (ret == -1) {
|
||||
free(tdb_data.dptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
search the database for a single simple dn
|
||||
*/
|
||||
int ltdb_search_dn(struct ldb_context *ldb, char *dn,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_message msg, *msg2;
|
||||
|
||||
ret = ltdb_search_dn1(ldb, dn, &msg);
|
||||
if (ret != 1) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
msg2 = ltdb_pull_attrs(ldb, &msg, attrs);
|
||||
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
|
||||
if (!msg2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*res = malloc_array_p(struct ldb_message *, 2);
|
||||
if (! *res) {
|
||||
msg_free_all_parts(msg2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*res)[0] = msg2;
|
||||
(*res)[1] = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a set of attributes from a record to a set of results
|
||||
return 0 on success, -1 on failure
|
||||
*/
|
||||
int ltdb_add_attr_results(struct ldb_context *ldb, struct ldb_message *msg,
|
||||
const char *attrs[],
|
||||
unsigned int *count,
|
||||
struct ldb_message ***res)
|
||||
{
|
||||
struct ldb_message *msg2;
|
||||
struct ldb_message **res2;
|
||||
|
||||
/* pull the attributes that the user wants */
|
||||
msg2 = ltdb_pull_attrs(ldb, msg, attrs);
|
||||
if (!msg2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add to the results list */
|
||||
res2 = realloc_p(*res, struct ldb_message *, (*count)+2);
|
||||
if (!res2) {
|
||||
msg_free_all_parts(msg2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*res) = res2;
|
||||
|
||||
(*res)[*count] = msg2;
|
||||
(*res)[(*count)+1] = NULL;
|
||||
(*count)++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
internal search state during a full db search
|
||||
*/
|
||||
struct ltdb_search_info {
|
||||
struct ldb_context *ldb;
|
||||
struct ldb_parse_tree *tree;
|
||||
const char *base;
|
||||
enum ldb_scope scope;
|
||||
const char **attrs;
|
||||
struct ldb_message **msgs;
|
||||
int failures;
|
||||
int count;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
search function for a non-indexed search
|
||||
*/
|
||||
static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state)
|
||||
{
|
||||
struct ltdb_search_info *sinfo = state;
|
||||
struct ldb_message msg;
|
||||
int ret;
|
||||
|
||||
if (key.dsize < 4 ||
|
||||
strncmp(key.dptr, "DN=", 3) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg.dn = key.dptr + 3;
|
||||
|
||||
/* unpack the record */
|
||||
ret = ltdb_unpack_data(sinfo->ldb, &data, &msg);
|
||||
if (ret == -1) {
|
||||
sinfo->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* see if it matches the given expression */
|
||||
if (!ldb_message_match(sinfo->ldb, &msg, sinfo->tree,
|
||||
sinfo->base, sinfo->scope)) {
|
||||
if (msg.elements) free(msg.elements);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ltdb_add_attr_results(sinfo->ldb, &msg, sinfo->attrs, &sinfo->count, &sinfo->msgs);
|
||||
|
||||
if (ret == -1) {
|
||||
sinfo->failures++;
|
||||
}
|
||||
|
||||
if (msg.elements) free(msg.elements);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
free a set of search results
|
||||
*/
|
||||
int ltdb_search_free(struct ldb_context *ldb, struct ldb_message **msgs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!msgs) return 0;
|
||||
|
||||
for (i=0;msgs[i];i++) {
|
||||
msg_free_all_parts(msgs[i]);
|
||||
}
|
||||
|
||||
free(msgs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
search the database with a LDAP-like expression.
|
||||
this is the "full search" non-indexed varient
|
||||
*/
|
||||
static int ltdb_search_full(struct ldb_context *ldb,
|
||||
const char *base,
|
||||
enum ldb_scope scope,
|
||||
struct ldb_parse_tree *tree,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
int ret;
|
||||
struct ltdb_search_info sinfo;
|
||||
|
||||
sinfo.tree = tree;
|
||||
sinfo.ldb = ldb;
|
||||
sinfo.scope = scope;
|
||||
sinfo.base = base;
|
||||
sinfo.attrs = attrs;
|
||||
sinfo.msgs = NULL;
|
||||
sinfo.count = 0;
|
||||
sinfo.failures = 0;
|
||||
|
||||
ret = tdb_traverse(ltdb->tdb, search_func, &sinfo);
|
||||
|
||||
if (ret == -1) {
|
||||
ltdb_search_free(ldb, sinfo.msgs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*res = sinfo.msgs;
|
||||
return sinfo.count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
search the database with a LDAP-like expression.
|
||||
choses a search method
|
||||
*/
|
||||
int ltdb_search(struct ldb_context *ldb, const char *base,
|
||||
enum ldb_scope scope, const char *expression,
|
||||
const char *attrs[], struct ldb_message ***res)
|
||||
{
|
||||
struct ldb_parse_tree *tree;
|
||||
int ret;
|
||||
|
||||
*res = NULL;
|
||||
|
||||
/* form a parse tree for the expression */
|
||||
tree = ldb_parse_tree(expression);
|
||||
if (!tree) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tree->operation == LDB_OP_SIMPLE &&
|
||||
strcmp(tree->u.simple.attr, "dn") == 0 &&
|
||||
!ltdb_has_wildcard(&tree->u.simple.value)) {
|
||||
/* yay! its a nice simple one */
|
||||
ret = ltdb_search_dn(ldb, tree->u.simple.value.data, attrs, res);
|
||||
} else {
|
||||
ret = ltdb_search_indexed(ldb, base, scope, tree, attrs, res);
|
||||
if (ret == -1) {
|
||||
ret = ltdb_search_full(ldb, base, scope, tree, attrs, res);
|
||||
}
|
||||
}
|
||||
|
||||
ldb_parse_tree_free(tree);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
303
source4/lib/ldb/ldb_tdb/ldb_tdb.c
Normal file
303
source4/lib/ldb/ldb_tdb/ldb_tdb.c
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
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 backend
|
||||
*
|
||||
* Description: core functions for tdb backend
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb_tdb/ldb_tdb.h"
|
||||
|
||||
/*
|
||||
form a TDB_DATA for a record key
|
||||
caller frees
|
||||
*/
|
||||
struct TDB_DATA ltdb_key(const char *dn)
|
||||
{
|
||||
TDB_DATA key;
|
||||
char *key_str = NULL;
|
||||
|
||||
asprintf(&key_str, "DN=%s", dn);
|
||||
if (!key_str) {
|
||||
errno = ENOMEM;
|
||||
key.dptr = NULL;
|
||||
key.dsize = 0;
|
||||
return key;
|
||||
}
|
||||
|
||||
key.dptr = key_str;
|
||||
key.dsize = strlen(key_str)+1;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
store a record into the db
|
||||
*/
|
||||
int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
TDB_DATA tdb_key, tdb_data;
|
||||
int ret;
|
||||
|
||||
tdb_key = ltdb_key(msg->dn);
|
||||
if (!tdb_key.dptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_pack_data(ldb, msg, &tdb_data);
|
||||
if (ret == -1) {
|
||||
free(tdb_key.dptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
|
||||
if (ret == -1) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = ltdb_index_add(ldb, msg);
|
||||
if (ret == -1) {
|
||||
tdb_delete(ltdb->tdb, tdb_key);
|
||||
}
|
||||
|
||||
done:
|
||||
free(tdb_key.dptr);
|
||||
free(tdb_data.dptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
add a record to the database
|
||||
*/
|
||||
static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
return ltdb_store(ldb, msg, TDB_INSERT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
delete a record from the database, not updating indexes (used for deleting
|
||||
index records)
|
||||
*/
|
||||
int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
TDB_DATA tdb_key;
|
||||
int ret;
|
||||
|
||||
tdb_key = ltdb_key(dn);
|
||||
if (!tdb_key.dptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = tdb_delete(ltdb->tdb, tdb_key);
|
||||
free(tdb_key.dptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
delete a record from the database
|
||||
*/
|
||||
static int ltdb_delete(struct ldb_context *ldb, const char *dn)
|
||||
{
|
||||
int ret;
|
||||
struct ldb_message msg;
|
||||
|
||||
/* in case any attribute of the message was indexed, we need
|
||||
to fetch the old record */
|
||||
ret = ltdb_search_dn1(ldb, dn, &msg);
|
||||
if (ret != 1) {
|
||||
/* not finding the old record is an error */
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_delete_noindex(ldb, dn);
|
||||
if (ret == -1) {
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove any indexed attributes */
|
||||
ret = ltdb_index_del(ldb, &msg);
|
||||
|
||||
ltdb_search_dn1_free(ldb, &msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
modify a record
|
||||
*/
|
||||
static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
TDB_DATA tdb_key, tdb_data;
|
||||
struct ldb_message msg2;
|
||||
int ret;
|
||||
|
||||
tdb_key = ltdb_key(msg->dn);
|
||||
if (!tdb_key.dptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
|
||||
if (!tdb_data.dptr) {
|
||||
free(tdb_key.dptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
|
||||
if (ret == -1) {
|
||||
free(tdb_key.dptr);
|
||||
free(tdb_data.dptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (i=0;i<msg->num_elements;i++) {
|
||||
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
|
||||
case LDB_FLAG_MOD_ADD:
|
||||
ret = find_element(&msg2, msg->elements[i].name);
|
||||
if (ret != -1) {
|
||||
errno = EEXIST;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
failed:
|
||||
#endif
|
||||
|
||||
free(tdb_key.dptr);
|
||||
free(tdb_data.dptr);
|
||||
if (msg2.elements) free(msg2.elements);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
close database
|
||||
*/
|
||||
static int ltdb_close(struct ldb_context *ldb)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
int ret;
|
||||
ret = tdb_close(ltdb->tdb);
|
||||
free(ltdb);
|
||||
free(ldb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
return extended error information
|
||||
*/
|
||||
static const char *ltdb_errstring(struct ldb_context *ldb)
|
||||
{
|
||||
struct ltdb_private *ltdb = ldb->private;
|
||||
return tdb_errorstr(ltdb->tdb);
|
||||
}
|
||||
|
||||
|
||||
static const struct ldb_backend_ops ltdb_ops = {
|
||||
ltdb_close,
|
||||
ltdb_search,
|
||||
ltdb_search_free,
|
||||
ltdb_add,
|
||||
ltdb_modify,
|
||||
ltdb_delete,
|
||||
ltdb_errstring
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
connect to the database
|
||||
*/
|
||||
struct ldb_context *ltdb_connect(const char *url,
|
||||
unsigned int flags,
|
||||
const char *options[])
|
||||
{
|
||||
const char *path;
|
||||
int tdb_flags, open_flags;
|
||||
struct ltdb_private *ltdb;
|
||||
TDB_CONTEXT *tdb;
|
||||
struct ldb_context *ldb;
|
||||
|
||||
/* parse the url */
|
||||
if (strncmp(url, "tdb://", 6) != 0) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
path = url+6;
|
||||
|
||||
tdb_flags = TDB_DEFAULT;
|
||||
|
||||
if (flags & LDB_FLG_RDONLY) {
|
||||
open_flags = O_RDONLY;
|
||||
} else {
|
||||
open_flags = O_CREAT | O_RDWR;
|
||||
}
|
||||
|
||||
tdb = tdb_open(path, 0, tdb_flags, open_flags, 0666);
|
||||
if (!tdb) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ltdb = malloc_p(struct ltdb_private);
|
||||
if (!ltdb) {
|
||||
tdb_close(tdb);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ltdb->tdb = tdb;
|
||||
|
||||
|
||||
ldb = malloc_p(struct ldb_context);
|
||||
if (!ldb) {
|
||||
tdb_close(tdb);
|
||||
free(ltdb);
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ldb->private = ltdb;
|
||||
ldb->ops = <db_ops;
|
||||
|
||||
return ldb;
|
||||
}
|
11
source4/lib/ldb/ldb_tdb/ldb_tdb.h
Normal file
11
source4/lib/ldb/ldb_tdb/ldb_tdb.h
Normal file
@ -0,0 +1,11 @@
|
||||
/* this private structure is used by the ltdb backend in the
|
||||
ldb_context */
|
||||
struct ltdb_private {
|
||||
TDB_CONTEXT *tdb;
|
||||
unsigned int connect_flags;
|
||||
};
|
||||
|
||||
|
||||
#define IVAL(p, ofs) (((unsigned *)((char *)(p) + (ofs)))[0])
|
||||
#define SIVAL(p, ofs, v) do { IVAL(p, ofs) = (v); } while (0)
|
||||
|
55
source4/lib/ldb/ldb_tdb/ldbadd.c
Normal file
55
source4/lib/ldb/ldb_tdb/ldbadd.c
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
a utility to add elements to a ldb
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
struct ldb_message *msg;
|
||||
int ret;
|
||||
int count=0, failures=0;
|
||||
|
||||
ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
|
||||
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((msg = ldif_read(stdin))) {
|
||||
ret = ldb->ops->add(ldb, msg);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to add record '%s'\n", msg->dn);
|
||||
failures++;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
ldif_read_free(msg);
|
||||
}
|
||||
|
||||
ldb->ops->close(ldb);
|
||||
|
||||
printf("Added %d records with %d failures\n", count, failures);
|
||||
|
||||
return 0;
|
||||
}
|
50
source4/lib/ldb/ldb_tdb/ldbdel.c
Normal file
50
source4/lib/ldb/ldb_tdb/ldbdel.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
a utility to delete elements in a ldb
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
int ret, i;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: ldbdel <dn...>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=1;i<argc;i++) {
|
||||
ret = ldb->ops->delete(ldb, argv[i]);
|
||||
if (ret != 0) {
|
||||
printf("delete of '%s' failed\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ldb->ops->close(ldb);
|
||||
return 0;
|
||||
}
|
73
source4/lib/ldb/ldb_tdb/ldbsearch.c
Normal file
73
source4/lib/ldb/ldb_tdb/ldbsearch.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
simple ldb search tool
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
struct ldb_message **msgs;
|
||||
int ret, i;
|
||||
const char *expression;
|
||||
const char **attrs = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: ldbsearch <expression> [attrs...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc > 2) {
|
||||
attrs = argv+2;
|
||||
}
|
||||
|
||||
expression = argv[1];
|
||||
|
||||
ldb = ltdb_connect("tdb://test.ldb", 0, NULL);
|
||||
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = ldb->ops->search(ldb, expression, attrs, &msgs);
|
||||
|
||||
if (ret == -1) {
|
||||
printf("search failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("# returned %d records\n", ret);
|
||||
|
||||
for (i=0;i<ret;i++) {
|
||||
printf("# record %d\n", i+1);
|
||||
ldif_write(stdout, msgs[i]);
|
||||
}
|
||||
|
||||
ret = ldb->ops->search_free(ldb, msgs);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "search_free failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb->ops->close(ldb);
|
||||
return 0;
|
||||
}
|
15
source4/lib/ldb/tests/init.ldif
Normal file
15
source4/lib/ldb/tests/init.ldif
Normal file
@ -0,0 +1,15 @@
|
||||
dn: o=University of Michigan,c=US
|
||||
objectclass: organization
|
||||
objectclass: domainRelatedObject
|
||||
l: Ann Arbor, Michigan
|
||||
st: Michigan
|
||||
o: University of Michigan
|
||||
o: UMICH
|
||||
o: UM
|
||||
o: U-M
|
||||
o: U of M
|
||||
description: The University of Michigan at Ann Arbor
|
||||
postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481
|
||||
09 $ US
|
||||
telephonenumber: +1 313 764-1817
|
||||
associateddomain: example.com
|
11
source4/lib/ldb/tests/init_slapd.sh
Executable file
11
source4/lib/ldb/tests/init_slapd.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PATH=/home/tridge/samba/openldap/prefix/sbin:/home/tridge/samba/openldap/prefix/bin:/home/tridge/samba/openldap/prefix/libexec:$PATH
|
||||
|
||||
rm -rf tests/tmp/db
|
||||
mkdir -p tests/tmp/db
|
||||
|
||||
killall slapd
|
||||
sleep 2
|
||||
killall -9 slapd
|
||||
slapadd -f tests/slapd.conf < tests/init.ldif || exit 1
|
11
source4/lib/ldb/tests/ldapi_url.sh
Executable file
11
source4/lib/ldb/tests/ldapi_url.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
# aargh, did LDAP ever have to expose this crap to users ...
|
||||
|
||||
BASE=`pwd`
|
||||
|
||||
TMPDIR=$BASE/tests/tmp
|
||||
|
||||
LDAPI_ESCAPE=`echo $TMPDIR/ldapi | sed 's|/|%2F|g'`
|
||||
|
||||
echo "ldapi://$LDAPI_ESCAPE"
|
25
source4/lib/ldb/tests/slapd.conf
Normal file
25
source4/lib/ldb/tests/slapd.conf
Normal file
@ -0,0 +1,25 @@
|
||||
loglevel 0
|
||||
|
||||
include tests/schema/core.schema
|
||||
include tests/schema/cosine.schema
|
||||
include tests/schema/inetorgperson.schema
|
||||
include tests/schema/openldap.schema
|
||||
include tests/schema/nis.schema
|
||||
|
||||
|
||||
pidfile tests/tmp/slapd.pid
|
||||
argsfile tests/tmp/slapd.args
|
||||
|
||||
access to * by * write
|
||||
|
||||
allow update_anon bind_anon_dn
|
||||
|
||||
defaultsearchbase "o=University of Michigan,c=US"
|
||||
|
||||
database ldbm
|
||||
suffix "o=University of Michigan,c=US"
|
||||
directory tests/tmp/db
|
||||
|
||||
index objectClass eq
|
||||
index drink eq
|
||||
index title eq
|
8
source4/lib/ldb/tests/start_slapd.sh
Executable file
8
source4/lib/ldb/tests/start_slapd.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PATH=/home/tridge/samba/openldap/prefix/sbin:/home/tridge/samba/openldap/prefix/bin:/home/tridge/samba/openldap/prefix/libexec:$PATH
|
||||
|
||||
mkdir -p tests/tmp/db
|
||||
|
||||
slapd -f tests/slapd.conf -h "`tests/ldapi_url.sh`" $*
|
||||
|
4
source4/lib/ldb/tests/test-index.ldif
Normal file
4
source4/lib/ldb/tests/test-index.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: @INDEXLIST
|
||||
@IDXATTR: drink
|
||||
@IDXATTR: title
|
||||
@IDXATTR: objectclass
|
416
source4/lib/ldb/tests/test.ldif
Normal file
416
source4/lib/ldb/tests/test.ldif
Normal file
@ -0,0 +1,416 @@
|
||||
dn: ou=People,o=University of Michigan,c=US
|
||||
objectclass: organizationalUnit
|
||||
objectclass: extensibleObject
|
||||
ou: People
|
||||
uidNumber: 0
|
||||
gidNumber: 0
|
||||
|
||||
dn: ou=Groups,o=University of Michigan,c=US
|
||||
objectclass: organizationalUnit
|
||||
ou: Groups
|
||||
|
||||
dn: ou=Information Technology Division,ou=People,o=University of Michigan,c=US
|
||||
objectclass: organizationalUnit
|
||||
ou: Information Technology Division
|
||||
description:: aMODwoPDgsKCw4PCgsOCwotFVlZQw4PCg8OCwoPDg8KCw4LCv0zDg8KDw4LCgsOD
|
||||
woLDgsKKT8ODwoPDgsKDw4PCgsOCwqs6w4PCg8OCwoLDg8KCw4LCjUQkw4PCg8OCwoLDg8KCw4LCi
|
||||
01QUcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4
|
||||
LCgsODwoLDgsKLRCQoZitEJMODwoPDgsKCw4PCgsOCwrfDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoP
|
||||
Dg8KCw4LCgcODwoPDgsKDw4PCgsOCwqHDg8KDw4LCgsODwoLDgsKLRCQkZitEJMODwoPDgsKCw4PC
|
||||
gsOCwrfDg8KDw4LCg8ODwoLDgsKQw4PCg8OCwoPDg8KCw4LCisODwoPDgsKCw4PCgsOCwotFUVZqU
|
||||
MODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKAw4PCg8OCwoLDg8KCw4LCik85dCTDg8KDw4
|
||||
LCgsODwoLDgsKFQ8ODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4L
|
||||
Cvzl0JMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPD
|
||||
gsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKLRCTDg8KDw4LCgsODwoLDgsKDw4PCg8OCwoLDg8KCw
|
||||
4LCuMODwoPDgsKDw4PCgsOCwoR0Q8ODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LChMODwo
|
||||
PDgsKDw4PCgsOCwoFOdTrDg8KDw4LCg8ODwoLDgsKHw4PCg8OCwoPDg8KCw4LChMODwoPDgsKDw4P
|
||||
CgsOCwoFOw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwrtHw4PCg8OCwoLDg8KCw4LChcOD
|
||||
woPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsK4dMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODw
|
||||
oLDgsKtR8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwo
|
||||
PDgsKDw4PCgsOCwr9SfGrDg8KDw4LCgsODwoLDgsKLQGgxw4PCg8OCwoPDg8KCw4LCoWhQw4PCg8O
|
||||
CwoPDg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKT8ODwoPDgsKCw4PCgsOC
|
||||
wotEJDDDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHTDg8KDw4LCgsODwoLDgsKDw4PCg
|
||||
8OCwoPDg8KCw4LCuHXDg8KDw4LCgsODwoLDgsKLRCRqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4
|
||||
PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpPDg8K
|
||||
Dw4LCg8ODwoLDgsKQXV9eW8ODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoPD
|
||||
g8KCw4LCgsODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODw
|
||||
oPDgsKDw4PCgsOCwozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgs
|
||||
OCwoxWV8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKxw4PCg8OCwoLDg8KCw4LCi3wkw4P
|
||||
Cg8OCwoLDg8KCw4LCjcODwoPDgsKCw4PCgsOCwofDg8KDw4LCg8ODwoLDgsKof8ODwoPDgsKDw4PC
|
||||
gsOCwr/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCg8ODwoPDgsKDw4PCgsOCwrh5w4PCg
|
||||
8OCwoLDg8KCw4LChzQzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PCgsOCworDg8KDw4LCgsODwo
|
||||
LDgsKIw4PCg8OCwoLDg8KCw4LCuDFBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNdDF
|
||||
Bw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPD
|
||||
gsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw
|
||||
4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgs
|
||||
KCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKAdcODwoPDgsKDw4PCgsOCwqhtw4PCg8OCwoLDg8KCw4L
|
||||
ChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCsMODwoPDgsKC
|
||||
w4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCt
|
||||
sODwoPDgsKDw4PCgsOCwq7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4
|
||||
PCgsOCwoPDg8KDw4LCg8ODwoLDgsKoZsODwoPDgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4w4P
|
||||
Cg8OCwoLDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwpUzw4PCg8OCwoPDg8KCw4LCicODwoPDgsKCw4PC
|
||||
gsOCworDg8KDw4LCgsODwoLDgsKISDJBw4PCg8OCwoPDg8KCw4LCvyTDg8KDw4LCgsODwoLDgsKNN
|
||||
DJBw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwo
|
||||
PDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8O
|
||||
DwoPDgsKDw4PCgsOCwojDg8KDw4LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCnEzDg8KDw4LCgsOD
|
||||
woLDgsKLSEBmw4PCg8OCwoLDg8KCw4LCg3lwdSTDg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw
|
||||
4LCv8ODwoPDgsKCw4PCgsOCwobDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgs
|
||||
KCw4PCgsOCwp/Dg8KDw4LCgsODwoLDgsKBw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwoj
|
||||
Dg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCwpPDg8KDw4LCgsOD
|
||||
woLDgsKBw4PCg8OCwoPDg8KCw4LCv1rDg8KDw4LCgsODwoLDgsKAw4PCg8OCwoLDg8KCw4LChMODw
|
||||
oPDgsKCw4PCgsOCwodqw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwoBqaMODwoPDgsKCw4
|
||||
PCgsOCwpBQw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDIMODwoPDgsKCw4PCgsOCwopPw4PCg8OCwoL
|
||||
Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKOacODwoPDgsKCw4PCgsOCwrhf
|
||||
XsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCw
|
||||
oLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKGw4PCg8OCwoLDg8KCw4LCgM
|
||||
ODwoPDgsKCw4PCgsOCwoRJw4PCg8OCwoLDg8KCw4LCgcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsO
|
||||
DwoLDgsKIw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQ9w4PCg8OCwoLDg8KCw4LCgcOD
|
||||
woPDgsKDw4PCgsOCwr9aw4PCg8OCwoLDg8KCw4LCgMODwoPDgsKCw4PCgsOCwoQxw4PCg8OCwoLDg
|
||||
8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwoM9w4PCg8OCwoPDg8KCw4LCm0
|
||||
7Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsK
|
||||
Cw4PCgsOCwrhfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
|
||||
gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODw
|
||||
oPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgs
|
||||
OCwo7Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoLDg8KCw4LCkMODwoPDgsKDw4PCgsOCwojDg8KDw4L
|
||||
CgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsK+
|
||||
S8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKww4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKDw
|
||||
4PCgsOCwoTDg8KDw4LCgsODwoLDgsKKT1DDg8KDw4LCg8ODwoLDgsKoRsODwoPDgsKCw4PCgsOCwo
|
||||
vDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwrZ0Y8ODwoPDgsK
|
||||
Cw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK/dF/Dg8KDw4LCgsODwoLDgsKhdHpPw4PCg8OCwoLDg8KC
|
||||
w4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PCg8OCwoPDg8KCw4LCqC1Jw4PCg8OCwoLDg8KCw4LChcODw
|
||||
oPDgsKDw4PCgsOCwoB1RMODwoPDgsKCw4PCgsOCwqFwek/Dg8KDw4LCgsODwoLDgsKLw4PCg8OCwo
|
||||
PDg8KCw4LCj1DDg8KDw4LCg8ODwoLDgsKoScODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsK
|
||||
AdTPDg8KDw4LCgsODwoLDgsKhbHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo5Qw4PC
|
||||
g8OCwoPDg8KCw4LCqEnDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHXDg8KDw4LCgsODw
|
||||
oLDgsKhaHpPw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo9Qw4PCg8OCwoPDg8KCw4LCqM
|
||||
ODwoPDgsKDw4PCgsOCwrpIw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoB1M8ODwoPDgsK
|
||||
Dw4PCgsOCwoBfXsODwoPDgsKDw4PCgsOCwoLDg8KDw4LCgsODwoLDgsK4X17Dg8KDw4LCg8ODwoLD
|
||||
gsKCw4PCg8OCwoLDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgjPDg8KDw4LCg8ODwoLDgsKAX17Dg
|
||||
8KDw4LCg8ODwoLDgsKCw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo7Dg8KDw4LCg8ODwo
|
||||
LDgsKoJ8ODwoPDgsKDw4PCgsOCwq3Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODwoP
|
||||
DgsKCw4PCgsOCwoPDg8KDw4LCg8ODwoLDgsK4aHU5w4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PC
|
||||
gsOCwovDg8KDw4LCg8ODwoLDgsKOw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpDDg8KDw
|
||||
4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgs
|
||||
KIw4PCg8OCwoPDg8KCw4LCv8ODwoPDgsKCw4PCgsOCwpLDg8KDw4LCg8ODwoLDgsKEw4PCg8OCwoL
|
||||
Dg8KCw4LChcODwoPDgsKDw4PCgsOCwoB0IcODwoPDgsKCw4PCgsOCwovDg8KDw4LCgsODwoLDgsKA
|
||||
w4PCg8OCwoPDg8KCw4LCtMODwoPDgsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKAdGbDg8KDw4LCg
|
||||
sODwoLDgsKLQGY9dGY9dTPDg8KDw4LCg8ODwoLDgsKAX17Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwo
|
||||
LDg8KCw4LCuF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwrhfXsODwoPDgsKDw4PCgsO
|
||||
CwoIzw4PCg8OCwoPDg8KCw4LCgF9ew4PCg8OCwoPDg8KCw4LCgsODwoPDgsKCw4PCgsOCwovDg8KD
|
||||
w4LCg8ODwoLDgsK/Ri9BUC9BRi9BWi9BZC9BWzBBZC9BZTBBZC9BZC9BbzBBZC9BeTBBw4PCg8OCw
|
||||
oLDg8KCw4LCgzBBMUFhMUFrMUE=
|
||||
description:: UF7Dg8KDw4LCg8ODwoLDgsKCw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOC
|
||||
wozDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg
|
||||
8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCqFDDg8KDw4LCg8ODwoLDgsKpRsODwoPDgsKDw4PCgsOCwo
|
||||
zDg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKDw4PCgsOCwozDg8KDw4LCg8O
|
||||
DwoLDgsKMw4PCg8OCwoPDg8KCw4LCjMODwoPDgsKCw4PCgsOCwotEJCDDg8KDw4LCgsODwoLDgsKD
|
||||
w4PCg8OCwoPDg8KCw4LCrMODwoPDgsKCw4PCgsOCwotUJCRTw4PCg8OCwoLDg8KCw4LCi1wkJFbDg
|
||||
8KDw4LCgsODwoLDgsKJTCRXVVBSU8ODwoPDgsKDw4PCgsOCwqjDg8KDw4LCg8ODwoLDgsKdT8ODwo
|
||||
PDgsKCw4PCgsOCwoN8JDB1w4PCg8OCwoPDg8KCw4LCh8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8O
|
||||
DwoLDgsKBTsODwoPDgsKDw4PCgsOCwqktw4PCg8OCwoLDg8KCw4LCg3wkMHTDg8KDw4LCgsODwoLD
|
||||
gsKDfCQww4PCg8OCwoLDg8KCw4LChTPDg8KDw4LCg8ODwoLDgsK2OTXDg8KDw4LCg8ODwoLDgsKAw
|
||||
4PCg8OCwoPDg8KCw4LCgU7Dg8KDw4LCgsODwoLDgsKEIMODwoPDgsKCw4PCgsOCwqFIw4PCg8OCwo
|
||||
PDg8KCw4LChU7Dg8KDw4LCgsODwoLDgsKJNcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCg8ODwoLDgsK
|
||||
BTsODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsKIw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKD
|
||||
w4PCgsOCwr9TXMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw
|
||||
4LChMODwoPDgsKCw4PCgsOCwpHDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLIEjDg8
|
||||
KDw4LCg8ODwoLDgsKFTlDDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ngw4PCg8OCwoL
|
||||
Dg8KCw4LCi8ODwoPDgsKDw4PCgsOCwpjDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCm3Rx
|
||||
w4PCg8OCwoLDg8KCw4LCizvDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi8ODwoPDgsKDw
|
||||
4PCgsOCwr9XaMODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGdGLDg8KDw4LCgsODwo
|
||||
LDgsKLf2zDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCi1D
|
||||
Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8OD
|
||||
woLDgsKow4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwq10SmgoT03Dg8KDw4LCgsODwoLDg
|
||||
sKLw4PCg8OCwoPDg8KCw4LCjcODwoPDgsKDw4PCgsOCwqggTMODwoPDgsKCw4PCgsOCwoXDg8KDw4
|
||||
LCg8ODwoLDgsKAdDrDg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLTSBQUcODwoPDgsK
|
||||
Dw4PCgsOCwr/Dg8KDw4LCg8ODwoLDgsKMw4PCg8OCwoLDg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKL
|
||||
RCQoZitEJCDDg8KDw4LCgsODwoLDgsK3w4PCg8OCwoPDg8KCw4LCiMODwoPDgsKDw4PCgsOCwoHDg
|
||||
8KDw4LCg8ODwoLDgsKhw4PCg8OCwoLDg8KCw4LCi0QkJGYrRCTDg8KDw4LCgsODwoLDgsK3w4PCg8
|
||||
OCwoPDg8KCw4LCkMODwoPDgsKDw4PCgsOCworDg8KDw4LCgsODwoLDgsKLRSBRVmpQw4PCg8OCwoP
|
||||
Dg8KCw4LCv8ODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsODwoLDgsKKTzl0JHXDg8KDw4LCgsODwoLD
|
||||
gsKhOXQkw4PCg8OCwoLDg8KCw4LChW/Dg8KDw4LCg8ODwoLDgsK/w4PCg8OCwoPDg8KCw4LCv8ODw
|
||||
oPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKhRMODwoPDgsKDw4PCgsOCwoVOw4PCg8OCwoLDg8
|
||||
KCw4LCi8ODwoPDgsKDw4PCgsOCwojDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCv1Ncw4P
|
||||
Cg8OCwoLDg8KCw4LCiUQkw4PCg8OCwoLDg8KCw4LChcODwoPDgsKDw4PCgsOCwoDDg8KDw4LCgsOD
|
||||
woLDgsKEw4PCg8OCwoPDg8KCw4LCtjPDg8KDw4LCg8ODwoLDgsK2w4PCg8OCwoLDg8KCw4LCjUQkw
|
||||
4PCg8OCwoLDg8KCw4LCiyBEw4PCg8OCwoPDg8KCw4LChU5Qw4PCg8OCwoLDg8KCw4LCi8ODwoPDgs
|
||||
KDw4PCgsOCwr9TYMODwoPDgsKCw4PCgsOCwovDg8KDw4LCg8ODwoLDgsK4w4PCg8OCwoLDg8KCw4L
|
||||
ChcODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKEw4PCg8OCwoPDg8KCw4LCkMODwoPDgsKC
|
||||
w4PCgsOCwovDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCj8ODwoPDgsKDw4PCgsOCwr9Ta
|
||||
MODwoPDgsKCw4PCgsOCwolEJDvDg8KDw4LCg8ODwoLDgsKGw4PCg8OCwoLDg8KCw4LChMODwoPDgs
|
||||
KCw4PCgsOCwr3Dg8KDw4LCgsODwoLDgsKNRCTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4L
|
||||
Cj1DDg8KDw4LCg8ODwoLDgsK/U2zDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoPDg8KCw4LCqMODwoPD
|
||||
gsKCw4PCgsOCwoXDg8KDw4LCg8ODwoLDgsKtw4PCg8OCwoLDg8KCw4LChMODwoPDgsKCw4PCgsOCw
|
||||
p9oMMODwoPDgsKDw4PCgsOCwolMw4PCg8OCwoLDg8KCw4LCi8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4
|
||||
LCg8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCq0vDg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4L
|
||||
CgMODwoPDgsKCw4PCgsOCwoTDg8KDw4LCgsODwoLDgsKLw4PCg8OCwoLDg8KCw4LCi0QkOcODwoPD
|
||||
gsKCw4PCgsOCwrDDg8KDw4LCg8ODwoLDgsKEdEU5w4PCg8OCwoLDg8KCw4LCtTR0PcODwoPDgsKCw
|
||||
4PCgsOCwovDg8KDw4LCg8ODwoLDgsKNw4PCg8OCwoPDg8KCw4LCqMODwoPDgsKDw4PCgsOCwo5Lw4
|
||||
PCg8OCwoLDg8KCw4LCi0AgUMODwoPDgsKDw4PCgsOCwr/Dg8KDw4LCgsODwoLDgsKsw4PCg8OCwoL
|
||||
Dg8KCw4LCik/Dg8KDw4LCgsODwoLDgsKFw4PCg8OCwoPDg8KCw4LCgHUow4PCg8OCwoLDg8KCw4LC
|
||||
i8ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCgsODwoLDgsKJw4PCg8OCwoLDg8KCw4LCtTTDg8KDw4LCg
|
||||
8ODwoLDgsKow4PCg8OCwoPDg8KCw4LCl8ODwoPDgsKDw4PCgsOCwrtWw4PCg8OCwoLDg8KCw4LCi8
|
||||
ODwoPDgsKDw4PCgsOCwo3Dg8KDw4LCg8ODwoLDgsKow4PCg8OCwoLDg8KCw4LCnw==
|
||||
|
||||
#LEAD COMMENT
|
||||
|
||||
# another comment
|
||||
dn: CN=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
#EMBEDDED COMMENT
|
||||
member: cn=Manager,o=University of Michigan,c=US
|
||||
member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Unive
|
||||
rsity of Michigan,c=US
|
||||
member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
|
||||
=US
|
||||
member: cn=John Doe,ou=Information Technology Division,ou=People,o=University
|
||||
of Michigan,c=US
|
||||
member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
|
||||
n,c=US
|
||||
member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
member: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Univ
|
||||
ersity of Michigan,c=US
|
||||
member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
|
||||
igan,c=US
|
||||
member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=Univers
|
||||
ity of Michigan,c=US
|
||||
owner: cn=Manager,o=University of Michigan,c=US
|
||||
cn: All Staff
|
||||
description: Everyone in the sample data
|
||||
objectclass: groupofnames
|
||||
|
||||
dn: cn=Alumni Assoc Staff,ou=Groups,o=University of Michigan,c=US
|
||||
member: cn=Manager,o=University of Michigan,c=US
|
||||
member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
member: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
member: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c
|
||||
=US
|
||||
member: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Mich
|
||||
igan,c=US
|
||||
member: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michiga
|
||||
n,c=US
|
||||
member: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Mic
|
||||
higan,c=US
|
||||
owner: cn=Manager,o=University of Michigan,c=US
|
||||
description: All Alumni Assoc Staff
|
||||
cn: Alumni Assoc Staff
|
||||
objectclass: groupofnames
|
||||
|
||||
dn: ou=Alumni Association,ou=People,o=University of Michigan,c=US
|
||||
objectclass: organizationalUnit
|
||||
ou: Alumni Association
|
||||
|
||||
dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,o=Universit
|
||||
y of Michigan,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Barbara Jensen
|
||||
cn: Babs Jensen
|
||||
sn:: IEplbnNlbiA=
|
||||
uid: bjensen
|
||||
title: Mythical Manager, Research Systems
|
||||
postaladdress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Ann
|
||||
Arbor, MI 48103-4943
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
userpassword:: YmplbnNlbg==
|
||||
mail: bjensen@mailgw.example.com
|
||||
homepostaladdress: 123 Wesley $ Ann Arbor, MI 48103
|
||||
description: Mythical manager of the rsdd unix project
|
||||
drink: water
|
||||
homephone: +1 313 555 2333
|
||||
pager: +1 313 555 3233
|
||||
facsimiletelephonenumber: +1 313 555 2274
|
||||
telephonenumber: +1 313 555 9022
|
||||
|
||||
dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=University
|
||||
of Michigan,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Bjorn Jensen
|
||||
cn: Biiff Jensen
|
||||
sn: Jensen
|
||||
uid: bjorn
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
userpassword:: Ympvcm4=
|
||||
homepostaladdress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
|
||||
drink: Iced Tea
|
||||
description: Hiker, biker
|
||||
title: Director, Embedded Systems
|
||||
postaladdress: Info Tech Division $ 535 W. William St. $ Ann Arbor, MI 48103
|
||||
mail: bjorn@mailgw.example.com
|
||||
homephone: +1 313 555 5444
|
||||
pager: +1 313 555 4474
|
||||
facsimiletelephonenumber: +1 313 555 2177
|
||||
telephonenumber: +1 313 555 0355
|
||||
|
||||
dn: cn=Dorothy Stevens,ou=Alumni Association,ou=People,o=University of Michiga
|
||||
n,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Dorothy Stevens
|
||||
cn: Dot Stevens
|
||||
sn: Stevens
|
||||
uid: dots
|
||||
title: Secretary, UM Alumni Association
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
drink: Lemonade
|
||||
homepostaladdress: 377 White St. Apt. 3 $ Ann Arbor, MI 48104
|
||||
description: Very tall
|
||||
facsimiletelephonenumber: +1 313 555 3223
|
||||
telephonenumber: +1 313 555 3664
|
||||
mail: dots@mail.alumni.example.com
|
||||
homephone: +1 313 555 0454
|
||||
|
||||
dn: cn=ITD Staff,ou=Groups,o=University of Michigan,c=US
|
||||
owner: cn=Manager,o=University of Michigan,c=US
|
||||
description: All ITD Staff
|
||||
cn: ITD Staff
|
||||
objectclass: groupofuniquenames
|
||||
uniquemember: cn=Manager,o=University of Michigan,c=US
|
||||
uniquemember: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,o=U
|
||||
niversity of Michigan,c=US
|
||||
uniquemember: cn=James A Jones 2,ou=Information Technology Division,ou=People,
|
||||
o=University of Michigan,c=US
|
||||
uniquemember: cn=John Doe,ou=Information Technology Division,ou=People,o=Unive
|
||||
rsity of Michigan,c=US
|
||||
|
||||
dn: cn=James A Jones 1,ou=Alumni Association,ou=People,o=University of Michiga
|
||||
n,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: James A Jones 1
|
||||
cn: James Jones
|
||||
cn: Jim Jones
|
||||
sn: Jones
|
||||
uid: jaj
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
userpassword:: amFq
|
||||
homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105
|
||||
homephone: +1 313 555 4772
|
||||
description: Outstanding
|
||||
title: Mad Cow Researcher, UM Alumni Association
|
||||
pager: +1 313 555 3923
|
||||
mail: jaj@mail.alumni.example.com
|
||||
facsimiletelephonenumber: +1 313 555 4332
|
||||
telephonenumber: +1 313 555 0895
|
||||
|
||||
dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,o=Universi
|
||||
ty of Michigan,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: James A Jones 2
|
||||
cn: James Jones
|
||||
cn: Jim Jones
|
||||
sn: Doe
|
||||
uid: jjones
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
homepostaladdress: 933 Brooks $ Ann Arbor, MI 48104
|
||||
homephone: +1 313 555 8838
|
||||
title: Senior Manager, Information Technology Division
|
||||
description: Not around very much
|
||||
mail: jjones@mailgw.example.com
|
||||
postaladdress: Info Tech Division $ 535 W William $ Ann Arbor, MI 48103
|
||||
pager: +1 313 555 2833
|
||||
facsimiletelephonenumber: +1 313 555 8688
|
||||
telephonenumber: +1 313 555 7334
|
||||
|
||||
dn: cn=Jane Doe,ou=Alumni Association,ou=People,o=University of Michigan,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Jane Doe
|
||||
cn: Jane Alverson
|
||||
sn: Doe
|
||||
uid: jdoe
|
||||
title: Programmer Analyst, UM Alumni Association
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
|
||||
drink: diet coke
|
||||
description: Enthusiastic
|
||||
mail: jdoe@woof.net
|
||||
homephone: +1 313 555 5445
|
||||
pager: +1 313 555 1220
|
||||
facsimiletelephonenumber: +1 313 555 2311
|
||||
telephonenumber: +1 313 555 4774
|
||||
|
||||
dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,o=University of Michigan
|
||||
,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Jennifer Smith
|
||||
cn: Jen Smith
|
||||
sn: Smith
|
||||
uid: jen
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
drink: Sam Adams
|
||||
homepostaladdress: 1000 Maple #44 $ Ann Arbor, MI 48103
|
||||
title: Telemarketer, UM Alumni Association
|
||||
mail: jen@mail.alumni.example.com
|
||||
homephone: +1 313 555 2333
|
||||
pager: +1 313 555 6442
|
||||
facsimiletelephonenumber: +1 313 555 2756
|
||||
telephonenumber: +1 313 555 8232
|
||||
|
||||
dn: cn=John Doe,ou=Information Technology Division,ou=People,o=University of M
|
||||
ichigan,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: John Doe
|
||||
cn: Jonathon Doe
|
||||
sn: Doe
|
||||
uid: johnd
|
||||
postaladdress: ITD $ 535 W. William $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
homepostaladdress: 912 East Bllvd $ Ann Arbor, MI 48104
|
||||
title: System Administrator, Information Technology Division
|
||||
description: overworked!
|
||||
mail: johnd@mailgw.example.com
|
||||
homephone: +1 313 555 3774
|
||||
pager: +1 313 555 6573
|
||||
facsimiletelephonenumber: +1 313 555 4544
|
||||
telephonenumber: +1 313 555 9394
|
||||
|
||||
dn: cn=Manager,o=University of Michigan,c=US
|
||||
objectclass: person
|
||||
cn: Manager
|
||||
cn: Directory Manager
|
||||
cn: Dir Man
|
||||
sn: Manager
|
||||
description: Manager of the directory
|
||||
userpassword:: c2VjcmV0
|
||||
|
||||
dn: cn=Mark Elliot,ou=Alumni Association,ou=People,o=University of Michigan,c=
|
||||
US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Mark Elliot
|
||||
cn: Mark A Elliot
|
||||
sn: Elliot
|
||||
uid: melliot
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
homepostaladdress: 199 Outer Drive $ Ypsilanti, MI 48198
|
||||
homephone: +1 313 555 0388
|
||||
drink: Gasoline
|
||||
title: Director, UM Alumni Association
|
||||
mail: melliot@mail.alumni.example.com
|
||||
pager: +1 313 555 7671
|
||||
facsimiletelephonenumber: +1 313 555 7762
|
||||
telephonenumber: +1 313 555 4177
|
||||
|
||||
dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,o=University of Michiga
|
||||
n,c=US
|
||||
objectclass: OpenLDAPperson
|
||||
cn: Ursula Hampster
|
||||
sn: Hampster
|
||||
uid: uham
|
||||
title: Secretary, UM Alumni Association
|
||||
postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109
|
||||
seealso: cn=All Staff,ou=Groups,o=University of Michigan,c=US
|
||||
homepostaladdress: 123 Anystreet $ Ann Arbor, MI 48104
|
||||
mail: uham@mail.alumni.example.com
|
||||
homephone: +1 313 555 8421
|
||||
pager: +1 313 555 2844
|
||||
facsimiletelephonenumber: +1 313 555 9700
|
||||
telephonenumber: +1 313 555 5331
|
||||
|
8
source4/lib/ldb/tests/testdata.txt
Normal file
8
source4/lib/ldb/tests/testdata.txt
Normal file
@ -0,0 +1,8 @@
|
||||
foo=bar5
|
||||
(&(|(a=b)(c=d))(e=f))
|
||||
(&(|(a=b)(c=d)(g=h))(e=f))
|
||||
name=firstname lastname
|
||||
(&(sid=S-1-2-3)(name = fred bloggs))
|
||||
(&(|(a=b)(c=d))(g=f))
|
||||
(&(sid=S-1-2-3)(!(name = fred bloggs)))
|
||||
(&(!(|(a=b)(c=d))(g=f)))
|
5
source4/lib/ldb/tests/testsearch.txt
Normal file
5
source4/lib/ldb/tests/testsearch.txt
Normal file
@ -0,0 +1,5 @@
|
||||
(blah=foo)
|
||||
(objectclass=person)
|
||||
(dn=*)
|
||||
(&(objectclass=person)(objectclass=person))
|
||||
(&(objectclass=person)(objectclass=personx))
|
74
source4/lib/ldb/tools/ldbadd.c
Normal file
74
source4/lib/ldb/tools/ldbadd.c
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
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: ldbadd
|
||||
*
|
||||
* Description: utility to add records - modelled on ldapadd
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
struct ldb_message *msg;
|
||||
int ret;
|
||||
int count=0, failures=0;
|
||||
const char *ldb_url;
|
||||
|
||||
ldb_url = getenv("LDB_URL");
|
||||
if (!ldb_url) {
|
||||
ldb_url = "tdb://test.ldb";
|
||||
}
|
||||
|
||||
ldb = ldb_connect(ldb_url, 0, NULL);
|
||||
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((msg = ldif_read_file(stdin))) {
|
||||
ret = ldb_add(ldb, msg);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "ERR: \"%s\" on DN %s\n",
|
||||
ldb_errstring(ldb), msg->dn);
|
||||
failures++;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
ldif_read_free(msg);
|
||||
}
|
||||
|
||||
ldb_close(ldb);
|
||||
|
||||
printf("Added %d records with %d failures\n", count, failures);
|
||||
|
||||
return 0;
|
||||
}
|
69
source4/lib/ldb/tools/ldbdel.c
Normal file
69
source4/lib/ldb/tools/ldbdel.c
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
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: ldbdel
|
||||
*
|
||||
* Description: utility to delete records - modelled on ldapdelete
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
int ret, i;
|
||||
const char *ldb_url;
|
||||
|
||||
ldb_url = getenv("LDB_URL");
|
||||
if (!ldb_url) {
|
||||
ldb_url = "tdb://test.ldb";
|
||||
}
|
||||
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: ldbdel <dn...>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ldb = ldb_connect(ldb_url, 0, NULL);
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=1;i<argc;i++) {
|
||||
ret = ldb_delete(ldb, argv[i]);
|
||||
if (ret != 0) {
|
||||
printf("delete of '%s' failed\n", argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ldb_close(ldb);
|
||||
return 0;
|
||||
}
|
122
source4/lib/ldb/tools/ldbsearch.c
Normal file
122
source4/lib/ldb/tools/ldbsearch.c
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
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: ldbsearch
|
||||
*
|
||||
* Description: utility for ldb search - modelled on ldapsearch
|
||||
*
|
||||
* Author: Andrew Tridgell
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <getopt.h>
|
||||
|
||||
int main(int argc, char * const argv[])
|
||||
{
|
||||
static struct ldb_context *ldb;
|
||||
struct ldb_message **msgs;
|
||||
int ret, i;
|
||||
const char *expression;
|
||||
const char * const *attrs = NULL;
|
||||
const char *ldb_url;
|
||||
const char *basedn = NULL;
|
||||
int opt;
|
||||
enum ldb_scope scope = LDB_SCOPE_DEFAULT;
|
||||
|
||||
ldb_url = getenv("LDB_URL");
|
||||
if (!ldb_url) {
|
||||
ldb_url = "tdb://test.ldb";
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "b:H:s:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
basedn = optarg;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
ldb_url = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (strcmp(optarg, "base") == 0) {
|
||||
scope = LDB_SCOPE_BASE;
|
||||
} else if (strcmp(optarg, "sub") == 0) {
|
||||
scope = LDB_SCOPE_SUBTREE;
|
||||
} else if (strcmp(optarg, "one") == 0) {
|
||||
scope = LDB_SCOPE_ONELEVEL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
printf("Usage: ldbsearch <expression> [attrs...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
attrs = argv+1;
|
||||
}
|
||||
|
||||
expression = argv[0];
|
||||
|
||||
ldb = ldb_connect(ldb_url, 0, NULL);
|
||||
|
||||
if (!ldb) {
|
||||
perror("ldb_connect");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = ldb_search(ldb, basedn, scope, expression, attrs, &msgs);
|
||||
|
||||
if (ret == -1) {
|
||||
printf("search failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("# returned %d records\n", ret);
|
||||
|
||||
for (i=0;i<ret;i++) {
|
||||
printf("# record %d\n", i+1);
|
||||
ldif_write_file(stdout, msgs[i]);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
ret = ldb_search_free(ldb, msgs);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "search_free failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ldb_close(ldb);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user