diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samba3sam.c | 44 | ||||
-rw-r--r-- | source4/lib/ldb/modules/ldb_map.c | 507 | ||||
-rw-r--r-- | source4/lib/ldb/modules/ldb_map.h | 10 | ||||
-rw-r--r-- | source4/scripting/libjs/upgrade.js | 11 | ||||
-rw-r--r-- | testdata/samba3/samba3.ldif | 43 | ||||
-rwxr-xr-x | testprogs/ejs/samba3sam | 41 |
6 files changed, 436 insertions, 220 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/samba3sam.c b/source4/dsdb/samdb/ldb_modules/samba3sam.c index 9337b612ba7..9730363e92a 100644 --- a/source4/dsdb/samdb/ldb_modules/samba3sam.c +++ b/source4/dsdb/samdb/ldb_modules/samba3sam.c @@ -85,7 +85,7 @@ static struct ldb_val convert_unix_name2id(struct ldb_module *module, TALLOC_CTX static struct ldb_val encode_sid(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val) { struct dom_sid *sid = dom_sid_parse_talloc(ctx, (char *)val->data); - struct ldb_val *out = talloc_zero(out, struct ldb_val); + struct ldb_val *out = talloc_zero(ctx, struct ldb_val); NTSTATUS status; if (sid == NULL) { @@ -128,9 +128,34 @@ static struct ldb_val decode_sid(struct ldb_module *module, TALLOC_CTX *ctx, con } const struct ldb_map_objectclass samba3_objectclasses[] = { - { "group", "sambaGroupMapping" }, - { "user", "sambaSAMAccount" }, - { "domain", "sambaDomain" }, + { + .local_name = "group", + .remote_name = "sambaGroupMapping", + .musts = { "gidNumber", "sambaSID", "sambaGroupType", NULL }, + .mays = { "displayName", "description", "sambaSIDList", NULL }, + }, + { + .local_name = "user", + .remote_name = "sambaSAMAccount", + .base_classes = { "top", NULL }, + .musts = { "uid", "sambaSID", NULL }, + .mays = { "cn", "sambaLMPassword", "sambaNTPassword", + "sambaPwdLastSet", "sambaLogonTime", "sambaLogoffTime", + "sambaKickoffTime", "sambaPwdCanChange", "sambaPwdMustChange", + "sambaAcctFlags", "displayName", "sambaHomePath", "sambaHomeDrive", + "sambaLogonScript", "sambaProfilePath", "description", "sambaUserWorkstations", + "sambaPrimaryGroupSID", "sambaDomainName", "sambaMungedDial", + "sambaBadPasswordCount", "sambaBadPasswordTime", + "sambaPasswordHistory", "sambaLogonHours", NULL } + + }, + { + .local_name = "domain", + .remote_name = "sambaDomain", + .base_classes = { "top", NULL }, + .musts = { "sambaDomainName", "sambaSID", NULL }, + .mays = { "sambaNextRid", "sambaNextGroupRid", "sambaNextUserRid", "sambaAlgorithmicRidBase", NULL }, + }, { NULL, NULL } }; @@ -237,17 +262,6 @@ const struct ldb_map_attribute samba3_attributes[] = }, }, - /* gidNumber -> unixName */ - { - .local_name = "unixName", - .type = MAP_CONVERT, - .u = { - .convert = { - .remote_name = "gidNumber", - }, - }, - }, - /* uid -> unixName */ { .local_name = "unixName", diff --git a/source4/lib/ldb/modules/ldb_map.c b/source4/lib/ldb/modules/ldb_map.c index 5b1afb56bc6..5a5575d1e04 100644 --- a/source4/lib/ldb/modules/ldb_map.c +++ b/source4/lib/ldb/modules/ldb_map.c @@ -27,15 +27,13 @@ #include "ldb/include/ldb_private.h" #include "ldb/modules/ldb_map.h" -/* - * - map_message_outgoing() should: - * - modify: not worry about anything simply map and hope everything - * will be ok. - * - make a list of remote objectclasses that will be used - * given the attributes that are available - * - only add attribute to the remote message if - * it is allowed by the objectclass - * +/* FIXME: + * - per remote objectclass: + * - remote name + * - local name + * - remote bases + * - musts + * - mays */ /* @@ -95,6 +93,17 @@ static const struct ldb_map_attribute builtin_attribute_maps[] = { } }; +static const struct ldb_map_objectclass *map_find_objectclass_remote(struct ldb_map_context *privdat, const char *name) +{ + int i; + for (i = 0; privdat->objectclass_maps[i].remote_name; i++) { + if (!ldb_attr_cmp(privdat->objectclass_maps[i].remote_name, name)) + return &privdat->objectclass_maps[i]; + } + + return NULL; +} + struct map_private { struct ldb_map_context context; const char *last_err_string; @@ -105,41 +114,39 @@ 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 int map_is_mappable(struct ldb_map_context *privdat, const struct ldb_message *msg) +/* Check whether the given attribute can fit into the specified + * message, obeying objectClass restrictions */ +static int map_msg_valid_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr) { - int i; - struct ldb_message_element *el; - - if (ldb_dn_is_special(msg->dn)) - return 0; - - el = ldb_msg_find_element(msg, "objectClass"); + struct ldb_map_context *map = module->private_data; + int i, j; + struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass"); - /* No objectClass... */ if (el == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Can't find objectClass"); return 0; } for (i = 0; i < el->num_values; i++) { - if (map_find_objectclass_local(privdat, (char *)el->values[i].data)) - return 1; + const struct ldb_map_objectclass *class = map_find_objectclass_remote(map, (char *)el->values[i].data); + + if (!class) + continue; + + for (j = 0; class->musts[j]; j++) { + if (!ldb_attr_cmp(class->musts[j], attr)) + return 1; + } + + for (j = 0; class->mays[j]; j++) { + if (!ldb_attr_cmp(class->mays[j], attr)) + return 1; + } } return 0; -} +} + /* 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) @@ -154,6 +161,40 @@ static const struct ldb_map_attribute *map_find_attr_local(struct ldb_map_contex return NULL; } +/* Check if a given attribute can be created by doing mapping from a local attribute to a remote one */ +static int map_msg_can_map_attr(struct ldb_module *module, const struct ldb_message *msg, const char *attr_name) +{ + struct ldb_map_context *map = module->private_data; + int i, j; + + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_map_attribute *attr = map_find_attr_local(map, msg->elements[i].name); + + if (!attr) + continue; + + switch (attr->type) { + case MAP_IGNORE: continue; + case MAP_KEEP: + if (ldb_attr_cmp(attr->local_name, attr_name) == 0) return 1; + break; + case MAP_RENAME: + case MAP_CONVERT: + if (ldb_attr_cmp(attr->u.rename.remote_name, attr_name) == 0) return 1; + break; + case MAP_GENERATE: + for (j = 0; attr->u.generate.remote_names[j]; j++) { + if (ldb_attr_cmp(attr->u.generate.remote_names[j], attr_name) == 0) return 1; + } + break; + } + } + + return 0; +} + + + /* 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) { @@ -547,8 +588,6 @@ static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, c msg->dn = map_remote_dn(module, 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() */ @@ -638,94 +677,6 @@ static struct ldb_message *ldb_map_message_incoming(struct ldb_module *module, c 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_element *elm; - int i,j; - - *fb = talloc_zero(module, struct ldb_message); - (*fb)->dn = talloc_reference(*fb, mo->dn); - - *mp = talloc_zero(module, struct ldb_message); - (*mp)->dn = map_local_dn(module, 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(*mp, 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, *mp, elm, mo->elements[i].flags); - break; - - case MAP_CONVERT: - elm = talloc(*mp, 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(module, *mp, &mo->elements[i].values[j]); - } - - ldb_msg_add(module->ldb, *mp, elm, mo->elements[i].flags); - break; - - case MAP_KEEP: - elm = talloc(*mp, 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, *mp, elm, mo->elements[i].flags); - break; - - case MAP_GENERATE: - attr->u.generate.generate_remote(module, attr->local_name, mo, *mp); - break; - } - } - - if ((*fb)->num_elements == 0) { - ldb_msg_add_string(module->ldb, *fb, "isMapped", "TRUE"); - } - - if ((*mp)->num_elements == 0) { - /* No elements, discard.. */ - talloc_free(*mp); - *mp = NULL; - } - - return 0; -} - - /* rename a record */ @@ -734,6 +685,13 @@ static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, con struct ldb_map_context *privdat = map_get_privdat(module); struct ldb_dn *n_olddn, *n_newdn; int fb_ret, mp_ret; + + fb_ret = ldb_next_rename_record(module, olddn, newdn); + + if (fb_ret != -1) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed"); + return fb_ret; + } n_olddn = map_local_dn(module, module, olddn); n_newdn = map_local_dn(module, module, newdn); @@ -743,16 +701,12 @@ static int map_rename(struct ldb_module *module, const struct ldb_dn *olddn, con ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record renamed"); } - fb_ret = ldb_next_rename_record(module, olddn, newdn); + ldb_next_rename_record(module, olddn, newdn); - if (fb_ret != -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record renamed"); - } - talloc_free(n_olddn); talloc_free(n_newdn); - return (fb_ret == -1 && mp_ret == -1)?-1:0; + return mp_ret; } /* @@ -764,6 +718,12 @@ static int map_delete(struct ldb_module *module, const struct ldb_dn *dn) struct ldb_dn *newdn; int fb_ret, mp_ret; + fb_ret = ldb_next_delete_record(module, dn); + if (fb_ret != -1) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted"); + return fb_ret; + } + newdn = map_local_dn(module, module, dn); mp_ret = ldb_delete(privdat->mapped_ldb, newdn); @@ -771,14 +731,11 @@ static int map_delete(struct ldb_module *module, const struct ldb_dn *dn) ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Mapped record deleted"); } - fb_ret = ldb_next_delete_record(module, dn); - if (fb_ret != -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Fallback record deleted"); - } + ldb_next_delete_record(module, newdn); talloc_free(newdn); - return (fb_ret == -1 && mp_ret == -1)?-1:0; + return mp_ret; } /* search fallback database */ @@ -869,7 +826,7 @@ static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_dn * merged = ldb_map_message_incoming(module, attrs, newres[i]); - /* Merge with additional data from local database */ + /* Merge with additional data from fallback database */ extraret = ldb_next_search(module, merged->dn, LDB_SCOPE_BASE, "", NULL, &extrares); if (extraret == -1) { @@ -888,10 +845,6 @@ static int map_search_bytree_mp(struct ldb_module *module, const struct ldb_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) != 0) { @@ -966,6 +919,20 @@ static int map_search(struct ldb_module *module, const struct ldb_dn *base, return ret; } +static int msg_contains_objectclass(const struct ldb_message *msg, const char *name) +{ + struct ldb_message_element *el = ldb_msg_find_element(msg, "objectClass"); + int i; + + for (i = 0; i < el->num_values; i++) { + if (ldb_attr_cmp((char *)el->values[i].data, name) == 0) { + return 1; + } + } + + return 0; +} + /* add a record */ @@ -974,32 +941,159 @@ 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; + struct ldb_message_element *ocs; + int i; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add"); - if (!map_is_mappable(privdat, msg)) { + if (ldb_dn_is_special(msg->dn)) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record"); return ldb_next_add_record(module, msg); } - if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) - return -1; + mp = talloc_zero(module, struct ldb_message); + mp->dn = map_local_dn(module, mp, msg->dn); - if (fb != NULL) { - ret = ldb_next_add_record(module, fb); - if (ret == -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding fallback record failed"); - return -1; + fb = talloc_zero(module, struct ldb_message); + fb->dn = talloc_reference(fb, msg->dn); + + /* We add objectClass, so 'top' should be no problem */ + ldb_msg_add_string(module->ldb, mp, "objectClass", "top"); + + /* make a list of remote objectclasses that can be used + * given the attributes that are available and add to + * mp_msg */ + for (i = 0; privdat->objectclass_maps[i].local_name; i++) { + int j, has_musts, has_baseclasses; + + /* Add this objectClass to the list if all musts are present */ + for (j = 0; privdat->objectclass_maps[i].musts[j]; j++) { + if (!map_msg_can_map_attr(module, msg, privdat->objectclass_maps[i].musts[j])) + break; } - } - talloc_free(fb); + has_musts = (privdat->objectclass_maps[i].musts[j] == NULL); + + /* Check if base classes are present as well */ + for (j = 0; privdat->objectclass_maps[i].base_classes[j]; j++) { + if (!msg_contains_objectclass(mp, privdat->objectclass_maps[i].base_classes[j])) + break; + } + + has_baseclasses = (privdat->objectclass_maps[i].base_classes[j] == NULL); - if (mp != NULL) { - ret = ldb_add(privdat->mapped_ldb, mp); - if (ret == -1) { - ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Adding mapped record failed"); - return -1; + /* Apparently, it contains all required elements */ + if (has_musts && has_baseclasses) { + ldb_msg_add_string(module->ldb, mp, "objectClass", privdat->objectclass_maps[i].remote_name); } } + ocs = ldb_msg_find_element(mp, "objectClass"); + if (ocs->num_values == 1) { /* Only top */ + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added fallback record"); + return ldb_next_add_record(module, msg); + } + + /* + * - try to map as much attributes as possible where allowed and add them to mp_msg + * - add other attributes to fb_msg + */ + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_map_attribute *attr; + struct ldb_message_element *elm; + enum ldb_map_attr_type map_type; + int j; + int mapped = 0; + + if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) + continue; + + attr = map_find_attr_local(privdat, msg->elements[i].name); + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name); + map_type = MAP_IGNORE; + } else map_type = attr->type; + + /* Decide whether or not we need to map or fallback */ + switch (map_type) { + case MAP_GENERATE: + attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb); + continue; + case MAP_KEEP: + mapped = map_msg_valid_attr(module, mp, attr->local_name); + case MAP_IGNORE: mapped = 0; break; + case MAP_CONVERT: + case MAP_RENAME: mapped = map_msg_valid_attr(module, mp, attr->u.rename.remote_name); + break; + } + + if (mapped) { + switch (map_type) { + case MAP_KEEP: + elm = talloc(fb, struct ldb_message_element); + + elm->num_values = msg->elements[i].num_values; + elm->values = talloc_reference(elm, msg->elements[i].values); + elm->name = talloc_strdup(elm, msg->elements[i].name); + break; + + case MAP_RENAME: + elm = talloc(mp, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = msg->elements[i].num_values; + elm->values = talloc_reference(elm, msg->elements[i].values); + break; + + case MAP_CONVERT: + elm = talloc(mp, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = msg->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(module, mp, &msg->elements[i].values[j]); + } + + mapped = map_msg_valid_attr(module, mp, attr->u.convert.remote_name); + + break; + + case MAP_GENERATE: + case MAP_IGNORE: + ldb_debug(module->ldb, LDB_DEBUG_FATAL, "This line should never be reached"); + break; + } + ldb_msg_add(module->ldb, mp, elm, 0); + } else { + elm = talloc(fb, struct ldb_message_element); + + elm->num_values = msg->elements[i].num_values; + elm->values = talloc_reference(elm, msg->elements[i].values); + elm->name = talloc_strdup(elm, msg->elements[i].name); + + ldb_msg_add(module->ldb, fb, elm, 0); + } + } + + ret = ldb_add(privdat->mapped_ldb, mp); + if (ret == -1) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Adding mapped record failed: %s", ldb_errstring(privdat->mapped_ldb)); + return -1; + } + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_add: Added mapped record"); + + 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_WARNING, "Adding fallback record failed: %s", ldb_next_errstring(module)); + return -1; + } + + talloc_free(fb); talloc_free(mp); return ret; @@ -1013,25 +1107,106 @@ 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; + struct ldb_message_element *elm; + int fb_ret, mp_ret; + int i,j; + + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "ldb_map_modify"); - if (!map_is_mappable(privdat, msg)) + if (ldb_dn_is_special(msg->dn)) return ldb_next_modify_record(module, msg); - if (ldb_map_message_outgoing(module, msg, &fb, &mp) == -1) - return -1; + fb = talloc_zero(module, struct ldb_message); + fb->dn = talloc_reference(fb, msg->dn); + + mp = talloc_zero(module, struct ldb_message); + mp->dn = map_local_dn(module, mp, msg->dn); + + /* Loop over mi and call generate_remote for each attribute */ + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_map_attribute *attr; + enum ldb_map_attr_type map_type; + + if (ldb_attr_cmp(msg->elements[i].name, "isMapped") == 0) + continue; + + attr = map_find_attr_local(privdat, msg->elements[i].name); + + if (!attr) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Undefined local attribute '%s', ignoring\n", msg->elements[i].name); + map_type = MAP_IGNORE; + } 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 = msg->elements[i].num_values; + elm->values = talloc_reference(elm, msg->elements[i].values); + elm->name = talloc_strdup(elm, msg->elements[i].name); + + ldb_msg_add(module->ldb, fb, elm, msg->elements[i].flags); + break; + case MAP_RENAME: + elm = talloc(mp, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = msg->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] = msg->elements[i].values[j]; + } + + ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags); + break; + + case MAP_CONVERT: + elm = talloc(mp, struct ldb_message_element); + + elm->name = talloc_strdup(elm, attr->u.rename.remote_name); + elm->num_values = msg->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(module, mp, &msg->elements[i].values[j]); + } + + ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags); + break; + + case MAP_KEEP: + elm = talloc(mp, struct ldb_message_element); - if (fb != NULL) { - ret = ldb_next_modify_record(module, fb); - talloc_free(fb); + elm->num_values = msg->elements[i].num_values; + elm->values = talloc_reference(elm, msg->elements[i].values); + elm->name = talloc_strdup(elm, msg->elements[i].name); + + ldb_msg_add(module->ldb, mp, elm, msg->elements[i].flags); + break; + + case MAP_GENERATE: + attr->u.generate.generate_remote(module, attr->local_name, msg, mp, fb); + break; + } + } + + if (fb->num_elements > 0) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying fallback record with %d elements", fb->num_elements); + fb_ret = ldb_next_modify_record(module, fb); + if (fb_ret == -1) { + ldb_msg_add_string(module->ldb, fb, "isMapped", "TRUE"); + fb_ret = ldb_next_add_record(module, fb); + } } + talloc_free(fb); - if (mp != NULL) { - ret = ldb_modify(privdat->mapped_ldb, mp); - talloc_free(mp); + if (mp->num_elements > 0) { + ldb_debug(module->ldb, LDB_DEBUG_TRACE, "Modifying mapped record with %d elements", mp->num_elements); + mp_ret = ldb_modify(privdat->mapped_ldb, mp); } + talloc_free(mp); - return ret; + return (mp_ret == -1 || fb_ret == -1)?-1:0; } static int map_lock(struct ldb_module *module, const char *lockname) diff --git a/source4/lib/ldb/modules/ldb_map.h b/source4/lib/ldb/modules/ldb_map.h index 4077660160a..984a4a2cd54 100644 --- a/source4/lib/ldb/modules/ldb_map.h +++ b/source4/lib/ldb/modules/ldb_map.h @@ -81,7 +81,8 @@ struct ldb_map_attribute struct ldb_module *, const char *local_attr, const struct ldb_message *local, - struct ldb_message *remote); + struct ldb_message *remote_mp, + struct ldb_message *remote_fb); /* 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 @@ -92,15 +93,22 @@ struct ldb_map_attribute } u; }; +#define LDB_MAP_MAX_SUBCLASSES 10 +#define LDB_MAP_MAX_MUSTS 10 +#define LDB_MAP_MAX_MAYS 50 struct ldb_map_objectclass { const char *local_name; const char *remote_name; + const char *base_classes[LDB_MAP_MAX_SUBCLASSES]; + const char *musts[LDB_MAP_MAX_MUSTS]; + const char *mays[LDB_MAP_MAX_MAYS]; }; struct ldb_map_context { struct ldb_map_attribute *attribute_maps; + /* NOTE: Always declare base classes first here */ const struct ldb_map_objectclass *objectclass_maps; struct ldb_context *mapped_ldb; }; diff --git a/source4/scripting/libjs/upgrade.js b/source4/scripting/libjs/upgrade.js index 45e6884e9fd..07fa8f34ccb 100644 --- a/source4/scripting/libjs/upgrade.js +++ b/source4/scripting/libjs/upgrade.js @@ -541,11 +541,6 @@ function upgrade(subobj, samba3, message, paths) // Enable samba3sam module if original passdb backend was ldap if (ldapurl != undefined) { message("Enabling Samba3 LDAP mappings for SAM database\n"); - var ldif = sprintf(" -dn: @MAP=samba3sam -@MAP_URL: %s", ldapurl); - ok = samdb.add(ldif); - assert(ok); ok = samdb.modify(" dn: @MODULES @@ -557,6 +552,12 @@ replace: @LIST message("Error enabling samba3sam module: " + samdb.errstring() + "\n"); ret = ret + 1; } + + ok = samdb.add(sprintf(" +dn: @MAP=samba3sam +@MAP_URL: %s", ldapurl)); + assert(ok); + } return ret; diff --git a/testdata/samba3/samba3.ldif b/testdata/samba3/samba3.ldif index 035eb1c5166..67c0ae14321 100644 --- a/testdata/samba3/samba3.ldif +++ b/testdata/samba3/samba3.ldif @@ -1,12 +1,19 @@ -dn: ou=Users,ou=Tests,dc=vernstok,dc=nl +dn: sambaDomainName=TESTS,dc=vernstok,dc=nl +objectclass: sambaDomain +objectclass: top +sambaSID: S-1-5-21-4231626423-2410014848-2360679739 +sambaNextRid: 2000 +sambaDomainName: TESTS + +dn: ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: organizationalUnit ou: Users -dn: ou=Groups,ou=Tests,dc=vernstok,dc=nl +dn: ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: organizationalUnit ou: Groups -dn: uid=nobody,ou=Users,ou=Tests,dc=vernstok,dc=nl +dn: uid=nobody,ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl cn: nobody sn: nobody objectClass: inetOrgPerson @@ -33,7 +40,7 @@ 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 +dn: cn=Domain Admins,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 512 @@ -44,7 +51,7 @@ 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 +dn: cn=Domain Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 513 @@ -54,7 +61,7 @@ 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 +dn: cn=Domain Guests,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 514 @@ -64,7 +71,7 @@ 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 +dn: cn=Print Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 550 @@ -74,7 +81,7 @@ 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 +dn: cn=Backup Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 551 @@ -84,7 +91,7 @@ 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 +dn: cn=Replicator,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 552 @@ -94,7 +101,7 @@ 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 +dn: cn=Domain Computers,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 553 @@ -104,7 +111,7 @@ 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 +dn: cn=Administrators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 544 @@ -114,7 +121,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-544 sambaGroupType: 2 displayName: Administrators -dn: cn=Users,ou=Groups,ou=Tests,dc=vernstok,dc=nl +dn: cn=Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 545 @@ -124,7 +131,7 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-545 sambaGroupType: 2 displayName: users -dn: cn=Guests,ou=Groups,ou=Tests,dc=vernstok,dc=nl +dn: cn=Guests,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 546 @@ -135,7 +142,7 @@ 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 +dn: cn=Power Users,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 547 @@ -145,7 +152,7 @@ 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 +dn: cn=Account Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 548 @@ -155,7 +162,7 @@ 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 +dn: cn=Server Operators,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: posixGroup objectClass: sambaGroupMapping gidNumber: 549 @@ -165,11 +172,11 @@ sambaSID: S-1-5-21-4231626423-2410014848-2360679739-549 sambaGroupType: 2 displayName: Server Operators -dn: ou=Computers,ou=Tests,dc=vernstok,dc=nl +dn: ou=Computers,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: organizationalUnit ou: Computers -dn: uid=Administrator,ou=Users,ou=Tests,dc=vernstok,dc=nl +dn: uid=Administrator,ou=Users,sambaDomainName=TESTS,dc=vernstok,dc=nl cn: Administrator sn: Administrator objectClass: inetOrgPerson diff --git a/testprogs/ejs/samba3sam b/testprogs/ejs/samba3sam index 14ddd011e98..c422bce16b4 100755 --- a/testprogs/ejs/samba3sam +++ b/testprogs/ejs/samba3sam @@ -40,6 +40,16 @@ assert(ldif != undefined); ok = s4.add(ldif); assert(ok); +var ldif = sys.file_load(mypath + "../../source/setup/provision_templates.ldif"); +var subobj = new Object(); +subobj.BASEDN = "dc=vernstok,dc=nl"; +ldif = substitute_var(ldif, subobj); +assert(ldif != undefined); +ok = s4.add(ldif); +assert(ok); + + + ok = s4.add(sprintf("dn: @MAP=samba3sam @MAP_URL: %s", s3url)); assert(ok); @@ -57,7 +67,6 @@ assert(ok); msg = s4.search("(ou=Users)"); assert(msg.length == 1); -assert(msg['mappedFromDn'] == msg['dn']); println("Looking up by non-mapped attribute"); msg = s4.search("(cn=Administrator)"); @@ -76,9 +85,8 @@ assert(msg.length == 0); println("Looking up mapped entry containing SID"); msg = s4.search("(cn=Replicator)"); assert(msg.length == 1); -assert(msg[0].dn == "cn=Replicator,ou=Groups,ou=Tests,dc=vernstok,dc=nl"); +assert(msg[0].dn == "cn=Replicator,ou=Groups,sambaDomainName=TESTS,dc=vernstok,dc=nl"); assert(msg[0].objectSid == "S-1-5-21-4231626423-2410014848-2360679739-552"); -assert(msg[0].mappedFromDn == msg[0].dn); println("Checking mapping of objectclass"); var oc = msg[0].objectclass; @@ -89,24 +97,23 @@ for (var i in oc) { println("Adding a record that will be fallbacked"); ok = s4.add(" dn: cn=Foo,dc=idealx,dc=org -unixName: root -lastLogon: 20000 +foo: bar +blah: Blie cn: Foo showInAdvancedViewOnly: TRUE "); assert(ok); println("Checking for existance of record"); -msg = s4.search("(cn=Foo)", new Array('unixName','lastLogon','cn','showInAdvancedViewOnly')); +msg = s4.search("(cn=Foo)", new Array('foo','blah','cn','showInAdvancedViewOnly')); assert(msg.length == 1); assert(msg[0].showInAdvancedViewOnly == "TRUE"); -assert(msg[0].cn == "Foo"); -assert(msg[0].unixName == "root"); -assert(msg[0].lastLogon == 20000); +assert(msg[0].foo == "bar"); +assert(msg[0].blah == "Blie"); println("Adding record that will be mapped"); ok = s4.add(" -dn: cn=Niemand,ou=Tests,dc=vernstok,dc=nl +dn: cn=Niemand,sambaDomainName=TESTS,dc=vernstok,dc=nl objectClass: user unixName: blah cn: Niemand @@ -116,15 +123,17 @@ assert(ok); println("Checking for existance of record (mapped)"); msg = s4.search("(unixName=blah)", new Array('unixName','cn','dn')); assert(msg.length == 1); +assert(msg[0].cn == "Niemand"); println("Checking for data in destination database"); -msg = s3.search("(cn=Niemand)"); +msg = s3.search("(displayName=Niemand)"); assert(msg.length >= 1); +assert(msg[0].sambaSID == "S-1-5-21-4231626423-2410014848-2360679739-2001"); assert(msg[0].displayName == "Niemand"); println("Adding attribute..."); ok = s4.modify(" -dn: cn=Niemand,ou=Tests,dc=vernstok,dc=nl +dn: cn=Niemand,sambaDomainName=TESTS,dc=vernstok,dc=nl changetype: modify add: description description: Blah @@ -134,11 +143,13 @@ assert(ok); println("Checking whether changes are still there..."); msg = s4.search("(cn=Niemand)"); assert(msg.length >= 1); +printVars(msg); +assert(msg[0].cn == "Niemand"); assert(msg[0].description == "Blah"); println("Modifying attribute..."); ok = s4.modify(" -dn: cn=Niemand,ou=Tests,dc=vernstok,dc=nl +dn: cn=Niemand,sambaDomainName=TESTS,dc=vernstok,dc=nl changetype: modify replace: description description: Blie @@ -152,7 +163,7 @@ assert(msg[0].description == "Blie"); println("Deleting attribute..."); ok = s4.modify(" -dn: cn=Niemand,ou=Tests,dc=vernstok,dc=nl +dn: cn=Niemand,sambaDomainName=TESTS,dc=vernstok,dc=nl changetype: modify delete: description "); @@ -164,7 +175,7 @@ assert(msg.length >= 1); assert(msg[0].description == undefined); println("Renaming record..."); -ok = s4.rename("cn=Niemand,ou=Tests,dc=vernstok,dc=nl", "cn=Niemand,dc=vernstok,dc=nl"); +ok = s4.rename("cn=Niemand,sambaDomainName=TESTS,dc=vernstok,dc=nl", "cn=Niemand,dc=vernstok,dc=nl"); println("Checking whether DN has changed..."); msg = s4.search("(cn=Niemand)"); |