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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/ldb/include/ldb_errors.h"
#include "lib/ldb/include/ldb_private.h"
#include "system/time.h"
+#include "dsdb/samdb/samdb.h"
+#include "version.h"
struct private_data {
int num_controls;
ldb_attr_in_list(attrs, "*");
}
+static int do_attribute_explicit(const char * const *attrs, const char *name)
+{
+ return attrs != NULL && ldb_attr_in_list(attrs, name);
+}
+
/*
add dynamically generated attributes to rootDSE result
{
struct private_data *priv = talloc_get_type(module->private_data, struct private_data);
char **server_sasl;
+ const struct dsdb_schema *schema;
+
+ schema = dsdb_get_schema(module->ldb);
msg->dn = ldb_dn_new(msg, module->ldb, NULL);
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) {
+ ldb_dn_alloc_linearized(msg, dn)) != 0) {
goto failed;
}
}
}
}
+ if (schema && do_attribute_explicit(attrs, "dsSchemaAttrCount")) {
+ struct dsdb_attribute *cur;
+ uint32_t n = 0;
+
+ for (cur = schema->attributes; cur; cur = cur->next) {
+ n++;
+ }
+
+ if (ldb_msg_add_fmt(msg, "dsSchemaAttrCount",
+ "%u", n) != 0) {
+ goto failed;
+ }
+ }
+
+ if (schema && do_attribute_explicit(attrs, "dsSchemaClassCount")) {
+ struct dsdb_class *cur;
+ uint32_t n = 0;
+
+ for (cur = schema->classes; cur; cur = cur->next) {
+ n++;
+ }
+
+ if (ldb_msg_add_fmt(msg, "dsSchemaClassCount",
+ "%u", n) != 0) {
+ goto failed;
+ }
+ }
+
+ if (schema && do_attribute_explicit(attrs, "dsSchemaPrefixCount")) {
+ if (ldb_msg_add_fmt(msg, "dsSchemaPrefixCount",
+ "%u", schema->num_prefixes) != 0) {
+ goto failed;
+ }
+ }
+
+ if (do_attribute_explicit(attrs, "validFSMOs")) {
+ const struct dsdb_naming_fsmo *naming_fsmo;
+ const struct dsdb_pdc_fsmo *pdc_fsmo;
+ const char *dn_str;
+
+ if (schema && schema->fsmo.we_are_master) {
+ dn_str = ldb_dn_get_linearized(samdb_schema_dn(module->ldb));
+ if (dn_str && dn_str[0]) {
+ if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != 0) {
+ goto failed;
+ }
+ }
+ }
+
+ naming_fsmo = talloc_get_type(ldb_get_opaque(module->ldb, "dsdb_naming_fsmo"),
+ struct dsdb_naming_fsmo);
+ if (naming_fsmo && naming_fsmo->we_are_master) {
+ dn_str = ldb_dn_get_linearized(samdb_partitions_dn(module->ldb, msg));
+ if (dn_str && dn_str[0]) {
+ if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != 0) {
+ goto failed;
+ }
+ }
+ }
+
+ pdc_fsmo = talloc_get_type(ldb_get_opaque(module->ldb, "dsdb_pdc_fsmo"),
+ struct dsdb_pdc_fsmo);
+ if (pdc_fsmo && pdc_fsmo->we_are_master) {
+ dn_str = ldb_dn_get_linearized(samdb_base_dn(module->ldb));
+ if (dn_str && dn_str[0]) {
+ if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != 0) {
+ goto failed;
+ }
+ }
+ }
+ }
+
+ if (schema && do_attribute_explicit(attrs, "vendorVersion")) {
+ if (ldb_msg_add_fmt(msg, "vendorVersion",
+ "%s", SAMBA_VERSION_STRING) != 0) {
+ goto failed;
+ }
+ }
+
/* TODO: lots more dynamic attributes should be added here */
return LDB_SUCCESS;
{
struct rootdse_context *ac;
- if (!context || !ares) {
- ldb_set_errstring(ldb, "NULL Context or Result in callback");
- goto error;
- }
-
ac = talloc_get_type(context, struct rootdse_context);
if (ares->type == LDB_REPLY_ENTRY) {
}
down_req->operation = req->operation;
- /* in our db we store the rootDSE with a DN of cn=rootDSE */
- down_req->op.search.base = ldb_dn_new(down_req, module->ldb, "cn=rootDSE");
+ /* in our db we store the rootDSE with a DN of @ROOTDSE */
+ down_req->op.search.base = ldb_dn_new(down_req, module->ldb, "@ROOTDSE");
down_req->op.search.scope = LDB_SCOPE_BASE;
down_req->op.search.tree = ldb_parse_tree(down_req, NULL);
if (down_req->op.search.base == NULL || down_req->op.search.tree == NULL) {
data->partitions = NULL;
module->private_data = data;
+ ldb_set_default_dns(module->ldb);
+
return ldb_next_init(module);
}
-static const struct ldb_module_ops rootdse_ops = {
- .name = "rootdse",
- .init_context = rootdse_init,
- .search = rootdse_search,
- .request = rootdse_request
-};
-
-int rootdse_module_init(void)
+static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
{
- return ldb_register_module(&rootdse_ops);
+ struct ldb_result *ext_res;
+ int ret;
+ struct ldb_dn *schema_dn;
+ struct ldb_message_element *schemaUpdateNowAttr;
+
+ /*
+ If dn is not "" we should let it pass through
+ */
+ if (!ldb_dn_is_null(req->op.mod.message->dn)) {
+ return ldb_next_request(module, req);
+ }
+
+ /*
+ dn is empty so check for schemaUpdateNow attribute
+ "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
+ */
+ schemaUpdateNowAttr = ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow");
+ if (!schemaUpdateNowAttr) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ schema_dn = samdb_schema_dn(module->ldb);
+ if (!schema_dn) {
+ ldb_reset_err_string(module->ldb);
+ ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+ "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
+ return ldb_next_request(module, req);
+ }
+
+ ret = ldb_extended(module->ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
+ if (ret != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ talloc_free(ext_res);
+ return ret;
}
+_PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = {
+ .name = "rootdse",
+ .init_context = rootdse_init,
+ .search = rootdse_search,
+ .request = rootdse_request,
+ .modify = rootdse_modify
+};