1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

s3-winbindd: Listen on IRPC and do forwarded DNS updates on an RODC

Change-Id: Ib87933c318f510d95f7008e122216d73803ede68
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
This commit is contained in:
Andrew Bartlett 2014-05-06 17:00:09 +12:00
parent cb79cc342e
commit 223fbdaf38
8 changed files with 423 additions and 0 deletions

View File

@ -2568,3 +2568,268 @@ NTSTATUS netlogon_creds_cli_LogonSamLogon(
TALLOC_FREE(frame); TALLOC_FREE(frame);
return status; return status;
} }
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
struct tevent_context *ev;
struct netlogon_creds_cli_context *context;
struct dcerpc_binding_handle *binding_handle;
char *srv_name_slash;
enum dcerpc_AuthType auth_type;
enum dcerpc_AuthLevel auth_level;
const char *site_name;
uint32_t dns_ttl;
struct NL_DNS_NAME_INFO_ARRAY *dns_names;
struct netlogon_creds_CredentialState *creds;
struct netlogon_creds_CredentialState tmp_creds;
struct netr_Authenticator req_auth;
struct netr_Authenticator rep_auth;
};
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
NTSTATUS status);
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
const char *site_name,
uint32_t dns_ttl,
struct NL_DNS_NAME_INFO_ARRAY *dns_names)
{
struct tevent_req *req;
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
struct tevent_req *subreq;
bool ok;
req = tevent_req_create(mem_ctx, &state,
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
if (req == NULL) {
return NULL;
}
state->ev = ev;
state->context = context;
state->binding_handle = b;
state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
context->server.computer);
if (tevent_req_nomem(state->srv_name_slash, req)) {
return tevent_req_post(req, ev);
}
state->site_name = site_name;
state->dns_ttl = dns_ttl;
state->dns_names = dns_names;
dcerpc_binding_handle_auth_info(state->binding_handle,
&state->auth_type,
&state->auth_level);
subreq = netlogon_creds_cli_lock_send(state, state->ev,
state->context);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq,
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
req);
return req;
}
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
NTSTATUS status)
{
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
if (state->creds == NULL) {
return;
}
if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
!NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
!NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
TALLOC_FREE(state->creds);
return;
}
netlogon_creds_cli_delete(state->context, &state->creds);
}
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
NTSTATUS status;
status = netlogon_creds_cli_lock_recv(subreq, state,
&state->creds);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
switch (state->auth_level) {
case DCERPC_AUTH_LEVEL_INTEGRITY:
case DCERPC_AUTH_LEVEL_PRIVACY:
break;
default:
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
return;
}
} else {
uint32_t tmp = state->creds->negotiate_flags;
if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
/*
* if DCERPC_AUTH_TYPE_SCHANNEL is supported
* it should be used, which means
* we had a chance to verify no downgrade
* happened.
*
* This relies on netlogon_creds_cli_check*
* being called before, as first request after
* the DCERPC bind.
*/
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
return;
}
}
/*
* we defer all callbacks in order to cleanup
* the database record.
*/
tevent_req_defer_callback(req, state->ev);
state->tmp_creds = *state->creds;
netlogon_creds_client_authenticator(&state->tmp_creds,
&state->req_auth);
ZERO_STRUCT(state->rep_auth);
subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
state->binding_handle,
state->srv_name_slash,
state->tmp_creds.computer_name,
&state->req_auth,
&state->rep_auth,
state->site_name,
state->dns_ttl,
state->dns_names);
if (tevent_req_nomem(subreq, req)) {
status = NT_STATUS_NO_MEMORY;
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
return;
}
tevent_req_set_callback(subreq,
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
req);
}
static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
tevent_req_data(req,
struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
NTSTATUS status;
NTSTATUS result;
bool ok;
status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state,
&result);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
return;
}
ok = netlogon_creds_client_check(&state->tmp_creds,
&state->rep_auth.cred);
if (!ok) {
status = NT_STATUS_ACCESS_DENIED;
tevent_req_nterror(req, status);
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
return;
}
if (tevent_req_nterror(req, result)) {
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
return;
}
*state->creds = state->tmp_creds;
status = netlogon_creds_cli_store(state->context,
&state->creds);
if (tevent_req_nterror(req, status)) {
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
return;
}
tevent_req_done(req);
}
NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
{
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
tevent_req_received(req);
return status;
}
tevent_req_received(req);
return NT_STATUS_OK;
}
NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
const char *site_name,
uint32_t dns_ttl,
struct NL_DNS_NAME_INFO_ARRAY *dns_names)
{
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
site_name,
dns_ttl,
dns_names);
if (req == NULL) {
goto fail;
}
if (!tevent_req_poll_ntstatus(req, ev, &status)) {
goto fail;
}
status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
fail:
TALLOC_FREE(frame);
return status;
}

View File

@ -132,5 +132,19 @@ NTSTATUS netlogon_creds_cli_LogonSamLogon(
union netr_Validation **validation, union netr_Validation **validation,
uint8_t *authoritative, uint8_t *authoritative,
uint32_t *flags); uint32_t *flags);
struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
const char *site_name,
uint32_t dns_ttl,
struct NL_DNS_NAME_INFO_ARRAY *dns_names);
NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req);
NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
struct netlogon_creds_cli_context *context,
struct dcerpc_binding_handle *b,
const char *site_name,
uint32_t dns_ttl,
struct NL_DNS_NAME_INFO_ARRAY *dns_names);
#endif /* NETLOGON_CREDS_CLI_H */ #endif /* NETLOGON_CREDS_CLI_H */

View File

@ -167,4 +167,10 @@ interface wbint
NTSTATUS wbint_PingDc( NTSTATUS wbint_PingDc(
[out,string,charset(UTF8)] char **dcname [out,string,charset(UTF8)] char **dcname
); );
NTSTATUS wbint_DsrUpdateReadOnlyServerDnsRecords(
[in,unique] [string,charset(UTF16)] uint16 *site_name,
[in] uint32 dns_ttl,
[in,out,ref] NL_DNS_NAME_INFO_ARRAY *dns_names
);
} }

View File

@ -42,6 +42,7 @@
#include "source4/lib/messaging/irpc.h" #include "source4/lib/messaging/irpc.h"
#include "source4/lib/messaging/messaging.h" #include "source4/lib/messaging/messaging.h"
#include "lib/param/param.h" #include "lib/param/param.h"
#include "source4/librpc/gen_ndr/ndr_winbind.h"
#undef DBGC_CLASS #undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND #define DBGC_CLASS DBGC_WINBIND
@ -1147,6 +1148,7 @@ bool winbindd_use_cache(void)
static void winbindd_register_handlers(struct messaging_context *msg_ctx, static void winbindd_register_handlers(struct messaging_context *msg_ctx,
bool foreground) bool foreground)
{ {
NTSTATUS status;
/* Setup signal handlers */ /* Setup signal handlers */
if (!winbindd_setup_sig_term_handler(true)) if (!winbindd_setup_sig_term_handler(true))
@ -1246,6 +1248,12 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
} }
} }
status = IRPC_REGISTER(winbind_imessaging_context(), winbind, WINBIND_DSRUPDATEREADONLYSERVERDNSRECORDS,
wb_irpc_DsrUpdateReadOnlyServerDnsRecords, NULL);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Could not register IRPC handler for wb_irpc_DsrUpdateReadOnlyServerDnsRecords\n"));
exit(1);
}
} }
struct winbindd_addrchanged_state { struct winbindd_addrchanged_state {

View File

@ -29,6 +29,7 @@
#include "../librpc/gen_ndr/ndr_netlogon_c.h" #include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "idmap.h" #include "idmap.h"
#include "../libcli/security/security.h" #include "../libcli/security/security.h"
#include "../libcli/auth/netlogon_creds_cli.h"
void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r) void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
{ {
@ -717,3 +718,41 @@ NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
DEBUG(5, ("winbindd_dual_ping_dc succeeded\n")); DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
return NT_STATUS_OK; return NT_STATUS_OK;
} }
NTSTATUS _wbint_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
struct wbint_DsrUpdateReadOnlyServerDnsRecords *r)
{
struct winbindd_domain *domain;
NTSTATUS status;
struct rpc_pipe_client *netlogon_pipe;
domain = wb_child_domain();
if (domain == NULL) {
return NT_STATUS_REQUEST_NOT_ACCEPTED;
}
status = cm_connect_netlogon(domain, &netlogon_pipe);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
goto done;
}
status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
netlogon_pipe->binding_handle,
r->in.site_name,
r->in.dns_ttl,
r->in.dns_names);
/* Pass back result code - zero for success, other values for
specific failures. */
DEBUG(3,("DNS records for domain %s %s\n", domain->name,
NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
done:
DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
("Update of DNS records via RW DC %s returned %s\n",
domain->name, nt_errstr(status)));
return status;
}

View File

@ -908,4 +908,9 @@ NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
/* The following definitions come from winbindd/winbindd_ads.c */ /* The following definitions come from winbindd/winbindd_ads.c */
ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name); ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name);
/* The following definitions come from winbindd/winbindd_update_rodc_dns.c */
struct irpc_message;
struct winbind_DsrUpdateReadOnlyServerDnsRecords;
NTSTATUS wb_irpc_DsrUpdateReadOnlyServerDnsRecords(struct irpc_message *msg,
struct winbind_DsrUpdateReadOnlyServerDnsRecords *req);
#endif /* _WINBINDD_PROTO_H_ */ #endif /* _WINBINDD_PROTO_H_ */

View File

@ -0,0 +1,85 @@
/*
Unix SMB/CIFS implementation.
async implementation of WINBINDD_CHANGE_MACHINE_ACCT
Copyright (C) Volker Lendecke 2009
Copyright (C) Guenther Deschner 2009
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 "winbindd.h"
#include "librpc/gen_ndr/ndr_wbint_c.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
#include "source4/lib/messaging/irpc.h"
struct wb_irpc_DsrUpdateReadOnlyServerDnsRecords_state {
struct irpc_message *msg;
struct winbind_DsrUpdateReadOnlyServerDnsRecords *req;
};
static void wb_irpc_DsrUpdateReadOnlyServerDnsRecords_callback(struct tevent_req *subreq);
NTSTATUS wb_irpc_DsrUpdateReadOnlyServerDnsRecords(struct irpc_message *msg,
struct winbind_DsrUpdateReadOnlyServerDnsRecords *req)
{
struct wb_irpc_DsrUpdateReadOnlyServerDnsRecords_state *s;
struct tevent_req *subreq;
struct winbindd_domain *domain;
DEBUG(5, ("wb_irpc_DsrUpdateReadOnlyServerDnsRecords called\n"));
s = talloc(msg, struct wb_irpc_DsrUpdateReadOnlyServerDnsRecords_state);
NT_STATUS_HAVE_NO_MEMORY(s);
s->msg = msg;
s->req = req;
domain = find_our_domain();
if (domain == NULL) {
return NT_STATUS_NO_SUCH_DOMAIN;
}
subreq = dcerpc_wbint_DsrUpdateReadOnlyServerDnsRecords_send(s, winbind_event_context(),
dom_child_handle(domain),
req->in.site_name,
req->in.dns_ttl,
req->in.dns_names);
if (!subreq) {
return NT_STATUS_NO_MEMORY;
}
tevent_req_set_callback(subreq,
wb_irpc_DsrUpdateReadOnlyServerDnsRecords_callback,
s);
msg->defer_reply = true;
return NT_STATUS_OK;
}
static void wb_irpc_DsrUpdateReadOnlyServerDnsRecords_callback(struct tevent_req *subreq)
{
struct wb_irpc_DsrUpdateReadOnlyServerDnsRecords_state *s =
tevent_req_callback_data(subreq,
struct wb_irpc_DsrUpdateReadOnlyServerDnsRecords_state);
NTSTATUS status, result;
DEBUG(5, ("wb_irpc_DsrUpdateReadOnlyServerDnsRecords_callback called\n"));
status = dcerpc_wbint_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, s, &result);
any_nt_status_not_ok(status, result, &status);
TALLOC_FREE(subreq);
irpc_send_reply(s->msg, status);
}

View File

@ -943,6 +943,7 @@ bld.SAMBA3_BINARY('winbindd/winbindd',
winbindd/winbindd_list_groups.c winbindd/winbindd_list_groups.c
winbindd/winbindd_check_machine_acct.c winbindd/winbindd_check_machine_acct.c
winbindd/winbindd_change_machine_acct.c winbindd/winbindd_change_machine_acct.c
winbindd/winbindd_update_rodc_dns.c
winbindd/winbindd_ping_dc.c winbindd/winbindd_ping_dc.c
winbindd/winbindd_pam_auth.c winbindd/winbindd_pam_auth.c
winbindd/winbindd_pam_logoff.c winbindd/winbindd_pam_logoff.c