summaryrefslogtreecommitdiff
path: root/source4/kdc
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-02-09 09:07:47 +0100
committerStefan Metzmacher <metze@samba.org>2011-03-04 21:19:05 +0100
commite70b09e8f8f99b2d63047525f1d5e360582f7eaa (patch)
tree5aab72f3c40630f4896baaba81216f75ede6d51a /source4/kdc
parentad9ac99afd04b1f69ca188eb0005a1226520bc7d (diff)
downloadsamba-e70b09e8f8f99b2d63047525f1d5e360582f7eaa.tar.gz
samba-e70b09e8f8f99b2d63047525f1d5e360582f7eaa.tar.bz2
samba-e70b09e8f8f99b2d63047525f1d5e360582f7eaa.zip
s4:kdc: split the kdc_udp_proxy() logic from the main kdc logic
By having kdc_udp_proxy_send/recv(), which just asks any writeable dc for a reponse blob, we simplify the interaction between client-local and local-writeable sockets. This allows us to make kdc_udp_call and kdc_udp_socket private to kdc.c again. metze
Diffstat (limited to 'source4/kdc')
-rw-r--r--source4/kdc/kdc-glue.h23
-rw-r--r--source4/kdc/kdc.c68
-rw-r--r--source4/kdc/proxy.c347
3 files changed, 231 insertions, 207 deletions
diff --git a/source4/kdc/kdc-glue.h b/source4/kdc/kdc-glue.h
index 75b6b988fe..f9489b1fd1 100644
--- a/source4/kdc/kdc-glue.h
+++ b/source4/kdc/kdc-glue.h
@@ -50,19 +50,6 @@ enum kdc_process_ret {
KDC_PROCESS_FAILED,
KDC_PROCESS_PROXY};
-struct kdc_udp_call {
- struct tsocket_address *src;
- DATA_BLOB in;
- DATA_BLOB out;
-};
-
-/* hold information about one kdc/kpasswd udp socket */
-struct kdc_udp_socket {
- struct kdc_socket *kdc_socket;
- struct tdgram_context *dgram;
- struct tevent_queue *send_queue;
-};
-
struct kdc_tcp_call {
struct kdc_tcp_connection *kdc_conn;
DATA_BLOB in;
@@ -116,8 +103,14 @@ NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx,
krb5_context context, struct HDB **db);
/* from proxy.c */
-void kdc_udp_proxy(struct kdc_server *kdc, struct kdc_udp_socket *sock,
- struct kdc_udp_call *call, uint16_t port);
+struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kdc_server *kdc,
+ uint16_t port,
+ DATA_BLOB in);
+NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out);
void kdc_tcp_proxy(struct kdc_server *kdc, struct kdc_tcp_connection *kdc_conn,
struct kdc_tcp_call *call, uint16_t port);
diff --git a/source4/kdc/kdc.c b/source4/kdc/kdc.c
index 249004323c..05c1d9c40d 100644
--- a/source4/kdc/kdc.c
+++ b/source4/kdc/kdc.c
@@ -345,6 +345,21 @@ static const struct stream_server_ops kdc_tcp_stream_ops = {
.send_handler = kdc_tcp_send
};
+/* hold information about one kdc/kpasswd udp socket */
+struct kdc_udp_socket {
+ struct kdc_socket *kdc_socket;
+ struct tdgram_context *dgram;
+ struct tevent_queue *send_queue;
+};
+
+struct kdc_udp_call {
+ struct kdc_udp_socket *sock;
+ struct tsocket_address *src;
+ DATA_BLOB in;
+ DATA_BLOB out;
+};
+
+static void kdc_udp_call_proxy_done(struct tevent_req *subreq);
static void kdc_udp_call_sendto_done(struct tevent_req *subreq);
static void kdc_udp_call_loop(struct tevent_req *subreq)
@@ -362,6 +377,7 @@ static void kdc_udp_call_loop(struct tevent_req *subreq)
talloc_free(call);
goto done;
}
+ call->sock = sock;
len = tdgram_recvfrom_recv(subreq, &sys_errno,
call, &buf, &call->src);
@@ -392,13 +408,26 @@ static void kdc_udp_call_loop(struct tevent_req *subreq)
}
if (ret == KDC_PROCESS_PROXY) {
+ uint16_t port;
+
if (!sock->kdc_socket->kdc->am_rodc) {
DEBUG(0,("kdc_udp_call_loop: proxying requested when not RODC"));
talloc_free(call);
goto done;
}
- kdc_udp_proxy(sock->kdc_socket->kdc, sock, call,
- tsocket_address_inet_port(sock->kdc_socket->local_address));
+
+ port = tsocket_address_inet_port(sock->kdc_socket->local_address);
+
+ subreq = kdc_udp_proxy_send(call,
+ sock->kdc_socket->kdc->task->event_ctx,
+ sock->kdc_socket->kdc,
+ port,
+ call->in);
+ if (subreq == NULL) {
+ talloc_free(call);
+ goto done;
+ }
+ tevent_req_set_callback(subreq, kdc_udp_call_proxy_done, call);
goto done;
}
@@ -428,6 +457,41 @@ done:
tevent_req_set_callback(subreq, kdc_udp_call_loop, sock);
}
+static void kdc_udp_call_proxy_done(struct tevent_req *subreq)
+{
+ struct kdc_udp_call *call =
+ tevent_req_callback_data(subreq,
+ struct kdc_udp_call);
+ NTSTATUS status;
+
+ status = kdc_udp_proxy_recv(subreq, call, &call->out);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* generate an error packet */
+ status = kdc_proxy_unavailable_error(call->sock->kdc_socket->kdc,
+ call, &call->out);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(call);
+ return;
+ }
+
+ subreq = tdgram_sendto_queue_send(call,
+ call->sock->kdc_socket->kdc->task->event_ctx,
+ call->sock->dgram,
+ call->sock->send_queue,
+ call->out.data,
+ call->out.length,
+ call->src);
+ if (subreq == NULL) {
+ talloc_free(call);
+ return;
+ }
+
+ tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call);
+}
+
static void kdc_udp_call_sendto_done(struct tevent_req *subreq)
{
struct kdc_udp_call *call = tevent_req_callback_data(subreq,
diff --git a/source4/kdc/proxy.c b/source4/kdc/proxy.c
index 6179bf18ab..a11f253b26 100644
--- a/source4/kdc/proxy.c
+++ b/source4/kdc/proxy.c
@@ -5,6 +5,7 @@
Copyright (C) Andrew Tridgell 2010
Copyright (C) Andrew Bartlett 2010
+ Copyright (C) Stefan Metzmacher 2011
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
@@ -24,6 +25,7 @@
#include "smbd/process_model.h"
#include "lib/tsocket/tsocket.h"
#include "libcli/util/tstream.h"
+#include "lib/util/tevent_ntstatus.h"
#include "lib/stream/packet.h"
#include "kdc/kdc-glue.h"
#include "dsdb/samdb/samdb.h"
@@ -75,287 +77,252 @@ static WERROR kdc_proxy_get_writeable_dcs(struct kdc_server *kdc, TALLOC_CTX *me
struct kdc_udp_proxy_state {
- struct kdc_udp_call *call;
- struct kdc_udp_socket *sock;
+ struct tevent_context *ev;
struct kdc_server *kdc;
+ uint16_t port;
+ DATA_BLOB in;
+ DATA_BLOB out;
char **proxy_list;
uint32_t next_proxy;
- const char *proxy_ip;
- uint16_t port;
+ struct {
+ struct nbt_name name;
+ const char *ip;
+ struct tdgram_context *dgram;
+ } proxy;
};
-static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state);
+static void kdc_udp_next_proxy(struct tevent_req *req);
-/*
- called when the send of the call to the proxy is complete
- this is used to get an errors from the sendto()
- */
-static void kdc_udp_proxy_sendto_done(struct tevent_req *req)
+struct tevent_req *kdc_udp_proxy_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct kdc_server *kdc,
+ uint16_t port,
+ DATA_BLOB in)
{
- struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
- struct kdc_udp_proxy_state);
- ssize_t ret;
- int sys_errno;
-
- ret = tdgram_sendto_queue_recv(req, &sys_errno);
- talloc_free(req);
+ struct tevent_req *req;
+ struct kdc_udp_proxy_state *state;
+ WERROR werr;
- if (ret == -1) {
- DEBUG(4,("kdc_udp_proxy: sendto for %s gave %d : %s\n",
- state->proxy_ip, sys_errno, strerror(sys_errno)));
- kdc_udp_next_proxy(state);
+ req = tevent_req_create(mem_ctx, &state,
+ struct kdc_udp_proxy_state);
+ if (req == NULL) {
+ return NULL;
}
-}
+ state->ev = ev;
+ state->kdc = kdc;
+ state->port = port;
+ state->in = in;
-/*
- called when the send of the reply to the client is complete
- this is used to get an errors from the sendto()
- */
-static void kdc_udp_proxy_reply_done(struct tevent_req *req)
-{
- struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
- struct kdc_udp_proxy_state);
- ssize_t ret;
- int sys_errno;
+ werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
+ if (!W_ERROR_IS_OK(werr)) {
+ NTSTATUS status = werror_to_ntstatus(werr);
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
- ret = tdgram_sendto_queue_recv(req, &sys_errno);
- if (ret == -1) {
- DEBUG(3,("kdc_udp_proxy: reply sendto gave %d : %s\n",
- sys_errno, strerror(sys_errno)));
+ kdc_udp_next_proxy(req);
+ if (!tevent_req_is_in_progress(req)) {
+ return tevent_req_post(req, ev);
}
- /* all done - we can destroy the proxy state */
- talloc_free(req);
- talloc_free(state);
+ return req;
}
+static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq);
/*
- called when the proxy replies
+ try the next proxy in the list
*/
-static void kdc_udp_proxy_reply(struct tevent_req *req)
+static void kdc_udp_next_proxy(struct tevent_req *req)
{
- struct kdc_udp_proxy_state *state = tevent_req_callback_data(req,
- struct kdc_udp_proxy_state);
- int sys_errno;
- uint8_t *buf;
- struct tsocket_address *src;
- ssize_t len;
+ struct kdc_udp_proxy_state *state =
+ tevent_req_data(req,
+ struct kdc_udp_proxy_state);
+ const char *proxy_dnsname = state->proxy_list[state->next_proxy];
+ struct composite_context *csubreq;
- len = tdgram_recvfrom_recv(req, &sys_errno,
- state, &buf, &src);
- talloc_free(req);
- if (len == -1) {
- DEBUG(4,("kdc_udp_proxy: reply from %s gave %d : %s\n",
- state->proxy_ip, sys_errno, strerror(sys_errno)));
- kdc_udp_next_proxy(state);
+ if (proxy_dnsname == NULL) {
+ tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
return;
}
- state->call->out.length = len;
- state->call->out.data = buf;
+ state->next_proxy++;
- /* TODO: check the reply came from the right IP? */
+ /* make sure we close the socket of the last try */
+ TALLOC_FREE(state->proxy.dgram);
+ ZERO_STRUCT(state->proxy);
- req = tdgram_sendto_queue_send(state,
- state->kdc->task->event_ctx,
- state->sock->dgram,
- state->sock->send_queue,
- state->call->out.data,
- state->call->out.length,
- state->call->src);
- if (req == NULL) {
- kdc_udp_next_proxy(state);
+ make_nbt_name(&state->proxy.name, proxy_dnsname, 0);
+
+ csubreq = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
+ state,
+ RESOLVE_NAME_FLAG_FORCE_DNS,
+ 0,
+ &state->proxy.name,
+ state->ev);
+ if (tevent_req_nomem(csubreq, req)) {
return;
}
-
- tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
+ csubreq->async.fn = kdc_udp_proxy_resolve_done;
+ csubreq->async.private_data = req;
}
+static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq);
+static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq);
-/*
- called when we've resolved the name of a proxy
- */
-static void kdc_udp_proxy_resolve_done(struct composite_context *c)
+static void kdc_udp_proxy_resolve_done(struct composite_context *csubreq)
{
- struct kdc_udp_proxy_state *state;
+ struct tevent_req *req =
+ talloc_get_type_abort(csubreq->async.private_data,
+ struct tevent_req);
+ struct kdc_udp_proxy_state *state =
+ tevent_req_data(req,
+ struct kdc_udp_proxy_state);
NTSTATUS status;
- struct tevent_req *req;
+ struct tevent_req *subreq;
struct tsocket_address *local_addr, *proxy_addr;
int ret;
- struct tdgram_context *dgram;
- struct tevent_queue *send_queue;
-
- state = talloc_get_type(c->async.private_data, struct kdc_udp_proxy_state);
- status = resolve_name_recv(c, state, &state->proxy_ip);
+ status = resolve_name_recv(csubreq, state, &state->proxy.ip);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("Unable to resolve proxy\n"));
- kdc_udp_next_proxy(state);
+ DEBUG(0,("Unable to resolve proxy[%s] - %s\n",
+ state->proxy.name.name, nt_errstr(status)));
+ kdc_udp_next_proxy(req);
return;
}
/* get an address for us to use locally */
ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0, &local_addr);
if (ret != 0) {
- kdc_udp_next_proxy(state);
+ kdc_udp_next_proxy(req);
return;
}
ret = tsocket_address_inet_from_strings(state, "ip",
- state->proxy_ip, state->port, &proxy_addr);
+ state->proxy.ip,
+ state->port,
+ &proxy_addr);
if (ret != 0) {
- kdc_udp_next_proxy(state);
+ kdc_udp_next_proxy(req);
return;
}
/* create a socket for us to work on */
- ret = tdgram_inet_udp_socket(local_addr, proxy_addr, state, &dgram);
+ ret = tdgram_inet_udp_socket(local_addr, proxy_addr,
+ state, &state->proxy.dgram);
if (ret != 0) {
- kdc_udp_next_proxy(state);
- return;
- }
-
- send_queue = tevent_queue_create(state, "kdc_udp_proxy");
- if (send_queue == NULL) {
- kdc_udp_next_proxy(state);
+ kdc_udp_next_proxy(req);
return;
}
- req = tdgram_sendto_queue_send(state,
- state->kdc->task->event_ctx,
- dgram,
- send_queue,
- state->call->in.data,
- state->call->in.length,
- proxy_addr);
- if (req == NULL) {
- kdc_udp_next_proxy(state);
+ subreq = tdgram_sendto_send(state,
+ state->ev,
+ state->proxy.dgram,
+ state->in.data,
+ state->in.length,
+ NULL);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
-
- tevent_req_set_callback(req, kdc_udp_proxy_sendto_done, state);
+ tevent_req_set_callback(subreq, kdc_udp_proxy_sendto_done, req);
/* setup to receive the reply from the proxy */
- req = tdgram_recvfrom_send(state, state->kdc->task->event_ctx, dgram);
- if (req == NULL) {
- kdc_udp_next_proxy(state);
+ subreq = tdgram_recvfrom_send(state, state->ev, state->proxy.dgram);
+ if (tevent_req_nomem(subreq, req)) {
return;
}
-
- tevent_req_set_callback(req, kdc_udp_proxy_reply, state);
-
- tevent_req_set_endtime(req, state->kdc->task->event_ctx,
+ tevent_req_set_callback(subreq, kdc_udp_proxy_recvfrom_done, req);
+ tevent_req_set_endtime(subreq, state->ev,
timeval_current_ofs(state->kdc->proxy_timeout, 0));
- DEBUG(4,("kdc_udp_proxy: proxying request to %s\n", state->proxy_ip));
+ DEBUG(4,("kdc_udp_proxy: proxying request to %s[%s]\n",
+ state->proxy.name.name, state->proxy.ip));
}
-
/*
- called when our proxies are not available
+ called when the send of the call to the proxy is complete
+ this is used to get an errors from the sendto()
*/
-static void kdc_udp_proxy_unavailable(struct kdc_udp_proxy_state *state)
+static void kdc_udp_proxy_sendto_done(struct tevent_req *subreq)
{
- int kret;
- krb5_data k5_error_blob;
- struct tevent_req *req;
-
- kret = krb5_mk_error(state->kdc->smb_krb5_context->krb5_context,
- KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL,
- NULL, NULL, NULL, NULL, &k5_error_blob);
- if (kret != 0) {
- DEBUG(2,(__location__ ": Unable to form krb5 error reply\n"));
- talloc_free(state);
- return;
- }
-
- state->call->out = data_blob_talloc(state, k5_error_blob.data, k5_error_blob.length);
- krb5_data_free(&k5_error_blob);
- if (!state->call->out.data) {
- talloc_free(state);
- return;
- }
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct kdc_udp_proxy_state *state =
+ tevent_req_data(req,
+ struct kdc_udp_proxy_state);
+ ssize_t ret;
+ int sys_errno;
- req = tdgram_sendto_queue_send(state,
- state->kdc->task->event_ctx,
- state->sock->dgram,
- state->sock->send_queue,
- state->call->out.data,
- state->call->out.length,
- state->call->src);
- if (!req) {
- talloc_free(state);
- return;
+ ret = tdgram_sendto_recv(subreq, &sys_errno);
+ TALLOC_FREE(subreq);
+ if (ret == -1) {
+ DEBUG(4,("kdc_udp_proxy: sendto for %s[%s] gave %d : %s\n",
+ state->proxy.name.name, state->proxy.ip,
+ sys_errno, strerror(sys_errno)));
+ kdc_udp_next_proxy(req);
}
-
- tevent_req_set_callback(req, kdc_udp_proxy_reply_done, state);
}
/*
- try the next proxy in the list
+ called when the proxy replies
*/
-static void kdc_udp_next_proxy(struct kdc_udp_proxy_state *state)
+static void kdc_udp_proxy_recvfrom_done(struct tevent_req *subreq)
{
- const char *proxy_dnsname = state->proxy_list[state->next_proxy];
- struct nbt_name name;
- struct composite_context *c;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct kdc_udp_proxy_state *state =
+ tevent_req_data(req,
+ struct kdc_udp_proxy_state);
+ int sys_errno;
+ uint8_t *buf;
+ ssize_t len;
- if (proxy_dnsname == NULL) {
- kdc_udp_proxy_unavailable(state);
+ len = tdgram_recvfrom_recv(subreq, &sys_errno,
+ state, &buf, NULL);
+ TALLOC_FREE(subreq);
+ if (len == -1) {
+ DEBUG(4,("kdc_udp_proxy: reply from %s[%s] gave %d : %s\n",
+ state->proxy.name.name, state->proxy.ip,
+ sys_errno, strerror(sys_errno)));
+ kdc_udp_next_proxy(req);
return;
}
- state->next_proxy++;
+ /*
+ * Check the reply came from the right IP?
+ * As we use connected udp sockets, that should not be needed...
+ */
- make_nbt_name(&name, proxy_dnsname, 0);
+ state->out.length = len;
+ state->out.data = buf;
- c = resolve_name_ex_send(lpcfg_resolve_context(state->kdc->task->lp_ctx),
- state,
- RESOLVE_NAME_FLAG_FORCE_DNS,
- 0,
- &name,
- state->kdc->task->event_ctx);
- if (c == NULL) {
- kdc_udp_next_proxy(state);
- return;
- }
- c->async.fn = kdc_udp_proxy_resolve_done;
- c->async.private_data = state;
+ tevent_req_done(req);
}
-
-/*
- proxy a UDP kdc request to a writeable DC
- */
-void kdc_udp_proxy(struct kdc_server *kdc, struct kdc_udp_socket *sock,
- struct kdc_udp_call *call, uint16_t port)
+NTSTATUS kdc_udp_proxy_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *out)
{
- struct kdc_udp_proxy_state *state;
- WERROR werr;
+ struct kdc_udp_proxy_state *state =
+ tevent_req_data(req,
+ struct kdc_udp_proxy_state);
+ NTSTATUS status;
- state = talloc_zero(kdc, struct kdc_udp_proxy_state);
- if (state == NULL) {
- talloc_free(call);
- return;
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
}
- state->call = talloc_steal(state, call);
- state->sock = sock;
- state->kdc = kdc;
- state->port = port;
-
- werr = kdc_proxy_get_writeable_dcs(kdc, state, &state->proxy_list);
- if (!W_ERROR_IS_OK(werr)) {
- kdc_udp_proxy_unavailable(state);
- return;
- }
+ out->data = talloc_move(mem_ctx, &state->out.data);
+ out->length = state->out.length;
- kdc_udp_next_proxy(state);
+ tevent_req_received(req);
+ return NT_STATUS_OK;
}
-
struct kdc_tcp_proxy_state {
struct kdc_tcp_call *call;
struct kdc_tcp_connection *kdc_conn;