24
24
#include "auth/auth.h"
25
25
#include "smbd/service.h"
26
26
#include "lib/events/events.h"
27
#include "lib/messaging/irpc.h"
28
27
#include "dsdb/repl/drepl_service.h"
29
#include "lib/ldb/include/ldb_errors.h"
28
#include <ldb_errors.h>
30
29
#include "../lib/util/dlinklist.h"
31
30
#include "librpc/gen_ndr/ndr_misc.h"
32
31
#include "librpc/gen_ndr/ndr_drsuapi.h"
33
32
#include "librpc/gen_ndr/ndr_drsblobs.h"
33
#include "libcli/security/security.h"
34
34
#include "param/param.h"
36
36
WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
39
struct ldb_dn *basedn;
39
static const char *attrs[] = { "namingContexts", NULL };
43
struct ldb_result *res;
41
44
struct ldb_message_element *el;
42
static const char *attrs[] = { "namingContexts", NULL };
46
basedn = ldb_dn_new(s, s->samdb, NULL);
47
W_ERROR_HAVE_NO_MEMORY(basedn);
49
ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
46
tmp_ctx = talloc_new(s);
47
W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
49
ret = ldb_search(s->samdb, tmp_ctx, &res,
50
ldb_dn_new(tmp_ctx, s->samdb, ""), LDB_SCOPE_BASE, attrs, NULL);
52
51
if (ret != LDB_SUCCESS) {
54
} else if (r->count != 1) {
59
el = ldb_msg_find_element(r->msgs[0], "namingContexts");
64
for (i=0; el && i < el->num_values; i++) {
65
const char *v = (const char *)el->values[i].data;
67
struct dreplsrv_partition *p;
69
pdn = ldb_dn_new(s, s->samdb, v);
70
if (!ldb_dn_validate(pdn)) {
74
p = talloc_zero(s, struct dreplsrv_partition);
75
W_ERROR_HAVE_NO_MEMORY(p);
77
p->dn = talloc_steal(p, pdn);
79
DLIST_ADD(s->partitions, p);
81
DEBUG(2, ("dreplsrv_partition[%s] loaded\n", v));
52
DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(s->samdb)));
54
return WERR_DS_DRA_INTERNAL_ERROR;
57
el = ldb_msg_find_element(res->msgs[0], "namingContexts");
59
DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
60
ldb_errstring(s->samdb)));
62
return WERR_DS_DRA_INTERNAL_ERROR;
65
for (i=0; i<el->num_values; i++) {
67
struct dreplsrv_partition *p;
69
pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
72
return WERR_DS_DRA_INTERNAL_ERROR;
74
if (!ldb_dn_validate(pdn)) {
75
return WERR_DS_DRA_INTERNAL_ERROR;
78
p = talloc_zero(s, struct dreplsrv_partition);
79
W_ERROR_HAVE_NO_MEMORY(p);
81
p->dn = talloc_steal(p, pdn);
83
DLIST_ADD(s->partitions, p);
85
DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn)));
86
90
status = dreplsrv_refresh_partitions(s);
87
91
W_ERROR_NOT_OK_RETURN(status);
92
static WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
93
const struct repsFromTo1 *rft,
94
struct dreplsrv_out_connection **_conn)
97
work out the principal to use for DRS replication connections
99
NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
101
const struct repsFromTo1 *rft,
102
const char **target_principal)
105
struct ldb_result *res;
106
const char *attrs[] = { "dNSHostName", NULL };
108
const char *hostname;
111
*target_principal = NULL;
113
tmp_ctx = talloc_new(mem_ctx);
115
/* we need to find their hostname */
116
ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &dn);
117
if (ret != LDB_SUCCESS) {
118
talloc_free(tmp_ctx);
119
/* its OK for their NTDSDSA DN not to be in our database */
123
/* strip off the NTDS Settings */
124
if (!ldb_dn_remove_child_components(dn, 1)) {
125
talloc_free(tmp_ctx);
129
ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, dn, attrs, 0);
130
if (ret != LDB_SUCCESS) {
131
talloc_free(tmp_ctx);
132
/* its OK for their account DN not to be in our database */
136
hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
137
if (hostname == NULL) {
138
talloc_free(tmp_ctx);
139
/* its OK to not have a dnshostname */
143
/* All DCs have the GC/hostname/realm name, but if some of the
144
* preconditions are not satisfied, then we will fall back to
146
* E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN}
147
* name. This means that if a AD server has a dnsHostName set
148
* on it's record, it must also have GC/hostname/realm
149
* servicePrincipalName */
151
*target_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
153
lpcfg_dnsdomain(s->task->lp_ctx));
154
talloc_free(tmp_ctx);
159
WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
160
const struct repsFromTo1 *rft,
161
struct dreplsrv_out_connection **_conn)
96
163
struct dreplsrv_out_connection *cur, *conn = NULL;
97
164
const char *hostname;
131
198
return ntstatus_to_werror(nt_status);
201
/* use the GC principal for DRS replication */
202
nt_status = dreplsrv_get_target_principal(s, conn->binding,
203
rft, &conn->binding->target_principal);
204
if (!NT_STATUS_IS_OK(nt_status)) {
205
return ntstatus_to_werror(nt_status);
134
208
DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
136
DEBUG(2,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
210
DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
138
DEBUG(2,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
212
DEBUG(4,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
220
find an existing source dsa in a list
222
static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa *list,
225
struct dreplsrv_partition_source_dsa *s;
226
for (s=list; s; s=s->next) {
227
if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
145
236
static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
146
237
struct dreplsrv_partition *p,
238
struct dreplsrv_partition_source_dsa **listp,
239
struct dreplsrv_partition_source_dsa *check_list,
147
240
const struct ldb_val *val)
173
266
status = dreplsrv_out_connection_attach(s, source->repsFrom1, &source->conn);
174
267
W_ERROR_NOT_OK_RETURN(status);
176
/* remove any existing source with the same GUID */
177
for (s2=p->sources; s2; s2=s2->next) {
270
dreplsrv_find_source_dsa(check_list, &source->repsFrom1->source_dsa_obj_guid)) {
271
/* its in the check list, don't add it again */
276
/* re-use an existing source if found */
277
for (s2=*listp; s2; s2=s2->next) {
178
278
if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid,
179
279
&source->repsFrom1->source_dsa_obj_guid) == 0) {
180
280
talloc_free(s2->repsFrom1->other_info);
188
DLIST_ADD_END(p->sources, source, struct dreplsrv_partition_source_dsa *);
288
DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
292
WERROR dreplsrv_partition_find_for_nc(struct dreplsrv_service *s,
293
const struct GUID *nc_guid,
294
const struct dom_sid *nc_sid,
295
const char *nc_dn_str,
296
struct dreplsrv_partition **_p)
298
struct dreplsrv_partition *p;
299
bool valid_sid, valid_guid;
300
struct dom_sid null_sid;
301
ZERO_STRUCT(null_sid);
305
valid_sid = nc_sid && !dom_sid_equal(&null_sid, nc_sid);
306
valid_guid = nc_guid && !GUID_all_zero(nc_guid);
308
if (!valid_sid && !valid_guid && !nc_dn_str) {
309
return WERR_DS_DRA_INVALID_PARAMETER;
312
for (p = s->partitions; p; p = p->next) {
313
if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
314
|| strequal(p->nc.dn, nc_dn_str)
315
|| (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
322
return WERR_DS_DRA_BAD_NC;
325
WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
326
const struct GUID *dsa_guid,
327
struct dreplsrv_partition_source_dsa **_dsa)
329
struct dreplsrv_partition_source_dsa *dsa;
331
SMB_ASSERT(dsa_guid != NULL);
332
SMB_ASSERT(!GUID_all_zero(dsa_guid));
335
for (dsa = p->sources; dsa; dsa = dsa->next) {
336
if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
342
return WERR_DS_DRA_NO_REPLICA;
345
WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
347
struct dreplsrv_partition_source_dsa **_dsa)
349
struct dreplsrv_partition_source_dsa *dsa;
351
SMB_ASSERT(dsa_dns != NULL);
354
for (dsa = p->sources; dsa; dsa = dsa->next) {
355
if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
361
return WERR_DS_DRA_NO_REPLICA;
192
365
static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
193
366
struct dreplsrv_partition *p)
196
const struct ldb_val *ouv_value;
197
struct replUpToDateVectorBlob ouv;
198
369
struct dom_sid *nc_sid;
199
370
struct ldb_message_element *orf_el = NULL;
200
371
struct ldb_result *r;
203
374
TALLOC_CTX *mem_ctx = talloc_new(p);
204
375
static const char *attrs[] = {
207
"replUpToDateVector",
212
DEBUG(2, ("dreplsrv_refresh_partition(%s)\n",
383
DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
213
384
ldb_dn_get_linearized(p->dn)));
215
386
ret = ldb_search(s->samdb, mem_ctx, &r, p->dn, LDB_SCOPE_BASE, attrs,
233
401
talloc_free(nc_sid);
236
ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
238
enum ndr_err_code ndr_err;
239
ndr_err = ndr_pull_struct_blob(ouv_value, mem_ctx,
240
lp_iconv_convenience(s->task->lp_ctx), &ouv,
241
(ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
242
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243
NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
244
talloc_free(mem_ctx);
245
return ntstatus_to_werror(nt_status);
247
/* NDR_PRINT_DEBUG(replUpToDateVectorBlob, &ouv); */
248
if (ouv.version != 2) {
249
talloc_free(mem_ctx);
250
return WERR_DS_DRA_INTERNAL_ERROR;
404
talloc_free(p->uptodatevector.cursors);
405
talloc_free(p->uptodatevector_ex.cursors);
406
ZERO_STRUCT(p->uptodatevector);
407
ZERO_STRUCT(p->uptodatevector_ex);
253
p->uptodatevector.count = ouv.ctr.ctr2.count;
254
p->uptodatevector.reserved = ouv.ctr.ctr2.reserved;
255
talloc_free(p->uptodatevector.cursors);
256
p->uptodatevector.cursors = talloc_steal(p, ouv.ctr.ctr2.cursors);
409
ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
410
if (ret != LDB_SUCCESS) {
411
DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
260
* TODO: add our own uptodatevector cursor
264
414
orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom");
266
416
for (i=0; i < orf_el->num_values; i++) {
267
status = dreplsrv_partition_add_source_dsa(s, p, &orf_el->values[i]);
417
status = dreplsrv_partition_add_source_dsa(s, p, &p->sources,
418
NULL, &orf_el->values[i]);
419
W_ERROR_NOT_OK_RETURN(status);
423
orf_el = ldb_msg_find_element(r->msgs[0], "repsTo");
425
for (i=0; i < orf_el->num_values; i++) {
426
status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies,
427
p->sources, &orf_el->values[i]);
268
428
W_ERROR_NOT_OK_RETURN(status);