Beispiel #1
0
/*
  decode/process data
*/
static NTSTATUS ldapsrv_decode(void *private_data, DATA_BLOB blob)
{
	NTSTATUS status;
	struct ldapsrv_connection *conn = talloc_get_type(private_data,
							  struct ldapsrv_connection);
	struct asn1_data *asn1 = asn1_init(conn);
	struct ldap_message *msg = talloc(conn, struct ldap_message);

	if (asn1 == NULL || msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!asn1_load(asn1, blob)) {
		talloc_free(msg);
		talloc_free(asn1);
		return NT_STATUS_NO_MEMORY;
	}

	status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
	if (!NT_STATUS_IS_OK(status)) {
		asn1_free(asn1);
		return status;
	}

	data_blob_free(&blob);
	talloc_steal(conn, msg);
	asn1_free(asn1);

	ldapsrv_process_message(conn, msg);
	return NT_STATUS_OK;
}
/*
  handle recv events on a cldap socket
*/
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;
	NTSTATUS status;

	if (in->recv_errno != 0) {
		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;
	}

	in->ldap_msg = talloc(in, struct ldap_message);
	if (in->ldap_msg == NULL) {
		goto nomem;
	}

	/* this initial decode is used to find the message id */
	status = ldap_decode(asn1, NULL, in->ldap_msg);
	if (!NT_STATUS_IS_OK(status)) {
		goto nterror;
	}

	/* find the pending request */
	p = idr_find(c->searches.idr, in->ldap_msg->messageid);
	if (p == NULL) {
		if (!c->incoming.handler) {
			TALLOC_FREE(in);
			return true;
		}

		/* this function should free or steal 'in' */
		c->incoming.handler(c, c->incoming.private_data, in);
		return false;
	}

	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;

	DLIST_REMOVE(c->searches.list, search);

	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);

	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 */
		return false;
	}
	if (!c->searches.list) {
		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);
	return false;
}
Beispiel #3
0
static void ldapsrv_call_read_done(struct tevent_req *subreq)
{
	struct ldapsrv_connection *conn =
		tevent_req_callback_data(subreq,
		struct ldapsrv_connection);
	NTSTATUS status;
	struct ldapsrv_call *call;
	struct asn1_data *asn1;
	DATA_BLOB blob;

	call = talloc_zero(conn, struct ldapsrv_call);
	if (!call) {
		ldapsrv_terminate_connection(conn, "no memory");
		return;
	}

	call->conn = conn;

	status = tstream_read_pdu_blob_recv(subreq,
					    call,
					    &blob);
	TALLOC_FREE(subreq);
	if (!NT_STATUS_IS_OK(status)) {
		const char *reason;

		reason = talloc_asprintf(call, "ldapsrv_call_loop: "
					 "tstream_read_pdu_blob_recv() - %s",
					 nt_errstr(status));
		if (!reason) {
			reason = nt_errstr(status);
		}

		ldapsrv_terminate_connection(conn, reason);
		return;
	}

	asn1 = asn1_init(call);
	if (asn1 == NULL) {
		ldapsrv_terminate_connection(conn, "no memory");
		return;
	}

	call->request = talloc(call, struct ldap_message);
	if (call->request == NULL) {
		ldapsrv_terminate_connection(conn, "no memory");
		return;
	}

	if (!asn1_load(asn1, blob)) {
		ldapsrv_terminate_connection(conn, "asn1_load failed");
		return;
	}

	status = ldap_decode(asn1, samba_ldap_control_handlers(),
			     call->request);
	if (!NT_STATUS_IS_OK(status)) {
		ldapsrv_terminate_connection(conn, nt_errstr(status));
		return;
	}

	data_blob_free(&blob);


	/* queue the call in the global queue */
	subreq = ldapsrv_process_call_send(call,
					   conn->connection->event.ctx,
					   conn->service->call_queue,
					   call);
	if (subreq == NULL) {
		ldapsrv_terminate_connection(conn, "ldapsrv_process_call_send failed");
		return;
	}
	tevent_req_set_callback(subreq, ldapsrv_call_process_done, call);
	conn->active_call = subreq;
}
Beispiel #4
0
/*
  handle recv events on a cldap socket
*/
static void 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;
	NTSTATUS status;

	if (in->recv_errno != 0) {
		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;
	}

	in->ldap_msg = talloc(in, struct ldap_message);
	if (in->ldap_msg == NULL) {
		goto nomem;
	}

	/* this initial decode is used to find the message id */
	status = ldap_decode(asn1, NULL, in->ldap_msg);
	if (!NT_STATUS_IS_OK(status)) {
		goto nterror;
	}

	/* find the pending request */
	p = idr_find(c->searches.idr, in->ldap_msg->messageid);
	if (p == NULL) {
		if (!c->incoming.handler) {
			goto done;
		}

		/* this function should free or steal 'in' */
		c->incoming.handler(c, c->incoming.private_data, in);
		return;
	}

	search = talloc_get_type(p, struct cldap_search_state);
	search->response.in = talloc_move(search, &in);
	search->response.asn1 = asn1;
	search->response.asn1->ofs = 0;

	tevent_req_done(search->req);
	goto done;

nomem:
	in->recv_errno = ENOMEM;
error:
	status = map_nt_error_from_unix(in->recv_errno);
nterror:
	/* in connected mode the first pending search gets the error */
	if (!c->connected) {
		/* otherwise we just ignore the error */
		goto done;
	}
	if (!c->searches.list) {
		goto done;
	}
	tevent_req_nterror(c->searches.list->req, status);
done:
	talloc_free(in);
}