LCOV - code coverage report
Current view: top level - source4/dsdb/repl - drepl_out_pull.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 93 114 81.6 %
Date: 2024-04-21 15:09:00 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS Implementation.
       3             :    DSDB replication service outgoing Pull-Replication
       4             :    
       5             :    Copyright (C) Stefan Metzmacher 2007
       6             :     
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             :    
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "dsdb/samdb/samdb.h"
      24             : #include "auth/auth.h"
      25             : #include "samba/service.h"
      26             : #include "lib/events/events.h"
      27             : #include "dsdb/repl/drepl_service.h"
      28             : #include <ldb_errors.h>
      29             : #include "../lib/util/dlinklist.h"
      30             : #include "librpc/gen_ndr/ndr_misc.h"
      31             : #include "librpc/gen_ndr/ndr_drsuapi.h"
      32             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      33             : #include "libcli/composite/composite.h"
      34             : #include "libcli/security/security.h"
      35             : 
      36             : #undef DBGC_CLASS
      37             : #define DBGC_CLASS            DBGC_DRS_REPL
      38             : 
      39             : /*
      40             :   update repsFrom/repsTo error information
      41             :  */
      42        7884 : void drepl_reps_update(struct dreplsrv_service *s, const char *reps_attr,
      43             :                        struct ldb_dn *dn,
      44             :                        struct GUID *source_dsa_obj_guid, WERROR status)
      45             : {
      46           0 :         struct repsFromToBlob *reps;
      47           0 :         uint32_t count, i;
      48           0 :         WERROR werr;
      49        7884 :         TALLOC_CTX *tmp_ctx = talloc_new(s);
      50           0 :         time_t t;
      51           0 :         NTTIME now;
      52             : 
      53        7884 :         t = time(NULL);
      54        7884 :         unix_to_nt_time(&now, t);
      55             : 
      56        7884 :         werr = dsdb_loadreps(s->samdb, tmp_ctx, dn, reps_attr, &reps, &count);
      57        7884 :         if (!W_ERROR_IS_OK(werr)) {
      58           0 :                 talloc_free(tmp_ctx);
      59          41 :                 return;
      60             :         }
      61             : 
      62       12672 :         for (i=0; i<count; i++) {
      63       12631 :                 if (GUID_equal(source_dsa_obj_guid,
      64       12631 :                                &reps[i].ctr.ctr1.source_dsa_obj_guid)) {
      65        7843 :                         break;
      66             :                 }
      67             :         }
      68             : 
      69        7884 :         if (i == count) {
      70             :                 /* no record to update */
      71          41 :                 talloc_free(tmp_ctx);
      72          41 :                 return;
      73             :         }
      74             : 
      75             :         /* only update the status fields */
      76        7843 :         reps[i].ctr.ctr1.last_attempt = now;
      77        7843 :         reps[i].ctr.ctr1.result_last_attempt = status;
      78        7843 :         if (W_ERROR_IS_OK(status)) {
      79        2903 :                 reps[i].ctr.ctr1.last_success = now;
      80        2903 :                 reps[i].ctr.ctr1.consecutive_sync_failures = 0;
      81             :         } else {
      82        4940 :                 reps[i].ctr.ctr1.consecutive_sync_failures++;
      83             :         }
      84             : 
      85        7843 :         werr = dsdb_savereps(s->samdb, tmp_ctx, dn, reps_attr, reps, count);
      86        7843 :         if (!W_ERROR_IS_OK(werr)) {
      87           0 :                 DEBUG(2,("drepl_reps_update: Failed to save %s for %s: %s\n",
      88             :                          reps_attr, ldb_dn_get_linearized(dn), win_errstr(werr)));
      89             :         }
      90        7843 :         talloc_free(tmp_ctx);
      91             : }
      92             : 
      93        4147 : WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
      94             :                                                struct dreplsrv_partition_source_dsa *source,
      95             :                                                uint32_t options,
      96             :                                                enum drsuapi_DsExtendedOperation extended_op,
      97             :                                                uint64_t fsmo_info,
      98             :                                                dreplsrv_extended_callback_t callback,
      99             :                                                void *cb_data)
     100             : {
     101           0 :         struct dreplsrv_out_operation *op;
     102             : 
     103        4147 :         op = talloc_zero(s, struct dreplsrv_out_operation);
     104        4147 :         W_ERROR_HAVE_NO_MEMORY(op);
     105             : 
     106        4147 :         op->service  = s;
     107             :         /*
     108             :          * source may either be the long-term list of partners, or
     109             :          * from dreplsrv_partition_source_dsa_temporary().  Because it
     110             :          * can be either, we can't talloc_steal() it here, so we
     111             :          * instead we reference it.
     112             :          *
     113             :          * We never talloc_free() the p->sources pointers - indeed we
     114             :          * never remove them - and the temp source will otherwise go
     115             :          * away with the msg it is allocated on.
     116             :          *
     117             :          * Finally the pointer created in drepl_request_extended_op()
     118             :          * is removed with talloc_unlink().
     119             :          *
     120             :          */
     121        4147 :         op->source_dsa       = talloc_reference(op, source);
     122        4147 :         if (!op->source_dsa) {
     123           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     124             :         }
     125             : 
     126        4147 :         op->options  = options;
     127        4147 :         op->extended_op = extended_op;
     128        4147 :         op->fsmo_info   = fsmo_info;
     129        4147 :         op->callback    = callback;
     130        4147 :         op->cb_data  = cb_data;
     131        4147 :         op->schedule_time = time(NULL);
     132        4147 :         op->more_flags       = 0;
     133             : 
     134        4147 :         DLIST_ADD_END(s->ops.pending, op);
     135             : 
     136        4147 :         return WERR_OK;
     137             : }
     138             : 
     139        1004 : static WERROR dreplsrv_schedule_partition_pull(struct dreplsrv_service *s,
     140             :                                                struct dreplsrv_partition *p,
     141             :                                                TALLOC_CTX *mem_ctx)
     142             : {
     143          10 :         WERROR status;
     144          10 :         struct dreplsrv_partition_source_dsa *cur;
     145             : 
     146        1175 :         for (cur = p->sources; cur; cur = cur->next) {
     147         171 :                 status = dreplsrv_schedule_partition_pull_source(s, cur,
     148             :                                                                  0, DRSUAPI_EXOP_NONE, 0,
     149             :                                                                  NULL, NULL);
     150         171 :                 W_ERROR_NOT_OK_RETURN(status);
     151             :         }
     152             : 
     153        1004 :         return WERR_OK;
     154             : }
     155             : 
     156         206 : WERROR dreplsrv_schedule_pull_replication(struct dreplsrv_service *s, TALLOC_CTX *mem_ctx)
     157             : {
     158           2 :         WERROR status;
     159           2 :         struct dreplsrv_partition *p;
     160             : 
     161        1210 :         for (p = s->partitions; p; p = p->next) {
     162        1004 :                 status = dreplsrv_schedule_partition_pull(s, p, mem_ctx);
     163        1004 :                 W_ERROR_NOT_OK_RETURN(status);
     164             :         }
     165             : 
     166         206 :         return WERR_OK;
     167             : }
     168             : 
     169             : 
     170        3846 : static void dreplsrv_pending_op_callback(struct tevent_req *subreq)
     171             : {
     172        3846 :         struct dreplsrv_out_operation *op = tevent_req_callback_data(subreq,
     173             :                                             struct dreplsrv_out_operation);
     174        3846 :         struct repsFromTo1 *rf = op->source_dsa->repsFrom1;
     175        3846 :         struct dreplsrv_service *s = op->service;
     176           0 :         WERROR werr;
     177             : 
     178        3846 :         werr = dreplsrv_op_pull_source_recv(subreq);
     179        3846 :         TALLOC_FREE(subreq);
     180             : 
     181        3846 :         DEBUG(4,("dreplsrv_op_pull_source(%s) for %s\n", win_errstr(werr),
     182             :                  ldb_dn_get_linearized(op->source_dsa->partition->dn)));
     183             : 
     184        3846 :         if (op->extended_op == DRSUAPI_EXOP_NONE) {
     185        1973 :                 drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
     186             :                                   &rf->source_dsa_obj_guid, werr);
     187             :         }
     188             : 
     189        3846 :         if (op->callback) {
     190        2836 :                 op->callback(s, werr, op->extended_ret, op->cb_data);
     191             :         }
     192        3846 :         talloc_free(op);
     193        3846 :         s->ops.current = NULL;
     194        3846 :         dreplsrv_run_pending_ops(s);
     195        3846 : }
     196             : 
     197        4573 : void dreplsrv_run_pull_ops(struct dreplsrv_service *s)
     198             : {
     199           0 :         struct dreplsrv_out_operation *op;
     200           0 :         time_t t;
     201           0 :         NTTIME now;
     202           0 :         struct tevent_req *subreq;
     203           0 :         WERROR werr;
     204             : 
     205        4573 :         if (s->ops.n_current || s->ops.current) {
     206             :                 /* if there's still one running, we're done */
     207        4272 :                 return;
     208             :         }
     209             : 
     210        4147 :         if (!s->ops.pending) {
     211             :                 /* if there're no pending operations, we're done */
     212           0 :                 return;
     213             :         }
     214             : 
     215        4147 :         t = time(NULL);
     216        4147 :         unix_to_nt_time(&now, t);
     217             : 
     218        4147 :         op = s->ops.pending;
     219        4147 :         s->ops.current = op;
     220        4147 :         DLIST_REMOVE(s->ops.pending, op);
     221             : 
     222        4147 :         op->source_dsa->repsFrom1->last_attempt = now;
     223             : 
     224             :         /* check if inbound replication is enabled */
     225        4147 :         if (!(op->options & DRSUAPI_DRS_SYNC_FORCED)) {
     226           0 :                 uint32_t rep_options;
     227        3230 :                 if (samdb_ntds_options(op->service->samdb, &rep_options) != LDB_SUCCESS) {
     228           0 :                         werr = WERR_DS_DRA_INTERNAL_ERROR;
     229           0 :                         goto failed;
     230             :                 }
     231             : 
     232        3230 :                 if ((rep_options & DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL)) {
     233         301 :                         werr = WERR_DS_DRA_SINK_DISABLED;
     234         301 :                         goto failed;
     235             :                 }
     236             :         }
     237             : 
     238        3846 :         subreq = dreplsrv_op_pull_source_send(op, s->task->event_ctx, op);
     239        3846 :         if (!subreq) {
     240           0 :                 werr = WERR_NOT_ENOUGH_MEMORY;
     241           0 :                 goto failed;
     242             :         }
     243             : 
     244        3846 :         tevent_req_set_callback(subreq, dreplsrv_pending_op_callback, op);
     245        3846 :         return;
     246             : 
     247         301 : failed:
     248         301 :         if (op->extended_op == DRSUAPI_EXOP_NONE) {
     249         301 :                 drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
     250         301 :                                   &op->source_dsa->repsFrom1->source_dsa_obj_guid, werr);
     251             :         }
     252             :         /* unblock queue processing */
     253         301 :         s->ops.current = NULL;
     254             :         /*
     255             :          * let the callback do its job just like in any other failure situation
     256             :          */
     257         301 :         if (op->callback) {
     258           2 :                 op->callback(s, werr, op->extended_ret, op->cb_data);
     259             :         }
     260             : }

Generated by: LCOV version 1.14