debug: Add new debug class "drs_repl" for DRS replication processing
[samba.git] / source4 / dsdb / repl / drepl_extended.c
1 /*
2    Unix SMB/CIFS mplementation.
3
4    DSDB replication service - extended operation code
5
6    Copyright (C) Andrew Tridgell 2010
7    Copyright (C) Andrew Bartlett 2010
8    Copyright (C) Nadezhda Ivanova 2010
9
10    based on drepl_notify.c
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
25 */
26
27 #include "includes.h"
28 #include "ldb_module.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "smbd/service.h"
31 #include "dsdb/repl/drepl_service.h"
32 #include "param/param.h"
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS            DBGC_DRS_REPL
36
37
38 /*
39   create the role owner source dsa structure
40
41   nc_dn: the DN of the subtree being replicated
42   source_dsa_dn: the DN of the server that we are replicating from
43  */
44 static WERROR drepl_create_extended_source_dsa(struct dreplsrv_service *service,
45                                                TALLOC_CTX *mem_ctx,
46                                                struct ldb_dn *nc_dn,
47                                                struct ldb_dn *source_dsa_dn,
48                                                uint64_t min_usn,
49                                                struct dreplsrv_partition_source_dsa **_sdsa)
50 {
51         struct dreplsrv_partition_source_dsa *sdsa;
52         struct ldb_context *ldb = service->samdb;
53         int ret;
54         WERROR werr;
55         struct ldb_dn *nc_root;
56         struct dreplsrv_partition *p;
57
58         sdsa = talloc_zero(service, struct dreplsrv_partition_source_dsa);
59         W_ERROR_HAVE_NO_MEMORY(sdsa);
60
61         sdsa->partition = talloc_zero(sdsa, struct dreplsrv_partition);
62         if (!sdsa->partition) {
63                 talloc_free(sdsa);
64                 return WERR_NOT_ENOUGH_MEMORY;
65         }
66
67         sdsa->partition->dn = ldb_dn_copy(sdsa->partition, nc_dn);
68         if (!sdsa->partition->dn) {
69                 talloc_free(sdsa);
70                 return WERR_NOT_ENOUGH_MEMORY;
71         }
72         sdsa->partition->nc.dn = ldb_dn_alloc_linearized(sdsa->partition, nc_dn);
73         if (!sdsa->partition->nc.dn) {
74                 talloc_free(sdsa);
75                 return WERR_NOT_ENOUGH_MEMORY;
76         }
77         ret = dsdb_find_guid_by_dn(ldb, nc_dn, &sdsa->partition->nc.guid);
78         if (ret != LDB_SUCCESS) {
79                 DEBUG(0,(__location__ ": Failed to find GUID for %s\n",
80                          ldb_dn_get_linearized(nc_dn)));
81                 talloc_free(sdsa);
82                 return WERR_DS_DRA_INTERNAL_ERROR;
83         }
84
85         sdsa->repsFrom1 = &sdsa->_repsFromBlob.ctr.ctr1;
86         ret = dsdb_find_guid_by_dn(ldb, source_dsa_dn, &sdsa->repsFrom1->source_dsa_obj_guid);
87         if (ret != LDB_SUCCESS) {
88                 DEBUG(0,(__location__ ": Failed to find objectGUID for %s\n",
89                          ldb_dn_get_linearized(source_dsa_dn)));
90                 talloc_free(sdsa);
91                 return WERR_DS_DRA_INTERNAL_ERROR;
92         }
93
94         sdsa->repsFrom1->other_info = talloc_zero(sdsa, struct repsFromTo1OtherInfo);
95         if (!sdsa->repsFrom1->other_info) {
96                 talloc_free(sdsa);
97                 return WERR_NOT_ENOUGH_MEMORY;
98         }
99
100         sdsa->repsFrom1->other_info->dns_name = samdb_ntds_msdcs_dns_name(ldb,
101                                                                           sdsa->repsFrom1->other_info,
102                                                                           &sdsa->repsFrom1->source_dsa_obj_guid);
103         if (!sdsa->repsFrom1->other_info->dns_name) {
104                 talloc_free(sdsa);
105                 return WERR_NOT_ENOUGH_MEMORY;
106         }
107
108         werr = dreplsrv_out_connection_attach(service, sdsa->repsFrom1, &sdsa->conn);
109         if (!W_ERROR_IS_OK(werr)) {
110                 DEBUG(0,(__location__ ": Failed to attach connection to %s\n",
111                          ldb_dn_get_linearized(nc_dn)));
112                 talloc_free(sdsa);
113                 return werr;
114         }
115
116         ret = dsdb_find_nc_root(service->samdb, sdsa, nc_dn, &nc_root);
117         if (ret != LDB_SUCCESS) {
118                 DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
119                          ldb_dn_get_linearized(nc_dn)));
120                 talloc_free(sdsa);
121                 return WERR_DS_DRA_INTERNAL_ERROR;
122         }
123
124         /* use the partition uptodateness vector */
125         ret = dsdb_load_udv_v2(service->samdb, nc_root, sdsa->partition,
126                                &sdsa->partition->uptodatevector.cursors,
127                                &sdsa->partition->uptodatevector.count);
128         if (ret != LDB_SUCCESS) {
129                 DEBUG(0,(__location__ ": Failed to load UDV for %s\n",
130                          ldb_dn_get_linearized(nc_root)));
131                 talloc_free(sdsa);
132                 return WERR_DS_DRA_INTERNAL_ERROR;
133         }
134
135         /* find the highwatermark from the partitions list */
136         for (p=service->partitions; p; p=p->next) {
137                 if (ldb_dn_compare(p->dn, nc_root) == 0) {
138                         struct dreplsrv_partition_source_dsa *s;
139                         werr = dreplsrv_partition_source_dsa_by_guid(p,
140                                                                      &sdsa->repsFrom1->source_dsa_obj_guid,
141                                                                      &s);
142                         if (W_ERROR_IS_OK(werr)) {
143                                 sdsa->repsFrom1->highwatermark = s->repsFrom1->highwatermark;
144                                 sdsa->repsFrom1->replica_flags = s->repsFrom1->replica_flags;
145                         }
146                 }
147         }
148
149         if (!service->am_rodc) {
150                 sdsa->repsFrom1->replica_flags |= DRSUAPI_DRS_WRIT_REP;
151         }
152
153         *_sdsa = sdsa;
154         return WERR_OK;
155 }
156
157 struct extended_op_data {
158         dreplsrv_extended_callback_t callback;
159         void *callback_data;
160         struct dreplsrv_partition_source_dsa *sdsa;
161 };
162
163 /*
164   called when an extended op finishes
165  */
166 static void extended_op_callback(struct dreplsrv_service *service,
167                                  WERROR err,
168                                  enum drsuapi_DsExtendedError exop_error,
169                                  void *cb_data)
170 {
171         struct extended_op_data *data = talloc_get_type_abort(cb_data, struct extended_op_data);
172         talloc_unlink(data, data->sdsa);
173         data->callback(service, err, exop_error, data->callback_data);
174         talloc_free(data);
175 }
176
177 /*
178   schedule a getncchanges request to the role owner for an extended operation
179  */
180 WERROR drepl_request_extended_op(struct dreplsrv_service *service,
181                                  struct ldb_dn *nc_dn,
182                                  struct ldb_dn *source_dsa_dn,
183                                  enum drsuapi_DsExtendedOperation extended_op,
184                                  uint64_t fsmo_info,
185                                  uint64_t min_usn,
186                                  dreplsrv_extended_callback_t callback,
187                                  void *callback_data)
188 {
189         WERROR werr;
190         struct extended_op_data *data;
191
192         data = talloc(service, struct extended_op_data);
193         W_ERROR_HAVE_NO_MEMORY(data);
194
195         werr = drepl_create_extended_source_dsa(service, data, nc_dn, source_dsa_dn, min_usn, &data->sdsa);
196         W_ERROR_NOT_OK_RETURN(werr);
197
198         data->callback = callback;
199         data->callback_data = callback_data;
200
201         werr = dreplsrv_schedule_partition_pull_source(service, data->sdsa,
202                                                        0, extended_op, fsmo_info,
203                                                        extended_op_callback, data);
204         if (!W_ERROR_IS_OK(werr)) {
205                 talloc_free(data);
206         }
207
208         dreplsrv_run_pending_ops(service);
209
210         return werr;
211 }