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