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 2f515e9b Lines: 554 878 63.1 %
Date: 2024-04-21 15:09:00 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    11028897 : static int do_attribute(const char * const *attrs, const char *name)
      63             : {
      64    11027176 :         return attrs == NULL ||
      65    22050719 :                 ldb_attr_in_list(attrs, name) ||
      66    10560203 :                 ldb_attr_in_list(attrs, "*");
      67             : }
      68             : 
      69     6172764 : static int do_attribute_explicit(const char * const *attrs, const char *name)
      70             : {
      71     6172740 :         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      890139 : static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg)
     231             : {
     232       17750 :         struct ldb_context *ldb;
     233      890139 :         struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct rootdse_private_data);
     234      890139 :         const char * const *attrs = ac->req->op.search.attrs;
     235      890139 :         const char **server_sasl = NULL;
     236       17750 :         const struct dsdb_schema *schema;
     237       17750 :         unsigned long long *val;
     238       17750 :         struct ldb_control *edn_control;
     239      890139 :         const char *dn_attrs[] = {
     240             :                 "configurationNamingContext",
     241             :                 "defaultNamingContext",
     242             :                 "rootDomainNamingContext",
     243             :                 "schemaNamingContext",
     244             :                 "serverName",
     245             :                 "validFSMOs",
     246             :                 "namingContexts",
     247             :                 NULL
     248             :         };
     249      890139 :         const char *guid_attrs[] = {
     250             :                 "dsServiceName",
     251             :                 NULL
     252             :         };
     253       17750 :         unsigned int i;
     254             : 
     255      890139 :         ldb = ldb_module_get_ctx(ac->module);
     256      890139 :         schema = dsdb_get_schema(ldb, NULL);
     257             : 
     258      890139 :         msg->dn = ldb_dn_new(msg, ldb, NULL);
     259             : 
     260             :         /* don't return the distinguishedName, cn and name attributes */
     261      890139 :         ldb_msg_remove_attr(msg, "distinguishedName");
     262      890139 :         ldb_msg_remove_attr(msg, "cn");
     263      890139 :         ldb_msg_remove_attr(msg, "name");
     264             : 
     265      890139 :         if (do_attribute(attrs, "serverName")) {
     266        1982 :                 if (ldb_msg_add_linearized_dn(msg, "serverName",
     267             :                         samdb_server_dn(ldb, msg)) != LDB_SUCCESS) {
     268           0 :                         goto failed;
     269             :                 }
     270             :         }
     271             : 
     272      890139 :         if (do_attribute(attrs, "dnsHostName")) {
     273          12 :                 struct ldb_result *res;
     274          12 :                 int ret;
     275        2124 :                 const char *dns_attrs[] = { "dNSHostName", NULL };
     276        2124 :                 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        2124 :                 if (ret == LDB_SUCCESS) {
     282        2124 :                         const char *hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
     283        2124 :                         if (hostname != NULL) {
     284        2124 :                                 if (ldb_msg_add_string(msg, "dnsHostName", hostname)) {
     285           0 :                                         goto failed;
     286             :                                 }
     287             :                         }
     288             :                 }
     289             :         }
     290             : 
     291      890139 :         if (do_attribute(attrs, "ldapServiceName")) {
     292           6 :                 struct loadparm_context *lp_ctx
     293         852 :                         = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
     294             :                                           struct loadparm_context);
     295           6 :                 char *ldap_service_name, *hostname;
     296             : 
     297         852 :                 hostname = strlower_talloc(msg, lpcfg_netbios_name(lp_ctx));
     298         852 :                 if (hostname == NULL) {
     299           0 :                         goto failed;
     300             :                 }
     301             : 
     302         852 :                 ldap_service_name = talloc_asprintf(msg, "%s:%s$@%s",
     303             :                                                     samdb_forest_name(ldb, msg),
     304             :                                                     hostname, lpcfg_realm(lp_ctx));
     305         852 :                 if (ldap_service_name == NULL) {
     306           0 :                         goto failed;
     307             :                 }
     308             : 
     309         852 :                 if (ldb_msg_add_string(msg, "ldapServiceName",
     310             :                                        ldap_service_name) != LDB_SUCCESS) {
     311           0 :                         goto failed;
     312             :                 }
     313             :         }
     314             : 
     315      890139 :         if (do_attribute(attrs, "currentTime")) {
     316        1327 :                 char *timestr = ldb_timestring(msg, time(NULL));
     317             : 
     318        1327 :                 if (timestr == NULL) {
     319           0 :                         goto failed;
     320             :                 }
     321             : 
     322        1327 :                 if (ldb_msg_add_steal_string(
     323             :                             msg, "currentTime", timestr) != LDB_SUCCESS) {
     324           0 :                         goto failed;
     325             :                 }
     326             :         }
     327             : 
     328      890139 :         if (priv && do_attribute(attrs, "supportedControl")) {
     329       66964 :                 for (i = 0; i < priv->num_controls; i++) {
     330       64149 :                         char *control = talloc_strdup(msg, priv->controls[i]);
     331       64149 :                         if (!control) {
     332           0 :                                 goto failed;
     333             :                         }
     334       64149 :                         if (ldb_msg_add_steal_string(msg, "supportedControl",
     335             :                                                      control) != LDB_SUCCESS) {
     336           0 :                                 goto failed;
     337             :                         }
     338             :                 }
     339             :         }
     340             : 
     341      890139 :         if (priv && do_attribute(attrs, "namingContexts")) {
     342       14185 :                 for (i = 0; i < priv->num_partitions; i++) {
     343       11266 :                         struct ldb_dn *dn = priv->partitions[i];
     344       11266 :                         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      890139 :         server_sasl = talloc_get_type(ldb_get_opaque(ldb, "supportedSASLMechanisms"),
     352             :                                        const char *);
     353      890139 :         if (server_sasl && do_attribute(attrs, "supportedSASLMechanisms")) {
     354      109360 :                 for (i = 0; server_sasl && server_sasl[i]; i++) {
     355       82020 :                         char *sasl_name = talloc_strdup(msg, server_sasl[i]);
     356       82020 :                         if (!sasl_name) {
     357           0 :                                 goto failed;
     358             :                         }
     359       82020 :                         if (ldb_msg_add_steal_string(msg, "supportedSASLMechanisms",
     360             :                                                      sasl_name) != LDB_SUCCESS) {
     361           0 :                                 goto failed;
     362             :                         }
     363             :                 }
     364             :         }
     365             : 
     366      890139 :         if (do_attribute(attrs, "highestCommittedUSN")) {
     367           6 :                 uint64_t seq_num;
     368        1367 :                 int ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ, &seq_num);
     369        1367 :                 if (ret == LDB_SUCCESS) {
     370        1367 :                         if (samdb_msg_add_uint64(ldb, msg, msg,
     371             :                                                  "highestCommittedUSN",
     372             :                                                  seq_num) != LDB_SUCCESS) {
     373           0 :                                 goto failed;
     374             :                         }
     375             :                 }
     376             :         }
     377             : 
     378      890139 :         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      890139 :         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      890139 :         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      890139 :         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      890139 :         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      890139 :         if (do_attribute(attrs, "domainFunctionality")) {
     441        1072 :                 if (samdb_msg_add_int(ldb, msg, msg, "domainFunctionality",
     442             :                                       dsdb_functional_level(ldb)) != LDB_SUCCESS) {
     443           0 :                         goto failed;
     444             :                 }
     445             :         }
     446             : 
     447      890139 :         if (do_attribute(attrs, "forestFunctionality")) {
     448         879 :                 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      890139 :         if (do_attribute(attrs, "domainControllerFunctionality")
     455        1306 :             && (val = talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), unsigned long long))) {
     456        1297 :                 if (samdb_msg_add_int(ldb, msg, msg,
     457             :                                       "domainControllerFunctionality",
     458        1297 :                                       *val) != LDB_SUCCESS) {
     459           0 :                         goto failed;
     460             :                 }
     461             :         }
     462             : 
     463      890139 :         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         851 :                 if (ldb_msg_add_fmt(msg, "isGlobalCatalogReady",
     471         851 :                                     "%s", samdb_is_gc(ldb)?"TRUE":"FALSE") != LDB_SUCCESS) {
     472           0 :                         goto failed;
     473             :                 }
     474             :         }
     475             : 
     476      890139 :         if (do_attribute_explicit(attrs, "tokenGroups")) {
     477             :                 /* Obtain the user's session_info */
     478          13 :                 struct auth_session_info *session_info
     479         553 :                         = (struct auth_session_info *)ldb_get_opaque(
     480             :                                 ldb,
     481             :                                 DSDB_SESSION_INFO);
     482         553 :                 if (session_info && session_info->security_token) {
     483             :                         /* The list of groups this user is in */
     484        3375 :                         for (i = 0; i < session_info->security_token->num_sids; i++) {
     485        2822 :                                 if (samdb_msg_add_dom_sid(ldb, msg, msg,
     486             :                                                           "tokenGroups",
     487        2822 :                                                           &session_info->security_token->sids[i]) != LDB_SUCCESS) {
     488           0 :                                         goto failed;
     489             :                                 }
     490             :                         }
     491             :                 }
     492             :         }
     493             : 
     494      890139 :         if (ac->netlogon.length > 0) {
     495        2948 :                 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      890139 :         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     1798009 :         for (i=0; guid_attrs[i]; i++) {
     506       17750 :                 struct ldb_result *res;
     507       17750 :                 struct ldb_message_element *el;
     508       17750 :                 struct ldb_dn *attr_dn;
     509      890139 :                 const char *no_attrs[] = { NULL };
     510       17750 :                 int ret;
     511             : 
     512      890139 :                 if (!do_attribute(attrs, guid_attrs[i])) continue;
     513             : 
     514      433130 :                 attr_dn = ldb_msg_find_attr_as_dn(ldb, ac->req, msg, guid_attrs[i]);
     515      433130 :                 if (attr_dn == NULL) {
     516           0 :                         continue;
     517             :                 }
     518             : 
     519      433130 :                 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      433130 :                 if (ret != LDB_SUCCESS) {
     526          19 :                         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          19 :                         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          19 :                         return LDB_ERR_OPERATIONS_ERROR;
     541             :                 }
     542             : 
     543      433111 :                 el = ldb_msg_find_element(msg, guid_attrs[i]);
     544      433111 :                 if (el == NULL) {
     545           0 :                         return ldb_operr(ldb);
     546             :                 }
     547             : 
     548      433111 :                 talloc_steal(el->values, res->msgs[0]->dn);
     549      433111 :                 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      433100 :                         el->values[0].data  = (uint8_t *)talloc_strdup(el->values,
     561      433100 :                                                                        ldb_dn_get_linearized(res->msgs[0]->dn));
     562             :                 }
     563      433111 :                 if (el->values[0].data == NULL) {
     564           0 :                         return ldb_oom(ldb);
     565             :                 }
     566      433111 :                 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      890120 :         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      872389 :         return LDB_SUCCESS;
     587             : 
     588           0 : failed:
     589           0 :         return ldb_operr(ldb);
     590             : }
     591             : 
     592             : /*
     593             :   handle search requests
     594             : */
     595             : 
     596      890151 : static struct rootdse_context *rootdse_init_context(struct ldb_module *module,
     597             :                                                     struct ldb_request *req)
     598             : {
     599       17750 :         struct ldb_context *ldb;
     600       17750 :         struct rootdse_context *ac;
     601             : 
     602      890151 :         ldb = ldb_module_get_ctx(module);
     603             : 
     604      890151 :         ac = talloc_zero(req, struct rootdse_context);
     605      890151 :         if (ac == NULL) {
     606           0 :                 ldb_set_errstring(ldb, "Out of Memory");
     607           0 :                 return NULL;
     608             :         }
     609             : 
     610      890151 :         ac->module = module;
     611      890151 :         ac->req = req;
     612             : 
     613      890151 :         return ac;
     614             : }
     615             : 
     616     1780259 : static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
     617             : {
     618       35481 :         struct rootdse_context *ac;
     619       35481 :         int ret;
     620             : 
     621     1780259 :         ac = talloc_get_type(req->context, struct rootdse_context);
     622             : 
     623     1780259 :         if (!ares) {
     624           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     625             :                                         LDB_ERR_OPERATIONS_ERROR);
     626             :         }
     627     1780259 :         if (ares->error != LDB_SUCCESS) {
     628           0 :                 return ldb_module_done(ac->req, ares->controls,
     629             :                                         ares->response, ares->error);
     630             :         }
     631             : 
     632     1780259 :         switch (ares->type) {
     633      890139 :         case LDB_REPLY_ENTRY:
     634             :                 /* for each record returned post-process to add any dynamic
     635             :                    attributes that have been asked for */
     636      890139 :                 ret = rootdse_add_dynamic(ac, ares->message);
     637      890139 :                 if (ret != LDB_SUCCESS) {
     638          19 :                         talloc_free(ares);
     639          19 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     640             :                 }
     641             : 
     642      890120 :                 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      890120 :         case LDB_REPLY_DONE:
     650      890120 :                 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    21280180 : static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
     680             : {
     681     1307190 :         unsigned int i, j;
     682    21280180 :         struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
     683     1307190 :         bool is_untrusted;
     684             : 
     685    21280180 :         if (!req->controls) {
     686     5212079 :                 return LDB_SUCCESS;
     687             :         }
     688             : 
     689    15801308 :         is_untrusted = ldb_req_is_untrusted(req);
     690             : 
     691    60059644 :         for (i=0; req->controls[i]; i++) {
     692    43217939 :                 bool is_registered = false;
     693    43217939 :                 bool is_critical = (req->controls[i]->critical != 0);
     694             : 
     695    43217939 :                 if (req->controls[i]->oid == NULL) {
     696           0 :                         continue;
     697             :                 }
     698             : 
     699    43217939 :                 if (is_untrusted || is_critical) {
     700   340128966 :                         for (j=0; j<priv->num_controls; j++) {
     701   339440739 :                                 if (strcasecmp(priv->controls[j], req->controls[i]->oid) == 0) {
     702    18383584 :                                         is_registered = true;
     703    18383584 :                                         break;
     704             :                                 }
     705             :                         }
     706             :                 }
     707             : 
     708    43217939 :                 if (is_untrusted && !is_registered) {
     709      591768 :                         if (!is_critical) {
     710             :                                 /* remove it by marking the oid NULL */
     711      591768 :                                 req->controls[i]->oid = NULL;
     712      591768 :                                 req->controls[i]->data = NULL;
     713      591768 :                                 req->controls[i]->critical = 0;
     714      591768 :                                 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    42626171 :                 if (!is_critical) {
     725    22727412 :                         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    19898759 :                 if (is_registered &&
     736    19802300 :                     strcmp(req->controls[i]->oid,
     737    19801774 :                            LDB_CONTROL_DIRSYNC_OID) != 0 &&
     738    19801774 :                     strcmp(req->controls[i]->oid,
     739    19748742 :                            LDB_CONTROL_VLV_REQ_OID) != 0 &&
     740    19748742 :                     strcmp(req->controls[i]->oid,
     741             :                            LDB_CONTROL_SERVER_SORT_OID) != 0) {
     742    19694925 :                         req->controls[i]->critical = 0;
     743             :                 }
     744             :         }
     745             : 
     746    14760911 :         return LDB_SUCCESS;
     747             : }
     748             : 
     749             : /* Ensure that anonymous users are not allowed to make anything other than rootDSE search operations */
     750             : 
     751    21280254 : static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
     752             : {
     753     1307190 :         struct auth_session_info *session_info;
     754    21280254 :         struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
     755    21280254 :         bool is_untrusted = ldb_req_is_untrusted(req);
     756    21280254 :         bool is_anonymous = true;
     757    21280254 :         if (is_untrusted == false) {
     758    18955300 :                 return LDB_SUCCESS;
     759             :         }
     760             : 
     761     1018351 :         session_info = (struct auth_session_info *)ldb_get_opaque(
     762             :                 ldb_module_get_ctx(module),
     763             :                 DSDB_SESSION_INFO);
     764     1018351 :         if (session_info) {
     765     1018351 :                 is_anonymous = security_token_is_anonymous(session_info->security_token);
     766             :         }
     767             : 
     768     1018351 :         if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
     769      990926 :                 return LDB_SUCCESS;
     770             :         }
     771             : 
     772       27425 :         if (req->operation == LDB_SEARCH) {
     773       27407 :                 if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
     774       27229 :                         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        2960 : 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        2960 :         TALLOC_CTX *tmp_ctx = talloc_new(ac->req);
     788          36 :         const char *domain, *host, *user, *domain_guid;
     789        2960 :         char *src_addr_s = NULL;
     790          36 :         struct dom_sid *domain_sid;
     791        2960 :         int acct_control = -1;
     792        2960 :         int version = -1;
     793          36 :         NTSTATUS status;
     794          36 :         struct netlogon_samlogon_response netlogon;
     795        2960 :         int ret = LDB_ERR_OPERATIONS_ERROR;
     796             : 
     797        2960 :         ldb = ldb_module_get_ctx(ac->module);
     798        2960 :         tree = ac->req->op.search.tree;
     799        2960 :         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
     800             :                                  struct loadparm_context);
     801        2960 :         src_addr = talloc_get_type(ldb_get_opaque(ldb, "remoteAddress"),
     802             :                                    struct tsocket_address);
     803        2960 :         if (src_addr) {
     804        2960 :                 src_addr_s = tsocket_address_inet_addr_string(src_addr,
     805             :                                                               tmp_ctx);
     806             :         }
     807             : 
     808        2960 :         status = parse_netlogon_request(tree, lp_ctx, tmp_ctx,
     809             :                                         &domain, &host, &user, &domain_guid,
     810             :                                         &domain_sid, &acct_control, &version);
     811        2960 :         if (!NT_STATUS_IS_OK(status)) {
     812           6 :                 goto failed;
     813             :         }
     814             : 
     815        2954 :         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        2954 :         if (!NT_STATUS_IS_OK(status)) {
     823           6 :                 goto failed;
     824             :         }
     825             : 
     826        2948 :         status = push_netlogon_samlogon_response(&ac->netlogon, ac, &netlogon);
     827        2948 :         if (!NT_STATUS_IS_OK(status)) {
     828           0 :                 goto failed;
     829             :         }
     830             : 
     831        2912 :         ret = LDB_SUCCESS;
     832        2960 : failed:
     833        2960 :         talloc_free(tmp_ctx);
     834        2960 :         return ret;
     835             : }
     836             : 
     837    18653082 : static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
     838             : {
     839     1110228 :         struct ldb_context *ldb;
     840     1110228 :         struct rootdse_context *ac;
     841     1110228 :         struct ldb_request *down_req;
     842     1110228 :         int ret;
     843             : 
     844    18653082 :         ret = rootdse_filter_operations(module, req);
     845    18653082 :         if (ret != LDB_SUCCESS) {
     846          56 :                 return ret;
     847             :         }
     848             : 
     849    18653026 :         ret = rootdse_filter_controls(module, req);
     850    18653026 :         if (ret != LDB_SUCCESS) {
     851           0 :                 return ret;
     852             :         }
     853             : 
     854    18653026 :         ldb = ldb_module_get_ctx(module);
     855             : 
     856             :         /* see if its for the rootDSE - only a base search on the "" DN qualifies */
     857    18653026 :         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    17762875 :                 return ldb_next_request(module, req);
     860             :         }
     861             : 
     862      890151 :         ac = rootdse_init_context(module, req);
     863      890151 :         if (ac == NULL) {
     864           0 :                 return ldb_operr(ldb);
     865             :         }
     866             : 
     867      890151 :         if (do_attribute_explicit(req->op.search.attrs, "netlogon")) {
     868        2960 :                 ret = rootdse_handle_netlogon(ac);
     869             :                 /* We have to return an empty result, so don't forward `ret' */
     870        2960 :                 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      890139 :         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      890139 :         LDB_REQ_SET_LOCATION(down_req);
     885      890139 :         if (ret != LDB_SUCCESS) {
     886           0 :                 return ret;
     887             :         }
     888             : 
     889      890139 :         return ldb_next_request(module, down_req);
     890             : }
     891             : 
     892     5209481 : static struct rootdse_private_data *rootdse_get_private_data(struct ldb_module *module)
     893             : {
     894     5209481 :         void *priv = ldb_module_get_private(module);
     895     5209481 :         struct rootdse_private_data *data = NULL;
     896      174146 :         struct ldb_context *ldb
     897     5209481 :                 = ldb_module_get_ctx(module);
     898             : 
     899     5209481 :         if (priv != NULL) {
     900     5026830 :                 data = talloc_get_type_abort(priv,
     901             :                                              struct rootdse_private_data);
     902             :         }
     903             : 
     904     5203433 :         if (data != NULL) {
     905     4858732 :                 return data;
     906             :         }
     907             : 
     908      182651 :         data = talloc_zero(module, struct rootdse_private_data);
     909      182651 :         if (data == NULL) {
     910           0 :                 return NULL;
     911             :         }
     912             : 
     913      182651 :         data->num_controls = 0;
     914      182651 :         data->controls = NULL;
     915      182651 :         data->num_partitions = 0;
     916      182651 :         data->partitions = NULL;
     917      182651 :         data->block_anonymous = true;
     918             : 
     919      182651 :         ldb_module_set_private(module, data);
     920             : 
     921      182651 :         ldb_set_default_dns(ldb);
     922             : 
     923      182651 :         return data;
     924             : }
     925             : 
     926             : 
     927     4152120 : static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
     928             : {
     929      138247 :         struct rootdse_private_data *priv =
     930     4152120 :                 rootdse_get_private_data(module);
     931      138247 :         char **list;
     932             : 
     933     4152120 :         if (priv == NULL) {
     934           0 :                 return ldb_module_oom(module);
     935             :         }
     936             : 
     937     4152120 :         list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
     938     4152120 :         if (!list) {
     939           0 :                 return ldb_oom(ldb_module_get_ctx(module));
     940             :         }
     941             : 
     942     4152120 :         list[priv->num_controls] = talloc_strdup(list, req->op.reg_control.oid);
     943     4152120 :         if (!list[priv->num_controls]) {
     944           0 :                 return ldb_oom(ldb_module_get_ctx(module));
     945             :         }
     946             : 
     947     4152120 :         priv->num_controls += 1;
     948     4152120 :         priv->controls = list;
     949             : 
     950     4152120 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     951             : }
     952             : 
     953      874710 : static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
     954             : {
     955       29851 :         struct rootdse_private_data *priv =
     956      874710 :                 rootdse_get_private_data(module);
     957       29851 :         struct ldb_dn **list;
     958             : 
     959      874710 :         if (priv == NULL) {
     960           0 :                 return ldb_module_oom(module);
     961             :         }
     962             : 
     963      874710 :         list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
     964      874710 :         if (!list) {
     965           0 :                 return ldb_oom(ldb_module_get_ctx(module));
     966             :         }
     967             : 
     968      874710 :         list[priv->num_partitions] = ldb_dn_copy(list, req->op.reg_partition.dn);
     969      874710 :         if (!list[priv->num_partitions]) {
     970           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     971             :         }
     972             : 
     973      874710 :         priv->num_partitions += 1;
     974      874710 :         priv->partitions = list;
     975             : 
     976      874710 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     977             : }
     978             : 
     979             : 
     980     5026830 : static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
     981             : {
     982     5026830 :         switch (req->operation) {
     983             : 
     984     4152120 :         case LDB_REQ_REGISTER_CONTROL:
     985     4152120 :                 return rootdse_register_control(module, req);
     986      874710 :         case LDB_REQ_REGISTER_PARTITION:
     987      874710 :                 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      182651 : static int rootdse_init(struct ldb_module *module)
     996             : {
     997        6048 :         int ret;
     998        6048 :         struct ldb_result *res;
     999      182651 :         const char *attrs[] = { "msDS-Behavior-Version", NULL };
    1000      182651 :         const char *ds_attrs[] = { "dsServiceName", NULL };
    1001        6048 :         TALLOC_CTX *mem_ctx;
    1002             : 
    1003        6048 :         struct ldb_context *ldb
    1004      182651 :                 = ldb_module_get_ctx(module);
    1005             : 
    1006        6048 :         struct rootdse_private_data *data
    1007      182651 :                 = rootdse_get_private_data(module);
    1008             : 
    1009      182651 :         if (data == NULL) {
    1010           0 :                 return ldb_module_oom(module);
    1011             :         }
    1012             : 
    1013      182651 :         ret = ldb_next_init(module);
    1014             : 
    1015      182651 :         if (ret != LDB_SUCCESS) {
    1016           0 :                 return ret;
    1017             :         }
    1018             : 
    1019      182651 :         mem_ctx = talloc_new(data);
    1020      182651 :         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      182651 :         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      182651 :         if (ret == LDB_SUCCESS && res->count == 1) {
    1038        6020 :                 int domain_behaviour_version
    1039      182441 :                         = ldb_msg_find_attr_as_int(res->msgs[0],
    1040             :                                                    "msDS-Behavior-Version", -1);
    1041      182441 :                 if (domain_behaviour_version != -1) {
    1042        6014 :                         unsigned long long *val
    1043      182409 :                                 = talloc(ldb, unsigned long long);
    1044      182409 :                         if (!val) {
    1045           0 :                                 talloc_free(mem_ctx);
    1046           0 :                                 return ldb_oom(ldb);
    1047             :                         }
    1048      182409 :                         *val = domain_behaviour_version;
    1049      182409 :                         ret = ldb_set_opaque(ldb, "domainFunctionality", val);
    1050      182409 :                         if (ret != LDB_SUCCESS) {
    1051           0 :                                 talloc_free(mem_ctx);
    1052           0 :                                 return ret;
    1053             :                         }
    1054             :                 }
    1055             :         }
    1056             : 
    1057      182651 :         ret = dsdb_module_search(module, mem_ctx, &res,
    1058             :                                  samdb_partitions_dn(ldb, mem_ctx),
    1059             :                                  LDB_SCOPE_BASE, attrs,
    1060             :                                  DSDB_FLAG_NEXT_MODULE |
    1061             :                                  DSDB_FLAG_AS_SYSTEM,
    1062             :                                  NULL, NULL);
    1063      182651 :         if (ret == LDB_SUCCESS && res->count == 1) {
    1064        6014 :                 int forest_behaviour_version
    1065      182435 :                         = ldb_msg_find_attr_as_int(res->msgs[0],
    1066             :                                                    "msDS-Behavior-Version", -1);
    1067      182435 :                 if (forest_behaviour_version != -1) {
    1068        6014 :                         unsigned long long *val
    1069      182435 :                                 = talloc(ldb, unsigned long long);
    1070      182435 :                         if (!val) {
    1071           0 :                                 talloc_free(mem_ctx);
    1072           0 :                                 return ldb_oom(ldb);
    1073             :                         }
    1074      182435 :                         *val = forest_behaviour_version;
    1075      182435 :                         ret = ldb_set_opaque(ldb, "forestFunctionality", val);
    1076      182435 :                         if (ret != LDB_SUCCESS) {
    1077           0 :                                 talloc_free(mem_ctx);
    1078           0 :                                 return ret;
    1079             :                         }
    1080             :                 }
    1081             :         }
    1082             : 
    1083             : 
    1084             :         /*
    1085             :          * For now, our own server's location in the DB is recorded in
    1086             :          * the @ROOTDSE record
    1087             :          *
    1088             :          * We can't call samdb_ntds_settings_dn() in the rootdse, as
    1089             :          * that routine used the rootdse result!
    1090             :          */
    1091      182651 :         ret = dsdb_module_search(module, mem_ctx, &res,
    1092             :                                  ldb_dn_new(mem_ctx, ldb, "@ROOTDSE"),
    1093             :                                  LDB_SCOPE_BASE, ds_attrs,
    1094             :                                  DSDB_FLAG_NEXT_MODULE |
    1095             :                                  DSDB_FLAG_AS_SYSTEM,
    1096             :                                  NULL, NULL);
    1097      182651 :         if (ret == LDB_SUCCESS && res->count == 1) {
    1098        6048 :                 struct ldb_dn *ds_dn
    1099      182651 :                         = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0],
    1100             :                                                   "dsServiceName");
    1101      182651 :                 if (ds_dn) {
    1102      182651 :                         ret = dsdb_module_search(module, mem_ctx, &res, ds_dn,
    1103             :                                                  LDB_SCOPE_BASE, attrs,
    1104             :                                                  DSDB_FLAG_NEXT_MODULE |
    1105             :                                                  DSDB_FLAG_AS_SYSTEM,
    1106             :                                                  NULL, NULL);
    1107      182651 :                         if (ret == LDB_SUCCESS && res->count == 1) {
    1108        6014 :                                 int domain_controller_behaviour_version
    1109      182435 :                                         = ldb_msg_find_attr_as_int(res->msgs[0],
    1110             :                                                                    "msDS-Behavior-Version", -1);
    1111      182435 :                                 if (domain_controller_behaviour_version != -1) {
    1112        6014 :                                         unsigned long long *val
    1113      182265 :                                                 = talloc(ldb, unsigned long long);
    1114      182265 :                                         if (!val) {
    1115           0 :                                                 talloc_free(mem_ctx);
    1116           0 :                                                 return ldb_oom(ldb);
    1117             :                                         }
    1118      182265 :                                         *val = domain_controller_behaviour_version;
    1119      182265 :                                         ret = ldb_set_opaque(ldb,
    1120             :                                                              "domainControllerFunctionality", val);
    1121      182265 :                                         if (ret != LDB_SUCCESS) {
    1122           0 :                                                 talloc_free(mem_ctx);
    1123           0 :                                                 return ret;
    1124             :                                         }
    1125             :                                 }
    1126             :                         }
    1127             :                 }
    1128             :         }
    1129             : 
    1130      182651 :         data->block_anonymous = dsdb_block_anonymous_ops(module, NULL);
    1131             : 
    1132      182651 :         talloc_free(mem_ctx);
    1133             : 
    1134      182651 :         return LDB_SUCCESS;
    1135             : }
    1136             : 
    1137             : /*
    1138             :  * This function gets the string SCOPE_DN:OPTIONAL_FEATURE_GUID and parse it
    1139             :  * to a DN and a GUID object
    1140             :  */
    1141           0 : static int get_optional_feature_dn_guid(struct ldb_request *req, struct ldb_context *ldb,
    1142             :                                                 TALLOC_CTX *mem_ctx,
    1143             :                                                 struct ldb_dn **op_feature_scope_dn,
    1144             :                                                 struct GUID *op_feature_guid)
    1145             : {
    1146           0 :         const struct ldb_message *msg = req->op.mod.message;
    1147           0 :         const char *ldb_val_str;
    1148           0 :         char *dn, *guid;
    1149           0 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1150           0 :         NTSTATUS status;
    1151             : 
    1152           0 :         ldb_val_str = ldb_msg_find_attr_as_string(msg, "enableOptionalFeature", NULL);
    1153           0 :         if (!ldb_val_str) {
    1154           0 :                 ldb_set_errstring(ldb,
    1155             :                                   "rootdse: unable to find 'enableOptionalFeature'!");
    1156           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1157             :         }
    1158             : 
    1159           0 :         guid = strchr(ldb_val_str, ':');
    1160           0 :         if (!guid) {
    1161           0 :                 ldb_set_errstring(ldb,
    1162             :                                   "rootdse: unable to find GUID in 'enableOptionalFeature'!");
    1163           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1164             :         }
    1165           0 :         status = GUID_from_string(guid+1, op_feature_guid);
    1166           0 :         if (!NT_STATUS_IS_OK(status)) {
    1167           0 :                 ldb_set_errstring(ldb,
    1168             :                                   "rootdse: bad GUID in 'enableOptionalFeature'!");
    1169           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1170             :         }
    1171             : 
    1172           0 :         dn = talloc_strndup(tmp_ctx, ldb_val_str, guid-ldb_val_str);
    1173           0 :         if (!dn) {
    1174           0 :                 ldb_set_errstring(ldb,
    1175             :                                   "rootdse: bad DN in 'enableOptionalFeature'!");
    1176           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1177             :         }
    1178             : 
    1179           0 :         *op_feature_scope_dn = ldb_dn_new(mem_ctx, ldb, dn);
    1180             : 
    1181           0 :         talloc_free(tmp_ctx);
    1182           0 :         return LDB_SUCCESS;
    1183             : }
    1184             : 
    1185             : /*
    1186             :  * This function gets the OPTIONAL_FEATURE_GUID and looks for the optional feature
    1187             :  * ldb_message object.
    1188             :  */
    1189           0 : static int dsdb_find_optional_feature(struct ldb_module *module, struct ldb_context *ldb,
    1190             :                                       TALLOC_CTX *mem_ctx, struct GUID op_feature_guid, struct ldb_message **msg,
    1191             :                                       struct ldb_request *parent)
    1192             : {
    1193           0 :         struct ldb_result *res;
    1194           0 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1195           0 :         int ret;
    1196             : 
    1197           0 :         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
    1198             :                                  NULL,
    1199             :                                  DSDB_FLAG_NEXT_MODULE |
    1200             :                                  DSDB_FLAG_AS_SYSTEM |
    1201             :                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
    1202             :                                  parent,
    1203             :                                  "(&(objectClass=msDS-OptionalFeature)"
    1204             :                                  "(msDS-OptionalFeatureGUID=%s))",GUID_string(tmp_ctx, &op_feature_guid));
    1205             : 
    1206           0 :         if (ret != LDB_SUCCESS) {
    1207           0 :                 talloc_free(tmp_ctx);
    1208           0 :                 return ret;
    1209             :         }
    1210           0 :         if (res->count == 0) {
    1211           0 :                 talloc_free(tmp_ctx);
    1212           0 :                 return LDB_ERR_NO_SUCH_OBJECT;
    1213             :         }
    1214           0 :         if (res->count != 1) {
    1215           0 :                 ldb_asprintf_errstring(ldb,
    1216             :                                        "More than one object found matching optional feature GUID %s\n",
    1217             :                                        GUID_string(tmp_ctx, &op_feature_guid));
    1218           0 :                 talloc_free(tmp_ctx);
    1219           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1220             :         }
    1221             : 
    1222           0 :         *msg = talloc_steal(mem_ctx, res->msgs[0]);
    1223             : 
    1224           0 :         talloc_free(tmp_ctx);
    1225           0 :         return LDB_SUCCESS;
    1226             : }
    1227             : 
    1228           0 : static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_context *ldb,
    1229             :                                       TALLOC_CTX *mem_ctx, struct ldb_dn *op_feature_scope_dn,
    1230             :                                       struct ldb_message *op_feature_msg, struct ldb_request *parent)
    1231             : {
    1232           0 :         int ret;
    1233           0 :         const int domain_func_level = dsdb_functional_level(ldb);
    1234           0 :         struct ldb_dn *ntds_settings_dn;
    1235           0 :         TALLOC_CTX *tmp_ctx;
    1236           0 :         unsigned int el_count = 0;
    1237           0 :         struct ldb_message *msg;
    1238             : 
    1239           0 :         ret = ldb_msg_find_attr_as_int(op_feature_msg, "msDS-RequiredForestBehaviorVersion", 0);
    1240           0 :         if (domain_func_level < ret){
    1241           0 :                 ldb_asprintf_errstring(ldb,
    1242             :                                        "rootdse_enable_recycle_bin: Domain functional level must be at least %d\n",
    1243             :                                        ret);
    1244           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1245             :         }
    1246             : 
    1247           0 :         tmp_ctx = talloc_new(mem_ctx);
    1248           0 :         ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
    1249           0 :         if (!ntds_settings_dn) {
    1250           0 :                 talloc_free(tmp_ctx);
    1251           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to find NTDS settings DN");
    1252             :         }
    1253             : 
    1254           0 :         ntds_settings_dn = ldb_dn_copy(tmp_ctx, ntds_settings_dn);
    1255           0 :         if (!ntds_settings_dn) {
    1256           0 :                 talloc_free(tmp_ctx);
    1257           0 :                 return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "Failed to copy NTDS settings DN");
    1258             :         }
    1259             : 
    1260           0 :         msg = ldb_msg_new(tmp_ctx);
    1261           0 :         if (msg == NULL) {
    1262           0 :                 talloc_free(tmp_ctx);
    1263           0 :                 return ldb_module_oom(module);
    1264             :         }
    1265           0 :         msg->dn = ntds_settings_dn;
    1266             : 
    1267           0 :         ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
    1268           0 :         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
    1269             : 
    1270           0 :         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
    1271           0 :         if (ret != LDB_SUCCESS) {
    1272           0 :                 ldb_asprintf_errstring(ldb,
    1273             :                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
    1274             :                                        ldb_dn_get_linearized(ntds_settings_dn),
    1275             :                                        ldb_errstring(ldb));
    1276           0 :                 talloc_free(tmp_ctx);
    1277           0 :                 return ret;
    1278             :         }
    1279             : 
    1280           0 :         msg->dn = op_feature_scope_dn;
    1281           0 :         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
    1282           0 :         if (ret != LDB_SUCCESS) {
    1283           0 :                 ldb_asprintf_errstring(ldb,
    1284             :                                        "rootdse_enable_recycle_bin: Failed to modify object %s - %s",
    1285             :                                        ldb_dn_get_linearized(op_feature_scope_dn),
    1286             :                                        ldb_errstring(ldb));
    1287           0 :                 talloc_free(tmp_ctx);
    1288           0 :                 return ret;
    1289             :         }
    1290             : 
    1291           0 :         return LDB_SUCCESS;
    1292             : }
    1293             : 
    1294           0 : static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_request *req)
    1295             : {
    1296             :         /*
    1297             :           steps:
    1298             :                - check for system (only system can enable features)
    1299             :                - extract GUID from the request
    1300             :                - find the feature object
    1301             :                - check functional level, must be at least msDS-RequiredForestBehaviorVersion
    1302             :                - check if it is already enabled (if enabled return LDAP_ATTRIBUTE_OR_VALUE_EXISTS) - probably not needed, just return error from the add/modify
    1303             :                - add/modify objects (see ntdsconnection code for an example)
    1304             :          */
    1305             : 
    1306           0 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1307           0 :         struct GUID op_feature_guid;
    1308           0 :         struct ldb_dn *op_feature_scope_dn;
    1309           0 :         struct ldb_message *op_feature_msg;
    1310           0 :         struct auth_session_info *session_info =
    1311           0 :                 (struct auth_session_info *)ldb_get_opaque(
    1312             :                         ldb,
    1313             :                         DSDB_SESSION_INFO);
    1314           0 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    1315           0 :         int ret;
    1316           0 :         const char *guid_string;
    1317             : 
    1318           0 :         if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
    1319           0 :                 ldb_set_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature");
    1320           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1321             :         }
    1322             : 
    1323           0 :         ret = get_optional_feature_dn_guid(req, ldb, tmp_ctx, &op_feature_scope_dn, &op_feature_guid);
    1324           0 :         if (ret != LDB_SUCCESS) {
    1325           0 :                 talloc_free(tmp_ctx);
    1326           0 :                 return ret;
    1327             :         }
    1328             : 
    1329           0 :         guid_string = GUID_string(tmp_ctx, &op_feature_guid);
    1330           0 :         if (!guid_string) {
    1331           0 :                 ldb_set_errstring(ldb, "rootdse: bad optional feature GUID");
    1332           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1333             :         }
    1334             : 
    1335           0 :         ret = dsdb_find_optional_feature(module, ldb, tmp_ctx, op_feature_guid, &op_feature_msg, req);
    1336           0 :         if (ret != LDB_SUCCESS) {
    1337           0 :                 ldb_asprintf_errstring(ldb,
    1338             :                                        "rootdse: unable to find optional feature for %s - %s",
    1339             :                                        guid_string, ldb_errstring(ldb));
    1340           0 :                 talloc_free(tmp_ctx);
    1341           0 :                 return ret;
    1342             :         }
    1343             : 
    1344           0 :         if (strcasecmp(DS_GUID_FEATURE_RECYCLE_BIN, guid_string) == 0) {
    1345           0 :                         ret = rootdse_enable_recycle_bin(module, ldb,
    1346             :                                                          tmp_ctx, op_feature_scope_dn,
    1347             :                                                          op_feature_msg, req);
    1348             :         } else {
    1349           0 :                 ldb_asprintf_errstring(ldb,
    1350             :                                        "rootdse: unknown optional feature %s",
    1351             :                                        guid_string);
    1352           0 :                 talloc_free(tmp_ctx);
    1353           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1354             :         }
    1355           0 :         if (ret != LDB_SUCCESS) {
    1356           0 :                 ldb_asprintf_errstring(ldb,
    1357             :                                        "rootdse: failed to set optional feature for %s - %s",
    1358             :                                        guid_string, ldb_errstring(ldb));
    1359           0 :                 talloc_free(tmp_ctx);
    1360           0 :                 return ret;
    1361             :         }
    1362             : 
    1363           0 :         talloc_free(tmp_ctx);
    1364           0 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);;
    1365             : }
    1366             : 
    1367         761 : static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request *req)
    1368             : {
    1369         761 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1370           0 :         struct ldb_result *ext_res;
    1371           0 :         int ret;
    1372           0 :         struct ldb_dn *schema_dn;
    1373             : 
    1374         761 :         schema_dn = ldb_get_schema_basedn(ldb);
    1375         761 :         if (!schema_dn) {
    1376           0 :                 ldb_reset_err_string(ldb);
    1377           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING,
    1378             :                           "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
    1379           0 :                 return ldb_next_request(module, req);
    1380             :         }
    1381             : 
    1382             :         /*
    1383             :          * schemaUpdateNow has been requested. Allow this to refresh the schema
    1384             :          * even if we're currently in the middle of a transaction
    1385             :          */
    1386         761 :         ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)1);
    1387         761 :         if (ret != LDB_SUCCESS) {
    1388           0 :                 return ldb_operr(ldb);
    1389             :         }
    1390             : 
    1391         761 :         ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
    1392         761 :         if (ret != LDB_SUCCESS) {
    1393           0 :                 ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0);
    1394           0 :                 return ldb_operr(ldb);
    1395             :         }
    1396             : 
    1397         761 :         talloc_free(ext_res);
    1398             : 
    1399         761 :         ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0);
    1400         761 :         if (ret != LDB_SUCCESS) {
    1401           0 :                 return ldb_operr(ldb);
    1402             :         }
    1403             : 
    1404         761 :         return ldb_module_done(req, NULL, NULL, ret);
    1405             : }
    1406             : 
    1407          36 : static int rootdse_schemaupgradeinprogress(struct ldb_module *module, struct ldb_request *req)
    1408             : {
    1409          36 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1410          36 :         int ret = LDB_SUCCESS;
    1411           0 :         struct ldb_dn *schema_dn;
    1412             : 
    1413          36 :         schema_dn = ldb_get_schema_basedn(ldb);
    1414          36 :         if (!schema_dn) {
    1415           0 :                 ldb_reset_err_string(ldb);
    1416           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING,
    1417             :                           "rootdse_modify: no schema dn present: (skip ldb_extended call)\n");
    1418           0 :                 return ldb_next_request(module, req);
    1419             :         }
    1420             : 
    1421             :         /* FIXME we have to do something in order to relax constraints for DRS
    1422             :          * setting schemaUpgradeInProgress cause the fschemaUpgradeInProgress
    1423             :          * in all LDAP connection (2K3/2K3R2) or in the current connection (2K8 and +)
    1424             :          * to be set to true.
    1425             :          */
    1426             : 
    1427             :         /* from 5.113 LDAPConnections in DRSR.pdf
    1428             :          * fschemaUpgradeInProgress: A Boolean that specifies certain constraint
    1429             :          * validations are skipped when adding, updating, or removing directory
    1430             :          * objects on the opened connection. The skipped constraint validations
    1431             :          * are documented in the applicable constraint sections in [MS-ADTS].
    1432             :          */
    1433          36 :         return ldb_module_done(req, NULL, NULL, ret);
    1434             : }
    1435             : 
    1436      543729 : static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
    1437             : {
    1438      543729 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1439       83688 :         int ret;
    1440             : 
    1441      543729 :         ret = rootdse_filter_operations(module, req);
    1442      543729 :         if (ret != LDB_SUCCESS) {
    1443           0 :                 return ret;
    1444             :         }
    1445             : 
    1446      543729 :         ret = rootdse_filter_controls(module, req);
    1447      543729 :         if (ret != LDB_SUCCESS) {
    1448           0 :                 return ret;
    1449             :         }
    1450             : 
    1451             :         /*
    1452             :                 If dn is not "" we should let it pass through
    1453             :         */
    1454      543729 :         if (!ldb_dn_is_null(req->op.add.message->dn)) {
    1455      543728 :                 return ldb_next_request(module, req);
    1456             :         }
    1457             : 
    1458           1 :         ldb_set_errstring(ldb, "rootdse_add: you cannot add a new rootdse entry!");
    1459           1 :         return LDB_ERR_NAMING_VIOLATION;
    1460             : }
    1461             : 
    1462      348917 : static int rootdse_start_trans(struct ldb_module *module)
    1463             : {
    1464        2231 :         int ret;
    1465      348917 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1466      348917 :         struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
    1467             :                                                                   struct rootdse_private_data);
    1468      348917 :         ret = ldb_next_start_trans(module);
    1469      348917 :         if (ret == LDB_SUCCESS) {
    1470      348917 :                 if (data->private_ev != NULL) {
    1471           0 :                         return ldb_operr(ldb);
    1472             :                 }
    1473      348917 :                 data->private_ev = s4_event_context_init(data);
    1474      348917 :                 if (data->private_ev == NULL) {
    1475           0 :                         return ldb_operr(ldb);
    1476             :                 }
    1477      348917 :                 data->saved_ev = ldb_get_event_context(ldb);
    1478      348917 :                 ldb_set_event_context(ldb, data->private_ev);
    1479             :         }
    1480      346686 :         return ret;
    1481             : }
    1482             : 
    1483      303857 : static int rootdse_end_trans(struct ldb_module *module)
    1484             : {
    1485        2226 :         int ret;
    1486      303857 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1487      303857 :         struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
    1488             :                                                                   struct rootdse_private_data);
    1489      303857 :         ret = ldb_next_end_trans(module);
    1490      303857 :         if (data->saved_ev == NULL) {
    1491           0 :                 return ldb_operr(ldb);
    1492             :         }
    1493             : 
    1494      303857 :         if (data->private_ev != ldb_get_event_context(ldb)) {
    1495           0 :                 return ldb_operr(ldb);
    1496             :         }
    1497      303857 :         ldb_set_event_context(ldb, data->saved_ev);
    1498      303857 :         data->saved_ev = NULL;
    1499      303857 :         TALLOC_FREE(data->private_ev);
    1500      301631 :         return ret;
    1501             : }
    1502             : 
    1503       45058 : static int rootdse_del_trans(struct ldb_module *module)
    1504             : {
    1505           4 :         int ret;
    1506       45058 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1507       45058 :         struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
    1508             :                                                                   struct rootdse_private_data);
    1509       45058 :         ret = ldb_next_del_trans(module);
    1510       45058 :         if (data->saved_ev == NULL) {
    1511           0 :                 return ldb_operr(ldb);
    1512             :         }
    1513             : 
    1514       45058 :         if (data->private_ev != ldb_get_event_context(ldb)) {
    1515           0 :                 return ldb_operr(ldb);
    1516             :         }
    1517       45058 :         ldb_set_event_context(ldb, data->saved_ev);
    1518       45058 :         data->saved_ev = NULL;
    1519       45058 :         TALLOC_FREE(data->private_ev);
    1520       45054 :         return ret;
    1521             : }
    1522             : 
    1523             : struct fsmo_transfer_state {
    1524             :         struct ldb_context *ldb;
    1525             :         struct ldb_request *req;
    1526             :         struct ldb_module *module;
    1527             : };
    1528             : 
    1529             : /*
    1530             :   called when a FSMO transfer operation has completed
    1531             :  */
    1532          22 : static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
    1533             : {
    1534          22 :         struct fsmo_transfer_state *fsmo = tevent_req_callback_data(treq, struct fsmo_transfer_state);
    1535           0 :         NTSTATUS status;
    1536           0 :         WERROR werr;
    1537           0 :         int ret;
    1538          22 :         struct ldb_request *req = fsmo->req;
    1539          22 :         struct ldb_context *ldb = fsmo->ldb;
    1540          22 :         struct ldb_module *module = fsmo->module;
    1541             : 
    1542          22 :         status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr);
    1543          22 :         talloc_free(fsmo);
    1544          22 :         if (!NT_STATUS_IS_OK(status)) {
    1545           0 :                 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", nt_errstr(status));
    1546             :                 /*
    1547             :                  * Now that it is failed, start the transaction up
    1548             :                  * again so the wrappers can close it without additional error
    1549             :                  */
    1550           0 :                 rootdse_start_trans(module);
    1551           0 :                 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
    1552           0 :                 return;
    1553             :         }
    1554          22 :         if (!W_ERROR_IS_OK(werr)) {
    1555           0 :                 ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", win_errstr(werr));
    1556             :                 /*
    1557             :                  * Now that it is failed, start the transaction up
    1558             :                  * again so the wrappers can close it without additional error
    1559             :                  */
    1560           0 :                 rootdse_start_trans(module);
    1561           0 :                 ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
    1562           0 :                 return;
    1563             :         }
    1564             : 
    1565             :         /*
    1566             :          * Now that it is done, start the transaction up again so the
    1567             :          * wrappers can close it without error
    1568             :          */
    1569          22 :         ret = rootdse_start_trans(module);
    1570          22 :         ldb_module_done(req, NULL, NULL, ret);
    1571             : }
    1572             : 
    1573          22 : static int rootdse_become_master(struct ldb_module *module,
    1574             :                                  struct ldb_request *req,
    1575             :                                  enum drepl_role_master role)
    1576             : {
    1577           0 :         struct imessaging_context *msg;
    1578          22 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1579          22 :         TALLOC_CTX *tmp_ctx = talloc_new(req);
    1580          22 :         struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm");
    1581           0 :         bool am_rodc;
    1582           0 :         struct dcerpc_binding_handle *irpc_handle;
    1583           0 :         int ret;
    1584           0 :         struct auth_session_info *session_info;
    1585           0 :         enum security_user_level level;
    1586           0 :         struct fsmo_transfer_state *fsmo;
    1587           0 :         struct tevent_req *treq;
    1588             : 
    1589          22 :         session_info = (struct auth_session_info *)ldb_get_opaque(
    1590             :                 ldb_module_get_ctx(module),
    1591             :                 DSDB_SESSION_INFO);
    1592          22 :         level = security_session_user_level(session_info, NULL);
    1593          22 :         if (level < SECURITY_ADMINISTRATOR) {
    1594           0 :                 return ldb_error(ldb, LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS, "Denied rootDSE modify for non-administrator");
    1595             :         }
    1596             : 
    1597          22 :         ret = samdb_rodc(ldb, &am_rodc);
    1598          22 :         if (ret != LDB_SUCCESS) {
    1599           0 :                 return ldb_error(ldb, ret, "Could not determine if server is RODC.");
    1600             :         }
    1601             : 
    1602          22 :         if (am_rodc) {
    1603           0 :                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
    1604             :                                  "RODC cannot become a role master.");
    1605             :         }
    1606             : 
    1607             :         /*
    1608             :          * We always delete the transaction, not commit it, because
    1609             :          * this gives the least surprise to this surprising action (as
    1610             :          * we will never record anything done to this point
    1611             :          */
    1612          22 :         rootdse_del_trans(module);
    1613             : 
    1614             :         /*
    1615             :          * We must use the global event loop to run this IRPC in
    1616             :          * single process mode
    1617             :          */
    1618          22 :         ldb_handle_use_global_event_context(req->handle);
    1619             : 
    1620          22 :         msg = imessaging_client_init(tmp_ctx, lp_ctx,
    1621             :                                     ldb_get_event_context(ldb));
    1622          22 :         if (!msg) {
    1623           0 :                 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s", lpcfg_imessaging_path(tmp_ctx, lp_ctx));
    1624           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1625             :         }
    1626          22 :         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg,
    1627             :                                                   "dreplsrv",
    1628             :                                                   &ndr_table_irpc);
    1629          22 :         if (irpc_handle == NULL) {
    1630           0 :                 return ldb_oom(ldb);
    1631             :         }
    1632          22 :         fsmo = talloc_zero(req, struct fsmo_transfer_state);
    1633          22 :         if (fsmo == NULL) {
    1634           0 :                 return ldb_oom(ldb);
    1635             :         }
    1636          22 :         fsmo->ldb = ldb;
    1637          22 :         fsmo->req = req;
    1638          22 :         fsmo->module = module;
    1639             : 
    1640             :         /*
    1641             :          * we send the call asynchronously, as the ldap client is
    1642             :          * expecting to get an error back if the role transfer fails
    1643             :          *
    1644             :          * We need more than the default 10 seconds IRPC allows, so
    1645             :          * set a longer timeout (default ldb timeout is 300 seconds).
    1646             :          * We send an async reply when we are done.
    1647             :          *
    1648             :          * We are the first module, so don't bother working out how
    1649             :          * long we have spent so far.
    1650             :          */
    1651          22 :         dcerpc_binding_handle_set_timeout(irpc_handle, req->timeout);
    1652             : 
    1653          22 :         treq = dcerpc_drepl_takeFSMORole_send(req, ldb_get_event_context(ldb), irpc_handle, role);
    1654          22 :         if (treq == NULL) {
    1655           0 :                 return ldb_oom(ldb);
    1656             :         }
    1657             : 
    1658          22 :         tevent_req_set_callback(treq, rootdse_fsmo_transfer_callback, fsmo);
    1659          22 :         return LDB_SUCCESS;
    1660             : }
    1661             : 
    1662      322181 : static int rootdse_modify(struct ldb_module *module, struct ldb_request *req)
    1663             : {
    1664      322181 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1665       17229 :         int ret;
    1666             : 
    1667      322181 :         ret = rootdse_filter_operations(module, req);
    1668      322181 :         if (ret != LDB_SUCCESS) {
    1669           9 :                 return ret;
    1670             :         }
    1671             : 
    1672      322172 :         ret = rootdse_filter_controls(module, req);
    1673      322172 :         if (ret != LDB_SUCCESS) {
    1674           0 :                 return ret;
    1675             :         }
    1676             : 
    1677             :         /*
    1678             :                 If dn is not "" we should let it pass through
    1679             :         */
    1680      322172 :         if (!ldb_dn_is_null(req->op.mod.message->dn)) {
    1681      321350 :                 return ldb_next_request(module, req);
    1682             :         }
    1683             : 
    1684             :         /*
    1685             :                 dn is empty so check for schemaUpdateNow attribute
    1686             :                 "The type of modification and values specified in the LDAP modify operation do not matter." MSDN
    1687             :         */
    1688         822 :         if (ldb_msg_find_element(req->op.mod.message, "schemaUpdateNow")) {
    1689         761 :                 return rootdse_schemaupdatenow(module, req);
    1690             :         }
    1691          61 :         if (ldb_msg_find_element(req->op.mod.message, "becomeDomainMaster")) {
    1692           4 :                 return rootdse_become_master(module, req, DREPL_NAMING_MASTER);
    1693             :         }
    1694          57 :         if (ldb_msg_find_element(req->op.mod.message, "becomeInfrastructureMaster")) {
    1695           4 :                 return rootdse_become_master(module, req, DREPL_INFRASTRUCTURE_MASTER);
    1696             :         }
    1697          53 :         if (ldb_msg_find_element(req->op.mod.message, "becomeRidMaster")) {
    1698           6 :                 return rootdse_become_master(module, req, DREPL_RID_MASTER);
    1699             :         }
    1700          47 :         if (ldb_msg_find_element(req->op.mod.message, "becomeSchemaMaster")) {
    1701           4 :                 return rootdse_become_master(module, req, DREPL_SCHEMA_MASTER);
    1702             :         }
    1703          43 :         if (ldb_msg_find_element(req->op.mod.message, "becomePdc")) {
    1704           4 :                 return rootdse_become_master(module, req, DREPL_PDC_MASTER);
    1705             :         }
    1706          39 :         if (ldb_msg_find_element(req->op.mod.message, "enableOptionalFeature")) {
    1707           0 :                 return rootdse_enableoptionalfeature(module, req);
    1708             :         }
    1709          39 :         if (ldb_msg_find_element(req->op.mod.message, "schemaUpgradeInProgress")) {
    1710          36 :                 return rootdse_schemaupgradeinprogress(module, req);
    1711             :         }
    1712             : 
    1713           3 :         ldb_set_errstring(ldb, "rootdse_modify: unknown attribute to change!");
    1714           3 :         return LDB_ERR_UNWILLING_TO_PERFORM;
    1715             : }
    1716             : 
    1717        1284 : static int rootdse_rename(struct ldb_module *module, struct ldb_request *req)
    1718             : {
    1719        1284 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1720           9 :         int ret;
    1721             : 
    1722        1284 :         ret = rootdse_filter_operations(module, req);
    1723        1284 :         if (ret != LDB_SUCCESS) {
    1724           0 :                 return ret;
    1725             :         }
    1726             : 
    1727        1284 :         ret = rootdse_filter_controls(module, req);
    1728        1284 :         if (ret != LDB_SUCCESS) {
    1729           0 :                 return ret;
    1730             :         }
    1731             : 
    1732             :         /*
    1733             :                 If dn is not "" we should let it pass through
    1734             :         */
    1735        1284 :         if (!ldb_dn_is_null(req->op.rename.olddn)) {
    1736        1284 :                 return ldb_next_request(module, req);
    1737             :         }
    1738             : 
    1739           0 :         ldb_set_errstring(ldb, "rootdse_remove: you cannot rename the rootdse entry!");
    1740           0 :         return LDB_ERR_NO_SUCH_OBJECT;
    1741             : }
    1742             : 
    1743      110697 : static int rootdse_delete(struct ldb_module *module, struct ldb_request *req)
    1744             : {
    1745      110697 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1746         171 :         int ret;
    1747             : 
    1748      110697 :         ret = rootdse_filter_operations(module, req);
    1749      110697 :         if (ret != LDB_SUCCESS) {
    1750           9 :                 return ret;
    1751             :         }
    1752             : 
    1753      110688 :         ret = rootdse_filter_controls(module, req);
    1754      110688 :         if (ret != LDB_SUCCESS) {
    1755           0 :                 return ret;
    1756             :         }
    1757             : 
    1758             :         /*
    1759             :                 If dn is not "" we should let it pass through
    1760             :         */
    1761      110688 :         if (!ldb_dn_is_null(req->op.del.dn)) {
    1762      110687 :                 return ldb_next_request(module, req);
    1763             :         }
    1764             : 
    1765           1 :         ldb_set_errstring(ldb, "rootdse_remove: you cannot delete the rootdse entry!");
    1766           1 :         return LDB_ERR_NO_SUCH_OBJECT;
    1767             : }
    1768             : 
    1769     1649281 : static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
    1770             : {
    1771       95865 :         int ret;
    1772             : 
    1773     1649281 :         ret = rootdse_filter_operations(module, req);
    1774     1649281 :         if (ret != LDB_SUCCESS) {
    1775           0 :                 return ret;
    1776             :         }
    1777             : 
    1778     1649281 :         ret = rootdse_filter_controls(module, req);
    1779     1649281 :         if (ret != LDB_SUCCESS) {
    1780           0 :                 return ret;
    1781             :         }
    1782             : 
    1783     1649281 :         return ldb_next_request(module, req);
    1784             : }
    1785             : 
    1786             : static const struct ldb_module_ops ldb_rootdse_module_ops = {
    1787             :         .name              = "rootdse",
    1788             :         .init_context      = rootdse_init,
    1789             :         .search            = rootdse_search,
    1790             :         .request           = rootdse_request,
    1791             :         .add               = rootdse_add,
    1792             :         .modify            = rootdse_modify,
    1793             :         .rename            = rootdse_rename,
    1794             :         .extended          = rootdse_extended,
    1795             :         .del               = rootdse_delete,
    1796             :         .start_transaction = rootdse_start_trans,
    1797             :         .end_transaction   = rootdse_end_trans,
    1798             :         .del_transaction   = rootdse_del_trans
    1799             : };
    1800             : 
    1801        6040 : int ldb_rootdse_module_init(const char *version)
    1802             : {
    1803        6040 :         LDB_MODULE_CHECK_VERSION(version);
    1804        6040 :         return ldb_register_module(&ldb_rootdse_module_ops);
    1805             : }

Generated by: LCOV version 1.14