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 */
dreplsrv_load_partitions(struct dreplsrv_service * s)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 */
dreplsrv_spn_exists(struct ldb_context * samdb,struct ldb_dn * account_dn,const char * principal_name)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 */
dreplsrv_get_target_principal(struct dreplsrv_service * s,TALLOC_CTX * mem_ctx,const struct repsFromTo1 * rft,char ** target_principal)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
dreplsrv_out_connection_attach(struct dreplsrv_service * s,const struct repsFromTo1 * rft,struct dreplsrv_out_connection ** _conn)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 */
dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa * list,struct GUID * guid)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
dreplsrv_partition_add_source_dsa(struct dreplsrv_service * s,struct dreplsrv_partition * p,struct dreplsrv_partition_source_dsa ** listp,struct dreplsrv_partition_source_dsa * check_list,const struct ldb_val * val)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 */
dreplsrv_partition_find_for_nc(struct dreplsrv_service * s,struct GUID * nc_guid,struct dom_sid * nc_sid,const char * nc_dn_str,struct dreplsrv_partition ** _p)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
dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition * p,const struct GUID * dsa_guid,struct dreplsrv_partition_source_dsa ** _dsa)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
dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition * p,const char * dsa_dns,struct dreplsrv_partition_source_dsa ** _dsa)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 */
dreplsrv_partition_source_dsa_temporary(struct dreplsrv_partition * p,TALLOC_CTX * mem_ctx,const struct GUID * dsa_guid,struct dreplsrv_partition_source_dsa ** _dsa)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
dreplsrv_refresh_partition(struct dreplsrv_service * s,struct dreplsrv_partition * p)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
dreplsrv_refresh_partitions(struct dreplsrv_service * s)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 }
650