summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2014-05-06 17:00:09 +1200
committerAndrew Bartlett <abartlet@samba.org>2014-06-11 10:18:26 +0200
commit223fbdaf3872fe71a75fec62813b91612af73a2b (patch)
tree95fb233e98d024ba4bc6fae9d3cf517b26dd39ec
parentcb79cc342e30bb2bbac33868836ea13d2d594c30 (diff)
downloadsamba-223fbdaf3872fe71a75fec62813b91612af73a2b.tar.gz
samba-223fbdaf3872fe71a75fec62813b91612af73a2b.tar.xz
samba-223fbdaf3872fe71a75fec62813b91612af73a2b.zip
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>
-rw-r--r--libcli/auth/netlogon_creds_cli.c265
-rw-r--r--libcli/auth/netlogon_creds_cli.h14
-rw-r--r--source3/librpc/idl/wbint.idl6
-rw-r--r--source3/winbindd/winbindd.c8
-rw-r--r--source3/winbindd/winbindd_dual_srv.c39
-rw-r--r--source3/winbindd/winbindd_proto.h5
-rw-r--r--source3/winbindd/winbindd_update_rodc_dns.c85
-rwxr-xr-xsource3/wscript_build1
8 files changed, 423 insertions, 0 deletions
diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 472a45272c7..05a30da98cf 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -2568,3 +2568,268 @@ NTSTATUS netlogon_creds_cli_LogonSamLogon(
TALLOC_FREE(frame);
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;
+}
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 90d01826d06..a910259a88b 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -132,5 +132,19 @@ NTSTATUS netlogon_creds_cli_LogonSamLogon(
union netr_Validation **validation,
uint8_t *authoritative,
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 */
diff --git a/source3/librpc/idl/wbint.idl b/source3/librpc/idl/wbint.idl
index f05107a0a8b..e91ef072fcc 100644
--- a/source3/librpc/idl/wbint.idl
+++ b/source3/librpc/idl/wbint.idl
@@ -167,4 +167,10 @@ interface wbint
NTSTATUS wbint_PingDc(
[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
+ );
}
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index 8a2c09e5158..153a400f2e8 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -42,6 +42,7 @@
#include "source4/lib/messaging/irpc.h"
#include "source4/lib/messaging/messaging.h"
#include "lib/param/param.h"
+#include "source4/librpc/gen_ndr/ndr_winbind.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
@@ -1147,6 +1148,7 @@ bool winbindd_use_cache(void)
static void winbindd_register_handlers(struct messaging_context *msg_ctx,
bool foreground)
{
+ NTSTATUS status;
/* Setup signal handlers */
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 {
diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index f064467bf23..721d293c4d0 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -29,6 +29,7 @@
#include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "idmap.h"
#include "../libcli/security/security.h"
+#include "../libcli/auth/netlogon_creds_cli.h"
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"));
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;
+}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 642aadd440d..7f3eb92e0cb 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -908,4 +908,9 @@ NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
/* The following definitions come from winbindd/winbindd_ads.c */
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_ */
diff --git a/source3/winbindd/winbindd_update_rodc_dns.c b/source3/winbindd/winbindd_update_rodc_dns.c
new file mode 100644
index 00000000000..f809dc615fc
--- /dev/null
+++ b/source3/winbindd/winbindd_update_rodc_dns.c
@@ -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);
+}
diff --git a/source3/wscript_build b/source3/wscript_build
index 806a49712c2..a0080b32fcb 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -943,6 +943,7 @@ bld.SAMBA3_BINARY('winbindd/winbindd',
winbindd/winbindd_list_groups.c
winbindd/winbindd_check_machine_acct.c
winbindd/winbindd_change_machine_acct.c
+ winbindd/winbindd_update_rodc_dns.c
winbindd/winbindd_ping_dc.c
winbindd/winbindd_pam_auth.c
winbindd/winbindd_pam_logoff.c