mirror of
				https://github.com/samba-team/samba.git
				synced 2025-11-04 00:23:49 +03:00 
			
		
		
		
	ldif parsing code in libcli/ldap/ldap_ldif.c, and instead use the ldb ldif code. To do that I have changed the ldap code to use 'struct ldb_message_element' instead of 'struct ldap_attribute'. They are essentially the same structure anyway, so by making them really the same it will be much easier to use the ldb code in libcli/ldap/ I have also made 'struct ldb_val' the same as a DATA_BLOB, which will simplify data handling in quite a few places (I haven't yet removed all the code that maps between these two, that will come later)
		
			
				
	
	
		
			696 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			696 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 
 | 
						|
   Unix SMB/CIFS implementation.
 | 
						|
 | 
						|
   cldap client library
 | 
						|
 | 
						|
   Copyright (C) Andrew Tridgell 2005
 | 
						|
   
 | 
						|
   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
 | 
						|
   (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, write to the Free Software
 | 
						|
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
  see RFC1798 for details of CLDAP
 | 
						|
 | 
						|
  basic properties
 | 
						|
    - carried over UDP on port 389
 | 
						|
    - request and response matched by message ID
 | 
						|
    - request consists of only a single searchRequest element
 | 
						|
    - response can be in one of two forms
 | 
						|
       - a single searchResponse, followed by a searchResult
 | 
						|
       - a single searchResult
 | 
						|
*/
 | 
						|
 | 
						|
#include "includes.h"
 | 
						|
#include "lib/events/events.h"
 | 
						|
#include "dlinklist.h"
 | 
						|
#include "libcli/ldap/ldap.h"
 | 
						|
#include "libcli/cldap/cldap.h"
 | 
						|
#include "lib/socket/socket.h"
 | 
						|
#include "include/asn_1.h"
 | 
						|
 | 
						|
/*
 | 
						|
  destroy a pending request
 | 
						|
*/
 | 
						|
static int cldap_request_destructor(void *ptr)
 | 
						|
{
 | 
						|
	struct cldap_request *req = talloc_get_type(ptr, struct cldap_request);
 | 
						|
	if (req->state == CLDAP_REQUEST_SEND) {
 | 
						|
		DLIST_REMOVE(req->cldap->send_queue, req);
 | 
						|
	}
 | 
						|
	if (!req->is_reply && req->message_id != 0) {
 | 
						|
		idr_remove(req->cldap->idr, req->message_id);
 | 
						|
		req->message_id = 0;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  handle recv events on a cldap socket
 | 
						|
*/
 | 
						|
static void cldap_socket_recv(struct cldap_socket *cldap)
 | 
						|
{
 | 
						|
	TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 | 
						|
	NTSTATUS status;
 | 
						|
	const char *src_addr;
 | 
						|
	int src_port;
 | 
						|
	DATA_BLOB blob;
 | 
						|
	size_t nread, dsize;
 | 
						|
	struct asn1_data asn1;
 | 
						|
	struct ldap_message *ldap_msg;
 | 
						|
	struct cldap_request *req;
 | 
						|
 | 
						|
	status = socket_pending(cldap->sock, &dsize);
 | 
						|
	if (!NT_STATUS_IS_OK(status)) {
 | 
						|
		talloc_free(tmp_ctx);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	blob = data_blob_talloc(tmp_ctx, NULL, dsize);
 | 
						|
	if (blob.data == NULL) {
 | 
						|
		talloc_free(tmp_ctx);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	status = socket_recvfrom(cldap->sock, blob.data, blob.length, &nread, 0,
 | 
						|
				 &src_addr, &src_port);
 | 
						|
	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", 
 | 
						|
		 blob.length, src_addr, src_port));
 | 
						|
 | 
						|
	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) {
 | 
						|
		talloc_free(tmp_ctx);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* this initial decode is used to find the message id */
 | 
						|
	if (!ldap_decode(&asn1, ldap_msg)) {
 | 
						|
		DEBUG(2,("Failed to decode ldap message\n"));
 | 
						|
		talloc_free(tmp_ctx);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	/* find the pending request */
 | 
						|
	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);
 | 
						|
		} else {
 | 
						|
			DEBUG(2,("Mismatched cldap reply %u from %s:%d\n",
 | 
						|
				 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->state = CLDAP_REQUEST_DONE;
 | 
						|
	talloc_free(req->te);
 | 
						|
 | 
						|
	talloc_free(tmp_ctx);
 | 
						|
 | 
						|
	if (req->async.fn) {
 | 
						|
		req->async.fn(req);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  handle request timeouts
 | 
						|
*/
 | 
						|
static void cldap_request_timeout(struct event_context *event_ctx, 
 | 
						|
				  struct timed_event *te, struct timeval t,
 | 
						|
				  void *private)
 | 
						|
{
 | 
						|
	struct cldap_request *req = talloc_get_type(private, struct cldap_request);
 | 
						|
 | 
						|
	/* possibly try again */
 | 
						|
	if (req->num_retries != 0) {
 | 
						|
		size_t len = req->encoded.length;
 | 
						|
 | 
						|
		req->num_retries--;
 | 
						|
 | 
						|
		socket_sendto(req->cldap->sock, &req->encoded, &len, 0, 
 | 
						|
			      req->dest_addr, req->dest_port);
 | 
						|
 | 
						|
		req->te = event_add_timed(req->cldap->event_ctx, req, 
 | 
						|
					  timeval_current_ofs(req->timeout, 0),
 | 
						|
					  cldap_request_timeout, req);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	req->state = CLDAP_REQUEST_TIMEOUT;
 | 
						|
	if (req->async.fn) {
 | 
						|
		req->async.fn(req);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  handle send events on a cldap socket
 | 
						|
*/
 | 
						|
static void cldap_socket_send(struct cldap_socket *cldap)
 | 
						|
{
 | 
						|
	struct cldap_request *req;
 | 
						|
	NTSTATUS status;
 | 
						|
 | 
						|
	while ((req = cldap->send_queue)) {
 | 
						|
		size_t len;
 | 
						|
		
 | 
						|
		len = req->encoded.length;
 | 
						|
		status = socket_sendto(cldap->sock, &req->encoded, &len, 0, 
 | 
						|
				       req->dest_addr, req->dest_port);
 | 
						|
		if (NT_STATUS_IS_ERR(status)) {
 | 
						|
			DEBUG(3,("Failed to send cldap request of length %u to %s:%d\n",
 | 
						|
				 req->encoded.length, req->dest_addr, req->dest_port));
 | 
						|
			DLIST_REMOVE(cldap->send_queue, req);
 | 
						|
			talloc_free(req);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!NT_STATUS_IS_OK(status)) return;
 | 
						|
 | 
						|
		DLIST_REMOVE(cldap->send_queue, req);
 | 
						|
 | 
						|
		if (req->is_reply) {
 | 
						|
			talloc_free(req);
 | 
						|
		} else {
 | 
						|
			req->state = CLDAP_REQUEST_WAIT;
 | 
						|
 | 
						|
			req->te = event_add_timed(cldap->event_ctx, req, 
 | 
						|
						  timeval_current_ofs(req->timeout, 0),
 | 
						|
						  cldap_request_timeout, req);
 | 
						|
 | 
						|
			EVENT_FD_READABLE(cldap->fde);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	EVENT_FD_NOT_WRITEABLE(cldap->fde);
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  handle fd events on a cldap_socket
 | 
						|
*/
 | 
						|
static void cldap_socket_handler(struct event_context *ev, struct fd_event *fde,
 | 
						|
				 uint16_t flags, void *private)
 | 
						|
{
 | 
						|
	struct cldap_socket *cldap = talloc_get_type(private, struct cldap_socket);
 | 
						|
	if (flags & EVENT_FD_WRITE) {
 | 
						|
		cldap_socket_send(cldap);
 | 
						|
	} 
 | 
						|
	if (flags & EVENT_FD_READ) {
 | 
						|
		cldap_socket_recv(cldap);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  initialise a cldap_socket. The event_ctx is optional, if provided
 | 
						|
  then operations will use that event context
 | 
						|
*/
 | 
						|
struct cldap_socket *cldap_socket_init(TALLOC_CTX *mem_ctx, 
 | 
						|
				       struct event_context *event_ctx)
 | 
						|
{
 | 
						|
	struct cldap_socket *cldap;
 | 
						|
	NTSTATUS status;
 | 
						|
 | 
						|
	cldap = talloc(mem_ctx, struct cldap_socket);
 | 
						|
	if (cldap == NULL) goto failed;
 | 
						|
 | 
						|
	if (event_ctx == NULL) {
 | 
						|
		cldap->event_ctx = event_context_init(cldap);
 | 
						|
	} else {
 | 
						|
		cldap->event_ctx = talloc_reference(cldap, event_ctx);
 | 
						|
	}
 | 
						|
	if (cldap->event_ctx == NULL) goto failed;
 | 
						|
 | 
						|
	cldap->idr = idr_init(cldap);
 | 
						|
	if (cldap->idr == NULL) goto failed;
 | 
						|
 | 
						|
	status = socket_create("ip", SOCKET_TYPE_DGRAM, &cldap->sock, 0);
 | 
						|
	if (!NT_STATUS_IS_OK(status)) goto failed;
 | 
						|
 | 
						|
	talloc_steal(cldap, cldap->sock);
 | 
						|
 | 
						|
	cldap->fde = event_add_fd(cldap->event_ctx, cldap, 
 | 
						|
				      socket_get_fd(cldap->sock), 0,
 | 
						|
				      cldap_socket_handler, cldap);
 | 
						|
 | 
						|
	cldap->send_queue = NULL;
 | 
						|
	cldap->incoming.handler = NULL;
 | 
						|
	
 | 
						|
	return cldap;
 | 
						|
 | 
						|
failed:
 | 
						|
	talloc_free(cldap);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  setup a handler for incoming requests
 | 
						|
*/
 | 
						|
NTSTATUS cldap_set_incoming_handler(struct cldap_socket *cldap,
 | 
						|
				  void (*handler)(struct cldap_socket *, struct ldap_message *, 
 | 
						|
						  const char *, int ),
 | 
						|
				  void *private)
 | 
						|
{
 | 
						|
	cldap->incoming.handler = handler;
 | 
						|
	cldap->incoming.private = private;
 | 
						|
	EVENT_FD_READABLE(cldap->fde);
 | 
						|
	return NT_STATUS_OK;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  queue a cldap request for send
 | 
						|
*/
 | 
						|
struct cldap_request *cldap_search_send(struct cldap_socket *cldap, 
 | 
						|
					struct cldap_search *io)
 | 
						|
{
 | 
						|
	struct ldap_message *msg;
 | 
						|
	struct cldap_request *req;
 | 
						|
	struct ldap_SearchRequest *search;
 | 
						|
 | 
						|
	req = talloc_zero(cldap, struct cldap_request);
 | 
						|
	if (req == NULL) goto failed;
 | 
						|
 | 
						|
	req->cldap       = cldap;
 | 
						|
	req->state       = CLDAP_REQUEST_SEND;
 | 
						|
	req->timeout     = io->in.timeout;
 | 
						|
	req->num_retries = io->in.retries;
 | 
						|
	req->is_reply    = False;
 | 
						|
 | 
						|
	req->dest_addr = talloc_strdup(req, io->in.dest_address);
 | 
						|
	if (req->dest_addr == NULL) goto failed;
 | 
						|
	req->dest_port = lp_cldap_port();
 | 
						|
 | 
						|
	req->message_id = idr_get_new_random(cldap->idr, req, UINT16_MAX);
 | 
						|
	if (req->message_id == -1) goto failed;
 | 
						|
 | 
						|
	talloc_set_destructor(req, cldap_request_destructor);
 | 
						|
 | 
						|
	msg = talloc(req, struct ldap_message);
 | 
						|
	if (msg == NULL) goto failed;
 | 
						|
	msg->messageid       = req->message_id;
 | 
						|
	msg->type            = LDAP_TAG_SearchRequest;
 | 
						|
	msg->num_controls    = 0;
 | 
						|
	msg->controls        = NULL;
 | 
						|
	search = &msg->r.SearchRequest;
 | 
						|
 | 
						|
	search->basedn         = "";
 | 
						|
	search->scope          = LDAP_SEARCH_SCOPE_BASE;
 | 
						|
	search->deref          = LDAP_DEREFERENCE_NEVER;
 | 
						|
	search->timelimit      = 0;
 | 
						|
	search->sizelimit      = 0;
 | 
						|
	search->attributesonly = False;
 | 
						|
	search->num_attributes = str_list_length(io->in.attributes);
 | 
						|
	search->attributes     = io->in.attributes;
 | 
						|
	search->tree           = ldb_parse_tree(req, io->in.filter);
 | 
						|
	if (search->tree == NULL) {
 | 
						|
		goto failed;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!ldap_encode(msg, &req->encoded)) {
 | 
						|
		DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 | 
						|
			 req->dest_addr, req->dest_port));
 | 
						|
		goto failed;
 | 
						|
	}
 | 
						|
	talloc_steal(req, req->encoded.data);
 | 
						|
 | 
						|
	DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
 | 
						|
 | 
						|
	EVENT_FD_WRITEABLE(cldap->fde);
 | 
						|
 | 
						|
	return req;
 | 
						|
 | 
						|
failed:
 | 
						|
	talloc_free(req);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  queue a cldap reply for send
 | 
						|
*/
 | 
						|
NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
 | 
						|
{
 | 
						|
	struct ldap_message *msg;
 | 
						|
	struct cldap_request *req;
 | 
						|
	DATA_BLOB blob1, blob2;
 | 
						|
	NTSTATUS status = NT_STATUS_NO_MEMORY;
 | 
						|
 | 
						|
	req = talloc_zero(cldap, struct cldap_request);
 | 
						|
	if (req == NULL) goto failed;
 | 
						|
 | 
						|
	req->cldap       = cldap;
 | 
						|
	req->state       = CLDAP_REQUEST_SEND;
 | 
						|
	req->is_reply    = True;
 | 
						|
 | 
						|
	req->dest_addr = talloc_strdup(req, io->dest_address);
 | 
						|
	if (req->dest_addr == NULL) goto failed;
 | 
						|
	req->dest_port = io->dest_port;
 | 
						|
 | 
						|
	talloc_set_destructor(req, cldap_request_destructor);
 | 
						|
 | 
						|
	msg = talloc(req, struct ldap_message);
 | 
						|
	if (msg == NULL) goto failed;
 | 
						|
	msg->messageid       = io->messageid;
 | 
						|
	msg->num_controls    = 0;
 | 
						|
	msg->controls        = NULL;
 | 
						|
	
 | 
						|
	if (io->response) {
 | 
						|
		msg->type = LDAP_TAG_SearchResultEntry;
 | 
						|
		msg->r.SearchResultEntry = *io->response;
 | 
						|
 | 
						|
		if (!ldap_encode(msg, &blob1)) {
 | 
						|
			DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 | 
						|
				 req->dest_addr, req->dest_port));
 | 
						|
			status = NT_STATUS_INVALID_PARAMETER;
 | 
						|
			goto failed;
 | 
						|
		}
 | 
						|
		talloc_steal(req, blob1.data);
 | 
						|
	} else {
 | 
						|
		blob1 = data_blob(NULL, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	msg->type = LDAP_TAG_SearchResultDone;
 | 
						|
	msg->r.SearchResultDone = *io->result;
 | 
						|
 | 
						|
	if (!ldap_encode(msg, &blob2)) {
 | 
						|
		DEBUG(0,("Failed to encode cldap message to %s:%d\n",
 | 
						|
			 req->dest_addr, req->dest_port));
 | 
						|
		status = NT_STATUS_INVALID_PARAMETER;
 | 
						|
		goto failed;
 | 
						|
	}
 | 
						|
	talloc_steal(req, blob2.data);
 | 
						|
 | 
						|
	req->encoded = data_blob_talloc(req, NULL, blob1.length + blob2.length);
 | 
						|
	if (req->encoded.data == NULL) goto failed;
 | 
						|
 | 
						|
	memcpy(req->encoded.data, blob1.data, blob1.length);
 | 
						|
	memcpy(req->encoded.data+blob1.length, blob2.data, blob2.length);
 | 
						|
 | 
						|
	DLIST_ADD_END(cldap->send_queue, req, struct cldap_request *);
 | 
						|
 | 
						|
	EVENT_FD_WRITEABLE(cldap->fde);
 | 
						|
 | 
						|
	return NT_STATUS_OK;
 | 
						|
 | 
						|
failed:
 | 
						|
	talloc_free(req);
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  receive a cldap reply
 | 
						|
*/
 | 
						|
NTSTATUS cldap_search_recv(struct cldap_request *req, 
 | 
						|
			   TALLOC_CTX *mem_ctx, 
 | 
						|
			   struct cldap_search *io)
 | 
						|
{
 | 
						|
	struct ldap_message *ldap_msg;
 | 
						|
 | 
						|
	if (req == NULL) {
 | 
						|
		return NT_STATUS_NO_MEMORY;
 | 
						|
	}
 | 
						|
 | 
						|
	while (req->state < CLDAP_REQUEST_DONE) {
 | 
						|
		if (event_loop_once(req->cldap->event_ctx) != 0) {
 | 
						|
			talloc_free(req);
 | 
						|
			return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (req->state == CLDAP_REQUEST_TIMEOUT) {
 | 
						|
		talloc_free(req);
 | 
						|
		return NT_STATUS_IO_TIMEOUT;
 | 
						|
	}
 | 
						|
 | 
						|
	ldap_msg = talloc(mem_ctx, struct ldap_message);
 | 
						|
	NT_STATUS_HAVE_NO_MEMORY(ldap_msg);
 | 
						|
 | 
						|
	if (!ldap_decode(&req->asn1, ldap_msg)) {
 | 
						|
		talloc_free(req);
 | 
						|
		return NT_STATUS_INVALID_PARAMETER;
 | 
						|
	}
 | 
						|
 | 
						|
	ZERO_STRUCT(io->out);
 | 
						|
 | 
						|
	/* the first possible form has a search result in first place */
 | 
						|
	if (ldap_msg->type == LDAP_TAG_SearchResultEntry) {
 | 
						|
		io->out.response = talloc(mem_ctx, struct ldap_SearchResEntry);
 | 
						|
		NT_STATUS_HAVE_NO_MEMORY(io->out.response);
 | 
						|
		*io->out.response = ldap_msg->r.SearchResultEntry;
 | 
						|
 | 
						|
		/* decode the 2nd part */
 | 
						|
		if (!ldap_decode(&req->asn1, ldap_msg)) {
 | 
						|
			talloc_free(req);
 | 
						|
			return NT_STATUS_INVALID_PARAMETER;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (ldap_msg->type != LDAP_TAG_SearchResultDone) {
 | 
						|
		talloc_free(req);
 | 
						|
		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 | 
						|
	}
 | 
						|
 | 
						|
	io->out.result = talloc(mem_ctx, struct ldap_Result);
 | 
						|
	NT_STATUS_HAVE_NO_MEMORY(io->out.result);
 | 
						|
	*io->out.result = ldap_msg->r.SearchResultDone;
 | 
						|
 | 
						|
	talloc_free(req);
 | 
						|
	return NT_STATUS_OK;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  synchronous cldap search
 | 
						|
*/
 | 
						|
NTSTATUS cldap_search(struct cldap_socket *cldap, 
 | 
						|
		      TALLOC_CTX *mem_ctx, 
 | 
						|
		      struct cldap_search *io)
 | 
						|
{
 | 
						|
	struct cldap_request *req = cldap_search_send(cldap, io);
 | 
						|
	return cldap_search_recv(req, mem_ctx, io);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  queue a cldap netlogon for send
 | 
						|
*/
 | 
						|
struct cldap_request *cldap_netlogon_send(struct cldap_socket *cldap, 
 | 
						|
					  struct cldap_netlogon *io)
 | 
						|
{
 | 
						|
	struct cldap_search search;
 | 
						|
	char *filter;
 | 
						|
	struct cldap_request *req;
 | 
						|
	const char *attr[] = { "NetLogon", NULL };
 | 
						|
	TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 | 
						|
 | 
						|
	filter = talloc_asprintf(tmp_ctx, "(&(NtVer=%s)", 
 | 
						|
				 ldap_encode_ndr_uint32(tmp_ctx, io->in.version));
 | 
						|
	if (filter == NULL) goto failed;
 | 
						|
	if (io->in.user) {
 | 
						|
		filter = talloc_asprintf_append(filter, "(User=%s)", io->in.user);
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	if (io->in.host) {
 | 
						|
		filter = talloc_asprintf_append(filter, "(Host=%s)", io->in.host);
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	if (io->in.realm) {
 | 
						|
		filter = talloc_asprintf_append(filter, "(DnsDomain=%s)", io->in.realm);
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	if (io->in.acct_control != -1) {
 | 
						|
		filter = talloc_asprintf_append(filter, "(AAC=%s)", 
 | 
						|
						ldap_encode_ndr_uint32(tmp_ctx, io->in.acct_control));
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	if (io->in.domain_sid) {
 | 
						|
		struct dom_sid *sid = dom_sid_parse_talloc(tmp_ctx, io->in.domain_sid);
 | 
						|
		if (sid == NULL) goto failed;
 | 
						|
		filter = talloc_asprintf_append(filter, "(domainSid=%s)",
 | 
						|
						ldap_encode_ndr_dom_sid(tmp_ctx, sid));
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	if (io->in.domain_guid) {
 | 
						|
		struct GUID guid;
 | 
						|
		NTSTATUS status;
 | 
						|
		status = GUID_from_string(io->in.domain_guid, &guid);
 | 
						|
		if (!NT_STATUS_IS_OK(status)) goto failed;
 | 
						|
		filter = talloc_asprintf_append(filter, "(DomainGuid=%s)",
 | 
						|
						ldap_encode_ndr_GUID(tmp_ctx, &guid));
 | 
						|
		if (filter == NULL) goto failed;
 | 
						|
	}
 | 
						|
	filter = talloc_asprintf_append(filter, ")");
 | 
						|
	if (filter == NULL) goto failed;
 | 
						|
 | 
						|
	search.in.dest_address = io->in.dest_address;
 | 
						|
	search.in.filter       = filter;
 | 
						|
	search.in.attributes   = attr;
 | 
						|
	search.in.timeout      = 2;
 | 
						|
	search.in.retries      = 2;
 | 
						|
 | 
						|
	req = cldap_search_send(cldap, &search);
 | 
						|
 | 
						|
	talloc_free(tmp_ctx);
 | 
						|
	return req;
 | 
						|
failed:
 | 
						|
	talloc_free(tmp_ctx);
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  receive a cldap netlogon reply
 | 
						|
*/
 | 
						|
NTSTATUS cldap_netlogon_recv(struct cldap_request *req, 
 | 
						|
			     TALLOC_CTX *mem_ctx, 
 | 
						|
			     struct cldap_netlogon *io)
 | 
						|
{
 | 
						|
	NTSTATUS status;
 | 
						|
	struct cldap_search search;
 | 
						|
	DATA_BLOB *data;
 | 
						|
 | 
						|
	status = cldap_search_recv(req, mem_ctx, &search);
 | 
						|
	if (!NT_STATUS_IS_OK(status)) {
 | 
						|
		return status;
 | 
						|
	}
 | 
						|
	if (search.out.response == NULL) {
 | 
						|
		return NT_STATUS_NOT_FOUND;
 | 
						|
	}
 | 
						|
 | 
						|
	if (search.out.response->num_attributes != 1 ||
 | 
						|
	    strcasecmp(search.out.response->attributes[0].name, "netlogon") != 0 ||
 | 
						|
	    search.out.response->attributes[0].num_values != 1 ||
 | 
						|
	    search.out.response->attributes[0].values->length < 2) {
 | 
						|
		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 | 
						|
	}
 | 
						|
	data = search.out.response->attributes[0].values;
 | 
						|
 | 
						|
	status = ndr_pull_union_blob(data, mem_ctx, &io->out.netlogon, 
 | 
						|
				     io->in.version & 0xF,
 | 
						|
				     (ndr_pull_flags_fn_t)ndr_pull_nbt_cldap_netlogon);
 | 
						|
	if (!NT_STATUS_IS_OK(status)) {
 | 
						|
		DEBUG(2,("cldap failed to parse netlogon response of type 0x%02x\n",
 | 
						|
			 SVAL(data->data, 0)));
 | 
						|
		dump_data(10, data->data, data->length);
 | 
						|
	}
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
  sync cldap netlogon search
 | 
						|
*/
 | 
						|
NTSTATUS cldap_netlogon(struct cldap_socket *cldap, 
 | 
						|
			TALLOC_CTX *mem_ctx, struct cldap_netlogon *io)
 | 
						|
{
 | 
						|
	struct cldap_request *req = cldap_netlogon_send(cldap, io);
 | 
						|
	return cldap_netlogon_recv(req, mem_ctx, io);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  send an empty reply (used on any error, so the client doesn't keep waiting
 | 
						|
  or send the bad request again)
 | 
						|
*/
 | 
						|
NTSTATUS cldap_empty_reply(struct cldap_socket *cldap, 
 | 
						|
			   uint32_t message_id,
 | 
						|
			   const char *src_address, int src_port)
 | 
						|
{
 | 
						|
	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.response     = NULL;
 | 
						|
	reply.result       = &result;
 | 
						|
 | 
						|
	ZERO_STRUCT(result);
 | 
						|
 | 
						|
	status = cldap_reply_send(cldap, &reply);
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  send a netlogon reply 
 | 
						|
*/
 | 
						|
NTSTATUS cldap_netlogon_reply(struct cldap_socket *cldap, 
 | 
						|
			      uint32_t message_id,
 | 
						|
			      const char *src_address, int src_port,
 | 
						|
			      uint32_t version,
 | 
						|
			      union nbt_cldap_netlogon *netlogon)
 | 
						|
{
 | 
						|
	NTSTATUS status;
 | 
						|
	struct cldap_reply reply;
 | 
						|
	struct ldap_SearchResEntry response;
 | 
						|
	struct ldap_Result result;
 | 
						|
	TALLOC_CTX *tmp_ctx = talloc_new(cldap);
 | 
						|
	DATA_BLOB blob;
 | 
						|
 | 
						|
	status = ndr_push_union_blob(&blob, tmp_ctx, netlogon, version & 0xF, 
 | 
						|
				     (ndr_push_flags_fn_t)ndr_push_nbt_cldap_netlogon);
 | 
						|
	if (!NT_STATUS_IS_OK(status)) {
 | 
						|
		talloc_free(tmp_ctx);
 | 
						|
		return status;
 | 
						|
	}
 | 
						|
 | 
						|
	reply.messageid    = message_id;
 | 
						|
	reply.dest_address = src_address;
 | 
						|
	reply.dest_port    = src_port;
 | 
						|
	reply.response     = &response;
 | 
						|
	reply.result       = &result;
 | 
						|
 | 
						|
	ZERO_STRUCT(result);
 | 
						|
 | 
						|
	response.dn = "";
 | 
						|
	response.num_attributes = 1;
 | 
						|
	response.attributes = talloc(tmp_ctx, struct ldb_message_element);
 | 
						|
	NT_STATUS_HAVE_NO_MEMORY(response.attributes);
 | 
						|
	response.attributes->name = "netlogon";
 | 
						|
	response.attributes->num_values = 1;
 | 
						|
	response.attributes->values = &blob;
 | 
						|
 | 
						|
	status = cldap_reply_send(cldap, &reply);
 | 
						|
 | 
						|
	talloc_free(tmp_ctx);
 | 
						|
 | 
						|
	return status;
 | 
						|
}
 | 
						|
 | 
						|
 |