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

Generated by: LCOV version 1.14