1
0
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:
Andrew Bartlett 2006-08-13 23:58:04 +00:00 committed by Gerald (Jerry) Carter
parent cf863ef3e3
commit 027583e6de
11 changed files with 3595 additions and 1517 deletions

View File

@ -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]

View 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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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__ */

View 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;
}

File diff suppressed because it is too large Load Diff

View 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);

View File

@ -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

View File

@ -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)");