s4:dsdb/repl: make use of dcerpc_binding_set_string_option("target_principal")
[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 NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
157                                        TALLOC_CTX *mem_ctx,
158                                        const struct repsFromTo1 *rft,
159                                        const 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",
274                                                     GUID_string(tmp_ctx, &rft->source_dsa_obj_guid),
275                                                     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                 if (strcmp(cur->binding->host, hostname) == 0) {
302                         conn = cur;
303                         break;
304                 }
305         }
306
307         if (!conn) {
308                 NTSTATUS nt_status;
309                 char *binding_str;
310                 const char *target_principal = NULL;
311
312                 conn = talloc_zero(s, struct dreplsrv_out_connection);
313                 W_ERROR_HAVE_NO_MEMORY(conn);
314
315                 conn->service   = s;
316
317                 binding_str = talloc_asprintf(conn, "ncacn_ip_tcp:%s[krb5,seal]",
318                                               hostname);
319                 W_ERROR_HAVE_NO_MEMORY(binding_str);
320                 nt_status = dcerpc_parse_binding(conn, binding_str, &conn->binding);
321                 talloc_free(binding_str);
322                 if (!NT_STATUS_IS_OK(nt_status)) {
323                         return ntstatus_to_werror(nt_status);
324                 }
325
326                 /* use the GC principal for DRS replication */
327                 nt_status = dreplsrv_get_target_principal(s, conn->binding,
328                                                           rft, &target_principal);
329                 if (!NT_STATUS_IS_OK(nt_status)) {
330                         return ntstatus_to_werror(nt_status);
331                 }
332
333                 nt_status = dcerpc_binding_set_string_option(conn->binding,
334                                                              "target_principal",
335                                                              target_principal);
336                 if (!NT_STATUS_IS_OK(nt_status)) {
337                         return ntstatus_to_werror(nt_status);
338                 }
339
340                 DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
341
342                 DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
343         } else {
344                 DEBUG(4,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
345         }
346
347         *_conn = conn;
348         return WERR_OK;
349 }
350
351 /*
352   find an existing source dsa in a list
353  */
354 static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa *list,
355                                                                       struct GUID *guid)
356 {
357         struct dreplsrv_partition_source_dsa *s;
358         for (s=list; s; s=s->next) {
359                 if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
360                         return s;
361                 }
362         }
363         return NULL;    
364 }
365
366
367
368 static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
369                                                 struct dreplsrv_partition *p,
370                                                 struct dreplsrv_partition_source_dsa **listp,
371                                                 struct dreplsrv_partition_source_dsa *check_list,
372                                                 const struct ldb_val *val)
373 {
374         WERROR status;
375         enum ndr_err_code ndr_err;
376         struct dreplsrv_partition_source_dsa *source, *s2;
377
378         source = talloc_zero(p, struct dreplsrv_partition_source_dsa);
379         W_ERROR_HAVE_NO_MEMORY(source);
380
381         ndr_err = ndr_pull_struct_blob(val, source, 
382                                        &source->_repsFromBlob,
383                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
384         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
385                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
386                 talloc_free(source);
387                 return ntstatus_to_werror(nt_status);
388         }
389         /* NDR_PRINT_DEBUG(repsFromToBlob, &source->_repsFromBlob); */
390         if (source->_repsFromBlob.version != 1) {
391                 talloc_free(source);
392                 return WERR_DS_DRA_INTERNAL_ERROR;
393         }
394
395         source->partition       = p;
396         source->repsFrom1       = &source->_repsFromBlob.ctr.ctr1;
397
398         status = dreplsrv_out_connection_attach(s, source->repsFrom1, &source->conn);
399         W_ERROR_NOT_OK_RETURN(status);
400
401         if (check_list && 
402             dreplsrv_find_source_dsa(check_list, &source->repsFrom1->source_dsa_obj_guid)) {
403                 /* its in the check list, don't add it again */
404                 talloc_free(source);
405                 return WERR_OK;
406         }
407
408         /* re-use an existing source if found */
409         for (s2=*listp; s2; s2=s2->next) {
410                 if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid, 
411                                  &source->repsFrom1->source_dsa_obj_guid) == 0) {
412                         talloc_free(s2->repsFrom1->other_info);
413                         *s2->repsFrom1 = *source->repsFrom1;
414                         talloc_steal(s2, s2->repsFrom1->other_info);
415                         talloc_free(source);
416                         return WERR_OK;
417                 }
418         }
419
420         DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
421         return WERR_OK;
422 }
423
424 /**
425  * Find a partition when given a NC
426  * If the NC can't be found it will return BAD_NC
427  * Initial checks for invalid parameters have to be done beforehand
428  */
429 WERROR dreplsrv_partition_find_for_nc(struct dreplsrv_service *s,
430                                       struct GUID *nc_guid,
431                                       struct dom_sid *nc_sid,
432                                       const char *nc_dn_str,
433                                       struct dreplsrv_partition **_p)
434 {
435         struct dreplsrv_partition *p;
436         bool valid_sid, valid_guid;
437         struct dom_sid null_sid;
438         ZERO_STRUCT(null_sid);
439
440         SMB_ASSERT(_p);
441
442         valid_sid  = nc_sid && !dom_sid_equal(&null_sid, nc_sid);
443         valid_guid = nc_guid && !GUID_all_zero(nc_guid);
444
445         if (!valid_sid && !valid_guid && (!nc_dn_str)) {
446                 return WERR_DS_DRA_BAD_NC;
447         }
448
449         for (p = s->partitions; p; p = p->next) {
450                 if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
451                     || strequal(p->nc.dn, nc_dn_str)
452                     || (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
453                 {
454                         /* fill in he right guid and sid if possible */
455                         if (nc_guid && !valid_guid) {
456                                 dsdb_get_extended_dn_guid(p->dn, nc_guid, "GUID");
457                         }
458                         if (nc_sid && !valid_sid) {
459                                 dsdb_get_extended_dn_sid(p->dn, nc_sid, "SID");
460                         }
461                         *_p = p;
462                         return WERR_OK;
463                 }
464         }
465
466         return WERR_DS_DRA_BAD_NC;
467 }
468
469 WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
470                                              const struct GUID *dsa_guid,
471                                              struct dreplsrv_partition_source_dsa **_dsa)
472 {
473         struct dreplsrv_partition_source_dsa *dsa;
474
475         SMB_ASSERT(dsa_guid != NULL);
476         SMB_ASSERT(!GUID_all_zero(dsa_guid));
477         SMB_ASSERT(_dsa);
478
479         for (dsa = p->sources; dsa; dsa = dsa->next) {
480                 if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
481                         *_dsa = dsa;
482                         return WERR_OK;
483                 }
484         }
485
486         return WERR_DS_DRA_NO_REPLICA;
487 }
488
489 WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
490                                             const char *dsa_dns,
491                                             struct dreplsrv_partition_source_dsa **_dsa)
492 {
493         struct dreplsrv_partition_source_dsa *dsa;
494
495         SMB_ASSERT(dsa_dns != NULL);
496         SMB_ASSERT(_dsa);
497
498         for (dsa = p->sources; dsa; dsa = dsa->next) {
499                 if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
500                         *_dsa = dsa;
501                         return WERR_OK;
502                 }
503         }
504
505         return WERR_DS_DRA_NO_REPLICA;
506 }
507
508
509 /*
510   create a temporary dsa structure for a replication. This is needed
511   for the initial replication of a new partition, such as when a new
512   domain NC is created and we are a global catalog server
513  */
514 WERROR dreplsrv_partition_source_dsa_temporary(struct dreplsrv_partition *p,
515                                                TALLOC_CTX *mem_ctx,
516                                                const struct GUID *dsa_guid,
517                                                struct dreplsrv_partition_source_dsa **_dsa)
518 {
519         struct dreplsrv_partition_source_dsa *dsa;
520         WERROR werr;
521
522         dsa = talloc_zero(mem_ctx, struct dreplsrv_partition_source_dsa);
523         W_ERROR_HAVE_NO_MEMORY(dsa);
524
525         dsa->partition = p;
526         dsa->repsFrom1 = &dsa->_repsFromBlob.ctr.ctr1;
527         dsa->repsFrom1->replica_flags = 0;
528         dsa->repsFrom1->source_dsa_obj_guid = *dsa_guid;
529
530         dsa->repsFrom1->other_info = talloc_zero(dsa, struct repsFromTo1OtherInfo);
531         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info);
532
533         dsa->repsFrom1->other_info->dns_name = samdb_ntds_msdcs_dns_name(p->service->samdb,
534                                                                          dsa->repsFrom1->other_info, dsa_guid);
535         W_ERROR_HAVE_NO_MEMORY(dsa->repsFrom1->other_info->dns_name);
536
537         werr = dreplsrv_out_connection_attach(p->service, dsa->repsFrom1, &dsa->conn);
538         if (!W_ERROR_IS_OK(werr)) {
539                 DEBUG(0,(__location__ ": Failed to attach connection to %s\n",
540                          ldb_dn_get_linearized(p->dn)));
541                 talloc_free(dsa);
542                 return werr;
543         }
544
545         *_dsa = dsa;
546
547         return WERR_OK;
548 }
549
550
551 static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
552                                          struct dreplsrv_partition *p)
553 {
554         WERROR status;
555         NTSTATUS ntstatus;
556         struct ldb_message_element *orf_el = NULL;
557         struct ldb_result *r = NULL;
558         unsigned int i;
559         int ret;
560         TALLOC_CTX *mem_ctx = talloc_new(p);
561         static const char *attrs[] = {
562                 "repsFrom",
563                 "repsTo",
564                 NULL
565         };
566         struct ldb_dn *dn;
567
568         DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
569                 ldb_dn_get_linearized(p->dn)));
570
571         ret = dsdb_search_dn(s->samdb, mem_ctx, &r, p->dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
572         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
573                 /* we haven't replicated the partition yet, but we
574                  * can fill in the guid, sid etc from the partition DN */
575                 dn = p->dn;
576         } else if (ret != LDB_SUCCESS) {
577                 talloc_free(mem_ctx);
578                 return WERR_FOOBAR;
579         } else {
580                 dn = r->msgs[0]->dn;
581         }
582         
583         talloc_free(discard_const(p->nc.dn));
584         ZERO_STRUCT(p->nc);
585         p->nc.dn        = ldb_dn_alloc_linearized(p, dn);
586         W_ERROR_HAVE_NO_MEMORY(p->nc.dn);
587         ntstatus = dsdb_get_extended_dn_guid(dn, &p->nc.guid, "GUID");
588         if (!NT_STATUS_IS_OK(ntstatus)) {
589                 DEBUG(0,(__location__ ": unable to get GUID for %s: %s\n",
590                          p->nc.dn, nt_errstr(ntstatus)));
591                 talloc_free(mem_ctx);
592                 return WERR_DS_DRA_INTERNAL_ERROR;
593         }
594         dsdb_get_extended_dn_sid(dn, &p->nc.sid, "SID");
595
596         talloc_free(p->uptodatevector.cursors);
597         talloc_free(p->uptodatevector_ex.cursors);
598         ZERO_STRUCT(p->uptodatevector);
599         ZERO_STRUCT(p->uptodatevector_ex);
600
601         ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
602         if (ret != LDB_SUCCESS) {
603                 DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
604         }
605
606         status = WERR_OK;
607
608         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom"))) {
609                 for (i=0; i < orf_el->num_values; i++) {
610                         status = dreplsrv_partition_add_source_dsa(s, p, &p->sources,
611                                                                    NULL, &orf_el->values[i]);
612                         W_ERROR_NOT_OK_GOTO_DONE(status);
613                 }
614         }
615
616         if (r != NULL && (orf_el = ldb_msg_find_element(r->msgs[0], "repsTo"))) {
617                 for (i=0; i < orf_el->num_values; i++) {
618                         status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies,
619                                                                    p->sources, &orf_el->values[i]);
620                         W_ERROR_NOT_OK_GOTO_DONE(status);
621                 }
622         }
623
624 done:
625         talloc_free(mem_ctx);
626         return status;
627 }
628
629 WERROR dreplsrv_refresh_partitions(struct dreplsrv_service *s)
630 {
631         WERROR status;
632         struct dreplsrv_partition *p;
633
634         for (p = s->partitions; p; p = p->next) {
635                 status = dreplsrv_refresh_partition(s, p);
636                 W_ERROR_NOT_OK_RETURN(status);
637         }
638
639         return WERR_OK;
640 }