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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "includes.h"
#include "lib/events/events.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
#include "libcli/ldap/ldap.h"
#include "libcli/cldap/cldap.h"
#include "lib/socket/socket.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_nbt.h"
+#include "param/param.h"
/*
destroy a pending request
*/
-static int cldap_request_destructor(void *ptr)
+static int cldap_request_destructor(struct cldap_request *req)
{
- struct cldap_request *req = talloc_get_type(ptr, struct cldap_request);
if (req->state == CLDAP_REQUEST_SEND) {
DLIST_REMOVE(req->cldap->send_queue, req);
}
{
TALLOC_CTX *tmp_ctx = talloc_new(cldap);
NTSTATUS status;
- const char *src_addr;
- int src_port;
+ struct socket_address *src;
DATA_BLOB blob;
size_t nread, dsize;
- struct asn1_data asn1;
+ struct asn1_data *asn1 = asn1_init(tmp_ctx);
struct ldap_message *ldap_msg;
struct cldap_request *req;
+ if (!asn1) return;
+
status = socket_pending(cldap->sock, &dsize);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
return;
}
- status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread, 0,
- &src_addr, &src_port);
+ status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread,
+ tmp_ctx, &src);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
return;
}
- talloc_steal(tmp_ctx, src_addr);
blob.length = nread;
DEBUG(2,("Received cldap packet of length %d from %s:%d\n",
- (int)blob.length, src_addr, src_port));
+ (int)blob.length, src->addr, src->port));
- if (!asn1_load(&asn1, blob)) {
+ if (!asn1_load(asn1, blob)) {
DEBUG(2,("Failed to setup for asn.1 decode\n"));
talloc_free(tmp_ctx);
return;
}
- talloc_steal(tmp_ctx, asn1.data);
ldap_msg = talloc(tmp_ctx, struct ldap_message);
if (ldap_msg == NULL) {
}
/* this initial decode is used to find the message id */
- if (!ldap_decode(&asn1, ldap_msg)) {
- DEBUG(2,("Failed to decode ldap message\n"));
+ status = ldap_decode(asn1, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("Failed to decode ldap message: %s\n", nt_errstr(status)));
talloc_free(tmp_ctx);
return;
}
req = idr_find(cldap->idr, ldap_msg->messageid);
if (req == NULL) {
if (cldap->incoming.handler) {
- cldap->incoming.handler(cldap, ldap_msg, src_addr, src_port);
+ cldap->incoming.handler(cldap, ldap_msg, src);
} else {
DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
- ldap_msg->messageid, src_addr, src_port));
+ ldap_msg->messageid, src->addr, src->port));
}
talloc_free(tmp_ctx);
return;
}
- req->asn1 = asn1;
- talloc_steal(req, asn1.data);
- req->asn1.ofs = 0;
+ req->asn1 = talloc_steal(req, asn1);
+ req->asn1->ofs = 0;
req->state = CLDAP_REQUEST_DONE;
talloc_free(req->te);
req->num_retries--;
- socket_sendto(req->cldap->sock, &req->encoded, &len, 0,
- req->dest_addr, req->dest_port);
+ socket_sendto(req->cldap->sock, &req->encoded, &len,
+ req->dest);
req->te = event_add_timed(req->cldap->event_ctx, req,
timeval_current_ofs(req->timeout, 0),
return;
}
- req->state = CLDAP_REQUEST_TIMEOUT;
+ req->state = CLDAP_REQUEST_ERROR;
+ req->status = NT_STATUS_IO_TIMEOUT;
if (req->async.fn) {
req->async.fn(req);
}
size_t len;
len = req->encoded.length;
- status = socket_sendto(cldap->sock, &req->encoded, &len, 0,
- req->dest_addr, req->dest_port);
+ status = socket_sendto(cldap->sock, &req->encoded, &len,
+ req->dest);
if (NT_STATUS_IS_ERR(status)) {
- DEBUG(3,("Failed to send cldap request of length %u to %s:%d\n",
- (unsigned)req->encoded.length, req->dest_addr, req->dest_port));
+ DEBUG(0,("Failed to send cldap request of length %u to %s:%d\n",
+ (unsigned)req->encoded.length, req->dest->addr, req->dest->port));
DLIST_REMOVE(cldap->send_queue, req);
- talloc_free(req);
+ req->state = CLDAP_REQUEST_ERROR;
+ req->status = status;
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
continue;
}
*/
NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
void (*handler)(struct cldap_socket *, struct ldap_message *,
- const char *, int ),
+ struct socket_address *),
void *private)
{
cldap->incoming.handler = handler;
req->timeout = io->in.timeout;
req->num_retries = io->in.retries;
req->is_reply = False;
+ req->asn1 = asn1_init(req);
+ if (!req->asn1) {
+ goto failed;
+ }
- req->dest_addr = talloc_strdup(req, io->in.dest_address);
- if (req->dest_addr == NULL) goto failed;
- req->dest_port = lp_cldap_port();
+ req->dest = socket_address_from_strings(req, cldap->sock->backend_name,
+ io->in.dest_address,
+ lp_cldap_port());
+ if (!req->dest) goto failed;
req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
if (req->message_id == -1) goto failed;
if (!ldap_encode(msg, &req->encoded, req)) {
DEBUG(0,("Failed to encode cldap message to %s:%d\n",
- req->dest_addr, req->dest_port));
+ req->dest->addr, req->dest->port));
goto failed;
}
req->cldap = cldap;
req->state = CLDAP_REQUEST_SEND;
req->is_reply = True;
+ req->asn1 = asn1_init(req);
+ if (!req->asn1) {
+ goto failed;
+ }
- req->dest_addr = talloc_strdup(req, io->dest_address);
- if (req->dest_addr == NULL) goto failed;
- req->dest_port = io->dest_port;
+ req->dest = io->dest;
+ if (talloc_reference(req, io->dest) == NULL) goto failed;
talloc_set_destructor(req, cldap_request_destructor);
if (!ldap_encode(msg, &blob1, req)) {
DEBUG(0,("Failed to encode cldap message to %s:%d\n",
- req->dest_addr, req->dest_port));
+ req->dest->addr, req->dest->port));
status = NT_STATUS_INVALID_PARAMETER;
goto failed;
}
if (!ldap_encode(msg, &blob2, req)) {
DEBUG(0,("Failed to encode cldap message to %s:%d\n",
- req->dest_addr, req->dest_port));
+ req->dest->addr, req->dest->port));
status = NT_STATUS_INVALID_PARAMETER;
goto failed;
}
struct cldap_search *io)
{
struct ldap_message *ldap_msg;
+ NTSTATUS status;
if (req == NULL) {
return NT_STATUS_NO_MEMORY;
}
}
- if (req->state == CLDAP_REQUEST_TIMEOUT) {
+ if (req->state == CLDAP_REQUEST_ERROR) {
+ status = req->status;
talloc_free(req);
- return NT_STATUS_IO_TIMEOUT;
+ return status;
}
ldap_msg = talloc(mem_ctx, struct ldap_message);
NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
- if (!ldap_decode(&req->asn1, ldap_msg)) {
+ status = ldap_decode(req->asn1, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("Failed to decode cldap search reply: %s\n", nt_errstr(status)));
talloc_free(req);
- return NT_STATUS_INVALID_PARAMETER;
+ return status;
}
ZERO_STRUCT(io->out);
*io->out.response = ldap_msg->r.SearchResultEntry;
/* decode the 2nd part */
- if (!ldap_decode(&req->asn1, ldap_msg)) {
+ status = ldap_decode(req->asn1, ldap_msg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2,("Failed to decode cldap search result entry: %s\n", nt_errstr(status)));
talloc_free(req);
- return NT_STATUS_INVALID_PARAMETER;
+ return status;
}
}
if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
talloc_free(req);
- return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
io->out.result = talloc(mem_ctx, struct ldap_Result);
*io->out.result = ldap_msg->r.SearchResultDone;
talloc_free(req);
+
+ if (io->out.result->resultcode != LDAP_SUCCESS) {
+ return NT_STATUS_LDAP(io->out.result->resultcode);
+ }
return NT_STATUS_OK;
}
*/
NTSTATUS cldap_empty_reply(struct cldap_socket *cldap,
uint32_t message_id,
- const char *src_address, int src_port)
+ struct socket_address *src)
+{
+ NTSTATUS status;
+ struct cldap_reply reply;
+ struct ldap_Result result;
+
+ reply.messageid = message_id;
+ reply.dest = src;
+ reply.response = NULL;
+ reply.result = &result;
+
+ ZERO_STRUCT(result);
+
+ status = cldap_reply_send(cldap, &reply);
+
+ return status;
+}
+
+/*
+ send an error reply (used on any error, so the client doesn't keep waiting
+ or send the bad request again)
+*/
+NTSTATUS cldap_error_reply(struct cldap_socket *cldap,
+ uint32_t message_id,
+ struct socket_address *src,
+ int resultcode,
+ const char *errormessage)
{
NTSTATUS status;
struct cldap_reply reply;
struct ldap_Result result;
reply.messageid = message_id;
- reply.dest_address = src_address;
- reply.dest_port = src_port;
+ reply.dest = src;
reply.response = NULL;
reply.result = &result;
ZERO_STRUCT(result);
+ result.resultcode = resultcode;
+ result.errormessage = errormessage;
status = cldap_reply_send(cldap, &reply);
*/
NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap,
uint32_t message_id,
- const char *src_address, int src_port,
+ struct socket_address *src,
uint32_t version,
union nbt_cldap_netlogon *netlogon)
{
}
reply.messageid = message_id;
- reply.dest_address = src_address;
- reply.dest_port = src_port;
+ reply.dest = src;
reply.response = &response;
reply.result = &result;