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 + -
显示快捷键?