s4:dsdb/rootdse: Pass rootdse context to rootdse_add_dynamic
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / rootdse.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    rootDSE ldb module
5
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Simo Sorce 2005-2008
8    Copyright (C) Matthieu Patou <mat@matws.net> 2011
9
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.
14
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.
19
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/>.
22 */
23
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
38 struct private_data {
39         unsigned int num_controls;
40         char **controls;
41         unsigned int num_partitions;
42         struct ldb_dn **partitions;
43         bool block_anonymous;
44 };
45
46 struct rootdse_context {
47         struct ldb_module *module;
48         struct ldb_request *req;
49 };
50
51 /*
52   return 1 if a specific attribute has been requested
53 */
54 static int do_attribute(const char * const *attrs, const char *name)
55 {
56         return attrs == NULL ||
57                 ldb_attr_in_list(attrs, name) ||
58                 ldb_attr_in_list(attrs, "*");
59 }
60
61 static int do_attribute_explicit(const char * const *attrs, const char *name)
62 {
63         return attrs != NULL && ldb_attr_in_list(attrs, name);
64 }
65
66
67 /*
68   expand a DN attribute to include extended DN information if requested
69  */
70 static int expand_dn_in_message(struct ldb_module *module, struct ldb_message *msg,
71                                 const char *attrname, struct ldb_control *edn_control,
72                                 struct ldb_request *req)
73 {
74         struct ldb_dn *dn, *dn2;
75         struct ldb_val *v;
76         int ret;
77         struct ldb_request *req2;
78         char *dn_string;
79         const char *no_attrs[] = { NULL };
80         struct ldb_result *res;
81         struct ldb_extended_dn_control *edn;
82         TALLOC_CTX *tmp_ctx = talloc_new(req);
83         struct ldb_context *ldb;
84         int edn_type = 0;
85         unsigned int i;
86         struct ldb_message_element *el;
87
88         ldb = ldb_module_get_ctx(module);
89
90         edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
91         if (edn) {
92                 edn_type = edn->type;
93         }
94
95         el = ldb_msg_find_element(msg, attrname);
96         if (!el || el->num_values == 0) {
97                 return LDB_SUCCESS;
98         }
99
100         for (i = 0; i < el->num_values; i++) {
101                 v = &el->values[i];
102                 if (v == NULL) {
103                         talloc_free(tmp_ctx);
104                         return LDB_SUCCESS;
105                 }
106
107                 dn_string = talloc_strndup(tmp_ctx, (const char *)v->data, v->length);
108                 if (dn_string == NULL) {
109                         talloc_free(tmp_ctx);
110                         return ldb_operr(ldb);
111                 }
112
113                 res = talloc_zero(tmp_ctx, struct ldb_result);
114                 if (res == NULL) {
115                         talloc_free(tmp_ctx);
116                         return ldb_operr(ldb);
117                 }
118
119                 dn = ldb_dn_new(tmp_ctx, ldb, dn_string);
120                 if (dn == NULL) {
121                         talloc_free(tmp_ctx);
122                         return ldb_operr(ldb);
123                 }
124
125                 ret = ldb_build_search_req(&req2, ldb, tmp_ctx,
126                                         dn,
127                                         LDB_SCOPE_BASE,
128                                         NULL,
129                                         no_attrs,
130                                         NULL,
131                                         res, ldb_search_default_callback,
132                                         req);
133                 LDB_REQ_SET_LOCATION(req2);
134                 if (ret != LDB_SUCCESS) {
135                         talloc_free(tmp_ctx);
136                         return ret;
137                 }
138
139
140                 ret = ldb_request_add_control(req2,
141                                         LDB_CONTROL_EXTENDED_DN_OID,
142                                         edn_control->critical, edn);
143                 if (ret != LDB_SUCCESS) {
144                         talloc_free(tmp_ctx);
145                         return ldb_error(ldb, ret, "Failed to add control");
146                 }
147
148                 ret = ldb_next_request(module, req2);
149                 if (ret == LDB_SUCCESS) {
150                         ret = ldb_wait(req2->handle, LDB_WAIT_ALL);
151                 }
152
153                 if (ret != LDB_SUCCESS) {
154                         talloc_free(tmp_ctx);
155                         return ret;
156                 }
157
158                 if (!res || res->count != 1) {
159                         talloc_free(tmp_ctx);
160                         return ldb_operr(ldb);
161                 }
162
163                 dn2 = res->msgs[0]->dn;
164
165                 v->data = (uint8_t *)ldb_dn_get_extended_linearized(msg->elements, dn2, edn_type);
166                 if (v->data == NULL) {
167                         talloc_free(tmp_ctx);
168                         return ldb_operr(ldb);
169                 }
170                 v->length = strlen((char *)v->data);
171         }
172
173         talloc_free(tmp_ctx);
174
175         return LDB_SUCCESS;
176 }
177
178 /*
179   see if we are master for a FSMO role
180  */
181 static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *dn, bool *master,
182                                      struct ldb_request *parent)
183 {
184         const char *attrs[] = { "fSMORoleOwner", NULL };
185         TALLOC_CTX *tmp_ctx = talloc_new(parent);
186         struct ldb_result *res;
187         int ret;
188         struct ldb_dn *owner_dn;
189
190         ret = dsdb_module_search_dn(module, tmp_ctx, &res,
191                                     dn, attrs,
192                                     DSDB_FLAG_NEXT_MODULE |
193                                     DSDB_FLAG_AS_SYSTEM |
194                                     DSDB_SEARCH_SHOW_EXTENDED_DN,
195                                     parent);
196         if (ret != LDB_SUCCESS) {
197                 talloc_free(tmp_ctx);
198                 return ret;
199         }
200
201         owner_dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
202                                            tmp_ctx, res->msgs[0], "fSMORoleOwner");
203         if (!owner_dn) {
204                 *master = false;
205                 talloc_free(tmp_ctx);
206                 return LDB_SUCCESS;
207         }
208
209         ret = samdb_dn_is_our_ntdsa(ldb_module_get_ctx(module), dn, master);
210         if (ret != LDB_SUCCESS) {
211                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to confirm if our ntdsDsa is %s: %s",
212                                        ldb_dn_get_linearized(owner_dn), ldb_errstring(ldb_module_get_ctx(module)));
213                 talloc_free(tmp_ctx);
214                 return ret;
215         }
216         
217         talloc_free(tmp_ctx);
218         return LDB_SUCCESS;
219 }
220
221 /*
222   add dynamically generated attributes to rootDSE result
223 */
224 static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg)
225 {
226         struct ldb_context *ldb;
227         struct private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct private_data);
228         const char * const *attrs = ac->req->op.search.attrs;
229         char **server_sasl;
230         const struct dsdb_schema *schema;
231         int *val;
232         struct ldb_control *edn_control;
233         const char *dn_attrs[] = {
234                 "configurationNamingContext",
235                 "defaultNamingContext",
236                 "rootDomainNamingContext",
237                 "schemaNamingContext",
238                 "serverName",
239                 "validFSMOs",
240                 "namingContexts",
241                 NULL
242         };
243         const char *guid_attrs[] = {
244                 "dsServiceName",
245                 NULL
246         };
247         unsigned int i;
248
249         ldb = ldb_module_get_ctx(ac->module);
250         schema = dsdb_get_schema(ldb, NULL);
251
252         msg->dn = ldb_dn_new(msg, ldb, NULL);
253
254         /* don't return the distinguishedName, cn and name attributes */
255         ldb_msg_remove_attr(msg, "distinguishedName");
256         ldb_msg_remove_attr(msg, "cn");
257         ldb_msg_remove_attr(msg, "name");
258
259         if (do_attribute(attrs, "serverName")) {
260                 if (ldb_msg_add_linearized_dn(msg, "serverName",
261                         samdb_server_dn(ldb, msg)) != LDB_SUCCESS) {
262                         goto failed;
263                 }
264         }
265
266         if (do_attribute(attrs, "dnsHostName")) {
267                 struct ldb_result *res;
268                 int ret;
269                 const char *dns_attrs[] = { "dNSHostName", NULL };
270                 ret = dsdb_module_search_dn(ac->module, msg, &res, samdb_server_dn(ldb, msg),
271                                             dns_attrs,
272                                             DSDB_FLAG_NEXT_MODULE |
273                                             DSDB_FLAG_AS_SYSTEM,
274                                             ac->req);
275                 if (ret == LDB_SUCCESS) {
276                         const char *hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
277                         if (hostname != NULL) {
278                                 if (ldb_msg_add_string(msg, "dnsHostName", hostname)) {
279                                         goto failed;
280                                 }
281                         }
282                 }
283         }
284
285         if (do_attribute(attrs, "ldapServiceName")) {
286                 struct loadparm_context *lp_ctx
287                         = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
288                                           struct loadparm_context);
289                 char *ldap_service_name, *hostname;
290
291                 hostname = strlower_talloc(msg, lpcfg_netbios_name(lp_ctx));
292                 if (hostname == NULL) {
293                         goto failed;
294                 }
295
296                 ldap_service_name = talloc_asprintf(msg, "%s:%s$@%s",
297                                                     samdb_forest_name(ldb, msg),
298                                                     hostname, lpcfg_realm(lp_ctx));
299                 if (ldap_service_name == NULL) {
300                         goto failed;
301                 }
302
303                 if (ldb_msg_add_string(msg, "ldapServiceName",
304                                        ldap_service_name) != LDB_SUCCESS) {
305                         goto failed;
306                 }
307         }
308
309         if (do_attribute(attrs, "currentTime")) {
310                 if (ldb_msg_add_steal_string(msg, "currentTime",
311                                              ldb_timestring(msg, time(NULL))) != LDB_SUCCESS) {
312                         goto failed;
313                 }
314         }
315
316         if (priv && do_attribute(attrs, "supportedControl")) {
317                 for (i = 0; i < priv->num_controls; i++) {
318                         char *control = talloc_strdup(msg, priv->controls[i]);
319                         if (!control) {
320                                 goto failed;
321                         }
322                         if (ldb_msg_add_steal_string(msg, "supportedControl",
323                                                      control) != LDB_SUCCESS) {
324                                 goto failed;
325                         }
326                 }
327         }
328
329         if (priv && do_attribute(attrs, "namingContexts")) {
330                 for (i = 0; i < priv->num_partitions; i++) {
331                         struct ldb_dn *dn = priv->partitions[i];
332                         if (ldb_msg_add_steal_string(msg, "namingContexts",
333                                                      ldb_dn_alloc_linearized(msg, dn)) != LDB_SUCCESS) {
334                                 goto failed;
335                         }
336                 }
337         }
338
339         server_sasl = talloc_get_type(ldb_get_opaque(ldb, "supportedSASLMechanisms"),
340                                        char *);
341         if (server_sasl && do_attribute(attrs, "supportedSASLMechanisms")) {
342                 for (i = 0; server_sasl && server_sasl[i]; i++) {
343                         char *sasl_name = talloc_strdup(msg, server_sasl[i]);
344                         if (!sasl_name) {
345                                 goto failed;
346                         }
347                         if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
348                                                      sasl_name) != LDB_SUCCESS) {
349                                 goto failed;
350                         }
351                 }
352         }
353
354         if (do_attribute(attrs, "highestCommittedUSN")) {
355                 uint64_t seq_num;
356                 int ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
357                 if (ret == LDB_SUCCESS) {
358                         if (samdb_msg_add_uint64(ldb, msg, msg,
359                                                  "highestCommittedUSN",
360                                                  seq_num) != LDB_SUCCESS) {
361                                 goto failed;
362                         }
363                 }
364         }
365
366         if (schema && do_attribute_explicit(attrs, "dsSchemaAttrCount")) {
367                 struct dsdb_attribute *cur;
368                 unsigned int n = 0;
369
370                 for (cur = schema->attributes; cur; cur = cur->next) {
371                         n++;
372                 }
373
374                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaAttrCount",
375                                        n) != LDB_SUCCESS) {
376                         goto failed;
377                 }
378         }
379
380         if (schema && do_attribute_explicit(attrs, "dsSchemaClassCount")) {
381                 struct dsdb_class *cur;
382                 unsigned int n = 0;
383
384                 for (cur = schema->classes; cur; cur = cur->next) {
385                         n++;
386                 }
387
388                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaClassCount",
389                                        n) != LDB_SUCCESS) {
390                         goto failed;
391                 }
392         }
393
394         if (schema && do_attribute_explicit(attrs, "dsSchemaPrefixCount")) {
395                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaPrefixCount",
396                                        schema->prefixmap->length) != LDB_SUCCESS) {
397                         goto failed;
398                 }
399         }
400
401         if (do_attribute_explicit(attrs, "validFSMOs")) {
402                 struct ldb_dn *dns[3];
403
404                 dns[0] = ldb_get_schema_basedn(ldb);
405                 dns[1] = samdb_partitions_dn(ldb, msg);
406                 dns[2] = ldb_get_default_basedn(ldb);
407
408                 for (i=0; i<3; i++) {
409                         bool master;
410                         int ret = dsdb_module_we_are_master(ac->module, dns[i], &master, ac->req);
411                         if (ret != LDB_SUCCESS) {
412                                 goto failed;
413                         }
414                         if (master && ldb_msg_add_fmt(msg, "validFSMOs", "%s",
415                                                       ldb_dn_get_linearized(dns[i])) != LDB_SUCCESS) {
416                                 goto failed;
417                         }
418                 }
419         }
420
421         if (do_attribute_explicit(attrs, "vendorVersion")) {
422                 if (ldb_msg_add_fmt(msg, "vendorVersion",
423                                     "%s", SAMBA_VERSION_STRING) != LDB_SUCCESS) {
424                         goto failed;
425                 }
426         }
427
428         if (do_attribute(attrs, "domainFunctionality")) {
429                 if (samdb_msg_add_int(ldb, msg, msg, "domainFunctionality",
430                                       dsdb_functional_level(ldb)) != LDB_SUCCESS) {
431                         goto failed;
432                 }
433         }
434
435         if (do_attribute(attrs, "forestFunctionality")) {
436                 if (samdb_msg_add_int(ldb, msg, msg, "forestFunctionality",
437                                       dsdb_forest_functional_level(ldb)) != LDB_SUCCESS) {
438                         goto failed;
439                 }
440         }
441
442         if (do_attribute(attrs, "domainControllerFunctionality")
443             && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int))) {
444                 if (samdb_msg_add_int(ldb, msg, msg,
445                                       "domainControllerFunctionality",
446                                       *val) != LDB_SUCCESS) {
447                         goto failed;
448                 }
449         }
450
451         if (do_attribute(attrs, "isGlobalCatalogReady")) {
452                 /* MS-ADTS 3.1.1.3.2.10
453                    Note, we should only return true here is we have
454                    completed at least one synchronisation. As both
455                    provision and vampire do a full sync, this means we
456                    can return true is the gc bit is set in the NTDSDSA
457                    options */
458                 if (ldb_msg_add_fmt(msg, "isGlobalCatalogReady",
459                                     "%s", samdb_is_gc(ldb)?"TRUE":"FALSE") != LDB_SUCCESS) {
460                         goto failed;
461                 }
462         }
463
464         if (do_attribute_explicit(attrs, "tokenGroups")) {
465                 /* Obtain the user's session_info */
466                 struct auth_session_info *session_info
467                         = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
468                 if (session_info && session_info->security_token) {
469                         /* The list of groups this user is in */
470                         for (i = 0; i < session_info->security_token->num_sids; i++) {
471                                 if (samdb_msg_add_dom_sid(ldb, msg, msg,
472                                                           "tokenGroups",
473                                                           &session_info->security_token->sids[i]) != LDB_SUCCESS) {
474                                         goto failed;
475                                 }
476                         }
477                 }
478         }
479
480         /* TODO: lots more dynamic attributes should be added here */
481
482         edn_control = ldb_request_get_control(ac->req, LDB_CONTROL_EXTENDED_DN_OID);
483
484         /* convert any GUID attributes to be in the right form */
485         for (i=0; guid_attrs[i]; i++) {
486                 struct ldb_result *res;
487                 struct ldb_message_element *el;
488                 struct ldb_dn *attr_dn;
489                 const char *no_attrs[] = { NULL };
490                 int ret;
491
492                 if (!do_attribute(attrs, guid_attrs[i])) continue;
493
494                 attr_dn = ldb_msg_find_attr_as_dn(ldb, ac->req, msg, guid_attrs[i]);
495                 if (attr_dn == NULL) {
496                         continue;
497                 }
498
499                 ret = dsdb_module_search_dn(ac->module, ac->req, &res,
500                                             attr_dn, no_attrs,
501                                             DSDB_FLAG_NEXT_MODULE |
502                                             DSDB_FLAG_AS_SYSTEM |
503                                             DSDB_SEARCH_SHOW_EXTENDED_DN,
504                                             ac->req);
505                 if (ret != LDB_SUCCESS) {
506                         return ldb_operr(ldb);
507                 }
508
509                 el = ldb_msg_find_element(msg, guid_attrs[i]);
510                 if (el == NULL) {
511                         return ldb_operr(ldb);
512                 }
513
514                 talloc_steal(el->values, res->msgs[0]->dn);
515                 if (edn_control) {
516                         struct ldb_extended_dn_control *edn;
517                         int edn_type = 0;
518                         edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
519                         if (edn != NULL) {
520                                 edn_type = edn->type;
521                         }
522                         el->values[0].data  = (uint8_t *)ldb_dn_get_extended_linearized(el->values,
523                                                                                         res->msgs[0]->dn,
524                                                                                         edn_type);
525                 } else {
526                         el->values[0].data  = (uint8_t *)talloc_strdup(el->values,
527                                                                        ldb_dn_get_linearized(res->msgs[0]->dn));
528                 }
529                 if (el->values[0].data == NULL) {
530                         return ldb_oom(ldb);
531                 }
532                 el->values[0].length = strlen((const char *)el->values[0].data);
533         }
534
535         /* if the client sent us the EXTENDED_DN control then we need
536            to expand the DNs to have GUID and SID. W2K8 join relies on
537            this */
538         if (edn_control) {
539                 int ret;
540                 for (i=0; dn_attrs[i]; i++) {
541                         if (!do_attribute(attrs, dn_attrs[i])) continue;
542                         ret = expand_dn_in_message(ac->module, msg, dn_attrs[i],
543                                                    edn_control, ac->req);
544                         if (ret != LDB_SUCCESS) {
545                                 DEBUG(0,(__location__ ": Failed to expand DN in rootDSE for %s\n",
546                                          dn_attrs[i]));
547                                 goto failed;
548                         }
549                 }
550         }
551
552         return LDB_SUCCESS;
553
554 failed:
555         return ldb_operr(ldb);
556 }
557
558 /*
559   handle search requests
560 */
561
562 static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
563                                                     struct ldb_request *req)
564 {
565         struct ldb_context *ldb;
566         struct rootdse_context *ac;
567
568         ldb = ldb_module_get_ctx(module);
569
570         ac = talloc_zero(req, struct rootdse_context);
571         if (ac == NULL) {
572                 ldb_set_errstring(ldb, "Out of Memory");
573                 return NULL;
574         }
575
576         ac->module = module;
577         ac->req = req;
578
579         return ac;
580 }
581
582 static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
583 {
584         struct rootdse_context *ac;
585         int ret;
586
587         ac = talloc_get_type(req->context, struct rootdse_context);
588
589         if (!ares) {
590                 return ldb_module_done(ac->req, NULL, NULL,
591                                         LDB_ERR_OPERATIONS_ERROR);
592         }
593         if (ares->error != LDB_SUCCESS) {
594                 return ldb_module_done(ac->req, ares->controls,
595                                         ares->response, ares->error);
596         }
597
598         switch (ares->type) {
599         case LDB_REPLY_ENTRY:
600                 /*
601                  * if the client explicit asks for the 'netlogon' attribute
602                  * the reply_entry needs to be skipped
603                  */
604                 if (ac->req->op.search.attrs &&
605                     ldb_attr_in_list(ac->req->op.search.attrs, "netlogon")) {
606                         talloc_free(ares);
607                         return LDB_SUCCESS;
608                 }
609
610                 /* for each record returned post-process to add any dynamic
611                    attributes that have been asked for */
612                 ret = rootdse_add_dynamic(ac, ares->message);
613                 if (ret != LDB_SUCCESS) {
614                         talloc_free(ares);
615                         return ldb_module_done(ac->req, NULL, NULL, ret);
616                 }
617
618                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
619
620         case LDB_REPLY_REFERRAL:
621                 /* should we allow the backend to return referrals in this case
622                  * ?? */
623                 break;
624
625         case LDB_REPLY_DONE:
626                 return ldb_module_done(ac->req, ares->controls,
627                                         ares->response, ares->error);
628         }
629
630         talloc_free(ares);
631         return LDB_SUCCESS;
632 }
633
634 /*
635   filter from controls from clients in several ways
636
637   1) mark our registered controls as non-critical in the request
638
639     This is needed as clients may mark controls as critical even if
640     they are not needed at all in a request. For example, the centrify
641     client sets the SD_FLAGS control as critical on ldap modify
642     requests which are setting the dNSHostName attribute on the
643     machine account. That request doesn't need SD_FLAGS at all, but
644     centrify adds it on all ldap requests.
645
646   2) if this request is untrusted then remove any non-registered
647      controls that are non-critical
648
649     This is used on ldap:// connections to prevent remote users from
650     setting an internal control that may be dangerous
651
652   3) if this request is untrusted then fail any request that includes
653      a critical non-registered control
654  */
655 static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
656 {
657         unsigned int i, j;
658         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
659         bool is_untrusted;
660
661         if (!req->controls) {
662                 return LDB_SUCCESS;
663         }
664
665         is_untrusted = ldb_req_is_untrusted(req);
666
667         for (i=0; req->controls[i]; i++) {
668                 bool is_registered = false;
669                 bool is_critical = (req->controls[i]->critical != 0);
670
671                 if (req->controls[i]->oid == NULL) {
672                         continue;
673                 }
674
675                 if (is_untrusted || is_critical) {
676                         for (j=0; j<priv->num_controls; j++) {
677                                 if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
678                                         is_registered = true;
679                                         break;
680                                 }
681                         }
682                 }
683
684                 if (is_untrusted && !is_registered) {
685                         if (!is_critical) {
686                                 /* remove it by marking the oid NULL */
687                                 req->controls[i]->oid = NULL;
688                                 req->controls[i]->data = NULL;
689                                 req->controls[i]->critical = 0;
690                                 continue;
691                         }
692                         /* its a critical unregistered control - give
693                            an error */
694                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
695                                                "Attempt to use critical non-registered control '%s'",
696                                                req->controls[i]->oid);
697                         return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
698                 }
699
700                 if (!is_critical) {
701                         continue;
702                 }
703
704                 /* If the control is DIRSYNC control then we keep the critical
705                  * flag as the dirsync module will need to act upon it
706                  */
707                 if (is_registered && strcmp(req->controls[i]->oid,
708                                         LDB_CONTROL_DIRSYNC_OID)!= 0) {
709                         req->controls[i]->critical = 0;
710                 }
711         }
712
713         return LDB_SUCCESS;
714 }
715
716 /* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
717
718 static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
719 {
720         struct auth_session_info *session_info;
721         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
722         bool is_untrusted = ldb_req_is_untrusted(req);
723         bool is_anonymous = true;
724         if (is_untrusted == false) {
725                 return LDB_SUCCESS;
726         }
727
728         session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
729         if (session_info) {
730                 is_anonymous = security_token_is_anonymous(session_info->security_token);
731         }
732         
733         if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
734                 return LDB_SUCCESS;
735         }
736         
737         if (req->operation == LDB_SEARCH) {
738                 if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
739                         return LDB_SUCCESS;
740                 }
741         }
742         ldb_set_errstring(ldb_module_get_ctx(module), "Operation unavailable without authentication");
743         return LDB_ERR_OPERATIONS_ERROR;
744 }
745
746 static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
747 {
748         struct ldb_context *ldb;
749         struct rootdse_context *ac;
750         struct ldb_request *down_req;
751         int ret;
752
753         ret = rootdse_filter_operations(module, req);
754         if (ret != LDB_SUCCESS) {
755                 return ret;
756         }
757
758         ret = rootdse_filter_controls(module, req);
759         if (ret != LDB_SUCCESS) {
760                 return ret;
761         }
762
763         ldb = ldb_module_get_ctx(module);
764
765         /* see if its for the rootDSE - only a base search on the "" DN qualifies */
766         if (!(req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base))) {
767                 /* Otherwise, pass down to the rest of the stack */
768                 return ldb_next_request(module, req);
769         }
770
771         ac = rootdse_init_context(module, req);
772         if (ac == NULL) {
773                 return ldb_operr(ldb);
774         }
775
776         /* in our db we store the rootDSE with a DN of @ROOTDSE */
777         ret = ldb_build_search_req(&down_req, ldb, ac,
778                                         ldb_dn_new(ac, ldb, "@ROOTDSE"),
779                                         LDB_SCOPE_BASE,
780                                         NULL,
781                                         req->op.search.attrs,
782                                         NULL,/* for now skip the controls from the client */
783                                         ac, rootdse_callback,
784                                         req);
785         LDB_REQ_SET_LOCATION(down_req);
786         if (ret != LDB_SUCCESS) {
787                 return ret;
788         }
789
790         return ldb_next_request(module, down_req);
791 }
792
793 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
794 {
795         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
796         char **list;
797
798         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
799         if (!list) {
800                 return ldb_oom(ldb_module_get_ctx(module));
801         }
802
803         list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid);
804         if (!list[priv->num_controls]) {
805                 return ldb_oom(ldb_module_get_ctx(module));
806         }
807
808         priv->num_controls += 1;
809         priv->controls = list;
810
811         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
812 }
813
814 static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
815 {
816         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
817         struct ldb_dn **list;
818
819         list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
820         if (!list) {
821                 return ldb_oom(ldb_module_get_ctx(module));
822         }
823
824         list[priv->num_partitions] = ldb_dn_copy(list, req->op.reg_partition.dn);
825         if (!list[priv->num_partitions]) {
826                 return ldb_operr(ldb_module_get_ctx(module));
827         }
828
829         priv->num_partitions += 1;
830         priv->partitions = list;
831
832         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
833 }
834
835
836 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
837 {
838         switch (req->operation) {
839
840         case LDB_REQ_REGISTER_CONTROL:
841                 return rootdse_register_control(module, req);
842         case LDB_REQ_REGISTER_PARTITION:
843                 return rootdse_register_partition(module, req);
844
845         default:
846                 break;
847         }
848         return ldb_next_request(module, req);
849 }
850
851 static int rootdse_init(struct ldb_module *module)
852 {
853         int ret;
854         struct ldb_context *ldb;
855         struct ldb_result *res;
856         struct private_data *data;
857         const char *attrs[] = { "msDS-Behavior-Version", NULL };
858         const char *ds_attrs[] = { "dsServiceName", NULL };
859         TALLOC_CTX *mem_ctx;
860
861         ldb = ldb_module_get_ctx(module);
862
863         data = talloc_zero(module, struct private_data);
864         if (data == NULL) {
865                 return ldb_oom(ldb);
866         }
867
868         data->num_controls = 0;
869         data->controls = NULL;
870         data->num_partitions = 0;
871         data->partitions = NULL;
872         data->block_anonymous = true;
873
874         ldb_module_set_private(module, data);
875
876         ldb_set_default_dns(ldb);
877
878         ret = ldb_next_init(module);
879
880         if (ret != LDB_SUCCESS) {
881                 return ret;
882         }
883
884         mem_ctx = talloc_new(data);
885         if (!mem_ctx) {
886                 return ldb_oom(ldb);
887         }
888
889         /* Now that the partitions are set up, do a search for:
890            - domainControllerFunctionality
891            - domainFunctionality
892            - forestFunctionality
893
894            Then stuff these values into an opaque
895         */
896         ret = dsdb_module_search(module, mem_ctx, &res,
897                                  ldb_get_default_basedn(ldb),
898                                  LDB_SCOPE_BASE, attrs,
899                                  DSDB_FLAG_NEXT_MODULE |
900                                  DSDB_FLAG_AS_SYSTEM,
901                                  NULL, NULL);
902         if (ret == LDB_SUCCESS && res->count == 1) {
903                 int domain_behaviour_version
904                         = ldb_msg_find_attr_as_int(res->msgs[0],
905                                                    "msDS-Behavior-Version", -1);
906                 if (domain_behaviour_version != -1) {
907                         int *val = talloc(ldb, int);
908                         if (!val) {
909                                 talloc_free(mem_ctx);
910                                 return ldb_oom(ldb);
911                         }
912                         *val = domain_behaviour_version;
913                         ret = ldb_set_opaque(ldb, "domainFunctionality", val);
914                         if (ret != LDB_SUCCESS) {
915                                 talloc_free(mem_ctx);
916                                 return ret;
917                         }
918                 }
919         }
920
921         ret = dsdb_module_search(module, mem_ctx, &res,
922                                  samdb_partitions_dn(ldb, mem_ctx),
923                                  LDB_SCOPE_BASE, attrs,
924                                  DSDB_FLAG_NEXT_MODULE |
925                                  DSDB_FLAG_AS_SYSTEM,
926                                  NULL, NULL);
927         if (ret == LDB_SUCCESS && res->count == 1) {
928                 int forest_behaviour_version
929                         = ldb_msg_find_attr_as_int(res->msgs[0],
930                                                    "msDS-Behavior-Version", -1);
931                 if (forest_behaviour_version != -1) {
932                         int *val = talloc(ldb, int);
933                         if (!val) {
934                                 talloc_free(mem_ctx);
935                                 return ldb_oom(ldb);
936                         }
937                         *val = forest_behaviour_version;
938                         ret = ldb_set_opaque(ldb, "forestFunctionality", val);
939                         if (ret != LDB_SUCCESS) {
940                                 talloc_free(mem_ctx);
941                                 return ret;
942                         }
943                 }
944         }
945
946         /* For now, our own server's location in the DB is recorded in
947          * the @ROOTDSE record */
948         ret = dsdb_module_search(module, mem_ctx, &res,
949                                  ldb_dn_new(mem_ctx, ldb, "@ROOTDSE"),
950                                  LDB_SCOPE_BASE, ds_attrs,
951                                  DSDB_FLAG_NEXT_MODULE |
952                                  DSDB_FLAG_AS_SYSTEM,
953                                  NULL, NULL);
954         if (ret == LDB_SUCCESS && res->count == 1) {
955                 struct ldb_dn *ds_dn
956                         = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0],
957                                                   "dsServiceName");
958                 if (ds_dn) {
959                         ret = dsdb_module_search(module, mem_ctx, &res, ds_dn,
960                                                  LDB_SCOPE_BASE, attrs,
961                                                  DSDB_FLAG_NEXT_MODULE |
962                                                  DSDB_FLAG_AS_SYSTEM,
963                                                  NULL, NULL);
964                         if (ret == LDB_SUCCESS && res->count == 1) {
965                                 int domain_controller_behaviour_version
966                                         = ldb_msg_find_attr_as_int(res->msgs[0],
967                                                                    "msDS-Behavior-Version", -1);
968                                 if (domain_controller_behaviour_version != -1) {
969                                         int *val = talloc(ldb, int);
970                                         if (!val) {
971                                                 talloc_free(mem_ctx);
972                                                 return ldb_oom(ldb);
973                                         }
974                                         *val = domain_controller_behaviour_version;
975                                         ret = ldb_set_opaque(ldb,
976                                                              "domainControllerFunctionality", val);
977                                         if (ret != LDB_SUCCESS) {
978                                                 talloc_free(mem_ctx);
979                                                 return ret;
980                                         }
981                                 }
982                         }
983                 }
984         }
985
986         data->block_anonymous = dsdb_block_anonymous_ops(module, NULL);
987
988         talloc_free(mem_ctx);
989
990         return LDB_SUCCESS;
991 }
992
993 /*
994  * This function gets the string SCOPE_DN:OPTIONAL_FEATURE_GUID and parse it
995  * to a DN and a GUID object
996  */
997 static int get_optional_feature_dn_guid(struct ldb_request *req, struct ldb_context *ldb,
998                                                 TALLOC_CTX *mem_ctx,
999                                                 struct ldb_dn **op_feature_scope_dn,
1000                                                 struct GUID *op_feature_guid)
1001 {
1002         const struct ldb_message *msg = req->op.mod.message;
1003         const char *ldb_val_str;
1004         char *dn, *guid;
1005         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1006         NTSTATUS status;
1007
1008         ldb_val_str = ldb_msg_find_attr_as_string(msg, "enableOptionalFeature", NULL);
1009         if (!ldb_val_str) {
1010                 ldb_set_errstring(ldb,
1011                                   "rootdse: unable to find 'enableOptionalFeature'!");
1012                 return LDB_ERR_UNWILLING_TO_PERFORM;
1013         }
1014
1015         guid = strchr(ldb_val_str, ':');
1016         if (!guid) {
1017                 ldb_set_errstring(ldb,
1018                                   "rootdse: unable to find GUID in 'enableOptionalFeature'!");
1019                 return LDB_ERR_UNWILLING_TO_PERFORM;
1020         }
1021         status = GUID_from_string(guid+1, op_feature_guid);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 ldb_set_errstring(ldb,
1024                                   "rootdse: bad GUID in 'enableOptionalFeature'!");
1025                 return LDB_ERR_UNWILLING_TO_PERFORM;
1026         }
1027
1028         dn = talloc_strndup(tmp_ctx, ldb_val_str, guid-ldb_val_str);
1029         if (!dn) {
1030                 ldb_set_errstring(ldb,
1031                                   "rootdse: bad DN in 'enableOptionalFeature'!");
1032                 return LDB_ERR_UNWILLING_TO_PERFORM;
1033         }
1034
1035         *op_feature_scope_dn = ldb_dn_new(mem_ctx, ldb, dn);
1036
1037         talloc_free(tmp_ctx);
1038         return LDB_SUCCESS;
1039 }
1040
1041 /*
1042  * This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
1043  * ldb_message object.
1044  */
1045 static int dsdb_find_optional_feature(struct ldb_module *module, struct ldb_context *ldb,
1046                                       TALLOC_CTX *mem_ctx, struct GUID op_feature_guid, struct ldb_message **msg,
1047                                       struct ldb_request *parent)
1048 {
1049         struct ldb_result *res;
1050         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1051         int ret;
1052
1053         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
1054                                  NULL,
1055                                  DSDB_FLAG_NEXT_MODULE |
1056                                  DSDB_FLAG_AS_SYSTEM |
1057                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
1058                                  parent,
1059                                  "(&(objectClass=msDS-OptionalFeature)"
1060                                  "(msDS-OptionalFeatureGUID=%s))",GUID_string(tmp_ctx, &op_feature_guid));
1061
1062         if (ret != LDB_SUCCESS) {
1063                 talloc_free(tmp_ctx);
1064                 return ret;
1065         }
1066         if (res->count == 0) {
1067                 talloc_free(tmp_ctx);
1068                 return LDB_ERR_NO_SUCH_OBJECT;
1069         }
1070         if (res->count != 1) {
1071                 ldb_asprintf_errstring(ldb,
1072                                        "More than one object found matching optional feature GUID %s\n",
1073                                        GUID_string(tmp_ctx, &op_feature_guid));
1074                 talloc_free(tmp_ctx);
1075                 return LDB_ERR_OPERATIONS_ERROR;
1076         }
1077
1078         *msg = talloc_steal(mem_ctx, res->msgs[0]);
1079
1080         talloc_free(tmp_ctx);
1081         return LDB_SUCCESS;
1082 }
1083
1084 static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_context *ldb,
1085                                       TALLOC_CTX *mem_ctx, struct ldb_dn *op_feature_scope_dn,
1086                                       struct ldb_message *op_feature_msg, struct ldb_request *parent)
1087 {
1088         int ret;
1089         const int domain_func_level = dsdb_functional_level(ldb);
1090         struct ldb_dn *ntds_settings_dn;
1091         TALLOC_CTX *tmp_ctx;
1092         unsigned int el_count = 0;
1093         struct ldb_message *msg;
1094
1095         ret = ldb_msg_find_attr_as_int(op_feature_msg, "msDS-RequiredForestBehaviorVersion", 0);
1096         if (domain_func_level < ret){
1097                 ldb_asprintf_errstring(ldb,
1098                                        "rootdse_enable_recycle_bin: Domain functional level must be at least %d\n",
1099                                        ret);
1100                 return LDB_ERR_UNWILLING_TO_PERFORM;
1101         }
1102
1103         tmp_ctx = talloc_new(mem_ctx);
1104         ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
1105         if (!ntds_settings_dn) {
1106                 talloc_free(tmp_ctx);
1107                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to find NTDS settings DN");
1108         }
1109
1110         ntds_settings_dn = ldb_dn_copy(tmp_ctx, ntds_settings_dn);
1111         if (!ntds_settings_dn) {
1112                 talloc_free(tmp_ctx);
1113                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to copy NTDS settings DN");
1114         }
1115
1116         msg = ldb_msg_new(tmp_ctx);
1117         msg->dn = ntds_settings_dn;
1118
1119         ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
1120         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
1121
1122         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1123         if (ret != LDB_SUCCESS) {
1124                 ldb_asprintf_errstring(ldb,
1125                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1126                                        ldb_dn_get_linearized(ntds_settings_dn),
1127                                        ldb_errstring(ldb));
1128                 talloc_free(tmp_ctx);
1129                 return ret;
1130         }
1131
1132         msg->dn = op_feature_scope_dn;
1133         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1134         if (ret != LDB_SUCCESS) {
1135                 ldb_asprintf_errstring(ldb,
1136                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
1137                                        ldb_dn_get_linearized(op_feature_scope_dn),
1138                                        ldb_errstring(ldb));
1139                 talloc_free(tmp_ctx);
1140                 return ret;
1141         }
1142
1143         return LDB_SUCCESS;
1144 }
1145
1146 static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_request *req)
1147 {
1148         /*
1149           steps:
1150                - check for system (only system can enable features)
1151                - extract GUID from the request
1152                - find the feature object
1153                - check functional level, must be at least msDS-RequiredForestBehaviorVersion
1154                - check if it is already enabled (if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS) - probably not needed, just return error from the add/modify
1155                - add/modify objects (see ntdsconnection code for an example)
1156          */
1157
1158         struct ldb_context *ldb = ldb_module_get_ctx(module);
1159         struct GUID op_feature_guid;
1160         struct ldb_dn *op_feature_scope_dn;
1161         struct ldb_message *op_feature_msg;
1162         struct auth_session_info *session_info =
1163                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
1164         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1165         int ret;
1166         const char *guid_string;
1167
1168         if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
1169                 ldb_set_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature");
1170                 return LDB_ERR_UNWILLING_TO_PERFORM;
1171         }
1172
1173         ret = get_optional_feature_dn_guid(req, ldb, tmp_ctx, &op_feature_scope_dn, &op_feature_guid);
1174         if (ret != LDB_SUCCESS) {
1175                 talloc_free(tmp_ctx);
1176                 return ret;
1177         }
1178
1179         guid_string = GUID_string(tmp_ctx, &op_feature_guid);
1180         if (!guid_string) {
1181                 ldb_set_errstring(ldb, "rootdse: bad optional feature GUID");
1182                 return LDB_ERR_UNWILLING_TO_PERFORM;
1183         }
1184
1185         ret = dsdb_find_optional_feature(module, ldb, tmp_ctx, op_feature_guid, &op_feature_msg, req);
1186         if (ret != LDB_SUCCESS) {
1187                 ldb_asprintf_errstring(ldb,
1188                                        "rootdse: unable to find optional feature for %s - %s",
1189                                        guid_string, ldb_errstring(ldb));
1190                 talloc_free(tmp_ctx);
1191                 return ret;
1192         }
1193
1194         if (strcasecmp(DS_GUID_FEATURE_RECYCLE_BIN, guid_string) == 0) {
1195                         ret = rootdse_enable_recycle_bin(module, ldb,
1196                                                          tmp_ctx, op_feature_scope_dn,
1197                                                          op_feature_msg, req);
1198         } else {
1199                 ldb_asprintf_errstring(ldb,
1200                                        "rootdse: unknown optional feature %s",
1201                                        guid_string);
1202                 talloc_free(tmp_ctx);
1203                 return LDB_ERR_UNWILLING_TO_PERFORM;
1204         }
1205         if (ret != LDB_SUCCESS) {
1206                 ldb_asprintf_errstring(ldb,
1207                                        "rootdse: failed to set optional feature for %s - %s",
1208                                        guid_string, ldb_errstring(ldb));
1209                 talloc_free(tmp_ctx);
1210                 return ret;
1211         }
1212
1213         talloc_free(tmp_ctx);
1214         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);;
1215 }
1216
1217 static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request *req)
1218 {
1219         struct ldb_context *ldb = ldb_module_get_ctx(module);
1220         struct ldb_result *ext_res;
1221         int ret;
1222         struct ldb_dn *schema_dn;
1223
1224         schema_dn = ldb_get_schema_basedn(ldb);
1225         if (!schema_dn) {
1226                 ldb_reset_err_string(ldb);
1227                 ldb_debug(ldb, LDB_DEBUG_WARNING,
1228                           "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1229                 return ldb_next_request(module, req);
1230         }
1231
1232         ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
1233         if (ret != LDB_SUCCESS) {
1234                 return ldb_operr(ldb);
1235         }
1236
1237         talloc_free(ext_res);
1238         return ldb_module_done(req, NULL, NULL, ret);
1239 }
1240
1241 static int rootdse_schemaupgradeinprogress(struct ldb_module *module, struct ldb_request *req)
1242 {
1243         struct ldb_context *ldb = ldb_module_get_ctx(module);
1244         int ret = LDB_SUCCESS;
1245         struct ldb_dn *schema_dn;
1246
1247         schema_dn = ldb_get_schema_basedn(ldb);
1248         if (!schema_dn) {
1249                 ldb_reset_err_string(ldb);
1250                 ldb_debug(ldb, LDB_DEBUG_WARNING,
1251                           "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1252                 return ldb_next_request(module, req);
1253         }
1254
1255         /* FIXME we have to do something in order to relax constraints for DRS
1256          * setting schemaUpgradeInProgress cause the fschemaUpgradeInProgress
1257          * in all LDAP connection (2K3/2K3R2) or in the current connection (2K8 and +)
1258          * to be set to true.
1259          */
1260
1261         /* from 5.113 LDAPConnections in DRSR.pdf
1262          * fschemaUpgradeInProgress: A Boolean that specifies certain constraint
1263          * validations are skipped when adding, updating, or removing directory
1264          * objects on the opened connection. The skipped constraint validations
1265          * are documented in the applicable constraint sections in [MS-ADTS].
1266          */
1267         return ldb_module_done(req, NULL, NULL, ret);
1268 }
1269
1270 static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
1271 {
1272         struct ldb_context *ldb = ldb_module_get_ctx(module);
1273         int ret;
1274
1275         ret = rootdse_filter_operations(module, req);
1276         if (ret != LDB_SUCCESS) {
1277                 return ret;
1278         }
1279
1280         ret = rootdse_filter_controls(module, req);
1281         if (ret != LDB_SUCCESS) {
1282                 return ret;
1283         }
1284
1285         /*
1286                 If dn is not "" we should let it pass through
1287         */
1288         if (!ldb_dn_is_null(req->op.add.message->dn)) {
1289                 return ldb_next_request(module, req);
1290         }
1291
1292         ldb_set_errstring(ldb, "rootdse_add: you cannot add a new rootdse entry!");
1293         return LDB_ERR_NAMING_VIOLATION;
1294 }
1295
1296 struct fsmo_transfer_state {
1297         struct ldb_context *ldb;
1298         struct ldb_request *req;
1299         struct ldb_module *module;
1300 };
1301
1302 /*
1303   called when a FSMO transfer operation has completed
1304  */
1305 static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
1306 {
1307         struct fsmo_transfer_state *fsmo = tevent_req_callback_data(treq, struct fsmo_transfer_state);
1308         NTSTATUS status;
1309         WERROR werr;
1310         int ret;
1311         struct ldb_request *req = fsmo->req;
1312         struct ldb_context *ldb = fsmo->ldb;
1313
1314         status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr);
1315         talloc_free(fsmo);
1316         if (!NT_STATUS_IS_OK(status)) {
1317                 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", nt_errstr(status));
1318                 /*
1319                  * Now that it is failed, start the transaction up
1320                  * again so the wrappers can close it without additional error
1321                  */
1322                 ldb_next_start_trans(fsmo->module);
1323                 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1324                 return;
1325         }
1326         if (!W_ERROR_IS_OK(werr)) {
1327                 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", win_errstr(werr));
1328                 /*
1329                  * Now that it is failed, start the transaction up
1330                  * again so the wrappers can close it without additional error
1331                  */
1332                 ldb_next_start_trans(fsmo->module);
1333                 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
1334                 return;
1335         }
1336
1337         /*
1338          * Now that it is done, start the transaction up again so the
1339          * wrappers can close it without error
1340          */
1341         ret = ldb_next_start_trans(fsmo->module);
1342         ldb_module_done(req, NULL, NULL, ret);
1343 }
1344
1345 static int rootdse_become_master(struct ldb_module *module,
1346                                  struct ldb_request *req,
1347                                  enum drepl_role_master role)
1348 {
1349         struct imessaging_context *msg;
1350         struct ldb_context *ldb = ldb_module_get_ctx(module);
1351         TALLOC_CTX *tmp_ctx = talloc_new(req);
1352         struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
1353         bool am_rodc;
1354         struct dcerpc_binding_handle *irpc_handle;
1355         int ret;
1356         struct auth_session_info *session_info;
1357         enum security_user_level level;
1358         struct fsmo_transfer_state *fsmo;
1359         struct tevent_req *treq;
1360
1361         session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo");
1362         level = security_session_user_level(session_info, NULL);
1363         if (level < SECURITY_ADMINISTRATOR) {
1364                 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS, "Denied rootDSE modify for non-administrator");
1365         }
1366
1367         ret = samdb_rodc(ldb, &am_rodc);
1368         if (ret != LDB_SUCCESS) {
1369                 return ldb_error(ldb, ret, "Could not determine if server is RODC.");
1370         }
1371
1372         if (am_rodc) {
1373                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1374                                  "RODC cannot become a role master.");
1375         }
1376
1377         /*
1378          * We always delete the transaction, not commit it, because
1379          * this gives the least supprise to this supprising action (as
1380          * we will never record anything done to this point
1381          */
1382         ldb_next_del_trans(module);
1383
1384         msg = imessaging_client_init(tmp_ctx, lp_ctx,
1385                                     ldb_get_event_context(ldb));
1386         if (!msg) {
1387                 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s", lpcfg_imessaging_path(tmp_ctx, lp_ctx));
1388                 return LDB_ERR_OPERATIONS_ERROR;
1389         }
1390         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg,
1391                                                   "dreplsrv",
1392                                                   &ndr_table_irpc);
1393         if (irpc_handle == NULL) {
1394                 return ldb_oom(ldb);
1395         }
1396         fsmo = talloc_zero(req, struct fsmo_transfer_state);
1397         if (fsmo == NULL) {
1398                 return ldb_oom(ldb);
1399         }
1400         fsmo->ldb = ldb;
1401         fsmo->req = req;
1402         fsmo->module = module;
1403
1404         /*
1405          * we send the call asynchronously, as the ldap client is
1406          * expecting to get an error back if the role transfer fails
1407          *
1408          * We need more than the default 10 seconds IRPC allows, so
1409          * set a longer timeout (default ldb timeout is 300 seconds).
1410          * We send an async reply when we are done.
1411          *
1412          * We are the first module, so don't bother working out how
1413          * long we have spent so far.
1414          */
1415         dcerpc_binding_handle_set_timeout(irpc_handle, req->timeout);
1416
1417         treq = dcerpc_drepl_takeFSMORole_send(req, ldb_get_event_context(ldb), irpc_handle, role);
1418         if (treq == NULL) {
1419                 return ldb_oom(ldb);
1420         }
1421
1422         tevent_req_set_callback(treq, rootdse_fsmo_transfer_callback, fsmo);
1423         return LDB_SUCCESS;
1424 }
1425
1426 static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
1427 {
1428         struct ldb_context *ldb = ldb_module_get_ctx(module);
1429         int ret;
1430
1431         ret = rootdse_filter_operations(module, req);
1432         if (ret != LDB_SUCCESS) {
1433                 return ret;
1434         }
1435
1436         ret = rootdse_filter_controls(module, req);
1437         if (ret != LDB_SUCCESS) {
1438                 return ret;
1439         }
1440
1441         /*
1442                 If dn is not "" we should let it pass through
1443         */
1444         if (!ldb_dn_is_null(req->op.mod.message->dn)) {
1445                 return ldb_next_request(module, req);
1446         }
1447
1448         /*
1449                 dn is empty so check for schemaUpdateNow attribute
1450                 "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
1451         */
1452         if (ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow")) {
1453                 return rootdse_schemaupdatenow(module, req);
1454         }
1455         if (ldb_msg_find_element(req->op.mod.message, "becomeDomainMaster")) {
1456                 return rootdse_become_master(module, req, DREPL_NAMING_MASTER);
1457         }
1458         if (ldb_msg_find_element(req->op.mod.message, "becomeInfrastructureMaster")) {
1459                 return rootdse_become_master(module, req, DREPL_INFRASTRUCTURE_MASTER);
1460         }
1461         if (ldb_msg_find_element(req->op.mod.message, "becomeRidMaster")) {
1462                 return rootdse_become_master(module, req, DREPL_RID_MASTER);
1463         }
1464         if (ldb_msg_find_element(req->op.mod.message, "becomeSchemaMaster")) {
1465                 return rootdse_become_master(module, req, DREPL_SCHEMA_MASTER);
1466         }
1467         if (ldb_msg_find_element(req->op.mod.message, "becomePdc")) {
1468                 return rootdse_become_master(module, req, DREPL_PDC_MASTER);
1469         }
1470         if (ldb_msg_find_element(req->op.mod.message, "enableOptionalFeature")) {
1471                 return rootdse_enableoptionalfeature(module, req);
1472         }
1473         if (ldb_msg_find_element(req->op.mod.message, "schemaUpgradeInProgress")) {
1474                 return rootdse_schemaupgradeinprogress(module, req);
1475         }
1476
1477         ldb_set_errstring(ldb, "rootdse_modify: unknown attribute to change!");
1478         return LDB_ERR_UNWILLING_TO_PERFORM;
1479 }
1480
1481 static int rootdse_rename(struct ldb_module *module, struct ldb_request *req)
1482 {
1483         struct ldb_context *ldb = ldb_module_get_ctx(module);
1484         int ret;
1485
1486         ret = rootdse_filter_operations(module, req);
1487         if (ret != LDB_SUCCESS) {
1488                 return ret;
1489         }
1490
1491         ret = rootdse_filter_controls(module, req);
1492         if (ret != LDB_SUCCESS) {
1493                 return ret;
1494         }
1495
1496         /*
1497                 If dn is not "" we should let it pass through
1498         */
1499         if (!ldb_dn_is_null(req->op.rename.olddn)) {
1500                 return ldb_next_request(module, req);
1501         }
1502
1503         ldb_set_errstring(ldb, "rootdse_remove: you cannot rename the rootdse entry!");
1504         return LDB_ERR_NO_SUCH_OBJECT;
1505 }
1506
1507 static int rootdse_delete(struct ldb_module *module, struct ldb_request *req)
1508 {
1509         struct ldb_context *ldb = ldb_module_get_ctx(module);
1510         int ret;
1511
1512         ret = rootdse_filter_operations(module, req);
1513         if (ret != LDB_SUCCESS) {
1514                 return ret;
1515         }
1516
1517         ret = rootdse_filter_controls(module, req);
1518         if (ret != LDB_SUCCESS) {
1519                 return ret;
1520         }
1521
1522         /*
1523                 If dn is not "" we should let it pass through
1524         */
1525         if (!ldb_dn_is_null(req->op.del.dn)) {
1526                 return ldb_next_request(module, req);
1527         }
1528
1529         ldb_set_errstring(ldb, "rootdse_remove: you cannot delete the rootdse entry!");
1530         return LDB_ERR_NO_SUCH_OBJECT;
1531 }
1532
1533 static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
1534 {
1535         int ret;
1536
1537         ret = rootdse_filter_operations(module, req);
1538         if (ret != LDB_SUCCESS) {
1539                 return ret;
1540         }
1541
1542         ret = rootdse_filter_controls(module, req);
1543         if (ret != LDB_SUCCESS) {
1544                 return ret;
1545         }
1546
1547         return ldb_next_request(module, req);
1548 }
1549
1550 static const struct ldb_module_ops ldb_rootdse_module_ops = {
1551         .name           = "rootdse",
1552         .init_context   = rootdse_init,
1553         .search         = rootdse_search,
1554         .request        = rootdse_request,
1555         .add            = rootdse_add,
1556         .modify         = rootdse_modify,
1557         .rename         = rootdse_rename,
1558         .extended       = rootdse_extended,
1559         .del            = rootdse_delete
1560 };
1561
1562 int ldb_rootdse_module_init(const char *version)
1563 {
1564         LDB_MODULE_CHECK_VERSION(version);
1565         return ldb_register_module(&ldb_rootdse_module_ops);
1566 }