wmi-1.3.16 from opsview.com

This commit is contained in:
Are Casilla
2019-02-16 00:16:52 +01:00
parent 163fdd3d1b
commit 17b3af2911
2146 changed files with 678824 additions and 0 deletions
@@ -0,0 +1,407 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
** 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
*/
/*
attribute handlers for well known attribute types, selected by syntax OID
see rfc2252
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
#include "ldb/include/ldb_handlers.h"
/*
default handler that just copies a ldb_val.
*/
int ldb_handler_copy(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
*out = ldb_val_dup(mem_ctx, in);
if (in->length > 0 && out->data == NULL) {
ldb_oom(ldb);
return -1;
}
return 0;
}
/*
a case folding copy handler, removing leading and trailing spaces and
multiple internal spaces
We exploit the fact that utf8 never uses the space octet except for
the space itself
*/
int ldb_handler_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
char *s, *t;
int l;
if (!in || !out || !(in->data)) {
return -1;
}
out->data = (uint8_t *)ldb_casefold(ldb, mem_ctx, (const char *)(in->data));
if (out->data == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb_handler_fold: unable to casefold string [%s]", in->data);
return -1;
}
s = (char *)(out->data);
/* remove trailing spaces if any */
l = strlen(s);
while (l > 0 && s[l - 1] == ' ') l--;
s[l] = '\0';
/* remove leading spaces if any */
if (*s == ' ') {
for (t = s; *s == ' '; s++) ;
/* remove leading spaces by moving down the string */
memmove(t, s, l);
s = t;
}
/* check middle spaces */
while ((t = strchr(s, ' ')) != NULL) {
for (s = t; *s == ' '; s++) ;
if ((s - t) > 1) {
l = strlen(s);
/* remove all spaces but one by moving down the string */
memmove(t + 1, s, l);
}
}
out->length = strlen((char *)out->data);
return 0;
}
/*
canonicalise a ldap Integer
rfc2252 specifies it should be in decimal form
*/
int ldb_canonicalise_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
char *end;
long long i = strtoll((char *)in->data, &end, 0);
if (*end != 0) {
return -1;
}
out->data = (uint8_t *)talloc_asprintf(mem_ctx, "%lld", i);
if (out->data == NULL) {
return -1;
}
out->length = strlen((char *)out->data);
return 0;
}
/*
compare two Integers
*/
int ldb_comparison_Integer(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
return strtoll((char *)v1->data, NULL, 0) - strtoll((char *)v2->data, NULL, 0);
}
/*
compare two binary blobs
*/
int ldb_comparison_binary(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
if (v1->length != v2->length) {
return v1->length - v2->length;
}
return memcmp(v1->data, v2->data, v1->length);
}
/*
compare two case insensitive strings, ignoring multiple whitespaces
and leading and trailing whitespaces
see rfc2252 section 8.1
try to optimize for the ascii case,
but if we find out an utf8 codepoint revert to slower but correct function
*/
int ldb_comparison_fold(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
const char *s1=(const char *)v1->data, *s2=(const char *)v2->data;
const char *u1, *u2;
char *b1, *b2;
int ret;
while (*s1 == ' ') s1++;
while (*s2 == ' ') s2++;
/* TODO: make utf8 safe, possibly with helper function from application */
while (*s1 && *s2) {
/* the first 127 (0x7F) chars are ascii and utf8 guarantes they
* never appear in multibyte sequences */
if (((unsigned char)s1[0]) & 0x80) goto utf8str;
if (((unsigned char)s2[0]) & 0x80) goto utf8str;
if (toupper((unsigned char)*s1) != toupper((unsigned char)*s2))
break;
if (*s1 == ' ') {
while (s1[0] == s1[1]) s1++;
while (s2[0] == s2[1]) s2++;
}
s1++; s2++;
}
if (! (*s1 && *s2)) {
/* check for trailing spaces only if one of the pointers
* has reached the end of the strings otherwise we
* can mistakenly match.
* ex. "domain users" <-> "domainUpdates"
*/
while (*s1 == ' ') s1++;
while (*s2 == ' ') s2++;
}
return (int)(toupper(*s1)) - (int)(toupper(*s2));
utf8str:
/* no need to recheck from the start, just from the first utf8 char found */
b1 = ldb_casefold(ldb, mem_ctx, s1);
b2 = ldb_casefold(ldb, mem_ctx, s2);
if (b1 && b2) {
/* Both strings converted correctly */
u1 = b1;
u2 = b2;
} else {
/* One of the strings was not UTF8, so we have no options but to do a binary compare */
u1 = s1;
u2 = s2;
}
while (*u1 & *u2) {
if (*u1 != *u2)
break;
if (*u1 == ' ') {
while (u1[0] == u1[1]) u1++;
while (u2[0] == u2[1]) u2++;
}
u1++; u2++;
}
if (! (*u1 && *u2)) {
while (*u1 == ' ') u1++;
while (*u2 == ' ') u2++;
}
ret = (int)(*u1 - *u2);
talloc_free(b1);
talloc_free(b2);
return ret;
}
/*
canonicalise a attribute in DN format
*/
int ldb_canonicalise_dn(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
struct ldb_dn *dn;
int ret = -1;
out->length = 0;
out->data = NULL;
dn = ldb_dn_new(ldb, mem_ctx, (char *)in->data);
if ( ! ldb_dn_validate(dn)) {
return LDB_ERR_INVALID_DN_SYNTAX;
}
out->data = (uint8_t *)ldb_dn_alloc_casefold(mem_ctx, dn);
if (out->data == NULL) {
goto done;
}
out->length = strlen((char *)out->data);
ret = 0;
done:
talloc_free(dn);
return ret;
}
/*
compare two dns
*/
int ldb_comparison_dn(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
struct ldb_dn *dn1 = NULL, *dn2 = NULL;
int ret;
dn1 = ldb_dn_new(ldb, mem_ctx, (char *)v1->data);
if ( ! ldb_dn_validate(dn1)) return -1;
dn2 = ldb_dn_new(ldb, mem_ctx, (char *)v2->data);
if ( ! ldb_dn_validate(dn2)) {
talloc_free(dn1);
return -1;
}
ret = ldb_dn_compare(dn1, dn2);
talloc_free(dn1);
talloc_free(dn2);
return ret;
}
/*
compare two objectclasses, looking at subclasses
*/
int ldb_comparison_objectclass(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
int ret, i;
const char **subclasses;
ret = ldb_comparison_fold(ldb, mem_ctx, v1, v2);
if (ret == 0) {
return 0;
}
subclasses = ldb_subclass_list(ldb, (char *)v1->data);
if (subclasses == NULL) {
return ret;
}
for (i=0;subclasses[i];i++) {
struct ldb_val vs;
vs.data = discard_const(subclasses[i]);
vs.length = strlen(subclasses[i]);
if (ldb_comparison_objectclass(ldb, mem_ctx, &vs, v2) == 0) {
return 0;
}
}
return ret;
}
/*
compare two utc time values. 1 second resolution
*/
int ldb_comparison_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *v1, const struct ldb_val *v2)
{
time_t t1, t2;
t1 = ldb_string_to_time((char *)v1->data);
t2 = ldb_string_to_time((char *)v2->data);
return (int)t2 - (int)t1;
}
/*
canonicalise a utc time
*/
int ldb_canonicalise_utctime(struct ldb_context *ldb, void *mem_ctx,
const struct ldb_val *in, struct ldb_val *out)
{
time_t t = ldb_string_to_time((char *)in->data);
out->data = (uint8_t *)ldb_timestring(mem_ctx, t);
if (out->data == NULL) {
return -1;
}
out->length = strlen((char *)out->data);
return 0;
}
/*
table of standard attribute handlers
*/
static const struct ldb_attrib_handler ldb_standard_attribs[] = {
{
.attr = LDB_SYNTAX_INTEGER,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_Integer,
.comparison_fn = ldb_comparison_Integer
},
{
.attr = LDB_SYNTAX_OCTET_STRING,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_copy,
.comparison_fn = ldb_comparison_binary
},
{
.attr = LDB_SYNTAX_DIRECTORY_STRING,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_fold,
.comparison_fn = ldb_comparison_fold
},
{
.attr = LDB_SYNTAX_DN,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_dn,
.comparison_fn = ldb_comparison_dn
},
{
.attr = LDB_SYNTAX_OBJECTCLASS,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_fold,
.comparison_fn = ldb_comparison_objectclass
},
{
.attr = LDB_SYNTAX_UTC_TIME,
.flags = 0,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_canonicalise_utctime,
.comparison_fn = ldb_comparison_utctime
}
};
/*
return the attribute handlers for a given syntax name
*/
const struct ldb_attrib_handler *ldb_attrib_handler_syntax(struct ldb_context *ldb,
const char *syntax)
{
int i;
unsigned num_handlers = sizeof(ldb_standard_attribs)/sizeof(ldb_standard_attribs[0]);
/* TODO: should be replaced with a binary search */
for (i=0;i<num_handlers;i++) {
if (strcmp(ldb_standard_attribs[i].attr, syntax) == 0) {
return &ldb_standard_attribs[i];
}
}
return NULL;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,300 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2005
** 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
*/
/*
register handlers for specific attributes and objectclass relationships
this allows a backend to store its schema information in any format
it likes (or to not have any schema information at all) while keeping the
message matching logic generic
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
add to the list of ldif handlers for this ldb context
*/
int ldb_set_attrib_handlers(struct ldb_context *ldb,
const struct ldb_attrib_handler *handlers,
unsigned num_handlers)
{
int i, j, n;
struct ldb_attrib_handler *h;
n = ldb->schema.num_attrib_handlers + num_handlers;
h = talloc_realloc(ldb, ldb->schema.attrib_handlers,
struct ldb_attrib_handler, n);
if (h == NULL) {
ldb_oom(ldb);
return -1;
}
ldb->schema.attrib_handlers = h;
for (i = 0; i < num_handlers; i++) {
for (j = 0; j < ldb->schema.num_attrib_handlers; j++) {
if (ldb_attr_cmp(handlers[i].attr, h[j].attr) < 0) {
memmove(h+j+1, h+j, sizeof(*h) * (ldb->schema.num_attrib_handlers-j));
break;
}
}
h[j] = handlers[i];
if (h[j].flags & LDB_ATTR_FLAG_ALLOCATED) {
h[j].attr = talloc_strdup(h, h[j].attr);
if (h[j].attr == NULL) {
ldb_oom(ldb);
return -1;
}
}
ldb->schema.num_attrib_handlers++;
}
return 0;
}
/*
default handler function pointers
*/
static const struct ldb_attrib_handler ldb_default_attrib_handler = {
.attr = NULL,
.ldif_read_fn = ldb_handler_copy,
.ldif_write_fn = ldb_handler_copy,
.canonicalise_fn = ldb_handler_copy,
.comparison_fn = ldb_comparison_binary,
};
/*
return the attribute handlers for a given attribute
*/
const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb,
const char *attrib)
{
int i, e, b = 0, r;
const struct ldb_attrib_handler *def = &ldb_default_attrib_handler;
/* as handlers are sorted, '*' must be the first if present */
if (strcmp(ldb->schema.attrib_handlers[0].attr, "*") == 0) {
def = &ldb->schema.attrib_handlers[0];
b = 1;
}
/* do a binary search on the array */
e = ldb->schema.num_attrib_handlers - 1;
while (b <= e) {
i = (b + e) / 2;
r = ldb_attr_cmp(attrib, ldb->schema.attrib_handlers[i].attr);
if (r == 0) {
return &ldb->schema.attrib_handlers[i];
}
if (r < 0) {
e = i - 1;
} else {
b = i + 1;
}
}
return def;
}
/*
add to the list of ldif handlers for this ldb context
*/
void ldb_remove_attrib_handler(struct ldb_context *ldb, const char *attrib)
{
const struct ldb_attrib_handler *h;
int i;
h = ldb_attrib_handler(ldb, attrib);
if (h == &ldb_default_attrib_handler) {
return;
}
if (h->flags & LDB_ATTR_FLAG_ALLOCATED) {
talloc_free(discard_const_p(char, h->attr));
}
i = h - ldb->schema.attrib_handlers;
if (i < ldb->schema.num_attrib_handlers - 1) {
memmove(&ldb->schema.attrib_handlers[i],
h+1, sizeof(*h) * (ldb->schema.num_attrib_handlers-(i+1)));
}
ldb->schema.num_attrib_handlers--;
}
/*
setup a attribute handler using a standard syntax
*/
int ldb_set_attrib_handler_syntax(struct ldb_context *ldb,
const char *attr, const char *syntax)
{
const struct ldb_attrib_handler *h = ldb_attrib_handler_syntax(ldb, syntax);
struct ldb_attrib_handler h2;
if (h == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Unknown syntax '%s'\n", syntax);
return -1;
}
h2 = *h;
h2.attr = attr;
return ldb_set_attrib_handlers(ldb, &h2, 1);
}
/*
setup the attribute handles for well known attributes
*/
int ldb_setup_wellknown_attributes(struct ldb_context *ldb)
{
const struct {
const char *attr;
const char *syntax;
} wellknown[] = {
{ "dn", LDB_SYNTAX_DN },
{ "distinguishedName", LDB_SYNTAX_DN },
{ "cn", LDB_SYNTAX_DIRECTORY_STRING },
{ "dc", LDB_SYNTAX_DIRECTORY_STRING },
{ "ou", LDB_SYNTAX_DIRECTORY_STRING },
{ "objectClass", LDB_SYNTAX_OBJECTCLASS }
};
int i;
for (i=0;i<ARRAY_SIZE(wellknown);i++) {
if (ldb_set_attrib_handler_syntax(ldb, wellknown[i].attr,
wellknown[i].syntax) != 0) {
return -1;
}
}
return 0;
}
/*
return the list of subclasses for a class
*/
const char **ldb_subclass_list(struct ldb_context *ldb, const char *classname)
{
int i;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
return (const char **)ldb->schema.classes[i].subclasses;
}
}
return NULL;
}
/*
add a new subclass
*/
static int ldb_subclass_new(struct ldb_context *ldb, const char *classname, const char *subclass)
{
struct ldb_subclass *s, *c;
s = talloc_realloc(ldb, ldb->schema.classes, struct ldb_subclass, ldb->schema.num_classes+1);
if (s == NULL) goto failed;
ldb->schema.classes = s;
c = &s[ldb->schema.num_classes];
c->name = talloc_strdup(s, classname);
if (c->name == NULL) goto failed;
c->subclasses = talloc_array(s, char *, 2);
if (c->subclasses == NULL) goto failed;
c->subclasses[0] = talloc_strdup(c->subclasses, subclass);
if (c->subclasses[0] == NULL) goto failed;
c->subclasses[1] = NULL;
ldb->schema.num_classes++;
return 0;
failed:
ldb_oom(ldb);
return -1;
}
/*
add a subclass
*/
int ldb_subclass_add(struct ldb_context *ldb, const char *classname, const char *subclass)
{
int i, n;
struct ldb_subclass *c;
char **s;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
break;
}
}
if (i == ldb->schema.num_classes) {
return ldb_subclass_new(ldb, classname, subclass);
}
c = &ldb->schema.classes[i];
for (n=0;c->subclasses[n];n++) /* noop */;
s = talloc_realloc(ldb->schema.classes, c->subclasses, char *, n+2);
if (s == NULL) {
ldb_oom(ldb);
return -1;
}
c->subclasses = s;
s[n] = talloc_strdup(s, subclass);
if (s[n] == NULL) {
ldb_oom(ldb);
return -1;
}
s[n+1] = NULL;
return 0;
}
/*
remove a set of subclasses for a class
*/
void ldb_subclass_remove(struct ldb_context *ldb, const char *classname)
{
int i;
struct ldb_subclass *c;
for (i=0;i<ldb->schema.num_classes;i++) {
if (ldb_attr_cmp(classname, ldb->schema.classes[i].name) == 0) {
break;
}
}
if (i == ldb->schema.num_classes) {
return;
}
c = &ldb->schema.classes[i];
talloc_free(c->name);
talloc_free(c->subclasses);
if (ldb->schema.num_classes-(i+1) > 0) {
memmove(c, c+1, sizeof(*c) * (ldb->schema.num_classes-(i+1)));
}
ldb->schema.num_classes--;
if (ldb->schema.num_classes == 0) {
talloc_free(ldb->schema.classes);
ldb->schema.classes = NULL;
}
}
+106
View File
@@ -0,0 +1,106 @@
/*
ldb database library
Copyright (C) Simo Sorce 2005
** 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_controls.c
*
* Component: ldb controls utility functions
*
* Description: helper functions for control modules
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
/* check if a control with the specified "oid" exist and return it */
/* returns NULL if not found */
struct ldb_control *get_control_from_list(struct ldb_control **controls, const char *oid)
{
int i;
/* check if there's a paged request control */
if (controls != NULL) {
for (i = 0; controls[i]; i++) {
if (strcmp(oid, controls[i]->oid) == 0) {
break;
}
}
return controls[i];
}
return NULL;
}
/* saves the current controls list into the "saver" and replace the one in req with a new one excluding
the "exclude" control */
/* returns False on error */
int save_controls(struct ldb_control *exclude, struct ldb_request *req, struct ldb_control ***saver)
{
struct ldb_control **lcs;
int i, j;
*saver = req->controls;
for (i = 0; req->controls[i]; i++);
if (i == 1) {
req->controls = NULL;
return 1;
}
lcs = talloc_array(req, struct ldb_control *, i);
if (!lcs) {
return 0;
}
for (i = 0, j = 0; (*saver)[i]; i++) {
if (exclude == (*saver)[i]) continue;
lcs[j] = (*saver)[i];
j++;
}
lcs[j] = NULL;
req->controls = lcs;
return 1;
}
/* check if there's any control marked as critical in the list */
/* return True if any, False if none */
int check_critical_controls(struct ldb_control **controls)
{
int i;
if (controls == NULL) {
return 0;
}
for (i = 0; controls[i]; i++) {
if (controls[i]->critical) {
return 1;
}
}
return 0;
}
+105
View File
@@ -0,0 +1,105 @@
/*
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 debug
*
* Description: functions for printing debug messages
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
this allows the user to choose their own debug function
*/
int ldb_set_debug(struct ldb_context *ldb,
void (*debug)(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap),
void *context)
{
ldb->debug_ops.debug = debug;
ldb->debug_ops.context = context;
return 0;
}
/*
debug function for ldb_set_debug_stderr
*/
static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
static void ldb_debug_stderr(void *context, enum ldb_debug_level level,
const char *fmt, va_list ap)
{
if (level <= LDB_DEBUG_WARNING) {
vfprintf(stderr, fmt, ap);
}
}
/*
convenience function to setup debug messages on stderr
messages of level LDB_DEBUG_WARNING and higher are printed
*/
int ldb_set_debug_stderr(struct ldb_context *ldb)
{
return ldb_set_debug(ldb, ldb_debug_stderr, ldb);
}
/*
log a message
*/
void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...)
{
va_list ap;
if (ldb->debug_ops.debug == NULL) {
ldb_set_debug_stderr(ldb);
}
va_start(ap, fmt);
ldb->debug_ops.debug(ldb->debug_ops.context, level, fmt, ap);
va_end(ap);
}
/*
log a message, and set the ldb error string to the same message
*/
void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level,
const char *fmt, ...)
{
va_list ap;
char *msg;
va_start(ap, fmt);
msg = talloc_vasprintf(ldb, fmt, ap);
va_end(ap);
if (msg != NULL) {
ldb_set_errstring(ldb, msg);
ldb_debug(ldb, level, "%s", msg);
}
talloc_free(msg);
}
File diff suppressed because it is too large Load Diff
+761
View File
@@ -0,0 +1,761 @@
/*
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
*/
/*
see RFC2849 for the LDIF format definition
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
/*
*/
static int ldb_read_data_file(void *mem_ctx, struct ldb_val *value)
{
struct stat statbuf;
char *buf;
int count, size, bytes;
int ret;
int f;
const char *fname = (const char *)value->data;
if (strncmp(fname, "file://", 7) != 0) {
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
fname += 7;
f = open(fname, O_RDONLY);
if (f == -1) {
return -1;
}
if (fstat(f, &statbuf) != 0) {
ret = -1;
goto done;
}
if (statbuf.st_size == 0) {
ret = -1;
goto done;
}
value->data = (uint8_t *)talloc_size(mem_ctx, statbuf.st_size + 1);
if (value->data == NULL) {
ret = -1;
goto done;
}
value->data[statbuf.st_size] = 0;
count = 0;
size = statbuf.st_size;
buf = (char *)value->data;
while (count < statbuf.st_size) {
bytes = read(f, buf, size);
if (bytes == -1) {
talloc_free(value->data);
ret = -1;
goto done;
}
count += bytes;
buf += bytes;
size -= bytes;
}
value->length = statbuf.st_size;
ret = statbuf.st_size;
done:
close(f);
return ret;
}
/*
this base64 decoder was taken from jitterbug (written by tridge).
we might need to replace it with a new version
*/
int ldb_base64_decode(char *s)
{
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset=0, byte_offset, idx, i, n;
uint8_t *d = (uint8_t *)s;
char *p=NULL;
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 (bit_offset >= 3) {
n--;
}
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(void *mem_ctx, const char *buf, int len)
{
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int bit_offset, byte_offset, idx, i;
const uint8_t *d = (const uint8_t *)buf;
int bytes = (len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
char *out;
out = talloc_array(mem_ctx, char, bytes+pad_bytes+1);
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];
}
for (;i<bytes+pad_bytes;i++)
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)
{
unsigned int i;
uint8_t *p = val->data;
if (val->length == 0) {
return 0;
}
if (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_data,
const char *buf, size_t length, int start_pos)
{
unsigned int i;
int total=0, ret;
for (i=0;i<length;i++) {
ret = fprintf_fn(private_data, "%c", buf[i]);
CHECK_RET;
if (i != (length-1) && (i + start_pos) % 77 == 0) {
ret = fprintf_fn(private_data, "\n ");
CHECK_RET;
}
}
return total;
}
#undef CHECK_RET
/*
encode as base64 to a file
*/
static int base64_encode_f(struct ldb_context *ldb,
int (*fprintf_fn)(void *, const char *, ...),
void *private_data,
const char *buf, int len, int start_pos)
{
char *b = ldb_base64_encode(ldb, buf, len);
int ret;
if (!b) {
return -1;
}
ret = fold_string(fprintf_fn, private_data, b, strlen(b), start_pos);
talloc_free(b);
return ret;
}
static const struct {
const char *name;
enum ldb_changetype changetype;
} ldb_changetypes[] = {
{"add", LDB_CHANGETYPE_ADD},
{"delete", LDB_CHANGETYPE_DELETE},
{"modify", LDB_CHANGETYPE_MODIFY},
{NULL, 0}
};
/* this macro is used to handle the return checking on fprintf_fn() */
#define CHECK_RET do { if (ret < 0) { talloc_free(mem_ctx); return ret; } total += ret; } while (0)
/*
write to ldif, using a caller supplied write method
*/
int ldb_ldif_write(struct ldb_context *ldb,
int (*fprintf_fn)(void *, const char *, ...),
void *private_data,
const struct ldb_ldif *ldif)
{
TALLOC_CTX *mem_ctx;
unsigned int i, j;
int total=0, ret;
const struct ldb_message *msg;
mem_ctx = talloc_named_const(NULL, 0, "ldb_ldif_write");
msg = ldif->msg;
ret = fprintf_fn(private_data, "dn: %s\n", ldb_dn_get_linearized(msg->dn));
CHECK_RET;
if (ldif->changetype != LDB_CHANGETYPE_NONE) {
for (i=0;ldb_changetypes[i].name;i++) {
if (ldb_changetypes[i].changetype == ldif->changetype) {
break;
}
}
if (!ldb_changetypes[i].name) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Invalid ldif changetype %d\n",
ldif->changetype);
talloc_free(mem_ctx);
return -1;
}
ret = fprintf_fn(private_data, "changetype: %s\n", ldb_changetypes[i].name);
CHECK_RET;
}
for (i=0;i<msg->num_elements;i++) {
const struct ldb_attrib_handler *h;
h = ldb_attrib_handler(ldb, msg->elements[i].name);
if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
case LDB_FLAG_MOD_ADD:
fprintf_fn(private_data, "add: %s\n",
msg->elements[i].name);
break;
case LDB_FLAG_MOD_DELETE:
fprintf_fn(private_data, "delete: %s\n",
msg->elements[i].name);
break;
case LDB_FLAG_MOD_REPLACE:
fprintf_fn(private_data, "replace: %s\n",
msg->elements[i].name);
break;
}
}
for (j=0;j<msg->elements[i].num_values;j++) {
struct ldb_val v;
ret = h->ldif_write_fn(ldb, mem_ctx, &msg->elements[i].values[j], &v);
CHECK_RET;
if (ldb_should_b64_encode(&v)) {
ret = fprintf_fn(private_data, "%s:: ",
msg->elements[i].name);
CHECK_RET;
ret = base64_encode_f(ldb, fprintf_fn, private_data,
(char *)v.data, v.length,
strlen(msg->elements[i].name)+3);
CHECK_RET;
ret = fprintf_fn(private_data, "\n");
CHECK_RET;
} else {
ret = fprintf_fn(private_data, "%s: ", msg->elements[i].name);
CHECK_RET;
ret = fold_string(fprintf_fn, private_data,
(char *)v.data, v.length,
strlen(msg->elements[i].name)+2);
CHECK_RET;
ret = fprintf_fn(private_data, "\n");
CHECK_RET;
}
if (v.data != msg->elements[i].values[j].data) {
talloc_free(v.data);
}
}
if (ldif->changetype == LDB_CHANGETYPE_MODIFY) {
fprintf_fn(private_data, "-\n");
}
}
ret = fprintf_fn(private_data,"\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(struct ldb_context *ldb,
int (*fgetc_fn)(void *), void *private_data)
{
size_t alloc_size=0, chunk_size = 0;
char *chunk = NULL;
int c;
int in_comment = 0;
while ((c = fgetc_fn(private_data)) != EOF) {
if (chunk_size+1 >= alloc_size) {
char *c2;
alloc_size += 1024;
c2 = talloc_realloc(ldb, chunk, char, alloc_size);
if (!c2) {
talloc_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;
}
if (chunk) {
chunk[chunk_size] = 0;
}
return chunk;
}
/* simple ldif attribute parser */
static int next_attr(void *mem_ctx, char **s, const char **attr, struct ldb_val *value)
{
char *p;
int base64_encoded = 0;
int binary_file = 0;
if (strncmp(*s, "-\n", 2) == 0) {
value->length = 0;
*attr = "-";
*s += 2;
return 0;
}
p = strchr(*s, ':');
if (!p) {
return -1;
}
*p++ = 0;
if (*p == ':') {
base64_encoded = 1;
p++;
}
if (*p == '<') {
binary_file = 1;
p++;
}
*attr = *s;
while (*p == ' ' || *p == '\t') {
p++;
}
value->data = (uint8_t *)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 = ldb_base64_decode((char *)value->data);
if (len == -1) {
/* it wasn't valid base64 data */
return -1;
}
value->length = len;
}
if (binary_file) {
int len = ldb_read_data_file(mem_ctx, value);
if (len == -1) {
/* an error occured hile trying to retrieve the file */
return -1;
}
}
return 0;
}
/*
free a message from a ldif_read
*/
void ldb_ldif_read_free(struct ldb_context *ldb, struct ldb_ldif *ldif)
{
talloc_free(ldif);
}
/*
read from a LDIF source, creating a ldb_message
*/
struct ldb_ldif *ldb_ldif_read(struct ldb_context *ldb,
int (*fgetc_fn)(void *), void *private_data)
{
struct ldb_ldif *ldif;
struct ldb_message *msg;
const char *attr=NULL;
char *chunk=NULL, *s;
struct ldb_val value;
unsigned flags = 0;
value.data = NULL;
ldif = talloc(ldb, struct ldb_ldif);
if (!ldif) return NULL;
ldif->msg = talloc(ldif, struct ldb_message);
if (ldif->msg == NULL) {
talloc_free(ldif);
return NULL;
}
ldif->changetype = LDB_CHANGETYPE_NONE;
msg = ldif->msg;
msg->dn = NULL;
msg->elements = NULL;
msg->num_elements = 0;
msg->private_data = NULL;
chunk = next_chunk(ldb, fgetc_fn, private_data);
if (!chunk) {
goto failed;
}
talloc_steal(ldif, chunk);
msg->private_data = chunk;
s = chunk;
if (next_attr(ldif, &s, &attr, &value) != 0) {
goto failed;
}
/* first line must be a dn */
if (ldb_attr_cmp(attr, "dn") != 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: First line of ldif must be a dn not '%s'\n",
attr);
goto failed;
}
msg->dn = ldb_dn_new(msg, ldb, (char *)value.data);
if ( ! ldb_dn_validate(msg->dn)) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "Error: Unable to parse dn '%s'\n",
value.data);
goto failed;
}
while (next_attr(ldif, &s, &attr, &value) == 0) {
const struct ldb_attrib_handler *h;
struct ldb_message_element *el;
int ret, empty = 0;
if (ldb_attr_cmp(attr, "changetype") == 0) {
int i;
for (i=0;ldb_changetypes[i].name;i++) {
if (ldb_attr_cmp((char *)value.data, ldb_changetypes[i].name) == 0) {
ldif->changetype = ldb_changetypes[i].changetype;
break;
}
}
if (!ldb_changetypes[i].name) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Error: Bad ldif changetype '%s'\n",(char *)value.data);
}
flags = 0;
continue;
}
if (ldb_attr_cmp(attr, "add") == 0) {
flags = LDB_FLAG_MOD_ADD;
empty = 1;
}
if (ldb_attr_cmp(attr, "delete") == 0) {
flags = LDB_FLAG_MOD_DELETE;
empty = 1;
}
if (ldb_attr_cmp(attr, "replace") == 0) {
flags = LDB_FLAG_MOD_REPLACE;
empty = 1;
}
if (ldb_attr_cmp(attr, "-") == 0) {
flags = 0;
continue;
}
if (empty) {
if (ldb_msg_add_empty(msg, (char *)value.data, flags, NULL) != 0) {
goto failed;
}
continue;
}
el = &msg->elements[msg->num_elements-1];
h = ldb_attrib_handler(ldb, attr);
if (msg->num_elements > 0 && ldb_attr_cmp(attr, el->name) == 0 &&
flags == el->flags) {
/* its a continuation */
el->values =
talloc_realloc(msg->elements, el->values,
struct ldb_val, el->num_values+1);
if (!el->values) {
goto failed;
}
ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[el->num_values]);
if (ret != 0) {
goto failed;
}
if (value.length == 0) {
ldb_debug(ldb, LDB_DEBUG_ERROR,
"Error: Attribute value cannot be empty for attribute '%s'\n", el->name);
goto failed;
}
if (value.data != el->values[el->num_values].data) {
talloc_steal(el->values, el->values[el->num_values].data);
}
el->num_values++;
} else {
/* its a new attribute */
msg->elements = talloc_realloc(ldif, msg->elements,
struct ldb_message_element,
msg->num_elements+1);
if (!msg->elements) {
goto failed;
}
el = &msg->elements[msg->num_elements];
el->flags = flags;
el->name = talloc_strdup(msg->elements, attr);
el->values = talloc(msg->elements, struct ldb_val);
if (!el->values || !el->name) {
goto failed;
}
el->num_values = 1;
ret = h->ldif_read_fn(ldb, ldif, &value, &el->values[0]);
if (ret != 0) {
goto failed;
}
if (value.data != el->values[0].data) {
talloc_steal(el->values, el->values[0].data);
}
msg->num_elements++;
}
}
return ldif;
failed:
talloc_free(ldif);
return NULL;
}
/*
a wrapper around ldif_read() for reading from FILE*
*/
struct ldif_read_file_state {
FILE *f;
};
static int fgetc_file(void *private_data)
{
struct ldif_read_file_state *state =
(struct ldif_read_file_state *)private_data;
return fgetc(state->f);
}
struct ldb_ldif *ldb_ldif_read_file(struct ldb_context *ldb, FILE *f)
{
struct ldif_read_file_state state;
state.f = f;
return ldb_ldif_read(ldb, 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_data)
{
struct ldif_read_string_state *state =
(struct ldif_read_string_state *)private_data;
if (state->s[0] != 0) {
return *state->s++;
}
return EOF;
}
struct ldb_ldif *ldb_ldif_read_string(struct ldb_context *ldb, const char **s)
{
struct ldif_read_string_state state;
struct ldb_ldif *ldif;
state.s = *s;
ldif = ldb_ldif_read(ldb, fgetc_string, &state);
*s = state.s;
return ldif;
}
/*
wrapper around ldif_write() for a file
*/
struct ldif_write_file_state {
FILE *f;
};
static int fprintf_file(void *private_data, const char *fmt, ...) PRINTF_ATTRIBUTE(2, 3);
static int fprintf_file(void *private_data, const char *fmt, ...)
{
struct ldif_write_file_state *state =
(struct ldif_write_file_state *)private_data;
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(state->f, fmt, ap);
va_end(ap);
return ret;
}
int ldb_ldif_write_file(struct ldb_context *ldb, FILE *f, const struct ldb_ldif *ldif)
{
struct ldif_write_file_state state;
state.f = f;
return ldb_ldif_write(ldb, fprintf_file, &state, ldif);
}
+430
View File
@@ -0,0 +1,430 @@
/*
ldb database library
Copyright (C) Andrew Tridgell 2004-2005
Copyright (C) Simo Sorce 2005
** 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
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
check if the scope matches in a search result
*/
static int ldb_match_scope(struct ldb_context *ldb,
struct ldb_dn *base,
struct ldb_dn *dn,
enum ldb_scope scope)
{
int ret = 0;
if (base == NULL || dn == NULL) {
return 1;
}
switch (scope) {
case LDB_SCOPE_BASE:
if (ldb_dn_compare(base, dn) == 0) {
ret = 1;
}
break;
case LDB_SCOPE_ONELEVEL:
if (ldb_dn_get_comp_num(dn) == (ldb_dn_get_comp_num(base) + 1)) {
if (ldb_dn_compare_base(base, dn) == 0) {
ret = 1;
}
}
break;
case LDB_SCOPE_SUBTREE:
default:
if (ldb_dn_compare_base(base, dn) == 0) {
ret = 1;
}
break;
}
return ret;
}
/*
match if node is present
*/
static int ldb_match_present(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
if (ldb_attr_dn(tree->u.present.attr) == 0) {
return 1;
}
if (ldb_msg_find_element(msg, tree->u.present.attr)) {
return 1;
}
return 0;
}
static int ldb_match_comparison(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope,
enum ldb_parse_op comp_op)
{
unsigned int i;
struct ldb_message_element *el;
const struct ldb_attrib_handler *h;
int ret;
/* FIXME: APPROX comparison not handled yet */
if (comp_op == LDB_OP_APPROX) return 0;
el = ldb_msg_find_element(msg, tree->u.comparison.attr);
if (el == NULL) {
return 0;
}
h = ldb_attrib_handler(ldb, el->name);
for (i = 0; i < el->num_values; i++) {
ret = h->comparison_fn(ldb, ldb, &el->values[i], &tree->u.comparison.value);
if (ret == 0) {
return 1;
}
if (ret > 0 && comp_op == LDB_OP_GREATER) {
return 1;
}
if (ret < 0 && comp_op == LDB_OP_LESS) {
return 1;
}
}
return 0;
}
/*
match a simple leaf node
*/
static int ldb_match_equality(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
struct ldb_message_element *el;
const struct ldb_attrib_handler *h;
struct ldb_dn *valuedn;
int ret;
if (ldb_attr_dn(tree->u.equality.attr) == 0) {
valuedn = ldb_dn_new(ldb, ldb, (char *)tree->u.equality.value.data);
if (valuedn == NULL) {
return 0;
}
ret = ldb_dn_compare(msg->dn, valuedn);
talloc_free(valuedn);
if (ret == 0) return 1;
return 0;
}
/* TODO: handle the "*" case derived from an extended search
operation without the attibute type defined */
el = ldb_msg_find_element(msg, tree->u.equality.attr);
if (el == NULL) {
return 0;
}
h = ldb_attrib_handler(ldb, el->name);
for (i=0;i<el->num_values;i++) {
if (h->comparison_fn(ldb, ldb, &tree->u.equality.value,
&el->values[i]) == 0) {
return 1;
}
}
return 0;
}
static int ldb_wildcard_compare(struct ldb_context *ldb,
const struct ldb_parse_tree *tree,
const struct ldb_val value)
{
const struct ldb_attrib_handler *h;
struct ldb_val val;
struct ldb_val cnk;
struct ldb_val *chunk;
char *p, *g;
uint8_t *save_p = NULL;
int c = 0;
h = ldb_attrib_handler(ldb, tree->u.substring.attr);
if(h->canonicalise_fn(ldb, ldb, &value, &val) != 0)
return -1;
save_p = val.data;
cnk.data = NULL;
if ( ! tree->u.substring.start_with_wildcard ) {
chunk = tree->u.substring.chunks[c];
if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
/* This deals with wildcard prefix searches on binary attributes (eg objectGUID) */
if (cnk.length > val.length) {
goto failed;
}
if (memcmp((char *)val.data, (char *)cnk.data, cnk.length) != 0) goto failed;
val.length -= cnk.length;
val.data += cnk.length;
c++;
talloc_free(cnk.data);
cnk.data = NULL;
}
while (tree->u.substring.chunks[c]) {
chunk = tree->u.substring.chunks[c];
if(h->canonicalise_fn(ldb, ldb, chunk, &cnk) != 0) goto failed;
/* FIXME: case of embedded nulls */
p = strstr((char *)val.data, (char *)cnk.data);
if (p == NULL) goto failed;
if ( (! tree->u.substring.chunks[c + 1]) && (! tree->u.substring.end_with_wildcard) ) {
do { /* greedy */
g = strstr((char *)p + cnk.length, (char *)cnk.data);
if (g) p = g;
} while(g);
}
val.length = val.length - (p - (char *)(val.data)) - cnk.length;
val.data = (uint8_t *)(p + cnk.length);
c++;
talloc_free(cnk.data);
cnk.data = NULL;
}
if ( (! tree->u.substring.end_with_wildcard) && (*(val.data) != 0) ) goto failed; /* last chunk have not reached end of string */
talloc_free(save_p);
return 1;
failed:
talloc_free(save_p);
talloc_free(cnk.data);
return 0;
}
/*
match a simple leaf node
*/
static int ldb_match_substring(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
struct ldb_message_element *el;
el = ldb_msg_find_element(msg, tree->u.substring.attr);
if (el == NULL) {
return 0;
}
for (i = 0; i < el->num_values; i++) {
if (ldb_wildcard_compare(ldb, tree, el->values[i]) == 1) {
return 1;
}
}
return 0;
}
/*
bitwise-and comparator
*/
static int ldb_comparator_and(const struct ldb_val *v1, const struct ldb_val *v2)
{
uint64_t i1, i2;
i1 = strtoull((char *)v1->data, NULL, 0);
i2 = strtoull((char *)v2->data, NULL, 0);
return ((i1 & i2) == i2);
}
/*
bitwise-or comparator
*/
static int ldb_comparator_or(const struct ldb_val *v1, const struct ldb_val *v2)
{
uint64_t i1, i2;
i1 = strtoull((char *)v1->data, NULL, 0);
i2 = strtoull((char *)v2->data, NULL, 0);
return ((i1 & i2) != 0);
}
/*
extended match, handles things like bitops
*/
static int ldb_match_extended(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
int i;
const struct {
const char *oid;
int (*comparator)(const struct ldb_val *, const struct ldb_val *);
} rules[] = {
{ LDB_OID_COMPARATOR_AND, ldb_comparator_and},
{ LDB_OID_COMPARATOR_OR, ldb_comparator_or}
};
int (*comp)(const struct ldb_val *, const struct ldb_val *) = NULL;
struct ldb_message_element *el;
if (tree->u.extended.dnAttributes) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: dnAttributes extended match not supported yet");
return -1;
}
if (tree->u.extended.rule_id == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-rule extended matches not supported yet");
return -1;
}
if (tree->u.extended.attr == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: no-attribute extended matches not supported yet");
return -1;
}
for (i=0;i<ARRAY_SIZE(rules);i++) {
if (strcmp(rules[i].oid, tree->u.extended.rule_id) == 0) {
comp = rules[i].comparator;
break;
}
}
if (comp == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "ldb: unknown extended rule_id %s\n",
tree->u.extended.rule_id);
return -1;
}
/* find the message element */
el = ldb_msg_find_element(msg, tree->u.extended.attr);
if (el == NULL) {
return 0;
}
for (i=0;i<el->num_values;i++) {
int ret = comp(&el->values[i], &tree->u.extended.value);
if (ret == -1 || ret == 1) return ret;
}
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
*/
static int ldb_match_message(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
enum ldb_scope scope)
{
unsigned int i;
int v;
switch (tree->operation) {
case LDB_OP_AND:
for (i=0;i<tree->u.list.num_elements;i++) {
v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
if (!v) return 0;
}
return 1;
case LDB_OP_OR:
for (i=0;i<tree->u.list.num_elements;i++) {
v = ldb_match_message(ldb, msg, tree->u.list.elements[i], scope);
if (v) return 1;
}
return 0;
case LDB_OP_NOT:
return ! ldb_match_message(ldb, msg, tree->u.isnot.child, scope);
case LDB_OP_EQUALITY:
return ldb_match_equality(ldb, msg, tree, scope);
case LDB_OP_SUBSTRING:
return ldb_match_substring(ldb, msg, tree, scope);
case LDB_OP_GREATER:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_GREATER);
case LDB_OP_LESS:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_LESS);
case LDB_OP_PRESENT:
return ldb_match_present(ldb, msg, tree, scope);
case LDB_OP_APPROX:
return ldb_match_comparison(ldb, msg, tree, scope, LDB_OP_APPROX);
case LDB_OP_EXTENDED:
return ldb_match_extended(ldb, msg, tree, scope);
}
return 0;
}
int ldb_match_msg(struct ldb_context *ldb,
const struct ldb_message *msg,
const struct ldb_parse_tree *tree,
struct ldb_dn *base,
enum ldb_scope scope)
{
if ( ! ldb_match_scope(ldb, base, msg->dn, scope) ) {
return 0;
}
return ldb_match_message(ldb, msg, tree, scope);
}
+452
View File
@@ -0,0 +1,452 @@
/*
ldb database library
Copyright (C) Simo Sorce 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 modules core
*
* Description: core modules routines
*
* Author: Simo Sorce
*/
#include "includes.h"
#include "ldb/include/includes.h"
#if (_SAMBA_BUILD_ >= 4)
#include "build.h"
#include "dynconfig.h"
#endif
#define LDB_MODULE_PREFIX "modules:"
#define LDB_MODULE_PREFIX_LEN 8
static char *ldb_modules_strdup_no_spaces(TALLOC_CTX *mem_ctx, const char *string)
{
int i, len;
char *trimmed;
trimmed = talloc_strdup(mem_ctx, string);
if (!trimmed) {
return NULL;
}
len = strlen(trimmed);
for (i = 0; trimmed[i] != '\0'; i++) {
switch (trimmed[i]) {
case ' ':
case '\t':
case '\n':
memmove(&trimmed[i], &trimmed[i + 1], len -i -1);
break;
}
}
return trimmed;
}
/* modules are called in inverse order on the stack.
Lets place them as an admin would think the right order is.
Modules order is important */
const char **ldb_modules_list_from_string(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *string)
{
char **modules = NULL;
const char **m;
char *modstr, *p;
int i;
/* spaces not admitted */
modstr = ldb_modules_strdup_no_spaces(mem_ctx, string);
if ( ! modstr) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_strdup_no_spaces()\n");
return NULL;
}
modules = talloc_realloc(mem_ctx, modules, char *, 2);
if ( ! modules ) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
talloc_free(modstr);
return NULL;
}
talloc_steal(modules, modstr);
i = 0;
/* The str*r*chr walks backwards: This is how we get the inverse order mentioned above */
while ((p = strrchr(modstr, ',')) != NULL) {
*p = '\0';
p++;
modules[i] = p;
i++;
modules = talloc_realloc(mem_ctx, modules, char *, i + 2);
if ( ! modules ) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Out of Memory in ldb_modules_list_from_string()\n");
return NULL;
}
}
modules[i] = modstr;
modules[i + 1] = NULL;
m = (const char **)modules;
return m;
}
static struct ops_list_entry {
const struct ldb_module_ops *ops;
struct ops_list_entry *next;
} *registered_modules = NULL;
static const struct ldb_module_ops *ldb_find_module_ops(const char *name)
{
struct ops_list_entry *e;
for (e = registered_modules; e; e = e->next) {
if (strcmp(e->ops->name, name) == 0)
return e->ops;
}
return NULL;
}
#ifndef STATIC_ldb_MODULES
#ifdef HAVE_LDB_LDAP
#define LDAP_INIT ldb_ldap_init,
#else
#define LDAP_INIT
#endif
#ifdef HAVE_LDB_SQLITE3
#define SQLITE3_INIT ldb_sqlite3_init,
#else
#define SQLITE3_INIT
#endif
#define STATIC_ldb_MODULES \
{ \
LDAP_INIT \
SQLITE3_INIT \
ldb_tdb_init, \
ldb_operational_init, \
ldb_rdn_name_init, \
ldb_objectclass_init, \
ldb_paged_results_init, \
ldb_sort_init, \
ldb_asq_init, \
NULL \
}
#endif
int ldb_global_init(void)
{
static int (*static_init_fns[])(void) = STATIC_ldb_MODULES;
static int initialized = 0;
int ret = 0, i;
if (initialized)
return 0;
initialized = 1;
for (i = 0; static_init_fns[i]; i++) {
if (static_init_fns[i]() == -1)
ret = -1;
}
return ret;
}
int ldb_register_module(const struct ldb_module_ops *ops)
{
struct ops_list_entry *entry = talloc(talloc_autofree_context(), struct ops_list_entry);
if (ldb_find_module_ops(ops->name) != NULL)
return -1;
if (entry == NULL)
return -1;
entry->ops = ops;
entry->next = registered_modules;
registered_modules = entry;
return 0;
}
int ldb_try_load_dso(struct ldb_context *ldb, const char *name)
{
char *path;
void *handle;
int (*init_fn) (void);
char *modulesdir;
#ifdef HAVE_DLOPEN
if (getenv("LD_LDB_MODULE_PATH") != NULL) {
modulesdir = talloc_strdup(ldb, getenv("LD_LDB_MODULE_PATH"));
} else {
#ifdef _SAMBA_BUILD_
modulesdir = talloc_asprintf(ldb, "%s/ldb", dyn_MODULESDIR);
#else
modulesdir = talloc_strdup(ldb, MODULESDIR);
#endif
}
path = talloc_asprintf(ldb, "%s/%s.%s", modulesdir, name, SHLIBEXT);
talloc_free(modulesdir);
ldb_debug(ldb, LDB_DEBUG_TRACE, "trying to load %s from %s\n", name, path);
handle = dlopen(path, RTLD_NOW);
if (handle == NULL) {
ldb_debug(ldb, LDB_DEBUG_WARNING, "unable to load %s from %s: %s\n", name, path, dlerror());
return -1;
}
init_fn = (int (*)(void))dlsym(handle, "init_module");
if (init_fn == NULL) {
ldb_debug(ldb, LDB_DEBUG_ERROR, "no symbol `init_module' found in %s: %s\n", path, dlerror());
return -1;
}
talloc_free(path);
return init_fn();
#else
ldb_debug(ldb, LDB_DEBUG_TRACE, "no dlopen() - not trying to load %s module\n", name);
return -1;
#endif
}
int ldb_load_modules_list(struct ldb_context *ldb, const char **module_list, struct ldb_module *backend, struct ldb_module **out)
{
struct ldb_module *module;
int i;
module = backend;
for (i = 0; module_list[i] != NULL; i++) {
struct ldb_module *current;
const struct ldb_module_ops *ops;
ops = ldb_find_module_ops(module_list[i]);
if (ops == NULL) {
if (ldb_try_load_dso(ldb, module_list[i]) == 0) {
ops = ldb_find_module_ops(module_list[i]);
}
}
if (ops == NULL) {
ldb_debug(ldb, LDB_DEBUG_WARNING, "WARNING: Module [%s] not found\n",
module_list[i]);
continue;
}
current = talloc_zero(ldb, struct ldb_module);
if (current == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
talloc_set_name(current, "ldb_module: %s", module_list[i]);
current->ldb = ldb;
current->ops = ops;
DLIST_ADD(module, current);
}
*out = module;
return LDB_SUCCESS;
}
int ldb_init_module_chain(struct ldb_context *ldb, struct ldb_module *module)
{
while (module && module->ops->init_context == NULL)
module = module->next;
if (module && module->ops->init_context &&
module->ops->init_context(module) != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "module initialization failed\n");
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
int ldb_load_modules(struct ldb_context *ldb, const char *options[])
{
const char **modules = NULL;
int i;
int ret;
TALLOC_CTX *mem_ctx = talloc_new(ldb);
if (!mem_ctx) {
return LDB_ERR_OPERATIONS_ERROR;
}
/* find out which modules we are requested to activate */
/* check if we have a custom module list passd as ldb option */
if (options) {
for (i = 0; options[i] != NULL; i++) {
if (strncmp(options[i], LDB_MODULE_PREFIX, LDB_MODULE_PREFIX_LEN) == 0) {
modules = ldb_modules_list_from_string(ldb, mem_ctx, &options[i][LDB_MODULE_PREFIX_LEN]);
}
}
}
/* if not overloaded by options and the backend is not ldap try to load the modules list from ldb */
if ((modules == NULL) && (strcmp("ldap", ldb->modules->ops->name) != 0)) {
const char * const attrs[] = { "@LIST" , NULL};
struct ldb_result *res = NULL;
struct ldb_dn *mods_dn;
mods_dn = ldb_dn_new(mem_ctx, ldb, "@MODULES");
if (mods_dn == NULL) {
talloc_free(mem_ctx);
return -1;
}
ret = ldb_search(ldb, mods_dn, LDB_SCOPE_BASE, "", attrs, &res);
talloc_steal(mods_dn, res);
if (ret == LDB_SUCCESS && (res->count == 0 || res->msgs[0]->num_elements == 0)) {
ldb_debug(ldb, LDB_DEBUG_TRACE, "no modules required by the db\n");
} else {
if (ret != LDB_SUCCESS) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "ldb error (%s) occurred searching for modules, bailing out\n", ldb_errstring(ldb));
talloc_free(mem_ctx);
return -1;
}
if (res->count > 1) {
ldb_debug(ldb, LDB_DEBUG_FATAL, "Too many records found (%d), bailing out\n", res->count);
talloc_free(mem_ctx);
return -1;
}
modules = ldb_modules_list_from_string(ldb, mem_ctx,
(const char *)res->msgs[0]->elements[0].values[0].data);
}
talloc_free(mods_dn);
}
if (modules != NULL) {
ret = ldb_load_modules_list(ldb, modules, ldb->modules, &ldb->modules);
talloc_free(modules);
if (ret != LDB_SUCCESS) {
return ret;
}
} else {
ldb_debug(ldb, LDB_DEBUG_TRACE, "No modules specified for this database\n");
}
return ldb_init_module_chain(ldb, ldb->modules);
}
/*
by using this we allow ldb modules to only implement the functions they care about,
which makes writing a module simpler, and makes it more likely to keep working
when ldb is extended
*/
#define FIND_OP(module, op) do { \
struct ldb_context *ldb = module->ldb; \
module = module->next; \
while (module && module->ops->op == NULL) module = module->next; \
if (module == NULL) { \
ldb_asprintf_errstring(ldb, "Unable to find backend operation for " #op ); \
return LDB_ERR_OPERATIONS_ERROR; \
} \
} while (0)
/*
helper functions to call the next module in chain
*/
int ldb_next_request(struct ldb_module *module, struct ldb_request *request)
{
switch (request->operation) {
case LDB_SEARCH:
FIND_OP(module, search);
return module->ops->search(module, request);
case LDB_ADD:
FIND_OP(module, add);
return module->ops->add(module, request);
case LDB_MODIFY:
FIND_OP(module, modify);
return module->ops->modify(module, request);
case LDB_DELETE:
FIND_OP(module, del);
return module->ops->del(module, request);
case LDB_RENAME:
FIND_OP(module, rename);
return module->ops->rename(module, request);
case LDB_SEQUENCE_NUMBER:
FIND_OP(module, sequence_number);
return module->ops->sequence_number(module, request);
default:
FIND_OP(module, request);
return module->ops->request(module, request);
}
}
int ldb_next_init(struct ldb_module *module)
{
/* init is different in that it is not an error if modules
* do not require initialization */
module = module->next;
while (module && module->ops->init_context == NULL)
module = module->next;
if (module == NULL)
return LDB_SUCCESS;
return module->ops->init_context(module);
}
int ldb_next_start_trans(struct ldb_module *module)
{
FIND_OP(module, start_transaction);
return module->ops->start_transaction(module);
}
int ldb_next_end_trans(struct ldb_module *module)
{
FIND_OP(module, end_transaction);
return module->ops->end_transaction(module);
}
int ldb_next_del_trans(struct ldb_module *module)
{
FIND_OP(module, del_transaction);
return module->ops->del_transaction(module);
}
+846
View File
@@ -0,0 +1,846 @@
/*
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 message component utility functions
*
* Description: functions for manipulating ldb_message structures
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
/*
create a new ldb_message in a given memory context (NULL for top level)
*/
struct ldb_message *ldb_msg_new(void *mem_ctx)
{
return talloc_zero(mem_ctx, struct ldb_message);
}
/*
find an element in a message by attribute name
*/
struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
const char *attr_name)
{
unsigned int i;
for (i=0;i<msg->num_elements;i++) {
if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
return &msg->elements[i];
}
}
return NULL;
}
/*
see if two ldb_val structures contain exactly the same data
return 1 for a match, 0 for a mis-match
*/
int ldb_val_equal_exact(const struct ldb_val *v1, const 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;
}
/*
find a value in an element
assumes case sensitive comparison
*/
struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
struct ldb_val *val)
{
unsigned int i;
for (i=0;i<el->num_values;i++) {
if (ldb_val_equal_exact(val, &el->values[i])) {
return &el->values[i];
}
}
return NULL;
}
/*
duplicate a ldb_val structure
*/
struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
{
struct ldb_val v2;
v2.length = v->length;
if (v->data == NULL) {
v2.data = NULL;
return v2;
}
/* the +1 is to cope with buggy C library routines like strndup
that look one byte beyond */
v2.data = talloc_array(mem_ctx, uint8_t, 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 an empty element to a message
*/
int ldb_msg_add_empty( struct ldb_message *msg,
const char *attr_name,
int flags,
struct ldb_message_element **return_el)
{
struct ldb_message_element *els;
/* FIXME: we should probably leave this to the schema module to check */
if (! ldb_valid_attr_name(attr_name)) {
return LDB_ERR_OPERATIONS_ERROR;
}
els = talloc_realloc(msg, msg->elements,
struct ldb_message_element, msg->num_elements+1);
if (!els) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
els[msg->num_elements].values = NULL;
els[msg->num_elements].num_values = 0;
els[msg->num_elements].flags = flags;
els[msg->num_elements].name = talloc_strdup(els, attr_name);
if (!els[msg->num_elements].name) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
msg->elements = els;
msg->num_elements++;
if (return_el) {
*return_el = &els[msg->num_elements-1];
}
return LDB_SUCCESS;
}
/*
add an empty element to a message
*/
int ldb_msg_add(struct ldb_message *msg,
const struct ldb_message_element *el,
int flags)
{
if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
msg->elements[msg->num_elements-1] = *el;
msg->elements[msg->num_elements-1].flags = flags;
return LDB_SUCCESS;
}
/*
add a value to a message
*/
int ldb_msg_add_value(struct ldb_message *msg,
const char *attr_name,
const struct ldb_val *val,
struct ldb_message_element **return_el)
{
struct ldb_message_element *el;
struct ldb_val *vals;
int ret;
el = ldb_msg_find_element(msg, attr_name);
if (!el) {
ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
if (ret != LDB_SUCCESS) {
return ret;
}
}
vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
if (!vals) {
errno = ENOMEM;
return LDB_ERR_OPERATIONS_ERROR;
}
el->values = vals;
el->values[el->num_values] = *val;
el->num_values++;
if (return_el) {
*return_el = el;
}
return LDB_SUCCESS;
}
/*
add a value to a message, stealing it into the 'right' place
*/
int ldb_msg_add_steal_value(struct ldb_message *msg,
const char *attr_name,
struct ldb_val *val)
{
int ret;
struct ldb_message_element *el;
ret = ldb_msg_add_value(msg, attr_name, val, &el);
if (ret == LDB_SUCCESS) {
talloc_steal(el->values, val->data);
}
return ret;
}
/*
add a string element to a message
*/
int ldb_msg_add_string(struct ldb_message *msg,
const char *attr_name, const char *str)
{
struct ldb_val val;
val.data = discard_const_p(uint8_t, str);
val.length = strlen(str);
if (val.length == 0) {
/* allow empty strings as non-existant attributes */
return LDB_SUCCESS;
}
return ldb_msg_add_value(msg, attr_name, &val, NULL);
}
/*
add a string element to a message, stealing it into the 'right' place
*/
int ldb_msg_add_steal_string(struct ldb_message *msg,
const char *attr_name, char *str)
{
struct ldb_val val;
val.data = (uint8_t *)str;
val.length = strlen(str);
return ldb_msg_add_steal_value(msg, attr_name, &val);
}
/*
add a printf formatted element to a message
*/
int ldb_msg_add_fmt(struct ldb_message *msg,
const char *attr_name, const char *fmt, ...)
{
struct ldb_val val;
va_list ap;
char *str;
va_start(ap, fmt);
str = talloc_vasprintf(msg, fmt, ap);
va_end(ap);
if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
val.data = (uint8_t *)str;
val.length = strlen(str);
return ldb_msg_add_steal_value(msg, attr_name, &val);
}
/*
compare two ldb_message_element structures
assumes case senistive comparison
*/
int ldb_msg_element_compare(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
unsigned int i;
if (el1->num_values != el2->num_values) {
return el1->num_values - el2->num_values;
}
for (i=0;i<el1->num_values;i++) {
if (!ldb_msg_find_val(el2, &el1->values[i])) {
return -1;
}
}
return 0;
}
/*
compare two ldb_message_element structures
comparing by element name
*/
int ldb_msg_element_compare_name(struct ldb_message_element *el1,
struct ldb_message_element *el2)
{
return ldb_attr_cmp(el1->name, el2->name);
}
/*
convenience functions to return common types from a message
these return the first value if the attribute is multi-valued
*/
const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
if (!el || el->num_values == 0) {
return NULL;
}
return &el->values[0];
}
int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtol((const char *)v->data, NULL, 0);
}
unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
const char *attr_name,
unsigned int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoul((const char *)v->data, NULL, 0);
}
int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
const char *attr_name,
int64_t default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoll((const char *)v->data, NULL, 0);
}
uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
const char *attr_name,
uint64_t default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtoull((const char *)v->data, NULL, 0);
}
double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
const char *attr_name,
double default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return strtod((const char *)v->data, NULL);
}
int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
const char *attr_name,
int default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
if (strcasecmp((const char *)v->data, "FALSE") == 0) {
return 0;
}
if (strcasecmp((const char *)v->data, "TRUE") == 0) {
return 1;
}
return default_value;
}
const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
const char *attr_name,
const char *default_value)
{
const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return default_value;
}
return (const char *)v->data;
}
struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
void *mem_ctx,
const struct ldb_message *msg,
const char *attr_name)
{
struct ldb_dn *res_dn;
const struct ldb_val *v;
v = ldb_msg_find_ldb_val(msg, attr_name);
if (!v || !v->data) {
return NULL;
}
res_dn = ldb_dn_new(mem_ctx, ldb, (const char *)v->data);
if ( ! ldb_dn_validate(res_dn)) {
talloc_free(res_dn);
return NULL;
}
return res_dn;
}
/*
sort the elements of a message by name
*/
void ldb_msg_sort_elements(struct ldb_message *msg)
{
qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
(comparison_fn_t)ldb_msg_element_compare_name);
}
/*
shallow copy a message - copying only the elements array so that the caller
can safely add new elements without changing the message
*/
struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
int i;
msg2 = talloc(mem_ctx, struct ldb_message);
if (msg2 == NULL) return NULL;
*msg2 = *msg;
msg2->private_data = NULL;
msg2->elements = talloc_array(msg2, struct ldb_message_element,
msg2->num_elements);
if (msg2->elements == NULL) goto failed;
for (i=0;i<msg2->num_elements;i++) {
msg2->elements[i] = msg->elements[i];
}
return msg2;
failed:
talloc_free(msg2);
return NULL;
}
/*
copy a message, allocating new memory for all parts
*/
struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
const struct ldb_message *msg)
{
struct ldb_message *msg2;
int i, j;
msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
if (msg2 == NULL) return NULL;
msg2->dn = ldb_dn_copy(msg2, msg2->dn);
if (msg2->dn == NULL) goto failed;
for (i=0;i<msg2->num_elements;i++) {
struct ldb_message_element *el = &msg2->elements[i];
struct ldb_val *values = el->values;
el->name = talloc_strdup(msg2->elements, el->name);
if (el->name == NULL) goto failed;
el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
for (j=0;j<el->num_values;j++) {
el->values[j] = ldb_val_dup(el->values, &values[j]);
if (el->values[j].data == NULL && values[j].length != 0) {
goto failed;
}
}
}
return msg2;
failed:
talloc_free(msg2);
return NULL;
}
/*
canonicalise a message, merging elements of the same name
*/
struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
const struct ldb_message *msg)
{
int i;
struct ldb_message *msg2;
msg2 = ldb_msg_copy(ldb, msg);
if (msg2 == NULL) return NULL;
ldb_msg_sort_elements(msg2);
for (i=1;i<msg2->num_elements;i++) {
struct ldb_message_element *el1 = &msg2->elements[i-1];
struct ldb_message_element *el2 = &msg2->elements[i];
if (ldb_msg_element_compare_name(el1, el2) == 0) {
el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
el1->num_values + el2->num_values);
if (el1->values == NULL) {
return NULL;
}
memcpy(el1->values + el1->num_values,
el2->values,
sizeof(struct ldb_val) * el2->num_values);
el1->num_values += el2->num_values;
talloc_free(discard_const_p(char, el2->name));
if (i+1<msg2->num_elements) {
memmove(el2, el2+1, sizeof(struct ldb_message_element) *
(msg2->num_elements - (i+1)));
}
msg2->num_elements--;
i--;
}
}
return msg2;
}
/*
return a ldb_message representing the differences between msg1 and msg2. If you
then use this in a ldb_modify() call it can be used to save edits to a message
*/
struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
struct ldb_message *msg1,
struct ldb_message *msg2)
{
struct ldb_message *mod;
struct ldb_message_element *el;
unsigned int i;
mod = ldb_msg_new(ldb);
mod->dn = msg1->dn;
mod->num_elements = 0;
mod->elements = NULL;
msg2 = ldb_msg_canonicalize(ldb, msg2);
if (msg2 == NULL) {
return NULL;
}
/* look in msg2 to find elements that need to be added
or modified */
for (i=0;i<msg2->num_elements;i++) {
el = ldb_msg_find_element(msg1, msg2->elements[i].name);
if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
continue;
}
if (ldb_msg_add(mod,
&msg2->elements[i],
el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
return NULL;
}
}
/* look in msg1 to find elements that need to be deleted */
for (i=0;i<msg1->num_elements;i++) {
el = ldb_msg_find_element(msg2, msg1->elements[i].name);
if (!el) {
if (ldb_msg_add_empty(mod,
msg1->elements[i].name,
LDB_FLAG_MOD_DELETE, NULL) != 0) {
return NULL;
}
}
}
return mod;
}
int ldb_msg_sanity_check(struct ldb_context *ldb,
const struct ldb_message *msg)
{
int i, j;
/* basic check on DN */
if (msg->dn == NULL) {
/* TODO: return also an error string */
ldb_set_errstring(ldb, "ldb message lacks a DN!");
return LDB_ERR_INVALID_DN_SYNTAX;
}
/* basic syntax checks */
for (i = 0; i < msg->num_elements; i++) {
for (j = 0; j < msg->elements[i].num_values; j++) {
if (msg->elements[i].values[j].length == 0) {
TALLOC_CTX *mem_ctx = talloc_new(ldb);
/* an attribute cannot be empty */
/* TODO: return also an error string */
ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
msg->elements[i].name,
ldb_dn_get_linearized(msg->dn));
talloc_free(mem_ctx);
return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
}
}
}
return LDB_SUCCESS;
}
/*
copy an attribute list. This only copies the array, not the elements
(ie. the elements are left as the same pointers)
*/
const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
{
const char **ret;
int i;
for (i=0;attrs[i];i++) /* noop */ ;
ret = talloc_array(mem_ctx, const char *, i+1);
if (ret == NULL) {
return NULL;
}
for (i=0;attrs[i];i++) {
ret[i] = attrs[i];
}
ret[i] = attrs[i];
return ret;
}
/*
copy an attribute list. This only copies the array, not the elements
(ie. the elements are left as the same pointers). The new attribute is added to the list.
*/
const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
{
const char **ret;
int i;
for (i=0;attrs[i];i++) /* noop */ ;
ret = talloc_array(mem_ctx, const char *, i+2);
if (ret == NULL) {
return NULL;
}
for (i=0;attrs[i];i++) {
ret[i] = attrs[i];
}
ret[i] = new_attr;
ret[i+1] = NULL;
return ret;
}
/*
return 1 if an attribute is in a list of attributes, or 0 otherwise
*/
int ldb_attr_in_list(const char * const *attrs, const char *attr)
{
int i;
for (i=0;attrs[i];i++) {
if (ldb_attr_cmp(attrs[i], attr) == 0) {
return 1;
}
}
return 0;
}
/*
rename the specified attribute in a search result
*/
int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el == NULL) {
return LDB_SUCCESS;
}
el->name = talloc_strdup(msg->elements, replace);
if (el->name == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
/*
copy the specified attribute in a search result to a new attribute
*/
int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el == NULL) {
return LDB_SUCCESS;
}
if (ldb_msg_add(msg, el, 0) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
return ldb_msg_rename_attr(msg, attr, replace);
}
/*
remove the specified attribute in a search result
*/
void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
{
struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
if (el) {
int n = (el - msg->elements);
if (n != msg->num_elements-1) {
memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
}
msg->num_elements--;
}
}
/*
remove the specified element in a search result
*/
void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
{
int n = (el - msg->elements);
if (n != msg->num_elements-1) {
memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
}
msg->num_elements--;
}
/*
return a LDAP formatted time string
*/
char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
{
struct tm *tm = gmtime(&t);
char *ts;
int r;
if (!tm) {
return NULL;
}
/* we now excatly how long this string will be */
ts = talloc_array(mem_ctx, char, 18);
/* formatted like: 20040408072012.0Z */
r = snprintf(ts, 18,
"%04u%02u%02u%02u%02u%02u.0Z",
tm->tm_year+1900, tm->tm_mon+1,
tm->tm_mday, tm->tm_hour, tm->tm_min,
tm->tm_sec);
if (r != 17) {
talloc_free(ts);
return NULL;
}
return ts;
}
/*
convert a LDAP time string to a time_t. Return 0 if unable to convert
*/
time_t ldb_string_to_time(const char *s)
{
struct tm tm;
if (s == NULL) return 0;
memset(&tm, 0, sizeof(tm));
if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
return 0;
}
tm.tm_year -= 1900;
tm.tm_mon -= 1;
return timegm(&tm);
}
/*
dump a set of results to a file. Useful from within gdb
*/
void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
{
int i;
for (i = 0; i < result->count; i++) {
struct ldb_ldif ldif;
fprintf(f, "# record %d\n", i+1);
ldif.changetype = LDB_CHANGETYPE_NONE;
ldif.msg = result->msgs[i];
ldb_ldif_write_file(ldb, f, &ldif);
}
}
int ldb_msg_check_string_attribute(const struct ldb_message *msg, const char *name, const char *value)
{
struct ldb_message_element *el;
struct ldb_val val;
el = ldb_msg_find_element(msg, name);
if (el == NULL)
return 0;
val.data = discard_const_p(uint8_t, value);
val.length = strlen(value);
if (ldb_msg_find_val(el, &val))
return 1;
return 0;
}
+817
View File
@@ -0,0 +1,817 @@
/*
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"
#include "ldb/include/includes.h"
#include "system/locale.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> ::= '=' | '~=' | '<=' | '>='
*/
/*
decode a RFC2254 binary string representation of a buffer.
Used in LDAP filters.
*/
struct ldb_val ldb_binary_decode(void *mem_ctx, const char *str)
{
int i, j;
struct ldb_val ret;
int slen = str?strlen(str):0;
ret.data = (uint8_t *)talloc_size(mem_ctx, slen+1);
ret.length = 0;
if (ret.data == NULL) return ret;
for (i=j=0;i<slen;i++) {
if (str[i] == '\\') {
unsigned c;
if (sscanf(&str[i+1], "%02X", &c) != 1) {
talloc_free(ret.data);
memset(&ret, 0, sizeof(ret));
return ret;
}
((uint8_t *)ret.data)[j++] = c;
i += 2;
} else {
((uint8_t *)ret.data)[j++] = str[i];
}
}
ret.length = j;
((uint8_t *)ret.data)[j] = 0;
return ret;
}
/*
encode a blob as a RFC2254 binary string, escaping any
non-printable or '\' characters
*/
char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
{
int i;
char *ret;
int len = val.length;
unsigned char *buf = val.data;
for (i=0;i<val.length;i++) {
if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
len += 2;
}
}
ret = talloc_array(mem_ctx, char, len+1);
if (ret == NULL) return NULL;
len = 0;
for (i=0;i<val.length;i++) {
if (!isprint(buf[i]) || strchr(" *()\\&|!\"", buf[i])) {
snprintf(ret+len, 4, "\\%02X", buf[i]);
len += 3;
} else {
ret[len++] = buf[i];
}
}
ret[len] = 0;
return ret;
}
/*
encode a string as a RFC2254 binary string, escaping any
non-printable or '\' characters. This routine is suitable for use
in escaping user data in ldap filters.
*/
char *ldb_binary_encode_string(void *mem_ctx, const char *string)
{
struct ldb_val val;
val.data = discard_const_p(uint8_t, string);
val.length = strlen(string);
return ldb_binary_encode(mem_ctx, val);
}
/* find the first matching wildcard */
static char *ldb_parse_find_wildcard(char *value)
{
while (*value) {
value = strpbrk(value, "\\*");
if (value == NULL) return NULL;
if (value[0] == '\\') {
if (value[1] == '\0') return NULL;
value += 2;
continue;
}
if (value[0] == '*') return value;
}
return NULL;
}
/* return a NULL terminated list of binary strings representing the value
chunks separated by wildcards that makes the value portion of the filter
*/
static struct ldb_val **ldb_wildcard_decode(void *mem_ctx, const char *string)
{
struct ldb_val **ret = NULL;
int val = 0;
char *wc, *str;
wc = talloc_strdup(mem_ctx, string);
if (wc == NULL) return NULL;
while (wc && *wc) {
str = wc;
wc = ldb_parse_find_wildcard(str);
if (wc && *wc) {
if (wc == str) {
wc++;
continue;
}
*wc = 0;
wc++;
}
ret = talloc_realloc(mem_ctx, ret, struct ldb_val *, val + 2);
if (ret == NULL) return NULL;
ret[val] = talloc(mem_ctx, struct ldb_val);
if (ret[val] == NULL) return NULL;
*(ret[val]) = ldb_binary_decode(mem_ctx, str);
if ((ret[val])->data == NULL) return NULL;
val++;
}
if (ret != NULL) {
ret[val] = NULL;
}
return ret;
}
static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s);
/*
parse an extended match
possible forms:
(attr:oid:=value)
(attr:dn:oid:=value)
(attr:dn:=value)
(:dn:oid:=value)
the ':dn' part sets the dnAttributes boolean if present
the oid sets the rule_id string
*/
static struct ldb_parse_tree *ldb_parse_extended(struct ldb_parse_tree *ret,
char *attr, char *value)
{
char *p1, *p2;
ret->operation = LDB_OP_EXTENDED;
ret->u.extended.value = ldb_binary_decode(ret, value);
if (ret->u.extended.value.data == NULL) goto failed;
p1 = strchr(attr, ':');
if (p1 == NULL) goto failed;
p2 = strchr(p1+1, ':');
*p1 = 0;
if (p2) *p2 = 0;
ret->u.extended.attr = attr;
if (strcmp(p1+1, "dn") == 0) {
ret->u.extended.dnAttributes = 1;
if (p2) {
ret->u.extended.rule_id = talloc_strdup(ret, p2+1);
if (ret->u.extended.rule_id == NULL) goto failed;
} else {
ret->u.extended.rule_id = NULL;
}
} else {
ret->u.extended.dnAttributes = 0;
ret->u.extended.rule_id = talloc_strdup(ret, p1+1);
if (ret->u.extended.rule_id == NULL) goto failed;
}
return ret;
failed:
talloc_free(ret);
return NULL;
}
static enum ldb_parse_op ldb_parse_filtertype(void *mem_ctx, char **type, char **value, const char **s)
{
enum ldb_parse_op filter = 0;
char *name, *val, *k;
const char *p = *s;
const char *t, *t1;
/* retrieve attributetype name */
t = p;
while ((isascii(*p) && isalnum((unsigned char)*p)) || (*p == '-')) { /* attribute names can only be alphanums */
p++;
}
if (*p == ':') { /* but extended searches have : and . chars too */
p = strstr(p, ":=");
if (p == NULL) { /* malformed attribute name */
return 0;
}
}
t1 = p;
while (isspace((unsigned char)*p)) p++;
if (!strchr("=<>~:", *p)) {
return 0;
}
/* save name */
name = (char *)talloc_memdup(mem_ctx, t, t1 - t + 1);
if (name == NULL) return 0;
name[t1 - t] = '\0';
/* retrieve filtertype */
if (*p == '=') {
filter = LDB_OP_EQUALITY;
} else if (*(p + 1) == '=') {
switch (*p) {
case '<':
filter = LDB_OP_LESS;
p++;
break;
case '>':
filter = LDB_OP_GREATER;
p++;
break;
case '~':
filter = LDB_OP_APPROX;
p++;
break;
case ':':
filter = LDB_OP_EXTENDED;
p++;
break;
}
}
if (!filter) {
talloc_free(name);
return filter;
}
p++;
while (isspace((unsigned char)*p)) p++;
/* retieve value */
t = p;
while (*p && ((*p != ')') || ((*p == ')') && (*(p - 1) == '\\')))) p++;
val = (char *)talloc_memdup(mem_ctx, t, p - t + 1);
if (val == NULL) {
talloc_free(name);
return 0;
}
val[p - t] = '\0';
k = &(val[p - t]);
/* remove trailing spaces from value */
while ((k > val) && (isspace((unsigned char)*(k - 1)))) k--;
*k = '\0';
*type = name;
*value = val;
*s = p;
return filter;
}
/*
<simple> ::= <attributetype> <filtertype> <attributevalue>
*/
static struct ldb_parse_tree *ldb_parse_simple(void *mem_ctx, const char **s)
{
char *attr, *value;
struct ldb_parse_tree *ret;
enum ldb_parse_op filtertype;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
filtertype = ldb_parse_filtertype(ret, &attr, &value, s);
if (!filtertype) {
talloc_free(ret);
return NULL;
}
switch (filtertype) {
case LDB_OP_PRESENT:
ret->operation = LDB_OP_PRESENT;
ret->u.present.attr = attr;
break;
case LDB_OP_EQUALITY:
if (strcmp(value, "*") == 0) {
ret->operation = LDB_OP_PRESENT;
ret->u.present.attr = attr;
break;
}
if (ldb_parse_find_wildcard(value) != NULL) {
ret->operation = LDB_OP_SUBSTRING;
ret->u.substring.attr = attr;
ret->u.substring.start_with_wildcard = 0;
ret->u.substring.end_with_wildcard = 0;
ret->u.substring.chunks = ldb_wildcard_decode(ret, value);
if (ret->u.substring.chunks == NULL){
talloc_free(ret);
return NULL;
}
if (value[0] == '*')
ret->u.substring.start_with_wildcard = 1;
if (value[strlen(value) - 1] == '*')
ret->u.substring.end_with_wildcard = 1;
talloc_free(value);
break;
}
ret->operation = LDB_OP_EQUALITY;
ret->u.equality.attr = attr;
ret->u.equality.value = ldb_binary_decode(ret, value);
if (ret->u.equality.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_GREATER:
ret->operation = LDB_OP_GREATER;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_LESS:
ret->operation = LDB_OP_LESS;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_APPROX:
ret->operation = LDB_OP_APPROX;
ret->u.comparison.attr = attr;
ret->u.comparison.value = ldb_binary_decode(ret, value);
if (ret->u.comparison.value.data == NULL) {
talloc_free(ret);
return NULL;
}
talloc_free(value);
break;
case LDB_OP_EXTENDED:
ret = ldb_parse_extended(ret, attr, value);
break;
default:
talloc_free(ret);
return NULL;
}
return ret;
}
/*
parse a filterlist
<and> ::= '&' <filterlist>
<or> ::= '|' <filterlist>
<filterlist> ::= <filter> | <filter> <filterlist>
*/
static struct ldb_parse_tree *ldb_parse_filterlist(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret, *next;
enum ldb_parse_op op;
const char *p = *s;
switch (*p) {
case '&':
op = LDB_OP_AND;
break;
case '|':
op = LDB_OP_OR;
break;
default:
return NULL;
}
p++;
while (isspace((unsigned char)*p)) p++;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
ret->operation = op;
ret->u.list.num_elements = 1;
ret->u.list.elements = talloc(ret, struct ldb_parse_tree *);
if (!ret->u.list.elements) {
errno = ENOMEM;
talloc_free(ret);
return NULL;
}
ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p);
if (!ret->u.list.elements[0]) {
talloc_free(ret);
return NULL;
}
while (isspace((unsigned char)*p)) p++;
while (*p && (next = ldb_parse_filter(ret->u.list.elements, &p))) {
struct ldb_parse_tree **e;
e = talloc_realloc(ret, ret->u.list.elements,
struct ldb_parse_tree *,
ret->u.list.num_elements + 1);
if (!e) {
errno = ENOMEM;
talloc_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((unsigned char)*p)) p++;
}
*s = p;
return ret;
}
/*
<not> ::= '!' <filter>
*/
static struct ldb_parse_tree *ldb_parse_not(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
if (*p != '!') {
return NULL;
}
p++;
ret = talloc(mem_ctx, struct ldb_parse_tree);
if (!ret) {
errno = ENOMEM;
return NULL;
}
ret->operation = LDB_OP_NOT;
ret->u.isnot.child = ldb_parse_filter(ret, &p);
if (!ret->u.isnot.child) {
talloc_free(ret);
return NULL;
}
*s = p;
return ret;
}
/*
parse a filtercomp
<filtercomp> ::= <and> | <or> | <not> | <simple>
*/
static struct ldb_parse_tree *ldb_parse_filtercomp(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
while (isspace((unsigned char)*p)) p++;
switch (*p) {
case '&':
ret = ldb_parse_filterlist(mem_ctx, &p);
break;
case '|':
ret = ldb_parse_filterlist(mem_ctx, &p);
break;
case '!':
ret = ldb_parse_not(mem_ctx, &p);
break;
case '(':
case ')':
return NULL;
default:
ret = ldb_parse_simple(mem_ctx, &p);
}
*s = p;
return ret;
}
/*
<filter> ::= '(' <filtercomp> ')'
*/
static struct ldb_parse_tree *ldb_parse_filter(void *mem_ctx, const char **s)
{
struct ldb_parse_tree *ret;
const char *p = *s;
if (*p != '(') {
return NULL;
}
p++;
ret = ldb_parse_filtercomp(mem_ctx, &p);
if (*p != ')') {
return NULL;
}
p++;
while (isspace((unsigned char)*p)) {
p++;
}
*s = p;
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(void *mem_ctx, const char *s)
{
if (s == NULL || *s == 0) {
s = "(|(objectClass=*)(distinguishedName=*))";
}
while (isspace((unsigned char)*s)) s++;
if (*s == '(') {
return ldb_parse_filter(mem_ctx, &s);
}
return ldb_parse_simple(mem_ctx, &s);
}
/*
construct a ldap parse filter given a parse tree
*/
char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree)
{
char *s, *s2, *ret;
int i;
if (tree == NULL) {
return NULL;
}
switch (tree->operation) {
case LDB_OP_AND:
case LDB_OP_OR:
ret = talloc_asprintf(mem_ctx, "(%c", tree->operation==LDB_OP_AND?'&':'|');
if (ret == NULL) return NULL;
for (i=0;i<tree->u.list.num_elements;i++) {
s = ldb_filter_from_tree(mem_ctx, tree->u.list.elements[i]);
if (s == NULL) {
talloc_free(ret);
return NULL;
}
s2 = talloc_asprintf_append(ret, "%s", s);
talloc_free(s);
if (s2 == NULL) {
talloc_free(ret);
return NULL;
}
ret = s2;
}
s = talloc_asprintf_append(ret, ")");
if (s == NULL) {
talloc_free(ret);
return NULL;
}
return s;
case LDB_OP_NOT:
s = ldb_filter_from_tree(mem_ctx, tree->u.isnot.child);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(!%s)", s);
talloc_free(s);
return ret;
case LDB_OP_EQUALITY:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_SUBSTRING:
ret = talloc_asprintf(mem_ctx, "(%s=%s", tree->u.substring.attr,
tree->u.substring.start_with_wildcard?"*":"");
if (ret == NULL) return NULL;
for (i = 0; tree->u.substring.chunks[i]; i++) {
s2 = ldb_binary_encode(mem_ctx, *(tree->u.substring.chunks[i]));
if (s2 == NULL) {
talloc_free(ret);
return NULL;
}
if (tree->u.substring.chunks[i+1] ||
tree->u.substring.end_with_wildcard) {
s = talloc_asprintf_append(ret, "%s*", s2);
} else {
s = talloc_asprintf_append(ret, "%s", s2);
}
if (s == NULL) {
talloc_free(ret);
return NULL;
}
ret = s;
}
s = talloc_asprintf_append(ret, ")");
if (s == NULL) {
talloc_free(ret);
return NULL;
}
ret = s;
return ret;
case LDB_OP_GREATER:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s>=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_LESS:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s<=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_PRESENT:
ret = talloc_asprintf(mem_ctx, "(%s=*)", tree->u.present.attr);
return ret;
case LDB_OP_APPROX:
s = ldb_binary_encode(mem_ctx, tree->u.equality.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s~=%s)",
tree->u.equality.attr, s);
talloc_free(s);
return ret;
case LDB_OP_EXTENDED:
s = ldb_binary_encode(mem_ctx, tree->u.extended.value);
if (s == NULL) return NULL;
ret = talloc_asprintf(mem_ctx, "(%s%s%s%s:=%s)",
tree->u.extended.attr?tree->u.extended.attr:"",
tree->u.extended.dnAttributes?":dn":"",
tree->u.extended.rule_id?":":"",
tree->u.extended.rule_id?tree->u.extended.rule_id:"",
s);
talloc_free(s);
return ret;
}
return NULL;
}
/*
replace any occurances of an attribute name in the parse tree with a
new name
*/
void ldb_parse_tree_attr_replace(struct ldb_parse_tree *tree,
const char *attr,
const char *replace)
{
int i;
switch (tree->operation) {
case LDB_OP_AND:
case LDB_OP_OR:
for (i=0;i<tree->u.list.num_elements;i++) {
ldb_parse_tree_attr_replace(tree->u.list.elements[i],
attr, replace);
}
break;
case LDB_OP_NOT:
ldb_parse_tree_attr_replace(tree->u.isnot.child, attr, replace);
break;
case LDB_OP_EQUALITY:
case LDB_OP_GREATER:
case LDB_OP_LESS:
case LDB_OP_APPROX:
if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
tree->u.equality.attr = replace;
}
break;
case LDB_OP_SUBSTRING:
if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
tree->u.substring.attr = replace;
}
break;
case LDB_OP_PRESENT:
if (ldb_attr_cmp(tree->u.present.attr, attr) == 0) {
tree->u.present.attr = replace;
}
break;
case LDB_OP_EXTENDED:
if (tree->u.extended.attr &&
ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
tree->u.extended.attr = replace;
}
break;
}
}
+138
View File
@@ -0,0 +1,138 @@
/*
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 utf8 handling
*
* Description: case folding and case comparison for UTF8 strings
*
* Author: Andrew Tridgell
*/
#include "includes.h"
#include "ldb/include/includes.h"
#include "system/locale.h"
/*
this allow the user to pass in a caseless comparison
function to handle utf8 caseless comparisons
*/
void ldb_set_utf8_fns(struct ldb_context *ldb,
void *context,
char *(*casefold)(void *, void *, const char *))
{
if (context)
ldb->utf8_fns.context = context;
if (casefold)
ldb->utf8_fns.casefold = casefold;
}
/*
a simple case folding function
NOTE: does not handle UTF8
*/
char *ldb_casefold_default(void *context, void *mem_ctx, const char *s)
{
int i;
char *ret = talloc_strdup(mem_ctx, s);
if (!s) {
errno = ENOMEM;
return NULL;
}
for (i=0;ret[i];i++) {
ret[i] = toupper((unsigned char)ret[i]);
}
return ret;
}
void ldb_set_utf8_default(struct ldb_context *ldb)
{
ldb_set_utf8_fns(ldb, NULL, ldb_casefold_default);
}
char *ldb_casefold(struct ldb_context *ldb, void *mem_ctx, const char *s)
{
return ldb->utf8_fns.casefold(ldb->utf8_fns.context, mem_ctx, s);
}
/*
check the attribute name is valid according to rfc2251
returns 1 if the name is ok
*/
int ldb_valid_attr_name(const char *s)
{
int i;
if (!s || !s[0])
return 0;
/* handle special ldb_tdb wildcard */
if (strcmp(s, "*") == 0) return 1;
for (i = 0; s[i]; i++) {
if (! isascii(s[i])) {
return 0;
}
if (i == 0) { /* first char must be an alpha (or our special '@' identifier) */
if (! (isalpha(s[i]) || (s[i] == '@'))) {
return 0;
}
} else {
if (! (isalnum(s[i]) || (s[i] == '-'))) {
return 0;
}
}
}
return 1;
}
char *ldb_attr_casefold(void *mem_ctx, const char *s)
{
int i;
char *ret = talloc_strdup(mem_ctx, s);
if (!ret) {
errno = ENOMEM;
return NULL;
}
for (i = 0; ret[i]; i++) {
ret[i] = toupper((unsigned char)ret[i]);
}
return ret;
}
/*
we accept either 'dn' or 'distinguishedName' for a distinguishedName
*/
int ldb_attr_dn(const char *attr)
{
if (ldb_attr_cmp(attr, "dn") == 0 ||
ldb_attr_cmp(attr, "distinguishedName") == 0) {
return 0;
}
return -1;
}
+254
View File
@@ -0,0 +1,254 @@
/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
The GNU C 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.1 of the License, or (at your option) any later version.
The GNU C 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 the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* If you consider tuning this algorithm, you should consult first:
Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
/* Modified to be used in samba4 by
* Simo Sorce <idra@samba.org> 2005
*/
#include "includes.h"
#include "ldb/include/includes.h"
/* Byte-wise swap two items of size SIZE. */
#define SWAP(a, b, size) \
do \
{ \
register size_t __size = (size); \
register char *__a = (a), *__b = (b); \
do \
{ \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while (0)
/* Discontinue quicksort algorithm when partition gets below this size.
This particular magic number was chosen to work best on a Sun 4/260. */
#define MAX_THRESH 4
/* Stack node declarations used to store unfulfilled partition obligations. */
typedef struct
{
char *lo;
char *hi;
} stack_node;
/* The next 4 #defines implement a very fast in-line stack abstraction. */
/* The stack needs log (total_elements) entries (we could even subtract
log(MAX_THRESH)). Since total_elements has type size_t, we get as
upper bound for log (total_elements):
bits per byte (CHAR_BIT) * sizeof(size_t). */
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
#define STACK_NOT_EMPTY (stack < top)
/* Order size using quicksort. This implementation incorporates
four optimizations discussed in Sedgewick:
1. Non-recursive, using an explicit stack of pointer that store the
next array partition to sort. To save time, this maximum amount
of space required to store an array of SIZE_MAX is allocated on the
stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
Pretty cheap, actually.
2. Chose the pivot element using a median-of-three decision tree.
This reduces the probability of selecting a bad pivot value and
eliminates certain extraneous comparisons.
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
insertion sort to order the MAX_THRESH items within each partition.
This is a big win, since insertion sort is faster for small, mostly
sorted array segments.
4. The larger of the two sub-partitions is always pushed onto the
stack first, with the algorithm then concentrating on the
smaller partition. This *guarantees* no more than log (total_elems)
stack size is needed (actually O(1) in this case)! */
void ldb_qsort (void *const pbase, size_t total_elems, size_t size,
void *opaque, ldb_qsort_cmp_fn_t cmp)
{
register char *base_ptr = (char *) pbase;
const size_t max_thresh = MAX_THRESH * size;
if (total_elems == 0)
/* Avoid lossage with unsigned arithmetic below. */
return;
if (total_elems > MAX_THRESH)
{
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
stack_node stack[STACK_SIZE];
stack_node *top = stack;
PUSH (NULL, NULL);
while (STACK_NOT_EMPTY)
{
char *left_ptr;
char *right_ptr;
/* Select median value from among LO, MID, and HI. Rearrange
LO and HI so the three values are sorted. This lowers the
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR in
the while loops. */
char *mid = lo + size * ((hi - lo) / size >> 1);
if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
SWAP (mid, lo, size);
if ((*cmp) ((void *) hi, (void *) mid, opaque) < 0)
SWAP (mid, hi, size);
else
goto jump_over;
if ((*cmp) ((void *) mid, (void *) lo, opaque) < 0)
SWAP (mid, lo, size);
jump_over:;
left_ptr = lo + size;
right_ptr = hi - size;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while ((*cmp) ((void *) left_ptr, (void *) mid, opaque) < 0)
left_ptr += size;
while ((*cmp) ((void *) mid, (void *) right_ptr, opaque) < 0)
right_ptr -= size;
if (left_ptr < right_ptr)
{
SWAP (left_ptr, right_ptr, size);
if (mid == left_ptr)
mid = right_ptr;
else if (mid == right_ptr)
mid = left_ptr;
left_ptr += size;
right_ptr -= size;
}
else if (left_ptr == right_ptr)
{
left_ptr += size;
right_ptr -= size;
break;
}
}
while (left_ptr <= right_ptr);
/* Set up pointers for next iteration. First determine whether
left and right partitions are below the threshold size. If so,
ignore one or both. Otherwise, push the larger partition's
bounds on the stack and continue sorting the smaller one. */
if ((size_t) (right_ptr - lo) <= max_thresh)
{
if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore both small partitions. */
POP (lo, hi);
else
/* Ignore small left partition. */
lo = left_ptr;
}
else if ((size_t) (hi - left_ptr) <= max_thresh)
/* Ignore small right partition. */
hi = right_ptr;
else if ((right_ptr - lo) > (hi - left_ptr))
{
/* Push larger left partition indices. */
PUSH (lo, right_ptr);
lo = left_ptr;
}
else
{
/* Push larger right partition indices. */
PUSH (left_ptr, hi);
hi = right_ptr;
}
}
}
/* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient
for partitions below MAX_THRESH size. BASE_PTR points to the beginning
of the array to sort, and END_PTR points at the very last element in
the array (*not* one beyond it!). */
#define min(x, y) ((x) < (y) ? (x) : (y))
{
char *const end_ptr = &base_ptr[size * (total_elems - 1)];
char *tmp_ptr = base_ptr;
char *thresh = min(end_ptr, base_ptr + max_thresh);
register char *run_ptr;
/* Find smallest element in first threshold and place it at the
array's beginning. This is the smallest array element,
and the operation speeds up insertion sort's inner loop. */
for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr = run_ptr;
if (tmp_ptr != base_ptr)
SWAP (tmp_ptr, base_ptr, size);
/* Insertion sort, running from left-hand-side up to right-hand-side. */
run_ptr = base_ptr + size;
while ((run_ptr += size) <= end_ptr)
{
tmp_ptr = run_ptr - size;
while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, opaque) < 0)
tmp_ptr -= size;
tmp_ptr += size;
if (tmp_ptr != run_ptr)
{
char *trav;
trav = run_ptr + size;
while (--trav >= run_ptr)
{
char c = *trav;
char *hi, *lo;
for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
*hi = *lo;
*hi = c;
}
}
}
}
}