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