LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - dns_notify.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 153 217 70.5 %
Date: 2024-02-28 12:06:22 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /*
       2             :    ldb database library
       3             : 
       4             :    Copyright (C) Samuel Cabrero <samuelcabrero@kernevil.me> 2014
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : /*
      21             :  *  Name: ldb
      22             :  *
      23             :  *  Component: ldb dns_notify module
      24             :  *
      25             :  *  Description: Notify the DNS server when zones are changed, either by direct
      26             :  *               RPC management calls or DRS inbound replication.
      27             :  *
      28             :  *  Author: Samuel Cabrero <samuelcabrero@kernevil.me>
      29             :  */
      30             : 
      31             : #include "includes.h"
      32             : #include "ldb_module.h"
      33             : #include "dsdb/samdb/ldb_modules/util.h"
      34             : #include "dsdb/samdb/samdb.h"
      35             : #include "dsdb/common/proto.h"
      36             : #include "librpc/gen_ndr/ndr_irpc.h"
      37             : #include "lib/messaging/irpc.h"
      38             : #include "librpc/gen_ndr/ndr_irpc_c.h"
      39             : #include "param/param.h"
      40             : #include "util/dlinklist.h"
      41             : 
      42             : #undef strcasecmp
      43             : 
      44             : struct dns_notify_watched_dn {
      45             :         struct dns_notify_watched_dn *next, *prev;
      46             :         struct ldb_dn *dn;
      47             : };
      48             : 
      49             : struct dns_notify_private {
      50             :         struct dns_notify_watched_dn *watched;
      51             :         bool reload_zones;
      52             : };
      53             : 
      54             : struct dns_notify_dnssrv_state {
      55             :         struct imessaging_context *msg_ctx;
      56             :         struct dnssrv_reload_dns_zones r;
      57             : };
      58             : 
      59           0 : static void dns_notify_dnssrv_done(struct tevent_req *req)
      60             : {
      61           0 :         NTSTATUS status;
      62           0 :         struct dns_notify_dnssrv_state *state;
      63             : 
      64           0 :         state = tevent_req_callback_data(req, struct dns_notify_dnssrv_state);
      65             : 
      66           0 :         status = dcerpc_dnssrv_reload_dns_zones_r_recv(req, state);
      67           0 :         if (!NT_STATUS_IS_OK(status)) {
      68           0 :                 DEBUG(1, ("%s: Error notifying dns server: %s\n",
      69             :                       __func__, nt_errstr(status)));
      70             :         }
      71           0 :         imessaging_cleanup(state->msg_ctx);
      72             : 
      73           0 :         talloc_free(req);
      74           0 :         talloc_free(state);
      75           0 : }
      76             : 
      77        1481 : static void dns_notify_dnssrv_send(struct ldb_module *module)
      78             : {
      79          27 :         struct ldb_context *ldb;
      80          27 :         struct loadparm_context *lp_ctx;
      81          27 :         struct dns_notify_dnssrv_state *state;
      82          27 :         struct dcerpc_binding_handle *handle;
      83          27 :         struct tevent_req *req;
      84             : 
      85        1481 :         ldb = ldb_module_get_ctx(module);
      86             : 
      87        1481 :         lp_ctx = ldb_get_opaque(ldb, "loadparm");
      88        1481 :         if (lp_ctx == NULL) {
      89           0 :                 return;
      90             :         }
      91             : 
      92        1481 :         state = talloc_zero(module, struct dns_notify_dnssrv_state);
      93        1481 :         if (state == NULL) {
      94           0 :                 return;
      95             :         }
      96             : 
      97             :         /* Initialize messaging client */
      98        1481 :         state->msg_ctx = imessaging_client_init(state, lp_ctx,
      99             :                                                 ldb_get_event_context(ldb));
     100        1481 :         if (state->msg_ctx == NULL) {
     101           8 :                 ldb_asprintf_errstring(ldb, "Failed to generate client messaging context in %s",
     102             :                                        lpcfg_imessaging_path(state, lp_ctx));
     103           8 :                 talloc_free(state);
     104           8 :                 return;
     105             :         }
     106             : 
     107             :         /* Get a handle to notify the DNS server */
     108        1473 :         handle = irpc_binding_handle_by_name(state, state->msg_ctx,
     109             :                                              "dnssrv",
     110             :                                              &ndr_table_irpc);
     111        1473 :         if (handle == NULL) {
     112         249 :                 imessaging_cleanup(state->msg_ctx);
     113         249 :                 talloc_free(state);
     114         249 :                 return;
     115             :         }
     116             : 
     117             :         /* Send the notifications */
     118        1224 :         req = dcerpc_dnssrv_reload_dns_zones_r_send(state,
     119             :                                                     ldb_get_event_context(ldb),
     120             :                                                     handle,
     121             :                                                     &state->r);
     122        1224 :         if (req == NULL) {
     123           0 :                 imessaging_cleanup(state->msg_ctx);
     124           0 :                 talloc_free(state);
     125           0 :                 return;
     126             :         }
     127        1224 :         tevent_req_set_callback(req, dns_notify_dnssrv_done, state);
     128             : }
     129             : 
     130      920022 : static int dns_notify_add(struct ldb_module *module, struct ldb_request *req)
     131             : {
     132       83765 :         struct ldb_context *ldb;
     133       83765 :         struct dns_notify_private *data;
     134       83765 :         struct dns_notify_watched_dn *w;
     135       83765 :         struct dsdb_schema *schema;
     136       83765 :         const struct dsdb_class *objectclass;
     137             : 
     138      920022 :         if (ldb_dn_is_special(req->op.add.message->dn)) {
     139        1517 :                 return ldb_next_request(module, req);
     140             :         }
     141             : 
     142      918505 :         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
     143      271837 :                 return ldb_next_request(module, req);
     144             :         }
     145             : 
     146      646668 :         ldb = ldb_module_get_ctx(module);
     147      646668 :         data = talloc_get_type(ldb_module_get_private(module),
     148             :                                struct dns_notify_private);
     149      646668 :         if (data == NULL) {
     150           0 :                 return ldb_operr(ldb);
     151             :         }
     152             : 
     153     2584314 :         for (w = data->watched; w; w = w->next) {
     154     1938821 :                 if (ldb_dn_compare_base(w->dn, req->op.add.message->dn) == 0) {
     155       15176 :                         schema = dsdb_get_schema(ldb, req);
     156       15176 :                         if (schema == NULL) {
     157           0 :                                 return ldb_operr(ldb);
     158             :                         }
     159             : 
     160       15176 :                         objectclass = dsdb_get_structural_oc_from_msg(schema, req->op.add.message);
     161       15176 :                         if (objectclass == NULL) {
     162           0 :                                 return ldb_operr(ldb);
     163             :                         }
     164             : 
     165       15176 :                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, "dnsZone") == 0) {
     166        1175 :                                 data->reload_zones = true;
     167        1175 :                                 break;
     168             :                         }
     169             :                 }
     170             :         }
     171             : 
     172      646668 :         return ldb_next_request(module, req);
     173             : }
     174             : 
     175     1274404 : static int dns_notify_modify(struct ldb_module *module, struct ldb_request *req)
     176             : {
     177       30553 :         TALLOC_CTX *tmp_ctx;
     178       30553 :         struct ldb_context *ldb;
     179       30553 :         struct dns_notify_private *data;
     180       30553 :         struct dns_notify_watched_dn *w;
     181       30553 :         struct ldb_dn *dn;
     182       30553 :         struct ldb_result *res;
     183       30553 :         struct dsdb_schema *schema;
     184       30553 :         const struct dsdb_class *objectclass;
     185     1274404 :         const char * const attrs[] = { "objectClass", NULL };
     186       30553 :         int ret;
     187             : 
     188     1274404 :         if (ldb_dn_is_special(req->op.mod.message->dn)) {
     189      226728 :                 return ldb_next_request(module, req);
     190             :         }
     191             : 
     192     1047676 :         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
     193       19184 :                 return ldb_next_request(module, req);
     194             :         }
     195             : 
     196     1028492 :         ldb = ldb_module_get_ctx(module);
     197     1028492 :         data = talloc_get_type(ldb_module_get_private(module),
     198             :                                struct dns_notify_private);
     199     1028492 :         if (data == NULL) {
     200           0 :                 return ldb_operr(ldb);
     201             :         }
     202             : 
     203     1028492 :         tmp_ctx = talloc_new(module);
     204     1028492 :         if (tmp_ctx == NULL) {
     205           0 :                 return ldb_oom(ldb);
     206             :         }
     207             : 
     208     4112195 :         for (w = data->watched; w; w = w->next) {
     209     3084608 :                 if (ldb_dn_compare_base(w->dn, req->op.add.message->dn) == 0) {
     210       10170 :                         dn = ldb_dn_copy(tmp_ctx, req->op.mod.message->dn);
     211             : 
     212       10170 :                         ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
     213             :                                                     DSDB_FLAG_NEXT_MODULE |
     214             :                                                     DSDB_SEARCH_SHOW_RECYCLED |
     215             :                                                     DSDB_SEARCH_REVEAL_INTERNALS |
     216             :                                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
     217       10170 :                         if (ret != LDB_SUCCESS) {
     218             :                                 /* 
     219             :                                  * We want the give the caller the
     220             :                                  * error from trying the actual
     221             :                                  * request, below 
     222             :                                  */
     223           0 :                                 break;
     224             :                         }
     225             : 
     226       10170 :                         schema = dsdb_get_schema(ldb, req);
     227       10170 :                         if (schema == NULL) {
     228           0 :                                 talloc_free(tmp_ctx);
     229           0 :                                 return ldb_operr(ldb);
     230             :                         }
     231             : 
     232       10170 :                         objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]);
     233       10170 :                         if (objectclass == NULL) {
     234           0 :                                 talloc_free(tmp_ctx);
     235           0 :                                 return ldb_operr(ldb);
     236             :                         }
     237             : 
     238       10170 :                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, "dnsZone") == 0) {
     239         905 :                                 data->reload_zones = true;
     240         905 :                                 break;
     241             :                         }
     242             :                 }
     243             :         }
     244             : 
     245     1028492 :         talloc_free(tmp_ctx);
     246     1028492 :         return ldb_next_request(module, req);
     247             : }
     248             : 
     249          17 : static int dns_notify_delete(struct ldb_module *module, struct ldb_request *req)
     250             : {
     251           9 :         TALLOC_CTX *tmp_ctx;
     252           9 :         struct ldb_context *ldb;
     253           9 :         struct dns_notify_private *data;
     254           9 :         struct dns_notify_watched_dn *w;
     255           9 :         struct ldb_dn *old_dn;
     256           9 :         struct ldb_result *res;
     257           9 :         struct dsdb_schema *schema;
     258           9 :         const struct dsdb_class *objectclass;
     259          17 :         const char * const attrs[] = { "objectClass", NULL };
     260           9 :         int ret;
     261             : 
     262          17 :         if (ldb_dn_is_special(req->op.del.dn)) {
     263           1 :                 return ldb_next_request(module, req);
     264             :         }
     265             : 
     266          16 :         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
     267          16 :                 return ldb_next_request(module, req);
     268             :         }
     269             : 
     270           0 :         ldb = ldb_module_get_ctx(module);
     271           0 :         data = talloc_get_type(ldb_module_get_private(module),
     272             :                                struct dns_notify_private);
     273           0 :         if (data == NULL) {
     274           0 :                 return ldb_operr(ldb);
     275             :         }
     276             : 
     277           0 :         tmp_ctx = talloc_new(module);
     278           0 :         if (tmp_ctx == NULL) {
     279           0 :                 return ldb_oom(ldb);
     280             :         }
     281             : 
     282           0 :         for (w = data->watched; w; w = w->next) {
     283           0 :                 if (ldb_dn_compare_base(w->dn, req->op.add.message->dn) == 0) {
     284           0 :                         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
     285           0 :                         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, attrs,
     286             :                                                     DSDB_FLAG_NEXT_MODULE |
     287             :                                                     DSDB_SEARCH_SHOW_RECYCLED |
     288             :                                                     DSDB_SEARCH_REVEAL_INTERNALS |
     289             :                                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
     290           0 :                         if (ret != LDB_SUCCESS) {
     291             :                                 /* 
     292             :                                  * We want the give the caller the
     293             :                                  * error from trying the actual
     294             :                                  * request, below 
     295             :                                  */
     296           0 :                                 break;
     297             :                         }
     298             : 
     299           0 :                         schema = dsdb_get_schema(ldb, req);
     300           0 :                         if (schema == NULL) {
     301           0 :                                 talloc_free(tmp_ctx);
     302           0 :                                 return ldb_operr(ldb);
     303             :                         }
     304             : 
     305           0 :                         objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]);
     306           0 :                         if (objectclass == NULL) {
     307           0 :                                 talloc_free(tmp_ctx);
     308           0 :                                 return ldb_operr(ldb);
     309             :                         }
     310             : 
     311           0 :                         if (ldb_attr_cmp(objectclass->lDAPDisplayName, "dnsZone") == 0) {
     312           0 :                                 data->reload_zones = true;
     313           0 :                                 break;
     314             :                         }
     315             :                 }
     316             :         }
     317             : 
     318           0 :         talloc_free(tmp_ctx);
     319           0 :         return ldb_next_request(module, req);
     320             : }
     321             : 
     322      348931 : static int dns_notify_start_trans(struct ldb_module *module)
     323             : {
     324        2157 :         struct ldb_context *ldb;
     325        2157 :         struct dns_notify_private *data;
     326             : 
     327      348931 :         ldb = ldb_module_get_ctx(module);
     328      348931 :         data = talloc_get_type(ldb_module_get_private(module),
     329             :                                struct dns_notify_private);
     330      348931 :         if (data == NULL) {
     331           0 :                 return ldb_operr(ldb);
     332             :         }
     333             : 
     334      348931 :         data->reload_zones = false;
     335             : 
     336      348931 :         return ldb_next_start_trans(module);
     337             : }
     338             : 
     339      303561 : static int dns_notify_end_trans(struct ldb_module *module)
     340             : {
     341        2152 :         struct ldb_context *ldb;
     342        2152 :         struct dns_notify_private *data;
     343        2152 :         int ret;
     344             : 
     345      303561 :         ldb = ldb_module_get_ctx(module);
     346      303561 :         data = talloc_get_type(ldb_module_get_private(module),
     347             :                                struct dns_notify_private);
     348      303561 :         if (data == NULL) {
     349           0 :                 return ldb_operr(ldb);
     350             :         }
     351             : 
     352      303561 :         ret = ldb_next_end_trans(module);
     353      303561 :         if (ret == LDB_SUCCESS) {
     354      303561 :                 if (data->reload_zones) {
     355        1481 :                         dns_notify_dnssrv_send(module);
     356             :                 }
     357             :         }
     358             : 
     359      301409 :         return ret;
     360             : }
     361             : 
     362       45368 : static int dns_notify_del_trans(struct ldb_module *module)
     363             : {
     364           4 :         struct ldb_context *ldb;
     365           4 :         struct dns_notify_private *data;
     366             : 
     367       45368 :         ldb = ldb_module_get_ctx(module);
     368       45368 :         data = talloc_get_type(ldb_module_get_private(module),
     369             :                                struct dns_notify_private);
     370       45368 :         if (data == NULL) {
     371           0 :                 return ldb_operr(ldb);
     372             :         }
     373             : 
     374       45368 :         data->reload_zones = false;
     375             : 
     376       45368 :         return ldb_next_del_trans(module);
     377             : }
     378             : 
     379      179628 : static int dns_notify_init(struct ldb_module *module)
     380             : {
     381        5993 :         struct ldb_context *ldb;
     382        5993 :         struct dns_notify_private *data;
     383        5993 :         struct dns_notify_watched_dn *watched;
     384        5993 :         struct ldb_dn *domain_dn;
     385        5993 :         struct ldb_dn *forest_dn;
     386             : 
     387      179628 :         ldb = ldb_module_get_ctx(module);
     388             : 
     389      179628 :         data = talloc_zero(module, struct dns_notify_private);
     390      179628 :         if (data == NULL) {
     391           0 :                 return ldb_oom(ldb);
     392             :         }
     393             : 
     394      179628 :         domain_dn = ldb_get_default_basedn(ldb);
     395      179628 :         forest_dn = ldb_get_root_basedn(ldb);
     396             : 
     397             :         /* Register hook on domain partition */
     398      179628 :         watched = talloc_zero(data, struct dns_notify_watched_dn);
     399      179628 :         if (watched == NULL) {
     400           0 :                 talloc_free(data);
     401           0 :                 return ldb_oom(ldb);
     402             :         }
     403      179628 :         watched->dn = ldb_dn_new_fmt(watched, ldb,
     404             :                                      "CN=MicrosoftDNS,CN=System,%s",
     405             :                                      ldb_dn_get_linearized(domain_dn));
     406      179628 :         if (watched->dn == NULL) {
     407           0 :                 talloc_free(data);
     408           0 :                 return ldb_oom(ldb);
     409             :         }
     410      179628 :         DLIST_ADD(data->watched, watched);
     411             : 
     412             :         /* Check for DomainDnsZones partition and register hook */
     413      179628 :         watched = talloc_zero(data, struct dns_notify_watched_dn);
     414      179628 :         if (watched == NULL) {
     415           0 :                 talloc_free(data);
     416           0 :                 return ldb_oom(ldb);
     417             :         }
     418      179628 :         watched->dn = ldb_dn_new_fmt(watched, ldb, "CN=MicrosoftDNS,DC=DomainDnsZones,%s", ldb_dn_get_linearized(forest_dn));
     419      179628 :         DLIST_ADD(data->watched, watched);
     420             : 
     421             :         /* Check for ForestDnsZones partition and register hook */
     422      179628 :         watched = talloc_zero(data, struct dns_notify_watched_dn);
     423      179628 :         if (watched == NULL) {
     424           0 :                 talloc_free(data);
     425           0 :                 return ldb_oom(ldb);
     426             :         }
     427      179628 :         watched->dn = ldb_dn_new_fmt(watched, ldb, "CN=MicrosoftDNS,DC=ForestDnsZones,%s", ldb_dn_get_linearized(forest_dn));
     428      179628 :         DLIST_ADD(data->watched, watched);
     429             : 
     430      179628 :         ldb_module_set_private(module, data);
     431             : 
     432      179628 :         return ldb_next_init(module);
     433             : }
     434             : 
     435             : static const struct ldb_module_ops ldb_dns_notify_module_ops = {
     436             :         .name              = "dns_notify",
     437             :         .init_context      = dns_notify_init,
     438             :         .add               = dns_notify_add,
     439             :         .modify            = dns_notify_modify,
     440             :         .del               = dns_notify_delete,
     441             :         .start_transaction = dns_notify_start_trans,
     442             :         .end_transaction   = dns_notify_end_trans,
     443             :         .del_transaction   = dns_notify_del_trans,
     444             : };
     445             : 
     446        5922 : int ldb_dns_notify_module_init(const char *version)
     447             : {
     448        5922 :         LDB_MODULE_CHECK_VERSION(version);
     449        5922 :         return ldb_register_module(&ldb_dns_notify_module_ops);
     450             : }

Generated by: LCOV version 1.14