mirror of
https://github.com/samba-team/samba.git
synced 2025-01-10 01:18:15 +03:00
r17525: This is a merge from the Google Summer of Code 2006 project by Martin Kühl
<mkhl@samba.org>.
Martin took over the work done last year by Jelmer, in last year's
SoC. This was a substanital task, as the the ldb modules API changed
significantly during the past year, with the addition of async calls.
This changeset reimplements and enables the ldb_map ldb module and
adapts the example module and test case, both named samba3sam, to the
implementation.
The ldb_map module supports splitting an ldb database into two parts
(called the "local" and "remote" part) and storing the data in one of
them (the remote database) in a different format while the other acts
as a fallback.
This allows ldb to e.g. store to and load data from a remote LDAP
server and present it according to the Samba4 schema while still
allowing the LDAP to present and modify its data separately.
A complex example of this is the samba3sam module (by Jelmer
Vernooij), which maps data between the samba3 and samba4 schemas.
A simpler example is given by the entryUUID module (by Andrew
Bartlett), which handles some of the differences between AD and
OpenLDAP in operational attributes. It principally maps objectGUID,
to and from entryUUID elements. This is also an example of a module
that doesn't use the local backend as fallback storage.
This merge also splits the ldb_map.c file into smaller, more
manageable parts.
(This used to be commit af2bece4d3
)
This commit is contained in:
parent
cf863ef3e3
commit
027583e6de
@ -33,6 +33,18 @@ OBJ_FILES = \
|
||||
# End MODULE ldb_samldb
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE ldb_entryUUID
|
||||
[MODULE::ldb_entryUUID]
|
||||
SUBSYSTEM = ldb
|
||||
INIT_FUNCTION = ldb_entryUUID_module_init
|
||||
ENABLE = YES
|
||||
OBJ_FILES = \
|
||||
entryUUID.o
|
||||
#
|
||||
# End MODULE ldb_entryUUID
|
||||
################################################
|
||||
|
||||
# ################################################
|
||||
# # Start MODULE ldb_proxy
|
||||
# [MODULE::ldb_proxy]
|
||||
|
182
source4/dsdb/samdb/ldb_modules/entryUUID.c
Normal file
182
source4/dsdb/samdb/ldb_modules/entryUUID.c
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
ldb database module
|
||||
|
||||
LDAP semantics mapping module
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
This module relies on ldb_map to do all the real work, but performs
|
||||
some of the trivial mappings between AD semantics and that provided
|
||||
by OpenLDAP and similar servers.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb/include/ldb.h"
|
||||
#include "ldb/include/ldb_private.h"
|
||||
#include "ldb/include/ldb_errors.h"
|
||||
#include "ldb/modules/ldb_map.h"
|
||||
|
||||
#include "librpc/gen_ndr/ndr_misc.h"
|
||||
#include "librpc/ndr/libndr.h"
|
||||
|
||||
static struct ldb_val encode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
|
||||
{
|
||||
struct GUID guid;
|
||||
NTSTATUS status = GUID_from_string((char *)val->data, &guid);
|
||||
struct ldb_val out = data_blob(NULL, 0);
|
||||
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return out;
|
||||
}
|
||||
status = ndr_push_struct_blob(&out, ctx, &guid,
|
||||
(ndr_push_flags_fn_t)ndr_push_GUID);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return out;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static struct ldb_val decode_guid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
|
||||
{
|
||||
struct GUID *guid;
|
||||
NTSTATUS status;
|
||||
struct ldb_val out = data_blob(NULL, 0);
|
||||
|
||||
guid = talloc(ctx, struct GUID);
|
||||
if (guid == NULL) {
|
||||
return out;
|
||||
}
|
||||
status = ndr_pull_struct_blob(val, guid, guid,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_GUID);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
talloc_free(guid);
|
||||
return out;
|
||||
}
|
||||
out = data_blob_string_const(GUID_string(ctx, guid));
|
||||
talloc_free(guid);
|
||||
return out;
|
||||
}
|
||||
|
||||
/* The backend holds binary sids, so just copy them back */
|
||||
static struct ldb_val sid_copy(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
|
||||
{
|
||||
struct ldb_val out = data_blob(NULL, 0);
|
||||
ldb_handler_copy(module->ldb, ctx, val, &out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Ensure we always convert sids into binary, so the backend doesn't have to know about both forms */
|
||||
static struct ldb_val sid_always_binary(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val)
|
||||
{
|
||||
struct ldb_val out = data_blob(NULL, 0);
|
||||
const struct ldb_attrib_handler *handler = ldb_attrib_handler(module->ldb, "objectSid");
|
||||
|
||||
if (handler->canonicalise_fn(module->ldb, ctx, val, &out) != LDB_SUCCESS) {
|
||||
return data_blob(NULL, 0);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const struct ldb_map_attribute entryUUID_attributes[] =
|
||||
{
|
||||
/* objectGUID */
|
||||
{
|
||||
.local_name = "objectGUID",
|
||||
.type = MAP_CONVERT,
|
||||
.u = {
|
||||
.convert = {
|
||||
.remote_name = "entryUUID",
|
||||
.convert_local = decode_guid,
|
||||
.convert_remote = encode_guid,
|
||||
},
|
||||
},
|
||||
},
|
||||
/* objectSid */
|
||||
{
|
||||
.local_name = "objectSid",
|
||||
.type = MAP_CONVERT,
|
||||
.u = {
|
||||
.convert = {
|
||||
.remote_name = "objectSid",
|
||||
.convert_local = sid_always_binary,
|
||||
.convert_remote = sid_copy,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.local_name = "whenCreated",
|
||||
.type = MAP_RENAME,
|
||||
.u = {
|
||||
.rename = {
|
||||
.remote_name = "createTimestamp"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
.local_name = "whenChanged",
|
||||
.type = MAP_RENAME,
|
||||
.u = {
|
||||
.rename = {
|
||||
.remote_name = "modifyTimestamp"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
.local_name = "*",
|
||||
.type = MAP_KEEP,
|
||||
},
|
||||
{
|
||||
.local_name = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
/* the context init function */
|
||||
static int entryUUID_init(struct ldb_module *module)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ldb_map_init(module, entryUUID_attributes, NULL, NULL);
|
||||
if (ret != LDB_SUCCESS)
|
||||
return ret;
|
||||
|
||||
return ldb_next_init(module);
|
||||
}
|
||||
|
||||
static struct ldb_module_ops entryUUID_ops = {
|
||||
.name = "entryUUID",
|
||||
.init_context = entryUUID_init,
|
||||
};
|
||||
|
||||
/* the init function */
|
||||
int ldb_entryUUID_module_init(void)
|
||||
{
|
||||
struct ldb_module_ops ops = ldb_map_get_ops();
|
||||
entryUUID_ops.add = ops.add;
|
||||
entryUUID_ops.modify = ops.modify;
|
||||
entryUUID_ops.del = ops.del;
|
||||
entryUUID_ops.rename = ops.rename;
|
||||
entryUUID_ops.search = ops.search;
|
||||
entryUUID_ops.wait = ops.wait;
|
||||
|
||||
return ldb_register_module(&entryUUID_ops);
|
||||
}
|
@ -5,11 +5,17 @@
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb/modules/ldb_map.h"
|
||||
#include "ldb/include/ldb.h"
|
||||
#include "ldb/include/ldb_private.h"
|
||||
#include "ldb/include/ldb_errors.h"
|
||||
#include "ldb/modules/ldb_map.h"
|
||||
#include "system/passwd.h"
|
||||
|
||||
#include "librpc/gen_ndr/ndr_security.h"
|
||||
#include "librpc/ndr/libndr.h"
|
||||
#include "libcli/security/security.h"
|
||||
#include "libcli/security/proto.h"
|
||||
|
||||
/*
|
||||
* sambaSID -> member (dn!)
|
||||
* sambaSIDList -> member (dn!)
|
||||
@ -855,8 +861,33 @@ const struct ldb_map_attribute samba3_attributes[] =
|
||||
}
|
||||
};
|
||||
|
||||
/* the context init function */
|
||||
static int samba3sam_init(struct ldb_module *module)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ldb_map_init(module, samba3_attributes, samba3_objectclasses, "samba3sam");
|
||||
if (ret != LDB_SUCCESS)
|
||||
return ret;
|
||||
|
||||
return ldb_next_init(module);
|
||||
}
|
||||
|
||||
static struct ldb_module_ops samba3sam_ops = {
|
||||
.name = "samba3sam",
|
||||
.init_context = samba3sam_init,
|
||||
};
|
||||
|
||||
/* the init function */
|
||||
int ldb_samba3sam_module_init(void)
|
||||
{
|
||||
return ldb_map_init(ldb, samba3_attributes, samba3_objectclasses, "samba3sam");
|
||||
struct ldb_module_ops ops = ldb_map_get_ops();
|
||||
samba3sam_ops.add = ops.add;
|
||||
samba3sam_ops.modify = ops.modify;
|
||||
samba3sam_ops.del = ops.del;
|
||||
samba3sam_ops.rename = ops.rename;
|
||||
samba3sam_ops.search = ops.search;
|
||||
samba3sam_ops.wait = ops.wait;
|
||||
|
||||
return ldb_register_module(&samba3sam_ops);
|
||||
}
|
||||
|
@ -81,13 +81,16 @@ PUBLIC_DEPENDENCIES = \
|
||||
# End MODULE ldb_ildap
|
||||
################################################
|
||||
|
||||
# ################################################
|
||||
# # Start MODULE ldb_map
|
||||
# [SUBSYSTEM::ldb_map]
|
||||
# PUBLIC_DEPENDENCIES = ldb
|
||||
# OBJ_FILES = modules/ldb_map.o
|
||||
# # End MODULE ldb_map
|
||||
# ################################################
|
||||
################################################
|
||||
# Start MODULE ldb_map
|
||||
[MODULE::ldb_map]
|
||||
SUBSYSTEM = ldb
|
||||
OBJ_FILES = \
|
||||
modules/ldb_map_inbound.o \
|
||||
modules/ldb_map_outbound.o \
|
||||
modules/ldb_map.o
|
||||
# End MODULE ldb_map
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start MODULE ldb_skel
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,8 @@
|
||||
ldb database library - map backend
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
Development sponsored by the Google Summer of Code program
|
||||
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
|
||||
Development sponsored by the Google Summer of Code program
|
||||
|
||||
** NOTE! The following LGPL license applies to the ldb
|
||||
** library. This does NOT imply that all of Samba is released
|
||||
@ -15,12 +16,12 @@
|
||||
|
||||
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
|
||||
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
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LDB_MAP_H__
|
||||
@ -39,10 +40,21 @@
|
||||
* while returning too many attributes in ldb_search() doesn't)
|
||||
*/
|
||||
|
||||
|
||||
/* Name of the internal attribute pointing from the local to the
|
||||
* remote part of a record */
|
||||
#define IS_MAPPED "isMapped"
|
||||
|
||||
|
||||
struct ldb_map_context;
|
||||
|
||||
struct ldb_map_attribute
|
||||
{
|
||||
/* convert a local ldb_val to a remote ldb_val */
|
||||
typedef struct ldb_val (*ldb_map_convert_func) (struct ldb_module *module, void *mem_ctx, const struct ldb_val *val);
|
||||
|
||||
#define LDB_MAP_MAX_REMOTE_NAMES 10
|
||||
|
||||
/* map from local to remote attribute */
|
||||
struct ldb_map_attribute {
|
||||
const char *local_name; /* local name */
|
||||
|
||||
enum ldb_map_attr_type {
|
||||
@ -55,8 +67,8 @@ struct ldb_map_attribute
|
||||
multiple remote attributes. */
|
||||
} type;
|
||||
|
||||
/* if set, will be called for expressions that contain this attribute */
|
||||
struct ldb_parse_tree *(*convert_operator) (struct ldb_map_context *, TALLOC_CTX *ctx, const struct ldb_parse_tree *);
|
||||
/* if set, will be called for search expressions that contain this attribute */
|
||||
struct ldb_parse_tree *(*convert_operator)(const struct ldb_map_context *, TALLOC_CTX *ctx, const struct ldb_parse_tree *);
|
||||
|
||||
union {
|
||||
struct {
|
||||
@ -65,43 +77,46 @@ struct ldb_map_attribute
|
||||
|
||||
struct {
|
||||
const char *remote_name;
|
||||
struct ldb_val (*convert_local) (struct ldb_module *, TALLOC_CTX *, const struct ldb_val *);
|
||||
|
||||
|
||||
/* Convert local to remote data */
|
||||
ldb_map_convert_func convert_local;
|
||||
|
||||
/* Convert remote to local data */
|
||||
/* an entry can have convert_remote set to NULL, as long as there as an entry with the same local_name
|
||||
* that is non-NULL before it. */
|
||||
struct ldb_val (*convert_remote) (struct ldb_module *, TALLOC_CTX *, const struct ldb_val *);
|
||||
ldb_map_convert_func convert_remote;
|
||||
} convert;
|
||||
|
||||
struct {
|
||||
/* Generate the local attribute from remote message */
|
||||
struct ldb_message_element *(*generate_local) (
|
||||
struct ldb_module *,
|
||||
TALLOC_CTX *ctx,
|
||||
const char *attr,
|
||||
const struct ldb_message *remote);
|
||||
struct ldb_message_element *(*generate_local)(struct ldb_module *, TALLOC_CTX *mem_ctx, const char *remote_attr, const struct ldb_message *remote);
|
||||
|
||||
/* Update remote message with information from local message */
|
||||
void (*generate_remote) (
|
||||
struct ldb_module *,
|
||||
const char *local_attr,
|
||||
const struct ldb_message *local,
|
||||
struct ldb_message *remote_mp,
|
||||
struct ldb_message *remote_fb);
|
||||
void (*generate_remote)(struct ldb_module *, const char *local_attr, const struct ldb_message *old, struct ldb_message *remote, struct ldb_message *local);
|
||||
|
||||
/* Name(s) for this attribute on the remote server. This is an array since
|
||||
* one local attribute's data can be split up into several attributes
|
||||
* remotely */
|
||||
#define LDB_MAP_MAX_REMOTE_NAMES 10
|
||||
const char *remote_names[LDB_MAP_MAX_REMOTE_NAMES];
|
||||
|
||||
/* Names of additional remote attributes
|
||||
* required for the generation. NULL
|
||||
* indicates that `local_attr' suffices. */
|
||||
/*
|
||||
#define LDB_MAP_MAX_SELF_ATTRIBUTES 10
|
||||
const char *self_attrs[LDB_MAP_MAX_SELF_ATTRIBUTES];
|
||||
*/
|
||||
} generate;
|
||||
} u;
|
||||
};
|
||||
|
||||
#define LDB_MAP_MAX_SUBCLASSES 10
|
||||
#define LDB_MAP_MAX_MUSTS 10
|
||||
#define LDB_MAP_MAX_MAYS 50
|
||||
struct ldb_map_objectclass
|
||||
{
|
||||
|
||||
#define LDB_MAP_MAX_SUBCLASSES 10
|
||||
#define LDB_MAP_MAX_MUSTS 10
|
||||
#define LDB_MAP_MAX_MAYS 50
|
||||
|
||||
/* map from local to remote objectClass */
|
||||
struct ldb_map_objectclass {
|
||||
const char *local_name;
|
||||
const char *remote_name;
|
||||
const char *base_classes[LDB_MAP_MAX_SUBCLASSES];
|
||||
@ -109,12 +124,26 @@ struct ldb_map_objectclass
|
||||
const char *mays[LDB_MAP_MAX_MAYS];
|
||||
};
|
||||
|
||||
struct ldb_map_context
|
||||
{
|
||||
|
||||
/* private context data */
|
||||
struct ldb_map_context {
|
||||
struct ldb_map_attribute *attribute_maps;
|
||||
/* NOTE: Always declare base classes first here */
|
||||
const struct ldb_map_objectclass *objectclass_maps;
|
||||
struct ldb_context *mapped_ldb;
|
||||
/* struct ldb_context *mapped_ldb; */
|
||||
const struct ldb_dn *local_base_dn;
|
||||
const struct ldb_dn *remote_base_dn;
|
||||
};
|
||||
|
||||
/* initialization function */
|
||||
int
|
||||
ldb_map_init(struct ldb_module *module,
|
||||
const struct ldb_map_attribute *attrs,
|
||||
const struct ldb_map_objectclass *ocls,
|
||||
const char *name);
|
||||
|
||||
/* get copy of map_ops */
|
||||
struct ldb_module_ops
|
||||
ldb_map_get_ops(void);
|
||||
|
||||
#endif /* __LDB_MAP_H__ */
|
||||
|
724
source4/lib/ldb/modules/ldb_map_inbound.c
Normal file
724
source4/lib/ldb/modules/ldb_map_inbound.c
Normal file
@ -0,0 +1,724 @@
|
||||
/*
|
||||
ldb database mapping module
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
|
||||
|
||||
* NOTICE: this module is NOT released under the GNU LGPL license as
|
||||
* other ldb code. This module is release under the GNU GPL v2 or
|
||||
* later license.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "ldb/include/includes.h"
|
||||
|
||||
#include "ldb/modules/ldb_map.h"
|
||||
#include "ldb/modules/ldb_map_private.h"
|
||||
|
||||
|
||||
/* Mapping message elements
|
||||
* ======================== */
|
||||
|
||||
/* Map a message element into the remote partition. */
|
||||
static struct ldb_message_element *ldb_msg_el_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, const struct ldb_message_element *old)
|
||||
{
|
||||
struct ldb_message_element *el;
|
||||
int i;
|
||||
|
||||
el = talloc_zero(mem_ctx, struct ldb_message_element);
|
||||
if (el == NULL) {
|
||||
map_oom(module);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
el->num_values = old->num_values;
|
||||
el->values = talloc_array(el, struct ldb_val, el->num_values);
|
||||
if (el->values == NULL) {
|
||||
talloc_free(el);
|
||||
map_oom(module);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
el->name = map_attr_map_local(el, map, old->name);
|
||||
|
||||
for (i = 0; i < el->num_values; i++) {
|
||||
el->values[i] = ldb_val_map_local(module, el->values, map, old->values[i]);
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/* Add a message element either to a local or to a remote message,
|
||||
* depending on whether it goes into the local or remote partition. */
|
||||
static int ldb_msg_el_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg, const char *attr_name, /* const char * const names[], */ const struct ldb_message_element *old)
|
||||
{
|
||||
const struct ldb_map_context *data = map_get_context(module);
|
||||
const struct ldb_map_attribute *map = map_attr_find_local(data, attr_name);
|
||||
struct ldb_message_element *el;
|
||||
|
||||
/* Unknown attribute: ignore */
|
||||
if (map == NULL) {
|
||||
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
|
||||
"Not mapping attribute '%s': no mapping found\n",
|
||||
old->name);
|
||||
goto local;
|
||||
}
|
||||
|
||||
switch (map->type) {
|
||||
case MAP_IGNORE:
|
||||
goto local;
|
||||
|
||||
case MAP_CONVERT:
|
||||
if (map->u.convert.convert_local == NULL) {
|
||||
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
|
||||
"Not mapping attribute '%s': "
|
||||
"'convert_local' not set\n",
|
||||
map->local_name);
|
||||
goto local;
|
||||
}
|
||||
/* fall through */
|
||||
case MAP_KEEP:
|
||||
case MAP_RENAME:
|
||||
el = ldb_msg_el_map_local(module, remote, map, old);
|
||||
break;
|
||||
|
||||
case MAP_GENERATE:
|
||||
if (map->u.generate.generate_remote == NULL) {
|
||||
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
|
||||
"Not mapping attribute '%s': "
|
||||
"'generate_remote' not set\n",
|
||||
map->local_name);
|
||||
goto local;
|
||||
}
|
||||
|
||||
/* TODO: if this attr requires context:
|
||||
* make sure all context attrs are mappable (in 'names')
|
||||
* make sure all context attrs have already been mapped?
|
||||
* maybe postpone generation until they have been mapped?
|
||||
*/
|
||||
|
||||
map->u.generate.generate_remote(module, map->local_name, msg, remote, local);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (el == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ldb_msg_add(remote, el, old->flags);
|
||||
|
||||
local:
|
||||
el = talloc(local, struct ldb_message_element);
|
||||
if (el == NULL) {
|
||||
map_oom(module);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*el = *old; /* copy the old element */
|
||||
|
||||
return ldb_msg_add(local, el, old->flags);
|
||||
}
|
||||
|
||||
/* Mapping messages
|
||||
* ================ */
|
||||
|
||||
/* Check whether a message will be (partially) mapped into the remote partition. */
|
||||
static BOOL ldb_msg_check_remote(struct ldb_module *module, const struct ldb_message *msg)
|
||||
{
|
||||
const struct ldb_map_context *data = map_get_context(module);
|
||||
BOOL ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < msg->num_elements; i++) {
|
||||
ret = map_attr_check_remote(data, msg->elements[i].name);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Split message elements that stay in the local partition from those
|
||||
* that are mapped into the remote partition. */
|
||||
static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *local, struct ldb_message *remote, const struct ldb_message *msg)
|
||||
{
|
||||
/* const char * const names[]; */
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < msg->num_elements; i++) {
|
||||
/* Skip 'IS_MAPPED' */
|
||||
if (ldb_attr_cmp(msg->elements[i].name, IS_MAPPED) == 0) {
|
||||
ldb_debug(module->ldb, LDB_DEBUG_WARNING, "ldb_map: "
|
||||
"Skipping attribute '%s'\n",
|
||||
msg->elements[i].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = ldb_msg_el_partition(module, local, remote, msg, msg->elements[i].name, &msg->elements[i]);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Inbound requests: add, modify, rename, delete
|
||||
* ============================================= */
|
||||
|
||||
/* Add the remote record. */
|
||||
int map_add_do_remote(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
|
||||
|
||||
ac->step = MAP_ADD_REMOTE;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_remote_request(ac->module, ac->remote_req);
|
||||
}
|
||||
|
||||
/* Add the local record. */
|
||||
int map_add_do_local(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
|
||||
|
||||
ac->step = MAP_ADD_LOCAL;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_request(ac->module, ac->local_req);
|
||||
}
|
||||
|
||||
/* Add a record. */
|
||||
int map_add(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
const struct ldb_message *msg = req->op.add.message;
|
||||
struct ldb_handle *h;
|
||||
struct map_context *ac;
|
||||
struct ldb_message *local, *remote;
|
||||
const char *dn;
|
||||
|
||||
/* Do not manipulate our control entries */
|
||||
if (ldb_dn_is_special(msg->dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
|
||||
if (!ldb_dn_check_local(module, msg->dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping needed, fail */
|
||||
if (!ldb_msg_check_remote(module, msg)) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Prepare context and handle */
|
||||
h = map_init_handle(req, module);
|
||||
if (h == NULL) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac = talloc_get_type(h->private_data, struct map_context);
|
||||
|
||||
/* Prepare the local operation */
|
||||
ac->local_req = talloc(ac, struct ldb_request);
|
||||
if (ac->local_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->local_req) = *req; /* copy the request */
|
||||
|
||||
ac->local_req->context = NULL;
|
||||
ac->local_req->callback = NULL;
|
||||
|
||||
/* Prepare the remote operation */
|
||||
ac->remote_req = talloc(ac, struct ldb_request);
|
||||
if (ac->remote_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->remote_req) = *req; /* copy the request */
|
||||
|
||||
ac->remote_req->context = NULL;
|
||||
ac->remote_req->callback = NULL;
|
||||
|
||||
/* Prepare the local message */
|
||||
local = ldb_msg_new(ac->local_req);
|
||||
if (local == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
local->dn = msg->dn;
|
||||
|
||||
/* Prepare the remote message */
|
||||
remote = ldb_msg_new(ac->remote_req);
|
||||
if (remote == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
|
||||
|
||||
/* Split local from remote message */
|
||||
ldb_msg_partition(module, local, remote, msg);
|
||||
ac->local_req->op.add.message = local;
|
||||
ac->remote_req->op.add.message = remote;
|
||||
|
||||
if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
|
||||
/* No local data or db, just run the remote request */
|
||||
talloc_free(ac->local_req);
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return map_add_do_remote(h);
|
||||
}
|
||||
|
||||
/* Store remote DN in 'IS_MAPPED' */
|
||||
/* TODO: use GUIDs here instead */
|
||||
dn = ldb_dn_linearize(local, remote->dn);
|
||||
if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return map_add_do_local(h);
|
||||
|
||||
oom:
|
||||
map_oom(module);
|
||||
failed:
|
||||
talloc_free(h);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Modify the remote record. */
|
||||
int map_modify_do_remote(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
|
||||
|
||||
ac->step = MAP_MODIFY_REMOTE;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_remote_request(ac->module, ac->remote_req);
|
||||
}
|
||||
|
||||
/* Modify the local record. */
|
||||
int map_modify_do_local(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
struct ldb_message *msg;
|
||||
char *dn;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
if (ac->local_dn == NULL) {
|
||||
/* No local record present, add it instead */
|
||||
msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
|
||||
|
||||
/* Add local 'IS_MAPPED' */
|
||||
/* TODO: use GUIDs here instead */
|
||||
dn = ldb_dn_linearize(msg, ac->remote_req->op.mod.message->dn);
|
||||
if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD) != 0) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Turn request into 'add' */
|
||||
ac->local_req->operation = LDB_ADD;
|
||||
ac->local_req->op.add.message = msg;
|
||||
/* TODO: Could I just leave msg in there? I think so,
|
||||
* but it looks clearer this way. */
|
||||
}
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
|
||||
|
||||
ac->step = MAP_MODIFY_LOCAL;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_request(ac->module, ac->local_req);
|
||||
}
|
||||
|
||||
/* Modify a record. */
|
||||
int map_modify(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
const struct ldb_message *msg = req->op.mod.message;
|
||||
struct ldb_handle *h;
|
||||
struct map_context *ac;
|
||||
struct ldb_message *local, *remote;
|
||||
|
||||
/* Do not manipulate our control entries */
|
||||
if (ldb_dn_is_special(msg->dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
|
||||
if (!ldb_dn_check_local(module, msg->dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping needed, skip to next module */
|
||||
/* TODO: What if the remote part exists, the local doesn't,
|
||||
* and this request wants to modify local data and thus
|
||||
* add the local record? */
|
||||
if (!ldb_msg_check_remote(module, msg)) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Prepare context and handle */
|
||||
h = map_init_handle(req, module);
|
||||
if (h == NULL) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac = talloc_get_type(h->private_data, struct map_context);
|
||||
|
||||
/* Prepare the local operation */
|
||||
ac->local_req = talloc(ac, struct ldb_request);
|
||||
if (ac->local_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->local_req) = *req; /* copy the request */
|
||||
|
||||
ac->local_req->context = NULL;
|
||||
ac->local_req->callback = NULL;
|
||||
|
||||
/* Prepare the remote operation */
|
||||
ac->remote_req = talloc(ac, struct ldb_request);
|
||||
if (ac->remote_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->remote_req) = *req; /* copy the request */
|
||||
|
||||
ac->remote_req->context = NULL;
|
||||
ac->remote_req->callback = NULL;
|
||||
|
||||
/* Prepare the local message */
|
||||
local = ldb_msg_new(ac->local_req);
|
||||
if (local == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
local->dn = msg->dn;
|
||||
|
||||
/* Prepare the remote message */
|
||||
remote = ldb_msg_new(ac->remote_req);
|
||||
if (remote == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
|
||||
|
||||
/* Split local from remote message */
|
||||
ldb_msg_partition(module, local, remote, msg);
|
||||
ac->local_req->op.mod.message = local;
|
||||
ac->remote_req->op.mod.message = remote;
|
||||
|
||||
if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
|
||||
/* No local data or db, just run the remote request */
|
||||
talloc_free(ac->local_req);
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return map_modify_do_remote(h);
|
||||
}
|
||||
|
||||
/* prepare the search operation */
|
||||
ac->search_req = map_search_self_req(ac, msg->dn);
|
||||
if (ac->search_req == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ac->step = MAP_SEARCH_SELF_MODIFY;
|
||||
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return ldb_next_request(module, ac->search_req);
|
||||
|
||||
oom:
|
||||
map_oom(module);
|
||||
failed:
|
||||
talloc_free(h);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Delete the remote record. */
|
||||
int map_delete_do_remote(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
|
||||
|
||||
ac->step = MAP_DELETE_REMOTE;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_remote_request(ac->module, ac->remote_req);
|
||||
}
|
||||
|
||||
/* Delete the local record. */
|
||||
int map_delete_do_local(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
/* No local record, continue remotely */
|
||||
if (ac->local_dn == NULL) {
|
||||
return map_delete_do_remote(handle);
|
||||
}
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
|
||||
|
||||
ac->step = MAP_DELETE_LOCAL;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_request(ac->module, ac->local_req);
|
||||
}
|
||||
|
||||
/* Delete a record. */
|
||||
int map_delete(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
struct ldb_handle *h;
|
||||
struct map_context *ac;
|
||||
|
||||
/* Do not manipulate our control entries */
|
||||
if (ldb_dn_is_special(req->op.del.dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
|
||||
if (!ldb_dn_check_local(module, req->op.del.dn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* Prepare context and handle */
|
||||
h = map_init_handle(req, module);
|
||||
if (h == NULL) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac = talloc_get_type(h->private_data, struct map_context);
|
||||
|
||||
/* Prepare the local operation */
|
||||
ac->local_req = talloc(ac, struct ldb_request);
|
||||
if (ac->local_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->local_req) = *req; /* copy the request */
|
||||
ac->local_req->op.del.dn = req->op.del.dn;
|
||||
|
||||
ac->local_req->context = NULL;
|
||||
ac->local_req->callback = NULL;
|
||||
|
||||
/* Prepare the remote operation */
|
||||
ac->remote_req = talloc(ac, struct ldb_request);
|
||||
if (ac->remote_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->remote_req) = *req; /* copy the request */
|
||||
ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
|
||||
|
||||
/* No local db, just run the remote request */
|
||||
if (!map_check_local_db(ac->module)) {
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return map_delete_do_remote(h);
|
||||
}
|
||||
|
||||
ac->remote_req->context = NULL;
|
||||
ac->remote_req->callback = NULL;
|
||||
|
||||
/* Prepare the search operation */
|
||||
ac->search_req = map_search_self_req(ac, req->op.del.dn);
|
||||
if (ac->search_req == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
|
||||
ac->step = MAP_SEARCH_SELF_DELETE;
|
||||
|
||||
return ldb_next_request(module, ac->search_req);
|
||||
|
||||
oom:
|
||||
map_oom(module);
|
||||
failed:
|
||||
talloc_free(h);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Rename the remote record. */
|
||||
int map_rename_do_remote(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
|
||||
|
||||
ac->step = MAP_RENAME_REMOTE;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_remote_request(ac->module, ac->remote_req);
|
||||
}
|
||||
|
||||
/* Update the local 'IS_MAPPED' attribute. */
|
||||
int map_rename_do_fixup(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
|
||||
|
||||
ac->step = MAP_RENAME_FIXUP;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_request(ac->module, ac->down_req);
|
||||
}
|
||||
|
||||
/* Rename the local record. */
|
||||
int map_rename_do_local(struct ldb_handle *handle)
|
||||
{
|
||||
struct map_context *ac;
|
||||
|
||||
ac = talloc_get_type(handle->private_data, struct map_context);
|
||||
|
||||
/* No local record, continue remotely */
|
||||
if (ac->local_dn == NULL) {
|
||||
return map_rename_do_remote(handle);
|
||||
}
|
||||
|
||||
ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
|
||||
|
||||
ac->step = MAP_RENAME_LOCAL;
|
||||
|
||||
handle->state = LDB_ASYNC_INIT;
|
||||
handle->status = LDB_SUCCESS;
|
||||
|
||||
return ldb_next_request(ac->module, ac->local_req);
|
||||
}
|
||||
|
||||
/* Rename a record. */
|
||||
int map_rename(struct ldb_module *module, struct ldb_request *req)
|
||||
{
|
||||
struct ldb_handle *h;
|
||||
struct map_context *ac;
|
||||
|
||||
/* Do not manipulate our control entries */
|
||||
if (ldb_dn_is_special(req->op.rename.olddn)) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* No mapping requested (perhaps no DN mapping specified), skip to next module */
|
||||
if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
|
||||
(!ldb_dn_check_local(module, req->op.rename.newdn))) {
|
||||
return ldb_next_request(module, req);
|
||||
}
|
||||
|
||||
/* Rename into/out of the mapped partition requested, bail out */
|
||||
if (!ldb_dn_check_local(module, req->op.rename.olddn) ||
|
||||
!ldb_dn_check_local(module, req->op.rename.newdn)) {
|
||||
return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
|
||||
}
|
||||
|
||||
/* Prepare context and handle */
|
||||
h = map_init_handle(req, module);
|
||||
if (h == NULL) {
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
||||
ac = talloc_get_type(h->private_data, struct map_context);
|
||||
|
||||
/* Prepare the local operation */
|
||||
ac->local_req = talloc(ac, struct ldb_request);
|
||||
if (ac->local_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->local_req) = *req; /* copy the request */
|
||||
ac->local_req->op.rename.olddn = req->op.rename.olddn;
|
||||
ac->local_req->op.rename.newdn = req->op.rename.newdn;
|
||||
|
||||
ac->local_req->context = NULL;
|
||||
ac->local_req->callback = NULL;
|
||||
|
||||
/* Prepare the remote operation */
|
||||
ac->remote_req = talloc(ac, struct ldb_request);
|
||||
if (ac->remote_req == NULL) {
|
||||
goto oom;
|
||||
}
|
||||
|
||||
*(ac->remote_req) = *req; /* copy the request */
|
||||
ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
|
||||
ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
|
||||
|
||||
ac->remote_req->context = NULL;
|
||||
ac->remote_req->callback = NULL;
|
||||
|
||||
/* No local db, just run the remote request */
|
||||
if (!map_check_local_db(ac->module)) {
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
return map_rename_do_remote(h);
|
||||
}
|
||||
|
||||
/* Prepare the fixup operation */
|
||||
/* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
|
||||
ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
|
||||
if (ac->down_req == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Prepare the search operation */
|
||||
ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
|
||||
if (ac->search_req == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
req->handle = h; /* return our own handle to deal with this call */
|
||||
|
||||
ac->step = MAP_SEARCH_SELF_RENAME;
|
||||
|
||||
return ldb_next_request(module, ac->search_req);
|
||||
|
||||
oom:
|
||||
map_oom(module);
|
||||
failed:
|
||||
talloc_free(h);
|
||||
return LDB_ERR_OPERATIONS_ERROR;
|
||||
}
|
1134
source4/lib/ldb/modules/ldb_map_outbound.c
Normal file
1134
source4/lib/ldb/modules/ldb_map_outbound.c
Normal file
File diff suppressed because it is too large
Load Diff
118
source4/lib/ldb/modules/ldb_map_private.h
Normal file
118
source4/lib/ldb/modules/ldb_map_private.h
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
/* A handy macro to report Out of Memory conditions */
|
||||
#define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
|
||||
|
||||
/* The type of search callback functions */
|
||||
typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *);
|
||||
|
||||
/* The special DN from which the local and remote base DNs are fetched */
|
||||
#define MAP_DN_NAME "@MAP"
|
||||
#define MAP_DN_FROM "@FROM"
|
||||
#define MAP_DN_TO "@TO"
|
||||
|
||||
/* Private data structures
|
||||
* ======================= */
|
||||
|
||||
/* Global private data */
|
||||
struct map_private {
|
||||
struct ldb_map_context context;
|
||||
};
|
||||
|
||||
/* Context data for mapped requests */
|
||||
struct map_context {
|
||||
enum map_step {
|
||||
MAP_SEARCH_REMOTE,
|
||||
MAP_ADD_REMOTE,
|
||||
MAP_ADD_LOCAL,
|
||||
MAP_SEARCH_SELF_MODIFY,
|
||||
MAP_MODIFY_REMOTE,
|
||||
MAP_MODIFY_LOCAL,
|
||||
MAP_SEARCH_SELF_DELETE,
|
||||
MAP_DELETE_REMOTE,
|
||||
MAP_DELETE_LOCAL,
|
||||
MAP_SEARCH_SELF_RENAME,
|
||||
MAP_RENAME_REMOTE,
|
||||
MAP_RENAME_FIXUP,
|
||||
MAP_RENAME_LOCAL
|
||||
} step;
|
||||
|
||||
struct ldb_module *module;
|
||||
|
||||
const struct ldb_dn *local_dn;
|
||||
const struct ldb_parse_tree *local_tree;
|
||||
const char * const *local_attrs;
|
||||
|
||||
struct ldb_request *orig_req;
|
||||
struct ldb_request *local_req;
|
||||
struct ldb_request *remote_req;
|
||||
struct ldb_request *down_req;
|
||||
struct ldb_request *search_req;
|
||||
|
||||
/* for search, we may have a lot of contexts */
|
||||
int num_searches;
|
||||
struct ldb_request **search_reqs;
|
||||
};
|
||||
|
||||
/* Context data for mapped search requests */
|
||||
struct map_search_context {
|
||||
struct map_context *ac;
|
||||
struct ldb_reply *local_res;
|
||||
struct ldb_reply *remote_res;
|
||||
};
|
||||
|
||||
|
||||
/* Common operations
|
||||
* ================= */
|
||||
|
||||
/* The following definitions come from lib/ldb/modules/ldb_map.c */
|
||||
const struct ldb_map_context *map_get_context(struct ldb_module *module);
|
||||
struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares);
|
||||
struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module);
|
||||
|
||||
int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request);
|
||||
|
||||
BOOL map_check_local_db(struct ldb_module *module);
|
||||
BOOL map_attr_check_remote(const struct ldb_map_context *data, const char *attr);
|
||||
BOOL ldb_dn_check_local(struct ldb_module *module, const struct ldb_dn *dn);
|
||||
|
||||
const struct ldb_map_attribute *map_attr_find_local(const struct ldb_map_context *data, const char *name);
|
||||
const struct ldb_map_attribute *map_attr_find_remote(const struct ldb_map_context *data, const char *name);
|
||||
|
||||
const char *map_attr_map_local(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
|
||||
const char *map_attr_map_remote(void *mem_ctx, const struct ldb_map_attribute *map, const char *attr);
|
||||
|
||||
struct ldb_val ldb_val_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val);
|
||||
struct ldb_val ldb_val_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_map_attribute *map, struct ldb_val val);
|
||||
|
||||
struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
|
||||
struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
|
||||
struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, const struct ldb_dn *dn);
|
||||
|
||||
struct ldb_request *map_search_base_req(struct map_context *ac, const struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback);
|
||||
struct ldb_request *map_search_self_req(struct map_context *ac, const struct ldb_dn *dn);
|
||||
struct ldb_request *map_build_fixup_req(struct map_context *ac, const struct ldb_dn *olddn, const struct ldb_dn *newdn);
|
||||
|
||||
|
||||
/* LDB Requests
|
||||
* ============ */
|
||||
|
||||
/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */
|
||||
int map_add_do_remote(struct ldb_handle *handle);
|
||||
int map_add_do_local(struct ldb_handle *handle);
|
||||
int map_add(struct ldb_module *module, struct ldb_request *req);
|
||||
|
||||
int map_modify_do_remote(struct ldb_handle *handle);
|
||||
int map_modify_do_local(struct ldb_handle *handle);
|
||||
int map_modify(struct ldb_module *module, struct ldb_request *req);
|
||||
|
||||
int map_delete_do_remote(struct ldb_handle *handle);
|
||||
int map_delete_do_local(struct ldb_handle *handle);
|
||||
int map_delete(struct ldb_module *module, struct ldb_request *req);
|
||||
|
||||
int map_rename_do_remote(struct ldb_handle *handle);
|
||||
int map_rename_do_fixup(struct ldb_handle *handle);
|
||||
int map_rename_do_local(struct ldb_handle *handle);
|
||||
int map_rename(struct ldb_module *module, struct ldb_request *req);
|
||||
|
||||
/* The following definitions come from lib/ldb/modules/ldb_map_outbound.c */
|
||||
int map_search(struct ldb_module *module, struct ldb_request *req);
|
38
testdata/samba3/samba3.ldif
vendored
38
testdata/samba3/samba3.ldif
vendored
@ -1,19 +1,19 @@
|
||||
dn: sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: sambaDomainName=TESTS,${BASEDN}
|
||||
objectclass: sambaDomain
|
||||
objectclass: top
|
||||
sambaSID: S-1-5-21-4231626423-2410014848-2360679739
|
||||
sambaNextRid: 2000
|
||||
sambaDomainName: TESTS
|
||||
|
||||
dn: ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: ou=Users,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: organizationalUnit
|
||||
ou: Users
|
||||
|
||||
dn: ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: organizationalUnit
|
||||
ou: Groups
|
||||
|
||||
dn: uid=nobody,ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: uid=nobody,ou=Users,sambaDomainName=TESTS,${BASEDN}
|
||||
cn: nobody
|
||||
sn: nobody
|
||||
objectClass: inetOrgPerson
|
||||
@ -40,7 +40,7 @@ sambaAcctFlags: [NU ]
|
||||
sambaSID: S-1-5-21-4231626423-2410014848-2360679739-2998
|
||||
loginShell: /bin/false
|
||||
|
||||
dn: cn=Domain Admins,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Domain Admins,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 512
|
||||
@ -51,7 +51,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-512
|
||||
sambaGroupType: 2
|
||||
displayName: Domain Admins
|
||||
|
||||
dn: cn=Domain Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Domain Users,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 513
|
||||
@ -61,7 +61,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-513
|
||||
sambaGroupType: 2
|
||||
displayName: Domain Users
|
||||
|
||||
dn: cn=Domain Guests,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Domain Guests,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 514
|
||||
@ -71,7 +71,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-514
|
||||
sambaGroupType: 2
|
||||
displayName: Domain Guests
|
||||
|
||||
dn: cn=Print Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Print Operators,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 550
|
||||
@ -81,7 +81,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-550
|
||||
sambaGroupType: 2
|
||||
displayName: Print Operators
|
||||
|
||||
dn: cn=Backup Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Backup Operators,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 551
|
||||
@ -91,7 +91,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-551
|
||||
sambaGroupType: 2
|
||||
displayName: Backup Operators
|
||||
|
||||
dn: cn=Replicator,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Replicator,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 552
|
||||
@ -101,7 +101,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552
|
||||
sambaGroupType: 2
|
||||
displayName: Replicator
|
||||
|
||||
dn: cn=Domain Computers,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Domain Computers,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 553
|
||||
@ -111,7 +111,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-553
|
||||
sambaGroupType: 2
|
||||
displayName: Domain Computers
|
||||
|
||||
dn: cn=Administrators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Administrators,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 544
|
||||
@ -121,7 +121,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-544
|
||||
sambaGroupType: 2
|
||||
displayName: Administrators
|
||||
|
||||
dn: cn=Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Users,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 545
|
||||
@ -131,7 +131,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-545
|
||||
sambaGroupType: 2
|
||||
displayName: users
|
||||
|
||||
dn: cn=Guests,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Guests,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 546
|
||||
@ -142,7 +142,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-546
|
||||
sambaGroupType: 2
|
||||
displayName: Guests
|
||||
|
||||
dn: cn=Power Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Power Users,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 547
|
||||
@ -152,7 +152,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-547
|
||||
sambaGroupType: 2
|
||||
displayName: Power Users
|
||||
|
||||
dn: cn=Account Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Account Operators,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 548
|
||||
@ -162,7 +162,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-548
|
||||
sambaGroupType: 2
|
||||
displayName: Account Operators
|
||||
|
||||
dn: cn=Server Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: cn=Server Operators,ou=Groups,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: posixGroup
|
||||
objectClass: sambaGroupMapping
|
||||
gidNumber: 549
|
||||
@ -172,11 +172,11 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-549
|
||||
sambaGroupType: 2
|
||||
displayName: Server Operators
|
||||
|
||||
dn: ou=Computers,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: ou=Computers,sambaDomainName=TESTS,${BASEDN}
|
||||
objectClass: organizationalUnit
|
||||
ou: Computers
|
||||
|
||||
dn: uid=Administrator,ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl
|
||||
dn: uid=Administrator,ou=Users,sambaDomainName=TESTS,${BASEDN}
|
||||
cn: Administrator
|
||||
sn: Administrator
|
||||
objectClass: inetOrgPerson
|
||||
|
@ -8,75 +8,92 @@ libinclude("base.js");
|
||||
var mypath = substr(ARGV[0], 0, -strlen("samba3sam"));
|
||||
|
||||
var sys = sys_init();
|
||||
var s3url;
|
||||
var s3url = "tdb://samba3.ldb";
|
||||
var s4url = "tdb://samba4.ldb";
|
||||
var s3 = ldb_init();
|
||||
var s4 = ldb_init();
|
||||
var msg;
|
||||
var ok;
|
||||
|
||||
if (ARGV.length == 2) {
|
||||
s3url = ARGV[1];
|
||||
ok = s3.connect(s3url);
|
||||
assert(ok);
|
||||
} else {
|
||||
s3url = "tdb://samba3.ldb";
|
||||
sys.unlink("samba3.ldb");
|
||||
println("Adding samba3 LDIF...");
|
||||
var s3 = ldb_init();
|
||||
ok = s3.connect(s3url);
|
||||
assert(ok);
|
||||
var ldif = sys.file_load(mypath + "../../testdata/samba3/samba3.ldif");
|
||||
assert(ldif != undefined);
|
||||
ok = s3.add(ldif);
|
||||
assert(ok);
|
||||
}
|
||||
var local = new Object();
|
||||
local.BASEDN = "dc=vernstok,dc=nl";
|
||||
var remote = new Object();
|
||||
remote.BASEDN = "CN=Samba3Sam," + local.BASEDN;
|
||||
|
||||
var prt_ldif = sprintf("dn: @PARTITION
|
||||
partition: %s:%s
|
||||
partition: %s:%s", remote.BASEDN, s3url, local.BASEDN, s4url);
|
||||
|
||||
var map_ldif = sprintf("dn: @MAP=samba3sam
|
||||
@FROM: %s
|
||||
@TO: %s", local.BASEDN, remote.BASEDN);
|
||||
|
||||
var mod_ldif = "dn: @MODULES
|
||||
@LIST: rootdse,paged_results,server_sort,extended_dn,asq,samldb,objectclass,password_hash,operational,objectguid,rdn_name,samba3sam,partition";
|
||||
|
||||
sys.unlink("samba3.ldb");
|
||||
ok = s3.connect(s3url);
|
||||
assert(ok);
|
||||
|
||||
println("Initial samba3 LDIF...");
|
||||
var path = "../../testdata/samba3/samba3.ldif"
|
||||
var ldif = sys.file_load(mypath + path);
|
||||
ldif = substitute_var(ldif, remote);
|
||||
assert(ldif != undefined);
|
||||
ok = s3.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
println("Initial samba4 LDIF...");
|
||||
var s4 = ldb_init();
|
||||
sys.unlink("samba4.ldb");
|
||||
ok = s4.connect("tdb://samba4.ldb");
|
||||
assert(ok);
|
||||
|
||||
var ldif = sys.file_load(mypath + "../../source/setup/provision_init.ldif");
|
||||
println("Initial samba4 LDIF...");
|
||||
var path = "../../source/setup/provision_init.ldif";
|
||||
var ldif = sys.file_load(mypath + path);
|
||||
ldif = substitute_var(ldif, local);
|
||||
assert(ldif != undefined);
|
||||
ok = s4.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
var ldif = sys.file_load(mypath + "../../source/setup/provision_templates.ldif");
|
||||
var subobj = new Object();
|
||||
subobj.BASEDN = "dc=vernstok,dc=nl";
|
||||
ldif = substitute_var(ldif, subobj);
|
||||
var path = "../../source/setup/provision_templates.ldif";
|
||||
var ldif = sys.file_load(mypath + path);
|
||||
ldif = substitute_var(ldif, local);
|
||||
assert(ldif != undefined);
|
||||
ok = s4.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
|
||||
|
||||
ok = s4.add(sprintf("dn: @MAP=samba3sam
|
||||
@MAP_URL: %s", s3url));
|
||||
println("Registering partitions...");
|
||||
var ldif = substitute_var(prt_ldif, local);
|
||||
assert(ldif != undefined);
|
||||
ok = s4.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
ok = s4.modify("
|
||||
dn: @MODULES
|
||||
replace: @LIST
|
||||
@LIST: samldb,timestamps,objectguid,rdn_name,samba3sam");
|
||||
println("Registering mapping...");
|
||||
var ldif = substitute_var(map_ldif, local);
|
||||
assert(ldif != undefined);
|
||||
ok = s4.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
println("Reconnecting to LDB database");
|
||||
println("Registering modules...");
|
||||
var ldif = substitute_var(mod_ldif, local);
|
||||
assert(ldif != undefined);
|
||||
ok = s4.add(ldif);
|
||||
assert(ok);
|
||||
|
||||
println("Reconnecting to LDB database...");
|
||||
s4 = ldb_init();
|
||||
ok = s4.connect("tdb://samba4.ldb");
|
||||
ok = s4.connect(s4url);
|
||||
assert(ok);
|
||||
|
||||
msg = s4.search("(ou=Users)");
|
||||
assert(msg.length == 1);
|
||||
|
||||
println("Looking up by non-mapped attribute");
|
||||
msg = s4.search("(cn=Administrator)");
|
||||
assert(msg[0].cn == "Administrator");
|
||||
assert(msg.length == 1);
|
||||
assert(msg[0].cn == "Administrator");
|
||||
|
||||
println("Looking up by mapped attribute");
|
||||
msg = s4.search("(name=Backup Operators)");
|
||||
assert(msg[0].name == "Backup Operators");
|
||||
assert(msg.length == 1);
|
||||
assert(msg[0].name == "Backup Operators");
|
||||
|
||||
println("Looking up by old name of renamed attribute");
|
||||
msg = s4.search("(displayName=Backup Operators)");
|
||||
@ -88,8 +105,9 @@ assert(msg.length == 1);
|
||||
assert(msg[0].dn == "cn=Replicator,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl");
|
||||
assert(msg[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552");
|
||||
|
||||
println("Checking mapping of objectclass");
|
||||
var oc = msg[0].objectclass;
|
||||
println("Checking mapping of objectClass");
|
||||
var oc = msg[0].objectClass;
|
||||
assert(oc != undefined);
|
||||
for (var i in oc) {
|
||||
assert(oc[i] == "posixGroup" || oc[i] == "group");
|
||||
}
|
||||
@ -104,8 +122,13 @@ showInAdvancedViewOnly: TRUE
|
||||
");
|
||||
assert(ok);
|
||||
|
||||
println("Checking for existance of record");
|
||||
println("Checking for existence of record (local)");
|
||||
/* TODO: This record must be searched in the local database, which is currently only supported for base searches
|
||||
msg = s4.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly'));
|
||||
TODO: Actually, this version should work as well but doesn't...
|
||||
msg = s4.search("(cn=Foo)", "dc=idealx,dc=org", s4.LDB_SCOPE_SUBTREE new Array('foo','blah','cn','showInAdvancedViewOnly'));
|
||||
*/
|
||||
msg = s4.search("", "cn=Foo,dc=idealx,dc=org", s4.LDB_SCOPE_BASE new Array('foo','blah','cn','showInAdvancedViewOnly'));
|
||||
assert(msg.length == 1);
|
||||
assert(msg[0].showInAdvancedViewOnly == "TRUE");
|
||||
assert(msg[0].foo == "bar");
|
||||
@ -121,10 +144,24 @@ cn: Niemand
|
||||
");
|
||||
assert(ok);
|
||||
|
||||
println("Checking for existance of record (mapped)");
|
||||
msg = s4.search("(unixName=bin)", new Array('unixName','cn','dn'));
|
||||
println("Checking for existence of record (remote)");
|
||||
msg = s4.search("(unixName=bin)", new Array('unixName','cn','dn', 'unicodePwd'));
|
||||
assert(msg.length == 1);
|
||||
assert(msg[0].cn == "Niemand");
|
||||
assert(msg[0].unicodePwd == "geheim");
|
||||
|
||||
println("Checking for existence of record (local && remote)");
|
||||
msg = s4.search("(&(unixName=bin)(unicodePwd=geheim))", new Array('unixName','cn','dn', 'unicodePwd'));
|
||||
assert(msg.length == 1); // TODO: should check with more records
|
||||
assert(msg[0].cn == "Niemand");
|
||||
assert(msg[0].unixName == "bin");
|
||||
assert(msg[0].unicodePwd == "geheim");
|
||||
|
||||
println("Checking for existence of record (local || remote)");
|
||||
msg = s4.search("(|(unixName=bin)(unicodePwd=geheim))", new Array('unixName','cn','dn', 'unicodePwd'));
|
||||
assert(msg.length == 1); // TODO: should check with more records
|
||||
assert(msg[0].cn == "Niemand");
|
||||
assert(msg[0].unixName == "bin" || msg[0].unicodePwd == "geheim");
|
||||
|
||||
println("Checking for data in destination database");
|
||||
msg = s3.search("(cn=Niemand)");
|
||||
|
Loading…
Reference in New Issue
Block a user