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