The Samba-Bugzilla – Attachment 9880 Details for
Bug 10569
Rename checks prevent conflict resolution and create DRS lockups
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
4.1 patch cherry-picked from master
0001-dsdb-Do-checks-for-invalid-renames-in-samldb-before-.patch (text/plain), 18.56 KB, created by
Andrew Bartlett
on 2014-04-27 23:15:15 UTC
(
hide
)
Description:
4.1 patch cherry-picked from master
Filename:
MIME Type:
Creator:
Andrew Bartlett
Created:
2014-04-27 23:15:15 UTC
Size:
18.56 KB
patch
obsolete
>From a81d0ac43f151e0dae2c7439f94b957118a73200 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Mon, 24 Mar 2014 17:15:19 +1300 >Subject: [PATCH] dsdb: Do checks for invalid renames in samldb, before > repl_meta_data > >This ensures that conflict objects can be created in CN=System, and >that we do not stop replication just because some other DC allowed a >rename we do not like. > >This is achived by doing the work in the samldb module, which is above >repl_meta_data in the stack. > >Andrew Bartlett > >Change-Id: I8c1a7d3e0fbd5a470cf1326cc055044ca885f7d9 >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >Reviewed-by: Guenter Kukkukk <kukks@samba.org> >Tested-by: Guenter Kukkukk <kukks@samba.org> >(cherry picked from commit d3cd9f1575af18a6765a6b6a31811c9976f9c11e) >--- > source4/dsdb/samdb/ldb_modules/samldb.c | 261 +++++++++++++++++++++++- > source4/dsdb/samdb/ldb_modules/subtree_rename.c | 248 +--------------------- > 2 files changed, 271 insertions(+), 238 deletions(-) > >diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c >index 603370f..a63a44e 100644 >--- a/source4/dsdb/samdb/ldb_modules/samldb.c >+++ b/source4/dsdb/samdb/ldb_modules/samldb.c >@@ -1,7 +1,7 @@ > /* > SAM ldb module > >- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 >+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2014 > Copyright (C) Simo Sorce 2004-2008 > Copyright (C) Matthias Dieter Wallnöfer 2009-2011 > Copyright (C) Matthieu Patou 2012 >@@ -2595,6 +2595,264 @@ static int samldb_delete(struct ldb_module *module, struct ldb_request *req) > return ldb_next_request(module, req); > } > >+/* rename */ >+ >+static int check_rename_constraints(struct ldb_message *msg, >+ struct samldb_ctx *ac, >+ struct ldb_dn *olddn, struct ldb_dn *newdn) >+{ >+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module); >+ struct ldb_dn *dn1, *dn2, *nc_root; >+ int32_t systemFlags; >+ bool move_op = false; >+ bool rename_op = false; >+ int ret; >+ >+ /* Skip the checks if old and new DN are the same, or if we have the >+ * relax control specified or if the returned objects is already >+ * deleted and needs only to be moved for consistency. */ >+ >+ if (ldb_dn_compare(olddn, newdn) == 0) { >+ return LDB_SUCCESS; >+ } >+ if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) { >+ return LDB_SUCCESS; >+ } >+ if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) { >+ return LDB_SUCCESS; >+ } >+ >+ /* Objects under CN=System */ >+ >+ dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb)); >+ if (dn1 == NULL) return ldb_oom(ldb); >+ >+ if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) { >+ talloc_free(dn1); >+ return LDB_ERR_OPERATIONS_ERROR; >+ } >+ >+ if ((ldb_dn_compare_base(dn1, olddn) == 0) && >+ (ldb_dn_compare_base(dn1, newdn) != 0)) { >+ talloc_free(dn1); >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!", >+ ldb_dn_get_linearized(olddn)); >+ return LDB_ERR_OTHER; >+ } >+ >+ talloc_free(dn1); >+ >+ /* LSA objects */ >+ >+ if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) || >+ (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!", >+ ldb_dn_get_linearized(olddn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ >+ /* systemFlags */ >+ >+ dn1 = ldb_dn_get_parent(ac, olddn); >+ if (dn1 == NULL) return ldb_oom(ldb); >+ dn2 = ldb_dn_get_parent(ac, newdn); >+ if (dn2 == NULL) return ldb_oom(ldb); >+ >+ if (ldb_dn_compare(dn1, dn2) == 0) { >+ rename_op = true; >+ } else { >+ move_op = true; >+ } >+ >+ talloc_free(dn1); >+ talloc_free(dn2); >+ >+ systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0); >+ >+ /* Fetch name context */ >+ >+ ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) { >+ if (move_op) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot move %s within schema partition", >+ ldb_dn_get_linearized(olddn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ if (rename_op && >+ (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot rename %s within schema partition", >+ ldb_dn_get_linearized(olddn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) { >+ if (move_op && >+ (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) { >+ /* Here we have to do more: control the >+ * "ALLOW_LIMITED_MOVE" flag. This means that the >+ * grand-grand-parents of two objects have to be equal >+ * in order to perform the move (this is used for >+ * moving "server" objects in the "sites" container). */ >+ bool limited_move = >+ systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE; >+ >+ if (limited_move) { >+ dn1 = ldb_dn_copy(ac, olddn); >+ if (dn1 == NULL) return ldb_oom(ldb); >+ dn2 = ldb_dn_copy(ac, newdn); >+ if (dn2 == NULL) return ldb_oom(ldb); >+ >+ limited_move &= ldb_dn_remove_child_components(dn1, 3); >+ limited_move &= ldb_dn_remove_child_components(dn2, 3); >+ limited_move &= ldb_dn_compare(dn1, dn2) == 0; >+ >+ talloc_free(dn1); >+ talloc_free(dn2); >+ } >+ >+ if (!limited_move) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot move %s to %s in config partition", >+ ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ } >+ if (rename_op && >+ (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot rename %s to %s within config partition", >+ ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) { >+ if (move_op && >+ (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set", >+ ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ if (rename_op && >+ (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) { >+ ldb_asprintf_errstring(ldb, >+ "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set", >+ ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >+ return LDB_ERR_UNWILLING_TO_PERFORM; >+ } >+ } >+ >+ talloc_free(nc_root); >+ >+ return LDB_SUCCESS; >+} >+ >+ >+static int samldb_rename_search_base_callback(struct ldb_request *req, >+ struct ldb_reply *ares) >+{ >+ struct ldb_request *rename_req; >+ struct samldb_ctx *ac; >+ int ret; >+ >+ ac = talloc_get_type(req->context, struct samldb_ctx); >+ >+ if (!ares) { >+ return ldb_module_done(ac->req, NULL, NULL, >+ LDB_ERR_OPERATIONS_ERROR); >+ } >+ if (ares->error != LDB_SUCCESS) { >+ return ldb_module_done(ac->req, ares->controls, >+ ares->response, ares->error); >+ } >+ >+ switch (ares->type) { >+ case LDB_REPLY_ENTRY: >+ /* >+ * This is the root entry of the originating move >+ * respectively rename request. It has been already >+ * stored in the list using "subtree_rename_search()". >+ * Only this one is subject to constraint checking. >+ */ >+ ret = check_rename_constraints(ares->message, ac, >+ ac->req->op.rename.olddn, >+ ac->req->op.rename.newdn); >+ if (ret != LDB_SUCCESS) { >+ return ldb_module_done(ac->req, NULL, NULL, >+ ret); >+ } >+ break; >+ >+ case LDB_REPLY_REFERRAL: >+ /* ignore */ >+ break; >+ >+ case LDB_REPLY_DONE: >+ >+ /* >+ * Great, no problem with the rename, so go ahead as >+ * if we never were here >+ */ >+ ret = ldb_next_request(ac->module, ac->req); >+ talloc_free(ares); >+ return ret; >+ } >+ >+ talloc_free(ares); >+ return LDB_SUCCESS; >+} >+ >+ >+/* rename */ >+static int samldb_rename(struct ldb_module *module, struct ldb_request *req) >+{ >+ struct ldb_context *ldb; >+ static const char * const attrs[] = { "objectClass", "systemFlags", >+ "isDeleted", NULL }; >+ struct ldb_request *search_req; >+ struct samldb_ctx *ac; >+ int ret; >+ >+ if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */ >+ return ldb_next_request(module, req); >+ } >+ >+ ldb = ldb_module_get_ctx(module); >+ >+ ac = samldb_ctx_init(module, req); >+ if (!ac) { >+ return ldb_oom(ldb); >+ } >+ >+ ret = ldb_build_search_req(&search_req, ldb, ac, >+ req->op.rename.olddn, >+ LDB_SCOPE_BASE, >+ "(objectClass=*)", >+ attrs, >+ NULL, >+ ac, >+ samldb_rename_search_base_callback, >+ req); >+ LDB_REQ_SET_LOCATION(search_req); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID, >+ true, NULL); >+ if (ret != LDB_SUCCESS) { >+ return ret; >+ } >+ >+ return ldb_next_request(ac->module, search_req); >+} >+ > /* extended */ > > static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req) >@@ -2634,6 +2892,7 @@ static const struct ldb_module_ops ldb_samldb_module_ops = { > .add = samldb_add, > .modify = samldb_modify, > .del = samldb_delete, >+ .rename = samldb_rename, > .extended = samldb_extended > }; > >diff --git a/source4/dsdb/samdb/ldb_modules/subtree_rename.c b/source4/dsdb/samdb/ldb_modules/subtree_rename.c >index d26dabe..b9ecb3f 100644 >--- a/source4/dsdb/samdb/ldb_modules/subtree_rename.c >+++ b/source4/dsdb/samdb/ldb_modules/subtree_rename.c >@@ -91,166 +91,11 @@ static int subtree_rename_callback(struct ldb_request *req, > return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS); > } > >-static int check_constraints(struct ldb_message *msg, >- struct subtree_rename_context *ac, >- struct ldb_dn *olddn, struct ldb_dn *newdn) >-{ >- struct ldb_context *ldb = ldb_module_get_ctx(ac->module); >- struct ldb_dn *dn1, *dn2, *nc_root; >- int32_t systemFlags; >- bool move_op = false; >- bool rename_op = false; >- int ret; >- >- /* Skip the checks if old and new DN are the same, or if we have the >- * relax control specified or if the returned objects is already >- * deleted and needs only to be moved for consistency. */ >- >- if (ldb_dn_compare(olddn, newdn) == 0) { >- return LDB_SUCCESS; >- } >- if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) { >- return LDB_SUCCESS; >- } >- if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) { >- return LDB_SUCCESS; >- } >- >- /* Objects under CN=System */ >- >- dn1 = ldb_dn_copy(ac, ldb_get_default_basedn(ldb)); >- if (dn1 == NULL) return ldb_oom(ldb); >- >- if ( ! ldb_dn_add_child_fmt(dn1, "CN=System")) { >- talloc_free(dn1); >- return LDB_ERR_OPERATIONS_ERROR; >- } >- >- if ((ldb_dn_compare_base(dn1, olddn) == 0) && >- (ldb_dn_compare_base(dn1, newdn) != 0)) { >- talloc_free(dn1); >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!", >- ldb_dn_get_linearized(olddn)); >- return LDB_ERR_OTHER; >- } >- >- talloc_free(dn1); >- >- /* LSA objects */ >- >- if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) || >- (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!", >- ldb_dn_get_linearized(olddn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- >- /* systemFlags */ >- >- dn1 = ldb_dn_get_parent(ac, olddn); >- if (dn1 == NULL) return ldb_oom(ldb); >- dn2 = ldb_dn_get_parent(ac, newdn); >- if (dn2 == NULL) return ldb_oom(ldb); >- >- if (ldb_dn_compare(dn1, dn2) == 0) { >- rename_op = true; >- } else { >- move_op = true; >- } >- >- talloc_free(dn1); >- talloc_free(dn2); >- >- systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0); >- >- /* Fetch name context */ >- >- ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- >- if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) { >- if (move_op) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot move %s within schema partition", >- ldb_dn_get_linearized(olddn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- if (rename_op && >- (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot rename %s within schema partition", >- ldb_dn_get_linearized(olddn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) { >- if (move_op && >- (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) { >- /* Here we have to do more: control the >- * "ALLOW_LIMITED_MOVE" flag. This means that the >- * grand-grand-parents of two objects have to be equal >- * in order to perform the move (this is used for >- * moving "server" objects in the "sites" container). */ >- bool limited_move = >- systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE; >- >- if (limited_move) { >- dn1 = ldb_dn_copy(ac, olddn); >- if (dn1 == NULL) return ldb_oom(ldb); >- dn2 = ldb_dn_copy(ac, newdn); >- if (dn2 == NULL) return ldb_oom(ldb); >- >- limited_move &= ldb_dn_remove_child_components(dn1, 3); >- limited_move &= ldb_dn_remove_child_components(dn2, 3); >- limited_move &= ldb_dn_compare(dn1, dn2) == 0; >- >- talloc_free(dn1); >- talloc_free(dn2); >- } >- >- if (!limited_move) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot move %s to %s in config partition", >- ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- } >- if (rename_op && >- (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot rename %s to %s within config partition", >- ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) { >- if (move_op && >- (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set", >- ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- if (rename_op && >- (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) { >- ldb_asprintf_errstring(ldb, >- "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set", >- ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn)); >- return LDB_ERR_UNWILLING_TO_PERFORM; >- } >- } >- >- talloc_free(nc_root); >- >- return LDB_SUCCESS; >-} >- > static int subtree_rename_search_onelevel_callback(struct ldb_request *req, > struct ldb_reply *ares) > { > struct subtree_rename_context *ac; >+ struct ldb_request *rename_req; > int ret; > > ac = talloc_get_type(req->context, struct subtree_rename_context); >@@ -298,7 +143,7 @@ static int subtree_rename_search_onelevel_callback(struct ldb_request *req, > > case LDB_REPLY_DONE: > >- ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ac->module), ac, >+ ret = ldb_build_rename_req(&rename_req, ldb_module_get_ctx(ac->module), ac, > ac->req->op.rename.olddn, > ac->req->op.rename.newdn, > ac->req->controls, >@@ -310,88 +155,17 @@ static int subtree_rename_search_onelevel_callback(struct ldb_request *req, > } > > talloc_free(ares); >- return ldb_next_request(ac->module, req); >+ return ldb_next_request(ac->module, rename_req); > } > > return LDB_SUCCESS; > } > >-static int subtree_rename_search_base_callback(struct ldb_request *req, >- struct ldb_reply *ares) >-{ >- struct ldb_request *search_req; >- struct subtree_rename_context *ac; >- static const char * const no_attrs[] = {NULL}; >- int ret; >- >- ac = talloc_get_type(req->context, struct subtree_rename_context); >- >- if (!ares) { >- return ldb_module_done(ac->req, NULL, NULL, >- LDB_ERR_OPERATIONS_ERROR); >- } >- if (ares->error != LDB_SUCCESS) { >- return ldb_module_done(ac->req, ares->controls, >- ares->response, ares->error); >- } >- >- switch (ares->type) { >- case LDB_REPLY_ENTRY: >- /* >- * This is the root entry of the originating move >- * respectively rename request. It has been already >- * stored in the list using "subtree_rename_search()". >- * Only this one is subject to constraint checking. >- */ >- ret = check_constraints(ares->message, ac, >- ac->req->op.rename.olddn, >- ac->req->op.rename.newdn); >- if (ret != LDB_SUCCESS) { >- return ldb_module_done(ac->req, NULL, NULL, >- ret); >- } >- break; >- >- case LDB_REPLY_REFERRAL: >- /* ignore */ >- break; >- >- case LDB_REPLY_DONE: >- >- ret = ldb_build_search_req(&search_req, ldb_module_get_ctx(ac->module), ac, >- ac->req->op.rename.olddn, >- LDB_SCOPE_ONELEVEL, >- "(objectClass=*)", >- no_attrs, >- NULL, >- ac, >- subtree_rename_search_onelevel_callback, >- req); >- LDB_REQ_SET_LOCATION(search_req); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- >- ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID, >- true, NULL); >- if (ret != LDB_SUCCESS) { >- return ret; >- } >- >- talloc_free(ares); >- return ldb_next_request(ac->module, search_req); >- } >- >- talloc_free(ares); >- return LDB_SUCCESS; >-} >- > /* rename */ > static int subtree_rename(struct ldb_module *module, struct ldb_request *req) > { > struct ldb_context *ldb; >- static const char * const attrs[] = { "objectClass", "systemFlags", >- "isDeleted", NULL }; >+ static const char * const no_attrs[] = {NULL}; > struct ldb_request *search_req; > struct subtree_rename_context *ac; > int ret; >@@ -416,14 +190,14 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *req) > return ldb_oom(ldb); > } > >- ret = ldb_build_search_req(&search_req, ldb, ac, >- req->op.rename.olddn, >- LDB_SCOPE_BASE, >+ ret = ldb_build_search_req(&search_req, ldb_module_get_ctx(ac->module), ac, >+ ac->req->op.rename.olddn, >+ LDB_SCOPE_ONELEVEL, > "(objectClass=*)", >- attrs, >+ no_attrs, > NULL, >- ac, >- subtree_rename_search_base_callback, >+ ac, >+ subtree_rename_search_onelevel_callback, > req); > LDB_REQ_SET_LOCATION(search_req); > if (ret != LDB_SUCCESS) { >@@ -436,7 +210,7 @@ static int subtree_rename(struct ldb_module *module, struct ldb_request *req) > return ret; > } > >- return ldb_next_request(module, search_req); >+ return ldb_next_request(ac->module, search_req); > } > > static const struct ldb_module_ops ldb_subtree_rename_module_ops = { >-- >1.9.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
metze
:
review+
Actions:
View
Attachments on
bug 10569
: 9880