1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

s4:dsdb: add forest trust scanner service

See MS-ADTS 3.1.1.6.4 PDC Forest Trust Update

It basically connects to all forest trusts
and searches for crossRef objects with
SYSTEM_FLAG_CR_NTDS_DOMAIN under
CN=Partitions,CN=Configuration.

With this information it add/removes
FOREST_TRUST_SCANNER_INFO records into
the msDS-TrustForestTrustInfo of the local
trustedDomain object.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
This commit is contained in:
Stefan Metzmacher 2025-02-10 14:56:15 +01:00 committed by Ralph Boehme
parent af0b912215
commit f5b112b436
5 changed files with 1679 additions and 0 deletions

View File

@ -0,0 +1,122 @@
/*
Unix SMB/CIFS Implementation.
forest trust scanner service
Copyright (C) Stefan Metzmacher 2025
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "dsdb/samdb/samdb.h"
#include "samba/service.h"
#include "dsdb/ft_scanner/ft_scanner_service.h"
#include "dsdb/ft_scanner/ft_scanner_service_proto.h"
#include <ldb_errors.h>
static void ft_scanner_periodic_run(struct ft_scanner_service *service);
static void ft_scanner_periodic_handler_te(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval t,
void *ptr)
{
struct ft_scanner_service *service =
talloc_get_type_abort(ptr,
struct ft_scanner_service);
NTSTATUS status;
service->periodic.te = NULL;
ft_scanner_periodic_run(service);
status = ft_scanner_periodic_schedule(service,
service->periodic.interval);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(service->task, nt_errstr(status), false);
return;
}
}
NTSTATUS ft_scanner_periodic_schedule(struct ft_scanner_service *service,
uint32_t next_interval)
{
TALLOC_CTX *frame = NULL;
struct tevent_timer *new_te = NULL;
struct timeval next_time;
/* prevent looping */
if (next_interval == 0) next_interval = 1;
next_time = timeval_current_ofs(next_interval, 50);
if (service->periodic.te) {
/*
* if the timestamp of the new event is higher,
* as current next we don't need to reschedule
*/
if (timeval_compare(&next_time, &service->periodic.next_event) > 0) {
return NT_STATUS_OK;
}
}
/* reset the next scheduled timestamp */
service->periodic.next_event = next_time;
new_te = tevent_add_timer(service->task->event_ctx, service,
service->periodic.next_event,
ft_scanner_periodic_handler_te, service);
if (new_te == NULL) {
return NT_STATUS_NO_MEMORY;
}
frame = talloc_stackframe();
D_DEBUG("ft_scanner_periodic_schedule(%u) %sscheduled for: %s\n",
next_interval,
(service->periodic.te?"re":""),
nt_time_string(frame, timeval_to_nttime(&next_time)));
TALLOC_FREE(frame);
TALLOC_FREE(service->periodic.te);
service->periodic.te = new_te;
return NT_STATUS_OK;
}
static void ft_scanner_periodic_run(struct ft_scanner_service *service)
{
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
bool is_pdc;
is_pdc = samdb_is_pdc(service->l_samdb);
if (!is_pdc) {
DBG_DEBUG("NO-OP: we are not the current PDC\n");
TALLOC_FREE(frame);
return;
}
DBG_DEBUG("Running ft_scanner_check_trusts()\n");
status = ft_scanner_check_trusts(service);
if (!NT_STATUS_IS_OK(status)) {
DBG_WARNING("ft_scanner_check_trusts() => %s\n",
nt_errstr(status));
TALLOC_FREE(frame);
return;
}
DBG_DEBUG("ft_scanner_check_trusts() => %s\n",
nt_errstr(status));
TALLOC_FREE(frame);
}

View File

@ -0,0 +1,157 @@
/*
Unix SMB/CIFS Implementation.
forest trust scanner service
Copyright (C) Stefan Metzmacher 2025
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "dsdb/samdb/samdb.h"
#include "auth/auth.h"
#include "samba/service.h"
#include "dsdb/ft_scanner/ft_scanner_service.h"
#include "dsdb/ft_scanner/ft_scanner_service_proto.h"
#include <ldb_errors.h>
#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/ndr_irpc.h"
#include "param/param.h"
#include "libds/common/roles.h"
static NTSTATUS ft_scanner_connect_samdb(struct ft_scanner_service *service)
{
struct auth_session_info *session_info = NULL;
session_info = system_session(service->task->lp_ctx);
if (session_info == NULL) {
return NT_STATUS_DS_INIT_FAILURE;
}
service->l_samdb = samdb_connect(service,
service->task->event_ctx,
service->task->lp_ctx,
session_info,
NULL,
0);
if (service->l_samdb == NULL) {
return NT_STATUS_DS_UNAVAILABLE;
}
return NT_STATUS_OK;
}
/*
startup the forest trust scanner service task
*/
static NTSTATUS ft_scanner_task_init(struct task_server *task)
{
struct ft_scanner_service *service = NULL;
uint32_t periodic_startup_interval;
NTSTATUS status;
bool am_rodc;
int ret;
switch (lpcfg_server_role(task->lp_ctx)) {
case ROLE_STANDALONE:
task_server_terminate(task,
"ft_scanner: no forest trust scanning "
"required in standalone configuration",
false);
return NT_STATUS_INVALID_DOMAIN_ROLE;
case ROLE_DOMAIN_MEMBER:
task_server_terminate(task,
"ft_scanner: no forest trust scanning "
"required in domain member configuration",
false);
return NT_STATUS_INVALID_DOMAIN_ROLE;
case ROLE_ACTIVE_DIRECTORY_DC:
/* Yes, we want forest trust scanning */
break;
}
task_server_set_title(task, "task[ft_scanner]");
service = talloc_zero(task, struct ft_scanner_service);
if (!service) {
task_server_terminate(task, "ft_scanner_task_init: out of memory", true);
return NT_STATUS_NO_MEMORY;
}
service->task = task;
service->startup_time = timeval_current();
task->private_data = service;
status = ft_scanner_connect_samdb(service);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(task, talloc_asprintf(task,
"ft_scanner: Failed to connect to local samdb: %s\n",
nt_errstr(status)), true);
return status;
}
ret = samdb_rodc(service->l_samdb, &am_rodc);
if (ret != LDB_SUCCESS) {
status = NT_STATUS_LDAP(ret);
task_server_terminate(task, talloc_asprintf(task,
"ft_scanner: Failed to get rodc state: %s\n",
nt_errstr(status)), true);
return status;
}
if (am_rodc) {
task_server_terminate(task,
"ft_scanner: no forest trust scanning "
"required on RODC configuration",
false);
return NT_STATUS_INVALID_DOMAIN_ROLE;
}
periodic_startup_interval = lpcfg_parm_int(task->lp_ctx,
NULL,
"ft_scanner",
"periodic_startup_interval",
15); /* in seconds */
service->periodic.interval = lpcfg_parm_int(task->lp_ctx,
NULL,
"ft_scanner",
"periodic_interval",
900); /* in seconds */
service->periodic.interval = MAX(service->periodic.interval, 60);
status = ft_scanner_periodic_schedule(service, periodic_startup_interval);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(task, talloc_asprintf(task,
"ft_scanner: Failed to periodic schedule: %s\n",
nt_errstr(status)), true);
return status;
}
irpc_add_name(task->msg_ctx, "ft_scanner");
return NT_STATUS_OK;
}
/*
register ourselves as a available server
*/
NTSTATUS server_service_ft_scanner_init(TALLOC_CTX *ctx)
{
static const struct service_details details = {
.inhibit_fork_on_accept = true,
.inhibit_pre_fork = true,
.task_init = ft_scanner_task_init,
.post_fork = NULL,
};
return register_server_service(ctx, "ft_scanner", &details);
}

View File

@ -0,0 +1,57 @@
/*
Unix SMB/CIFS Implementation.
forest trust scanner service
Copyright (C) Stefan Metzmacher 2025
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DSDB_FT_SCANNER_FT_SCANNER_SERVICE_H_
#define _DSDB_FT_SCANNER_FT_SCANNER_SERVICE_H_
struct ft_scanner_service {
/* the whole ft_scanner service is in one task */
struct task_server *task;
/* the time the service was started */
struct timeval startup_time;
/*
* a connection to the local samdb
*/
struct ldb_context *l_samdb;
/* some stuff for periodic processing */
struct {
/*
* the interval between to periodic runs
*/
uint32_t interval;
/*
* the timestamp for the next event,
* this is the timestamp passed to event_add_timed()
*/
struct timeval next_event;
/*
* here we have a reference to the timed event the
* schedules the periodic stuff
*/
struct tevent_timer *te;
} periodic;
};
#endif /* _DSDB_FT_SCANNER_FT_SCANNER_SERVICE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -69,6 +69,20 @@ bld.SAMBA_MODULE('service_dns_update',
enabled=bld.AD_DC_BUILD_IS_ENABLED()
)
bld.SAMBA_MODULE('service_ft_scanner',
source='''
ft_scanner/ft_scanner_service.c
ft_scanner/ft_scanner_periodic.c
ft_scanner/ft_scanner_tdos.c
''',
autoproto='ft_scanner/ft_scanner_service_proto.h',
subsystem='service',
init_function='server_service_ft_scanner_init',
deps='samdb process_model',
internal_module=False,
enabled=bld.AD_DC_BUILD_IS_ENABLED()
)
pyldb_util = bld.pyembed_libname('pyldb-util')
pyrpc_util = bld.pyembed_libname('pyrpc_util')
pyparam_util = bld.pyembed_libname('pyparam_util')