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