From f9447d2a17089178d311e03e398c25c749450f6d Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 30 Aug 2005 11:08:03 +0000 Subject: r9786: Move ldb_map into ldb/modules/ Move samba3sam to dsdb/ (This used to be commit eb9d615bcd49328131613f64745760a90553b7f2) --- source4/dsdb/config.mk | 10 + source4/dsdb/samdb/ldb_modules/samba3sam.c | 631 +++++++++++++++ source4/lib/ldb/config.mk | 5 +- source4/lib/ldb/ldb_map/README | 29 - source4/lib/ldb/ldb_map/ldb_map.c | 1151 ---------------------------- source4/lib/ldb/ldb_map/ldb_map.h | 108 --- source4/lib/ldb/modules/ldb_map.c | 1151 ++++++++++++++++++++++++++++ source4/lib/ldb/modules/ldb_map.h | 108 +++ source4/lib/ldb/samba/samba3sam.c | 631 --------------- source4/lib/ldb/tests/samba3.ldif | 200 ----- source4/lib/samba3/PLAN | 3 +- source4/setup/upgrade | 0 12 files changed, 1904 insertions(+), 2123 deletions(-) create mode 100644 source4/dsdb/samdb/ldb_modules/samba3sam.c delete mode 100644 source4/lib/ldb/ldb_map/README delete mode 100644 source4/lib/ldb/ldb_map/ldb_map.c delete mode 100644 source4/lib/ldb/ldb_map/ldb_map.h create mode 100644 source4/lib/ldb/modules/ldb_map.c create mode 100644 source4/lib/ldb/modules/ldb_map.h delete mode 100644 source4/lib/ldb/samba/samba3sam.c delete mode 100644 source4/lib/ldb/tests/samba3.ldif mode change 100644 => 100755 source4/setup/upgrade (limited to 'source4') diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index 8f66eab39c..0b03d221ba 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -21,6 +21,16 @@ INIT_OBJ_FILES = \ # End MODULE libldb_samldb ################################################ +################################################ +# Start MODULE libldb_samba3sam +[MODULE::libldb_samba3sam] +SUBSYSTEM = LIBLDB +INIT_OBJ_FILES = \ + dsdb/samdb/ldb_modules/samba3sam.o +# +# End MODULE libldb_samldb +################################################ + ################################################ # Start SUBSYSTEM SAMDB [SUBSYSTEM::SAMDB] diff --git a/source4/dsdb/samdb/ldb_modules/samba3sam.c b/source4/dsdb/samdb/ldb_modules/samba3sam.c new file mode 100644 index 0000000000..444d7e8d12 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/samba3sam.c @@ -0,0 +1,631 @@ +/* + ldb database library - Samba3 SAM compatibility backend + + Copyright (C) Jelmer Vernooij 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "includes.h" +#include "ldb/modules/ldb_map.h" +#include "ldb/include/ldb.h" +#include "ldb/include/ldb_private.h" + +/* FIXME: + * sambaSID -> member (dn!) + * sambaSIDList -> member (dn!) + * sambaDomainName -> name + * sambaTrustPassword + * sambaUnixIdPool + * sambaIdmapEntry + * sambaAccountPolicy + * sambaSidEntry + * sambaAcctFlags -> systemFlags ? + * sambaPasswordHistory -> ntPwdHistory*/ + +/* Not necessary: + * sambaConfig + * sambaShare + * sambaConfigOption + * sambaNextGroupRid + * sambaNextUserRid + * sambaAlgorithmicRidBase + */ + +/* Not in Samba4: + * sambaKickoffTime + * sambaPwdCanChange + * sambaPwdMustChange + * sambaHomePath + * sambaHomeDrive + * sambaLogonScript + * sambaProfilePath + * sambaUserWorkstations + * sambaMungedDial + * sambaLogonHours */ + +/* In Samba4 but not in Samba3: +*/ + +static struct ldb_val convert_sid_rid(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + printf("Converting SID TO RID *\n"); + + return ldb_val_dup(ctx, val); +} + +static struct ldb_val convert_rid_sid(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + printf("Converting RID TO SID *\n"); + + return ldb_val_dup(ctx, val); +} + +static struct ldb_val convert_unix_id2name(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + printf("Converting UNIX ID to name\n"); + + return ldb_val_dup(ctx, val); +} + +static struct ldb_val convert_unix_name2id(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + printf("Converting UNIX name to ID\n"); + + return ldb_val_dup(ctx, val); +} + +const struct ldb_map_objectclass samba3_objectclasses[] = { + { "group", "sambaGroupMapping" }, + { "user", "sambaSAMAccount" }, + { "domain", "sambaDomain" }, + { NULL, NULL } +}; + +const struct ldb_map_attribute samba3_attributes[] = +{ + /* sambaNextRid -> nextRid */ + { + .local_name = "nextRid", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaNextRid", + }, + + /* sambaBadPasswordTime -> badPasswordtime*/ + { + .local_name = "badPasswordTime", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaBadPasswordTime", + }, + + /* sambaLMPassword -> lmPwdHash*/ + { + .local_name = "lmPwdHash", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaLMPassword", + }, + + /* sambaGroupType -> groupType */ + { + .local_name = "groupType", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaGroupType", + }, + + /* sambaNTPassword -> ntPwdHash*/ + { + .local_name = "badPwdCount", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaNTPassword", + }, + + /* sambaPrimaryGroupSID -> primaryGroupID */ + { + .local_name = "primaryGroupID", + .type = MAP_CONVERT, + .u.convert.remote_name = "sambaPrimaryGroupSID", + .u.convert.convert_local = convert_rid_sid, + .u.convert.convert_remote = convert_sid_rid, + }, + + /* sambaBadPasswordCount -> badPwdCount */ + { + .local_name = "badPwdCount", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaBadPasswordCount", + }, + + /* sambaLogonTime -> lastLogon*/ + { + .local_name = "lastLogon", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaLogonTime", + }, + + /* sambaLogoffTime -> lastLogoff*/ + { + .local_name = "lastLogoff", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaLogoffTime", + }, + + /* gidNumber -> unixName */ + { + .local_name = "unixName", + .type = MAP_CONVERT, + .u.convert.remote_name = "gidNumber", + .u.convert.convert_local = convert_unix_name2id, + .u.convert.convert_remote = convert_unix_id2name, + }, + + /* uid -> unixName */ + { + .local_name = "unixName", + .type = MAP_CONVERT, + .u.convert.remote_name = "uid", + .u.convert.convert_local = convert_unix_name2id, + .u.convert.convert_remote = convert_unix_id2name, + }, + + /* displayName -> name */ + { + .local_name = "name", + .type = MAP_RENAME, + .u.rename.remote_name = "displayName", + }, + + /* cn */ + { + .local_name = "cn", + .type = MAP_KEEP, + }, + + /* sAMAccountName -> cn */ + { + .local_name = "sAMAccountName", + .type = MAP_RENAME, + .u.rename.remote_name = "uid", + }, + + /* objectCategory */ + { + .local_name = "objectCategory", + .type = MAP_IGNORE, + }, + + /* objectGUID */ + { + .local_name = "objectGUID", + .type = MAP_IGNORE, + }, + + /* objectVersion */ + { + .local_name = "objectVersion", + .type = MAP_IGNORE, + }, + + /* codePage */ + { + .local_name = "codePage", + .type = MAP_IGNORE, + }, + + /* dNSHostName */ + { + .local_name = "dNSHostName", + .type = MAP_IGNORE, + }, + + + /* dnsDomain */ + { + .local_name = "dnsDomain", + .type = MAP_IGNORE, + }, + + /* dnsRoot */ + { + .local_name = "dnsRoot", + .type = MAP_IGNORE, + }, + + /* countryCode */ + { + .local_name = "countryCode", + .type = MAP_IGNORE, + }, + + /* nTMixedDomain */ + { + .local_name = "nTMixedDomain", + .type = MAP_IGNORE, + }, + + /* operatingSystem */ + { + .local_name = "operatingSystem", + .type = MAP_IGNORE, + }, + + /* operatingSystemVersion */ + { + .local_name = "operatingSystemVersion", + .type = MAP_IGNORE, + }, + + + /* servicePrincipalName */ + { + .local_name = "servicePrincipalName", + .type = MAP_IGNORE, + }, + + /* msDS-Behavior-Version */ + { + .local_name = "msDS-Behavior-Version", + .type = MAP_IGNORE, + }, + + /* msDS-KeyVersionNumber */ + { + .local_name = "msDS-KeyVersionNumber", + .type = MAP_IGNORE, + }, + + /* msDs-masteredBy */ + { + .local_name = "msDs-masteredBy", + .type = MAP_IGNORE, + }, + + /* ou */ + { + .local_name = "ou", + .type = MAP_KEEP, + }, + + /* dc */ + { + .local_name = "dc", + .type = MAP_KEEP, + }, + + /* description */ + { + .local_name = "description", + .type = MAP_KEEP, + }, + + /* sambaSID -> objectSid*/ + { + .local_name = "objectSid", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaSID", + }, + + /* sambaPwdLastSet -> pwdLastSet */ + { + .local_name = "pwdLastSet", + .type = MAP_RENAME, + .u.rename.remote_name = "sambaPwdLastSet", + }, + + /* accountExpires */ + { + .local_name = "accountExpires", + .type = MAP_IGNORE, + }, + + /* adminCount */ + { + .local_name = "adminCount", + .type = MAP_IGNORE, + }, + + /* canonicalName */ + { + .local_name = "canonicalName", + .type = MAP_IGNORE, + }, + + /* createTimestamp */ + { + .local_name = "createTimestamp", + .type = MAP_IGNORE, + }, + + /* creationTime */ + { + .local_name = "creationTime", + .type = MAP_IGNORE, + }, + + /* dMDLocation */ + { + .local_name = "dMDLocation", + .type = MAP_IGNORE, + }, + + /* fSMORoleOwner */ + { + .local_name = "fSMORoleOwner", + .type = MAP_IGNORE, + }, + + /* forceLogoff */ + { + .local_name = "forceLogoff", + .type = MAP_IGNORE, + }, + + /* instanceType */ + { + .local_name = "instanceType", + .type = MAP_IGNORE, + }, + + /* invocationId */ + { + .local_name = "invocationId", + .type = MAP_IGNORE, + }, + + /* isCriticalSystemObject */ + { + .local_name = "isCriticalSystemObject", + .type = MAP_IGNORE, + }, + + /* localPolicyFlags */ + { + .local_name = "localPolicyFlags", + .type = MAP_IGNORE, + }, + + /* lockOutObservationWindow */ + { + .local_name = "lockOutObservationWindow", + .type = MAP_IGNORE, + }, + + /* lockoutDuration */ + { + .local_name = "lockoutDuration", + .type = MAP_IGNORE, + }, + + /* lockoutThreshold */ + { + .local_name = "lockoutThreshold", + .type = MAP_IGNORE, + }, + + /* logonCount */ + { + .local_name = "logonCount", + .type = MAP_IGNORE, + }, + + /* masteredBy */ + { + .local_name = "masteredBy", + .type = MAP_IGNORE, + }, + + /* maxPwdAge */ + { + .local_name = "maxPwdAge", + .type = MAP_IGNORE, + }, + + /* member */ + { + .local_name = "member", + .type = MAP_IGNORE, + }, + + /* memberOf */ + { + .local_name = "memberOf", + .type = MAP_IGNORE, + }, + + /* minPwdAge */ + { + .local_name = "minPwdAge", + .type = MAP_IGNORE, + }, + + /* minPwdLength */ + { + .local_name = "minPwdLength", + .type = MAP_IGNORE, + }, + + /* modifiedCount */ + { + .local_name = "modifiedCount", + .type = MAP_IGNORE, + }, + + /* modifiedCountAtLastProm */ + { + .local_name = "modifiedCountAtLastProm", + .type = MAP_IGNORE, + }, + + /* modifyTimestamp */ + { + .local_name = "modifyTimestamp", + .type = MAP_IGNORE, + }, + + /* nCName */ + { + .local_name = "nCName", + .type = MAP_IGNORE, + }, + + /* nETBIOSName */ + { + .local_name = "nETBIOSName", + .type = MAP_IGNORE, + }, + + /* oEMInformation */ + { + .local_name = "oEMInformation", + .type = MAP_IGNORE, + }, + + /* privilege */ + { + .local_name = "privilege", + .type = MAP_IGNORE, + }, + + /* pwdHistoryLength */ + { + .local_name = "pwdHistoryLength", + .type = MAP_IGNORE, + }, + + /* pwdProperties */ + { + .local_name = "pwdProperties", + .type = MAP_IGNORE, + }, + + /* rIDAvailablePool */ + { + .local_name = "rIDAvailablePool", + .type = MAP_IGNORE, + }, + + /* revision */ + { + .local_name = "revision", + .type = MAP_IGNORE, + }, + + /* ridManagerReference */ + { + .local_name = "ridManagerReference", + .type = MAP_IGNORE, + }, + + /* sAMAccountType */ + { + .local_name = "sAMAccountType", + .type = MAP_IGNORE, + }, + + /* sPNMappings */ + { + .local_name = "sPNMappings", + .type = MAP_IGNORE, + }, + + /* serverReference */ + { + .local_name = "serverReference", + .type = MAP_IGNORE, + }, + + /* serverState */ + { + .local_name = "serverState", + .type = MAP_IGNORE, + }, + + /* showInAdvancedViewOnly */ + { + .local_name = "showInAdvancedViewOnly", + .type = MAP_IGNORE, + }, + + /* subRefs */ + { + .local_name = "subRefs", + .type = MAP_IGNORE, + }, + + /* systemFlags */ + { + .local_name = "systemFlags", + .type = MAP_IGNORE, + }, + + /* uASCompat */ + { + .local_name = "uASCompat", + .type = MAP_IGNORE, + }, + + /* uSNChanged */ + { + .local_name = "uSNChanged", + .type = MAP_IGNORE, + }, + + /* uSNCreated */ + { + .local_name = "uSNCreated", + .type = MAP_IGNORE, + }, + + /* unicodePwd */ + { + .local_name = "unicodePwd", + .type = MAP_IGNORE, + }, + + /* userAccountControl */ + { + .local_name = "userAccountControl", + .type = MAP_IGNORE, + }, + + /* whenChanged */ + { + .local_name = "whenChanged", + .type = MAP_IGNORE, + }, + + /* whenCreated */ + { + .local_name = "whenCreated", + .type = MAP_IGNORE, + }, + + { + .local_name = NULL, + } +}; + + /* the init function */ +#ifdef HAVE_DLOPEN_DISABLED +struct ldb_module *init_module(struct ldb_context *ldb, const char *options[]) +#else +struct ldb_module *ldb_samba3sam_module_init(struct ldb_context *ldb, const char *options[]) +#endif +{ + return ldb_map_init(ldb, samba3_attributes, samba3_objectclasses, "samba3sam"); +} diff --git a/source4/lib/ldb/config.mk b/source4/lib/ldb/config.mk index 23a99e367b..f75964c44f 100644 --- a/source4/lib/ldb/config.mk +++ b/source4/lib/ldb/config.mk @@ -41,7 +41,7 @@ NOPROTO = YES # Start MODULE libldb_map [MODULE::libldb_map] SUBSYSTEM = LIBLDB -INIT_OBJ_FILES = lib/ldb/ldb_map/ldb_map.o +INIT_OBJ_FILES = lib/ldb/modules/ldb_map.o # End MODULE libldb_map ################################################ @@ -115,8 +115,7 @@ REQUIRED_SUBSYSTEMS = \ # Start SUBSYSTEM LDBSAMBA [SUBSYSTEM::LDBSAMBA] OBJ_FILES = \ - lib/ldb/samba/ldif_handlers.o \ - lib/ldb/samba/samba3sam.o + lib/ldb/samba/ldif_handlers.o # End SUBSYSTEM LDBSAMBA ################################################ diff --git a/source4/lib/ldb/ldb_map/README b/source4/lib/ldb/ldb_map/README deleted file mode 100644 index 3c7e30a331..0000000000 --- a/source4/lib/ldb/ldb_map/README +++ /dev/null @@ -1,29 +0,0 @@ -This directory contains a skeleton backend for ldb backends that allow -using an LDAP server while mapping the attributes in that schema to -another schema. This backend will never be used itself but instead have -other backends based on it (e.g. ldb_samba3 for a Samba3-LDAP-to-samdb -backend) - -Each backend that uses this skeleton has to specify an array of -struct objectclass_mapping's (see ldb_map.h). - -If no mappings are defined for an objectclass, it will be kept as is. - -Special mapping routine for dn's (calls rdn mapping routine) -Special mapping routine for rdn's - -Keep cache of mapped dn's so we don't have to traverse the tree each time - -search - Simply uses search_bytree - -search_bytree - Map all attributes in parse_tree - -add -modify - Map ldb_message to LDAPMod - -rename -delete - Simply map dn diff --git a/source4/lib/ldb/ldb_map/ldb_map.c b/source4/lib/ldb/ldb_map/ldb_map.c deleted file mode 100644 index 7a620f3b81..0000000000 --- a/source4/lib/ldb/ldb_map/ldb_map.c +++ /dev/null @@ -1,1151 +0,0 @@ -/* - ldb database library - map backend - - Copyright (C) Jelmer Vernooij 2005 - - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "includes.h" -#include "lib/ldb/include/ldb.h" -#include "lib/ldb/include/ldb_private.h" -#include "lib/ldb/ldb_map/ldb_map.h" - -/* TODO: - * - objectclass hint in ldb_map_attribute - * for use when multiple remote attributes (independant of each other) - * map to one local attribute. E.g.: (uid, gidNumber) -> unixName - * (use MAP_GENERATE instead ?) - */ - -/* - - special attribute 'isMapped' - - add/modify - - split up ldb_message into fallback and mapped parts if is_mappable - - search: - - search local one for not isMapped entries - - remove remote attributes from ldb_parse_tree - - search remote one - - per record, search local one for additional data (by dn) - - test if (full expression) is now true - - delete - - delete both - - rename - - rename locally and remotely -*/ - -static const struct ldb_map_attribute builtin_attribute_maps[]; - -struct map_private { - struct ldb_map_context context; - const char *last_err_string; -}; - -static struct ldb_map_context *map_get_privdat(struct ldb_module *module) -{ - return &((struct map_private *)module->private_data)->context; -} - -static const struct ldb_map_objectclass *map_find_objectclass_local(struct ldb_map_context *privdat, const char *name) -{ - int i; - for (i = 0; privdat->objectclass_maps[i].local_name; i++) { - if (!ldb_attr_cmp(privdat->objectclass_maps[i].local_name, name)) - return &privdat->objectclass_maps[i]; - } - - return NULL; -} - -/* Decide whether a add/modify should be pushed to the - * remote LDAP server. We currently only do this if we see an objectClass we know */ -static BOOL map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg) -{ - int i; - struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass"); - - /* No objectClass... */ - if (el == NULL) { - return False; - } - - for (i = 0; i < el->num_values; i++) { - if (map_find_objectclass_local(privdat, (char *)el->values[i].data)) - return True; - } - - return False; -} - -/* find an attribute by the local name */ -static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr) -{ - int i; - - for (i = 0; privdat->attribute_maps[i].local_name; i++) { - if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr)) - return &privdat->attribute_maps[i]; - } - - return NULL; -} - -/* find an attribute by the remote name */ -static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr) -{ - int i; - - for (i = 0; privdat->attribute_maps[i].local_name; i++) { - if (privdat->attribute_maps[i].type == MAP_IGNORE) - continue; - - if (privdat->attribute_maps[i].type == MAP_GENERATE) - continue; - - if (privdat->attribute_maps[i].type == MAP_KEEP && - ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0) - return &privdat->attribute_maps[i]; - - if ((privdat->attribute_maps[i].type == MAP_RENAME || - privdat->attribute_maps[i].type == MAP_CONVERT) && - ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0) - return &privdat->attribute_maps[i]; - - } - - return NULL; -} - -static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree) -{ - int i; - const struct ldb_map_attribute *attr; - struct ldb_parse_tree *new_tree; - enum ldb_map_attr_type map_type; - struct ldb_val value, newvalue; - struct ldb_map_context *privdat = map_get_privdat(module); - - if (tree == NULL) - return NULL; - - - /* Find attr in question and: - * - if it has a convert_operator function, run that - * - otherwise, replace attr name with required[0] */ - - if (tree->operation == LDB_OP_AND || - tree->operation == LDB_OP_OR) { - - new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); - new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements); - new_tree->u.list.num_elements = 0; - for (i = 0; i < tree->u.list.num_elements; i++) { - struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]); - - if (child) { - new_tree->u.list.elements[i] = child; - new_tree->u.list.num_elements++; - } - } - - return new_tree; - } - - if (tree->operation == LDB_OP_NOT) { - struct ldb_parse_tree *child; - - new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); - child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child); - - if (!child) { - talloc_free(new_tree); - return NULL; - } - - new_tree->u.isnot.child = child; - return new_tree; - } - - /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER, - * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED - * - * (all have attr as the first element) - */ - - attr = map_find_attr_local(privdat, tree->u.equality.attr); - - if (!attr) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr); - map_type = MAP_KEEP; - } else { - map_type = attr->type; - } - - if (attr && attr->convert_operator) { - /* Run convert_operator */ - return attr->convert_operator(privdat, module, tree); - } - - if (map_type == MAP_IGNORE) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Search on ignored attribute '%s'\n", tree->u.equality.attr); - return NULL; - } - - if (map_type == MAP_GENERATE) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Can't do conversion for MAP_GENERATE in map_parse_tree without convert_operator for '%s'\n", tree->u.equality.attr); - return NULL; - } - - if (tree->operation == LDB_OP_EQUALITY) { - value = tree->u.equality.value; - } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER || - tree->operation == LDB_OP_APPROX) { - value = tree->u.comparison.value; - } else if (tree->operation == LDB_OP_EXTENDED) { - value = tree->u.extended.value; - } - - new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); - - if (map_type == MAP_KEEP) { - new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr); - } else { /* MAP_RENAME / MAP_CONVERT */ - new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name); - } - - if (new_tree->operation == LDB_OP_PRESENT) - return new_tree; - - if (new_tree->operation == LDB_OP_SUBSTRING) { - new_tree->u.substring.chunks = NULL; /* FIXME! */ - return new_tree; - } - - if (map_type == MAP_CONVERT) { - newvalue = attr->u.convert.convert_local(privdat, new_tree, &value); - } else { - newvalue = ldb_val_dup(new_tree, &value); - } - - if (new_tree->operation == LDB_OP_EQUALITY) { - new_tree->u.equality.value = newvalue; - } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER || - new_tree->operation == LDB_OP_APPROX) { - new_tree->u.comparison.value = newvalue; - } else if (new_tree->operation == LDB_OP_EXTENDED) { - new_tree->u.extended.value = newvalue; - new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id); - } - - return new_tree; -} - -/* Remote DN -> Local DN */ -static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn) -{ - struct ldb_dn *newdn; - int i; - - if (dn == NULL) - return NULL; - - newdn = talloc_memdup(ctx, dn, sizeof(*dn)); - if (!newdn) - return NULL; - - newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); - - if (!newdn->components) - return NULL; - - /* For each rdn, map the attribute name and possibly the - * complete rdn */ - - for (i = 0; i < dn->comp_num; i++) { - const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name); - enum ldb_map_attr_type map_type; - - /* Unknown attribute - leave this dn as is and hope the best... */ - if (!attr) map_type = MAP_KEEP; - else map_type = attr->type; - - switch (map_type) { - case MAP_IGNORE: - case MAP_GENERATE: - DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name)); - talloc_free(newdn); - return NULL; - - case MAP_KEEP: - newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name); - newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); - break; - - case MAP_CONVERT: - newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name); - newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value); - break; - - case MAP_RENAME: - newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name); - newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); - break; - } - } - return newdn; -} - -/* Local DN -> Remote DN */ -static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn) -{ - struct ldb_dn *newdn; - int i; - - if (dn == NULL) - return NULL; - - newdn = talloc_memdup(ctx, dn, sizeof(*dn)); - if (!newdn) - return NULL; - - newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); - - if (!newdn->components) - return NULL; - - /* For each rdn, map the attribute name and possibly the - * complete rdn using an equality convert_operator call */ - - for (i = 0; i < dn->comp_num; i++) { - const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name); - enum ldb_map_attr_type map_type; - - /* Unknown attribute - leave this dn as is and hope the best... */ - if (!attr) map_type = MAP_KEEP; else map_type = attr->type; - - switch (map_type) - { - case MAP_IGNORE: - case MAP_GENERATE: - DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name)); - talloc_free(newdn); - return NULL; - - case MAP_CONVERT: - newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name); - newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value); - break; - - case MAP_RENAME: - newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name); - newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); - break; - - case MAP_KEEP: - newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name); - newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); - continue; - } - } - - return newdn; -} - -/* Loop over ldb_map_attribute array and add remote_names */ -static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[]) -{ - int i; - const char **ret; - int ar_size = 0, last_element = 0; - struct ldb_map_context *privdat = map_get_privdat(module); - - if (attrs == NULL) - return NULL; - - /* Start with good guess of number of elements */ - for (i = 0; attrs[i]; i++); - - ret = talloc_array(module, const char *, i); - ar_size = i; - - for (i = 0; attrs[i]; i++) { - int j; - const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]); - enum ldb_map_attr_type map_type; - - if (!attr) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]); - map_type = MAP_IGNORE; - } else map_type = attr->type; - - switch (map_type) - { - case MAP_IGNORE: break; - case MAP_KEEP: - if (last_element >= ar_size) { - ret = talloc_realloc(module, ret, const char *, ar_size+1); - ar_size++; - } - ret[last_element] = attr->local_name; - last_element++; - break; - - case MAP_RENAME: - case MAP_CONVERT: - if (last_element >= ar_size) { - ret = talloc_realloc(module, ret, const char *, ar_size+1); - ar_size++; - } - ret[last_element] = attr->u.rename.remote_name; - last_element++; - break; - - case MAP_GENERATE: - /* Add remote_names[] for this attribute to the list of - * attributes to request from the remote server */ - for (j = 0; attr->u.generate.remote_names[j]; j++) { - if (last_element >= ar_size) { - ret = talloc_realloc(module, ret, const char *, ar_size+1); - ar_size++; - } - ret[last_element] = attr->u.generate.remote_names[j]; - last_element++; - } - break; - } - } - - if (last_element >= ar_size) { - ret = talloc_realloc(module, ret, const char *, ar_size+1); - ar_size++; - } - - ret[last_element] = NULL; - - return ret; -} - -static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_map_context *privdat = map_get_privdat(module); - int i, j; - int count = 0; - const char **ret = talloc_array(module, const char *, 1); - - ret[0] = NULL; - - for (i = 0; privdat->attribute_maps[i].local_name; i++) { - BOOL avail = False; - const struct ldb_map_attribute *attr = &privdat->attribute_maps[i]; - - /* If all remote attributes for this attribute are present, add the - * local one to the list */ - - switch (attr->type) { - case MAP_IGNORE: break; - case MAP_KEEP: - avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL); - break; - - case MAP_RENAME: - case MAP_CONVERT: - avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL); - break; - - case MAP_GENERATE: - avail = True; - for (j = 0; attr->u.generate.remote_names[j]; j++) { - avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL); - } - break; - } - - if (!avail) - continue; - - ret = talloc_realloc(module, ret, const char *, count+2); - ret[count] = attr->local_name; - ret[count+1] = NULL; - count++; - } - - return ret; -} - -/* Used for search */ -static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi) -{ - int i, j; - struct ldb_message *msg = talloc_zero(module, struct ldb_message); - struct ldb_message_element *elm, *oldelm; - struct ldb_map_context *privdat = map_get_privdat(module); - const char **newattrs = NULL; - - msg->dn = map_remote_dn(privdat, module, mi->dn); - - ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn)); - - /* Loop over attrs, find in ldb_map_attribute array and - * run generate() */ - - if (attrs == NULL) { - /* Generate list of the local attributes that /can/ be generated - * using the specific remote attributes */ - - attrs = newattrs = available_local_attributes(module, mi); - } - - for (i = 0; attrs[i]; i++) { - const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]); - enum ldb_map_attr_type map_type; - - if (!attr) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]); - map_type = MAP_IGNORE; - } else map_type = attr->type; - - switch (map_type) { - case MAP_IGNORE:break; - case MAP_RENAME: - oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name); - if (!oldelm) continue; - - elm = talloc(msg, struct ldb_message_element); - elm->name = talloc_strdup(elm, attr->local_name); - elm->num_values = oldelm->num_values; - elm->values = talloc_reference(elm, oldelm->values); - - ldb_msg_add(module->ldb, msg, elm, oldelm->flags); - break; - - case MAP_CONVERT: - oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name); - if (!oldelm) continue; - - elm = talloc(msg, struct ldb_message_element); - elm->name = talloc_strdup(elm, attr->local_name); - elm->num_values = oldelm->num_values; - elm->values = talloc_array(elm, struct ldb_val, elm->num_values); - - for (j = 0; j < oldelm->num_values; j++) - elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]); - - ldb_msg_add(module->ldb, msg, elm, oldelm->flags); - break; - - case MAP_KEEP: - oldelm = ldb_msg_find_element(mi, attr->local_name); - if (!oldelm) continue; - - elm = talloc(msg, struct ldb_message_element); - - elm->num_values = oldelm->num_values; - elm->values = talloc_reference(elm, oldelm->values); - elm->name = talloc_strdup(elm, oldelm->name); - - ldb_msg_add(module->ldb, msg, elm, oldelm->flags); - break; - - case MAP_GENERATE: - elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi); - if (!elm) continue; - - ldb_msg_add(module->ldb, msg, elm, elm->flags); - break; - default: - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name); - break; - } - } - - talloc_free(newattrs); - - return msg; -} - -/* Used for add, modify */ -static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp) -{ - struct ldb_map_context *privdat = map_get_privdat(module); - struct ldb_message *msg = talloc_zero(module, struct ldb_message); - struct ldb_message_element *elm; - int i,j; - - *fb = talloc_zero(module, struct ldb_message); - (*fb)->dn = talloc_reference(*fb, mo->dn); - - *mp = msg; - - msg->private_data = mo->private_data; - - msg->dn = map_local_dn(privdat, module, mo->dn); - - /* Loop over mi and call generate_remote for each attribute */ - for (i = 0; i < mo->num_elements; i++) { - const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name); - enum ldb_map_attr_type map_type; - - if (!attr) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name); - map_type = MAP_IGNORE; - continue; - } else map_type = attr->type; - - switch (map_type) { - case MAP_IGNORE: /* Add to fallback message */ - elm = talloc(*fb, struct ldb_message_element); - - elm->num_values = mo->elements[i].num_values; - elm->values = talloc_reference(elm, mo->elements[i].values); - elm->name = talloc_strdup(elm, mo->elements[i].name); - - ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags); - break; - case MAP_RENAME: - elm = talloc(msg, struct ldb_message_element); - - elm->name = talloc_strdup(elm, attr->u.rename.remote_name); - elm->num_values = mo->elements[i].num_values; - elm->values = talloc_reference(elm, mo->elements[i].values); - - ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); - break; - - case MAP_CONVERT: - elm = talloc(msg, struct ldb_message_element); - - elm->name = talloc_strdup(elm, attr->u.rename.remote_name); - elm->num_values = mo->elements[i].num_values; - elm->values = talloc_array(elm, struct ldb_val, elm->num_values); - - for (j = 0; j < elm->num_values; j++) { - elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]); - } - - ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); - break; - - case MAP_KEEP: - elm = talloc(msg, struct ldb_message_element); - - elm->num_values = mo->elements[i].num_values; - elm->values = talloc_reference(elm, mo->elements[i].values); - elm->name = talloc_strdup(elm, mo->elements[i].name); - - ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); - break; - - case MAP_GENERATE: - attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg); - break; - } - } - - return 0; -} - - -/* - rename a record -*/ -static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) -{ - struct ldb_map_context *privdat = map_get_privdat(module); - struct ldb_dn *n_olddn, *n_newdn; - int ret; - - ret = ldb_next_rename_record(module, olddn, newdn); - - n_olddn = map_local_dn(privdat, module, olddn); - n_newdn = map_local_dn(privdat, module, newdn); - - ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn); - - talloc_free(n_olddn); - talloc_free(n_newdn); - - return ret; -} - -/* - delete a record -*/ -static int map_delete(struct ldb_module *module, const struct ldb_dn *dn) -{ - struct ldb_map_context *privdat = map_get_privdat(module); - struct ldb_dn *newdn; - int ret; - - ret = ldb_next_delete_record(module, dn); - - newdn = map_local_dn(privdat, module, dn); - - ret = ldb_delete(privdat->mapped_ldb, newdn); - - talloc_free(newdn); - - return ret; -} - -/* search fallback database */ -static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, struct ldb_message ***res) -{ - int ret; - struct ldb_parse_tree t_and, t_not, t_present, *childs[2]; - - t_present.operation = LDB_OP_PRESENT; - t_present.u.present.attr = talloc_strdup(NULL, "isMapped"); - - t_not.operation = LDB_OP_NOT; - t_not.u.isnot.child = &t_present; - - childs[0] = &t_not; - childs[1] = tree; - t_and.operation = LDB_OP_AND; - t_and.u.list.num_elements = 2; - t_and.u.list.elements = childs; - - ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res); - - talloc_free(t_present.u.present.attr); - - return ret; -} - -static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, struct ldb_message ***res) -{ - struct ldb_parse_tree *new_tree; - struct ldb_dn *new_base; - struct ldb_message **newres; - const char **newattrs; - int mpret, ret; - struct ldb_map_context *privdat = map_get_privdat(module); - int i; - - /*- search mapped database */ - - new_tree = ldb_map_parse_tree(module, module, tree); - newattrs = ldb_map_attrs(module, attrs); - new_base = map_local_dn(privdat, module, base); - - mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres); - - talloc_free(new_base); - talloc_free(new_tree); - talloc_free(newattrs); - - if (mpret == -1) { - struct map_private *map_private = module->private_data; - map_private->last_err_string = ldb_errstring(privdat->mapped_ldb); - return -1; - } - - /* - - per returned record, search fallback database for additional data (by dn) - - test if (full expression) is now true - */ - - *res = talloc_array(module, struct ldb_message *, mpret); - - ret = 0; - - for (i = 0; i < mpret; i++) { - struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]); - struct ldb_message **extrares = NULL; - int extraret; - - /* Merge with additional data from local database */ - extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares); - - if (extraret == -1) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n"); - } else if (extraret > 1) { - ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n"); - talloc_free(newres); - return -1; - } else if (extraret == 0) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN"); - } - - if (extraret == 1) { - int j; - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN"); - for (j = 0; j < extrares[0]->num_elements; j++) { - ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags); - } - - ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE"); - } else { - ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE"); - } - - if (ldb_match_msg(module->ldb, merged, tree, base, scope)) { - (*res)[ret] = merged; - ret++; - } else { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match"); - } - } - - talloc_free(newres); - - return ret; -} - - -/* - search for matching records using a ldb_parse_tree -*/ -static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, struct ldb_message ***res) -{ - struct ldb_message **fbres, **mpres; - int i; - int ret_fb, ret_mp; - - ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres); - if (ret_fb == -1) - return -1; - - ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres); - if (ret_mp == -1) { - return -1; - } - - /* Merge results */ - *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp); - - for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i]; - for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i]; - - return ret_fb + ret_mp; -} -/* - search for matching records -*/ -static int map_search(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, const char *expression, - const char * const *attrs, struct ldb_message ***res) -{ - struct map_private *map = module->private_data; - struct ldb_parse_tree *tree; - int ret; - - tree = ldb_parse_tree(NULL, expression); - if (tree == NULL) { - map->last_err_string = "expression parse failed"; - return -1; - } - - ret = map_search_bytree(module, base, scope, tree, attrs, res); - talloc_free(tree); - return ret; -} - -/* - add a record -*/ -static int map_add(struct ldb_module *module, const struct ldb_message *msg) -{ - int ret; - struct ldb_map_context *privdat = map_get_privdat(module); - struct ldb_message *fb, *mp; - - if (!map_is_mappable(privdat, msg)) { - return ldb_next_add_record(module, msg); - } - - if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) - return -1; - - ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE"); - - ret = ldb_next_add_record(module, fb); - if (ret == -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed"); - return -1; - } - - ret = ldb_add(privdat->mapped_ldb, mp); - if (ret == -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed"); - return -1; - } - - talloc_free(fb); - talloc_free(mp); - - return ret; -} - - -/* - modify a record -*/ -static int map_modify(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_map_context *privdat = map_get_privdat(module); - struct ldb_message *fb, *mp; - int ret; - - if (!map_is_mappable(privdat, msg)) - return ldb_next_modify_record(module, msg); - - - if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) - return -1; - - ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE"); - - ret = ldb_next_modify_record(module, fb); - - ret = ldb_modify(privdat->mapped_ldb, mp); - - talloc_free(fb); - talloc_free(mp); - - return ret; -} - -static int map_lock(struct ldb_module *module, const char *lockname) -{ - return ldb_next_named_lock(module, lockname); -} - -static int map_unlock(struct ldb_module *module, const char *lockname) -{ - return ldb_next_named_unlock(module, lockname); -} - -/* - return extended error information -*/ -static const char *map_errstring(struct ldb_module *module) -{ - struct map_private *map = module->private_data; - - if (map->last_err_string) - return map->last_err_string; - - return ldb_next_errstring(module); -} - -static const struct ldb_module_ops map_ops = { - .name = "map", - .search = map_search, - .search_bytree = map_search_bytree, - .add_record = map_add, - .modify_record = map_modify, - .delete_record = map_delete, - .rename_record = map_rename, - .named_lock = map_lock, - .named_unlock = map_unlock, - .errstring = map_errstring -}; - -static char *map_find_url(struct ldb_context *ldb, const char *name) -{ - const char * const attrs[] = { "@MAP_URL" , NULL}; - struct ldb_message **msg = NULL; - struct ldb_dn *mods; - char *url; - int ret; - - mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name); - if (mods == NULL) { - ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN"); - return NULL; - } - - ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg); - talloc_free(mods); - if (ret < 1) { - ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP"); - return NULL; - } - - url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL)); - - talloc_free(msg); - - return url; -} - -/* the init function */ -struct ldb_module *ldb_map_init(struct ldb_context *ldb, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char *name) -{ - int i, j; - struct ldb_module *ctx; - struct map_private *data; - char *url; - - ctx = talloc(ldb, struct ldb_module); - if (!ctx) - return NULL; - - data = talloc(ctx, struct map_private); - if (!data) { - talloc_free(ctx); - return NULL; - } - - data->context.mapped_ldb = ldb_init(data); - url = map_find_url(ldb, name); - - if (!url) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name); - return NULL; - } - - if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) { - ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url); - return NULL; - } - - talloc_free(url); - - data->last_err_string = NULL; - - /* Get list of attribute maps */ - j = 0; - data->context.attribute_maps = NULL; - - for (i = 0; attrs[i].local_name; i++) { - data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); - data->context.attribute_maps[j] = attrs[i]; - j++; - } - - for (i = 0; builtin_attribute_maps[i].local_name; i++) { - data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); - data->context.attribute_maps[j] = builtin_attribute_maps[i]; - j++; - } - - data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); - ZERO_STRUCT(data->context.attribute_maps[j].local_name); - - data->context.objectclass_maps = ocls; - ctx->private_data = data; - ctx->ldb = ldb; - ctx->prev = ctx->next = NULL; - ctx->ops = &map_ops; - - return ctx; -} - -static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - struct ldb_dn *dn, *newdn;; - struct ldb_val *newval; - - dn = ldb_dn_explode(ctx, (char *)val->data); - - newdn = map_local_dn(map, ctx, dn); - - talloc_free(dn); - - newval = talloc(ctx, struct ldb_val); - newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn); - newval->length = strlen((char *)newval->data); - - talloc_free(newdn); - - return *newval; -} - -static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - struct ldb_dn *dn, *newdn;; - struct ldb_val *newval; - - dn = ldb_dn_explode(ctx, (char *)val->data); - - newdn = map_remote_dn(map, ctx, dn); - - talloc_free(dn); - - newval = talloc(ctx, struct ldb_val); - newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn); - newval->length = strlen((char *)newval->data); - - talloc_free(newdn); - - return *newval; -} - -static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - int i; - - for (i = 0; map->objectclass_maps[i].local_name; i++) { - if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) { - struct ldb_val newval; - newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name); - newval.length = strlen((char *)newval.data); - - return ldb_val_dup(ctx, &newval); - } - } - - return ldb_val_dup(ctx, val); -} - -static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - int i; - - for (i = 0; map->objectclass_maps[i].remote_name; i++) { - if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) { - struct ldb_val newval; - newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name); - newval.length = strlen((char *)newval.data); - - return ldb_val_dup(ctx, &newval); - } - } - - return ldb_val_dup(ctx, val); -} - -static const struct ldb_map_attribute builtin_attribute_maps[] = { - { - .local_name = "dn", - .type = MAP_CONVERT, - .u.convert.remote_name = "dn", - .u.convert.convert_local = map_convert_local_dn, - .u.convert.convert_remote = map_convert_remote_dn, - }, - { - .local_name = "objectclass", - .type = MAP_CONVERT, - .u.convert.remote_name = "objectclass", - .u.convert.convert_local = map_convert_local_objectclass, - .u.convert.convert_remote = map_convert_remote_objectclass, - }, - { - .local_name = NULL, - } -}; - diff --git a/source4/lib/ldb/ldb_map/ldb_map.h b/source4/lib/ldb/ldb_map/ldb_map.h deleted file mode 100644 index 02fec649c6..0000000000 --- a/source4/lib/ldb/ldb_map/ldb_map.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - ldb database library - map backend - - Copyright (C) Jelmer Vernooij 2005 - - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef __LDB_MAP_H__ -#define __LDB_MAP_H__ - -/* ldb_map is a skeleton LDB module that can be used for any other modules - * that need to map attributes. - * - * The term 'remote' in this header refers to the connection where the - * original schema is used on while 'local' means the local connection - * that any upper layers will use. - * - * All local attributes will have to have a definition. Not all remote - * attributes need a definition as LDB is a lot less stricter then LDAP - * (in other words, sending unknown attributes to an LDAP server hurts us, - * returning too much attributes in ldb_search() doesn't) - */ - -struct ldb_map_context; - -struct ldb_map_attribute -{ - const char *local_name; /* local name */ - - enum ldb_map_attr_type { - MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */ - MAP_KEEP, /* Keep as is. Same name locally and remotely. */ - MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */ - MAP_CONVERT, /* Rename + convert data */ - MAP_GENERATE /* Use generate function for generating new name/data. - Used for generating attributes based on - 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 *); - - union { - struct { - const char *remote_name; - } rename; - - struct { - const char *remote_name; - struct ldb_val (*convert_local) (struct ldb_map_context *, TALLOC_CTX *, const struct ldb_val *); - struct ldb_val (*convert_remote) (struct ldb_map_context *, TALLOC_CTX *, const struct ldb_val *); - } convert; - - struct { - /* Generate the local attribute from remote message */ - struct ldb_message_element *(*generate_local) ( - struct ldb_map_context *, - TALLOC_CTX *ctx, - const char *attr, - const struct ldb_message *remote); - - /* Update remote message with information from local message */ - void (*generate_remote) ( - struct ldb_map_context *, - const char *local_attr, - const struct ldb_message *local, - struct ldb_message *remote); - - /* 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]; - } generate; - } u; -}; - -struct ldb_map_objectclass -{ - const char *local_name; - const char *remote_name; -}; - -struct ldb_map_context -{ - struct ldb_map_attribute *attribute_maps; - const struct ldb_map_objectclass *objectclass_maps; - struct ldb_context *mapped_ldb; -}; - -#endif /* __LDB_MAP_H__ */ diff --git a/source4/lib/ldb/modules/ldb_map.c b/source4/lib/ldb/modules/ldb_map.c new file mode 100644 index 0000000000..531d5ccd67 --- /dev/null +++ b/source4/lib/ldb/modules/ldb_map.c @@ -0,0 +1,1151 @@ +/* + ldb database library - map backend + + Copyright (C) Jelmer Vernooij 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "includes.h" +#include "lib/ldb/include/ldb.h" +#include "lib/ldb/include/ldb_private.h" +#include "lib/ldb/modules/ldb_map.h" + +/* TODO: + * - objectclass hint in ldb_map_attribute + * for use when multiple remote attributes (independant of each other) + * map to one local attribute. E.g.: (uid, gidNumber) -> unixName + * (use MAP_GENERATE instead ?) + */ + +/* + - special attribute 'isMapped' + - add/modify + - split up ldb_message into fallback and mapped parts if is_mappable + - search: + - search local one for not isMapped entries + - remove remote attributes from ldb_parse_tree + - search remote one + - per record, search local one for additional data (by dn) + - test if (full expression) is now true + - delete + - delete both + - rename + - rename locally and remotely +*/ + +static const struct ldb_map_attribute builtin_attribute_maps[]; + +struct map_private { + struct ldb_map_context context; + const char *last_err_string; +}; + +static struct ldb_map_context *map_get_privdat(struct ldb_module *module) +{ + return &((struct map_private *)module->private_data)->context; +} + +static const struct ldb_map_objectclass *map_find_objectclass_local(struct ldb_map_context *privdat, const char *name) +{ + int i; + for (i = 0; privdat->objectclass_maps[i].local_name; i++) { + if (!ldb_attr_cmp(privdat->objectclass_maps[i].local_name, name)) + return &privdat->objectclass_maps[i]; + } + + return NULL; +} + +/* Decide whether a add/modify should be pushed to the + * remote LDAP server. We currently only do this if we see an objectClass we know */ +static BOOL map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg) +{ + int i; + struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass"); + + /* No objectClass... */ + if (el == NULL) { + return False; + } + + for (i = 0; i < el->num_values; i++) { + if (map_find_objectclass_local(privdat, (char *)el->values[i].data)) + return True; + } + + return False; +} + +/* find an attribute by the local name */ +static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_context *privdat, const char *attr) +{ + int i; + + for (i = 0; privdat->attribute_maps[i].local_name; i++) { + if (!ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr)) + return &privdat->attribute_maps[i]; + } + + return NULL; +} + +/* find an attribute by the remote name */ +static const struct ldb_map_attribute *map_find_attr_remote(struct ldb_map_context *privdat, const char *attr) +{ + int i; + + for (i = 0; privdat->attribute_maps[i].local_name; i++) { + if (privdat->attribute_maps[i].type == MAP_IGNORE) + continue; + + if (privdat->attribute_maps[i].type == MAP_GENERATE) + continue; + + if (privdat->attribute_maps[i].type == MAP_KEEP && + ldb_attr_cmp(privdat->attribute_maps[i].local_name, attr) == 0) + return &privdat->attribute_maps[i]; + + if ((privdat->attribute_maps[i].type == MAP_RENAME || + privdat->attribute_maps[i].type == MAP_CONVERT) && + ldb_attr_cmp(privdat->attribute_maps[i].u.rename.remote_name, attr) == 0) + return &privdat->attribute_maps[i]; + + } + + return NULL; +} + +static struct ldb_parse_tree *ldb_map_parse_tree(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_parse_tree *tree) +{ + int i; + const struct ldb_map_attribute *attr; + struct ldb_parse_tree *new_tree; + enum ldb_map_attr_type map_type; + struct ldb_val value, newvalue; + struct ldb_map_context *privdat = map_get_privdat(module); + + if (tree == NULL) + return NULL; + + + /* Find attr in question and: + * - if it has a convert_operator function, run that + * - otherwise, replace attr name with required[0] */ + + if (tree->operation == LDB_OP_AND || + tree->operation == LDB_OP_OR) { + + new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); + new_tree->u.list.elements = talloc_array(new_tree, struct ldb_parse_tree *, tree->u.list.num_elements); + new_tree->u.list.num_elements = 0; + for (i = 0; i < tree->u.list.num_elements; i++) { + struct ldb_parse_tree *child = ldb_map_parse_tree(module, new_tree, tree->u.list.elements[i]); + + if (child) { + new_tree->u.list.elements[i] = child; + new_tree->u.list.num_elements++; + } + } + + return new_tree; + } + + if (tree->operation == LDB_OP_NOT) { + struct ldb_parse_tree *child; + + new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); + child = ldb_map_parse_tree(module, new_tree, tree->u.isnot.child); + + if (!child) { + talloc_free(new_tree); + return NULL; + } + + new_tree->u.isnot.child = child; + return new_tree; + } + + /* tree->operation is LDB_OP_EQUALITY, LDB_OP_SUBSTRING, LDB_OP_GREATER, + * LDB_OP_LESS, LDB_OP_APPROX, LDB_OP_PRESENT or LDB_OP_EXTENDED + * + * (all have attr as the first element) + */ + + attr = map_find_attr_local(privdat, tree->u.equality.attr); + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s', leaving as is\n", tree->u.equality.attr); + map_type = MAP_KEEP; + } else { + map_type = attr->type; + } + + if (attr && attr->convert_operator) { + /* Run convert_operator */ + return attr->convert_operator(privdat, module, tree); + } + + if (map_type == MAP_IGNORE) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Search on ignored attribute '%s'\n", tree->u.equality.attr); + return NULL; + } + + if (map_type == MAP_GENERATE) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Can't do conversion for MAP_GENERATE in map_parse_tree without convert_operator for '%s'\n", tree->u.equality.attr); + return NULL; + } + + if (tree->operation == LDB_OP_EQUALITY) { + value = tree->u.equality.value; + } else if (tree->operation == LDB_OP_LESS || tree->operation == LDB_OP_GREATER || + tree->operation == LDB_OP_APPROX) { + value = tree->u.comparison.value; + } else if (tree->operation == LDB_OP_EXTENDED) { + value = tree->u.extended.value; + } + + new_tree = talloc_memdup(ctx, tree, sizeof(*tree)); + + if (map_type == MAP_KEEP) { + new_tree->u.equality.attr = talloc_strdup(new_tree, tree->u.equality.attr); + } else { /* MAP_RENAME / MAP_CONVERT */ + new_tree->u.equality.attr = talloc_strdup(new_tree, attr->u.rename.remote_name); + } + + if (new_tree->operation == LDB_OP_PRESENT) + return new_tree; + + if (new_tree->operation == LDB_OP_SUBSTRING) { + new_tree->u.substring.chunks = NULL; /* FIXME! */ + return new_tree; + } + + if (map_type == MAP_CONVERT) { + newvalue = attr->u.convert.convert_local(privdat, new_tree, &value); + } else { + newvalue = ldb_val_dup(new_tree, &value); + } + + if (new_tree->operation == LDB_OP_EQUALITY) { + new_tree->u.equality.value = newvalue; + } else if (new_tree->operation == LDB_OP_LESS || new_tree->operation == LDB_OP_GREATER || + new_tree->operation == LDB_OP_APPROX) { + new_tree->u.comparison.value = newvalue; + } else if (new_tree->operation == LDB_OP_EXTENDED) { + new_tree->u.extended.value = newvalue; + new_tree->u.extended.rule_id = talloc_strdup(new_tree, tree->u.extended.rule_id); + } + + return new_tree; +} + +/* Remote DN -> Local DN */ +static struct ldb_dn *map_remote_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn) +{ + struct ldb_dn *newdn; + int i; + + if (dn == NULL) + return NULL; + + newdn = talloc_memdup(ctx, dn, sizeof(*dn)); + if (!newdn) + return NULL; + + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + + if (!newdn->components) + return NULL; + + /* For each rdn, map the attribute name and possibly the + * complete rdn */ + + for (i = 0; i < dn->comp_num; i++) { + const struct ldb_map_attribute *attr = map_find_attr_remote(privdat, dn->components[i].name); + enum ldb_map_attr_type map_type; + + /* Unknown attribute - leave this dn as is and hope the best... */ + if (!attr) map_type = MAP_KEEP; + else map_type = attr->type; + + switch (map_type) { + case MAP_IGNORE: + case MAP_GENERATE: + DEBUG(0, ("Local MAP_IGNORE or MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name)); + talloc_free(newdn); + return NULL; + + case MAP_KEEP: + newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name); + newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); + break; + + case MAP_CONVERT: + newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name); + newdn->components[i].value = attr->u.convert.convert_remote(privdat, ctx, &dn->components[i].value); + break; + + case MAP_RENAME: + newdn->components[i].name = talloc_strdup(newdn->components, attr->local_name); + newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); + break; + } + } + return newdn; +} + +/* Local DN -> Remote DN */ +static struct ldb_dn *map_local_dn(struct ldb_map_context *privdat, TALLOC_CTX *ctx, const struct ldb_dn *dn) +{ + struct ldb_dn *newdn; + int i; + + if (dn == NULL) + return NULL; + + newdn = talloc_memdup(ctx, dn, sizeof(*dn)); + if (!newdn) + return NULL; + + newdn->components = talloc_array(newdn, struct ldb_dn_component, newdn->comp_num); + + if (!newdn->components) + return NULL; + + /* For each rdn, map the attribute name and possibly the + * complete rdn using an equality convert_operator call */ + + for (i = 0; i < dn->comp_num; i++) { + const struct ldb_map_attribute *attr = map_find_attr_local(privdat, dn->components[i].name); + enum ldb_map_attr_type map_type; + + /* Unknown attribute - leave this dn as is and hope the best... */ + if (!attr) map_type = MAP_KEEP; else map_type = attr->type; + + switch (map_type) + { + case MAP_IGNORE: + case MAP_GENERATE: + DEBUG(0, ("Local MAP_IGNORE/MAP_GENERATE attribute '%s' used in DN!", dn->components[i].name)); + talloc_free(newdn); + return NULL; + + case MAP_CONVERT: + newdn->components[i].name = talloc_strdup(newdn->components, attr->u.convert.remote_name); + newdn->components[i].value = attr->u.convert.convert_local(privdat, newdn->components, &dn->components[i].value); + break; + + case MAP_RENAME: + newdn->components[i].name = talloc_strdup(newdn->components, attr->u.rename.remote_name); + newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); + break; + + case MAP_KEEP: + newdn->components[i].name = talloc_strdup(newdn->components, dn->components[i].name); + newdn->components[i].value = ldb_val_dup(newdn->components, &dn->components[i].value); + continue; + } + } + + return newdn; +} + +/* Loop over ldb_map_attribute array and add remote_names */ +static const char **ldb_map_attrs(struct ldb_module *module, const char *const attrs[]) +{ + int i; + const char **ret; + int ar_size = 0, last_element = 0; + struct ldb_map_context *privdat = map_get_privdat(module); + + if (attrs == NULL) + return NULL; + + /* Start with good guess of number of elements */ + for (i = 0; attrs[i]; i++); + + ret = talloc_array(module, const char *, i); + ar_size = i; + + for (i = 0; attrs[i]; i++) { + int j; + const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]); + enum ldb_map_attr_type map_type; + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Local attribute '%s' does not have a definition!\n", attrs[i]); + map_type = MAP_IGNORE; + } else map_type = attr->type; + + switch (map_type) + { + case MAP_IGNORE: break; + case MAP_KEEP: + if (last_element >= ar_size) { + ret = talloc_realloc(module, ret, const char *, ar_size+1); + ar_size++; + } + ret[last_element] = attr->local_name; + last_element++; + break; + + case MAP_RENAME: + case MAP_CONVERT: + if (last_element >= ar_size) { + ret = talloc_realloc(module, ret, const char *, ar_size+1); + ar_size++; + } + ret[last_element] = attr->u.rename.remote_name; + last_element++; + break; + + case MAP_GENERATE: + /* Add remote_names[] for this attribute to the list of + * attributes to request from the remote server */ + for (j = 0; attr->u.generate.remote_names[j]; j++) { + if (last_element >= ar_size) { + ret = talloc_realloc(module, ret, const char *, ar_size+1); + ar_size++; + } + ret[last_element] = attr->u.generate.remote_names[j]; + last_element++; + } + break; + } + } + + if (last_element >= ar_size) { + ret = talloc_realloc(module, ret, const char *, ar_size+1); + ar_size++; + } + + ret[last_element] = NULL; + + return ret; +} + +static const char **available_local_attributes(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_map_context *privdat = map_get_privdat(module); + int i, j; + int count = 0; + const char **ret = talloc_array(module, const char *, 1); + + ret[0] = NULL; + + for (i = 0; privdat->attribute_maps[i].local_name; i++) { + BOOL avail = False; + const struct ldb_map_attribute *attr = &privdat->attribute_maps[i]; + + /* If all remote attributes for this attribute are present, add the + * local one to the list */ + + switch (attr->type) { + case MAP_IGNORE: break; + case MAP_KEEP: + avail = (ldb_msg_find_ldb_val(msg, attr->local_name) != NULL); + break; + + case MAP_RENAME: + case MAP_CONVERT: + avail = (ldb_msg_find_ldb_val(msg, attr->u.rename.remote_name) != NULL); + break; + + case MAP_GENERATE: + avail = True; + for (j = 0; attr->u.generate.remote_names[j]; j++) { + avail &= (ldb_msg_find_ldb_val(msg, attr->u.generate.remote_names[j]) != NULL); + } + break; + } + + if (!avail) + continue; + + ret = talloc_realloc(module, ret, const char *, count+2); + ret[count] = attr->local_name; + ret[count+1] = NULL; + count++; + } + + return ret; +} + +/* Used for search */ +static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, const char * const*attrs, const struct ldb_message *mi) +{ + int i, j; + struct ldb_message *msg = talloc_zero(module, struct ldb_message); + struct ldb_message_element *elm, *oldelm; + struct ldb_map_context *privdat = map_get_privdat(module); + const char **newattrs = NULL; + + msg->dn = map_remote_dn(privdat, module, mi->dn); + + ldb_msg_add_string(module->ldb, msg, "mappedFromDn", ldb_dn_linearize(msg, mi->dn)); + + /* Loop over attrs, find in ldb_map_attribute array and + * run generate() */ + + if (attrs == NULL) { + /* Generate list of the local attributes that /can/ be generated + * using the specific remote attributes */ + + attrs = newattrs = available_local_attributes(module, mi); + } + + for (i = 0; attrs[i]; i++) { + const struct ldb_map_attribute *attr = map_find_attr_local(privdat, attrs[i]); + enum ldb_map_attr_type map_type; + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Unable to find local attribute '%s' when generating incoming message\n", attrs[i]); + map_type = MAP_IGNORE; + } else map_type = attr->type; + + switch (map_type) { + case MAP_IGNORE:break; + case MAP_RENAME: + oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name); + if (!oldelm) continue; + + elm = talloc(msg, struct ldb_message_element); + elm->name = talloc_strdup(elm, attr->local_name); + elm->num_values = oldelm->num_values; + elm->values = talloc_reference(elm, oldelm->values); + + ldb_msg_add(module->ldb, msg, elm, oldelm->flags); + break; + + case MAP_CONVERT: + oldelm = ldb_msg_find_element(mi, attr->u.rename.remote_name); + if (!oldelm) continue; + + elm = talloc(msg, struct ldb_message_element); + elm->name = talloc_strdup(elm, attr->local_name); + elm->num_values = oldelm->num_values; + elm->values = talloc_array(elm, struct ldb_val, elm->num_values); + + for (j = 0; j < oldelm->num_values; j++) + elm->values[j] = attr->u.convert.convert_remote(privdat, elm, &oldelm->values[j]); + + ldb_msg_add(module->ldb, msg, elm, oldelm->flags); + break; + + case MAP_KEEP: + oldelm = ldb_msg_find_element(mi, attr->local_name); + if (!oldelm) continue; + + elm = talloc(msg, struct ldb_message_element); + + elm->num_values = oldelm->num_values; + elm->values = talloc_reference(elm, oldelm->values); + elm->name = talloc_strdup(elm, oldelm->name); + + ldb_msg_add(module->ldb, msg, elm, oldelm->flags); + break; + + case MAP_GENERATE: + elm = attr->u.generate.generate_local(privdat, msg, attr->local_name, mi); + if (!elm) continue; + + ldb_msg_add(module->ldb, msg, elm, elm->flags); + break; + default: + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Unknown attr->type for %s", attr->local_name); + break; + } + } + + talloc_free(newattrs); + + return msg; +} + +/* Used for add, modify */ +static int ldb_map_message_outgoing(struct ldb_module *module, const struct ldb_message *mo, struct ldb_message **fb, struct ldb_message **mp) +{ + struct ldb_map_context *privdat = map_get_privdat(module); + struct ldb_message *msg = talloc_zero(module, struct ldb_message); + struct ldb_message_element *elm; + int i,j; + + *fb = talloc_zero(module, struct ldb_message); + (*fb)->dn = talloc_reference(*fb, mo->dn); + + *mp = msg; + + msg->private_data = mo->private_data; + + msg->dn = map_local_dn(privdat, module, mo->dn); + + /* Loop over mi and call generate_remote for each attribute */ + for (i = 0; i < mo->num_elements; i++) { + const struct ldb_map_attribute *attr = map_find_attr_local(privdat, mo->elements[i].name); + enum ldb_map_attr_type map_type; + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", mo->elements[i].name); + map_type = MAP_IGNORE; + continue; + } else map_type = attr->type; + + switch (map_type) { + case MAP_IGNORE: /* Add to fallback message */ + elm = talloc(*fb, struct ldb_message_element); + + elm->num_values = mo->elements[i].num_values; + elm->values = talloc_reference(elm, mo->elements[i].values); + elm->name = talloc_strdup(elm, mo->elements[i].name); + + ldb_msg_add(module->ldb, *fb, elm, mo->elements[i].flags); + break; + case MAP_RENAME: + elm = talloc(msg, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = mo->elements[i].num_values; + elm->values = talloc_reference(elm, mo->elements[i].values); + + ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); + break; + + case MAP_CONVERT: + elm = talloc(msg, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = mo->elements[i].num_values; + elm->values = talloc_array(elm, struct ldb_val, elm->num_values); + + for (j = 0; j < elm->num_values; j++) { + elm->values[j] = attr->u.convert.convert_local(privdat, msg, &mo->elements[i].values[j]); + } + + ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); + break; + + case MAP_KEEP: + elm = talloc(msg, struct ldb_message_element); + + elm->num_values = mo->elements[i].num_values; + elm->values = talloc_reference(elm, mo->elements[i].values); + elm->name = talloc_strdup(elm, mo->elements[i].name); + + ldb_msg_add(module->ldb, msg, elm, mo->elements[i].flags); + break; + + case MAP_GENERATE: + attr->u.generate.generate_remote(privdat, attr->local_name, mo, msg); + break; + } + } + + return 0; +} + + +/* + rename a record +*/ +static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_map_context *privdat = map_get_privdat(module); + struct ldb_dn *n_olddn, *n_newdn; + int ret; + + ret = ldb_next_rename_record(module, olddn, newdn); + + n_olddn = map_local_dn(privdat, module, olddn); + n_newdn = map_local_dn(privdat, module, newdn); + + ret = ldb_rename(privdat->mapped_ldb, n_olddn, n_newdn); + + talloc_free(n_olddn); + talloc_free(n_newdn); + + return ret; +} + +/* + delete a record +*/ +static int map_delete(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ldb_map_context *privdat = map_get_privdat(module); + struct ldb_dn *newdn; + int ret; + + ret = ldb_next_delete_record(module, dn); + + newdn = map_local_dn(privdat, module, dn); + + ret = ldb_delete(privdat->mapped_ldb, newdn); + + talloc_free(newdn); + + return ret; +} + +/* search fallback database */ +static int map_search_bytree_fb(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, struct ldb_message ***res) +{ + int ret; + struct ldb_parse_tree t_and, t_not, t_present, *childs[2]; + + t_present.operation = LDB_OP_PRESENT; + t_present.u.present.attr = talloc_strdup(NULL, "isMapped"); + + t_not.operation = LDB_OP_NOT; + t_not.u.isnot.child = &t_present; + + childs[0] = &t_not; + childs[1] = tree; + t_and.operation = LDB_OP_AND; + t_and.u.list.num_elements = 2; + t_and.u.list.elements = childs; + + ret = ldb_next_search_bytree(module, base, scope, &t_and, attrs, res); + + talloc_free(t_present.u.present.attr); + + return ret; +} + +static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, struct ldb_message ***res) +{ + struct ldb_parse_tree *new_tree; + struct ldb_dn *new_base; + struct ldb_message **newres; + const char **newattrs; + int mpret, ret; + struct ldb_map_context *privdat = map_get_privdat(module); + int i; + + /*- search mapped database */ + + new_tree = ldb_map_parse_tree(module, module, tree); + newattrs = ldb_map_attrs(module, attrs); + new_base = map_local_dn(privdat, module, base); + + mpret = ldb_search_bytree(privdat->mapped_ldb, new_base, scope, new_tree, newattrs, &newres); + + talloc_free(new_base); + talloc_free(new_tree); + talloc_free(newattrs); + + if (mpret == -1) { + struct map_private *map_private = module->private_data; + map_private->last_err_string = ldb_errstring(privdat->mapped_ldb); + return -1; + } + + /* + - per returned record, search fallback database for additional data (by dn) + - test if (full expression) is now true + */ + + *res = talloc_array(module, struct ldb_message *, mpret); + + ret = 0; + + for (i = 0; i < mpret; i++) { + struct ldb_message *merged = ldb_map_message_incoming(module, attrs, newres[i]); + struct ldb_message **extrares = NULL; + int extraret; + + /* Merge with additional data from local database */ + extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares); + + if (extraret == -1) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Error searching for extra data!\n"); + } else if (extraret > 1) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "More than one result for extra data!\n"); + talloc_free(newres); + return -1; + } else if (extraret == 0) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "No extra data found for remote DN"); + } + + if (extraret == 1) { + int j; + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Extra data found for remote DN"); + for (j = 0; j < extrares[0]->num_elements; j++) { + ldb_msg_add(module->ldb, merged, &(extrares[0]->elements[j]), extrares[0]->elements[j].flags); + } + + ldb_msg_add_string(module->ldb, merged, "extraMapped", "TRUE"); + } else { + ldb_msg_add_string(module->ldb, merged, "extraMapped", "FALSE"); + } + + if (ldb_match_msg(module->ldb, merged, tree, base, scope)) { + (*res)[ret] = merged; + ret++; + } else { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Discarded merged message because it did not match"); + } + } + + talloc_free(newres); + + return ret; +} + + +/* + search for matching records using a ldb_parse_tree +*/ +static int map_search_bytree(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, struct ldb_message ***res) +{ + struct ldb_message **fbres, **mpres; + int i; + int ret_fb, ret_mp; + + ret_fb = map_search_bytree_fb(module, base, scope, tree, attrs, &fbres); + if (ret_fb == -1) + return -1; + + ret_mp = map_search_bytree_mp(module, base, scope, tree, attrs, &mpres); + if (ret_mp == -1) { + return -1; + } + + /* Merge results */ + *res = talloc_array(module, struct ldb_message *, ret_fb + ret_mp); + + for (i = 0; i < ret_fb; i++) (*res)[i] = fbres[i]; + for (i = 0; i < ret_mp; i++) (*res)[ret_fb+i] = mpres[i]; + + return ret_fb + ret_mp; +} +/* + search for matching records +*/ +static int map_search(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, const char *expression, + const char * const *attrs, struct ldb_message ***res) +{ + struct map_private *map = module->private_data; + struct ldb_parse_tree *tree; + int ret; + + tree = ldb_parse_tree(NULL, expression); + if (tree == NULL) { + map->last_err_string = "expression parse failed"; + return -1; + } + + ret = map_search_bytree(module, base, scope, tree, attrs, res); + talloc_free(tree); + return ret; +} + +/* + add a record +*/ +static int map_add(struct ldb_module *module, const struct ldb_message *msg) +{ + int ret; + struct ldb_map_context *privdat = map_get_privdat(module); + struct ldb_message *fb, *mp; + + if (!map_is_mappable(privdat, msg)) { + return ldb_next_add_record(module, msg); + } + + if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) + return -1; + + ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE"); + + ret = ldb_next_add_record(module, fb); + if (ret == -1) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed"); + return -1; + } + + ret = ldb_add(privdat->mapped_ldb, mp); + if (ret == -1) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed"); + return -1; + } + + talloc_free(fb); + talloc_free(mp); + + return ret; +} + + +/* + modify a record +*/ +static int map_modify(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_map_context *privdat = map_get_privdat(module); + struct ldb_message *fb, *mp; + int ret; + + if (!map_is_mappable(privdat, msg)) + return ldb_next_modify_record(module, msg); + + + if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) + return -1; + + ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE"); + + ret = ldb_next_modify_record(module, fb); + + ret = ldb_modify(privdat->mapped_ldb, mp); + + talloc_free(fb); + talloc_free(mp); + + return ret; +} + +static int map_lock(struct ldb_module *module, const char *lockname) +{ + return ldb_next_named_lock(module, lockname); +} + +static int map_unlock(struct ldb_module *module, const char *lockname) +{ + return ldb_next_named_unlock(module, lockname); +} + +/* + return extended error information +*/ +static const char *map_errstring(struct ldb_module *module) +{ + struct map_private *map = module->private_data; + + if (map->last_err_string) + return map->last_err_string; + + return ldb_next_errstring(module); +} + +static const struct ldb_module_ops map_ops = { + .name = "map", + .search = map_search, + .search_bytree = map_search_bytree, + .add_record = map_add, + .modify_record = map_modify, + .delete_record = map_delete, + .rename_record = map_rename, + .named_lock = map_lock, + .named_unlock = map_unlock, + .errstring = map_errstring +}; + +static char *map_find_url(struct ldb_context *ldb, const char *name) +{ + const char * const attrs[] = { "@MAP_URL" , NULL}; + struct ldb_message **msg = NULL; + struct ldb_dn *mods; + char *url; + int ret; + + mods = ldb_dn_string_compose(ldb, NULL, "@MAP=%s", name); + if (mods == NULL) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Can't construct DN"); + return NULL; + } + + ret = ldb_search(ldb, mods, LDB_SCOPE_BASE, "", attrs, &msg); + talloc_free(mods); + if (ret < 1) { + ldb_debug(ldb, LDB_DEBUG_ERROR, "Not enough results found looking for @MAP"); + return NULL; + } + + url = talloc_strdup(ldb, ldb_msg_find_string(msg[0], "@MAP_URL", NULL)); + + talloc_free(msg); + + return url; +} + +/* the init function */ +struct ldb_module *ldb_map_init(struct ldb_context *ldb, const struct ldb_map_attribute *attrs, const struct ldb_map_objectclass *ocls, const char *name) +{ + int i, j; + struct ldb_module *ctx; + struct map_private *data; + char *url; + + ctx = talloc(ldb, struct ldb_module); + if (!ctx) + return NULL; + + data = talloc(ctx, struct map_private); + if (!data) { + talloc_free(ctx); + return NULL; + } + + data->context.mapped_ldb = ldb_init(data); + url = map_find_url(ldb, name); + + if (!url) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "@MAP=%s not set!\n", name); + return NULL; + } + + if (ldb_connect(data->context.mapped_ldb, url, 0, NULL) != 0) { + ldb_debug(ldb, LDB_DEBUG_FATAL, "Unable to open mapped database for %s at '%s'\n", name, url); + return NULL; + } + + talloc_free(url); + + data->last_err_string = NULL; + + /* Get list of attribute maps */ + j = 0; + data->context.attribute_maps = NULL; + + for (i = 0; attrs[i].local_name; i++) { + data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); + data->context.attribute_maps[j] = attrs[i]; + j++; + } + + for (i = 0; builtin_attribute_maps[i].local_name; i++) { + data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); + data->context.attribute_maps[j] = builtin_attribute_maps[i]; + j++; + } + + data->context.attribute_maps = talloc_realloc(data, data->context.attribute_maps, struct ldb_map_attribute, j+1); + ZERO_STRUCT(data->context.attribute_maps[j].local_name); + + data->context.objectclass_maps = ocls; + ctx->private_data = data; + ctx->ldb = ldb; + ctx->prev = ctx->next = NULL; + ctx->ops = &map_ops; + + return ctx; +} + +static struct ldb_val map_convert_local_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn;; + struct ldb_val *newval; + + dn = ldb_dn_explode(ctx, (char *)val->data); + + newdn = map_local_dn(map, ctx, dn); + + talloc_free(dn); + + newval = talloc(ctx, struct ldb_val); + newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn); + newval->length = strlen((char *)newval->data); + + talloc_free(newdn); + + return *newval; +} + +static struct ldb_val map_convert_remote_dn(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + struct ldb_dn *dn, *newdn;; + struct ldb_val *newval; + + dn = ldb_dn_explode(ctx, (char *)val->data); + + newdn = map_remote_dn(map, ctx, dn); + + talloc_free(dn); + + newval = talloc(ctx, struct ldb_val); + newval->data = (uint8_t *)ldb_dn_linearize(ctx, newdn); + newval->length = strlen((char *)newval->data); + + talloc_free(newdn); + + return *newval; +} + +static struct ldb_val map_convert_local_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + int i; + + for (i = 0; map->objectclass_maps[i].local_name; i++) { + if (!strcmp(map->objectclass_maps[i].local_name, (char *)val->data)) { + struct ldb_val newval; + newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].remote_name); + newval.length = strlen((char *)newval.data); + + return ldb_val_dup(ctx, &newval); + } + } + + return ldb_val_dup(ctx, val); +} + +static struct ldb_val map_convert_remote_objectclass(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) +{ + int i; + + for (i = 0; map->objectclass_maps[i].remote_name; i++) { + if (!strcmp(map->objectclass_maps[i].remote_name, (char *)val->data)) { + struct ldb_val newval; + newval.data = (uint8_t*)talloc_strdup(ctx, map->objectclass_maps[i].local_name); + newval.length = strlen((char *)newval.data); + + return ldb_val_dup(ctx, &newval); + } + } + + return ldb_val_dup(ctx, val); +} + +static const struct ldb_map_attribute builtin_attribute_maps[] = { + { + .local_name = "dn", + .type = MAP_CONVERT, + .u.convert.remote_name = "dn", + .u.convert.convert_local = map_convert_local_dn, + .u.convert.convert_remote = map_convert_remote_dn, + }, + { + .local_name = "objectclass", + .type = MAP_CONVERT, + .u.convert.remote_name = "objectclass", + .u.convert.convert_local = map_convert_local_objectclass, + .u.convert.convert_remote = map_convert_remote_objectclass, + }, + { + .local_name = NULL, + } +}; + diff --git a/source4/lib/ldb/modules/ldb_map.h b/source4/lib/ldb/modules/ldb_map.h new file mode 100644 index 0000000000..02fec649c6 --- /dev/null +++ b/source4/lib/ldb/modules/ldb_map.h @@ -0,0 +1,108 @@ +/* + ldb database library - map backend + + Copyright (C) Jelmer Vernooij 2005 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __LDB_MAP_H__ +#define __LDB_MAP_H__ + +/* ldb_map is a skeleton LDB module that can be used for any other modules + * that need to map attributes. + * + * The term 'remote' in this header refers to the connection where the + * original schema is used on while 'local' means the local connection + * that any upper layers will use. + * + * All local attributes will have to have a definition. Not all remote + * attributes need a definition as LDB is a lot less stricter then LDAP + * (in other words, sending unknown attributes to an LDAP server hurts us, + * returning too much attributes in ldb_search() doesn't) + */ + +struct ldb_map_context; + +struct ldb_map_attribute +{ + const char *local_name; /* local name */ + + enum ldb_map_attr_type { + MAP_IGNORE, /* Ignore this local attribute. Doesn't exist remotely. */ + MAP_KEEP, /* Keep as is. Same name locally and remotely. */ + MAP_RENAME, /* Simply rename the attribute. Name changes, data is the same */ + MAP_CONVERT, /* Rename + convert data */ + MAP_GENERATE /* Use generate function for generating new name/data. + Used for generating attributes based on + 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 *); + + union { + struct { + const char *remote_name; + } rename; + + struct { + const char *remote_name; + struct ldb_val (*convert_local) (struct ldb_map_context *, TALLOC_CTX *, const struct ldb_val *); + struct ldb_val (*convert_remote) (struct ldb_map_context *, TALLOC_CTX *, const struct ldb_val *); + } convert; + + struct { + /* Generate the local attribute from remote message */ + struct ldb_message_element *(*generate_local) ( + struct ldb_map_context *, + TALLOC_CTX *ctx, + const char *attr, + const struct ldb_message *remote); + + /* Update remote message with information from local message */ + void (*generate_remote) ( + struct ldb_map_context *, + const char *local_attr, + const struct ldb_message *local, + struct ldb_message *remote); + + /* 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]; + } generate; + } u; +}; + +struct ldb_map_objectclass +{ + const char *local_name; + const char *remote_name; +}; + +struct ldb_map_context +{ + struct ldb_map_attribute *attribute_maps; + const struct ldb_map_objectclass *objectclass_maps; + struct ldb_context *mapped_ldb; +}; + +#endif /* __LDB_MAP_H__ */ diff --git a/source4/lib/ldb/samba/samba3sam.c b/source4/lib/ldb/samba/samba3sam.c deleted file mode 100644 index f7d83ced8f..0000000000 --- a/source4/lib/ldb/samba/samba3sam.c +++ /dev/null @@ -1,631 +0,0 @@ -/* - ldb database library - Samba3 SAM compatibility backend - - Copyright (C) Jelmer Vernooij 2005 - - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "includes.h" -#include "ldb/ldb_map/ldb_map.h" -#include "ldb/include/ldb.h" -#include "ldb/include/ldb_private.h" - -/* FIXME: - * sambaSID -> member (dn!) - * sambaSIDList -> member (dn!) - * sambaDomainName -> name - * sambaTrustPassword - * sambaUnixIdPool - * sambaIdmapEntry - * sambaAccountPolicy - * sambaSidEntry - * sambaAcctFlags -> systemFlags ? - * sambaPasswordHistory -> ntPwdHistory*/ - -/* Not necessary: - * sambaConfig - * sambaShare - * sambaConfigOption - * sambaNextGroupRid - * sambaNextUserRid - * sambaAlgorithmicRidBase - */ - -/* Not in Samba4: - * sambaKickoffTime - * sambaPwdCanChange - * sambaPwdMustChange - * sambaHomePath - * sambaHomeDrive - * sambaLogonScript - * sambaProfilePath - * sambaUserWorkstations - * sambaMungedDial - * sambaLogonHours */ - -/* In Samba4 but not in Samba3: -*/ - -static struct ldb_val convert_sid_rid(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - printf("Converting SID TO RID *\n"); - - return ldb_val_dup(ctx, val); -} - -static struct ldb_val convert_rid_sid(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - printf("Converting RID TO SID *\n"); - - return ldb_val_dup(ctx, val); -} - -static struct ldb_val convert_unix_id2name(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - printf("Converting UNIX ID to name\n"); - - return ldb_val_dup(ctx, val); -} - -static struct ldb_val convert_unix_name2id(struct ldb_map_context *map, TALLOC_CTX *ctx, const struct ldb_val *val) -{ - printf("Converting UNIX name to ID\n"); - - return ldb_val_dup(ctx, val); -} - -const struct ldb_map_objectclass samba3_objectclasses[] = { - { "group", "sambaGroupMapping" }, - { "user", "sambaSAMAccount" }, - { "domain", "sambaDomain" }, - { NULL, NULL } -}; - -const struct ldb_map_attribute samba3_attributes[] = -{ - /* sambaNextRid -> nextRid */ - { - .local_name = "nextRid", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaNextRid", - }, - - /* sambaBadPasswordTime -> badPasswordtime*/ - { - .local_name = "badPasswordTime", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaBadPasswordTime", - }, - - /* sambaLMPassword -> lmPwdHash*/ - { - .local_name = "lmPwdHash", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaLMPassword", - }, - - /* sambaGroupType -> groupType */ - { - .local_name = "groupType", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaGroupType", - }, - - /* sambaNTPassword -> ntPwdHash*/ - { - .local_name = "badPwdCount", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaNTPassword", - }, - - /* sambaPrimaryGroupSID -> primaryGroupID */ - { - .local_name = "primaryGroupID", - .type = MAP_CONVERT, - .u.convert.remote_name = "sambaPrimaryGroupSID", - .u.convert.convert_local = convert_rid_sid, - .u.convert.convert_remote = convert_sid_rid, - }, - - /* sambaBadPasswordCount -> badPwdCount */ - { - .local_name = "badPwdCount", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaBadPasswordCount", - }, - - /* sambaLogonTime -> lastLogon*/ - { - .local_name = "lastLogon", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaLogonTime", - }, - - /* sambaLogoffTime -> lastLogoff*/ - { - .local_name = "lastLogoff", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaLogoffTime", - }, - - /* gidNumber -> unixName */ - { - .local_name = "unixName", - .type = MAP_CONVERT, - .u.convert.remote_name = "gidNumber", - .u.convert.convert_local = convert_unix_name2id, - .u.convert.convert_remote = convert_unix_id2name, - }, - - /* uid -> unixName */ - { - .local_name = "unixName", - .type = MAP_CONVERT, - .u.convert.remote_name = "uid", - .u.convert.convert_local = convert_unix_name2id, - .u.convert.convert_remote = convert_unix_id2name, - }, - - /* displayName -> name */ - { - .local_name = "name", - .type = MAP_RENAME, - .u.rename.remote_name = "displayName", - }, - - /* cn */ - { - .local_name = "cn", - .type = MAP_KEEP, - }, - - /* sAMAccountName -> cn */ - { - .local_name = "sAMAccountName", - .type = MAP_RENAME, - .u.rename.remote_name = "uid", - }, - - /* objectCategory */ - { - .local_name = "objectCategory", - .type = MAP_IGNORE, - }, - - /* objectGUID */ - { - .local_name = "objectGUID", - .type = MAP_IGNORE, - }, - - /* objectVersion */ - { - .local_name = "objectVersion", - .type = MAP_IGNORE, - }, - - /* codePage */ - { - .local_name = "codePage", - .type = MAP_IGNORE, - }, - - /* dNSHostName */ - { - .local_name = "dNSHostName", - .type = MAP_IGNORE, - }, - - - /* dnsDomain */ - { - .local_name = "dnsDomain", - .type = MAP_IGNORE, - }, - - /* dnsRoot */ - { - .local_name = "dnsRoot", - .type = MAP_IGNORE, - }, - - /* countryCode */ - { - .local_name = "countryCode", - .type = MAP_IGNORE, - }, - - /* nTMixedDomain */ - { - .local_name = "nTMixedDomain", - .type = MAP_IGNORE, - }, - - /* operatingSystem */ - { - .local_name = "operatingSystem", - .type = MAP_IGNORE, - }, - - /* operatingSystemVersion */ - { - .local_name = "operatingSystemVersion", - .type = MAP_IGNORE, - }, - - - /* servicePrincipalName */ - { - .local_name = "servicePrincipalName", - .type = MAP_IGNORE, - }, - - /* msDS-Behavior-Version */ - { - .local_name = "msDS-Behavior-Version", - .type = MAP_IGNORE, - }, - - /* msDS-KeyVersionNumber */ - { - .local_name = "msDS-KeyVersionNumber", - .type = MAP_IGNORE, - }, - - /* msDs-masteredBy */ - { - .local_name = "msDs-masteredBy", - .type = MAP_IGNORE, - }, - - /* ou */ - { - .local_name = "ou", - .type = MAP_KEEP, - }, - - /* dc */ - { - .local_name = "dc", - .type = MAP_KEEP, - }, - - /* description */ - { - .local_name = "description", - .type = MAP_KEEP, - }, - - /* sambaSID -> objectSid*/ - { - .local_name = "objectSid", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaSID", - }, - - /* sambaPwdLastSet -> pwdLastSet */ - { - .local_name = "pwdLastSet", - .type = MAP_RENAME, - .u.rename.remote_name = "sambaPwdLastSet", - }, - - /* accountExpires */ - { - .local_name = "accountExpires", - .type = MAP_IGNORE, - }, - - /* adminCount */ - { - .local_name = "adminCount", - .type = MAP_IGNORE, - }, - - /* canonicalName */ - { - .local_name = "canonicalName", - .type = MAP_IGNORE, - }, - - /* createTimestamp */ - { - .local_name = "createTimestamp", - .type = MAP_IGNORE, - }, - - /* creationTime */ - { - .local_name = "creationTime", - .type = MAP_IGNORE, - }, - - /* dMDLocation */ - { - .local_name = "dMDLocation", - .type = MAP_IGNORE, - }, - - /* fSMORoleOwner */ - { - .local_name = "fSMORoleOwner", - .type = MAP_IGNORE, - }, - - /* forceLogoff */ - { - .local_name = "forceLogoff", - .type = MAP_IGNORE, - }, - - /* instanceType */ - { - .local_name = "instanceType", - .type = MAP_IGNORE, - }, - - /* invocationId */ - { - .local_name = "invocationId", - .type = MAP_IGNORE, - }, - - /* isCriticalSystemObject */ - { - .local_name = "isCriticalSystemObject", - .type = MAP_IGNORE, - }, - - /* localPolicyFlags */ - { - .local_name = "localPolicyFlags", - .type = MAP_IGNORE, - }, - - /* lockOutObservationWindow */ - { - .local_name = "lockOutObservationWindow", - .type = MAP_IGNORE, - }, - - /* lockoutDuration */ - { - .local_name = "lockoutDuration", - .type = MAP_IGNORE, - }, - - /* lockoutThreshold */ - { - .local_name = "lockoutThreshold", - .type = MAP_IGNORE, - }, - - /* logonCount */ - { - .local_name = "logonCount", - .type = MAP_IGNORE, - }, - - /* masteredBy */ - { - .local_name = "masteredBy", - .type = MAP_IGNORE, - }, - - /* maxPwdAge */ - { - .local_name = "maxPwdAge", - .type = MAP_IGNORE, - }, - - /* member */ - { - .local_name = "member", - .type = MAP_IGNORE, - }, - - /* memberOf */ - { - .local_name = "memberOf", - .type = MAP_IGNORE, - }, - - /* minPwdAge */ - { - .local_name = "minPwdAge", - .type = MAP_IGNORE, - }, - - /* minPwdLength */ - { - .local_name = "minPwdLength", - .type = MAP_IGNORE, - }, - - /* modifiedCount */ - { - .local_name = "modifiedCount", - .type = MAP_IGNORE, - }, - - /* modifiedCountAtLastProm */ - { - .local_name = "modifiedCountAtLastProm", - .type = MAP_IGNORE, - }, - - /* modifyTimestamp */ - { - .local_name = "modifyTimestamp", - .type = MAP_IGNORE, - }, - - /* nCName */ - { - .local_name = "nCName", - .type = MAP_IGNORE, - }, - - /* nETBIOSName */ - { - .local_name = "nETBIOSName", - .type = MAP_IGNORE, - }, - - /* oEMInformation */ - { - .local_name = "oEMInformation", - .type = MAP_IGNORE, - }, - - /* privilege */ - { - .local_name = "privilege", - .type = MAP_IGNORE, - }, - - /* pwdHistoryLength */ - { - .local_name = "pwdHistoryLength", - .type = MAP_IGNORE, - }, - - /* pwdProperties */ - { - .local_name = "pwdProperties", - .type = MAP_IGNORE, - }, - - /* rIDAvailablePool */ - { - .local_name = "rIDAvailablePool", - .type = MAP_IGNORE, - }, - - /* revision */ - { - .local_name = "revision", - .type = MAP_IGNORE, - }, - - /* ridManagerReference */ - { - .local_name = "ridManagerReference", - .type = MAP_IGNORE, - }, - - /* sAMAccountType */ - { - .local_name = "sAMAccountType", - .type = MAP_IGNORE, - }, - - /* sPNMappings */ - { - .local_name = "sPNMappings", - .type = MAP_IGNORE, - }, - - /* serverReference */ - { - .local_name = "serverReference", - .type = MAP_IGNORE, - }, - - /* serverState */ - { - .local_name = "serverState", - .type = MAP_IGNORE, - }, - - /* showInAdvancedViewOnly */ - { - .local_name = "showInAdvancedViewOnly", - .type = MAP_IGNORE, - }, - - /* subRefs */ - { - .local_name = "subRefs", - .type = MAP_IGNORE, - }, - - /* systemFlags */ - { - .local_name = "systemFlags", - .type = MAP_IGNORE, - }, - - /* uASCompat */ - { - .local_name = "uASCompat", - .type = MAP_IGNORE, - }, - - /* uSNChanged */ - { - .local_name = "uSNChanged", - .type = MAP_IGNORE, - }, - - /* uSNCreated */ - { - .local_name = "uSNCreated", - .type = MAP_IGNORE, - }, - - /* unicodePwd */ - { - .local_name = "unicodePwd", - .type = MAP_IGNORE, - }, - - /* userAccountControl */ - { - .local_name = "userAccountControl", - .type = MAP_IGNORE, - }, - - /* whenChanged */ - { - .local_name = "whenChanged", - .type = MAP_IGNORE, - }, - - /* whenCreated */ - { - .local_name = "whenCreated", - .type = MAP_IGNORE, - }, - - { - .local_name = NULL, - } -}; - - /* the init function */ -#ifdef HAVE_DLOPEN_DISABLED -struct ldb_module *init_module(struct ldb_context *ldb, const char *options[]) -#else -struct ldb_module *ldb_samba3sam_module_init(struct ldb_context *ldb, const char *options[]) -#endif -{ - return ldb_map_init(ldb, samba3_attributes, samba3_objectclasses, "samba3sam"); -} diff --git a/source4/lib/ldb/tests/samba3.ldif b/source4/lib/ldb/tests/samba3.ldif deleted file mode 100644 index 035eb1c516..0000000000 --- a/source4/lib/ldb/tests/samba3.ldif +++ /dev/null @@ -1,200 +0,0 @@ -dn: ou=Users,ou=Tests,dc=vernstok,dc=nl -objectClass: organizationalUnit -ou: Users - -dn: ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: organizationalUnit -ou: Groups - -dn: uid=nobody,ou=Users,ou=Tests,dc=vernstok,dc=nl -cn: nobody -sn: nobody -objectClass: inetOrgPerson -objectClass: sambaSAMAccount -objectClass: posixAccount -objectClass: shadowAccount -gidNumber: 514 -uid: nobody -uidNumber: 999 -homeDirectory: /dev/null -sambaPwdLastSet: 0 -sambaLogonTime: 0 -sambaLogoffTime: 2147483647 -sambaKickoffTime: 2147483647 -sambaPwdCanChange: 0 -sambaPwdMustChange: 2147483647 -sambaHomePath: \\PDC-SMB3\home\%U -sambaHomeDrive: H: -sambaProfilePath: \\PDC-SMB3\profiles\%U\nobody -sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-514 -sambaLMPassword: NO PASSWORDXXXXXXXXXXXXXXXXXXXXX -sambaNTPassword: NO PASSWORDXXXXXXXXXXXXXXXXXXXXX -sambaAcctFlags: [NU ] -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-2998 -loginShell: /bin/false - -dn: cn=Domain Admins,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 512 -cn: Domain Admins -memberUid: Administrator -description: Netbios Domain Administrators -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-512 -sambaGroupType: 2 -displayName: Domain Admins - -dn: cn=Domain Users,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 513 -cn: Domain Users -description: Netbios Domain Users -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-513 -sambaGroupType: 2 -displayName: Domain Users - -dn: cn=Domain Guests,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 514 -cn: Domain Guests -description: Netbios Domain Guests Users -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-514 -sambaGroupType: 2 -displayName: Domain Guests - -dn: cn=Print Operators,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 550 -cn: Print Operators -description: Netbios Domain Print Operators -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-550 -sambaGroupType: 2 -displayName: Print Operators - -dn: cn=Backup Operators,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 551 -cn: Backup Operators -description: Netbios Domain Members can bypass file security to back up files -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-551 -sambaGroupType: 2 -displayName: Backup Operators - -dn: cn=Replicator,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 552 -cn: Replicator -description: Netbios Domain Supports file replication in a sambaDomainName -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-552 -sambaGroupType: 2 -displayName: Replicator - -dn: cn=Domain Computers,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 553 -cn: Domain Computers -description: Netbios Domain Computers accounts -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-553 -sambaGroupType: 2 -displayName: Domain Computers - -dn: cn=Administrators,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 544 -cn: Administrators -description: Netbios Domain Members can fully administer the computer/sambaDomainName -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-544 -sambaGroupType: 2 -displayName: Administrators - -dn: cn=Users,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 545 -cn: Users -description: Netbios Domain Ordinary users -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-545 -sambaGroupType: 2 -displayName: users - -dn: cn=Guests,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 546 -cn: Guests -memberUid: nobody -description: Netbios Domain Users granted guest access to the computer/sambaDomainName -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-546 -sambaGroupType: 2 -displayName: Guests - -dn: cn=Power Users,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 547 -cn: Power Users -description: Netbios Domain Members can share directories and printers -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-547 -sambaGroupType: 2 -displayName: Power Users - -dn: cn=Account Operators,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 548 -cn: Account Operators -description: Netbios Domain Users to manipulate users accounts -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-548 -sambaGroupType: 2 -displayName: Account Operators - -dn: cn=Server Operators,ou=Groups,ou=Tests,dc=vernstok,dc=nl -objectClass: posixGroup -objectClass: sambaGroupMapping -gidNumber: 549 -cn: Server Operators -description: Netbios Domain Server Operators -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-549 -sambaGroupType: 2 -displayName: Server Operators - -dn: ou=Computers,ou=Tests,dc=vernstok,dc=nl -objectClass: organizationalUnit -ou: Computers - -dn: uid=Administrator,ou=Users,ou=Tests,dc=vernstok,dc=nl -cn: Administrator -sn: Administrator -objectClass: inetOrgPerson -objectClass: sambaSAMAccount -objectClass: posixAccount -objectClass: shadowAccount -gidNumber: 512 -uid: Administrator -uidNumber: 0 -homeDirectory: /home/%U -sambaPwdLastSet: 0 -sambaLogonTime: 0 -sambaLogoffTime: 2147483647 -sambaKickoffTime: 2147483647 -sambaPwdCanChange: 0 -sambaPwdMustChange: 2147483647 -sambaHomePath: \\PDC-SMB3\home\%U -sambaHomeDrive: H: -sambaProfilePath: \\PDC-SMB3\profiles\%U\Administrator -sambaPrimaryGroupSID: S-1-5-21-4231626423-2410014848-2360679739-512 -sambaLMPassword: XXX -sambaNTPassword: XXX -sambaAcctFlags: [U ] -sambaSID: S-1-5-21-4231626423-2410014848-2360679739-2996 -loginShell: /bin/false -gecos: Netbios Domain Administrator - - diff --git a/source4/lib/samba3/PLAN b/source4/lib/samba3/PLAN index abc3d5d6ae..67395ca84c 100644 --- a/source4/lib/samba3/PLAN +++ b/source4/lib/samba3/PLAN @@ -1,4 +1,5 @@ TODO (SoC project): - move ini parsing stuff to seperate file param/ini.c - - test ldb_map backend (testsuite?) - parse "passdb backend" setting and parse tdbsam/passdb based on it + - test ldb_map backend (testsuite?) + - testsuite for the static upgrade diff --git a/source4/setup/upgrade b/source4/setup/upgrade old mode 100644 new mode 100755 -- cgit