mirror of
https://github.com/samba-team/samba.git
synced 2025-01-13 13:18:06 +03:00
parent
22ae788666
commit
f08fafc492
@ -1,7 +1,6 @@
|
||||
/*
|
||||
ldb database library
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
Copyright (C) Derrell Lipman 2005
|
||||
|
||||
** NOTE! The following LGPL license applies to the ldb
|
||||
@ -37,6 +36,7 @@
|
||||
#include "includes.h"
|
||||
#include "ldb/include/ldb.h"
|
||||
#include "ldb/include/ldb_private.h"
|
||||
#include "ldb/include/ldb_parse.h"
|
||||
#include "ldb/ldb_sqlite3/ldb_sqlite3.h"
|
||||
|
||||
#ifndef FALSE
|
||||
@ -294,124 +294,314 @@ lsqlite3_add_msg_attr(struct ldb_context *ldb,
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *
|
||||
lsqlite3_parsetree_to_sql(struct ldb_module *module,
|
||||
char * hTalloc,
|
||||
const struct ldb_parse_tree *t)
|
||||
{
|
||||
int i;
|
||||
char * child;
|
||||
char * p;
|
||||
char * ret = NULL;
|
||||
char * pAttrName;
|
||||
|
||||
|
||||
switch(t->operation) {
|
||||
case LDB_OP_SIMPLE:
|
||||
break;
|
||||
|
||||
case LDB_OP_AND:
|
||||
ret = lsqlite3_parsetree_to_sql(module,
|
||||
hTalloc,
|
||||
t->u.list.elements[0]);
|
||||
|
||||
for (i = 1; i < t->u.list.num_elements; i++) {
|
||||
child =
|
||||
lsqlite3_parsetree_to_sql(
|
||||
module,
|
||||
hTalloc,
|
||||
t->u.list.elements[i]);
|
||||
ret = talloc_asprintf_append(ret,
|
||||
"INTERSECT\n"
|
||||
"%s\n",
|
||||
child);
|
||||
talloc_free(child);
|
||||
}
|
||||
|
||||
child = ret;
|
||||
ret = talloc_asprintf("(\n"
|
||||
"%s\n"
|
||||
")\n",
|
||||
child);
|
||||
talloc_free(child);
|
||||
return ret;
|
||||
|
||||
case LDB_OP_OR:
|
||||
child =
|
||||
lsqlite3_parsetree_to_sql(
|
||||
module,
|
||||
hTalloc,
|
||||
t->u.list.elements[0]);
|
||||
|
||||
for (i = 1; i < t->u.list.num_elements; i++) {
|
||||
child =
|
||||
lsqlite3_parsetree_to_sql(
|
||||
module,
|
||||
hTalloc,
|
||||
t->u.list.elements[i]);
|
||||
ret = talloc_asprintf_append(ret,
|
||||
"UNION\n"
|
||||
"%s\n",
|
||||
child);
|
||||
talloc_free(child);
|
||||
}
|
||||
child = ret;
|
||||
ret = talloc_asprintf("(\n"
|
||||
"%s\n"
|
||||
")\n",
|
||||
child);
|
||||
talloc_free(child);
|
||||
return ret;
|
||||
|
||||
case LDB_OP_NOT:
|
||||
child =
|
||||
lsqlite3_parsetree_to_sql(
|
||||
module,
|
||||
hTalloc,
|
||||
t->u.not.child);
|
||||
ret = talloc_asprintf(hTalloc,
|
||||
"(\n"
|
||||
" SELECT eid\n"
|
||||
" FROM ldb_entry\n"
|
||||
" WHERE eid NOT IN %s\n"
|
||||
")\n",
|
||||
child);
|
||||
talloc_free(child);
|
||||
return ret;
|
||||
|
||||
default:
|
||||
/* should never occur */
|
||||
abort();
|
||||
};
|
||||
|
||||
/* Get a case-folded copy of the attribute name */
|
||||
pAttrName = ldb_casefold((struct ldb_context *) module,
|
||||
t->u.simple.attr);
|
||||
|
||||
/*
|
||||
* For simple searches, we want to retrieve the list of EIDs that
|
||||
* match the criteria. We accomplish this by searching the
|
||||
* appropriate table, ldb_attr_<attributeName>, for the eid
|
||||
* corresponding to all matching values.
|
||||
*/
|
||||
if (t->u.simple.value.length == 1 &&
|
||||
(*(const char *) t->u.simple.value.data) == '*') {
|
||||
/*
|
||||
* Special case for "attr_name=*". In this case, we want the
|
||||
* eid corresponding to all values in the specified attribute
|
||||
* table.
|
||||
*/
|
||||
if ((p = sqlite3_mprintf("(\n"
|
||||
" SELECT eid\n"
|
||||
" FROM ldb_attr_%q\n"
|
||||
")\n",
|
||||
pAttrName)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = talloc_strdup(hTalloc, p);
|
||||
sqlite3_free(p);
|
||||
|
||||
} else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) {
|
||||
/*
|
||||
* For object classes, we want to search for all objectclasses
|
||||
* that are subclasses as well.
|
||||
*/
|
||||
if ((p = sqlite3_mprintf(
|
||||
"(\n"
|
||||
" SELECT eid\n"
|
||||
" FROM ldb_attr_objectclass\n"
|
||||
" WHERE attr_name IN\n"
|
||||
" (SELECT class_name\n"
|
||||
" FROM ldb_objectclasses\n"
|
||||
" WHERE tree_key GLOB\n"
|
||||
" (SELECT tree_key\n"
|
||||
" FROM ldb_objectclasses\n"
|
||||
" WHERE class_name = %Q) || '*')\n"
|
||||
")\n",
|
||||
t->u.simple.value.data)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = talloc_strdup(hTalloc, p);
|
||||
sqlite3_free(p);
|
||||
|
||||
} else {
|
||||
/* A normal query. */
|
||||
if ((p = sqlite3_mprintf("(\n"
|
||||
" SELECT eid\n"
|
||||
" FROM ldb_attr_%q\n"
|
||||
" WHERE attr_value = %Q\n"
|
||||
")\n",
|
||||
pAttrName,
|
||||
t->u.simple.value.data)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = talloc_strdup(hTalloc, p);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
lsqlite3_parsetree_to_tablelist(struct ldb_module *module,
|
||||
char * hTalloc,
|
||||
const struct ldb_parse_tree *t)
|
||||
{
|
||||
#warning "obtain talloc'ed array of attribute names for table list"
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* search for matching records
|
||||
*/
|
||||
static int
|
||||
lsqlite3_search(struct ldb_module *module,
|
||||
const char *base,
|
||||
lsqlite3_search(struct ldb_module * module,
|
||||
const char * pBaseDN,
|
||||
enum ldb_scope scope,
|
||||
const char *expression,
|
||||
const char * pExpression,
|
||||
const char * const attrs[],
|
||||
struct ldb_message ***res)
|
||||
struct ldb_message *** res)
|
||||
{
|
||||
#warning "lsqlite3_search() not yet implemented"
|
||||
#if 0
|
||||
int count;
|
||||
int msg_count;
|
||||
struct ldb_context * ldb = module->ldb;
|
||||
struct lsqlite3_private * lsqlite3 = module->private_data;
|
||||
|
||||
if (base == NULL) {
|
||||
base = "";
|
||||
int ret;
|
||||
int bLoop;
|
||||
long long eid;
|
||||
char * sql;
|
||||
char * sql_constraints;
|
||||
char * table_list;
|
||||
char * hTalloc;
|
||||
const char * pTail;
|
||||
sqlite3_stmt * pStmt;
|
||||
struct ldb_parse_tree * pTree;
|
||||
struct lsqlite3_private * lsqlite3 = module->private_data;
|
||||
|
||||
if (pBaseDN == NULL) {
|
||||
pBaseDN = "";
|
||||
}
|
||||
|
||||
lsqlite3->last_rc = ldap_search_s(lsqlite3->ldap, base, (int)scope,
|
||||
expression,
|
||||
discard_const_p(char *, attrs),
|
||||
0, &ldapres);
|
||||
if (lsqlite3->last_rc != LDAP_SUCCESS) {
|
||||
/*
|
||||
* Obtain the eid of the base DN
|
||||
*/
|
||||
if ((pTail = sqlite3_mprintf("SELECT eid "
|
||||
" FROM ldb_attr_dn "
|
||||
" WHERE attr_value = %Q;",
|
||||
pBaseDN)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (bLoop = TRUE; bLoop; ) {
|
||||
|
||||
/* Compile the SQL statement into sqlite virtual machine */
|
||||
if ((ret = sqlite3_prepare(lsqlite3->sqlite,
|
||||
pTail,
|
||||
-1,
|
||||
&pStmt,
|
||||
&pTail)) != SQLITE_OK) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* One row expected */
|
||||
if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) {
|
||||
(void) sqlite3_finalize(pStmt);
|
||||
continue;
|
||||
} else if (ret != SQLITE_ROW) {
|
||||
(void) sqlite3_finalize(pStmt);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Retrieve the EID */
|
||||
eid = sqlite3_column_int64(pStmt, 0);
|
||||
|
||||
/* Free the virtual machine */
|
||||
if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) {
|
||||
(void) sqlite3_finalize(pStmt);
|
||||
continue;
|
||||
} else if (ret != SQLITE_OK) {
|
||||
(void) sqlite3_finalize(pStmt);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Normal condition is only one time through loop. Loop is
|
||||
* rerun in error conditions, via "continue", above.
|
||||
*/
|
||||
ret = 0;
|
||||
bLoop = FALSE;
|
||||
}
|
||||
|
||||
/* Parse the filter expression into a tree we can work with */
|
||||
if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate a temporary talloc context */
|
||||
hTalloc = talloc_new(module);
|
||||
|
||||
count = ldap_count_entries(lsqlite3->ldap, ldapres);
|
||||
if (count == -1 || count == 0) {
|
||||
ldap_msgfree(ldapres);
|
||||
return count;
|
||||
}
|
||||
/* Move the parse tree to our temporary context */
|
||||
talloc_steal(hTalloc, pTree);
|
||||
|
||||
/* Convert filter into a series of SQL statements (constraints) */
|
||||
sql_constraints = lsqlite3_parsetree_to_sql(module, hTalloc, pTree);
|
||||
|
||||
/* Get the list of attribute names to use as our extra table list */
|
||||
table_list = lsqlite3_parsetree_to_tablelist(module, hTalloc, pTree);
|
||||
|
||||
(*res) = talloc_array(lsqlite3, struct ldb_message *, count+1);
|
||||
if (! *res) {
|
||||
ldap_msgfree(ldapres);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
switch(scope) {
|
||||
case LDB_SCOPE_DEFAULT:
|
||||
case LDB_SCOPE_SUBTREE:
|
||||
sql = sqlite3_mprintf(
|
||||
"SELECT entry.entry_data\n"
|
||||
" FROM ldb_entry AS entry\n"
|
||||
" WHERE entry.eid IN\n"
|
||||
" (SELECT ldb_entry.eid\n"
|
||||
" FROM ldb_entry,\n"
|
||||
" ldb_descendants,\n"
|
||||
" %q\n"
|
||||
" WHERE ldb_descendants.aeid = %lld\n"
|
||||
" AND ldb_entry.eid = ldb_descendants.deid\n"
|
||||
" AND ldap_entry.eid IN\n"
|
||||
"%s);",
|
||||
table_list,
|
||||
sql_constraints);
|
||||
break;
|
||||
|
||||
(*res)[0] = NULL;
|
||||
#warning "scope BASE and ONLEVEL not yet implemented"
|
||||
case LDB_SCOPE_BASE:
|
||||
break;
|
||||
|
||||
msg_count = 0;
|
||||
case LDB_SCOPE_ONELEVEL:
|
||||
break;
|
||||
}
|
||||
|
||||
/* loop over all messages */
|
||||
for (msg=ldap_first_entry(lsqlite3->ldap, ldapres);
|
||||
msg;
|
||||
msg=ldap_next_entry(lsqlite3->ldap, msg)) {
|
||||
BerElement *berptr = NULL;
|
||||
char *attr, *dn;
|
||||
|
||||
if (msg_count == count) {
|
||||
/* hmm, got too many? */
|
||||
ldb_debug(ldb, LDB_DEBUG_FATAL, "Fatal: ldap message count inconsistent\n");
|
||||
break;
|
||||
}
|
||||
|
||||
(*res)[msg_count] = talloc(*res, struct ldb_message);
|
||||
if (!(*res)[msg_count]) {
|
||||
goto failed;
|
||||
}
|
||||
(*res)[msg_count+1] = NULL;
|
||||
|
||||
dn = ldap_get_dn(lsqlite3->ldap, msg);
|
||||
if (!dn) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
(*res)[msg_count]->dn = talloc_strdup((*res)[msg_count], dn);
|
||||
ldap_memfree(dn);
|
||||
if (!(*res)[msg_count]->dn) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
(*res)[msg_count]->num_elements = 0;
|
||||
(*res)[msg_count]->elements = NULL;
|
||||
(*res)[msg_count]->private_data = NULL;
|
||||
|
||||
/* loop over all attributes */
|
||||
for (attr=ldap_first_attribute(lsqlite3->ldap, msg, &berptr);
|
||||
attr;
|
||||
attr=ldap_next_attribute(lsqlite3->ldap, msg, berptr)) {
|
||||
struct berval **bval;
|
||||
bval = ldap_get_values_len(lsqlite3->ldap, msg, attr);
|
||||
|
||||
if (bval) {
|
||||
lsqlite3_add_msg_attr(ldb, (*res)[msg_count], attr, bval);
|
||||
ldap_value_free_len(bval);
|
||||
}
|
||||
|
||||
ldap_memfree(attr);
|
||||
}
|
||||
if (berptr) ber_free(berptr, 0);
|
||||
|
||||
msg_count++;
|
||||
}
|
||||
|
||||
ldap_msgfree(ldapres);
|
||||
|
||||
return msg_count;
|
||||
|
||||
failed:
|
||||
if (*res) lsqlite3_search_free(module, *res);
|
||||
return -1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
lsqlite3_new_attr(struct lsqlite3_private * lsqlite3,
|
||||
lsqlite3_new_attr(struct ldb_module * module,
|
||||
char * pAttrName)
|
||||
{
|
||||
struct lsqlite3_private * lsqlite3 = module->private_data;
|
||||
|
||||
/* Get a case-folded copy of the attribute name */
|
||||
pAttrName = ldb_casefold((struct ldb_context *) module, pAttrName);
|
||||
|
||||
QUERY_NOROWS(lsqlite3,
|
||||
FALSE,
|
||||
"CREATE TABLE ldb_attr_%q "
|
||||
@ -429,12 +619,13 @@ lsqlite3_new_attr(struct lsqlite3_private * lsqlite3,
|
||||
* requests in the ldb_message
|
||||
*/
|
||||
static int
|
||||
lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
const struct ldb_message *msg,
|
||||
lsqlite3_msg_to_sql(struct ldb_module * module,
|
||||
const struct ldb_message * msg,
|
||||
long long eid,
|
||||
int use_flags)
|
||||
{
|
||||
int flags;
|
||||
char * pAttrName;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
struct lsqlite3_private * lsqlite3 = module->private_data;
|
||||
@ -450,7 +641,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
|
||||
if (flags == LDB_FLAG_MOD_ADD) {
|
||||
/* Create the attribute table if it doesn't exist */
|
||||
if (lsqlite3_new_attr(lsqlite3, el->name) != 0) {
|
||||
if (lsqlite3_new_attr(module, el->name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -458,6 +649,10 @@ lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
/* For each value of the specified attribute name... */
|
||||
for (j = 0; j < el->num_values; j++) {
|
||||
|
||||
/* Get a case-folded copy of the attribute name */
|
||||
pAttrName = ldb_casefold((struct ldb_context *) module,
|
||||
el->name);
|
||||
|
||||
/* ... bind the attribute value, if necessary */
|
||||
switch (flags) {
|
||||
case LDB_FLAG_MOD_ADD:
|
||||
@ -467,6 +662,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
" (eid, attr_value) "
|
||||
" VALUES "
|
||||
" (%lld, %Q);",
|
||||
pAttrName,
|
||||
eid, el->values[j].data);
|
||||
QUERY_NOROWS(lsqlite3,
|
||||
FALSE,
|
||||
@ -486,6 +682,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
"UPDATE ldb_attr_%q "
|
||||
" SET attr_value = %Q "
|
||||
" WHERE eid = %lld;",
|
||||
pAttrName,
|
||||
el->values[j].data,
|
||||
eid);
|
||||
QUERY_NOROWS(lsqlite3,
|
||||
@ -506,6 +703,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module,
|
||||
"DELETE FROM ldb_attr_%q "
|
||||
" WHERE eid = %lld "
|
||||
" AND attr_value = %Q;",
|
||||
pAttrName,
|
||||
eid,
|
||||
el->values[j].data);
|
||||
QUERY_NOROWS(lsqlite3,
|
||||
@ -903,16 +1101,11 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3,
|
||||
;
|
||||
|
||||
/* Skip protocol indicator of url */
|
||||
if (strchr(url, ':')) {
|
||||
if (strncmp(url, "sqlite://", 9) != 0) {
|
||||
errno = EINVAL;
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
p = url + 9;
|
||||
} else {
|
||||
p = url;
|
||||
}
|
||||
|
||||
if ((p = strchr(url, ':')) == NULL) {
|
||||
return SQLITE_MISUSE;
|
||||
} else {
|
||||
++p;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we'll be creating a new database, or opening an existing one
|
||||
|
Loading…
Reference in New Issue
Block a user