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