dreplsrv: Use is_null_sid
[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
449         SMB_ASSERT(_p);
450
451         valid_sid  = nc_sid && !is_null_sid(nc_sid);
452         valid_guid = nc_guid && !GUID_all_zero(nc_guid);
453
454         if (!valid_sid && !valid_guid && (!nc_dn_str)) {
455                 return WERR_DS_DRA_BAD_NC;
456         }
457
458         for (p = s->partitions; p; p = p->next) {
459                 if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
460                     || strequal(p->nc.dn, nc_dn_str)
461                     || (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
462                 {
463                         /* fill in he right guid and sid if possible */
464                         if (nc_guid && !valid_guid) {
465                                 dsdb_get_extended_dn_guid(p->dn, nc_guid, "GUID");
466                         }
467                         if (nc_sid && !valid_sid) {
468                                 dsdb_get_extended_dn_sid(p->dn, nc_sid, "SID");
469                         }
470                         *_p = p;
471                         return WERR_OK;
472                 }
473         }
474
475         return WERR_DS_DRA_BAD_NC;
476 }
477
478 WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
479                                              const struct GUID *dsa_guid,
480                                              struct dreplsrv_partition_source_dsa **_dsa)
481 {
482         struct dreplsrv_partition_source_dsa *dsa;
483
484         SMB_ASSERT(dsa_guid != NULL);
485         SMB_ASSERT(!GUID_all_zero(dsa_guid));
486         SMB_ASSERT(_dsa);
487
488         for (dsa = p->sources; dsa; dsa = dsa->next) {
489                 if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
490                         *_dsa = dsa;
491                         return WERR_OK;
492                 }
493         }
494
495         return WERR_DS_DRA_NO_REPLICA;
496 }
497
498 WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
499                                             const char *dsa_dns,
500                                             struct dreplsrv_partition_source_dsa **_dsa)
501 {
502         struct dreplsrv_partition_source_dsa *dsa;
503
504         SMB_ASSERT(dsa_dns != NULL);
505         SMB_ASSERT(_dsa);
506
507         for (dsa = p->sources; dsa; dsa = dsa->next) {
508                 if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
509                         *_dsa = dsa;
510                         return WERR_OK;
511                 }
512         }
513
514         return WERR_DS_DRA_NO_REPLICA;
515 }
516
517
518 /*
519   create a temporary dsa structure for a replication. This is needed
520   for the initial replication of a new partition, such as when a new
521   domain NC is created and we are a global catalog server
522  */
523 WERROR dreplsrv_partition_source_dsa_temporary(struct dreplsrv_partition *p,
524                                                TALLOC_CTX *mem_ctx,
525                                                const struct GUID *dsa_guid,
526                                                struct dreplsrv_partition_source_dsa **_dsa)
527 {
528         struct dreplsrv_partition_source_dsa *dsa;
529         WERROR werr;
530
531         dsa = talloc_zero(mem_ctx, struct dreplsrv_partition_source_dsa);
532         W_ERROR_HAVE_NO_MEMORY(dsa);
533
534         dsa->partition = p;
535         dsa->repsFrom1 = &dsa->_repsFromBlob.ctr.ctr1;
536         dsa->repsFrom1->replica_flags = 0;
537         dsa->repsFrom1->source_dsa_obj_guid = *dsa_guid;
538
539         dsa->repsFrom1->other_info = talloc_zero(dsa, struct repsFromTo1OtherInfo);
540         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info);
541
542         dsa->repsFrom1->other_info->dns_name = samdb_ntds_msdcs_dns_name(p->service->samdb,
543                                                                          dsa->repsFrom1->other_info, dsa_guid);
544         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info->dns_name);
545
546         werr = dreplsrv_out_connection_attach(p->service, dsa->repsFrom1, &dsa->conn);
547         if (!W_ERROR_IS_OK(werr)) {
548                 DEBUG(0,(__location__ ": Failed to attach connection to %s\n",
549                          ldb_dn_get_linearized(p->dn)));
550                 talloc_free(dsa);
551                 return werr;
552         }
553
554         *_dsa = dsa;
555
556         return WERR_OK;
557 }
558
559
560 static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
561                                          struct dreplsrv_partition *p)
562 {
563         WERROR status;
564         NTSTATUS ntstatus;
565         struct ldb_message_element *orf_el = NULL;
566         struct ldb_result *r = NULL;
567         unsigned int i;
568         int ret;
569         TALLOC_CTX *mem_ctx = talloc_new(p);
570         static const char *attrs[] = {
571                 "repsFrom",
572                 "repsTo",
573                 NULL
574         };
575         struct ldb_dn *dn;
576
577         DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
578                 ldb_dn_get_linearized(p->dn)));
579
580         ret = dsdb_search_dn(s->samdb, mem_ctx, &r, p->dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
581         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
582                 /* we haven't replicated the partition yet, but we
583                  * can fill in the guid, sid etc from the partition DN */
584                 dn = p->dn;
585         } else if (ret != LDB_SUCCESS) {
586                 talloc_free(mem_ctx);
587                 return WERR_FOOBAR;
588         } else {
589                 dn = r->msgs[0]->dn;
590         }
591         
592         talloc_free(discard_const(p->nc.dn));
593         ZERO_STRUCT(p->nc);
594         p->nc.dn        = ldb_dn_alloc_linearized(p, dn);
595         W_ERROR_HAVE_NO_MEMORY(p->nc.dn);
596         ntstatus = dsdb_get_extended_dn_guid(dn, &p->nc.guid, "GUID");
597         if (!NT_STATUS_IS_OK(ntstatus)) {
598                 DEBUG(0,(__location__ ": unable to get GUID for %s: %s\n",
599                          p->nc.dn, nt_errstr(ntstatus)));
600                 talloc_free(mem_ctx);
601                 return WERR_DS_DRA_INTERNAL_ERROR;
602         }
603         dsdb_get_extended_dn_sid(dn, &p->nc.sid, "SID");
604
605         talloc_free(p->uptodatevector.cursors);
606         talloc_free(p->uptodatevector_ex.cursors);
607         ZERO_STRUCT(p->uptodatevector);
608         ZERO_STRUCT(p->uptodatevector_ex);
609
610         ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
611         if (ret != LDB_SUCCESS) {
612                 DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
613         }
614
615         status = WERR_OK;
616
617         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom"))) {
618                 for (i=0; i < orf_el->num_values; i++) {
619                         status = dreplsrv_partition_add_source_dsa(s, p, &p->sources,
620                                                                    NULL, &orf_el->values[i]);
621                         W_ERROR_NOT_OK_GOTO_DONE(status);
622                 }
623         }
624
625         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsTo"))) {
626                 for (i=0; i < orf_el->num_values; i++) {
627                         status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies,
628                                                                    p->sources, &orf_el->values[i]);
629                         W_ERROR_NOT_OK_GOTO_DONE(status);
630                 }
631         }
632
633 done:
634         talloc_free(mem_ctx);
635         return status;
636 }
637
638 WERROR dreplsrv_refresh_partitions(struct dreplsrv_service *s)
639 {
640         WERROR status;
641         struct dreplsrv_partition *p;
642
643         for (p = s->partitions; p; p = p->next) {
644                 status = dreplsrv_refresh_partition(s, p);
645                 W_ERROR_NOT_OK_RETURN(status);
646         }
647
648         return WERR_OK;
649 }