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