s4-drs: do not try to contact for replication servers that are not anymore in reps*
[nivanova/samba-autobuild/.git] / source4 / dsdb / repl / drepl_partitions.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB replication service
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 "smbd/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/security/security.h"
34 #include "param/param.h"
35 #include "dsdb/common/util.h"
36
37 /*
38   load the partitions list based on replicated NC attributes in our
39   NTDSDSA object
40  */
41 WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
42 {
43         WERROR status;
44         static const char *attrs[] = { "hasMasterNCs", "msDs-hasMasterNCs", "hasPartialReplicaNCs", "msDS-HasFullReplicaNCs", NULL };
45         unsigned int a;
46         int ret;
47         TALLOC_CTX *tmp_ctx;
48         struct ldb_result *res;
49         struct ldb_message_element *el;
50         struct ldb_dn *ntds_dn;
51
52         tmp_ctx = talloc_new(s);
53         W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
54
55         ntds_dn = samdb_ntds_settings_dn(s->samdb);
56         if (!ntds_dn) {
57                 DEBUG(1,(__location__ ": Unable to find ntds_dn: %s\n", ldb_errstring(s->samdb)));
58                 talloc_free(tmp_ctx);
59                 return WERR_DS_DRA_INTERNAL_ERROR;
60         }
61
62         ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, ntds_dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
63         if (ret != LDB_SUCCESS) {
64                 DEBUG(1,("Searching for hasMasterNCs in NTDS DN failed: %s\n", ldb_errstring(s->samdb)));
65                 talloc_free(tmp_ctx);
66                 return WERR_DS_DRA_INTERNAL_ERROR;
67         }
68
69         for (a=0; attrs[a]; a++) {
70                 int i;
71
72                 el = ldb_msg_find_element(res->msgs[0], attrs[a]);
73                 if (el == NULL) {
74                         continue;
75                 }
76                 for (i=0; i<el->num_values; i++) {
77                         struct ldb_dn *pdn;
78                         struct dreplsrv_partition *p, *tp;
79                         bool found;
80
81                         pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
82                         if (pdn == NULL) {
83                                 talloc_free(tmp_ctx);
84                                 return WERR_DS_DRA_INTERNAL_ERROR;
85                         }
86                         if (!ldb_dn_validate(pdn)) {
87                                 return WERR_DS_DRA_INTERNAL_ERROR;
88                         }
89
90                         p = talloc_zero(s, struct dreplsrv_partition);
91                         W_ERROR_HAVE_NO_MEMORY(p);
92
93                         p->dn = talloc_steal(p, pdn);
94                         p->service = s;
95
96                         if (strcasecmp(attrs[a], "hasPartialReplicaNCs") == 0) {
97                                 p->partial_replica = true;
98                         } else if (strcasecmp(attrs[a], "msDS-HasFullReplicaNCs") == 0) {
99                                 p->rodc_replica = true;
100                         }
101
102                         /* Do not add partitions more than once */
103                         found = false;
104                         for (tp = s->partitions; tp; tp = tp->next) {
105                                 if (ldb_dn_compare(tp->dn, p->dn) == 0) {
106                                         found = true;
107                                         break;
108                                 }
109                         }
110                         if (found) {
111                                 talloc_free(p);
112                                 continue;
113                         }
114
115                         DLIST_ADD(s->partitions, p);
116                         DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn)));
117                 }
118         }
119
120         talloc_free(tmp_ctx);
121
122         status = dreplsrv_refresh_partitions(s);
123         W_ERROR_NOT_OK_RETURN(status);
124
125         return WERR_OK;
126 }
127
128 /*
129   Check if particular SPN exists for an account
130  */
131 static bool dreplsrv_spn_exists(struct ldb_context *samdb, struct ldb_dn *ntds_dn,
132                                 const char *principal_name)
133 {
134         TALLOC_CTX *tmp_ctx;
135         const char *attrs[] = { "serverReference", NULL };
136         const char *attrs_empty[] = { NULL };
137         int ret;
138         struct ldb_result *res;
139         struct ldb_dn *account_dn;
140
141         tmp_ctx = talloc_new(samdb);
142
143         ret = dsdb_search_dn(samdb, tmp_ctx, &res, ntds_dn, attrs, 0);
144         if (ret != LDB_SUCCESS) {
145                 talloc_free(tmp_ctx);
146                 return false;
147         }
148
149         account_dn = ldb_msg_find_attr_as_dn(samdb, tmp_ctx, res->msgs[0], "serverReference");
150         if (account_dn == NULL) {
151                 talloc_free(tmp_ctx);
152                 return false;
153         }
154
155         talloc_free(res);
156
157         ret = dsdb_search(samdb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs_empty,
158                         0, "servicePrincipalName=%s",
159                         ldb_binary_encode_string(tmp_ctx, principal_name));
160         if (ret != LDB_SUCCESS || res->count != 1) {
161                 talloc_free(tmp_ctx);
162                 return false;
163         }
164
165         talloc_free(tmp_ctx);
166         return true;
167 }
168
169 /*
170   work out the principal to use for DRS replication connections
171  */
172 NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
173                                        TALLOC_CTX *mem_ctx,
174                                        const struct repsFromTo1 *rft,
175                                        const char **target_principal)
176 {
177         TALLOC_CTX *tmp_ctx;
178         struct ldb_result *res;
179         const char *attrs_server[] = { "dNSHostName", NULL };
180         const char *attrs_ntds[] = { "msDS-HasDomainNCs", "hasMasterNCs", NULL };
181         int ret;
182         const char *hostname, *dnsdomain=NULL;
183         struct ldb_dn *ntds_dn, *server_dn;
184         struct ldb_dn *forest_dn, *nc_dn;
185
186         *target_principal = NULL;
187
188         tmp_ctx = talloc_new(mem_ctx);
189
190         /* we need to find their hostname */
191         ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &ntds_dn);
192         if (ret != LDB_SUCCESS) {
193                 talloc_free(tmp_ctx);
194                 /* its OK for their NTDSDSA DN not to be in our database */
195                 return NT_STATUS_OK;
196         }
197
198         server_dn = ldb_dn_copy(tmp_ctx, ntds_dn);
199         if (server_dn == NULL) {
200                 talloc_free(tmp_ctx);
201                 return NT_STATUS_OK;
202         }
203
204         /* strip off the NTDS Settings */
205         if (!ldb_dn_remove_child_components(server_dn, 1)) {
206                 talloc_free(tmp_ctx);
207                 return NT_STATUS_OK;
208         }
209
210         ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, server_dn, attrs_server, 0);
211         if (ret != LDB_SUCCESS) {
212                 talloc_free(tmp_ctx);
213                 /* its OK for their server DN not to be in our database */
214                 return NT_STATUS_OK;
215         }
216
217         forest_dn = ldb_get_root_basedn(s->samdb);
218         if (forest_dn == NULL) {
219                 talloc_free(tmp_ctx);
220                 return NT_STATUS_OK;
221         }
222
223         hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
224         if (hostname != NULL) {
225                 char *local_principal;
226
227                 /*
228                   if we have the dNSHostName attribute then we can use
229                   the GC/hostname/realm SPN. All DCs should have this SPN
230
231                   Windows DC may set up it's dNSHostName before setting up
232                   GC/xx/xx SPN. So make sure it exists, before using it.
233                  */
234                 local_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
235                                                     hostname,
236                                                     samdb_dn_to_dns_domain(tmp_ctx, forest_dn));
237                 if (dreplsrv_spn_exists(s->samdb, ntds_dn, local_principal)) {
238                         *target_principal = local_principal;
239                         talloc_free(tmp_ctx);
240                         return NT_STATUS_OK;
241                 }
242
243                 talloc_free(local_principal);
244         }
245
246         /*
247            if we can't find the dNSHostName then we will try for the
248            E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN}
249            SPN. To use that we need the DNS domain name of the target
250            DC. We find that by first looking for the msDS-HasDomainNCs
251            in the NTDSDSA object of the DC, and if we don't find that,
252            then we look for the hasMasterNCs attribute, and eliminate
253            the known schema and configuruation DNs. Despite how
254            bizarre this seems, Hongwei tells us that this is in fact
255            what windows does to find the SPN!!
256         */
257         ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, ntds_dn, attrs_ntds, 0);
258         if (ret != LDB_SUCCESS) {
259                 talloc_free(tmp_ctx);
260                 return NT_STATUS_OK;
261         }
262
263         nc_dn = ldb_msg_find_attr_as_dn(s->samdb, tmp_ctx, res->msgs[0], "msDS-HasDomainNCs");
264         if (nc_dn != NULL) {
265                 dnsdomain = samdb_dn_to_dns_domain(tmp_ctx, nc_dn);
266         }
267
268         if (dnsdomain == NULL) {
269                 struct ldb_message_element *el;
270                 int i;
271                 el = ldb_msg_find_element(res->msgs[0], "hasMasterNCs");
272                 for (i=0; el && i<el->num_values; i++) {
273                         nc_dn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
274                         if (nc_dn == NULL ||
275                             ldb_dn_compare(ldb_get_config_basedn(s->samdb), nc_dn) == 0 ||
276                             ldb_dn_compare(ldb_get_schema_basedn(s->samdb), nc_dn) == 0) {
277                                 continue;
278                         }
279                         /* it must be a domain DN, get the equivalent
280                            DNS domain name */
281                         dnsdomain = samdb_dn_to_dns_domain(tmp_ctx, nc_dn);
282                         break;
283                 }
284         }
285
286         if (dnsdomain != NULL) {
287                 *target_principal = talloc_asprintf(mem_ctx,
288                                                     "E3514235-4B06-11D1-AB04-00C04FC2DCD2/%s/%s",
289                                                     GUID_string(tmp_ctx, &rft->source_dsa_obj_guid),
290                                                     dnsdomain);
291         }
292
293         talloc_free(tmp_ctx);
294         return NT_STATUS_OK;
295 }
296
297
298 WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
299                                       const struct repsFromTo1 *rft,
300                                       struct dreplsrv_out_connection **_conn)
301 {
302         struct dreplsrv_out_connection *cur, *conn = NULL;
303         const char *hostname;
304
305         if (!rft->other_info) {
306                 return WERR_FOOBAR;
307         }
308
309         if (!rft->other_info->dns_name) {
310                 return WERR_FOOBAR;
311         }
312
313         hostname = rft->other_info->dns_name;
314
315         for (cur = s->connections; cur; cur = cur->next) {              
316                 if (strcmp(cur->binding->host, hostname) == 0) {
317                         conn = cur;
318                         break;
319                 }
320         }
321
322         if (!conn) {
323                 NTSTATUS nt_status;
324                 char *binding_str;
325
326                 conn = talloc_zero(s, struct dreplsrv_out_connection);
327                 W_ERROR_HAVE_NO_MEMORY(conn);
328
329                 conn->service   = s;
330
331                 binding_str = talloc_asprintf(conn, "ncacn_ip_tcp:%s[krb5,seal]",
332                                               hostname);
333                 W_ERROR_HAVE_NO_MEMORY(binding_str);
334                 nt_status = dcerpc_parse_binding(conn, binding_str, &conn->binding);
335                 talloc_free(binding_str);
336                 if (!NT_STATUS_IS_OK(nt_status)) {
337                         return ntstatus_to_werror(nt_status);
338                 }
339
340                 /* use the GC principal for DRS replication */
341                 nt_status = dreplsrv_get_target_principal(s, conn->binding,
342                                                           rft, &conn->binding->target_principal);
343                 if (!NT_STATUS_IS_OK(nt_status)) {
344                         return ntstatus_to_werror(nt_status);
345                 }
346
347                 DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
348
349                 DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
350         } else {
351                 DEBUG(4,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
352         }
353
354         *_conn = conn;
355         return WERR_OK;
356 }
357
358 /*
359   find an existing source dsa in a list
360  */
361 static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa *list,
362                                                                       struct GUID *guid)
363 {
364         struct dreplsrv_partition_source_dsa *s;
365         for (s=list; s; s=s->next) {
366                 if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
367                         return s;
368                 }
369         }
370         return NULL;    
371 }
372
373
374
375 static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
376                                                 struct dreplsrv_partition *p,
377                                                 struct dreplsrv_partition_source_dsa **listp,
378                                                 struct dreplsrv_partition_source_dsa *check_list,
379                                                 struct dreplsrv_partition_source_dsa **oldlist,
380                                                 const struct ldb_val *val)
381 {
382         WERROR status;
383         enum ndr_err_code ndr_err;
384         struct dreplsrv_partition_source_dsa *source, *s2;
385
386         source = talloc_zero(p, struct dreplsrv_partition_source_dsa);
387         W_ERROR_HAVE_NO_MEMORY(source);
388
389         ndr_err = ndr_pull_struct_blob(val, source, 
390                                        &source->_repsFromBlob,
391                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
392         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
393                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
394                 talloc_free(source);
395                 return ntstatus_to_werror(nt_status);
396         }
397         /* NDR_PRINT_DEBUG(repsFromToBlob, &source->_repsFromBlob); */
398         if (source->_repsFromBlob.version != 1) {
399                 talloc_free(source);
400                 return WERR_DS_DRA_INTERNAL_ERROR;
401         }
402
403         source->partition       = p;
404         source->repsFrom1       = &source->_repsFromBlob.ctr.ctr1;
405
406         status = dreplsrv_out_connection_attach(s, source->repsFrom1, &source->conn);
407         W_ERROR_NOT_OK_RETURN(status);
408
409         if (check_list && 
410             dreplsrv_find_source_dsa(check_list, &source->repsFrom1->source_dsa_obj_guid)) {
411                 /* its in the check list, don't add it again */
412                 talloc_free(source);
413                 return WERR_OK;
414         }
415
416         /* re-use an existing source if found */
417         for (s2=*oldlist; s2; s2=s2->next) {
418                 if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid, 
419                                  &source->repsFrom1->source_dsa_obj_guid) == 0) {
420                         talloc_free(s2->repsFrom1->other_info);
421                         *s2->repsFrom1 = *source->repsFrom1;
422                         talloc_steal(s2, s2->repsFrom1->other_info);
423                         talloc_free(source);
424                         source = s2;
425                         DLIST_REMOVE(*oldlist, s2);
426                         break;
427                 }
428         }
429
430         DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
431         return WERR_OK;
432 }
433
434 WERROR dreplsrv_partition_find_for_nc(struct dreplsrv_service *s,
435                                       struct GUID *nc_guid,
436                                       struct dom_sid *nc_sid,
437                                       const char *nc_dn_str,
438                                       struct dreplsrv_partition **_p)
439 {
440         struct dreplsrv_partition *p;
441         bool valid_sid, valid_guid;
442         struct dom_sid null_sid;
443         ZERO_STRUCT(null_sid);
444
445         SMB_ASSERT(_p);
446
447         valid_sid  = nc_sid && !dom_sid_equal(&null_sid, nc_sid);
448         valid_guid = nc_guid && !GUID_all_zero(nc_guid);
449
450         if (!valid_sid && !valid_guid && !nc_dn_str) {
451                 return WERR_DS_DRA_INVALID_PARAMETER;
452         }
453
454         for (p = s->partitions; p; p = p->next) {
455                 if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
456                     || strequal(p->nc.dn, nc_dn_str)
457                     || (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
458                 {
459                         /* fill in he right guid and sid if possible */
460                         if (nc_guid && !valid_guid) {
461                                 dsdb_get_extended_dn_guid(p->dn, nc_guid, "GUID");
462                         }
463                         if (nc_sid && !valid_sid) {
464                                 dsdb_get_extended_dn_sid(p->dn, nc_sid, "SID");
465                         }
466                         *_p = p;
467                         return WERR_OK;
468                 }
469         }
470
471         return WERR_DS_DRA_BAD_NC;
472 }
473
474 WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
475                                              const struct GUID *dsa_guid,
476                                              struct dreplsrv_partition_source_dsa **_dsa)
477 {
478         struct dreplsrv_partition_source_dsa *dsa;
479
480         SMB_ASSERT(dsa_guid != NULL);
481         SMB_ASSERT(!GUID_all_zero(dsa_guid));
482         SMB_ASSERT(_dsa);
483
484         for (dsa = p->sources; dsa; dsa = dsa->next) {
485                 if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
486                         *_dsa = dsa;
487                         return WERR_OK;
488                 }
489         }
490
491         return WERR_DS_DRA_NO_REPLICA;
492 }
493
494 WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
495                                             const char *dsa_dns,
496                                             struct dreplsrv_partition_source_dsa **_dsa)
497 {
498         struct dreplsrv_partition_source_dsa *dsa;
499
500         SMB_ASSERT(dsa_dns != NULL);
501         SMB_ASSERT(_dsa);
502
503         for (dsa = p->sources; dsa; dsa = dsa->next) {
504                 if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
505                         *_dsa = dsa;
506                         return WERR_OK;
507                 }
508         }
509
510         return WERR_DS_DRA_NO_REPLICA;
511 }
512
513
514 /*
515   create a temporary dsa structure for a replication. This is needed
516   for the initial replication of a new partition, such as when a new
517   domain NC is created and we are a global catalog server
518  */
519 WERROR dreplsrv_partition_source_dsa_temporary(struct dreplsrv_partition *p,
520                                                TALLOC_CTX *mem_ctx,
521                                                const struct GUID *dsa_guid,
522                                                struct dreplsrv_partition_source_dsa **_dsa)
523 {
524         struct dreplsrv_partition_source_dsa *dsa;
525         WERROR werr;
526
527         dsa = talloc_zero(mem_ctx, struct dreplsrv_partition_source_dsa);
528         W_ERROR_HAVE_NO_MEMORY(dsa);
529
530         dsa->partition = p;
531         dsa->repsFrom1 = &dsa->_repsFromBlob.ctr.ctr1;
532         dsa->repsFrom1->replica_flags = 0;
533         dsa->repsFrom1->source_dsa_obj_guid = *dsa_guid;
534
535         dsa->repsFrom1->other_info = talloc_zero(dsa, struct repsFromTo1OtherInfo);
536         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info);
537
538         dsa->repsFrom1->other_info->dns_name = samdb_ntds_msdcs_dns_name(p->service->samdb,
539                                                                          dsa->repsFrom1->other_info, dsa_guid);
540         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info->dns_name);
541
542         werr = dreplsrv_out_connection_attach(p->service, dsa->repsFrom1, &dsa->conn);
543         if (!W_ERROR_IS_OK(werr)) {
544                 DEBUG(0,(__location__ ": Failed to attach connection to %s\n",
545                          ldb_dn_get_linearized(p->dn)));
546                 talloc_free(dsa);
547                 return werr;
548         }
549
550         *_dsa = dsa;
551
552         return WERR_OK;
553 }
554
555
556 static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
557                                          struct dreplsrv_partition *p)
558 {
559         WERROR status;
560         NTSTATUS ntstatus;
561         struct ldb_message_element *orf_el = NULL;
562         struct ldb_result *r = NULL;
563         unsigned int i;
564         int ret;
565         TALLOC_CTX *mem_ctx = talloc_new(p);
566         static const char *attrs[] = {
567                 "repsFrom",
568                 "repsTo",
569                 NULL
570         };
571         struct ldb_dn *dn;
572         struct dreplsrv_partition_source_dsa *src, *oldsources, *oldnotifies;
573
574         DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
575                 ldb_dn_get_linearized(p->dn)));
576
577         ret = dsdb_search_dn(s->samdb, mem_ctx, &r, p->dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
578         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
579                 /* we haven't replicated the partition yet, but we
580                  * can fill in the guid, sid etc from the partition DN */
581                 dn = p->dn;
582         } else if (ret != LDB_SUCCESS) {
583                 talloc_free(mem_ctx);
584                 return WERR_FOOBAR;
585         } else {
586                 dn = r->msgs[0]->dn;
587         }
588         
589         talloc_free(discard_const(p->nc.dn));
590         ZERO_STRUCT(p->nc);
591         p->nc.dn        = ldb_dn_alloc_linearized(p, dn);
592         W_ERROR_HAVE_NO_MEMORY(p->nc.dn);
593         ntstatus = dsdb_get_extended_dn_guid(dn, &p->nc.guid, "GUID");
594         if (!NT_STATUS_IS_OK(ntstatus)) {
595                 DEBUG(0,(__location__ ": unable to get GUID for %s: %s\n",
596                          p->nc.dn, nt_errstr(ntstatus)));
597                 talloc_free(mem_ctx);
598                 return WERR_DS_DRA_INTERNAL_ERROR;
599         }
600         dsdb_get_extended_dn_sid(dn, &p->nc.sid, "SID");
601
602         talloc_free(p->uptodatevector.cursors);
603         talloc_free(p->uptodatevector_ex.cursors);
604         ZERO_STRUCT(p->uptodatevector);
605         ZERO_STRUCT(p->uptodatevector_ex);
606
607         ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
608         if (ret != LDB_SUCCESS) {
609                 DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
610         }
611
612         status = WERR_OK;
613
614         oldsources = p->sources;
615         p->sources = NULL;
616         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom"))) {
617                 for (i=0; i < orf_el->num_values; i++) {
618                         status = dreplsrv_partition_add_source_dsa(s, p, &p->sources,
619                                                                    NULL, &oldsources,
620                                                                    &orf_el->values[i]);
621                         W_ERROR_NOT_OK_GOTO_DONE(status);
622                 }
623         } else {
624                 if (r != NULL && p->sources) {
625                         DEBUG(0, ("repsFrom do not exists or is empty\n"));
626                 }
627         }
628
629         oldnotifies = p->notifies;
630         p->notifies = NULL;
631         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsTo"))) {
632                 for (i=0; i < orf_el->num_values; i++) {
633                         status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies,
634                                                                    p->sources,
635                                                                    &oldnotifies,
636                                                                    &orf_el->values[i]);
637                         W_ERROR_NOT_OK_GOTO_DONE(status);
638                 }
639         }
640
641         if (oldsources) {
642                 src = oldsources;
643                 while(src) {
644                         struct dreplsrv_partition_source_dsa *tmp = src->next;
645                         talloc_free(src);
646                         src = tmp;
647                 }
648         }
649
650
651         if (oldnotifies) {
652                 src = oldnotifies;
653                 while(src) {
654                         struct dreplsrv_partition_source_dsa *tmp = src->next;
655                         talloc_free(src);
656                         src = tmp;
657                 }
658         }
659
660 done:
661         talloc_free(mem_ctx);
662         return status;
663 }
664
665 WERROR dreplsrv_refresh_partitions(struct dreplsrv_service *s)
666 {
667         WERROR status;
668         struct dreplsrv_partition *p;
669
670         for (p = s->partitions; p; p = p->next) {
671                 status = dreplsrv_refresh_partition(s, p);
672                 W_ERROR_NOT_OK_RETURN(status);
673         }
674
675         return WERR_OK;
676 }