s4:dsdb - use the more safe "samdb_msg_add_(u)int*" calls always where possible
[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
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "lib/ldb/include/ldb.h"
25 #include "lib/ldb/include/ldb_module.h"
26 #include "system/time.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "version.h"
29 #include "dsdb/samdb/ldb_modules/util.h"
30 #include "libcli/security/security.h"
31 #include "libcli/security/session.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 };
44
45 /*
46   return 1 if a specific attribute has been requested
47 */
48 static int do_attribute(const char * const *attrs, const char *name)
49 {
50         return attrs == NULL ||
51                 ldb_attr_in_list(attrs, name) ||
52                 ldb_attr_in_list(attrs, "*");
53 }
54
55 static int do_attribute_explicit(const char * const *attrs, const char *name)
56 {
57         return attrs != NULL && ldb_attr_in_list(attrs, name);
58 }
59
60
61 /*
62   expand a DN attribute to include extended DN information if requested
63  */
64 static int expand_dn_in_message(struct ldb_module *module, struct ldb_message *msg,
65                                 const char *attrname, struct ldb_control *edn_control,
66                                 struct ldb_request *req)
67 {
68         struct ldb_dn *dn, *dn2;
69         struct ldb_val *v;
70         int ret;
71         struct ldb_request *req2;
72         char *dn_string;
73         const char *no_attrs[] = { NULL };
74         struct ldb_result *res;
75         struct ldb_extended_dn_control *edn;
76         TALLOC_CTX *tmp_ctx = talloc_new(req);
77         struct ldb_context *ldb;
78         int edn_type = 0;
79
80         ldb = ldb_module_get_ctx(module);
81
82         edn = talloc_get_type(edn_control->data, struct ldb_extended_dn_control);
83         if (edn) {
84                 edn_type = edn->type;
85         }
86
87         v = discard_const_p(struct ldb_val, ldb_msg_find_ldb_val(msg, attrname));
88         if (v == NULL) {
89                 talloc_free(tmp_ctx);
90                 return LDB_SUCCESS;
91         }
92
93         dn_string = talloc_strndup(tmp_ctx, (const char *)v->data, v->length);
94         if (dn_string == NULL) {
95                 talloc_free(tmp_ctx);
96                 return ldb_operr(ldb);
97         }
98
99         res = talloc_zero(tmp_ctx, struct ldb_result);
100         if (res == NULL) {
101                 talloc_free(tmp_ctx);
102                 return ldb_operr(ldb);
103         }
104
105         dn = ldb_dn_new(tmp_ctx, ldb, dn_string);
106         if (!ldb_dn_validate(dn)) {
107                 talloc_free(tmp_ctx);
108                 return ldb_operr(ldb);
109         }
110
111         ret = ldb_build_search_req(&req2, ldb, tmp_ctx,
112                                    dn,
113                                    LDB_SCOPE_BASE,
114                                    NULL,
115                                    no_attrs,
116                                    NULL,
117                                    res, ldb_search_default_callback,
118                                    req);
119         LDB_REQ_SET_LOCATION(req2);
120         if (ret != LDB_SUCCESS) {
121                 talloc_free(tmp_ctx);
122                 return ret;
123         }
124
125
126         ret = ldb_request_add_control(req2,
127                                       LDB_CONTROL_EXTENDED_DN_OID,
128                                       edn_control->critical, edn);
129         if (ret != LDB_SUCCESS) {
130                 talloc_free(tmp_ctx);
131                 return ret;
132         }
133
134         ret = ldb_next_request(module, req2);
135         if (ret == LDB_SUCCESS) {
136                 ret = ldb_wait(req2->handle, LDB_WAIT_ALL);
137         }
138         if (ret != LDB_SUCCESS) {
139                 talloc_free(tmp_ctx);
140                 return ret;
141         }
142
143         if (!res || res->count != 1) {
144                 talloc_free(tmp_ctx);
145                 return ldb_operr(ldb);
146         }
147
148         dn2 = res->msgs[0]->dn;
149
150         v->data = (uint8_t *)ldb_dn_get_extended_linearized(msg->elements, dn2, edn_type);
151         if (v->data == NULL) {
152                 talloc_free(tmp_ctx);
153                 return ldb_operr(ldb);
154         }
155         v->length = strlen((char *)v->data);
156
157
158         talloc_free(tmp_ctx);
159
160         return LDB_SUCCESS;
161 }
162
163
164 /*
165   add dynamically generated attributes to rootDSE result
166 */
167 static int rootdse_add_dynamic(struct ldb_module *module, struct ldb_message *msg,
168                                const char * const *attrs, struct ldb_request *req)
169 {
170         struct ldb_context *ldb;
171         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
172         char **server_sasl;
173         const struct dsdb_schema *schema;
174         int *val;
175         struct ldb_control *edn_control;
176         const char *dn_attrs[] = {
177                 "configurationNamingContext",
178                 "defaultNamingContext",
179                 "dsServiceName",
180                 "rootDomainNamingContext",
181                 "schemaNamingContext",
182                 "serverName",
183                 NULL
184         };
185
186         ldb = ldb_module_get_ctx(module);
187         schema = dsdb_get_schema(ldb, NULL);
188
189         msg->dn = ldb_dn_new(msg, ldb, NULL);
190
191         /* don't return the distinguishedName, cn and name attributes */
192         ldb_msg_remove_attr(msg, "distinguishedName");
193         ldb_msg_remove_attr(msg, "cn");
194         ldb_msg_remove_attr(msg, "name");
195
196         if (do_attribute(attrs, "serverName")) {
197                 if (ldb_msg_add_linearized_dn(msg, "serverName",
198                         samdb_server_dn(ldb, msg)) != LDB_SUCCESS) {
199                         goto failed;
200                 }
201         }
202
203         if (do_attribute(attrs, "dnsHostName")) {
204                 if (ldb_msg_add_string(msg, "dnsHostName",
205                         samdb_search_string(ldb, msg, samdb_server_dn(ldb, msg),
206                                             "dNSHostName", NULL)) != LDB_SUCCESS) {
207                         goto failed;
208                 }
209         }
210
211         if (do_attribute(attrs, "ldapServiceName")) {
212                 struct loadparm_context *lp_ctx
213                         = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
214                                           struct loadparm_context);
215                 char *ldap_service_name, *hostname;
216
217                 hostname = talloc_strdup(msg, lpcfg_netbios_name(lp_ctx));
218                 if (hostname == NULL) {
219                         goto failed;
220                 }
221                 strlower_m(hostname);
222
223                 ldap_service_name = talloc_asprintf(msg, "%s:%s$@%s",
224                                                     samdb_forest_name(ldb, msg),
225                                                     hostname, lpcfg_realm(lp_ctx));
226                 if (ldap_service_name == NULL) {
227                         goto failed;
228                 }
229
230                 if (ldb_msg_add_string(msg, "ldapServiceName",
231                                        ldap_service_name) != LDB_SUCCESS) {
232                         goto failed;
233                 }
234         }
235
236         if (do_attribute(attrs, "currentTime")) {
237                 if (ldb_msg_add_steal_string(msg, "currentTime",
238                                              ldb_timestring(msg, time(NULL))) != LDB_SUCCESS) {
239                         goto failed;
240                 }
241         }
242
243         if (priv && do_attribute(attrs, "supportedControl")) {
244                 unsigned int i;
245                 for (i = 0; i < priv->num_controls; i++) {
246                         char *control = talloc_strdup(msg, priv->controls[i]);
247                         if (!control) {
248                                 goto failed;
249                         }
250                         if (ldb_msg_add_steal_string(msg, "supportedControl",
251                                                      control) != LDB_SUCCESS) {
252                                 goto failed;
253                         }
254                 }
255         }
256
257         if (priv && do_attribute(attrs, "namingContexts")) {
258                 unsigned int i;
259                 for (i = 0; i < priv->num_partitions; i++) {
260                         struct ldb_dn *dn = priv->partitions[i];
261                         if (ldb_msg_add_steal_string(msg, "namingContexts",
262                                                      ldb_dn_alloc_linearized(msg, dn)) != LDB_SUCCESS) {
263                                 goto failed;
264                         }
265                 }
266         }
267
268         server_sasl = talloc_get_type(ldb_get_opaque(ldb, "supportedSASLMechanisms"),
269                                        char *);
270         if (server_sasl && do_attribute(attrs, "supportedSASLMechanisms")) {
271                 unsigned int i;
272                 for (i = 0; server_sasl && server_sasl[i]; i++) {
273                         char *sasl_name = talloc_strdup(msg, server_sasl[i]);
274                         if (!sasl_name) {
275                                 goto failed;
276                         }
277                         if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
278                                                      sasl_name) != LDB_SUCCESS) {
279                                 goto failed;
280                         }
281                 }
282         }
283
284         if (do_attribute(attrs, "highestCommittedUSN")) {
285                 uint64_t seq_num;
286                 int ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
287                 if (ret == LDB_SUCCESS) {
288                         if (samdb_msg_add_uint64(ldb, msg, msg,
289                                                  "highestCommittedUSN",
290                                                  seq_num) != LDB_SUCCESS) {
291                                 goto failed;
292                         }
293                 }
294         }
295
296         if (schema && do_attribute_explicit(attrs, "dsSchemaAttrCount")) {
297                 struct dsdb_attribute *cur;
298                 unsigned int n = 0;
299
300                 for (cur = schema->attributes; cur; cur = cur->next) {
301                         n++;
302                 }
303
304                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaAttrCount",
305                                        n) != LDB_SUCCESS) {
306                         goto failed;
307                 }
308         }
309
310         if (schema && do_attribute_explicit(attrs, "dsSchemaClassCount")) {
311                 struct dsdb_class *cur;
312                 unsigned int n = 0;
313
314                 for (cur = schema->classes; cur; cur = cur->next) {
315                         n++;
316                 }
317
318                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaClassCount",
319                                        n) != LDB_SUCCESS) {
320                         goto failed;
321                 }
322         }
323
324         if (schema && do_attribute_explicit(attrs, "dsSchemaPrefixCount")) {
325                 if (samdb_msg_add_uint(ldb, msg, msg, "dsSchemaPrefixCount",
326                                        schema->prefixmap->length) != LDB_SUCCESS) {
327                         goto failed;
328                 }
329         }
330
331         if (do_attribute_explicit(attrs, "validFSMOs")) {
332                 const struct dsdb_naming_fsmo *naming_fsmo;
333                 const struct dsdb_pdc_fsmo *pdc_fsmo;
334                 const char *dn_str;
335
336                 if (schema && schema->fsmo.we_are_master) {
337                         dn_str = ldb_dn_get_linearized(ldb_get_schema_basedn(ldb));
338                         if (dn_str && dn_str[0]) {
339                                 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
340                                         goto failed;
341                                 }
342                         }
343                 }
344
345                 naming_fsmo = talloc_get_type(ldb_get_opaque(ldb, "dsdb_naming_fsmo"),
346                                               struct dsdb_naming_fsmo);
347                 if (naming_fsmo && naming_fsmo->we_are_master) {
348                         dn_str = ldb_dn_get_linearized(samdb_partitions_dn(ldb, msg));
349                         if (dn_str && dn_str[0]) {
350                                 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
351                                         goto failed;
352                                 }
353                         }
354                 }
355
356                 pdc_fsmo = talloc_get_type(ldb_get_opaque(ldb, "dsdb_pdc_fsmo"),
357                                            struct dsdb_pdc_fsmo);
358                 if (pdc_fsmo && pdc_fsmo->we_are_master) {
359                         dn_str = ldb_dn_get_linearized(ldb_get_default_basedn(ldb));
360                         if (dn_str && dn_str[0]) {
361                                 if (ldb_msg_add_fmt(msg, "validFSMOs", "%s", dn_str) != LDB_SUCCESS) {
362                                         goto failed;
363                                 }
364                         }
365                 }
366         }
367
368         if (do_attribute_explicit(attrs, "vendorVersion")) {
369                 if (ldb_msg_add_fmt(msg, "vendorVersion",
370                                     "%s", SAMBA_VERSION_STRING) != LDB_SUCCESS) {
371                         goto failed;
372                 }
373         }
374
375         if (do_attribute(attrs, "domainFunctionality")) {
376                 if (samdb_msg_add_int(ldb, msg, msg, "domainFunctionality",
377                                       dsdb_functional_level(ldb)) != LDB_SUCCESS) {
378                         goto failed;
379                 }
380         }
381
382         if (do_attribute(attrs, "forestFunctionality")) {
383                 if (samdb_msg_add_int(ldb, msg, msg, "forestFunctionality",
384                                       dsdb_forest_functional_level(ldb)) != LDB_SUCCESS) {
385                         goto failed;
386                 }
387         }
388
389         if (do_attribute(attrs, "domainControllerFunctionality")
390             && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), int))) {
391                 if (samdb_msg_add_int(ldb, msg, msg,
392                                       "domainControllerFunctionality",
393                                       *val) != LDB_SUCCESS) {
394                         goto failed;
395                 }
396         }
397
398         if (do_attribute(attrs, "isGlobalCatalogReady")) {
399                 /* MS-ADTS 3.1.1.3.2.10
400                    Note, we should only return true here is we have
401                    completed at least one synchronisation. As both
402                    provision and vampire do a full sync, this means we
403                    can return true is the gc bit is set in the NTDSDSA
404                    options */
405                 if (ldb_msg_add_fmt(msg, "isGlobalCatalogReady",
406                                     "%s", samdb_is_gc(ldb)?"TRUE":"FALSE") != LDB_SUCCESS) {
407                         goto failed;
408                 }
409         }
410
411         if (do_attribute_explicit(attrs, "tokenGroups")) {
412                 unsigned int i;
413                 /* Obtain the user's session_info */
414                 struct auth_session_info *session_info
415                         = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
416                 if (session_info && session_info->security_token) {
417                         /* The list of groups this user is in */
418                         for (i = 0; i < session_info->security_token->num_sids; i++) {
419                                 if (samdb_msg_add_dom_sid(ldb, msg, msg,
420                                                           "tokenGroups",
421                                                           &session_info->security_token->sids[i]) != LDB_SUCCESS) {
422                                         goto failed;
423                                 }
424                         }
425                 }
426         }
427
428         /* TODO: lots more dynamic attributes should be added here */
429
430         edn_control = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID);
431
432         /* if the client sent us the EXTENDED_DN control then we need
433            to expand the DNs to have GUID and SID. W2K8 join relies on
434            this */
435         if (edn_control) {
436                 unsigned int i;
437                 int ret;
438                 for (i=0; dn_attrs[i]; i++) {
439                         if (!do_attribute(attrs, dn_attrs[i])) continue;
440                         ret = expand_dn_in_message(module, msg, dn_attrs[i],
441                                                    edn_control, req);
442                         if (ret != LDB_SUCCESS) {
443                                 DEBUG(0,(__location__ ": Failed to expand DN in rootDSE for %s\n",
444                                          dn_attrs[i]));
445                                 goto failed;
446                         }
447                 }
448         }
449
450         return LDB_SUCCESS;
451
452 failed:
453         return ldb_operr(ldb);
454 }
455
456 /*
457   handle search requests
458 */
459
460 struct rootdse_context {
461         struct ldb_module *module;
462         struct ldb_request *req;
463 };
464
465 static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
466                                                     struct ldb_request *req)
467 {
468         struct ldb_context *ldb;
469         struct rootdse_context *ac;
470
471         ldb = ldb_module_get_ctx(module);
472
473         ac = talloc_zero(req, struct rootdse_context);
474         if (ac == NULL) {
475                 ldb_set_errstring(ldb, "Out of Memory");
476                 return NULL;
477         }
478
479         ac->module = module;
480         ac->req = req;
481
482         return ac;
483 }
484
485 static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
486 {
487         struct rootdse_context *ac;
488         int ret;
489
490         ac = talloc_get_type(req->context, struct rootdse_context);
491
492         if (!ares) {
493                 return ldb_module_done(ac->req, NULL, NULL,
494                                         LDB_ERR_OPERATIONS_ERROR);
495         }
496         if (ares->error != LDB_SUCCESS) {
497                 return ldb_module_done(ac->req, ares->controls,
498                                         ares->response, ares->error);
499         }
500
501         switch (ares->type) {
502         case LDB_REPLY_ENTRY:
503                 /*
504                  * if the client explicit asks for the 'netlogon' attribute
505                  * the reply_entry needs to be skipped
506                  */
507                 if (ac->req->op.search.attrs &&
508                     ldb_attr_in_list(ac->req->op.search.attrs, "netlogon")) {
509                         talloc_free(ares);
510                         return LDB_SUCCESS;
511                 }
512
513                 /* for each record returned post-process to add any dynamic
514                    attributes that have been asked for */
515                 ret = rootdse_add_dynamic(ac->module, ares->message,
516                                           ac->req->op.search.attrs, ac->req);
517                 if (ret != LDB_SUCCESS) {
518                         talloc_free(ares);
519                         return ldb_module_done(ac->req, NULL, NULL, ret);
520                 }
521
522                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
523
524         case LDB_REPLY_REFERRAL:
525                 /* should we allow the backend to return referrals in this case
526                  * ?? */
527                 break;
528
529         case LDB_REPLY_DONE:
530                 return ldb_module_done(ac->req, ares->controls,
531                                         ares->response, ares->error);
532         }
533
534         talloc_free(ares);
535         return LDB_SUCCESS;
536 }
537
538 /*
539   filter from controls from clients in several ways
540
541   1) mark our registered controls as non-critical in the request
542
543     This is needed as clients may mark controls as critical even if
544     they are not needed at all in a request. For example, the centrify
545     client sets the SD_FLAGS control as critical on ldap modify
546     requests which are setting the dNSHostName attribute on the
547     machine account. That request doesn't need SD_FLAGS at all, but
548     centrify adds it on all ldap requests.
549
550   2) if this request is untrusted then remove any non-registered
551      controls that are non-critical
552
553     This is used on ldap:// connections to prevent remote users from
554     setting an internal control that may be dangerous
555
556   3) if this request is untrusted then fail any request that includes
557      a critical non-registered control
558  */
559 static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
560 {
561         unsigned int i, j;
562         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
563         bool is_untrusted;
564
565         if (!req->controls) {
566                 return LDB_SUCCESS;
567         }
568
569         is_untrusted = ldb_req_is_untrusted(req);
570
571         for (i=0; req->controls[i]; i++) {
572                 bool is_registered = false;
573                 bool is_critical = (req->controls[i]->critical != 0);
574
575                 if (req->controls[i]->oid == NULL) {
576                         continue;
577                 }
578
579                 if (is_untrusted || is_critical) {
580                         for (j=0; j<priv->num_controls; j++) {
581                                 if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
582                                         is_registered = true;
583                                         break;
584                                 }
585                         }
586                 }
587
588                 if (is_untrusted && !is_registered) {
589                         if (!is_critical) {
590                                 /* remove it by marking the oid NULL */
591                                 req->controls[i]->oid = NULL;
592                                 req->controls[i]->data = NULL;
593                                 req->controls[i]->critical = 0;
594                                 continue;
595                         }
596                         /* its a critical unregistered control - give
597                            an error */
598                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
599                                                "Attempt to use critical non-registered control '%s'",
600                                                req->controls[i]->oid);
601                         return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
602                 }
603
604                 if (!is_critical) {
605                         continue;
606                 }
607
608                 if (is_registered) {
609                         req->controls[i]->critical = 0;
610                 }
611         }
612
613         return LDB_SUCCESS;
614 }
615
616
617 static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
618 {
619         struct ldb_context *ldb;
620         struct rootdse_context *ac;
621         struct ldb_request *down_req;
622         int ret;
623
624         ret = rootdse_filter_controls(module, req);
625         if (ret != LDB_SUCCESS) {
626                 return ret;
627         }
628
629         ldb = ldb_module_get_ctx(module);
630
631         /* see if its for the rootDSE - only a base search on the "" DN qualifies */
632         if (!(req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base))) {
633                 /* Otherwise, pass down to the rest of the stack */
634                 return ldb_next_request(module, req);
635         }
636
637         ac = rootdse_init_context(module, req);
638         if (ac == NULL) {
639                 return ldb_operr(ldb);
640         }
641
642         /* in our db we store the rootDSE with a DN of @ROOTDSE */
643         ret = ldb_build_search_req(&down_req, ldb, ac,
644                                         ldb_dn_new(ac, ldb, "@ROOTDSE"),
645                                         LDB_SCOPE_BASE,
646                                         NULL,
647                                         req->op.search.attrs,
648                                         NULL,/* for now skip the controls from the client */
649                                         ac, rootdse_callback,
650                                         req);
651         LDB_REQ_SET_LOCATION(down_req);
652         if (ret != LDB_SUCCESS) {
653                 return ret;
654         }
655
656         return ldb_next_request(module, down_req);
657 }
658
659 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
660 {
661         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
662         char **list;
663
664         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
665         if (!list) {
666                 return ldb_oom(ldb_module_get_ctx(module));
667         }
668
669         list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid);
670         if (!list[priv->num_controls]) {
671                 return ldb_oom(ldb_module_get_ctx(module));
672         }
673
674         priv->num_controls += 1;
675         priv->controls = list;
676
677         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
678 }
679
680 static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
681 {
682         struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
683         struct ldb_dn **list;
684
685         list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
686         if (!list) {
687                 return ldb_oom(ldb_module_get_ctx(module));
688         }
689
690         list[priv->num_partitions] = ldb_dn_copy(list, req->op.reg_partition.dn);
691         if (!list[priv->num_partitions]) {
692                 return ldb_operr(ldb_module_get_ctx(module));
693         }
694
695         priv->num_partitions += 1;
696         priv->partitions = list;
697
698         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
699 }
700
701
702 static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
703 {
704         switch (req->operation) {
705
706         case LDB_REQ_REGISTER_CONTROL:
707                 return rootdse_register_control(module, req);
708         case LDB_REQ_REGISTER_PARTITION:
709                 return rootdse_register_partition(module, req);
710
711         default:
712                 break;
713         }
714         return ldb_next_request(module, req);
715 }
716
717 static int rootdse_init(struct ldb_module *module)
718 {
719         int ret;
720         struct ldb_context *ldb;
721         struct ldb_result *res;
722         struct private_data *data;
723         const char *attrs[] = { "msDS-Behavior-Version", NULL };
724         const char *ds_attrs[] = { "dsServiceName", NULL };
725         TALLOC_CTX *mem_ctx;
726
727         ldb = ldb_module_get_ctx(module);
728
729         data = talloc_zero(module, struct private_data);
730         if (data == NULL) {
731                 return ldb_oom(ldb);
732         }
733
734         data->num_controls = 0;
735         data->controls = NULL;
736         data->num_partitions = 0;
737         data->partitions = NULL;
738         ldb_module_set_private(module, data);
739
740         ldb_set_default_dns(ldb);
741
742         ret = ldb_next_init(module);
743
744         if (ret != LDB_SUCCESS) {
745                 return ret;
746         }
747
748         mem_ctx = talloc_new(data);
749         if (!mem_ctx) {
750                 return ldb_oom(ldb);
751         }
752
753         /* Now that the partitions are set up, do a search for:
754            - domainControllerFunctionality
755            - domainFunctionality
756            - forestFunctionality
757
758            Then stuff these values into an opaque
759         */
760         ret = ldb_search(ldb, mem_ctx, &res,
761                          ldb_get_default_basedn(ldb),
762                          LDB_SCOPE_BASE, attrs, NULL);
763         if (ret == LDB_SUCCESS && res->count == 1) {
764                 int domain_behaviour_version
765                         = ldb_msg_find_attr_as_int(res->msgs[0],
766                                                    "msDS-Behavior-Version", -1);
767                 if (domain_behaviour_version != -1) {
768                         int *val = talloc(ldb, int);
769                         if (!val) {
770                                 talloc_free(mem_ctx);
771                                 return ldb_oom(ldb);
772                         }
773                         *val = domain_behaviour_version;
774                         ret = ldb_set_opaque(ldb, "domainFunctionality", val);
775                         if (ret != LDB_SUCCESS) {
776                                 talloc_free(mem_ctx);
777                                 return ret;
778                         }
779                 }
780         }
781
782         ret = ldb_search(ldb, mem_ctx, &res,
783                          samdb_partitions_dn(ldb, mem_ctx),
784                          LDB_SCOPE_BASE, attrs, NULL);
785         if (ret == LDB_SUCCESS && res->count == 1) {
786                 int forest_behaviour_version
787                         = ldb_msg_find_attr_as_int(res->msgs[0],
788                                                    "msDS-Behavior-Version", -1);
789                 if (forest_behaviour_version != -1) {
790                         int *val = talloc(ldb, int);
791                         if (!val) {
792                                 talloc_free(mem_ctx);
793                                 return ldb_oom(ldb);
794                         }
795                         *val = forest_behaviour_version;
796                         ret = ldb_set_opaque(ldb, "forestFunctionality", val);
797                         if (ret != LDB_SUCCESS) {
798                                 talloc_free(mem_ctx);
799                                 return ret;
800                         }
801                 }
802         }
803
804         ret = ldb_search(ldb, mem_ctx, &res,
805                          ldb_dn_new(mem_ctx, ldb, ""),
806                          LDB_SCOPE_BASE, ds_attrs, NULL);
807         if (ret == LDB_SUCCESS && res->count == 1) {
808                 struct ldb_dn *ds_dn
809                         = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0],
810                                                   "dsServiceName");
811                 if (ds_dn) {
812                         ret = ldb_search(ldb, mem_ctx, &res, ds_dn,
813                                          LDB_SCOPE_BASE, attrs, NULL);
814                         if (ret == LDB_SUCCESS && res->count == 1) {
815                                 int domain_controller_behaviour_version
816                                         = ldb_msg_find_attr_as_int(res->msgs[0],
817                                                                    "msDS-Behavior-Version", -1);
818                                 if (domain_controller_behaviour_version != -1) {
819                                         int *val = talloc(ldb, int);
820                                         if (!val) {
821                                                 talloc_free(mem_ctx);
822                                                 return ldb_oom(ldb);
823                                         }
824                                         *val = domain_controller_behaviour_version;
825                                         ret = ldb_set_opaque(ldb,
826                                                              "domainControllerFunctionality", val);
827                                         if (ret != LDB_SUCCESS) {
828                                                 talloc_free(mem_ctx);
829                                                 return ret;
830                                         }
831                                 }
832                         }
833                 }
834         }
835
836         talloc_free(mem_ctx);
837
838         return LDB_SUCCESS;
839 }
840
841 /*
842  * This function gets the string SCOPE_DN:OPTIONAL_FEATURE_GUID and parse it
843  * to a DN and a GUID object
844  */
845 static int get_optional_feature_dn_guid(struct ldb_request *req, struct ldb_context *ldb,
846                                                 TALLOC_CTX *mem_ctx,
847                                                 struct ldb_dn **op_feature_scope_dn,
848                                                 struct GUID *op_feature_guid)
849 {
850         const struct ldb_message *msg = req->op.mod.message;
851         const char *ldb_val_str;
852         char *dn, *guid;
853         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
854         NTSTATUS status;
855
856         ldb_val_str = ldb_msg_find_attr_as_string(msg, "enableOptionalFeature", NULL);
857         if (!ldb_val_str) {
858                 ldb_set_errstring(ldb,
859                                   "rootdse: unable to find 'enableOptionalFeature'!");
860                 return LDB_ERR_UNWILLING_TO_PERFORM;
861         }
862
863         guid = strchr(ldb_val_str, ':');
864         if (!guid) {
865                 ldb_set_errstring(ldb,
866                                   "rootdse: unable to find GUID in 'enableOptionalFeature'!");
867                 return LDB_ERR_UNWILLING_TO_PERFORM;
868         }
869         status = GUID_from_string(guid+1, op_feature_guid);
870         if (!NT_STATUS_IS_OK(status)) {
871                 ldb_set_errstring(ldb,
872                                   "rootdse: bad GUID in 'enableOptionalFeature'!");
873                 return LDB_ERR_UNWILLING_TO_PERFORM;
874         }
875
876         dn = talloc_strndup(tmp_ctx, ldb_val_str, guid-ldb_val_str);
877         if (!dn) {
878                 ldb_set_errstring(ldb,
879                                   "rootdse: bad DN in 'enableOptionalFeature'!");
880                 return LDB_ERR_UNWILLING_TO_PERFORM;
881         }
882
883         *op_feature_scope_dn = ldb_dn_new(mem_ctx, ldb, dn);
884
885         talloc_free(tmp_ctx);
886         return LDB_SUCCESS;
887 }
888
889 /*
890  * This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
891  * ldb_message object.
892  */
893 static int dsdb_find_optional_feature(struct ldb_module *module, struct ldb_context *ldb,
894                                 TALLOC_CTX *mem_ctx, struct GUID op_feature_guid, struct ldb_message **msg)
895 {
896         struct ldb_result *res;
897         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
898         int ret;
899
900         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
901                                 NULL,
902                                 DSDB_FLAG_NEXT_MODULE |
903                                 DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
904                                  "(&(objectClass=msDS-OptionalFeature)"
905                                  "(msDS-OptionalFeatureGUID=%s))",GUID_string(tmp_ctx, &op_feature_guid));
906
907         if (ret != LDB_SUCCESS) {
908                 talloc_free(tmp_ctx);
909                 return ret;
910         }
911         if (res->count == 0) {
912                 talloc_free(tmp_ctx);
913                 return LDB_ERR_NO_SUCH_OBJECT;
914         }
915         if (res->count != 1) {
916                 ldb_asprintf_errstring(ldb,
917                                        "More than one object found matching optional feature GUID %s\n",
918                                        GUID_string(tmp_ctx, &op_feature_guid));
919                 talloc_free(tmp_ctx);
920                 return LDB_ERR_OPERATIONS_ERROR;
921         }
922
923         *msg = talloc_steal(mem_ctx, res->msgs[0]);
924
925         talloc_free(tmp_ctx);
926         return LDB_SUCCESS;
927 }
928
929 static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_context *ldb,
930                         TALLOC_CTX *mem_ctx, struct ldb_dn *op_feature_scope_dn,
931                         struct ldb_message *op_feature_msg)
932 {
933         int ret;
934         const int domain_func_level = dsdb_functional_level(ldb);
935         struct ldb_dn *ntds_settings_dn;
936         TALLOC_CTX *tmp_ctx;
937         unsigned int el_count = 0;
938         struct ldb_message *msg;
939
940         ret = ldb_msg_find_attr_as_int(op_feature_msg, "msDS-RequiredForestBehaviorVersion", 0);
941         if (domain_func_level < ret){
942                 ldb_asprintf_errstring(ldb,
943                                        "rootdse_enable_recycle_bin: Domain functional level must be at least %d\n",
944                                        ret);
945                 return LDB_ERR_UNWILLING_TO_PERFORM;
946         }
947
948         tmp_ctx = talloc_new(mem_ctx);
949         ntds_settings_dn = samdb_ntds_settings_dn(ldb);
950         if (!ntds_settings_dn) {
951                 DEBUG(0, (__location__ ": Failed to find NTDS settings DN\n"));
952                 ret = LDB_ERR_OPERATIONS_ERROR;
953                 talloc_free(tmp_ctx);
954                 return ret;
955         }
956
957         ntds_settings_dn = ldb_dn_copy(tmp_ctx, ntds_settings_dn);
958         if (!ntds_settings_dn) {
959                 DEBUG(0, (__location__ ": Failed to copy NTDS settings DN\n"));
960                 ret = LDB_ERR_OPERATIONS_ERROR;
961                 talloc_free(tmp_ctx);
962                 return ret;
963         }
964
965         msg = ldb_msg_new(tmp_ctx);
966         msg->dn = ntds_settings_dn;
967
968         ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
969         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
970
971         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
972         if (ret != LDB_SUCCESS) {
973                 ldb_asprintf_errstring(ldb,
974                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
975                                        ldb_dn_get_linearized(ntds_settings_dn),
976                                        ldb_errstring(ldb));
977                 talloc_free(tmp_ctx);
978                 return ret;
979         }
980
981         msg->dn = op_feature_scope_dn;
982         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
983         if (ret != LDB_SUCCESS) {
984                 ldb_asprintf_errstring(ldb,
985                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
986                                        ldb_dn_get_linearized(op_feature_scope_dn),
987                                        ldb_errstring(ldb));
988                 talloc_free(tmp_ctx);
989                 return ret;
990         }
991
992         return LDB_SUCCESS;
993 }
994
995 static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_request *req)
996 {
997         /*
998           steps:
999                - check for system (only system can enable features)
1000                - extract GUID from the request
1001                - find the feature object
1002                - check functional level, must be at least msDS-RequiredForestBehaviorVersion
1003                - check if it is already enabled (if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS) - probably not needed, just return error from the add/modify
1004                - add/modify objects (see ntdsconnection code for an example)
1005          */
1006
1007         struct ldb_context *ldb = ldb_module_get_ctx(module);
1008         struct GUID op_feature_guid;
1009         struct ldb_dn *op_feature_scope_dn;
1010         struct ldb_message *op_feature_msg;
1011         struct auth_session_info *session_info =
1012                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
1013         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
1014         int ret;
1015         const char *guid_string;
1016
1017         if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
1018                 ldb_set_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature");
1019                 return LDB_ERR_UNWILLING_TO_PERFORM;
1020         }
1021
1022         ret = get_optional_feature_dn_guid(req, ldb, tmp_ctx, &op_feature_scope_dn, &op_feature_guid);
1023         if (ret != LDB_SUCCESS) {
1024                 talloc_free(tmp_ctx);
1025                 return ret;
1026         }
1027
1028         guid_string = GUID_string(tmp_ctx, &op_feature_guid);
1029         if (!guid_string) {
1030                 ldb_set_errstring(ldb, "rootdse: bad optional feature GUID");
1031                 return LDB_ERR_UNWILLING_TO_PERFORM;
1032         }
1033
1034         ret = dsdb_find_optional_feature(module, ldb, tmp_ctx, op_feature_guid, &op_feature_msg);
1035         if (ret != LDB_SUCCESS) {
1036                 ldb_asprintf_errstring(ldb,
1037                                        "rootdse: unable to find optional feature for %s - %s",
1038                                        guid_string, ldb_errstring(ldb));
1039                 talloc_free(tmp_ctx);
1040                 return ret;
1041         }
1042
1043         if (strcasecmp(DS_GUID_FEATURE_RECYCLE_BIN, guid_string) == 0) {
1044                         ret = rootdse_enable_recycle_bin(module, ldb,
1045                                                          tmp_ctx, op_feature_scope_dn,
1046                                                          op_feature_msg);
1047         } else {
1048                 ldb_asprintf_errstring(ldb,
1049                                        "rootdse: unknown optional feature %s",
1050                                        guid_string);
1051                 talloc_free(tmp_ctx);
1052                 return LDB_ERR_UNWILLING_TO_PERFORM;
1053         }
1054         if (ret != LDB_SUCCESS) {
1055                 ldb_asprintf_errstring(ldb,
1056                                        "rootdse: failed to set optional feature for %s - %s",
1057                                        guid_string, ldb_errstring(ldb));
1058                 talloc_free(tmp_ctx);
1059                 return ret;
1060         }
1061
1062         talloc_free(tmp_ctx);
1063         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);;
1064 }
1065
1066 static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request *req)
1067 {
1068         struct ldb_context *ldb = ldb_module_get_ctx(module);
1069         struct ldb_result *ext_res;
1070         int ret;
1071         struct ldb_dn *schema_dn;
1072
1073         schema_dn = ldb_get_schema_basedn(ldb);
1074         if (!schema_dn) {
1075                 ldb_reset_err_string(ldb);
1076                 ldb_debug(ldb, LDB_DEBUG_WARNING,
1077                           "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
1078                 return ldb_next_request(module, req);
1079         }
1080
1081         ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
1082         if (ret != LDB_SUCCESS) {
1083                 return ldb_operr(ldb);
1084         }
1085
1086         talloc_free(ext_res);
1087         return ldb_module_done(req, NULL, NULL, ret);
1088 }
1089
1090 static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
1091 {
1092         struct ldb_context *ldb = ldb_module_get_ctx(module);
1093         int ret;
1094
1095         ret = rootdse_filter_controls(module, req);
1096         if (ret != LDB_SUCCESS) {
1097                 return ret;
1098         }
1099
1100         /*
1101                 If dn is not "" we should let it pass through
1102         */
1103         if (!ldb_dn_is_null(req->op.add.message->dn)) {
1104                 return ldb_next_request(module, req);
1105         }
1106
1107         ldb_set_errstring(ldb, "rootdse_add: you cannot add a new rootdse entry!");
1108         return LDB_ERR_NAMING_VIOLATION;
1109 }
1110
1111 static int rootdse_become_master(struct ldb_module *module,
1112                                  struct ldb_request *req,
1113                                  uint32_t role)
1114 {
1115         struct drepl_takeFSMORole r;
1116         struct messaging_context *msg;
1117         struct ldb_context *ldb = ldb_module_get_ctx(module);
1118         TALLOC_CTX *tmp_ctx = talloc_new(req);
1119         struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
1120         NTSTATUS status_call;
1121         WERROR status_fn;
1122         bool am_rodc;
1123         struct dcerpc_binding_handle *irpc_handle;
1124         int ret;
1125
1126         ret = samdb_rodc(ldb, &am_rodc);
1127         if (ret != LDB_SUCCESS) {
1128                 return ldb_error(ldb, ret, "Could not determine if server is RODC.");
1129         }
1130
1131         if (am_rodc) {
1132                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1133                                  "RODC cannot become a role master.");
1134         }
1135
1136         msg = messaging_client_init(tmp_ctx, lpcfg_messaging_path(tmp_ctx, lp_ctx),
1137                                     ldb_get_event_context(ldb));
1138         if (!msg) {
1139                 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s", lpcfg_messaging_path(tmp_ctx, lp_ctx));
1140                 return LDB_ERR_OPERATIONS_ERROR;
1141         }
1142         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg,
1143                                                   "dreplsrv",
1144                                                   &ndr_table_irpc);
1145         if (irpc_handle == NULL) {
1146                 return ldb_oom(ldb);
1147         }
1148         r.in.role = role;
1149
1150         status_call = dcerpc_drepl_takeFSMORole_r(irpc_handle, tmp_ctx, &r);
1151         if (!NT_STATUS_IS_OK(status_call)) {
1152                 return LDB_ERR_OPERATIONS_ERROR;
1153         }
1154         status_fn = r.out.result;
1155         if (!W_ERROR_IS_OK(status_fn)) {
1156                 return LDB_ERR_OPERATIONS_ERROR;
1157         }
1158         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
1159 }
1160
1161 static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
1162 {
1163         struct ldb_context *ldb = ldb_module_get_ctx(module);
1164         int ret;
1165
1166         ret = rootdse_filter_controls(module, req);
1167         if (ret != LDB_SUCCESS) {
1168                 return ret;
1169         }
1170
1171         /*
1172                 If dn is not "" we should let it pass through
1173         */
1174         if (!ldb_dn_is_null(req->op.mod.message->dn)) {
1175                 return ldb_next_request(module, req);
1176         }
1177
1178         /*
1179                 dn is empty so check for schemaUpdateNow attribute
1180                 "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
1181         */
1182         if (ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow")) {
1183                 return rootdse_schemaupdatenow(module, req);
1184         }
1185         if (ldb_msg_find_element(req->op.mod.message, "becomeDomainMaster")) {
1186                 return rootdse_become_master(module, req, DREPL_NAMING_MASTER);
1187         }
1188         if (ldb_msg_find_element(req->op.mod.message, "becomeInfrastructureMaster")) {
1189                 return rootdse_become_master(module, req, DREPL_INFRASTRUCTURE_MASTER);
1190         }
1191         if (ldb_msg_find_element(req->op.mod.message, "becomeRidMaster")) {
1192                 return rootdse_become_master(module, req, DREPL_RID_MASTER);
1193         }
1194         if (ldb_msg_find_element(req->op.mod.message, "becomeSchemaMaster")) {
1195                 return rootdse_become_master(module, req, DREPL_SCHEMA_MASTER);
1196         }
1197         if (ldb_msg_find_element(req->op.mod.message, "becomePdc")) {
1198                 return rootdse_become_master(module, req, DREPL_PDC_MASTER);
1199         }
1200         if (ldb_msg_find_element(req->op.mod.message, "enableOptionalFeature")) {
1201                 return rootdse_enableoptionalfeature(module, req);
1202         }
1203
1204         ldb_set_errstring(ldb, "rootdse_modify: unknown attribute to change!");
1205         return LDB_ERR_UNWILLING_TO_PERFORM;
1206 }
1207
1208 static int rootdse_delete(struct ldb_module *module, struct ldb_request *req)
1209 {
1210         struct ldb_context *ldb = ldb_module_get_ctx(module);
1211         int ret;
1212
1213         ret = rootdse_filter_controls(module, req);
1214         if (ret != LDB_SUCCESS) {
1215                 return ret;
1216         }
1217
1218         /*
1219                 If dn is not "" we should let it pass through
1220         */
1221         if (!ldb_dn_is_null(req->op.del.dn)) {
1222                 return ldb_next_request(module, req);
1223         }
1224
1225         ldb_set_errstring(ldb, "rootdse_remove: you cannot delete the rootdse entry!");
1226         return LDB_ERR_NO_SUCH_OBJECT;
1227 }
1228
1229 _PUBLIC_ const struct ldb_module_ops ldb_rootdse_module_ops = {
1230         .name           = "rootdse",
1231         .init_context   = rootdse_init,
1232         .search         = rootdse_search,
1233         .request        = rootdse_request,
1234         .add            = rootdse_add,
1235         .modify         = rootdse_modify,
1236         .del            = rootdse_delete
1237 };