cldap.c

来自「samba最新软件」· C语言 代码 · 共 740 行 · 第 1/2 页

C
740
字号
/*    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 3 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, see <http://www.gnu.org/licenses/>.*//*  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 "lib/util/dlinklist.h"#include "libcli/ldap/ldap.h"#include "libcli/ldap/ldap_ndr.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(struct cldap_request *req){	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;	struct socket_address *src;	DATA_BLOB blob;	size_t nread, dsize;	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;	}	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,				 tmp_ctx, &src);	if (!NT_STATUS_IS_OK(status)) {		talloc_free(tmp_ctx);		return;	}	blob.length = nread;	DEBUG(2,("Received cldap packet of length %d from %s:%d\n", 		 (int)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;	}	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 */	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;	}	/* 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);		} 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 = talloc_steal(req, asn1);	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, 			      req->dest);		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_ERROR;	req->status = NT_STATUS_IO_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,				       req->dest);		if (NT_STATUS_IS_ERR(status)) {			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);			req->state = CLDAP_REQUEST_ERROR;			req->status = status;			if (req->async.fn) {				req->async.fn(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 smb_iconv_convenience *iconv_convenience){	struct cldap_socket *cldap;	NTSTATUS status;	cldap = talloc(mem_ctx, struct cldap_socket);	if (cldap == NULL) goto failed;	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;	cldap->iconv_convenience = iconv_convenience;		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 *, 						  struct socket_address *),				  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->asn1        = asn1_init(req);	if (!req->asn1) {		goto failed;	}	req->dest = socket_address_from_strings(req, cldap->sock->backend_name,						io->in.dest_address, 						io->in.dest_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;	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->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, req)) {		DEBUG(0,("Failed to encode cldap message to %s:%d\n",			 req->dest->addr, req->dest->port));		goto failed;	}	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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?