LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - rootdse.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 506 782 64.7 %
Date: 2021-09-23 10:06:22 Functions: 28 35 80.0 %

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

Generated by: LCOV version 1.13