*/
bool connected;
- /*
- * we allow sync requests only, if the caller
- * did not pass an event context to cldap_socket_init()
- */
- struct {
- bool allow_poll;
- struct tevent_context *ctx;
- } event;
-
/* the queue for outgoing dgrams */
struct tevent_queue *send_queue;
struct cldap_search_state *prev, *next;
struct {
+ struct tevent_context *ev;
struct cldap_socket *cldap;
} caller;
static bool cldap_recvfrom_setup(struct cldap_socket *c)
{
+ struct tevent_context *ev;
+
if (c->recv_subreq) {
return true;
}
return true;
}
- c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
+ ev = c->incoming.ev;
+ if (ev == NULL) {
+ ev = c->searches.list->caller.ev;
+ }
+
+ c->recv_subreq = tdgram_recvfrom_send(c, ev, c->sock);
if (!c->recv_subreq) {
return false;
}
nomem:
talloc_free(subreq);
talloc_free(in);
- /*TODO: call a dead socket handler */
- return;
}
/*
static bool cldap_socket_recv_dgram(struct cldap_socket *c,
struct cldap_incoming *in)
{
- DATA_BLOB blob;
struct asn1_data *asn1;
void *p;
struct cldap_search_state *search;
goto error;
}
- blob = data_blob_const(in->buf, in->len);
-
asn1 = asn1_init(in);
if (!asn1) {
goto nomem;
}
- if (!asn1_load(asn1, blob)) {
- goto nomem;
- }
+ asn1_load_nocopy(asn1, in->buf, in->len);
in->ldap_msg = talloc(in, struct ldap_message);
if (in->ldap_msg == NULL) {
p = idr_find(c->searches.idr, in->ldap_msg->messageid);
if (p == NULL) {
if (!c->incoming.handler) {
- goto done;
+ TALLOC_FREE(in);
+ return true;
}
/* this function should free or steal 'in' */
return false;
}
- search = talloc_get_type(p, struct cldap_search_state);
+ search = talloc_get_type_abort(p, struct cldap_search_state);
search->response.in = talloc_move(search, &in);
+
search->response.asn1 = asn1;
- search->response.asn1->ofs = 0;
+
+ asn1_load_nocopy(search->response.asn1,
+ search->response.in->buf, search->response.in->len);
DLIST_REMOVE(c->searches.list, search);
- if (!cldap_recvfrom_setup(c)) {
- goto nomem;
+ if (cldap_recvfrom_setup(c)) {
+ tevent_req_done(search->req);
+ return true;
}
+ /*
+ * This request was ok, just defer the notify of the caller
+ * and then just fail the next request if needed
+ */
+ tevent_req_defer_callback(search->req, search->caller.ev);
tevent_req_done(search->req);
- talloc_free(in);
- return true;
+ status = NT_STATUS_NO_MEMORY;
+ /* in is NULL it this point */
+ goto nterror;
nomem:
in->recv_errno = ENOMEM;
error:
status = map_nt_error_from_unix_common(in->recv_errno);
nterror:
+ TALLOC_FREE(in);
/* in connected mode the first pending search gets the error */
if (!c->connected) {
/* otherwise we just ignore the error */
- goto done;
+ return false;
}
if (!c->searches.list) {
- goto done;
+ return false;
}
+ /*
+ * We might called tevent_req_done() for a successful
+ * search before, so we better deliver the failure
+ * after the success, that is why we better also
+ * use tevent_req_defer_callback() here.
+ */
+ tevent_req_defer_callback(c->searches.list->req,
+ c->searches.list->caller.ev);
tevent_req_nterror(c->searches.list->req, status);
-done:
- talloc_free(in);
return false;
}
initialise a cldap_sock
*/
NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
const struct tsocket_address *local_addr,
const struct tsocket_address *remote_addr,
struct cldap_socket **_cldap)
struct tsocket_address *any = NULL;
NTSTATUS status;
int ret;
+ const char *fam = NULL;
+
+ if (local_addr == NULL && remote_addr == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (remote_addr) {
+ bool is_ipv4;
+ bool is_ipv6;
+
+ is_ipv4 = tsocket_address_is_inet(remote_addr, "ipv4");
+ is_ipv6 = tsocket_address_is_inet(remote_addr, "ipv6");
+
+ if (is_ipv4) {
+ fam = "ipv4";
+ } else if (is_ipv6) {
+ fam = "ipv6";
+ } else {
+ return NT_STATUS_INVALID_ADDRESS;
+ }
+ }
c = talloc_zero(mem_ctx, struct cldap_socket);
if (!c) {
goto nomem;
}
- if (!ev) {
- ev = tevent_context_init(c);
- if (!ev) {
- goto nomem;
+ if (!local_addr) {
+ /*
+ * Here we know the address family of the remote address.
+ */
+ if (fam == NULL) {
+ return NT_STATUS_INVALID_PARAMETER_MIX;
}
- c->event.allow_poll = true;
- }
- c->event.ctx = ev;
- if (!local_addr) {
- /* we use ipv4 here instead of ip, as otherwise we end
- up with a PF_INET6 socket, and sendto() for ipv4
- addresses will fail. That breaks cldap name
- resolution for winbind to IPv4 hosts. */
- ret = tsocket_address_inet_from_strings(c, "ipv4",
+ ret = tsocket_address_inet_from_strings(c, fam,
NULL, 0,
&any);
if (ret != 0) {
return NT_STATUS_PIPE_CONNECTED;
}
- /* if sync requests are allowed, we don't allow an incoming handler */
- if (c->event.allow_poll) {
- return NT_STATUS_INVALID_PIPE_STATE;
- }
c->incoming.ev = ev;
c->incoming.handler = handler;
c->incoming.private_data = private_data;
return NT_STATUS_PIPE_CONNECTED;
}
+ if (cldap->incoming.ev == NULL) {
+ return NT_STATUS_INVALID_PIPE_STATE;
+ }
+
if (!io->dest) {
return NT_STATUS_INVALID_ADDRESS;
}
data_blob_free(&blob2);
subreq = tdgram_sendto_queue_send(state,
- cldap->event.ctx,
+ cldap->incoming.ev,
cldap->sock,
cldap->send_queue,
state->blob.data,
queue a cldap reply for send
*/
struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
- struct cldap_socket *cldap,
- const struct cldap_search *io)
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_search *io)
{
struct tevent_req *req, *subreq;
struct cldap_search_state *state = NULL;
return NULL;
}
ZERO_STRUCTP(state);
+ state->caller.ev = ev;
state->req = req;
state->caller.cldap = cldap;
state->message_id = -1;
talloc_set_destructor(state, cldap_search_state_destructor);
+ if (state->caller.cldap == NULL) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ goto post;
+ }
+
if (io->in.dest_address) {
if (cldap->connected) {
tevent_req_nterror(req, NT_STATUS_PIPE_CONNECTED);
state->request.delay % 1000000);
}
- if (!tevent_req_set_endtime(req, state->caller.cldap->event.ctx, end)) {
+ if (!tevent_req_set_endtime(req, state->caller.ev, end)) {
tevent_req_oom(req);
goto post;
}
subreq = tdgram_sendto_queue_send(state,
- state->caller.cldap->event.ctx,
+ state->caller.ev,
state->caller.cldap->sock,
state->caller.cldap->send_queue,
state->request.blob.data,
}
tevent_req_set_callback(subreq, cldap_search_state_queue_done, req);
- DLIST_ADD_END(cldap->searches.list, state, struct cldap_search_state *);
+ DLIST_ADD_END(cldap->searches.list, state);
return req;
post:
- return tevent_req_post(req, cldap->event.ctx);
+ return tevent_req_post(req, state->caller.ev);
}
static void cldap_search_state_queue_done(struct tevent_req *subreq)
next = tevent_timeval_current_ofs(state->request.delay / 1000000,
state->request.delay % 1000000);
subreq = tevent_wakeup_send(state,
- state->caller.cldap->event.ctx,
+ state->caller.ev,
next);
if (tevent_req_nomem(subreq, req)) {
return;
}
subreq = tdgram_sendto_queue_send(state,
- state->caller.cldap->event.ctx,
+ state->caller.ev,
state->caller.cldap->sock,
state->caller.cldap->send_queue,
state->request.blob.data,
TALLOC_CTX *mem_ctx,
struct cldap_search *io)
{
+ TALLOC_CTX *frame;
struct tevent_req *req;
+ struct tevent_context *ev;
NTSTATUS status;
- if (!cldap->event.allow_poll) {
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
return NT_STATUS_INVALID_PIPE_STATE;
}
- if (cldap->searches.list) {
- return NT_STATUS_PIPE_BUSY;
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
}
- req = cldap_search_send(mem_ctx, cldap, io);
- NT_STATUS_HAVE_NO_MEMORY(req);
+ req = cldap_search_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
- if (!tevent_req_poll(req, cldap->event.ctx)) {
- talloc_free(req);
- return NT_STATUS_INTERNAL_ERROR;
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
}
status = cldap_search_recv(req, mem_ctx, io);
- talloc_free(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
- return status;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
}
struct cldap_netlogon_state {
struct cldap_search search;
};
-static void cldap_netlogon_state_done(struct tevent_req *subreq);
-/*
- queue a cldap netlogon for send
-*/
-struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
- struct cldap_socket *cldap,
- const struct cldap_netlogon *io)
+char *cldap_netlogon_create_filter(TALLOC_CTX *mem_ctx,
+ const struct cldap_netlogon *io)
{
- struct tevent_req *req, *subreq;
- struct cldap_netlogon_state *state;
char *filter;
- static const char * const attr[] = { "NetLogon", NULL };
- req = tevent_req_create(mem_ctx, &state,
- struct cldap_netlogon_state);
- if (!req) {
+ filter = talloc_asprintf(mem_ctx, "(&(NtVer=%s)",
+ ldap_encode_ndr_uint32(mem_ctx, io->in.version));
+ if (filter == NULL)
return NULL;
- }
- filter = talloc_asprintf(state, "(&(NtVer=%s)",
- ldap_encode_ndr_uint32(state, io->in.version));
- if (tevent_req_nomem(filter, req)) {
- goto post;
- }
if (io->in.user) {
filter = talloc_asprintf_append_buffer(filter, "(User=%s)", io->in.user);
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ if (filter == NULL) {
+ return NULL;
}
}
if (io->in.host) {
filter = talloc_asprintf_append_buffer(filter, "(Host=%s)", io->in.host);
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ if (filter == NULL) {
+ return NULL;
}
}
if (io->in.realm) {
filter = talloc_asprintf_append_buffer(filter, "(DnsDomain=%s)", io->in.realm);
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ if (filter == NULL) {
+ return NULL;
}
}
if (io->in.acct_control != -1) {
filter = talloc_asprintf_append_buffer(filter, "(AAC=%s)",
- ldap_encode_ndr_uint32(state, io->in.acct_control));
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ ldap_encode_ndr_uint32(mem_ctx, io->in.acct_control));
+ if (filter == NULL) {
+ return NULL;
}
}
if (io->in.domain_sid) {
- struct dom_sid *sid = dom_sid_parse_talloc(state, io->in.domain_sid);
- if (tevent_req_nomem(sid, req)) {
- goto post;
- }
+ struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, io->in.domain_sid);
+
filter = talloc_asprintf_append_buffer(filter, "(domainSid=%s)",
- ldap_encode_ndr_dom_sid(state, sid));
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ ldap_encode_ndr_dom_sid(mem_ctx, sid));
+ if (filter == NULL) {
+ return NULL;
}
}
if (io->in.domain_guid) {
struct GUID guid;
- NTSTATUS status;
- status = GUID_from_string(io->in.domain_guid, &guid);
- if (tevent_req_nterror(req, status)) {
- goto post;
- }
+ GUID_from_string(io->in.domain_guid, &guid);
+
filter = talloc_asprintf_append_buffer(filter, "(DomainGuid=%s)",
- ldap_encode_ndr_GUID(state, &guid));
- if (tevent_req_nomem(filter, req)) {
- goto post;
+ ldap_encode_ndr_GUID(mem_ctx, &guid));
+ if (filter == NULL) {
+ return NULL;
}
}
filter = talloc_asprintf_append_buffer(filter, ")");
+
+ return filter;
+}
+
+static void cldap_netlogon_state_done(struct tevent_req *subreq);
+/*
+ queue a cldap netlogon for send
+*/
+struct tevent_req *cldap_netlogon_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cldap_socket *cldap,
+ const struct cldap_netlogon *io)
+{
+ struct tevent_req *req, *subreq;
+ struct cldap_netlogon_state *state;
+ char *filter;
+ static const char * const attr[] = { "NetLogon", NULL };
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cldap_netlogon_state);
+ if (!req) {
+ return NULL;
+ }
+
+ filter = cldap_netlogon_create_filter(state, io);
if (tevent_req_nomem(filter, req)) {
goto post;
}
state->search.in.timeout = 2;
state->search.in.retries = 2;
- subreq = cldap_search_send(state, cldap, &state->search);
+ subreq = cldap_search_send(state, ev, cldap, &state->search);
if (tevent_req_nomem(subreq, req)) {
goto post;
}
return req;
post:
- return tevent_req_post(req, cldap->event.ctx);
+ return tevent_req_post(req, ev);
}
static void cldap_netlogon_state_done(struct tevent_req *subreq)
{
struct cldap_netlogon_state *state = tevent_req_data(req,
struct cldap_netlogon_state);
- NTSTATUS status;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
DATA_BLOB *data;
if (tevent_req_is_nterror(req, &status)) {
TALLOC_CTX *mem_ctx,
struct cldap_netlogon *io)
{
+ TALLOC_CTX *frame;
struct tevent_req *req;
+ struct tevent_context *ev;
NTSTATUS status;
- if (!cldap->event.allow_poll) {
+ if (cldap->searches.list) {
+ return NT_STATUS_PIPE_BUSY;
+ }
+
+ if (cldap->incoming.handler) {
return NT_STATUS_INVALID_PIPE_STATE;
}
- if (cldap->searches.list) {
- return NT_STATUS_PIPE_BUSY;
+ frame = talloc_stackframe();
+
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
}
- req = cldap_netlogon_send(mem_ctx, cldap, io);
- NT_STATUS_HAVE_NO_MEMORY(req);
+ req = cldap_netlogon_send(mem_ctx, ev, cldap, io);
+ if (req == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
- if (!tevent_req_poll(req, cldap->event.ctx)) {
- talloc_free(req);
- return NT_STATUS_INTERNAL_ERROR;
+ if (!tevent_req_poll(req, ev)) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(frame);
+ return status;
}
status = cldap_netlogon_recv(req, mem_ctx, io);
- talloc_free(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(frame);
+ return status;
+ }
- return status;
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
}