diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/config.mk | 11 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/extended_dn.c | 4 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/partition.c | 297 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/rootdse.c | 50 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 2 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 9 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 11 | ||||
-rw-r--r-- | source4/lib/ldb/modules/asq.c | 4 | ||||
-rw-r--r-- | source4/lib/ldb/modules/paged_results.c | 4 | ||||
-rw-r--r-- | source4/lib/ldb/modules/sort.c | 4 | ||||
-rw-r--r-- | source4/scripting/libjs/provision.js | 169 | ||||
-rwxr-xr-x | source4/setup/provision | 15 | ||||
-rw-r--r-- | source4/setup/provision.ldif | 43 | ||||
-rw-r--r-- | source4/setup/provision_basedn.ldif | 8 | ||||
-rw-r--r-- | source4/setup/provision_basedn_modify.ldif | 90 | ||||
-rw-r--r-- | source4/setup/provision_templates.ldif | 19 | ||||
-rw-r--r-- | source4/setup/provision_users.ldif | 2 |
17 files changed, 650 insertions, 92 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 3790d731d9..ce4f12bcfe 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -92,3 +92,14 @@ OBJ_FILES = \ # End MODULE ldb_extended_dn ################################################ +################################################ +# Start MODULE ldb_partition +[MODULE::ldb_partition] +SUBSYSTEM = ldb +INIT_FUNCTION = ldb_partition_init +OBJ_FILES = \ + partition.o +# +# End MODULE ldb_partition +################################################ + diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn.c b/source4/dsdb/samdb/ldb_modules/extended_dn.c index 71f7a2dc7e..aa800a0ae1 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn.c @@ -311,8 +311,8 @@ static int extended_init(struct ldb_module *module) return LDB_ERR_OPERATIONS_ERROR; } - req->operation = LDB_REQ_REGISTER; - req->op.reg.oid = LDB_CONTROL_EXTENDED_DN_OID; + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_EXTENDED_DN_OID; req->controls = NULL; ret = ldb_request(module->ldb, req); diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c new file mode 100644 index 0000000000..6d3d42c23a --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -0,0 +1,297 @@ +/* + Partitions ldb module + + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 + + * NOTICE: this module is NOT released under the GNU LGPL license as + * other ldb code. This module is release under the GNU GPL v2 or + * later license. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Name: ldb + * + * Component: ldb partitions module + * + * Description: Implement LDAP partitions + * + * Author: Andrew Bartlett + */ + +#include "includes.h" +#include "ldb/include/includes.h" + +struct partition { + struct ldb_module *module; + const char *backend; + struct ldb_dn *dn; +}; +struct partition_private_data { + struct partition **partitions; +}; + +struct ldb_module *find_backend(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn) +{ + int i; + struct partition_private_data *data = talloc_get_type(module->private_data, + struct partition_private_data); + /* Look at base DN */ + /* Figure out which partition it is under */ + /* Skip the lot if 'data' isn't here yet (initialistion) */ + for (i=0; data && data->partitions && data->partitions[i]; i++) { + if (ldb_dn_compare_base(module->ldb, + data->partitions[i]->dn, + dn) == 0) { + struct ldb_module *current; + static const struct ldb_module_ops ops; /* zero */ + current = talloc_zero(req, struct ldb_module); + if (current == NULL) { + return module; + } + + current->ldb = module->ldb; + current->ops = &ops; + current->prev = module; + current->next = data->partitions[i]->module; + return current; + } + } + + return module; +}; + +/* search */ +static int partition_search(struct ldb_module *module, struct ldb_request *req) +{ + /* Find backend */ + struct ldb_module *backend = find_backend(module, req, req->op.search.base); + + /* issue request */ + + /* (later) consider if we should be searching multiple + * partitions (for 'invisible' partition behaviour */ + return ldb_next_request(backend, req); +} + +/* add */ +static int partition_add(struct ldb_module *module, struct ldb_request *req) +{ + /* Find backend */ + struct ldb_module *backend = find_backend(module, req, req->op.add.message->dn); + + /* issue request */ + + return ldb_next_request(backend, req); +} + +/* modify */ +static int partition_modify(struct ldb_module *module, struct ldb_request *req) +{ + /* Find backend */ + struct ldb_module *backend = find_backend(module, req, req->op.mod.message->dn); + + /* issue request */ + + return ldb_next_request(backend, req); +} + +/* delete */ +static int partition_delete(struct ldb_module *module, struct ldb_request *req) +{ + /* Find backend */ + struct ldb_module *backend = find_backend(module, req, req->op.del.dn); + + /* issue request */ + + return ldb_next_request(backend, req); +} + +/* rename */ +static int partition_rename(struct ldb_module *module, struct ldb_request *req) +{ + /* Find backend */ + struct ldb_module *backend = find_backend(module, req, req->op.rename.olddn); + struct ldb_module *backend2 = find_backend(module, req, req->op.rename.newdn); + + if (backend->next != backend2->next) { + return LDB_ERR_AFFECTS_MULTIPLE_DSAS; + } + + /* issue request */ + + /* (later) consider if we should be searching multiple partitions */ + return ldb_next_request(backend, req); +} + +#if 0 +/* We should do this over the entire list of partitions */ + +/* start a transaction */ +static int partition_start_trans(struct ldb_module *module) +{ + return ldb_next_start_trans(module); +} + +/* end a transaction */ +static int partition_end_trans(struct ldb_module *module) +{ + return ldb_next_end_trans(module); +} + +/* delete a transaction */ +static int partition_del_trans(struct ldb_module *module) +{ + return ldb_next_del_trans(module); +} +#endif + +static int partition_init(struct ldb_module *module) +{ + int ret, i; + TALLOC_CTX *mem_ctx = talloc_new(module); + static const char *attrs[] = { "partition", NULL }; + struct ldb_result *res; + struct ldb_message *msg; + struct ldb_message_element *partition_attributes; + + struct partition_private_data *data; + + if (!mem_ctx) { + return LDB_ERR_OPERATIONS_ERROR; + } + + data = talloc(mem_ctx, struct partition_private_data); + if (data == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_search(module->ldb, ldb_dn_explode(mem_ctx, "@PARTITION"), + LDB_SCOPE_BASE, + NULL, attrs, + &res); + if (ret != LDB_SUCCESS) { + talloc_free(mem_ctx); + return ret; + } + talloc_steal(mem_ctx, res); + if (res->count == 0) { + talloc_free(mem_ctx); + return ldb_next_init(module); + } + + if (res->count > 1) { + talloc_free(mem_ctx); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + msg = res->msgs[0]; + + partition_attributes = ldb_msg_find_element(msg, "partition"); + if (!partition_attributes) { + ldb_set_errstring(module->ldb, + talloc_asprintf(module, "partition_init: " + "no partitions specified")); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + data->partitions = talloc_array(data, struct partition *, partition_attributes->num_values + 1); + if (!data->partitions) { + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + for (i=0; i < partition_attributes->num_values; i++) { + struct ldb_request *req; + + char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data); + char *p = strchr(base, ':'); + if (!p) { + ldb_set_errstring(module->ldb, + talloc_asprintf(module, "partition_init: " + "invalid form for partition record (missing ':'): %s", base)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + p[0] = '\0'; + p++; + if (!p[0]) { + ldb_set_errstring(module->ldb, + talloc_asprintf(module, "partition_init: " + "invalid form for partition record (missing backend database): %s", base)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + data->partitions[i] = talloc(data->partitions, struct partition); + if (!data->partitions[i]) { + talloc_free(mem_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + data->partitions[i]->dn = ldb_dn_explode(data->partitions[i], base); + if (!data->partitions[i]->dn) { + ldb_set_errstring(module->ldb, + talloc_asprintf(module, "partition_init: " + "invalid DN in partition record: %s", base)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + data->partitions[i]->backend = private_path(data->partitions[i], p); + ret = ldb_connect_backend(module->ldb, data->partitions[i]->backend, 0, NULL, &data->partitions[i]->module); + if (ret != LDB_SUCCESS) { + return ret; + } + + req = talloc_zero(mem_ctx, struct ldb_request); + if (req == NULL) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Out of memory!\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + req->operation = LDB_REQ_REGISTER_PARTITION; + req->op.reg_partition.dn = data->partitions[i]->dn; + + ret = ldb_request(module->ldb, req); + if (ret != LDB_SUCCESS) { + ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n"); + return LDB_ERR_OTHER; + } + talloc_free(req); + } + data->partitions[i] = NULL; + + module->private_data = data; + talloc_steal(module, data); + + talloc_free(mem_ctx); + return ldb_next_init(module); +} + +static const struct ldb_module_ops partition_ops = { + .name = "partition", + .init_context = partition_init, + .search = partition_search, + .add = partition_add, + .modify = partition_modify, + .del = partition_delete, + .rename = partition_rename, +#if 0 + .start_transaction = partition_start_trans, + .end_transaction = partition_end_trans, + .del_transaction = partition_del_trans, +#endif +}; + +int ldb_partition_init(void) +{ + return ldb_register_module(&partition_ops); +} diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index 49d93be7f2..fd3d2d0fe7 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -31,6 +31,8 @@ struct private_data { int num_controls; char **controls; + int num_partitions; + struct ldb_dn **partitions; }; /* @@ -54,8 +56,10 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms msg->dn = ldb_dn_explode(msg, ""); - /* don't return the distinduishedName attribute if any */ + /* don't return the distinduishedName, cn and name attributes */ ldb_msg_remove_attr(msg, "distinguishedName"); + ldb_msg_remove_attr(msg, "cn"); + ldb_msg_remove_attr(msg, "name"); if (do_attribute(attrs, "currentTime")) { if (ldb_msg_add_steal_string(msg, "currentTime", @@ -78,6 +82,17 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms } } + if (do_attribute(attrs, "namingContexts")) { + int i; + for (i = 0; i < priv->num_partitions; i++) { + struct ldb_dn *dn = priv->partitions[i]; + if (ldb_msg_add_steal_string(msg, "namingContexts", + ldb_dn_linearize(msg, dn)) != 0) { + goto failed; + } + } + } + server_creds = talloc_get_type(ldb_get_opaque(module->ldb, "server_credentials"), struct cli_credentials); if (server_creds && do_attribute(attrs, "supportedSASLMechanisms")) { @@ -111,7 +126,7 @@ static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *ms } } } - + /* TODO: lots more dynamic attributes should be added here */ return LDB_SUCCESS; @@ -189,7 +204,7 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req) /* in our db we store the rootDSE with a DN of cn=rootDSE */ down_req->op.search.base = ldb_dn_explode(down_req, "cn=rootDSE"); down_req->op.search.scope = LDB_SCOPE_BASE; - down_req->op.search.tree = ldb_parse_tree(down_req, "dn=*"); + down_req->op.search.tree = ldb_parse_tree(down_req, NULL); if (down_req->op.search.base == NULL || down_req->op.search.tree == NULL) { ldb_oom(module->ldb); talloc_free(down_req); @@ -224,7 +239,7 @@ static int rootdse_register_control(struct ldb_module *module, struct ldb_reques return LDB_ERR_OPERATIONS_ERROR; } - list[priv->num_controls] = talloc_strdup(list, req->op.reg.oid); + list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid); if (!list[priv->num_controls]) { return LDB_ERR_OPERATIONS_ERROR; } @@ -235,13 +250,36 @@ static int rootdse_register_control(struct ldb_module *module, struct ldb_reques return LDB_SUCCESS; } +static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req) +{ + struct private_data *priv = talloc_get_type(module->private_data, struct private_data); + struct ldb_dn **list; + + list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1); + if (!list) { + return LDB_ERR_OPERATIONS_ERROR; + } + + list[priv->num_partitions] = talloc_reference(list, req->op.reg_partition.dn); + if (!list[priv->num_partitions]) { + return LDB_ERR_OPERATIONS_ERROR; + } + + priv->num_partitions += 1; + priv->partitions = list; + + return LDB_SUCCESS; +} + static int rootdse_request(struct ldb_module *module, struct ldb_request *req) { switch (req->operation) { - case LDB_REQ_REGISTER: + case LDB_REQ_REGISTER_CONTROL: return rootdse_register_control(module, req); + case LDB_REQ_REGISTER_PARTITION: + return rootdse_register_partition(module, req); default: break; @@ -260,6 +298,8 @@ static int rootdse_init(struct ldb_module *module) data->num_controls = 0; data->controls = NULL; + data->num_partitions = 0; + data->partitions = NULL; module->private_data = data; return ldb_next_init(module); diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index b883809417..2f0c6f2d17 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -490,7 +490,7 @@ static int samldb_copy_template(struct ldb_module *module, struct ldb_message *m struct ldb_message *t; int ret, i, j; - struct ldb_dn *basedn = ldb_dn_string_compose(msg, samdb_base_dn(msg), "cn=Templates"); + struct ldb_dn *basedn = ldb_dn_explode(msg, "cn=Templates"); /* pull the template record */ ret = ldb_search(module->ldb, basedn, LDB_SCOPE_SUBTREE, filter, NULL, &res); diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c index 1b95fdf970..399308967e 100644 --- a/source4/dsdb/samdb/samdb.c +++ b/source4/dsdb/samdb/samdb.c @@ -404,7 +404,7 @@ struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *ms /* pull a guid structure from a objectGUID in a result set. */ -struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr) +struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr) { const struct ldb_val *v; NTSTATUS status; @@ -630,9 +630,10 @@ int samdb_copy_template(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message **res, *t; int ret, i, j; + struct ldb_dn *basedn = ldb_dn_explode(msg, "cn=Templates"); /* pull the template record */ - ret = gendb_search(sam_ldb, mem_ctx, NULL, &res, NULL, "%s", expression); + ret = gendb_search(sam_ldb, mem_ctx, basedn, &res, NULL, "%s", expression); if (ret != 1) { DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", expression, ret)); @@ -1136,7 +1137,7 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct return NT_STATUS_INTERNAL_DB_CORRUPTION; } - count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, + count = gendb_search(ctx, mem_ctx, samdb_base_dn(mem_ctx), &res, domain_attrs, "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); if (count != 1) { @@ -1313,7 +1314,7 @@ _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *me return NT_STATUS_TRANSACTION_ABORTED; } - user_dn = samdb_search_dn(ctx, mem_ctx, NULL, + user_dn = samdb_search_dn(ctx, mem_ctx, samdb_base_dn(mem_ctx), "(&(objectSid=%s)(objectClass=user))", ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); if (!user_dn) { diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index 033a9c1f39..b684b03ef4 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -567,7 +567,8 @@ enum ldb_request_type { LDB_MODIFY, LDB_DELETE, LDB_RENAME, - LDB_REQ_REGISTER, + LDB_REQ_REGISTER_CONTROL, + LDB_REQ_REGISTER_PARTITION, LDB_SEQUENCE_NUMBER }; @@ -638,6 +639,10 @@ struct ldb_register_control { const char *oid; }; +struct ldb_register_partition { + const struct ldb_dn *dn; +}; + struct ldb_sequence_number { uint64_t seq_num; }; @@ -652,7 +657,8 @@ struct ldb_request { struct ldb_modify mod; struct ldb_delete del; struct ldb_rename rename; - struct ldb_register_control reg; + struct ldb_register_control reg_control; + struct ldb_register_partition reg_partition; struct ldb_sequence_number seq_num; } op; @@ -1245,6 +1251,7 @@ const struct ldb_attrib_handler *ldb_attrib_handler(struct ldb_context *ldb, const char **ldb_attr_list_copy(void *mem_ctx, const char * const *attrs); +const char **ldb_attr_list_copy_add(void *mem_ctx, const char * const *attrs, const char *new_attr); int ldb_attr_in_list(const char * const *attrs, const char *attr); diff --git a/source4/lib/ldb/modules/asq.c b/source4/lib/ldb/modules/asq.c index 75ef4a487e..2c0baa6827 100644 --- a/source4/lib/ldb/modules/asq.c +++ b/source4/lib/ldb/modules/asq.c @@ -442,8 +442,8 @@ static int asq_init(struct ldb_module *module) return LDB_ERR_OPERATIONS_ERROR; } - req->operation = LDB_REQ_REGISTER; - req->op.reg.oid = LDB_CONTROL_ASQ_OID; + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_ASQ_OID; ret = ldb_request(module->ldb, req); if (ret != LDB_SUCCESS) { diff --git a/source4/lib/ldb/modules/paged_results.c b/source4/lib/ldb/modules/paged_results.c index bdfaea6d51..c5a1504fa5 100644 --- a/source4/lib/ldb/modules/paged_results.c +++ b/source4/lib/ldb/modules/paged_results.c @@ -542,8 +542,8 @@ static int paged_request_init(struct ldb_module *module) return LDB_ERR_OPERATIONS_ERROR; } - req->operation = LDB_REQ_REGISTER; - req->op.reg.oid = LDB_CONTROL_PAGED_RESULTS_OID; + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID; req->controls = NULL; ret = ldb_request(module->ldb, req); diff --git a/source4/lib/ldb/modules/sort.c b/source4/lib/ldb/modules/sort.c index 23f4f36478..d72647be66 100644 --- a/source4/lib/ldb/modules/sort.c +++ b/source4/lib/ldb/modules/sort.c @@ -429,8 +429,8 @@ static int server_sort_init(struct ldb_module *module) return LDB_ERR_OPERATIONS_ERROR; } - req->operation = LDB_REQ_REGISTER; - req->op.reg.oid = LDB_CONTROL_SERVER_SORT_OID; + req->operation = LDB_REQ_REGISTER_CONTROL; + req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID; req->controls = NULL; ret = ldb_request(module->ldb, req); diff --git a/source4/scripting/libjs/provision.js b/source4/scripting/libjs/provision.js index 64485efa03..877d8530e5 100644 --- a/source4/scripting/libjs/provision.js +++ b/source4/scripting/libjs/provision.js @@ -71,7 +71,7 @@ function setup_name_mapping(info, ldb, sid, unixname) { var attrs = new Array("dn"); var res = ldb.search(sprintf("objectSid=%s", sid), - NULL, ldb.SCOPE_DEFAULT, attrs); + info.subobj.BASEDN, ldb.SCOPE_SUBTREE, attrs); if (res.length != 1) { info.message("Failed to find record for objectSid %s\n", sid); return false; @@ -187,12 +187,72 @@ function ldb_erase(ldb) } /* + erase an ldb, removing all records +*/ +function ldb_erase_partitions(info, dbname) +{ + var rootDSE_attrs = new Array("namingContexts"); + var ldb = ldb_init(); + var lp = loadparm_init(); + var j; + + ldb.session_info = info.session_info; + ldb.credentials = info.credentials; + + + ldb.filename = dbname; + + var connect_ok = ldb.connect(dbname); + assert(connect_ok); + + ldb.transaction_start(); + + var res = ldb.search("(objectClass=*)", "", ldb.SCOPE_BASE, rootDSE_attrs); + assert(typeof(res) != "undefined"); + assert(res.length == 1); + for (j=0; j<res[0].namingContexts.length; j++) { + var attrs = new Array("dn"); + var basedn = res[0].namingContexts[j]; + var k; + var previous_remaining = 1; + var current_remaining = 0; + + for (k=0; k < 10 && (previous_remaining != current_remaining); k++) { + /* and the rest */ + var res2 = ldb.search("(|(objectclass=*)(dn=*))", basedn, ldb.SCOPE_SUBTREE, attrs); + var i; + if (typeof(res2) == "undefined") { + info.message("ldb search failed: " + ldb.errstring() + "\n"); + continue; + } + previous_remaining = current_remaining; + current_remaining = res2.length; + for (i=0;i<res2.length;i++) { + ldb.del(res2[i].dn); + } + + var res3 = ldb.search("(|(objectclass=*)(dn=*))", basedn, ldb.SCOPE_SUBTREE, attrs); + if (res3.length != 0) { + info.message("Failed to delete all records under " + basedn + ", " + res3.length + " records remaining\n"); + } + } + } + + var commit_ok = ldb.transaction_commit(); + if (!commit_ok) { + info.message("ldb commit failed: " + ldb.errstring() + "\n"); + assert(add_ok); + } +} + +/* setup a ldb in the private dir */ function setup_ldb(ldif, info, dbname) { var erase = true; var extra = ""; + var failok = false; var ldb = ldb_init(); var lp = loadparm_init(); ldb.session_info = info.session_info; @@ -202,10 +262,14 @@ function setup_ldb(ldif, info, dbname) extra = arguments[3]; } - if (arguments.length == 5) { + if (arguments.length >= 5) { erase = arguments[4]; } + if (arguments.length == 6) { + failok = arguments[5]; + } + var src = lp.get("setup directory") + "/" + ldif; var data = sys.file_load(src); @@ -215,7 +279,11 @@ function setup_ldb(ldif, info, dbname) ldb.filename = dbname; var connect_ok = ldb.connect(dbname); - assert(connect_ok); + if (!connect_ok) { + sys.unlink(sprintf("%s/%s", lp.get("private dir"), dbname)); + connect_ok = ldb.connect(dbname); + assert(connect_ok); + } ldb.transaction_start(); @@ -226,12 +294,50 @@ function setup_ldb(ldif, info, dbname) var add_ok = ldb.add(data); if (!add_ok) { info.message("ldb load failed: " + ldb.errstring() + "\n"); - assert(add_ok); + if (!failok) { + assert(add_ok); + } + } + if (add_ok) { + var commit_ok = ldb.transaction_commit(); + if (!commit_ok) { + info.message("ldb commit failed: " + ldb.errstring() + "\n"); + assert(commit_ok); + } + } +} + +/* + setup a ldb in the private dir + */ +function setup_ldb_modify(ldif, info, dbname) +{ + var ldb = ldb_init(); + var lp = loadparm_init(); + ldb.session_info = info.session_info; + ldb.credentials = info.credentials; + + var src = lp.get("setup directory") + "/" + ldif; + + var data = sys.file_load(src); + data = substitute_var(data, info.subobj); + + ldb.filename = dbname; + + var connect_ok = ldb.connect(dbname); + assert(connect_ok); + + ldb.transaction_start(); + + var mod_ok = ldb.modify(data); + if (!mod_ok) { + info.message("ldb load failed: " + ldb.errstring() + "\n"); + assert(mod_ok); } var commit_ok = ldb.transaction_commit(); if (!commit_ok) { info.message("ldb commit failed: " + ldb.errstring() + "\n"); - assert(add_ok); + assert(commit_ok); } } @@ -271,6 +377,7 @@ function provision_default_paths(subobj) paths.secrets = "secrets.ldb"; paths.dns = lp.get("private dir") + "/" + subobj.DNSDOMAIN + ".zone"; paths.winsdb = "wins.ldb"; + paths.ldap_basedn_ldif = lp.get("private dir") + "/" + subobj.DNSDOMAIN + ".ldif"; return paths; } @@ -289,12 +396,8 @@ function setup_name_mappings(info, subobj, session_info, credentials) return false; } var attrs = new Array("objectSid"); - var res = ldb.search("dnsDomain=" + subobj.REALM, - NULL, ldb.SCOPE_DEFAULT, attrs); - if (res.length != 1) { - info.message("Failed to find dnsDomain %s\n", subobj.REALM); - return false; - } + res = ldb.search("objectSid=*", subobj.BASEDN, ldb.SCOPE_BASE, attrs); + assert(res.length == 1 && res[0].objectSid != undefined); var sid = res[0].objectSid; /* add some foreign sids if they are not present already */ @@ -369,9 +472,16 @@ function provision(subobj, message, blank, paths, session_info, credentials) message("Setting up hklm.ldb\n"); setup_ldb("hklm.ldif", info, paths.hklm); - message("Setting up sam.ldb attributes\n"); setup_ldb("provision_init.ldif", info, paths.samdb); + message("Erasing data from partitions\n"); + ldb_erase_partitions(info, paths.samdb); + + message("Adding baseDN: " + subobj.BASEDN + "\n"); + setup_ldb("provision_basedn.ldif", info, paths.samdb, NULL, false, true); + message("Modifying baseDN: " + subobj.BASEDN + "\n"); + setup_ldb_modify("provision_basedn_modify.ldif", info, paths.samdb) + message("Setting up sam.ldb schema\n"); setup_ldb("schema.ldif", info, paths.samdb, NULL, false); message("Setting up display specifiers\n"); @@ -408,10 +518,12 @@ function provision_dns(subobj, message, paths, session_info, credentials) assert(ok); /* These values may have changed, due to an incoming SamSync, so fetch them from the database */ - subobj.DOMAINGUID = searchone(ldb, "(&(objectClass=domainDNS)(dnsDomain=" + subobj.DNSDOMAIN + "))", "objectGUID"); - assert(subobj.DOMAINGUID != undefined); + var attrs = new Array("objectGUID"); + res = ldb.search("objectGUID=*", subobj.BASEDN, ldb.SCOPE_BASE, attrs); + assert(res.length == 1 && res[0].objectGUID != undefined) + subobj.DOMAINGUID = res[0].objectGUID; - subobj.HOSTGUID = searchone(ldb, "(&(objectClass=computer)(cn=" + subobj.NETBIOSNAME + "))", "objectGUID"); + subobj.HOSTGUID = searchone(ldb, subobj.BASEDN, "(&(objectClass=computer)(cn=" + subobj.NETBIOSNAME + "))", "objectGUID"); assert(subobj.HOSTGUID != undefined); setup_file("provision.zone", @@ -421,6 +533,21 @@ function provision_dns(subobj, message, paths, session_info, credentials) message("Please install the zone located in " + paths.dns + " into your DNS server\n"); } +/* Write out a DNS zone file, from the info in the current database */ +function provision_ldapbase(subobj, message, paths) +{ + message("Setting up LDAP base entry: " + subobj.BASEDN + " \n"); + var rdns = split(",", subobj.BASEDN); + subobj.RDN_DC = substr(rdns[0], strlen("DC=")); + + setup_file("provision_basedn.ldif", + message, paths.ldap_basedn_ldif, + subobj); + + message("Please install the LDIF located in " + paths.ldap_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server\n"); +} + + /* guess reasonably default options for provisioning */ @@ -466,16 +593,17 @@ function provision_guess() subobj.DNSDOMAIN); rdn_list = split(".", subobj.DNSDOMAIN); subobj.BASEDN = "DC=" + join(",DC=", rdn_list); + subobj.LDAPBACKEND = "users.ldb"; return subobj; } /* search for one attribute as a string */ -function searchone(ldb, expression, attribute) +function searchone(ldb, basedn, expression, attribute) { var attrs = new Array(attribute); - res = ldb.search(expression, attrs); + res = ldb.search(expression, basedn, ldb.SCOPE_SUBTREE, attrs); if (res.length != 1 || res[0][attribute] == undefined) { return undefined; @@ -524,9 +652,12 @@ function newuser(username, unixname, password, message, session_info, credential ldb.transaction_start(); /* find the DNs for the domain and the domain users group */ - var domain_dn = searchone(ldb, "objectClass=domainDNS", "dn"); + var attrs = new Array("defaultNamingContext"); + res = ldb.search("defaultNamingContext=*", "", ldb.SCOPE_BASE, attrs); + assert(res.length == 1 && res[0].defaultNamingContext != undefined) + var domain_dn = res[0].defaultNamingContext; assert(domain_dn != undefined); - var dom_users = searchone(ldb, "name=Domain Users", "dn"); + var dom_users = searchone(ldb, domain_dn, "name=Domain Users", "dn"); assert(dom_users != undefined); var user_dn = sprintf("CN=%s,CN=Users,%s", username, domain_dn); diff --git a/source4/setup/provision b/source4/setup/provision index d6497cf180..a58f4a5dce 100755 --- a/source4/setup/provision +++ b/source4/setup/provision @@ -28,7 +28,9 @@ options = GetOptions(ARGV, 'wheel=s', 'users=s', 'quiet', - 'blank'); + 'blank', + 'ldap-base', + 'ldap-backend=s'); if (options == undefined) { println("Failed to parse options"); @@ -75,6 +77,8 @@ provision [options] --users GROUPNAME choose 'users' group --quiet Be quiet --blank do not add users or groups, just the structure + --ldap-base output only an LDIF file, suitable for creating an LDAP baseDN + --ldap-backend LDAPSERVER LDAP server to use for this provision You must provide at least a realm and domain @@ -108,6 +112,7 @@ for (r in options) { } var blank = (options["blank"] != undefined); +var ldapbase = (options["ldap-base"] != undefined); if (!provision_validate(subobj, message)) { return -1; @@ -118,7 +123,11 @@ var creds = options.get_credentials(); var paths = provision_default_paths(subobj); message("Provisioning for %s in realm %s\n", subobj.DOMAIN, subobj.REALM); message("Using administrator password: %s\n", subobj.ADMINPASS); -provision(subobj, message, blank, paths, system_session, creds); -provision_dns(subobj, message, paths, system_session, creds); +if (ldapbase) { + provision_ldapbase(subobj, message, paths); +} else { + provision(subobj, message, blank, paths, system_session, creds); + provision_dns(subobj, message, paths, system_session, creds); +} message("All OK\n"); return 0; diff --git a/source4/setup/provision.ldif b/source4/setup/provision.ldif index f59d92e769..c047d6d93a 100644 --- a/source4/setup/provision.ldif +++ b/source4/setup/provision.ldif @@ -1,38 +1,3 @@ -############################### -# Domain Naming Context -############################### -dn: ${BASEDN} -objectClass: top -objectClass: domain -objectClass: domainDNS -dnsDomain: ${DNSDOMAIN} -dc: ${RDN_DC} -objectGUID: ${DOMAINGUID} -creationTime: ${NTTIME} -forceLogoff: 9223372036854775808 -lockoutDuration: -18000000000 -lockOutObservationWindow: -18000000000 -lockoutThreshold: 0 -maxPwdAge: -37108517437440 -minPwdAge: 0 -minPwdLength: 7 -modifiedCountAtLastProm: 0 -nextRid: 1000 -pwdProperties: 1 -pwdHistoryLength: 24 -objectSid: ${DOMAINSID} -oEMInformation: Provisioned by Samba4: ${LDAPTIME} -serverState: 1 -nTMixedDomain: 1 -msDS-Behavior-Version: 0 -ridManagerReference: CN=RID Manager$,CN=System,${BASEDN} -uASCompat: 1 -modifiedCount: 1 -objectCategory: CN=Domain-DNS,CN=Schema,CN=Configuration,${BASEDN} -isCriticalSystemObject: TRUE -subRefs: CN=Configuration,${BASEDN} -subRefs: CN=Schema,CN=Configuration,${BASEDN} - dn: CN=Users,${BASEDN} objectClass: top objectClass: container @@ -57,15 +22,15 @@ systemFlags: 2348810240 objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN} isCriticalSystemObject: TRUE -dn: OU=Domain Controllers,${BASEDN} +dn: CN=Domain Controllers,${BASEDN} objectClass: top -objectClass: organizationalUnit -ou: Domain Controllers +objectClass: container +cn: Domain Controllers description: Default container for domain controllers instanceType: 4 showInAdvancedViewOnly: FALSE systemFlags: 2348810240 -objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,${BASEDN} +objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN} isCriticalSystemObject: TRUE dn: CN=ForeignSecurityPrincipals,${BASEDN} diff --git a/source4/setup/provision_basedn.ldif b/source4/setup/provision_basedn.ldif new file mode 100644 index 0000000000..4cf850e728 --- /dev/null +++ b/source4/setup/provision_basedn.ldif @@ -0,0 +1,8 @@ +################################ +## Domain Naming Context +################################ +dn: ${BASEDN} +objectClass: top +objectClass: domain +dc: ${RDN_DC} + diff --git a/source4/setup/provision_basedn_modify.ldif b/source4/setup/provision_basedn_modify.ldif new file mode 100644 index 0000000000..91a8d66f24 --- /dev/null +++ b/source4/setup/provision_basedn_modify.ldif @@ -0,0 +1,90 @@ +############################### +# Domain Naming Context +############################### +dn: ${BASEDN} +changetype: modify +replace: objectClass +objectClass: top +objectClass: domain +objectClass: domainDNS +- +replace: dnsDomain +dnsDomain: ${DNSDOMAIN} +- +replace: dc +dc: ${RDN_DC} +- +replace: objectGUID +objectGUID: ${DOMAINGUID} +- +replace: creationTime +creationTime: ${NTTIME} +- +replace: forceLogoff +forceLogoff: 9223372036854775808 +- +replace: lockoutDuration +lockoutDuration: -18000000000 +- +replace: lockOutObservationWindow +lockOutObservationWindow: -18000000000 +- +replace: lockoutThreshold +lockoutThreshold: 0 +- +replace: maxPwdAge +maxPwdAge: -37108517437440 +- +replace: minPwdAge +minPwdAge: 0 +- +replace: minPwdLength +minPwdLength: 7 +- +replace: modifiedCountAtLastProm +modifiedCountAtLastProm: 0 +- +replace: nextRid +nextRid: 1000 +- +replace: pwdProperties +pwdProperties: 1 +- +replace: pwdHistoryLength +pwdHistoryLength: 24 +- +replace: objectSid +objectSid: ${DOMAINSID} +- +replace: oEMInformation +oEMInformation: Provisioned by Samba4: ${LDAPTIME} +- +replace: serverState +serverState: 1 +- +replace: nTMixedDomain +nTMixedDomain: 1 +- +replace: msDS-Behavior-Version +msDS-Behavior-Version: 0 +- +replace: ridManagerReference +ridManagerReference: CN=RID Manager$,CN=System,${BASEDN} +- +replace: uASCompat +uASCompat: 1 +- +replace: modifiedCount +modifiedCount: 1 +- +replace: objectCategory +objectCategory: CN=Domain-DNS,CN=Schema,CN=Configuration,${BASEDN} +- +replace: isCriticalSystemObject +isCriticalSystemObject: TRUE +- +replace: subRefs +subRefs: CN=Configuration,${BASEDN} +subRefs: CN=Schema,CN=Configuration,${BASEDN} +- + diff --git a/source4/setup/provision_templates.ldif b/source4/setup/provision_templates.ldif index 11501a5b42..3b70d42520 100644 --- a/source4/setup/provision_templates.ldif +++ b/source4/setup/provision_templates.ldif @@ -1,4 +1,4 @@ -dn: CN=Templates,${BASEDN} +dn: CN=Templates objectClass: top objectClass: container cn: Templates @@ -14,7 +14,7 @@ isCriticalSystemObject: TRUE # with what classes you put them in ### -dn: CN=TemplateUser,CN=Templates,${BASEDN} +dn: CN=TemplateUser,CN=Templates objectClass: top objectClass: person objectClass: organizationalPerson @@ -36,7 +36,7 @@ logonCount: 0 sAMAccountType: 805306368 objectCategory: CN=Person,CN=Schema,CN=Configuration,${BASEDN} -dn: CN=TemplateComputer,CN=Templates,${BASEDN} +dn: CN=TemplateComputer,CN=Templates objectClass: top objectClass: person objectClass: organizationalPerson @@ -58,7 +58,7 @@ logonCount: 0 sAMAccountType: 805306369 objectCategory: CN=Computer,CN=Schema,CN=Configuration,${BASEDN} -dn: CN=TemplateTrustingDomain,CN=Templates,${BASEDN} +dn: CN=TemplateTrustingDomain,CN=Templates objectClass: top objectClass: Template objectClass: userTemplate @@ -71,13 +71,12 @@ countryCode: 0 badPasswordTime: 0 lastLogoff: 0 lastLogon: 0 -pwdLastSet: 0 primaryGroupID: 513 accountExpires: -1 logonCount: 0 sAMAccountType: 805306370 -dn: CN=TemplateGroup,CN=Templates,${BASEDN} +dn: CN=TemplateGroup,CN=Templates objectClass: top objectClass: Template objectClass: groupTemplate @@ -89,7 +88,7 @@ objectCategory: CN=Group,CN=Schema,CN=Configuration,${BASEDN} # Currently this isn't used, we don't have a way to detect it different from an incoming alias # -# dn: CN=TemplateAlias,CN=Templates,${BASEDN} +# dn: CN=TemplateAlias,CN=Templates # objectClass: top # objectClass: Template # objectClass: aliasTemplate @@ -98,7 +97,7 @@ objectCategory: CN=Group,CN=Schema,CN=Configuration,${BASEDN} # groupType: -2147483644 # sAMAccountType: 268435456 -dn: CN=TemplateForeignSecurityPrincipal,CN=Templates,${BASEDN} +dn: CN=TemplateForeignSecurityPrincipal,CN=Templates objectClass: top objectClass: Template objectClass: foreignSecurityPrincipalTemplate @@ -107,7 +106,7 @@ instanceType: 4 showInAdvancedViewOnly: TRUE objectCategory: CN=Foreign-Security-Principal,CN=Schema,CN=Configuration,${BASEDN} -dn: CN=TemplateSecret,CN=Templates,${BASEDN} +dn: CN=TemplateSecret,CN=Templates objectClass: top objectClass: leaf objectClass: Template @@ -115,7 +114,7 @@ objectClass: secretTemplate cn: TemplateSecret instanceType: 4 -dn: CN=TemplateTrustedDomain,CN=Templates,${BASEDN} +dn: CN=TemplateTrustedDomain,CN=Templates objectClass: top objectClass: leaf objectClass: Template diff --git a/source4/setup/provision_users.ldif b/source4/setup/provision_users.ldif index dc7bc016d5..5cd5991c41 100644 --- a/source4/setup/provision_users.ldif +++ b/source4/setup/provision_users.ldif @@ -68,7 +68,7 @@ privilege: SeNetworkLogonRight privilege: SeRemoteInteractiveLogonRight -dn: CN=${NETBIOSNAME},OU=Domain Controllers,${BASEDN} +dn: CN=${NETBIOSNAME},CN=Domain Controllers,${BASEDN} objectClass: computer cn: ${NETBIOSNAME} objectGUID: ${HOSTGUID} |