LCOV - code coverage report
Current view: top level - source4/dsdb/kcc - kcc_periodic.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 92 360 25.6 %
Date: 2021-09-23 10:06:22 Functions: 8 22 36.4 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS Implementation.
       3             :    KCC service periodic handling
       4             :    
       5             :    Copyright (C) Andrew Tridgell 2009
       6             :    based on repl service code
       7             :     
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             :    
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "lib/events/events.h"
      25             : #include "dsdb/samdb/samdb.h"
      26             : #include "auth/auth.h"
      27             : #include "samba/service.h"
      28             : #include "lib/messaging/irpc.h"
      29             : #include "dsdb/kcc/kcc_connection.h"
      30             : #include "dsdb/kcc/kcc_service.h"
      31             : #include <ldb_errors.h>
      32             : #include "../lib/util/dlinklist.h"
      33             : #include "librpc/gen_ndr/ndr_misc.h"
      34             : #include "librpc/gen_ndr/ndr_drsuapi.h"
      35             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      36             : #include "librpc/gen_ndr/ndr_irpc_c.h"
      37             : #include "param/param.h"
      38             : #include "dsdb/common/util.h"
      39             : 
      40             : /*
      41             :  * see if two repsFromToBlob blobs are for the same source DSA
      42             :  */
      43           0 : static bool kccsrv_same_source_dsa(struct repsFromToBlob *r1, struct repsFromToBlob *r2)
      44             : {
      45           0 :         return GUID_equal(&r1->ctr.ctr1.source_dsa_obj_guid,
      46           0 :                           &r2->ctr.ctr1.source_dsa_obj_guid);
      47             : }
      48             : 
      49             : /*
      50             :  * see if a repsFromToBlob is in a list
      51             :  */
      52           0 : static bool reps_in_list(struct repsFromToBlob *r, struct repsFromToBlob *reps, uint32_t count)
      53             : {
      54             :         uint32_t i;
      55           0 :         for (i=0; i<count; i++) {
      56           0 :                 if (kccsrv_same_source_dsa(r, &reps[i])) {
      57           0 :                         return true;
      58             :                 }
      59             :         }
      60           0 :         return false;
      61             : }
      62             : 
      63             : /*
      64             :   make sure we only add repsFrom entries for DCs who are masters for
      65             :   the partition
      66             :  */
      67           0 : static bool check_MasterNC(struct kccsrv_service *service, struct dsdb_ldb_dn_list_node *p, struct repsFromToBlob *r,
      68             :                            struct ldb_result *res)
      69             : {
      70           0 :         struct repsFromTo1 *r1 = &r->ctr.ctr1;
      71           0 :         struct GUID invocation_id = r1->source_dsa_invocation_id;
      72             :         unsigned int i, j;
      73             :         TALLOC_CTX *tmp_ctx;
      74             : 
      75             :         /* we are expecting only version 1 */
      76           0 :         SMB_ASSERT(r->version == 1);
      77             : 
      78           0 :         tmp_ctx = talloc_new(p);
      79           0 :         if (!tmp_ctx) {
      80           0 :                 return false;
      81             :         }
      82             : 
      83           0 :         for (i=0; i<res->count; i++) {
      84           0 :                 struct ldb_message *msg = res->msgs[i];
      85             :                 struct ldb_message_element *el;
      86             :                 struct ldb_dn *dn;
      87             : 
      88           0 :                 struct GUID id2 = samdb_result_guid(msg, "invocationID");
      89           0 :                 if (GUID_all_zero(&id2) ||
      90           0 :                     !GUID_equal(&invocation_id, &id2)) {
      91           0 :                         continue;
      92             :                 }
      93             : 
      94           0 :                 el = ldb_msg_find_element(msg, "msDS-hasMasterNCs");
      95           0 :                 if (!el || el->num_values == 0) {
      96           0 :                         el = ldb_msg_find_element(msg, "hasMasterNCs");
      97           0 :                         if (!el || el->num_values == 0) {
      98           0 :                                 continue;
      99             :                         }
     100             :                 }
     101           0 :                 for (j=0; j<el->num_values; j++) {
     102           0 :                         dn = ldb_dn_from_ldb_val(tmp_ctx, service->samdb, &el->values[j]);
     103           0 :                         if (!ldb_dn_validate(dn)) {
     104           0 :                                 talloc_free(dn);
     105           0 :                                 continue;
     106             :                         }
     107           0 :                         if (ldb_dn_compare(dn, p->dn) == 0) {
     108           0 :                                 DEBUG(5,("%s %s match on %s in %s\n",
     109             :                                          r1->other_info->dns_name,
     110             :                                          el->name,
     111             :                                          ldb_dn_get_linearized(dn),
     112             :                                          ldb_dn_get_linearized(msg->dn)));
     113           0 :                                 talloc_free(tmp_ctx);
     114           0 :                                 return true;
     115             :                         }
     116           0 :                         talloc_free(dn);
     117             :                 }
     118             :         }
     119           0 :         talloc_free(tmp_ctx);
     120           0 :         return false;
     121             : }
     122             : 
     123             : struct kccsrv_notify_drepl_server_state {
     124             :         struct dreplsrv_refresh r;
     125             : };
     126             : 
     127             : static void kccsrv_notify_drepl_server_done(struct tevent_req *subreq);
     128             : 
     129             : /**
     130             :  * Force dreplsrv to update its state as topology is changed
     131             :  */
     132           0 : static void kccsrv_notify_drepl_server(struct kccsrv_service *s,
     133             :                                        TALLOC_CTX *mem_ctx)
     134             : {
     135             :         struct kccsrv_notify_drepl_server_state *state;
     136             :         struct dcerpc_binding_handle *irpc_handle;
     137             :         struct tevent_req *subreq;
     138             : 
     139           0 :         state = talloc_zero(s, struct kccsrv_notify_drepl_server_state);
     140           0 :         if (state == NULL) {
     141           0 :                 return;
     142             :         }
     143             : 
     144           0 :         irpc_handle = irpc_binding_handle_by_name(state, s->task->msg_ctx,
     145             :                                                   "dreplsrv", &ndr_table_irpc);
     146           0 :         if (irpc_handle == NULL) {
     147             :                 /* dreplsrv is not running yet */
     148           0 :                 TALLOC_FREE(state);
     149           0 :                 return;
     150             :         }
     151             : 
     152           0 :         subreq = dcerpc_dreplsrv_refresh_r_send(state, s->task->event_ctx,
     153             :                                                 irpc_handle, &state->r);
     154           0 :         if (subreq == NULL) {
     155           0 :                 TALLOC_FREE(state);
     156           0 :                 return;
     157             :         }
     158           0 :         tevent_req_set_callback(subreq, kccsrv_notify_drepl_server_done, state);
     159             : }
     160             : 
     161           0 : static void kccsrv_notify_drepl_server_done(struct tevent_req *subreq)
     162             : {
     163           0 :         struct kccsrv_notify_drepl_server_state *state =
     164           0 :                 tevent_req_callback_data(subreq,
     165             :                 struct kccsrv_notify_drepl_server_state);
     166             : 
     167           0 :         dcerpc_dreplsrv_refresh_r_recv(subreq, state);
     168           0 :         TALLOC_FREE(subreq);
     169             : 
     170             :         /* we don't care about errors */
     171           0 :         TALLOC_FREE(state);
     172           0 : }
     173             : 
     174           0 : uint32_t kccsrv_replica_flags(struct kccsrv_service *s)
     175             : {
     176           0 :         if (s->am_rodc) {
     177           0 :                 return DRSUAPI_DRS_INIT_SYNC |
     178             :                         DRSUAPI_DRS_PER_SYNC |
     179             :                         DRSUAPI_DRS_ADD_REF |
     180             :                         DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |
     181             :                         DRSUAPI_DRS_NONGC_RO_REP;
     182             :         }
     183           0 :         return DRSUAPI_DRS_INIT_SYNC |
     184             :                 DRSUAPI_DRS_PER_SYNC |
     185             :                 DRSUAPI_DRS_ADD_REF |
     186             :                 DRSUAPI_DRS_WRIT_REP;
     187             : }
     188             : 
     189             : /*
     190             :  * add any missing repsFrom structures to our partitions
     191             :  */
     192           0 : NTSTATUS kccsrv_add_repsFrom(struct kccsrv_service *s, TALLOC_CTX *mem_ctx,
     193             :                             struct repsFromToBlob *reps, uint32_t count,
     194             :                             struct ldb_result *res)
     195             : {
     196             :         struct dsdb_ldb_dn_list_node *p;
     197           0 :         bool notify_dreplsrv = false;
     198           0 :         uint32_t replica_flags = kccsrv_replica_flags(s);
     199             : 
     200             :         /* update the repsFrom on all partitions */
     201           0 :         for (p=s->partitions; p; p=p->next) {
     202             :                 struct repsFromToBlob *our_reps;
     203             :                 uint32_t our_count;
     204             :                 WERROR werr;
     205             :                 uint32_t i, j;
     206           0 :                 bool modified = false;
     207             : 
     208           0 :                 werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsFrom", &our_reps, &our_count);
     209           0 :                 if (!W_ERROR_IS_OK(werr)) {
     210           0 :                         DEBUG(0,(__location__ ": Failed to load repsFrom from %s - %s\n", 
     211             :                                  ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb)));
     212           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     213             :                 }
     214             : 
     215             :                 /* see if the entry already exists */
     216           0 :                 for (i=0; i<count; i++) {
     217           0 :                         for (j=0; j<our_count; j++) {
     218           0 :                                 if (kccsrv_same_source_dsa(&reps[i], &our_reps[j])) {
     219             :                                         /* we already have this one -
     220             :                                            check the replica_flags are right */
     221           0 :                                         if (replica_flags != our_reps[j].ctr.ctr1.replica_flags) {
     222             :                                                 /* we need to update the old one with
     223             :                                                  * the new flags
     224             :                                                  */
     225           0 :                                                 our_reps[j].ctr.ctr1.replica_flags = replica_flags;
     226           0 :                                                 modified = true;
     227             :                                         }
     228           0 :                                         break;
     229             :                                 }
     230             :                         }
     231           0 :                         if (j == our_count) {
     232             :                                 /* we don't have the new one - add it
     233             :                                  * if it is a master
     234             :                                  */
     235           0 :                                 if (res && !check_MasterNC(s, p, &reps[i], res)) {
     236             :                                         /* its not a master, we don't
     237             :                                            want to pull from it */
     238           0 :                                         continue;
     239             :                                 }
     240             :                                 /* we need to add it to our repsFrom */
     241           0 :                                 our_reps = talloc_realloc(mem_ctx, our_reps, struct repsFromToBlob, our_count+1);
     242           0 :                                 NT_STATUS_HAVE_NO_MEMORY(our_reps);
     243           0 :                                 our_reps[our_count] = reps[i];
     244           0 :                                 our_reps[our_count].ctr.ctr1.replica_flags = replica_flags;
     245           0 :                                 our_count++;
     246           0 :                                 modified = true;
     247           0 :                                 DEBUG(4,(__location__ ": Added repsFrom for %s\n",
     248             :                                          reps[i].ctr.ctr1.other_info->dns_name));
     249             :                         }
     250             :                 }
     251             : 
     252             :                 /* remove any stale ones */
     253           0 :                 for (i=0; i<our_count; i++) {
     254           0 :                         if (!reps_in_list(&our_reps[i], reps, count) ||
     255           0 :                             (res && !check_MasterNC(s, p, &our_reps[i], res))) {
     256           0 :                                 DEBUG(4,(__location__ ": Removed repsFrom for %s\n",
     257             :                                          our_reps[i].ctr.ctr1.other_info->dns_name));
     258           0 :                                 memmove(&our_reps[i], &our_reps[i+1], (our_count-(i+1))*sizeof(our_reps[0]));
     259           0 :                                 our_count--;
     260           0 :                                 i--;
     261           0 :                                 modified = true;
     262             :                         }
     263             :                 }
     264             : 
     265           0 :                 if (modified) {
     266           0 :                         werr = dsdb_savereps(s->samdb, mem_ctx, p->dn, "repsFrom", our_reps, our_count);
     267           0 :                         if (!W_ERROR_IS_OK(werr)) {
     268           0 :                                 DEBUG(0,(__location__ ": Failed to save repsFrom to %s - %s\n", 
     269             :                                          ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb)));
     270           0 :                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     271             :                         }
     272             :                         /* dreplsrv should refresh its state */
     273           0 :                         notify_dreplsrv = true;
     274             :                 }
     275             : 
     276             :                 /* remove stale repsTo entries */
     277           0 :                 modified = false;
     278           0 :                 werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsTo", &our_reps, &our_count);
     279           0 :                 if (!W_ERROR_IS_OK(werr)) {
     280           0 :                         DEBUG(0,(__location__ ": Failed to load repsTo from %s - %s\n", 
     281             :                                  ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb)));
     282           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     283             :                 }
     284             : 
     285             :                 /* remove any stale ones */
     286           0 :                 for (i=0; i<our_count; i++) {
     287           0 :                         if (!reps_in_list(&our_reps[i], reps, count)) {
     288           0 :                                 DEBUG(4,(__location__ ": Removed repsTo for %s\n",
     289             :                                          our_reps[i].ctr.ctr1.other_info->dns_name));
     290           0 :                                 memmove(&our_reps[i], &our_reps[i+1], (our_count-(i+1))*sizeof(our_reps[0]));
     291           0 :                                 our_count--;
     292           0 :                                 i--;
     293           0 :                                 modified = true;
     294             :                         }
     295             :                 }
     296             : 
     297           0 :                 if (modified) {
     298           0 :                         werr = dsdb_savereps(s->samdb, mem_ctx, p->dn, "repsTo", our_reps, our_count);
     299           0 :                         if (!W_ERROR_IS_OK(werr)) {
     300           0 :                                 DEBUG(0,(__location__ ": Failed to save repsTo to %s - %s\n", 
     301             :                                          ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb)));
     302           0 :                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     303             :                         }
     304             :                         /* dreplsrv should refresh its state */
     305           0 :                         notify_dreplsrv = true;
     306             :                 }
     307             :         }
     308             : 
     309             :         /* notify dreplsrv toplogy has changed */
     310           0 :         if (notify_dreplsrv) {
     311           0 :                 kccsrv_notify_drepl_server(s, mem_ctx);
     312             :         }
     313             : 
     314           0 :         return NT_STATUS_OK;
     315             : 
     316             : }
     317             : 
     318             : 
     319             : /*
     320             :   form a unique list of DNs from a search result and a given set of attributes
     321             :  */
     322           0 : static int kccsrv_dn_list(struct ldb_context *ldb, struct ldb_result *res,
     323             :                           TALLOC_CTX *mem_ctx,
     324             :                           const char **attrs,
     325             :                           struct ldb_dn ***dn_list, int *dn_count)
     326             : {
     327             :         int i;
     328           0 :         struct ldb_dn **nc_list = NULL;
     329           0 :         int nc_count = 0;
     330             : 
     331           0 :         nc_list = talloc_array(mem_ctx, struct ldb_dn *, 0);
     332           0 :         if (nc_list == NULL) {
     333           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     334             :         }
     335             : 
     336             :         /* gather up a list of all NCs in this forest */
     337           0 :         for (i=0; i<res->count; i++) {
     338           0 :                 struct ldb_message *msg = res->msgs[i];
     339             :                 int j;
     340           0 :                 for (j=0; attrs[j]; j++) {
     341             :                         struct ldb_message_element *el;
     342             :                         int k;
     343             : 
     344           0 :                         el = ldb_msg_find_element(msg, attrs[j]);
     345           0 :                         if (el == NULL) continue;
     346           0 :                         for (k=0; k<el->num_values; k++) {
     347             :                                 struct ldb_dn *dn;
     348           0 :                                 dn = ldb_dn_from_ldb_val(nc_list, ldb, &el->values[k]);
     349           0 :                                 if (dn != NULL) {
     350             :                                         int l;
     351           0 :                                         for (l=0; l<nc_count; l++) {
     352           0 :                                                 if (ldb_dn_compare(nc_list[l], dn) == 0) break;
     353             :                                         }
     354           0 :                                         if (l < nc_count) continue;
     355           0 :                                         nc_list = talloc_realloc(mem_ctx, nc_list, struct ldb_dn *, nc_count+1);
     356           0 :                                         if (nc_list == NULL) {
     357           0 :                                                 return LDB_ERR_OPERATIONS_ERROR;
     358             :                                         }
     359           0 :                                         nc_list[nc_count] = dn;
     360           0 :                                         nc_count++;
     361             :                                 }
     362             :                         }
     363             :                 }
     364             :         }
     365             : 
     366           0 :         (*dn_list) = nc_list;
     367           0 :         (*dn_count) = nc_count;
     368           0 :         return LDB_SUCCESS;
     369             : }
     370             : 
     371             : 
     372             : /*
     373             :   look for any additional global catalog partitions that we should be
     374             :   replicating (by looking for msDS-HasDomainNCs), and add them to our
     375             :   hasPartialReplicaNCs NTDS attribute
     376             :  */
     377           0 : static int kccsrv_gc_update(struct kccsrv_service *s, struct ldb_result *res)
     378             : {
     379             :         int i;
     380           0 :         struct ldb_dn **nc_list = NULL;
     381           0 :         int nc_count = 0;
     382           0 :         struct ldb_dn **our_nc_list = NULL;
     383           0 :         int our_nc_count = 0;
     384           0 :         const char *attrs1[] = { "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", NULL };
     385           0 :         const char *attrs2[] = { "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", "hasPartialReplicaNCs", NULL };
     386             :         int ret;
     387           0 :         TALLOC_CTX *tmp_ctx = talloc_new(res);
     388             :         struct ldb_result *res2;
     389             :         struct ldb_message *msg;
     390             : 
     391             :         /* get a complete list of NCs for the forest */
     392           0 :         ret = kccsrv_dn_list(s->samdb, res, tmp_ctx, attrs1, &nc_list, &nc_count);
     393           0 :         if (ret != LDB_SUCCESS) {
     394           0 :                 DEBUG(1,("Failed to get NC list for GC update - %s\n", ldb_errstring(s->samdb)));
     395           0 :                 talloc_free(tmp_ctx);
     396           0 :                 return ret;
     397             :         }
     398             : 
     399             :         /* get a list of what NCs we are already replicating */
     400           0 :         ret = dsdb_search_dn(s->samdb, tmp_ctx, &res2, samdb_ntds_settings_dn(s->samdb, tmp_ctx), attrs2, 0);
     401           0 :         if (ret != LDB_SUCCESS) {
     402           0 :                 DEBUG(1,("Failed to get our NC list attributes for GC update - %s\n", ldb_errstring(s->samdb)));
     403           0 :                 talloc_free(tmp_ctx);
     404           0 :                 return ret;
     405             :         }
     406             : 
     407           0 :         ret = kccsrv_dn_list(s->samdb, res2, tmp_ctx, attrs2, &our_nc_list, &our_nc_count);
     408           0 :         if (ret != LDB_SUCCESS) {
     409           0 :                 DEBUG(1,("Failed to get our NC list for GC update - %s\n", ldb_errstring(s->samdb)));
     410           0 :                 talloc_free(tmp_ctx);
     411           0 :                 return ret;
     412             :         }
     413             : 
     414           0 :         msg = ldb_msg_new(tmp_ctx);
     415           0 :         if (msg == NULL) {
     416           0 :                 talloc_free(tmp_ctx);
     417           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     418             :         }
     419           0 :         msg->dn = res2->msgs[0]->dn;
     420             : 
     421             :         /* see if we are missing any */
     422           0 :         for (i=0; i<nc_count; i++) {
     423             :                 int j;
     424           0 :                 for (j=0; j<our_nc_count; j++) {
     425           0 :                         if (ldb_dn_compare(nc_list[i], our_nc_list[j]) == 0) break;
     426             :                 }
     427           0 :                 if (j == our_nc_count) {
     428             :                         /* its a new one */
     429           0 :                         ret = ldb_msg_add_string(msg, "hasPartialReplicaNCs",
     430           0 :                                                  ldb_dn_get_extended_linearized(msg, nc_list[i], 1));
     431           0 :                         if (ret != LDB_SUCCESS) {
     432           0 :                                 talloc_free(tmp_ctx);
     433           0 :                                 return ret;
     434             :                         }
     435             : 
     436             :                 }
     437             :         }
     438             : 
     439           0 :         if (msg->num_elements == 0) {
     440             :                 /* none to add */
     441           0 :                 talloc_free(tmp_ctx);
     442           0 :                 return LDB_SUCCESS;
     443             :         }
     444             : 
     445           0 :         if (s->am_rodc) {
     446           0 :                 DEBUG(5, ("%d partial replica should be added but we are RODC so we skip\n", msg->num_elements));
     447           0 :                 talloc_free(tmp_ctx);
     448           0 :                 return LDB_SUCCESS;
     449             :         }
     450             : 
     451           0 :         msg->elements[0].flags = LDB_FLAG_MOD_ADD;
     452             : 
     453           0 :         ret = dsdb_modify(s->samdb, msg, 0);
     454           0 :         if (ret != LDB_SUCCESS) {
     455           0 :                 DEBUG(0,("Failed to add hasPartialReplicaNCs - %s\n",
     456             :                          ldb_errstring(s->samdb)));
     457             :         }
     458             : 
     459           0 :         talloc_free(tmp_ctx);
     460           0 :         return ret;
     461             : }
     462             : 
     463             : 
     464             : /*
     465             :   this is the core of our initial simple KCC
     466             :   We just add a repsFrom entry for all DCs we find that have nTDSDSA
     467             :   objects, except for ourselves
     468             :  */
     469           0 : NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_ctx)
     470             : {
     471             :         struct ldb_result *res;
     472             :         unsigned int i;
     473             :         int ret;
     474           0 :         const char *attrs[] = { "objectGUID", "invocationID", "msDS-hasMasterNCs", "hasMasterNCs", "msDS-HasDomainNCs", NULL };
     475           0 :         struct repsFromToBlob *reps = NULL;
     476           0 :         uint32_t count = 0;
     477             :         struct kcc_connection_list *ntds_conn, *dsa_conn;
     478             : 
     479           0 :         ret = dsdb_search(s->samdb, mem_ctx, &res, s->config_dn, LDB_SCOPE_SUBTREE,
     480             :                           attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "objectClass=nTDSDSA");
     481           0 :         if (ret != LDB_SUCCESS) {
     482           0 :                 DEBUG(0,(__location__ ": Failed nTDSDSA search - %s\n", ldb_errstring(s->samdb)));
     483           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     484             :         }
     485             : 
     486           0 :         if (samdb_is_gc(s->samdb)) {
     487           0 :                 kccsrv_gc_update(s, res);
     488             :         }
     489             : 
     490             :         /* get the current list of connections */
     491           0 :         ntds_conn = kccsrv_find_connections(s, mem_ctx);
     492             : 
     493           0 :         dsa_conn = talloc_zero(mem_ctx, struct kcc_connection_list);
     494             : 
     495           0 :         for (i=0; i<res->count; i++) {
     496             :                 struct repsFromTo1 *r1;
     497             :                 struct GUID ntds_guid, invocation_id;
     498             : 
     499           0 :                 ntds_guid = samdb_result_guid(res->msgs[i], "objectGUID");
     500           0 :                 if (GUID_equal(&ntds_guid, &s->ntds_guid)) {
     501             :                         /* don't replicate with ourselves */
     502           0 :                         continue;
     503             :                 }
     504             : 
     505           0 :                 invocation_id = samdb_result_guid(res->msgs[i], "invocationID");
     506             : 
     507           0 :                 reps = talloc_realloc(mem_ctx, reps, struct repsFromToBlob, count+1);
     508           0 :                 NT_STATUS_HAVE_NO_MEMORY(reps);
     509             : 
     510           0 :                 ZERO_STRUCT(reps[count]);
     511           0 :                 reps[count].version = 1;
     512           0 :                 r1 = &reps[count].ctr.ctr1;
     513             : 
     514           0 :                 r1->other_info               = talloc_zero(reps, struct repsFromTo1OtherInfo);
     515           0 :                 r1->other_info->dns_name     = samdb_ntds_msdcs_dns_name(s->samdb, reps, &ntds_guid);
     516           0 :                 r1->source_dsa_obj_guid      = ntds_guid;
     517           0 :                 r1->source_dsa_invocation_id = invocation_id;
     518           0 :                 r1->replica_flags = kccsrv_replica_flags(s);
     519           0 :                 memset(r1->schedule, 0x11, sizeof(r1->schedule));
     520             : 
     521           0 :                 dsa_conn->servers = talloc_realloc(dsa_conn, dsa_conn->servers,
     522             :                                                   struct kcc_connection,
     523             :                                                   dsa_conn->count + 1);
     524           0 :                 NT_STATUS_HAVE_NO_MEMORY(dsa_conn->servers);
     525           0 :                 dsa_conn->servers[dsa_conn->count].dsa_guid = r1->source_dsa_obj_guid;
     526           0 :                 dsa_conn->count++;
     527             : 
     528           0 :                 count++;
     529             :         }
     530             : 
     531           0 :         kccsrv_apply_connections(s, ntds_conn, dsa_conn);
     532             : 
     533           0 :         return kccsrv_add_repsFrom(s, mem_ctx, reps, count, res);
     534             : }
     535             : 
     536             : 
     537             : static void kccsrv_periodic_run(struct kccsrv_service *service);
     538             : 
     539         296 : static void kccsrv_periodic_handler_te(struct tevent_context *ev, struct tevent_timer *te,
     540             :                                          struct timeval t, void *ptr)
     541             : {
     542         296 :         struct kccsrv_service *service = talloc_get_type(ptr, struct kccsrv_service);
     543             :         WERROR status;
     544             : 
     545         296 :         service->periodic.te = NULL;
     546             : 
     547         296 :         kccsrv_periodic_run(service);
     548             : 
     549         296 :         status = kccsrv_periodic_schedule(service, service->periodic.interval);
     550         296 :         if (!W_ERROR_IS_OK(status)) {
     551           0 :                 task_server_terminate(service->task, win_errstr(status), true);
     552           0 :                 return;
     553             :         }
     554             : }
     555             : 
     556         353 : WERROR kccsrv_periodic_schedule(struct kccsrv_service *service, uint32_t next_interval)
     557             : {
     558             :         TALLOC_CTX *tmp_mem;
     559             :         struct tevent_timer *new_te;
     560             :         struct timeval next_time;
     561             : 
     562             :         /* prevent looping */
     563         353 :         if (next_interval == 0) next_interval = 1;
     564             : 
     565         353 :         next_time = timeval_current_ofs(next_interval, 50);
     566             : 
     567         353 :         if (service->periodic.te) {
     568             :                 /*
     569             :                  * if the timestamp of the new event is higher,
     570             :                  * as current next we don't need to reschedule
     571             :                  */
     572           0 :                 if (timeval_compare(&next_time, &service->periodic.next_event) > 0) {
     573           0 :                         return WERR_OK;
     574             :                 }
     575             :         }
     576             : 
     577             :         /* reset the next scheduled timestamp */
     578         353 :         service->periodic.next_event = next_time;
     579             : 
     580         353 :         new_te = tevent_add_timer(service->task->event_ctx, service,
     581             :                                  service->periodic.next_event,
     582             :                                  kccsrv_periodic_handler_te, service);
     583         353 :         W_ERROR_HAVE_NO_MEMORY(new_te);
     584             : 
     585         353 :         tmp_mem = talloc_new(service);
     586         353 :         DEBUG(4,("kccsrv_periodic_schedule(%u) %sscheduled for: %s\n",
     587             :                 next_interval,
     588             :                 (service->periodic.te?"re":""),
     589             :                 nt_time_string(tmp_mem, timeval_to_nttime(&next_time))));
     590         353 :         talloc_free(tmp_mem);
     591             : 
     592         353 :         talloc_free(service->periodic.te);
     593         353 :         service->periodic.te = new_te;
     594             : 
     595         353 :         return WERR_OK;
     596             : }
     597             : 
     598             : /*
     599             :  * Check to see if any dns entries need scavenging. This only occurs if aging
     600             :  * is enabled in general ("zone scavenging" lpcfg) and on the zone
     601             :  * (zone->fAging is true).
     602             :  */
     603         296 : static NTSTATUS kccsrv_dns_zone_scavenging(
     604             :         struct kccsrv_service *s,
     605             :         TALLOC_CTX *mem_ctx)
     606             : {
     607             : 
     608         296 :         time_t current_time = time(NULL);
     609             :         time_t dns_scavenge_interval;
     610             :         NTSTATUS status;
     611         296 :         char *error_string = NULL;
     612             : 
     613             :         /*
     614             :          * Only perform zone scavenging if it's been enabled.
     615             :          * (it still might be disabled on all zones).
     616             :          */
     617         296 :         if (!lpcfg_dns_zone_scavenging(s->task->lp_ctx)) {
     618         296 :                 DBG_INFO("DNS scavenging not enabled");
     619         296 :                 return NT_STATUS_OK;
     620             :         }
     621             : 
     622           0 :         dns_scavenge_interval = lpcfg_parm_int(s->task->lp_ctx,
     623             :                                                NULL,
     624             :                                                "dnsserver",
     625             :                                                "scavenging_interval",
     626             :                                                2 * 60 * 60);
     627           0 :         if ((current_time - s->last_dns_scavenge) > dns_scavenge_interval) {
     628           0 :                 s->last_dns_scavenge = current_time;
     629           0 :                 status = dns_tombstone_records(mem_ctx, s->samdb,
     630             :                                                &error_string);
     631           0 :                 if (!NT_STATUS_IS_OK(status)) {
     632           0 :                         const char *err = NULL;
     633           0 :                         if (error_string != NULL) {
     634           0 :                                 err = error_string;
     635             :                         } else {
     636           0 :                                 err = nt_errstr(status);
     637             :                         }
     638           0 :                         DBG_ERR("DNS record scavenging process failed: %s",
     639             :                                 err);
     640           0 :                         return status;
     641             :                 }
     642             :         }
     643           0 :         DBG_INFO("Successfully tombstoned stale DNS records");
     644           0 :         return NT_STATUS_OK;
     645             : }
     646             : /*
     647             :  * check to see if any dns tombstones should be deleted. This is not optional
     648             :  * ([MS-DNSP] "DsTombstoneInterval") -- stale tombstones are useless clutter.
     649             :  *
     650             :  * Windows does it daily at 2am; we do it roughly daily at an uncontrolled
     651             :  * time.
     652             :  */
     653         296 : static NTSTATUS kccsrv_dns_zone_tombstone_deletion(struct kccsrv_service *s,
     654             :                                                    TALLOC_CTX *mem_ctx)
     655             : {
     656         296 :         time_t current_time = time(NULL);
     657             :         NTSTATUS status;
     658         296 :         char *error_string = NULL;
     659         296 :         time_t dns_collection_interval =
     660         296 :                 lpcfg_parm_int(s->task->lp_ctx,
     661             :                                NULL,
     662             :                                "dnsserver",
     663             :                                "tombstone_collection_interval",
     664             :                                24 * 60 * 60);
     665             : 
     666         296 :         if ((current_time - s->last_dns_tombstone_collection) >
     667             :             dns_collection_interval) {
     668          57 :                 s->last_dns_tombstone_collection = current_time;
     669          57 :                 status = dns_delete_tombstones(mem_ctx, s->samdb,
     670             :                                                &error_string);
     671          57 :                 if (!NT_STATUS_IS_OK(status)) {
     672           0 :                         const char *err = NULL;
     673           0 :                         if (error_string != NULL) {
     674           0 :                                 err = error_string;
     675             :                         } else {
     676           0 :                                 err = nt_errstr(status);
     677             :                         }
     678           0 :                         DBG_ERR("DNS tombstone deletion failed: %s", err);
     679           0 :                         return status;
     680             :                 }
     681             :         }
     682         296 :         DBG_INFO("Successfully deleted DNS tombstones");
     683         296 :         return NT_STATUS_OK;
     684             : }
     685             : 
     686             : /*
     687             :   check to see if any deleted objects need scavenging
     688             :  */
     689         296 : static NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx)
     690             : {
     691         296 :         time_t current_time = time(NULL);
     692         373 :         time_t interval = lpcfg_parm_int(
     693         296 :             s->task->lp_ctx, NULL, "kccsrv", "check_deleted_interval", 86400);
     694             :         uint32_t tombstoneLifetime;
     695             :         int ret;
     696         296 :         unsigned int num_objects_removed = 0;
     697         296 :         unsigned int num_links_removed = 0;
     698             :         NTSTATUS status;
     699         296 :         char *error_string = NULL;
     700             : 
     701         296 :         if (current_time - s->last_deleted_check < interval) {
     702         239 :                 return NT_STATUS_OK;
     703             :         }
     704             : 
     705          57 :         ret = dsdb_tombstone_lifetime(s->samdb, &tombstoneLifetime);
     706          57 :         if (ret != LDB_SUCCESS) {
     707           0 :                 DEBUG(1,(__location__ ": Failed to get tombstone lifetime\n"));
     708           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     709             :         }
     710             : 
     711          57 :         s->last_deleted_check = current_time;
     712             : 
     713          57 :         status = dsdb_garbage_collect_tombstones(mem_ctx, s->samdb,
     714             :                                                  s->partitions,
     715             :                                                  current_time, tombstoneLifetime,
     716             :                                                  &num_objects_removed,
     717             :                                                  &num_links_removed,
     718             :                                                  &error_string);
     719             : 
     720          57 :         if (NT_STATUS_IS_OK(status)) {
     721          57 :                 DEBUG(5, ("garbage_collect_tombstones: Removed %u tombstone objects "
     722             :                           "and %u tombstone links successfully\n",
     723             :                           num_objects_removed, num_links_removed));
     724             :         } else {
     725           0 :                 DEBUG(2, ("garbage_collect_tombstones: Failure removing tombstone "
     726             :                           "objects and links after removing %u tombstone objects "
     727             :                           "and %u tombstone links successfully: %s\n",
     728             :                           num_objects_removed, num_links_removed,
     729             :                           error_string ? error_string : nt_errstr(status)));
     730             :         }
     731          57 :         return status;
     732             : }
     733             : 
     734         296 : static void kccsrv_periodic_run(struct kccsrv_service *service)
     735             : {
     736             :         TALLOC_CTX *mem_ctx;
     737             :         NTSTATUS status;
     738             : 
     739         296 :         DEBUG(4,("kccsrv_periodic_run(): update\n"));
     740             : 
     741         296 :         mem_ctx = talloc_new(service);
     742             : 
     743         296 :         if (service->samba_kcc_code)
     744         296 :                 status = kccsrv_samba_kcc(service);
     745             :         else {
     746           0 :                 status = kccsrv_simple_update(service, mem_ctx);
     747           0 :                 if (!NT_STATUS_IS_OK(status))
     748           0 :                         DEBUG(0,("kccsrv_simple_update failed - %s\n",
     749             :                                 nt_errstr(status)));
     750             :         }
     751             : 
     752         296 :         status = kccsrv_check_deleted(service, mem_ctx);
     753         296 :         if (!NT_STATUS_IS_OK(status)) {
     754           0 :                 DEBUG(0,("kccsrv_check_deleted failed - %s\n", nt_errstr(status)));
     755             :         }
     756         296 :         status = kccsrv_dns_zone_scavenging(service, mem_ctx);
     757         296 :         if (!NT_STATUS_IS_OK(status)) {
     758           0 :                 DBG_ERR("kccsrv_dns_zone_aging failed - %s\n",
     759             :                         nt_errstr(status));
     760             :         }
     761         296 :         status = kccsrv_dns_zone_tombstone_deletion(service, mem_ctx);
     762         296 :         if (!NT_STATUS_IS_OK(status)) {
     763           0 :                 DBG_ERR("kccsrv_dns_zone_tombstone_scavenging failed - %s\n",
     764             :                         nt_errstr(status));
     765             :         }
     766         296 :         talloc_free(mem_ctx);
     767         296 : }
     768             : 
     769             : /* Called when samba_kcc script has finished
     770             :  */
     771         295 : static void samba_kcc_done(struct tevent_req *subreq)
     772             : {
     773         218 :         struct kccsrv_service *service =
     774         295 :                 tevent_req_callback_data(subreq, struct kccsrv_service);
     775             :         int rc;
     776             :         int sys_errno;
     777             : 
     778         295 :         service->periodic.subreq = NULL;
     779             : 
     780         295 :         rc = samba_runcmd_recv(subreq, &sys_errno);
     781         295 :         TALLOC_FREE(subreq);
     782             : 
     783         295 :         if (rc != 0)
     784           1 :                 service->periodic.status =
     785           1 :                         map_nt_error_from_unix_common(sys_errno);
     786             :         else
     787         294 :                 service->periodic.status = NT_STATUS_OK;
     788             : 
     789         295 :         if (!NT_STATUS_IS_OK(service->periodic.status))
     790           1 :                 DEBUG(0,(__location__ ": Failed samba_kcc - %s\n",
     791             :                         nt_errstr(service->periodic.status)));
     792             :         else
     793         294 :                 DEBUG(3,("Completed samba_kcc OK\n"));
     794         295 : }
     795             : 
     796             : /* Invocation of the samba_kcc python script for replication
     797             :  * topology generation.
     798             :  */
     799         296 : NTSTATUS kccsrv_samba_kcc(struct kccsrv_service *service)
     800             : {
     801         296 :         NTSTATUS status = NT_STATUS_OK;
     802         219 :         const char * const *samba_kcc_command =
     803         296 :                 lpcfg_samba_kcc_command(service->task->lp_ctx);
     804             : 
     805             :         /* kill any existing child */
     806         296 :         TALLOC_FREE(service->periodic.subreq);
     807             : 
     808         296 :         DEBUG(2, ("Calling samba_kcc script\n"));
     809         515 :         service->periodic.subreq = samba_runcmd_send(service,
     810         296 :                                         service->task->event_ctx,
     811             :                                         timeval_current_ofs(40, 0),
     812             :                                         2, 0, samba_kcc_command, NULL);
     813             : 
     814         296 :         if (service->periodic.subreq == NULL) {
     815           0 :                 status = NT_STATUS_NO_MEMORY;
     816           0 :                 goto xerror;
     817             :         }
     818         296 :         tevent_req_set_callback(service->periodic.subreq,
     819             :                                 samba_kcc_done, service);
     820             : 
     821         296 : xerror:
     822         296 :         if (!NT_STATUS_IS_OK(status))
     823           0 :                 DEBUG(0,(__location__ ": failed - %s\n", nt_errstr(status)));
     824         296 :         return status;
     825             : }

Generated by: LCOV version 1.13