dsdb: Do not permit nested event loops when in a transaction, use a nested event...
[Samba.git] / source4 / dsdb / samdb / ldb_modules / rootdse.c
blobb13dc9e5c591bff585f76c486235d4f5be434913
1 /*
2 Unix SMB/CIFS implementation.
4 rootDSE ldb module
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/>.
24 #include "includes.h"
25 #include <ldb.h>
26 #include <ldb_module.h>
27 #include "system/time.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "version.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"
37 #include "lib/tsocket/tsocket.h"
38 #include "cldap_server/cldap_server.h"
39 #include "lib/events/events.h"
41 struct rootdse_private_data {
42 unsigned int num_controls;
43 char **controls;
44 unsigned int num_partitions;
45 struct ldb_dn **partitions;
46 bool block_anonymous;
47 struct tevent_context *saved_ev;
48 struct tevent_context *private_ev;
51 struct rootdse_context {
52 struct ldb_module *module;
53 struct ldb_request *req;
54 struct ldb_val netlogon;
58 return 1 if a specific attribute has been requested
60 static int do_attribute(const char * const *attrs, const char *name)
62 return attrs == NULL ||
63 ldb_attr_in_list(attrs, name) ||
64 ldb_attr_in_list(attrs, "*");
67 static int do_attribute_explicit(const char * const *attrs, const char *name)
69 return attrs != NULL && ldb_attr_in_list(attrs, name);
74 expand a DN attribute to include extended DN information if requested
76 static int expand_dn_in_message(struct ldb_module *module, struct ldb_message *msg,
77 const char *attrname, struct ldb_control *edn_control,
78 struct ldb_request *req)
80 struct ldb_dn *dn, *dn2;
81 struct ldb_val *v;
82 int ret;
83 struct ldb_request *req2;
84 char *dn_string;
85 const char *no_attrs[] = { NULL };
86 struct ldb_result *res;
87 struct ldb_extended_dn_control *edn;
88 TALLOC_CTX *tmp_ctx = talloc_new(req);
89 struct ldb_context *ldb;
90 int edn_type = 0;
91 unsigned int i;
92 struct ldb_message_element *el;
94 ldb = ldb_module_get_ctx(module);
96 edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
97 if (edn) {
98 edn_type = edn->type;
101 el = ldb_msg_find_element(msg, attrname);
102 if (!el || el->num_values == 0) {
103 return LDB_SUCCESS;
106 for (i = 0; i < el->num_values; i++) {
107 v = &el->values[i];
108 if (v == NULL) {
109 talloc_free(tmp_ctx);
110 return LDB_SUCCESS;
113 dn_string = talloc_strndup(tmp_ctx, (const char *)v->data, v->length);
114 if (dn_string == NULL) {
115 talloc_free(tmp_ctx);
116 return ldb_operr(ldb);
119 res = talloc_zero(tmp_ctx, struct ldb_result);
120 if (res == NULL) {
121 talloc_free(tmp_ctx);
122 return ldb_operr(ldb);
125 dn = ldb_dn_new(tmp_ctx, ldb, dn_string);
126 if (dn == NULL) {
127 talloc_free(tmp_ctx);
128 return ldb_operr(ldb);
131 ret = ldb_build_search_req(&req2, ldb, tmp_ctx,
133 LDB_SCOPE_BASE,
134 NULL,
135 no_attrs,
136 NULL,
137 res, ldb_search_default_callback,
138 req);
139 LDB_REQ_SET_LOCATION(req2);
140 if (ret != LDB_SUCCESS) {
141 talloc_free(tmp_ctx);
142 return ret;
146 ret = ldb_request_add_control(req2,
147 LDB_CONTROL_EXTENDED_DN_OID,
148 edn_control->critical, edn);
149 if (ret != LDB_SUCCESS) {
150 talloc_free(tmp_ctx);
151 return ldb_error(ldb, ret, "Failed to add control");
154 ret = ldb_next_request(module, req2);
155 if (ret == LDB_SUCCESS) {
156 ret = ldb_wait(req2->handle, LDB_WAIT_ALL);
159 if (ret != LDB_SUCCESS) {
160 talloc_free(tmp_ctx);
161 return ret;
164 if (!res || res->count != 1) {
165 talloc_free(tmp_ctx);
166 return ldb_operr(ldb);
169 dn2 = res->msgs[0]->dn;
171 v->data = (uint8_t *)ldb_dn_get_extended_linearized(msg->elements, dn2, edn_type);
172 if (v->data == NULL) {
173 talloc_free(tmp_ctx);
174 return ldb_operr(ldb);
176 v->length = strlen((char *)v->data);
179 talloc_free(tmp_ctx);
181 return LDB_SUCCESS;
185 see if we are master for a FSMO role
187 static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *dn, bool *master,
188 struct ldb_request *parent)
190 const char *attrs[] = { "fSMORoleOwner", NULL };
191 TALLOC_CTX *tmp_ctx = talloc_new(parent);
192 struct ldb_result *res;
193 int ret;
194 struct ldb_dn *owner_dn;
196 ret = dsdb_module_search_dn(module, tmp_ctx, &res,
197 dn, attrs,
198 DSDB_FLAG_NEXT_MODULE |
199 DSDB_FLAG_AS_SYSTEM |
200 DSDB_SEARCH_SHOW_EXTENDED_DN,
201 parent);
202 if (ret != LDB_SUCCESS) {
203 talloc_free(tmp_ctx);
204 return ret;
207 owner_dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
208 tmp_ctx, res->msgs[0], "fSMORoleOwner");
209 if (!owner_dn) {
210 *master = false;
211 talloc_free(tmp_ctx);
212 return LDB_SUCCESS;
215 ret = samdb_dn_is_our_ntdsa(ldb_module_get_ctx(module), dn, master);
216 if (ret != LDB_SUCCESS) {
217 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to confirm if our ntdsDsa is %s: %s",
218 ldb_dn_get_linearized(owner_dn), ldb_errstring(ldb_module_get_ctx(module)));
219 talloc_free(tmp_ctx);
220 return ret;
223 talloc_free(tmp_ctx);
224 return LDB_SUCCESS;
228 add dynamically generated attributes to rootDSE result
230 static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg)
232 struct ldb_context *ldb;
233 struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct rootdse_private_data);
234 const char * const *attrs = ac->req->op.search.attrs;
235 char **server_sasl;
236 const struct dsdb_schema *schema;
237 int *val;
238 struct ldb_control *edn_control;
239 const char *dn_attrs[] = {
240 "configurationNamingContext",
241 "defaultNamingContext",
242 "rootDomainNamingContext",
243 "schemaNamingContext",
244 "serverName",
245 "validFSMOs",
246 "namingContexts",
247 NULL
249 const char *guid_attrs[] = {
250 "dsServiceName",
251 NULL
253 unsigned int i;
255 ldb = ldb_module_get_ctx(ac->module);
256 schema = dsdb_get_schema(ldb, NULL);
258 msg->dn = ldb_dn_new(msg, ldb, NULL);
260 /* don't return the distinguishedName, cn and name attributes */
261 ldb_msg_remove_attr(msg, "distinguishedName");
262 ldb_msg_remove_attr(msg, "cn");
263 ldb_msg_remove_attr(msg, "name");
265 if (do_attribute(attrs, "serverName")) {
266 if (ldb_msg_add_linearized_dn(msg, "serverName",
267 samdb_server_dn(ldb, msg)) != LDB_SUCCESS) {
268 goto failed;
272 if (do_attribute(attrs, "dnsHostName")) {
273 struct ldb_result *res;
274 int ret;
275 const char *dns_attrs[] = { "dNSHostName", NULL };
276 ret = dsdb_module_search_dn(ac->module, msg, &res, samdb_server_dn(ldb, msg),
277 dns_attrs,
278 DSDB_FLAG_NEXT_MODULE |
279 DSDB_FLAG_AS_SYSTEM,
280 ac->req);
281 if (ret == LDB_SUCCESS) {
282 const char *hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
283 if (hostname != NULL) {
284 if (ldb_msg_add_string(msg, "dnsHostName", hostname)) {
285 goto failed;
291 if (do_attribute(attrs, "ldapServiceName")) {
292 struct loadparm_context *lp_ctx
293 = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
294 struct loadparm_context);
295 char *ldap_service_name, *hostname;
297 hostname = strlower_talloc(msg, lpcfg_netbios_name(lp_ctx));
298 if (hostname == NULL) {
299 goto failed;
302 ldap_service_name = talloc_asprintf(msg, "%s:%s$@%s",
303 samdb_forest_name(ldb, msg),
304 hostname, lpcfg_realm(lp_ctx));
305 if (ldap_service_name == NULL) {
306 goto failed;
309 if (ldb_msg_add_string(msg, "ldapServiceName",
310 ldap_service_name) != LDB_SUCCESS) {
311 goto failed;
315 if (do_attribute(attrs, "currentTime")) {
316 if (ldb_msg_add_steal_string(msg, "currentTime",
317 ldb_timestring(msg, time(NULL))) != LDB_SUCCESS) {
318 goto failed;
322 if (priv && do_attribute(attrs, "supportedControl")) {
323 for (i = 0; i < priv->num_controls; i++) {
324 char *control = talloc_strdup(msg, priv->controls[i]);
325 if (!control) {
326 goto failed;
328 if (ldb_msg_add_steal_string(msg, "supportedControl",
329 control) != LDB_SUCCESS) {
330 goto failed;
335 if (priv && do_attribute(attrs, "namingContexts")) {
336 for (i = 0; i < priv->num_partitions; i++) {
337 struct ldb_dn *dn = priv->partitions[i];
338 if (ldb_msg_add_steal_string(msg, "namingContexts",
339 ldb_dn_alloc_linearized(msg, dn)) != LDB_SUCCESS) {
340 goto failed;
345 server_sasl = talloc_get_type(ldb_get_opaque(ldb, "supportedSASLMechanisms"),
346 char *);
347 if (server_sasl && do_attribute(attrs, "supportedSASLMechanisms")) {
348 for (i = 0; server_sasl && server_sasl[i]; i++) {
349 char *sasl_name = talloc_strdup(msg, server_sasl[i]);
350 if (!sasl_name) {
351 goto failed;
353 if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
354 sasl_name) != LDB_SUCCESS) {
355 goto failed;
360 if (do_attribute(attrs, "highestCommittedUSN")) {
361 uint64_t seq_num;
362 int ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
363 if (ret == LDB_SUCCESS) {
364 if (samdb_msg_add_uint64(ldb, msg, msg,
365 "highestCommittedUSN",
366 seq_num) != LDB_SUCCESS) {
367 goto failed;
372 if (schema && do_attribute_explicit(attrs, "dsSchemaAttrCount")) {
373 struct dsdb_attribute *cur;
374 unsigned int n = 0;
376 for (cur = schema->attributes; cur; cur = cur->next) {
377 n++;
380 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaAttrCount",
381 n) != LDB_SUCCESS) {
382 goto failed;
386 if (schema && do_attribute_explicit(attrs, "dsSchemaClassCount")) {
387 struct dsdb_class *cur;
388 unsigned int n = 0;
390 for (cur = schema->classes; cur; cur = cur->next) {
391 n++;
394 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaClassCount",
395 n) != LDB_SUCCESS) {
396 goto failed;
400 if (schema && do_attribute_explicit(attrs, "dsSchemaPrefixCount")) {
401 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaPrefixCount",
402 schema->prefixmap->length) != LDB_SUCCESS) {
403 goto failed;
407 if (do_attribute_explicit(attrs, "validFSMOs")) {
408 struct ldb_dn *dns[3];
410 dns[0] = ldb_get_schema_basedn(ldb);
411 dns[1] = samdb_partitions_dn(ldb, msg);
412 dns[2] = ldb_get_default_basedn(ldb);
414 for (i=0; i<3; i++) {
415 bool master;
416 int ret = dsdb_module_we_are_master(ac->module, dns[i], &master, ac->req);
417 if (ret != LDB_SUCCESS) {
418 goto failed;
420 if (master && ldb_msg_add_fmt(msg, "validFSMOs", "%s",
421 ldb_dn_get_linearized(dns[i])) != LDB_SUCCESS) {
422 goto failed;
427 if (do_attribute_explicit(attrs, "vendorVersion")) {
428 if (ldb_msg_add_fmt(msg, "vendorVersion",
429 "%s", SAMBA_VERSION_STRING) != LDB_SUCCESS) {
430 goto failed;
434 if (do_attribute(attrs, "domainFunctionality")) {
435 if (samdb_msg_add_int(ldb, msg, msg, "domainFunctionality",
436 dsdb_functional_level(ldb)) != LDB_SUCCESS) {
437 goto failed;
441 if (do_attribute(attrs, "forestFunctionality")) {
442 if (samdb_msg_add_int(ldb, msg, msg, "forestFunctionality",
443 dsdb_forest_functional_level(ldb)) != LDB_SUCCESS) {
444 goto failed;
448 if (do_attribute(attrs, "domainControllerFunctionality")
449 && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int))) {
450 if (samdb_msg_add_int(ldb, msg, msg,
451 "domainControllerFunctionality",
452 *val) != LDB_SUCCESS) {
453 goto failed;
457 if (do_attribute(attrs, "isGlobalCatalogReady")) {
458 /* MS-ADTS 3.1.1.3.2.10
459 Note, we should only return true here is we have
460 completed at least one synchronisation. As both
461 provision and vampire do a full sync, this means we
462 can return true is the gc bit is set in the NTDSDSA
463 options */
464 if (ldb_msg_add_fmt(msg, "isGlobalCatalogReady",
465 "%s", samdb_is_gc(ldb)?"TRUE":"FALSE") != LDB_SUCCESS) {
466 goto failed;
470 if (do_attribute_explicit(attrs, "tokenGroups")) {
471 /* Obtain the user's session_info */
472 struct auth_session_info *session_info
473 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
474 if (session_info && session_info->security_token) {
475 /* The list of groups this user is in */
476 for (i = 0; i < session_info->security_token->num_sids; i++) {
477 if (samdb_msg_add_dom_sid(ldb, msg, msg,
478 "tokenGroups",
479 &session_info->security_token->sids[i]) != LDB_SUCCESS) {
480 goto failed;
486 if (ac->netlogon.length > 0) {
487 if (ldb_msg_add_steal_value(msg, "netlogon", &ac->netlogon) != LDB_SUCCESS) {
488 goto failed;
492 /* TODO: lots more dynamic attributes should be added here */
494 edn_control = ldb_request_get_control(ac->req, LDB_CONTROL_EXTENDED_DN_OID);
496 /* convert any GUID attributes to be in the right form */
497 for (i=0; guid_attrs[i]; i++) {
498 struct ldb_result *res;
499 struct ldb_message_element *el;
500 struct ldb_dn *attr_dn;
501 const char *no_attrs[] = { NULL };
502 int ret;
504 if (!do_attribute(attrs, guid_attrs[i])) continue;
506 attr_dn = ldb_msg_find_attr_as_dn(ldb, ac->req, msg, guid_attrs[i]);
507 if (attr_dn == NULL) {
508 continue;
511 ret = dsdb_module_search_dn(ac->module, ac->req, &res,
512 attr_dn, no_attrs,
513 DSDB_FLAG_NEXT_MODULE |
514 DSDB_FLAG_AS_SYSTEM |
515 DSDB_SEARCH_SHOW_EXTENDED_DN,
516 ac->req);
517 if (ret != LDB_SUCCESS) {
518 return ldb_operr(ldb);
521 el = ldb_msg_find_element(msg, guid_attrs[i]);
522 if (el == NULL) {
523 return ldb_operr(ldb);
526 talloc_steal(el->values, res->msgs[0]->dn);
527 if (edn_control) {
528 struct ldb_extended_dn_control *edn;
529 int edn_type = 0;
530 edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
531 if (edn != NULL) {
532 edn_type = edn->type;
534 el->values[0].data = (uint8_t *)ldb_dn_get_extended_linearized(el->values,
535 res->msgs[0]->dn,
536 edn_type);
537 } else {
538 el->values[0].data = (uint8_t *)talloc_strdup(el->values,
539 ldb_dn_get_linearized(res->msgs[0]->dn));
541 if (el->values[0].data == NULL) {
542 return ldb_oom(ldb);
544 el->values[0].length = strlen((const char *)el->values[0].data);
547 /* if the client sent us the EXTENDED_DN control then we need
548 to expand the DNs to have GUID and SID. W2K8 join relies on
549 this */
550 if (edn_control) {
551 int ret;
552 for (i=0; dn_attrs[i]; i++) {
553 if (!do_attribute(attrs, dn_attrs[i])) continue;
554 ret = expand_dn_in_message(ac->module, msg, dn_attrs[i],
555 edn_control, ac->req);
556 if (ret != LDB_SUCCESS) {
557 DEBUG(0,(__location__ ": Failed to expand DN in rootDSE for %s\n",
558 dn_attrs[i]));
559 goto failed;
564 return LDB_SUCCESS;
566 failed:
567 return ldb_operr(ldb);
571 handle search requests
574 static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
575 struct ldb_request *req)
577 struct ldb_context *ldb;
578 struct rootdse_context *ac;
580 ldb = ldb_module_get_ctx(module);
582 ac = talloc_zero(req, struct rootdse_context);
583 if (ac == NULL) {
584 ldb_set_errstring(ldb, "Out of Memory");
585 return NULL;
588 ac->module = module;
589 ac->req = req;
591 return ac;
594 static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
596 struct rootdse_context *ac;
597 int ret;
599 ac = talloc_get_type(req->context, struct rootdse_context);
601 if (!ares) {
602 return ldb_module_done(ac->req, NULL, NULL,
603 LDB_ERR_OPERATIONS_ERROR);
605 if (ares->error != LDB_SUCCESS) {
606 return ldb_module_done(ac->req, ares->controls,
607 ares->response, ares->error);
610 switch (ares->type) {
611 case LDB_REPLY_ENTRY:
612 /* for each record returned post-process to add any dynamic
613 attributes that have been asked for */
614 ret = rootdse_add_dynamic(ac, ares->message);
615 if (ret != LDB_SUCCESS) {
616 talloc_free(ares);
617 return ldb_module_done(ac->req, NULL, NULL, ret);
620 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
622 case LDB_REPLY_REFERRAL:
623 /* should we allow the backend to return referrals in this case
624 * ?? */
625 break;
627 case LDB_REPLY_DONE:
628 return ldb_module_done(ac->req, ares->controls,
629 ares->response, ares->error);
632 talloc_free(ares);
633 return LDB_SUCCESS;
637 filter from controls from clients in several ways
639 1) mark our registered controls as non-critical in the request
641 This is needed as clients may mark controls as critical even if
642 they are not needed at all in a request. For example, the centrify
643 client sets the SD_FLAGS control as critical on ldap modify
644 requests which are setting the dNSHostName attribute on the
645 machine account. That request doesn't need SD_FLAGS at all, but
646 centrify adds it on all ldap requests.
648 2) if this request is untrusted then remove any non-registered
649 controls that are non-critical
651 This is used on ldap:// connections to prevent remote users from
652 setting an internal control that may be dangerous
654 3) if this request is untrusted then fail any request that includes
655 a critical non-registered control
657 static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
659 unsigned int i, j;
660 struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
661 bool is_untrusted;
663 if (!req->controls) {
664 return LDB_SUCCESS;
667 is_untrusted = ldb_req_is_untrusted(req);
669 for (i=0; req->controls[i]; i++) {
670 bool is_registered = false;
671 bool is_critical = (req->controls[i]->critical != 0);
673 if (req->controls[i]->oid == NULL) {
674 continue;
677 if (is_untrusted || is_critical) {
678 for (j=0; j<priv->num_controls; j++) {
679 if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
680 is_registered = true;
681 break;
686 if (is_untrusted && !is_registered) {
687 if (!is_critical) {
688 /* remove it by marking the oid NULL */
689 req->controls[i]->oid = NULL;
690 req->controls[i]->data = NULL;
691 req->controls[i]->critical = 0;
692 continue;
694 /* its a critical unregistered control - give
695 an error */
696 ldb_asprintf_errstring(ldb_module_get_ctx(module),
697 "Attempt to use critical non-registered control '%s'",
698 req->controls[i]->oid);
699 return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
702 if (!is_critical) {
703 continue;
706 /* If the control is DIRSYNC control then we keep the critical
707 * flag as the dirsync module will need to act upon it
709 if (is_registered && strcmp(req->controls[i]->oid,
710 LDB_CONTROL_DIRSYNC_OID)!= 0) {
711 req->controls[i]->critical = 0;
715 return LDB_SUCCESS;
718 /* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
720 static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
722 struct auth_session_info *session_info;
723 struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
724 bool is_untrusted = ldb_req_is_untrusted(req);
725 bool is_anonymous = true;
726 if (is_untrusted == false) {
727 return LDB_SUCCESS;
730 session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
731 if (session_info) {
732 is_anonymous = security_token_is_anonymous(session_info->security_token);
735 if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
736 return LDB_SUCCESS;
739 if (req->operation == LDB_SEARCH) {
740 if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
741 return LDB_SUCCESS;
744 ldb_set_errstring(ldb_module_get_ctx(module), "Operation unavailable without authentication");
745 return LDB_ERR_OPERATIONS_ERROR;
748 static int rootdse_handle_netlogon(struct rootdse_context *ac)
750 struct ldb_context *ldb;
751 struct ldb_parse_tree *tree;
752 struct loadparm_context *lp_ctx;
753 struct tsocket_address *src_addr;
754 TALLOC_CTX *tmp_ctx = talloc_new(ac->req);
755 const char *domain, *host, *user, *domain_guid;
756 char *src_addr_s = NULL;
757 struct dom_sid *domain_sid;
758 int acct_control = -1;
759 int version = -1;
760 NTSTATUS status;
761 struct netlogon_samlogon_response netlogon;
762 int ret = LDB_ERR_OPERATIONS_ERROR;
764 ldb = ldb_module_get_ctx(ac->module);
765 tree = ac->req->op.search.tree;
766 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
767 struct loadparm_context);
768 src_addr = talloc_get_type(ldb_get_opaque(ldb, "remoteAddress"),
769 struct tsocket_address);
770 if (src_addr) {
771 src_addr_s = tsocket_address_inet_addr_string(src_addr,
772 tmp_ctx);
775 status = parse_netlogon_request(tree, lp_ctx, tmp_ctx,
776 &domain, &host, &user, &domain_guid,
777 &domain_sid, &acct_control, &version);
778 if (!NT_STATUS_IS_OK(status)) {
779 goto failed;
782 status = fill_netlogon_samlogon_response(ldb, tmp_ctx,
783 domain, NULL, domain_sid,
784 domain_guid,
785 user, acct_control,
786 src_addr_s,
787 version, lp_ctx,
788 &netlogon, false);
789 if (!NT_STATUS_IS_OK(status)) {
790 goto failed;
793 status = push_netlogon_samlogon_response(&ac->netlogon, ac, &netlogon);
794 if (!NT_STATUS_IS_OK(status)) {
795 goto failed;
798 ret = LDB_SUCCESS;
799 failed:
800 talloc_free(tmp_ctx);
801 return ret;
804 static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
806 struct ldb_context *ldb;
807 struct rootdse_context *ac;
808 struct ldb_request *down_req;
809 int ret;
811 ret = rootdse_filter_operations(module, req);
812 if (ret != LDB_SUCCESS) {
813 return ret;
816 ret = rootdse_filter_controls(module, req);
817 if (ret != LDB_SUCCESS) {
818 return ret;
821 ldb = ldb_module_get_ctx(module);
823 /* see if its for the rootDSE - only a base search on the "" DN qualifies */
824 if (!(req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base))) {
825 /* Otherwise, pass down to the rest of the stack */
826 return ldb_next_request(module, req);
829 ac = rootdse_init_context(module, req);
830 if (ac == NULL) {
831 return ldb_operr(ldb);
834 if (do_attribute_explicit(req->op.search.attrs, "netlogon")) {
835 ret = rootdse_handle_netlogon(ac);
836 /* We have to return an empty result, so dont forward `ret' */
837 if (ret != LDB_SUCCESS) {
838 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
842 /* in our db we store the rootDSE with a DN of @ROOTDSE */
843 ret = ldb_build_search_req(&down_req, ldb, ac,
844 ldb_dn_new(ac, ldb, "@ROOTDSE"),
845 LDB_SCOPE_BASE,
846 NULL,
847 req->op.search.attrs,
848 NULL,/* for now skip the controls from the client */
849 ac, rootdse_callback,
850 req);
851 LDB_REQ_SET_LOCATION(down_req);
852 if (ret != LDB_SUCCESS) {
853 return ret;
856 return ldb_next_request(module, down_req);
859 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
861 struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
862 char **list;
864 list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
865 if (!list) {
866 return ldb_oom(ldb_module_get_ctx(module));
869 list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid);
870 if (!list[priv->num_controls]) {
871 return ldb_oom(ldb_module_get_ctx(module));
874 priv->num_controls += 1;
875 priv->controls = list;
877 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
880 static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
882 struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
883 struct ldb_dn **list;
885 list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
886 if (!list) {
887 return ldb_oom(ldb_module_get_ctx(module));
890 list[priv->num_partitions] = ldb_dn_copy(list, req->op.reg_partition.dn);
891 if (!list[priv->num_partitions]) {
892 return ldb_operr(ldb_module_get_ctx(module));
895 priv->num_partitions += 1;
896 priv->partitions = list;
898 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
902 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
904 switch (req->operation) {
906 case LDB_REQ_REGISTER_CONTROL:
907 return rootdse_register_control(module, req);
908 case LDB_REQ_REGISTER_PARTITION:
909 return rootdse_register_partition(module, req);
911 default:
912 break;
914 return ldb_next_request(module, req);
917 static int rootdse_init(struct ldb_module *module)
919 int ret;
920 struct ldb_context *ldb;
921 struct ldb_result *res;
922 struct rootdse_private_data *data;
923 const char *attrs[] = { "msDS-Behavior-Version", NULL };
924 const char *ds_attrs[] = { "dsServiceName", NULL };
925 TALLOC_CTX *mem_ctx;
927 ldb = ldb_module_get_ctx(module);
929 data = talloc_zero(module, struct rootdse_private_data);
930 if (data == NULL) {
931 return ldb_oom(ldb);
934 data->num_controls = 0;
935 data->controls = NULL;
936 data->num_partitions = 0;
937 data->partitions = NULL;
938 data->block_anonymous = true;
940 ldb_module_set_private(module, data);
942 ldb_set_default_dns(ldb);
944 ret = ldb_next_init(module);
946 if (ret != LDB_SUCCESS) {
947 return ret;
950 mem_ctx = talloc_new(data);
951 if (!mem_ctx) {
952 return ldb_oom(ldb);
955 /* Now that the partitions are set up, do a search for:
956 - domainControllerFunctionality
957 - domainFunctionality
958 - forestFunctionality
960 Then stuff these values into an opaque
962 ret = dsdb_module_search(module, mem_ctx, &res,
963 ldb_get_default_basedn(ldb),
964 LDB_SCOPE_BASE, attrs,
965 DSDB_FLAG_NEXT_MODULE |
966 DSDB_FLAG_AS_SYSTEM,
967 NULL, NULL);
968 if (ret == LDB_SUCCESS && res->count == 1) {
969 int domain_behaviour_version
970 = ldb_msg_find_attr_as_int(res->msgs[0],
971 "msDS-Behavior-Version", -1);
972 if (domain_behaviour_version != -1) {
973 int *val = talloc(ldb, int);
974 if (!val) {
975 talloc_free(mem_ctx);
976 return ldb_oom(ldb);
978 *val = domain_behaviour_version;
979 ret = ldb_set_opaque(ldb, "domainFunctionality", val);
980 if (ret != LDB_SUCCESS) {
981 talloc_free(mem_ctx);
982 return ret;
987 ret = dsdb_module_search(module, mem_ctx, &res,
988 samdb_partitions_dn(ldb, mem_ctx),
989 LDB_SCOPE_BASE, attrs,
990 DSDB_FLAG_NEXT_MODULE |
991 DSDB_FLAG_AS_SYSTEM,
992 NULL, NULL);
993 if (ret == LDB_SUCCESS && res->count == 1) {
994 int forest_behaviour_version
995 = ldb_msg_find_attr_as_int(res->msgs[0],
996 "msDS-Behavior-Version", -1);
997 if (forest_behaviour_version != -1) {
998 int *val = talloc(ldb, int);
999 if (!val) {
1000 talloc_free(mem_ctx);
1001 return ldb_oom(ldb);
1003 *val = forest_behaviour_version;
1004 ret = ldb_set_opaque(ldb, "forestFunctionality", val);
1005 if (ret != LDB_SUCCESS) {
1006 talloc_free(mem_ctx);
1007 return ret;
1012 /* For now, our own server's location in the DB is recorded in
1013 * the @ROOTDSE record */
1014 ret = dsdb_module_search(module, mem_ctx, &res,
1015 ldb_dn_new(mem_ctx, ldb, "@ROOTDSE"),
1016 LDB_SCOPE_BASE, ds_attrs,
1017 DSDB_FLAG_NEXT_MODULE |
1018 DSDB_FLAG_AS_SYSTEM,
1019 NULL, NULL);
1020 if (ret == LDB_SUCCESS && res->count == 1) {
1021 struct ldb_dn *ds_dn
1022 = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0],
1023 "dsServiceName");
1024 if (ds_dn) {
1025 ret = dsdb_module_search(module, mem_ctx, &res, ds_dn,
1026 LDB_SCOPE_BASE, attrs,
1027 DSDB_FLAG_NEXT_MODULE |
1028 DSDB_FLAG_AS_SYSTEM,
1029 NULL, NULL);
1030 if (ret == LDB_SUCCESS && res->count == 1) {
1031 int domain_controller_behaviour_version
1032 = ldb_msg_find_attr_as_int(res->msgs[0],
1033 "msDS-Behavior-Version", -1);
1034 if (domain_controller_behaviour_version != -1) {
1035 int *val = talloc(ldb, int);
1036 if (!val) {
1037 talloc_free(mem_ctx);
1038 return ldb_oom(ldb);
1040 *val = domain_controller_behaviour_version;
1041 ret = ldb_set_opaque(ldb,
1042 "domainControllerFunctionality", val);
1043 if (ret != LDB_SUCCESS) {
1044 talloc_free(mem_ctx);
1045 return ret;
1052 data->block_anonymous = dsdb_block_anonymous_ops(module, NULL);
1054 talloc_free(mem_ctx);
1056 return LDB_SUCCESS;
1060 * This function gets the string SCOPE_DN:OPTIONAL_FEATURE_GUID and parse it
1061 * to a DN and a GUID object
1063 static int get_optional_feature_dn_guid(struct ldb_request *req, struct ldb_context *ldb,
1064 TALLOC_CTX *mem_ctx,
1065 struct ldb_dn **op_feature_scope_dn,
1066 struct GUID *op_feature_guid)
1068 const struct ldb_message *msg = req->op.mod.message;
1069 const char *ldb_val_str;
1070 char *dn, *guid;
1071 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1072 NTSTATUS status;
1074 ldb_val_str = ldb_msg_find_attr_as_string(msg, "enableOptionalFeature", NULL);
1075 if (!ldb_val_str) {
1076 ldb_set_errstring(ldb,
1077 "rootdse: unable to find 'enableOptionalFeature'!");
1078 return LDB_ERR_UNWILLING_TO_PERFORM;
1081 guid = strchr(ldb_val_str, ':');
1082 if (!guid) {
1083 ldb_set_errstring(ldb,
1084 "rootdse: unable to find GUID in 'enableOptionalFeature'!");
1085 return LDB_ERR_UNWILLING_TO_PERFORM;
1087 status = GUID_from_string(guid+1, op_feature_guid);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 ldb_set_errstring(ldb,
1090 "rootdse: bad GUID in 'enableOptionalFeature'!");
1091 return LDB_ERR_UNWILLING_TO_PERFORM;
1094 dn = talloc_strndup(tmp_ctx, ldb_val_str, guid-ldb_val_str);
1095 if (!dn) {
1096 ldb_set_errstring(ldb,
1097 "rootdse: bad DN in 'enableOptionalFeature'!");
1098 return LDB_ERR_UNWILLING_TO_PERFORM;
1101 *op_feature_scope_dn = ldb_dn_new(mem_ctx, ldb, dn);
1103 talloc_free(tmp_ctx);
1104 return LDB_SUCCESS;
1108 * This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
1109 * ldb_message object.
1111 static int dsdb_find_optional_feature(struct ldb_module *module, struct ldb_context *ldb,
1112 TALLOC_CTX *mem_ctx, struct GUID op_feature_guid, struct ldb_message **msg,
1113 struct ldb_request *parent)
1115 struct ldb_result *res;
1116 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1117 int ret;
1119 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
1120 NULL,
1121 DSDB_FLAG_NEXT_MODULE |
1122 DSDB_FLAG_AS_SYSTEM |
1123 DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
1124 parent,
1125 "(&(objectClass=msDS-OptionalFeature)"
1126 "(msDS-OptionalFeatureGUID=%s))",GUID_string(tmp_ctx, &op_feature_guid));
1128 if (ret != LDB_SUCCESS) {
1129 talloc_free(tmp_ctx);
1130 return ret;
1132 if (res->count == 0) {
1133 talloc_free(tmp_ctx);
1134 return LDB_ERR_NO_SUCH_OBJECT;
1136 if (res->count != 1) {
1137 ldb_asprintf_errstring(ldb,
1138 "More than one object found matching optional feature GUID %s\n",
1139 GUID_string(tmp_ctx, &op_feature_guid));
1140 talloc_free(tmp_ctx);
1141 return LDB_ERR_OPERATIONS_ERROR;
1144 *msg = talloc_steal(mem_ctx, res->msgs[0]);
1146 talloc_free(tmp_ctx);
1147 return LDB_SUCCESS;
1150 static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_context *ldb,
1151 TALLOC_CTX *mem_ctx, struct ldb_dn *op_feature_scope_dn,
1152 struct ldb_message *op_feature_msg, struct ldb_request *parent)
1154 int ret;
1155 const int domain_func_level = dsdb_functional_level(ldb);
1156 struct ldb_dn *ntds_settings_dn;
1157 TALLOC_CTX *tmp_ctx;
1158 unsigned int el_count = 0;
1159 struct ldb_message *msg;
1161 ret = ldb_msg_find_attr_as_int(op_feature_msg, "msDS-RequiredForestBehaviorVersion", 0);
1162 if (domain_func_level < ret){
1163 ldb_asprintf_errstring(ldb,
1164 "rootdse_enable_recycle_bin: Domain functional level must be at least %d\n",
1165 ret);
1166 return LDB_ERR_UNWILLING_TO_PERFORM;
1169 tmp_ctx = talloc_new(mem_ctx);
1170 ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
1171 if (!ntds_settings_dn) {
1172 talloc_free(tmp_ctx);
1173 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to find NTDS settings DN");
1176 ntds_settings_dn = ldb_dn_copy(tmp_ctx, ntds_settings_dn);
1177 if (!ntds_settings_dn) {
1178 talloc_free(tmp_ctx);
1179 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to copy NTDS settings DN");
1182 msg = ldb_msg_new(tmp_ctx);
1183 msg->dn = ntds_settings_dn;
1185 ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
1186 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
1188 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1189 if (ret != LDB_SUCCESS) {
1190 ldb_asprintf_errstring(ldb,
1191 "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1192 ldb_dn_get_linearized(ntds_settings_dn),
1193 ldb_errstring(ldb));
1194 talloc_free(tmp_ctx);
1195 return ret;
1198 msg->dn = op_feature_scope_dn;
1199 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1200 if (ret != LDB_SUCCESS) {
1201 ldb_asprintf_errstring(ldb,
1202 "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1203 ldb_dn_get_linearized(op_feature_scope_dn),
1204 ldb_errstring(ldb));
1205 talloc_free(tmp_ctx);
1206 return ret;
1209 return LDB_SUCCESS;
1212 static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_request *req)
1215 steps:
1216 - check for system (only system can enable features)
1217 - extract GUID from the request
1218 - find the feature object
1219 - check functional level, must be at least msDS-RequiredForestBehaviorVersion
1220 - check if it is already enabled (if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS) - probably not needed, just return error from the add/modify
1221 - add/modify objects (see ntdsconnection code for an example)
1224 struct ldb_context *ldb = ldb_module_get_ctx(module);
1225 struct GUID op_feature_guid;
1226 struct ldb_dn *op_feature_scope_dn;
1227 struct ldb_message *op_feature_msg;
1228 struct auth_session_info *session_info =
1229 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
1230 TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1231 int ret;
1232 const char *guid_string;
1234 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
1235 ldb_set_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature");
1236 return LDB_ERR_UNWILLING_TO_PERFORM;
1239 ret = get_optional_feature_dn_guid(req, ldb, tmp_ctx, &op_feature_scope_dn, &op_feature_guid);
1240 if (ret != LDB_SUCCESS) {
1241 talloc_free(tmp_ctx);
1242 return ret;
1245 guid_string = GUID_string(tmp_ctx, &op_feature_guid);
1246 if (!guid_string) {
1247 ldb_set_errstring(ldb, "rootdse: bad optional feature GUID");
1248 return LDB_ERR_UNWILLING_TO_PERFORM;
1251 ret = dsdb_find_optional_feature(module, ldb, tmp_ctx, op_feature_guid, &op_feature_msg, req);
1252 if (ret != LDB_SUCCESS) {
1253 ldb_asprintf_errstring(ldb,
1254 "rootdse: unable to find optional feature for %s - %s",
1255 guid_string, ldb_errstring(ldb));
1256 talloc_free(tmp_ctx);
1257 return ret;
1260 if (strcasecmp(DS_GUID_FEATURE_RECYCLE_BIN, guid_string) == 0) {
1261 ret = rootdse_enable_recycle_bin(module, ldb,
1262 tmp_ctx, op_feature_scope_dn,
1263 op_feature_msg, req);
1264 } else {
1265 ldb_asprintf_errstring(ldb,
1266 "rootdse: unknown optional feature %s",
1267 guid_string);
1268 talloc_free(tmp_ctx);
1269 return LDB_ERR_UNWILLING_TO_PERFORM;
1271 if (ret != LDB_SUCCESS) {
1272 ldb_asprintf_errstring(ldb,
1273 "rootdse: failed to set optional feature for %s - %s",
1274 guid_string, ldb_errstring(ldb));
1275 talloc_free(tmp_ctx);
1276 return ret;
1279 talloc_free(tmp_ctx);
1280 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);;
1283 static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request *req)
1285 struct ldb_context *ldb = ldb_module_get_ctx(module);
1286 struct ldb_result *ext_res;
1287 int ret;
1288 struct ldb_dn *schema_dn;
1290 schema_dn = ldb_get_schema_basedn(ldb);
1291 if (!schema_dn) {
1292 ldb_reset_err_string(ldb);
1293 ldb_debug(ldb, LDB_DEBUG_WARNING,
1294 "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1295 return ldb_next_request(module, req);
1298 ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
1299 if (ret != LDB_SUCCESS) {
1300 return ldb_operr(ldb);
1303 talloc_free(ext_res);
1304 return ldb_module_done(req, NULL, NULL, ret);
1307 static int rootdse_schemaupgradeinprogress(struct ldb_module *module, struct ldb_request *req)
1309 struct ldb_context *ldb = ldb_module_get_ctx(module);
1310 int ret = LDB_SUCCESS;
1311 struct ldb_dn *schema_dn;
1313 schema_dn = ldb_get_schema_basedn(ldb);
1314 if (!schema_dn) {
1315 ldb_reset_err_string(ldb);
1316 ldb_debug(ldb, LDB_DEBUG_WARNING,
1317 "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1318 return ldb_next_request(module, req);
1321 /* FIXME we have to do something in order to relax constraints for DRS
1322 * setting schemaUpgradeInProgress cause the fschemaUpgradeInProgress
1323 * in all LDAP connection (2K3/2K3R2) or in the current connection (2K8 and +)
1324 * to be set to true.
1327 /* from 5.113 LDAPConnections in DRSR.pdf
1328 * fschemaUpgradeInProgress: A Boolean that specifies certain constraint
1329 * validations are skipped when adding, updating, or removing directory
1330 * objects on the opened connection. The skipped constraint validations
1331 * are documented in the applicable constraint sections in [MS-ADTS].
1333 return ldb_module_done(req, NULL, NULL, ret);
1336 static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
1338 struct ldb_context *ldb = ldb_module_get_ctx(module);
1339 int ret;
1341 ret = rootdse_filter_operations(module, req);
1342 if (ret != LDB_SUCCESS) {
1343 return ret;
1346 ret = rootdse_filter_controls(module, req);
1347 if (ret != LDB_SUCCESS) {
1348 return ret;
1352 If dn is not "" we should let it pass through
1354 if (!ldb_dn_is_null(req->op.add.message->dn)) {
1355 return ldb_next_request(module, req);
1358 ldb_set_errstring(ldb, "rootdse_add: you cannot add a new rootdse entry!");
1359 return LDB_ERR_NAMING_VIOLATION;
1362 static int rootdse_start_trans(struct ldb_module *module)
1364 int ret;
1365 struct ldb_context *ldb = ldb_module_get_ctx(module);
1366 struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
1367 struct rootdse_private_data);
1368 ret = ldb_next_start_trans(module);
1369 if (ret == LDB_SUCCESS) {
1370 if (data->private_ev != NULL) {
1371 return ldb_operr(ldb);
1373 data->private_ev = s4_event_context_init(data);
1374 if (data->private_ev == NULL) {
1375 return ldb_operr(ldb);
1377 data->saved_ev = ldb_get_event_context(ldb);
1378 ldb_set_event_context(ldb, data->private_ev);
1380 return ret;
1383 static int rootdse_end_trans(struct ldb_module *module)
1385 int ret;
1386 struct ldb_context *ldb = ldb_module_get_ctx(module);
1387 struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
1388 struct rootdse_private_data);
1389 ret = ldb_next_end_trans(module);
1390 if (data->saved_ev == NULL) {
1391 return ldb_operr(ldb);
1394 if (data->private_ev != ldb_get_event_context(ldb)) {
1395 return ldb_operr(ldb);
1397 ldb_set_event_context(ldb, data->saved_ev);
1398 data->saved_ev = NULL;
1399 TALLOC_FREE(data->private_ev);
1400 return ret;
1403 static int rootdse_del_trans(struct ldb_module *module)
1405 int ret;
1406 struct ldb_context *ldb = ldb_module_get_ctx(module);
1407 struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
1408 struct rootdse_private_data);
1409 ret = ldb_next_del_trans(module);
1410 if (data->saved_ev == NULL) {
1411 return ldb_operr(ldb);
1414 if (data->private_ev != ldb_get_event_context(ldb)) {
1415 return ldb_operr(ldb);
1417 ldb_set_event_context(ldb, data->saved_ev);
1418 data->saved_ev = NULL;
1419 TALLOC_FREE(data->private_ev);
1420 return ret;
1423 struct fsmo_transfer_state {
1424 struct ldb_context *ldb;
1425 struct ldb_request *req;
1426 struct ldb_module *module;
1430 called when a FSMO transfer operation has completed
1432 static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
1434 struct fsmo_transfer_state *fsmo = tevent_req_callback_data(treq, struct fsmo_transfer_state);
1435 NTSTATUS status;
1436 WERROR werr;
1437 int ret;
1438 struct ldb_request *req = fsmo->req;
1439 struct ldb_context *ldb = fsmo->ldb;
1440 struct ldb_module *module = fsmo->module;
1442 status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr);
1443 talloc_free(fsmo);
1444 if (!NT_STATUS_IS_OK(status)) {
1445 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", nt_errstr(status));
1447 * Now that it is failed, start the transaction up
1448 * again so the wrappers can close it without additional error
1450 rootdse_start_trans(module);
1451 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1452 return;
1454 if (!W_ERROR_IS_OK(werr)) {
1455 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", win_errstr(werr));
1457 * Now that it is failed, start the transaction up
1458 * again so the wrappers can close it without additional error
1460 rootdse_start_trans(module);
1461 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1462 return;
1466 * Now that it is done, start the transaction up again so the
1467 * wrappers can close it without error
1469 ret = rootdse_start_trans(module);
1470 ldb_module_done(req, NULL, NULL, ret);
1473 static int rootdse_become_master(struct ldb_module *module,
1474 struct ldb_request *req,
1475 enum drepl_role_master role)
1477 struct imessaging_context *msg;
1478 struct ldb_context *ldb = ldb_module_get_ctx(module);
1479 TALLOC_CTX *tmp_ctx = talloc_new(req);
1480 struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
1481 bool am_rodc;
1482 struct dcerpc_binding_handle *irpc_handle;
1483 int ret;
1484 struct auth_session_info *session_info;
1485 enum security_user_level level;
1486 struct fsmo_transfer_state *fsmo;
1487 struct tevent_req *treq;
1489 session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
1490 level = security_session_user_level(session_info, NULL);
1491 if (level < SECURITY_ADMINISTRATOR) {
1492 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS, "Denied rootDSE modify for non-administrator");
1495 ret = samdb_rodc(ldb, &am_rodc);
1496 if (ret != LDB_SUCCESS) {
1497 return ldb_error(ldb, ret, "Could not determine if server is RODC.");
1500 if (am_rodc) {
1501 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1502 "RODC cannot become a role master.");
1506 * We always delete the transaction, not commit it, because
1507 * this gives the least supprise to this supprising action (as
1508 * we will never record anything done to this point
1510 rootdse_del_trans(module);
1512 msg = imessaging_client_init(tmp_ctx, lp_ctx,
1513 ldb_get_event_context(ldb));
1514 if (!msg) {
1515 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s", lpcfg_imessaging_path(tmp_ctx, lp_ctx));
1516 return LDB_ERR_OPERATIONS_ERROR;
1518 irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg,
1519 "dreplsrv",
1520 &ndr_table_irpc);
1521 if (irpc_handle == NULL) {
1522 return ldb_oom(ldb);
1524 fsmo = talloc_zero(req, struct fsmo_transfer_state);
1525 if (fsmo == NULL) {
1526 return ldb_oom(ldb);
1528 fsmo->ldb = ldb;
1529 fsmo->req = req;
1530 fsmo->module = module;
1533 * we send the call asynchronously, as the ldap client is
1534 * expecting to get an error back if the role transfer fails
1536 * We need more than the default 10 seconds IRPC allows, so
1537 * set a longer timeout (default ldb timeout is 300 seconds).
1538 * We send an async reply when we are done.
1540 * We are the first module, so don't bother working out how
1541 * long we have spent so far.
1543 dcerpc_binding_handle_set_timeout(irpc_handle, req->timeout);
1545 treq = dcerpc_drepl_takeFSMORole_send(req, ldb_get_event_context(ldb), irpc_handle, role);
1546 if (treq == NULL) {
1547 return ldb_oom(ldb);
1550 tevent_req_set_callback(treq, rootdse_fsmo_transfer_callback, fsmo);
1551 return LDB_SUCCESS;
1554 static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
1556 struct ldb_context *ldb = ldb_module_get_ctx(module);
1557 int ret;
1559 ret = rootdse_filter_operations(module, req);
1560 if (ret != LDB_SUCCESS) {
1561 return ret;
1564 ret = rootdse_filter_controls(module, req);
1565 if (ret != LDB_SUCCESS) {
1566 return ret;
1570 If dn is not "" we should let it pass through
1572 if (!ldb_dn_is_null(req->op.mod.message->dn)) {
1573 return ldb_next_request(module, req);
1577 dn is empty so check for schemaUpdateNow attribute
1578 "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
1580 if (ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow")) {
1581 return rootdse_schemaupdatenow(module, req);
1583 if (ldb_msg_find_element(req->op.mod.message, "becomeDomainMaster")) {
1584 return rootdse_become_master(module, req, DREPL_NAMING_MASTER);
1586 if (ldb_msg_find_element(req->op.mod.message, "becomeInfrastructureMaster")) {
1587 return rootdse_become_master(module, req, DREPL_INFRASTRUCTURE_MASTER);
1589 if (ldb_msg_find_element(req->op.mod.message, "becomeRidMaster")) {
1590 return rootdse_become_master(module, req, DREPL_RID_MASTER);
1592 if (ldb_msg_find_element(req->op.mod.message, "becomeSchemaMaster")) {
1593 return rootdse_become_master(module, req, DREPL_SCHEMA_MASTER);
1595 if (ldb_msg_find_element(req->op.mod.message, "becomePdc")) {
1596 return rootdse_become_master(module, req, DREPL_PDC_MASTER);
1598 if (ldb_msg_find_element(req->op.mod.message, "enableOptionalFeature")) {
1599 return rootdse_enableoptionalfeature(module, req);
1601 if (ldb_msg_find_element(req->op.mod.message, "schemaUpgradeInProgress")) {
1602 return rootdse_schemaupgradeinprogress(module, req);
1605 ldb_set_errstring(ldb, "rootdse_modify: unknown attribute to change!");
1606 return LDB_ERR_UNWILLING_TO_PERFORM;
1609 static int rootdse_rename(struct ldb_module *module, struct ldb_request *req)
1611 struct ldb_context *ldb = ldb_module_get_ctx(module);
1612 int ret;
1614 ret = rootdse_filter_operations(module, req);
1615 if (ret != LDB_SUCCESS) {
1616 return ret;
1619 ret = rootdse_filter_controls(module, req);
1620 if (ret != LDB_SUCCESS) {
1621 return ret;
1625 If dn is not "" we should let it pass through
1627 if (!ldb_dn_is_null(req->op.rename.olddn)) {
1628 return ldb_next_request(module, req);
1631 ldb_set_errstring(ldb, "rootdse_remove: you cannot rename the rootdse entry!");
1632 return LDB_ERR_NO_SUCH_OBJECT;
1635 static int rootdse_delete(struct ldb_module *module, struct ldb_request *req)
1637 struct ldb_context *ldb = ldb_module_get_ctx(module);
1638 int ret;
1640 ret = rootdse_filter_operations(module, req);
1641 if (ret != LDB_SUCCESS) {
1642 return ret;
1645 ret = rootdse_filter_controls(module, req);
1646 if (ret != LDB_SUCCESS) {
1647 return ret;
1651 If dn is not "" we should let it pass through
1653 if (!ldb_dn_is_null(req->op.del.dn)) {
1654 return ldb_next_request(module, req);
1657 ldb_set_errstring(ldb, "rootdse_remove: you cannot delete the rootdse entry!");
1658 return LDB_ERR_NO_SUCH_OBJECT;
1661 static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
1663 int ret;
1665 ret = rootdse_filter_operations(module, req);
1666 if (ret != LDB_SUCCESS) {
1667 return ret;
1670 ret = rootdse_filter_controls(module, req);
1671 if (ret != LDB_SUCCESS) {
1672 return ret;
1675 return ldb_next_request(module, req);
1678 static const struct ldb_module_ops ldb_rootdse_module_ops = {
1679 .name = "rootdse",
1680 .init_context = rootdse_init,
1681 .search = rootdse_search,
1682 .request = rootdse_request,
1683 .add = rootdse_add,
1684 .modify = rootdse_modify,
1685 .rename = rootdse_rename,
1686 .extended = rootdse_extended,
1687 .del = rootdse_delete,
1688 .start_transaction = rootdse_start_trans,
1689 .end_transaction = rootdse_end_trans,
1690 .del_transaction = rootdse_del_trans
1693 int ldb_rootdse_module_init(const char *version)
1695 LDB_MODULE_CHECK_VERSION(version);
1696 return ldb_register_module(&ldb_rootdse_module_ops);