LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - rootdse.c (source / functions) Hit Total Coverage
Test: coverage report for douglas-v4-17-lts-2026-07-29 28d1e15b Lines: 527 816 64.6 %
Date: 2026-07-29 02:26:30 Functions: 28 33 84.8 %

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

Generated by: LCOV version 1.13