clitransport.c
来自「samba最新软件」· C语言 代码 · 共 667 行 · 第 1/2 页
C
667 行
/* Unix SMB/CIFS implementation. SMB client transport context management functions Copyright (C) Andrew Tridgell 1994-2005 Copyright (C) James Myers 2003 <myersjj@samba.org> 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/>.*/#include "includes.h"#include "libcli/raw/libcliraw.h"#include "libcli/raw/raw_proto.h"#include "lib/socket/socket.h"#include "lib/util/dlinklist.h"#include "lib/events/events.h"#include "lib/stream/packet.h"#include "librpc/gen_ndr/ndr_nbt.h"#include "param/param.h"#include "libcli/nbt/libnbt.h"/* an event has happened on the socket*/static void smbcli_transport_event_handler(struct event_context *ev, struct fd_event *fde, uint16_t flags, void *private){ struct smbcli_transport *transport = talloc_get_type(private, struct smbcli_transport); if (flags & EVENT_FD_READ) { packet_recv(transport->packet); return; } if (flags & EVENT_FD_WRITE) { packet_queue_run(transport->packet); }}/* destroy a transport */static int transport_destructor(struct smbcli_transport *transport){ smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT); return 0;}/* handle receive errors*/static void smbcli_transport_error(void *private, NTSTATUS status){ struct smbcli_transport *transport = talloc_get_type(private, struct smbcli_transport); smbcli_transport_dead(transport, status);}static NTSTATUS smbcli_transport_finish_recv(void *private, DATA_BLOB blob);/* create a transport structure based on an established socket*/struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock, TALLOC_CTX *parent_ctx, bool primary, struct smbcli_options *options){ struct smbcli_transport *transport; transport = talloc_zero(parent_ctx, struct smbcli_transport); if (!transport) return NULL; if (primary) { transport->socket = talloc_steal(transport, sock); } else { transport->socket = talloc_reference(transport, sock); } transport->negotiate.protocol = PROTOCOL_NT1; transport->options = *options; transport->negotiate.max_xmit = transport->options.max_xmit; /* setup the stream -> packet parser */ transport->packet = packet_init(transport); if (transport->packet == NULL) { talloc_free(transport); return NULL; } packet_set_private(transport->packet, transport); packet_set_socket(transport->packet, transport->socket->sock); packet_set_callback(transport->packet, smbcli_transport_finish_recv); packet_set_full_request(transport->packet, packet_full_request_nbt); packet_set_error_handler(transport->packet, smbcli_transport_error); packet_set_event_context(transport->packet, transport->socket->event.ctx); packet_set_nofree(transport->packet); smbcli_init_signing(transport); ZERO_STRUCT(transport->called); /* take over event handling from the socket layer - it only handles events up until we are connected */ talloc_free(transport->socket->event.fde); transport->socket->event.fde = event_add_fd(transport->socket->event.ctx, transport->socket->sock, socket_get_fd(transport->socket->sock), EVENT_FD_READ, smbcli_transport_event_handler, transport); packet_set_fde(transport->packet, transport->socket->event.fde); packet_set_serialise(transport->packet); talloc_set_destructor(transport, transport_destructor); return transport;}/* mark the transport as dead*/void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status){ smbcli_sock_dead(transport->socket); if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) { status = NT_STATUS_UNEXPECTED_NETWORK_ERROR; } /* kill only the first pending receive - this is so that if that async function frees the connection we don't die trying to use old memory. The caller has to cope with only one network error */ if (transport->pending_recv) { struct smbcli_request *req = transport->pending_recv; req->state = SMBCLI_REQUEST_ERROR; req->status = status; DLIST_REMOVE(transport->pending_recv, req); if (req->async.fn) { req->async.fn(req); } }}/* send a session request*/struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport, struct nbt_name *calling, struct nbt_name *called){ uint8_t *p; struct smbcli_request *req; DATA_BLOB calling_blob, called_blob; TALLOC_CTX *tmp_ctx = talloc_new(transport); NTSTATUS status; struct smb_iconv_convenience *iconv_convenience = lp_iconv_convenience(global_loadparm); status = nbt_name_dup(transport, called, &transport->called); if (!NT_STATUS_IS_OK(status)) goto failed; status = nbt_name_to_blob(tmp_ctx, iconv_convenience, &calling_blob, calling); if (!NT_STATUS_IS_OK(status)) goto failed; status = nbt_name_to_blob(tmp_ctx, iconv_convenience, &called_blob, called); if (!NT_STATUS_IS_OK(status)) goto failed; /* allocate output buffer */ req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + calling_blob.length + called_blob.length); if (req == NULL) goto failed; /* put in the destination name */ p = req->out.buffer + NBT_HDR_SIZE; memcpy(p, called_blob.data, called_blob.length); p += called_blob.length; memcpy(p, calling_blob.data, calling_blob.length); p += calling_blob.length; _smb_setlen(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE); SCVAL(req->out.buffer,0,0x81); if (!smbcli_request_send(req)) { smbcli_request_destroy(req); goto failed; } talloc_free(tmp_ctx); return req;failed: talloc_free(tmp_ctx); return NULL;}/* map a session request error to a NTSTATUS */static NTSTATUS map_session_refused_error(uint8_t error){ switch (error) { case 0x80: case 0x81: return NT_STATUS_REMOTE_NOT_LISTENING; case 0x82: return NT_STATUS_RESOURCE_NAME_NOT_FOUND; case 0x83: return NT_STATUS_REMOTE_RESOURCES; } return NT_STATUS_UNEXPECTED_IO_ERROR;}/* finish a smbcli_transport_connect()*/NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req){ NTSTATUS status; if (!smbcli_request_receive(req)) { smbcli_request_destroy(req); return NT_STATUS_UNEXPECTED_NETWORK_ERROR; } switch (CVAL(req->in.buffer,0)) { case 0x82: status = NT_STATUS_OK; break; case 0x83: status = map_session_refused_error(CVAL(req->in.buffer,4)); break; case 0x84: DEBUG(1,("Warning: session retarget not supported\n")); status = NT_STATUS_NOT_SUPPORTED; break; default: status = NT_STATUS_UNEXPECTED_IO_ERROR; break; } smbcli_request_destroy(req); return status;}/* send a session request (if needed)*/bool smbcli_transport_connect(struct smbcli_transport *transport, struct nbt_name *calling, struct nbt_name *called){ struct smbcli_request *req; NTSTATUS status; if (transport->socket->port == 445) { return true; } req = smbcli_transport_connect_send(transport, calling, called); status = smbcli_transport_connect_recv(req); return NT_STATUS_IS_OK(status);}/****************************************************************************get next mid in sequence****************************************************************************/uint16_t smbcli_transport_next_mid(struct smbcli_transport *transport){ uint16_t mid; struct smbcli_request *req; mid = transport->next_mid;again: /* now check to see if this mid is being used by one of the pending requests. This is quite efficient because the list is usually very short */ /* the zero mid is reserved for requests that don't have a mid */ if (mid == 0) mid = 1; for (req=transport->pending_recv; req; req=req->next) { if (req->mid == mid) { mid++; goto again; } } transport->next_mid = mid+1; return mid;}static void idle_handler(struct event_context *ev, struct timed_event *te, struct timeval t, void *private){ struct smbcli_transport *transport = talloc_get_type(private, struct smbcli_transport); struct timeval next = timeval_add(&t, 0, transport->idle.period); transport->socket->event.te = event_add_timed(transport->socket->event.ctx, transport, next, idle_handler, transport); transport->idle.func(transport, transport->idle.private);}/* setup the idle handler for a transport the period is in microseconds*/_PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, void (*idle_func)(struct smbcli_transport *, void *), uint64_t period, void *private){ transport->idle.func = idle_func; transport->idle.private = private; transport->idle.period = period;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?