2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Simo Sorce 2005-2008
8 Copyright (C) Matthieu Patou <mat@matws.net> 2011
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include <ldb_module.h>
27 #include "system/time.h"
28 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/samdb/ldb_modules/util.h"
31 #include "libcli/security/security.h"
32 #include "librpc/ndr/libndr.h"
33 #include "auth/auth.h"
34 #include "param/param.h"
35 #include "lib/messaging/irpc.h"
36 #include "librpc/gen_ndr/ndr_irpc_c.h"
39 unsigned int num_controls;
41 unsigned int num_partitions;
42 struct ldb_dn **partitions;
47 return 1 if a specific attribute has been requested
49 static int do_attribute(const char * const *attrs, const char *name)
51 return attrs == NULL ||
52 ldb_attr_in_list(attrs, name) ||
53 ldb_attr_in_list(attrs, "*");
56 static int do_attribute_explicit(const char * const *attrs, const char *name)
58 return attrs != NULL && ldb_attr_in_list(attrs, name);
63 expand a DN attribute to include extended DN information if requested
65 static int expand_dn_in_message(struct ldb_module *module, struct ldb_message *msg,
66 const char *attrname, struct ldb_control *edn_control,
67 struct ldb_request *req)
69 struct ldb_dn *dn, *dn2;
72 struct ldb_request *req2;
74 const char *no_attrs[] = { NULL };
75 struct ldb_result *res;
76 struct ldb_extended_dn_control *edn;
77 TALLOC_CTX *tmp_ctx = talloc_new(req);
78 struct ldb_context *ldb;
81 struct ldb_message_element *el;
83 ldb = ldb_module_get_ctx(module);
85 edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
90 el = ldb_msg_find_element(msg, attrname);
91 if (!el || el->num_values == 0) {
95 for (i = 0; i < el->num_values; i++) {
102 dn_string = talloc_strndup(tmp_ctx, (const char *)v->data, v->length);
103 if (dn_string == NULL) {
104 talloc_free(tmp_ctx);
105 return ldb_operr(ldb);
108 res = talloc_zero(tmp_ctx, struct ldb_result);
110 talloc_free(tmp_ctx);
111 return ldb_operr(ldb);
114 dn = ldb_dn_new(tmp_ctx, ldb, dn_string);
116 talloc_free(tmp_ctx);
117 return ldb_operr(ldb);
120 ret = ldb_build_search_req(&req2, ldb, tmp_ctx,
126 res, ldb_search_default_callback,
128 LDB_REQ_SET_LOCATION(req2);
129 if (ret != LDB_SUCCESS) {
130 talloc_free(tmp_ctx);
135 ret = ldb_request_add_control(req2,
136 LDB_CONTROL_EXTENDED_DN_OID,
137 edn_control->critical, edn);
138 if (ret != LDB_SUCCESS) {
139 talloc_free(tmp_ctx);
140 return ldb_error(ldb, ret, "Failed to add control");
143 ret = ldb_next_request(module, req2);
144 if (ret == LDB_SUCCESS) {
145 ret = ldb_wait(req2->handle, LDB_WAIT_ALL);
148 if (ret != LDB_SUCCESS) {
149 talloc_free(tmp_ctx);
153 if (!res || res->count != 1) {
154 talloc_free(tmp_ctx);
155 return ldb_operr(ldb);
158 dn2 = res->msgs[0]->dn;
160 v->data = (uint8_t *)ldb_dn_get_extended_linearized(msg->elements, dn2, edn_type);
161 if (v->data == NULL) {
162 talloc_free(tmp_ctx);
163 return ldb_operr(ldb);
165 v->length = strlen((char *)v->data);
168 talloc_free(tmp_ctx);
175 add dynamically generated attributes to rootDSE result
177 static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *msg,
178 const char * const *attrs, struct ldb_request *req)
180 struct ldb_context *ldb;
181 struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
183 const struct dsdb_schema *schema;
185 struct ldb_control *edn_control;
186 const char *dn_attrs[] = {
187 "configurationNamingContext",
188 "defaultNamingContext",
190 "rootDomainNamingContext",
191 "schemaNamingContext",
196 ldb = ldb_module_get_ctx(module);
197 schema = dsdb_get_schema(ldb, NULL);
199 msg->dn = ldb_dn_new(msg, ldb, NULL);
201 /* don't return the distinguishedName, cn and name attributes */
202 ldb_msg_remove_attr(msg, "distinguishedName");
203 ldb_msg_remove_attr(msg, "cn");
204 ldb_msg_remove_attr(msg, "name");
206 if (do_attribute(attrs, "serverName")) {
207 if (ldb_msg_add_linearized_dn(msg, "serverName",
208 samdb_server_dn(ldb, msg)) != LDB_SUCCESS) {
213 if (do_attribute(attrs, "dnsHostName")) {
214 struct ldb_result *res;
216 const char *dns_attrs[] = { "dNSHostName", NULL };
217 ret = dsdb_module_search_dn(module, msg, &res, samdb_server_dn(ldb, msg),
218 dns_attrs, DSDB_FLAG_NEXT_MODULE, req);
219 if (ret == LDB_SUCCESS) {
220 const char *hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
221 if (hostname != NULL) {
222 if (ldb_msg_add_string(msg, "dNSHostName", hostname)) {
229 if (do_attribute(attrs, "ldapServiceName")) {
230 struct loadparm_context *lp_ctx
231 = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
232 struct loadparm_context);
233 char *ldap_service_name, *hostname;
235 hostname = strlower_talloc(msg, lpcfg_netbios_name(lp_ctx));
236 if (hostname == NULL) {
240 ldap_service_name = talloc_asprintf(msg, "%s:%s$@%s",
241 samdb_forest_name(ldb, msg),
242 hostname, lpcfg_realm(lp_ctx));
243 if (ldap_service_name == NULL) {
247 if (ldb_msg_add_string(msg, "ldapServiceName",
248 ldap_service_name) != LDB_SUCCESS) {
253 if (do_attribute(attrs, "currentTime")) {
254 if (ldb_msg_add_steal_string(msg, "currentTime",
255 ldb_timestring(msg, time(NULL))) != LDB_SUCCESS) {
260 if (priv && do_attribute(attrs, "supportedControl")) {
262 for (i = 0; i < priv->num_controls; i++) {
263 char *control = talloc_strdup(msg, priv->controls[i]);
267 if (ldb_msg_add_steal_string(msg, "supportedControl",
268 control) != LDB_SUCCESS) {
274 if (priv && do_attribute(attrs, "namingContexts")) {
276 for (i = 0; i < priv->num_partitions; i++) {
277 struct ldb_dn *dn = priv->partitions[i];
278 if (ldb_msg_add_steal_string(msg, "namingContexts",
279 ldb_dn_alloc_linearized(msg, dn)) != LDB_SUCCESS) {
285 server_sasl = talloc_get_type(ldb_get_opaque(ldb, "supportedSASLMechanisms"),
287 if (server_sasl && do_attribute(attrs, "supportedSASLMechanisms")) {
289 for (i = 0; server_sasl && server_sasl[i]; i++) {
290 char *sasl_name = talloc_strdup(msg, server_sasl[i]);
294 if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
295 sasl_name) != LDB_SUCCESS) {
301 if (do_attribute(attrs, "highestCommittedUSN")) {
303 int ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
304 if (ret == LDB_SUCCESS) {
305 if (samdb_msg_add_uint64(ldb, msg, msg,
306 "highestCommittedUSN",
307 seq_num) != LDB_SUCCESS) {
313 if (schema && do_attribute_explicit(attrs, "dsSchemaAttrCount")) {
314 struct dsdb_attribute *cur;
317 for (cur = schema->attributes; cur; cur = cur->next) {
321 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaAttrCount",
327 if (schema && do_attribute_explicit(attrs, "dsSchemaClassCount")) {
328 struct dsdb_class *cur;
331 for (cur = schema->classes; cur; cur = cur->next) {
335 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaClassCount",
341 if (schema && do_attribute_explicit(attrs, "dsSchemaPrefixCount")) {
342 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaPrefixCount",
343 schema->prefixmap->length) != LDB_SUCCESS) {
348 if (do_attribute_explicit(attrs, "validFSMOs")) {
349 const struct dsdb_naming_fsmo *naming_fsmo;
350 const struct dsdb_pdc_fsmo *pdc_fsmo;
353 if (schema && schema->fsmo.we_are_master) {
354 dn_str = ldb_dn_get_linearized(ldb_get_schema_basedn(ldb));
355 if (dn_str && dn_str[0]) {
356 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
362 naming_fsmo = talloc_get_type(ldb_get_opaque(ldb, "dsdb_naming_fsmo"),
363 struct dsdb_naming_fsmo);
364 if (naming_fsmo && naming_fsmo->we_are_master) {
365 dn_str = ldb_dn_get_linearized(samdb_partitions_dn(ldb, msg));
366 if (dn_str && dn_str[0]) {
367 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
373 pdc_fsmo = talloc_get_type(ldb_get_opaque(ldb, "dsdb_pdc_fsmo"),
374 struct dsdb_pdc_fsmo);
375 if (pdc_fsmo && pdc_fsmo->we_are_master) {
376 dn_str = ldb_dn_get_linearized(ldb_get_default_basedn(ldb));
377 if (dn_str && dn_str[0]) {
378 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
385 if (do_attribute_explicit(attrs, "vendorVersion")) {
386 if (ldb_msg_add_fmt(msg, "vendorVersion",
387 "%s", SAMBA_VERSION_STRING) != LDB_SUCCESS) {
392 if (do_attribute(attrs, "domainFunctionality")) {
393 if (samdb_msg_add_int(ldb, msg, msg, "domainFunctionality",
394 dsdb_functional_level(ldb)) != LDB_SUCCESS) {
399 if (do_attribute(attrs, "forestFunctionality")) {
400 if (samdb_msg_add_int(ldb, msg, msg, "forestFunctionality",
401 dsdb_forest_functional_level(ldb)) != LDB_SUCCESS) {
406 if (do_attribute(attrs, "domainControllerFunctionality")
407 && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int))) {
408 if (samdb_msg_add_int(ldb, msg, msg,
409 "domainControllerFunctionality",
410 *val) != LDB_SUCCESS) {
415 if (do_attribute(attrs, "isGlobalCatalogReady")) {
416 /* MS-ADTS 3.1.1.3.2.10
417 Note, we should only return true here is we have
418 completed at least one synchronisation. As both
419 provision and vampire do a full sync, this means we
420 can return true is the gc bit is set in the NTDSDSA
422 if (ldb_msg_add_fmt(msg, "isGlobalCatalogReady",
423 "%s", samdb_is_gc(ldb)?"TRUE":"FALSE") != LDB_SUCCESS) {
428 if (do_attribute_explicit(attrs, "tokenGroups")) {
430 /* Obtain the user's session_info */
431 struct auth_session_info *session_info
432 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
433 if (session_info && session_info->security_token) {
434 /* The list of groups this user is in */
435 for (i = 0; i < session_info->security_token->num_sids; i++) {
436 if (samdb_msg_add_dom_sid(ldb, msg, msg,
438 &session_info->security_token->sids[i]) != LDB_SUCCESS) {
445 /* TODO: lots more dynamic attributes should be added here */
447 edn_control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
449 /* if the client sent us the EXTENDED_DN control then we need
450 to expand the DNs to have GUID and SID. W2K8 join relies on
455 for (i=0; dn_attrs[i]; i++) {
456 if (!do_attribute(attrs, dn_attrs[i])) continue;
457 ret = expand_dn_in_message(module, msg, dn_attrs[i],
459 if (ret != LDB_SUCCESS) {
460 DEBUG(0,(__location__ ": Failed to expand DN in rootDSE for %s\n",
470 return ldb_operr(ldb);
474 handle search requests
477 struct rootdse_context {
478 struct ldb_module *module;
479 struct ldb_request *req;
482 static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
483 struct ldb_request *req)
485 struct ldb_context *ldb;
486 struct rootdse_context *ac;
488 ldb = ldb_module_get_ctx(module);
490 ac = talloc_zero(req, struct rootdse_context);
492 ldb_set_errstring(ldb, "Out of Memory");
502 static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
504 struct rootdse_context *ac;
507 ac = talloc_get_type(req->context, struct rootdse_context);
510 return ldb_module_done(ac->req, NULL, NULL,
511 LDB_ERR_OPERATIONS_ERROR);
513 if (ares->error != LDB_SUCCESS) {
514 return ldb_module_done(ac->req, ares->controls,
515 ares->response, ares->error);
518 switch (ares->type) {
519 case LDB_REPLY_ENTRY:
521 * if the client explicit asks for the 'netlogon' attribute
522 * the reply_entry needs to be skipped
524 if (ac->req->op.search.attrs &&
525 ldb_attr_in_list(ac->req->op.search.attrs, "netlogon")) {
530 /* for each record returned post-process to add any dynamic
531 attributes that have been asked for */
532 ret = rootdse_add_dynamic(ac->module, ares->message,
533 ac->req->op.search.attrs, ac->req);
534 if (ret != LDB_SUCCESS) {
536 return ldb_module_done(ac->req, NULL, NULL, ret);
539 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
541 case LDB_REPLY_REFERRAL:
542 /* should we allow the backend to return referrals in this case
547 return ldb_module_done(ac->req, ares->controls,
548 ares->response, ares->error);
556 filter from controls from clients in several ways
558 1) mark our registered controls as non-critical in the request
560 This is needed as clients may mark controls as critical even if
561 they are not needed at all in a request. For example, the centrify
562 client sets the SD_FLAGS control as critical on ldap modify
563 requests which are setting the dNSHostName attribute on the
564 machine account. That request doesn't need SD_FLAGS at all, but
565 centrify adds it on all ldap requests.
567 2) if this request is untrusted then remove any non-registered
568 controls that are non-critical
570 This is used on ldap:// connections to prevent remote users from
571 setting an internal control that may be dangerous
573 3) if this request is untrusted then fail any request that includes
574 a critical non-registered control
576 static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
579 struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
582 if (!req->controls) {
586 is_untrusted = ldb_req_is_untrusted(req);
588 for (i=0; req->controls[i]; i++) {
589 bool is_registered = false;
590 bool is_critical = (req->controls[i]->critical != 0);
592 if (req->controls[i]->oid == NULL) {
596 if (is_untrusted || is_critical) {
597 for (j=0; j<priv->num_controls; j++) {
598 if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
599 is_registered = true;
605 if (is_untrusted && !is_registered) {
607 /* remove it by marking the oid NULL */
608 req->controls[i]->oid = NULL;
609 req->controls[i]->data = NULL;
610 req->controls[i]->critical = 0;
613 /* its a critical unregistered control - give
615 ldb_asprintf_errstring(ldb_module_get_ctx(module),
616 "Attempt to use critical non-registered control '%s'",
617 req->controls[i]->oid);
618 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
625 /* If the control is DIRSYNC control then we keep the critical
626 * flag as the dirsync module will need to act upon it
628 if (is_registered && strcmp(req->controls[i]->oid,
629 LDB_CONTROL_DIRSYNC_OID)!= 0) {
630 req->controls[i]->critical = 0;
637 /* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
639 static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
641 struct auth_session_info *session_info;
642 struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
643 bool is_untrusted = ldb_req_is_untrusted(req);
644 bool is_anonymous = true;
645 if (is_untrusted == false) {
649 session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
651 is_anonymous = security_token_is_anonymous(session_info->security_token);
654 if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
658 if (req->operation == LDB_SEARCH) {
659 if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
663 ldb_set_errstring(ldb_module_get_ctx(module), "Operation unavailable without authentication");
664 return LDB_ERR_OPERATIONS_ERROR;
667 static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
669 struct ldb_context *ldb;
670 struct rootdse_context *ac;
671 struct ldb_request *down_req;
674 ret = rootdse_filter_operations(module, req);
675 if (ret != LDB_SUCCESS) {
679 ret = rootdse_filter_controls(module, req);
680 if (ret != LDB_SUCCESS) {
684 ldb = ldb_module_get_ctx(module);
686 /* see if its for the rootDSE - only a base search on the "" DN qualifies */
687 if (!(req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base))) {
688 /* Otherwise, pass down to the rest of the stack */
689 return ldb_next_request(module, req);
692 ac = rootdse_init_context(module, req);
694 return ldb_operr(ldb);
697 /* in our db we store the rootDSE with a DN of @ROOTDSE */
698 ret = ldb_build_search_req(&down_req, ldb, ac,
699 ldb_dn_new(ac, ldb, "@ROOTDSE"),
702 req->op.search.attrs,
703 NULL,/* for now skip the controls from the client */
704 ac, rootdse_callback,
706 LDB_REQ_SET_LOCATION(down_req);
707 if (ret != LDB_SUCCESS) {
711 return ldb_next_request(module, down_req);
714 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
716 struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
719 list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
721 return ldb_oom(ldb_module_get_ctx(module));
724 list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid);
725 if (!list[priv->num_controls]) {
726 return ldb_oom(ldb_module_get_ctx(module));
729 priv->num_controls += 1;
730 priv->controls = list;
732 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
735 static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
737 struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
738 struct ldb_dn **list;
740 list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
742 return ldb_oom(ldb_module_get_ctx(module));
745 list[priv->num_partitions] = ldb_dn_copy(list, req->op.reg_partition.dn);
746 if (!list[priv->num_partitions]) {
747 return ldb_operr(ldb_module_get_ctx(module));
750 priv->num_partitions += 1;
751 priv->partitions = list;
753 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
757 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
759 switch (req->operation) {
761 case LDB_REQ_REGISTER_CONTROL:
762 return rootdse_register_control(module, req);
763 case LDB_REQ_REGISTER_PARTITION:
764 return rootdse_register_partition(module, req);
769 return ldb_next_request(module, req);
772 static int rootdse_init(struct ldb_module *module)
775 struct ldb_context *ldb;
776 struct ldb_result *res;
777 struct private_data *data;
778 const char *attrs[] = { "msDS-Behavior-Version", NULL };
779 const char *ds_attrs[] = { "dsServiceName", NULL };
782 ldb = ldb_module_get_ctx(module);
784 data = talloc_zero(module, struct private_data);
789 data->num_controls = 0;
790 data->controls = NULL;
791 data->num_partitions = 0;
792 data->partitions = NULL;
793 data->block_anonymous = true;
795 ldb_module_set_private(module, data);
797 ldb_set_default_dns(ldb);
799 ret = ldb_next_init(module);
801 if (ret != LDB_SUCCESS) {
805 mem_ctx = talloc_new(data);
810 /* Now that the partitions are set up, do a search for:
811 - domainControllerFunctionality
812 - domainFunctionality
813 - forestFunctionality
815 Then stuff these values into an opaque
817 ret = dsdb_module_search(module, mem_ctx, &res,
818 ldb_get_default_basedn(ldb),
819 LDB_SCOPE_BASE, attrs, DSDB_FLAG_NEXT_MODULE, NULL, NULL);
820 if (ret == LDB_SUCCESS && res->count == 1) {
821 int domain_behaviour_version
822 = ldb_msg_find_attr_as_int(res->msgs[0],
823 "msDS-Behavior-Version", -1);
824 if (domain_behaviour_version != -1) {
825 int *val = talloc(ldb, int);
827 talloc_free(mem_ctx);
830 *val = domain_behaviour_version;
831 ret = ldb_set_opaque(ldb, "domainFunctionality", val);
832 if (ret != LDB_SUCCESS) {
833 talloc_free(mem_ctx);
839 ret = dsdb_module_search(module, mem_ctx, &res,
840 samdb_partitions_dn(ldb, mem_ctx),
841 LDB_SCOPE_BASE, attrs, DSDB_FLAG_NEXT_MODULE, NULL, NULL);
842 if (ret == LDB_SUCCESS && res->count == 1) {
843 int forest_behaviour_version
844 = ldb_msg_find_attr_as_int(res->msgs[0],
845 "msDS-Behavior-Version", -1);
846 if (forest_behaviour_version != -1) {
847 int *val = talloc(ldb, int);
849 talloc_free(mem_ctx);
852 *val = forest_behaviour_version;
853 ret = ldb_set_opaque(ldb, "forestFunctionality", val);
854 if (ret != LDB_SUCCESS) {
855 talloc_free(mem_ctx);
861 /* For now, our own server's location in the DB is recorded in
862 * the @ROOTDSE record */
863 ret = dsdb_module_search(module, mem_ctx, &res,
864 ldb_dn_new(mem_ctx, ldb, "@ROOTDSE"),
865 LDB_SCOPE_BASE, ds_attrs, DSDB_FLAG_NEXT_MODULE, NULL, NULL);
866 if (ret == LDB_SUCCESS && res->count == 1) {
868 = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0],
871 ret = dsdb_module_search(module, mem_ctx, &res, ds_dn,
872 LDB_SCOPE_BASE, attrs, DSDB_FLAG_NEXT_MODULE, NULL, NULL);
873 if (ret == LDB_SUCCESS && res->count == 1) {
874 int domain_controller_behaviour_version
875 = ldb_msg_find_attr_as_int(res->msgs[0],
876 "msDS-Behavior-Version", -1);
877 if (domain_controller_behaviour_version != -1) {
878 int *val = talloc(ldb, int);
880 talloc_free(mem_ctx);
883 *val = domain_controller_behaviour_version;
884 ret = ldb_set_opaque(ldb,
885 "domainControllerFunctionality", val);
886 if (ret != LDB_SUCCESS) {
887 talloc_free(mem_ctx);
895 data->block_anonymous = dsdb_block_anonymous_ops(module, NULL);
897 talloc_free(mem_ctx);
903 * This function gets the string SCOPE_DN:OPTIONAL_FEATURE_GUID and parse it
904 * to a DN and a GUID object
906 static int get_optional_feature_dn_guid(struct ldb_request *req, struct ldb_context *ldb,
908 struct ldb_dn **op_feature_scope_dn,
909 struct GUID *op_feature_guid)
911 const struct ldb_message *msg = req->op.mod.message;
912 const char *ldb_val_str;
914 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
917 ldb_val_str = ldb_msg_find_attr_as_string(msg, "enableOptionalFeature", NULL);
919 ldb_set_errstring(ldb,
920 "rootdse: unable to find 'enableOptionalFeature'!");
921 return LDB_ERR_UNWILLING_TO_PERFORM;
924 guid = strchr(ldb_val_str, ':');
926 ldb_set_errstring(ldb,
927 "rootdse: unable to find GUID in 'enableOptionalFeature'!");
928 return LDB_ERR_UNWILLING_TO_PERFORM;
930 status = GUID_from_string(guid+1, op_feature_guid);
931 if (!NT_STATUS_IS_OK(status)) {
932 ldb_set_errstring(ldb,
933 "rootdse: bad GUID in 'enableOptionalFeature'!");
934 return LDB_ERR_UNWILLING_TO_PERFORM;
937 dn = talloc_strndup(tmp_ctx, ldb_val_str, guid-ldb_val_str);
939 ldb_set_errstring(ldb,
940 "rootdse: bad DN in 'enableOptionalFeature'!");
941 return LDB_ERR_UNWILLING_TO_PERFORM;
944 *op_feature_scope_dn = ldb_dn_new(mem_ctx, ldb, dn);
946 talloc_free(tmp_ctx);
951 * This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
952 * ldb_message object.
954 static int dsdb_find_optional_feature(struct ldb_module *module, struct ldb_context *ldb,
955 TALLOC_CTX *mem_ctx, struct GUID op_feature_guid, struct ldb_message **msg,
956 struct ldb_request *parent)
958 struct ldb_result *res;
959 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
962 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
964 DSDB_FLAG_NEXT_MODULE |
965 DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
967 "(&(objectClass=msDS-OptionalFeature)"
968 "(msDS-OptionalFeatureGUID=%s))",GUID_string(tmp_ctx, &op_feature_guid));
970 if (ret != LDB_SUCCESS) {
971 talloc_free(tmp_ctx);
974 if (res->count == 0) {
975 talloc_free(tmp_ctx);
976 return LDB_ERR_NO_SUCH_OBJECT;
978 if (res->count != 1) {
979 ldb_asprintf_errstring(ldb,
980 "More than one object found matching optional feature GUID %s\n",
981 GUID_string(tmp_ctx, &op_feature_guid));
982 talloc_free(tmp_ctx);
983 return LDB_ERR_OPERATIONS_ERROR;
986 *msg = talloc_steal(mem_ctx, res->msgs[0]);
988 talloc_free(tmp_ctx);
992 static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_context *ldb,
993 TALLOC_CTX *mem_ctx, struct ldb_dn *op_feature_scope_dn,
994 struct ldb_message *op_feature_msg, struct ldb_request *parent)
997 const int domain_func_level = dsdb_functional_level(ldb);
998 struct ldb_dn *ntds_settings_dn;
1000 unsigned int el_count = 0;
1001 struct ldb_message *msg;
1003 ret = ldb_msg_find_attr_as_int(op_feature_msg, "msDS-RequiredForestBehaviorVersion", 0);
1004 if (domain_func_level < ret){
1005 ldb_asprintf_errstring(ldb,
1006 "rootdse_enable_recycle_bin: Domain functional level must be at least %d\n",
1008 return LDB_ERR_UNWILLING_TO_PERFORM;
1011 tmp_ctx = talloc_new(mem_ctx);
1012 ntds_settings_dn = samdb_ntds_settings_dn(ldb);
1013 if (!ntds_settings_dn) {
1014 talloc_free(tmp_ctx);
1015 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to find NTDS settings DN");
1018 ntds_settings_dn = ldb_dn_copy(tmp_ctx, ntds_settings_dn);
1019 if (!ntds_settings_dn) {
1020 talloc_free(tmp_ctx);
1021 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to copy NTDS settings DN");
1024 msg = ldb_msg_new(tmp_ctx);
1025 msg->dn = ntds_settings_dn;
1027 ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
1028 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
1030 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1031 if (ret != LDB_SUCCESS) {
1032 ldb_asprintf_errstring(ldb,
1033 "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1034 ldb_dn_get_linearized(ntds_settings_dn),
1035 ldb_errstring(ldb));
1036 talloc_free(tmp_ctx);
1040 msg->dn = op_feature_scope_dn;
1041 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1042 if (ret != LDB_SUCCESS) {
1043 ldb_asprintf_errstring(ldb,
1044 "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1045 ldb_dn_get_linearized(op_feature_scope_dn),
1046 ldb_errstring(ldb));
1047 talloc_free(tmp_ctx);
1054 static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_request *req)
1058 - check for system (only system can enable features)
1059 - extract GUID from the request
1060 - find the feature object
1061 - check functional level, must be at least msDS-RequiredForestBehaviorVersion
1062 - check if it is already enabled (if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS) - probably not needed, just return error from the add/modify
1063 - add/modify objects (see ntdsconnection code for an example)
1066 struct ldb_context *ldb = ldb_module_get_ctx(module);
1067 struct GUID op_feature_guid;
1068 struct ldb_dn *op_feature_scope_dn;
1069 struct ldb_message *op_feature_msg;
1070 struct auth_session_info *session_info =
1071 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
1072 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1074 const char *guid_string;
1076 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
1077 ldb_set_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature");
1078 return LDB_ERR_UNWILLING_TO_PERFORM;
1081 ret = get_optional_feature_dn_guid(req, ldb, tmp_ctx, &op_feature_scope_dn, &op_feature_guid);
1082 if (ret != LDB_SUCCESS) {
1083 talloc_free(tmp_ctx);
1087 guid_string = GUID_string(tmp_ctx, &op_feature_guid);
1089 ldb_set_errstring(ldb, "rootdse: bad optional feature GUID");
1090 return LDB_ERR_UNWILLING_TO_PERFORM;
1093 ret = dsdb_find_optional_feature(module, ldb, tmp_ctx, op_feature_guid, &op_feature_msg, req);
1094 if (ret != LDB_SUCCESS) {
1095 ldb_asprintf_errstring(ldb,
1096 "rootdse: unable to find optional feature for %s - %s",
1097 guid_string, ldb_errstring(ldb));
1098 talloc_free(tmp_ctx);
1102 if (strcasecmp(DS_GUID_FEATURE_RECYCLE_BIN, guid_string) == 0) {
1103 ret = rootdse_enable_recycle_bin(module, ldb,
1104 tmp_ctx, op_feature_scope_dn,
1105 op_feature_msg, req);
1107 ldb_asprintf_errstring(ldb,
1108 "rootdse: unknown optional feature %s",
1110 talloc_free(tmp_ctx);
1111 return LDB_ERR_UNWILLING_TO_PERFORM;
1113 if (ret != LDB_SUCCESS) {
1114 ldb_asprintf_errstring(ldb,
1115 "rootdse: failed to set optional feature for %s - %s",
1116 guid_string, ldb_errstring(ldb));
1117 talloc_free(tmp_ctx);
1121 talloc_free(tmp_ctx);
1122 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);;
1125 static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request *req)
1127 struct ldb_context *ldb = ldb_module_get_ctx(module);
1128 struct ldb_result *ext_res;
1130 struct ldb_dn *schema_dn;
1132 schema_dn = ldb_get_schema_basedn(ldb);
1134 ldb_reset_err_string(ldb);
1135 ldb_debug(ldb, LDB_DEBUG_WARNING,
1136 "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1137 return ldb_next_request(module, req);
1140 ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
1141 if (ret != LDB_SUCCESS) {
1142 return ldb_operr(ldb);
1145 talloc_free(ext_res);
1146 return ldb_module_done(req, NULL, NULL, ret);
1149 static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
1151 struct ldb_context *ldb = ldb_module_get_ctx(module);
1154 ret = rootdse_filter_operations(module, req);
1155 if (ret != LDB_SUCCESS) {
1159 ret = rootdse_filter_controls(module, req);
1160 if (ret != LDB_SUCCESS) {
1165 If dn is not "" we should let it pass through
1167 if (!ldb_dn_is_null(req->op.add.message->dn)) {
1168 return ldb_next_request(module, req);
1171 ldb_set_errstring(ldb, "rootdse_add: you cannot add a new rootdse entry!");
1172 return LDB_ERR_NAMING_VIOLATION;
1175 struct fsmo_transfer_state {
1176 struct ldb_context *ldb;
1177 struct ldb_request *req;
1181 called when a FSMO transfer operation has completed
1183 static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
1185 struct fsmo_transfer_state *fsmo = tevent_req_callback_data(treq, struct fsmo_transfer_state);
1188 struct ldb_request *req = fsmo->req;
1189 struct ldb_context *ldb = fsmo->ldb;
1191 status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr);
1193 if (!NT_STATUS_IS_OK(status)) {
1194 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", nt_errstr(status));
1195 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1198 if (!W_ERROR_IS_OK(werr)) {
1199 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", win_errstr(werr));
1200 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1204 ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
1207 static int rootdse_become_master(struct ldb_module *module,
1208 struct ldb_request *req,
1209 enum drepl_role_master role)
1211 struct imessaging_context *msg;
1212 struct ldb_context *ldb = ldb_module_get_ctx(module);
1213 TALLOC_CTX *tmp_ctx = talloc_new(req);
1214 struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
1216 struct dcerpc_binding_handle *irpc_handle;
1218 struct auth_session_info *session_info;
1219 enum security_user_level level;
1220 struct fsmo_transfer_state *fsmo;
1221 struct tevent_req *treq;
1223 session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
1224 level = security_session_user_level(session_info, NULL);
1225 if (level < SECURITY_ADMINISTRATOR) {
1226 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS, "Denied rootDSE modify for non-administrator");
1229 ret = samdb_rodc(ldb, &am_rodc);
1230 if (ret != LDB_SUCCESS) {
1231 return ldb_error(ldb, ret, "Could not determine if server is RODC.");
1235 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1236 "RODC cannot become a role master.");
1239 msg = imessaging_client_init(tmp_ctx, lpcfg_imessaging_path(tmp_ctx, lp_ctx),
1240 ldb_get_event_context(ldb));
1242 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s", lpcfg_imessaging_path(tmp_ctx, lp_ctx));
1243 return LDB_ERR_OPERATIONS_ERROR;
1245 irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg,
1248 if (irpc_handle == NULL) {
1249 return ldb_oom(ldb);
1251 fsmo = talloc_zero(req, struct fsmo_transfer_state);
1253 return ldb_oom(ldb);
1258 /* we send the call asynchronously, as the ldap client is
1259 * expecting to get an error back if the role transfer fails
1262 treq = dcerpc_drepl_takeFSMORole_send(req, ldb_get_event_context(ldb), irpc_handle, role);
1264 return ldb_oom(ldb);
1267 tevent_req_set_callback(treq, rootdse_fsmo_transfer_callback, fsmo);
1271 static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
1273 struct ldb_context *ldb = ldb_module_get_ctx(module);
1276 ret = rootdse_filter_operations(module, req);
1277 if (ret != LDB_SUCCESS) {
1281 ret = rootdse_filter_controls(module, req);
1282 if (ret != LDB_SUCCESS) {
1287 If dn is not "" we should let it pass through
1289 if (!ldb_dn_is_null(req->op.mod.message->dn)) {
1290 return ldb_next_request(module, req);
1294 dn is empty so check for schemaUpdateNow attribute
1295 "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
1297 if (ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow")) {
1298 return rootdse_schemaupdatenow(module, req);
1300 if (ldb_msg_find_element(req->op.mod.message, "becomeDomainMaster")) {
1301 return rootdse_become_master(module, req, DREPL_NAMING_MASTER);
1303 if (ldb_msg_find_element(req->op.mod.message, "becomeInfrastructureMaster")) {
1304 return rootdse_become_master(module, req, DREPL_INFRASTRUCTURE_MASTER);
1306 if (ldb_msg_find_element(req->op.mod.message, "becomeRidMaster")) {
1307 return rootdse_become_master(module, req, DREPL_RID_MASTER);
1309 if (ldb_msg_find_element(req->op.mod.message, "becomeSchemaMaster")) {
1310 return rootdse_become_master(module, req, DREPL_SCHEMA_MASTER);
1312 if (ldb_msg_find_element(req->op.mod.message, "becomePdc")) {
1313 return rootdse_become_master(module, req, DREPL_PDC_MASTER);
1315 if (ldb_msg_find_element(req->op.mod.message, "enableOptionalFeature")) {
1316 return rootdse_enableoptionalfeature(module, req);
1319 ldb_set_errstring(ldb, "rootdse_modify: unknown attribute to change!");
1320 return LDB_ERR_UNWILLING_TO_PERFORM;
1323 static int rootdse_rename(struct ldb_module *module, struct ldb_request *req)
1325 struct ldb_context *ldb = ldb_module_get_ctx(module);
1328 ret = rootdse_filter_operations(module, req);
1329 if (ret != LDB_SUCCESS) {
1333 ret = rootdse_filter_controls(module, req);
1334 if (ret != LDB_SUCCESS) {
1339 If dn is not "" we should let it pass through
1341 if (!ldb_dn_is_null(req->op.rename.olddn)) {
1342 return ldb_next_request(module, req);
1345 ldb_set_errstring(ldb, "rootdse_remove: you cannot rename the rootdse entry!");
1346 return LDB_ERR_NO_SUCH_OBJECT;
1349 static int rootdse_delete(struct ldb_module *module, struct ldb_request *req)
1351 struct ldb_context *ldb = ldb_module_get_ctx(module);
1354 ret = rootdse_filter_operations(module, req);
1355 if (ret != LDB_SUCCESS) {
1359 ret = rootdse_filter_controls(module, req);
1360 if (ret != LDB_SUCCESS) {
1365 If dn is not "" we should let it pass through
1367 if (!ldb_dn_is_null(req->op.del.dn)) {
1368 return ldb_next_request(module, req);
1371 ldb_set_errstring(ldb, "rootdse_remove: you cannot delete the rootdse entry!");
1372 return LDB_ERR_NO_SUCH_OBJECT;
1375 static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
1379 ret = rootdse_filter_operations(module, req);
1380 if (ret != LDB_SUCCESS) {
1384 ret = rootdse_filter_controls(module, req);
1385 if (ret != LDB_SUCCESS) {
1389 return ldb_next_request(module, req);
1392 static const struct ldb_module_ops ldb_rootdse_module_ops = {
1394 .init_context = rootdse_init,
1395 .search = rootdse_search,
1396 .request = rootdse_request,
1398 .modify = rootdse_modify,
1399 .rename = rootdse_rename,
1400 .extended = rootdse_extended,
1401 .del = rootdse_delete
1404 int ldb_rootdse_module_init(const char *version)
1406 LDB_MODULE_CHECK_VERSION(version);
1407 return ldb_register_module(&ldb_rootdse_module_ops);