⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcon.c

📁 samba最新软件
💻 C
字号:
/*    Unix SMB2 implementation.      Copyright (C) Stefan Metzmacher	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/>.*/#include "includes.h"#include "libcli/smb2/smb2.h"#include "libcli/smb2/smb2_calls.h"#include "smb_server/smb_server.h"#include "smb_server/service_smb_proto.h"#include "smb_server/smb2/smb2_server.h"#include "librpc/gen_ndr/security.h"#include "smbd/service_stream.h"#include "ntvfs/ntvfs.h"#include "param/param.h"/*  send an oplock break request to a client*/static NTSTATUS smb2srv_send_oplock_break(void *p, struct ntvfs_handle *h, uint8_t level){	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,						       struct smbsrv_handle);	struct smb2srv_request *req;	NTSTATUS status;	/* setup a dummy request structure */	req = smb2srv_init_request(handle->tcon->smb_conn);	NT_STATUS_HAVE_NO_MEMORY(req);	req->in.buffer		= talloc_array(req, uint8_t, 					       NBT_HDR_SIZE + SMB2_MIN_SIZE);	NT_STATUS_HAVE_NO_MEMORY(req->in.buffer);	req->in.size		= NBT_HDR_SIZE + SMB2_MIN_SIZE;	req->in.allocated	= req->in.size;	req->in.hdr		= req->in.buffer+ NBT_HDR_SIZE;	req->in.body		= req->in.hdr	+ SMB2_HDR_BODY;	req->in.body_size	= req->in.size	- (SMB2_HDR_BODY+NBT_HDR_SIZE);	req->in.dynamic 	= NULL;	req->seqnum		= UINT64_MAX;	smb2srv_setup_bufinfo(req);	SIVAL(req->in.hdr, 0,				SMB2_MAGIC);	SSVAL(req->in.hdr, SMB2_HDR_LENGTH,		SMB2_HDR_BODY);	SSVAL(req->in.hdr, SMB2_HDR_EPOCH,		0);	SIVAL(req->in.hdr, SMB2_HDR_STATUS,		0);	SSVAL(req->in.hdr, SMB2_HDR_OPCODE,		SMB2_OP_BREAK);	SSVAL(req->in.hdr, SMB2_HDR_CREDIT,		0);	SIVAL(req->in.hdr, SMB2_HDR_FLAGS,		0);	SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,	0);	SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,		0);	SIVAL(req->in.hdr, SMB2_HDR_PID,		0);	SIVAL(req->in.hdr, SMB2_HDR_TID,		0);	SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,		0);	memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);	SSVAL(req->in.body, 0, 2);	status = smb2srv_setup_reply(req, 0x18, false, 0);	NT_STATUS_NOT_OK_RETURN(status);	SSVAL(req->out.hdr, SMB2_HDR_CREDIT,	0x0000);	SSVAL(req->out.body, 0x02, 0x0001);	SIVAL(req->out.body, 0x04, 0x00000000);	smb2srv_push_handle(req->out.body, 0x08, h);	smb2srv_send_reply(req);	return NT_STATUS_OK;}struct ntvfs_handle *smb2srv_pull_handle(struct smb2srv_request *req, const uint8_t *base, uint_t offset){	struct smbsrv_tcon *tcon;	struct smbsrv_handle *handle;	uint32_t hid;	uint32_t tid;	uint64_t uid;	/*	 * if there're chained requests used the cached handle	 *	 * TODO: check if this also correct when the given handle	 *       isn't all 0xFF.	 */	if (req->chained_file_handle) {		base = req->chained_file_handle;		offset = 0;	}	hid = IVAL(base, offset);	tid = IVAL(base, offset + 4);	uid = BVAL(base, offset + 8);	/* if it's the wildcard handle, don't waste time to search it... */	if (hid == UINT32_MAX && tid == UINT32_MAX && uid == UINT64_MAX) {		return NULL;	}	/*	 * if the (v)uid part doesn't match the given session the handle isn't	 * valid	 */	if (uid != req->session->vuid) {		return NULL;	}	/*	 * the handle can belong to a different tcon	 * as that TID in the SMB2 header says, but	 * the request should succeed nevertheless!	 *	 * because of this we put the 32 bit TID into the	 * 128 bit handle, so that we can extract the tcon from the	 * handle	 */	tcon = req->tcon;	if (tid != req->tcon->tid) {		tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);		if (!tcon) {			return NULL;		}	}	handle = smbsrv_smb2_handle_find(tcon, hid, req->request_time);	if (!handle) {		return NULL;	}	/*	 * as the smb2srv_tcon is a child object of the smb2srv_session	 * the handle belongs to the correct session!	 *	 * Note: no check is needed here for SMB2	 */	/*	 * as the handle may have overwritten the tcon	 * we need to set it on the request so that the	 * correct ntvfs context will be used for the ntvfs_*() request	 *	 * TODO: check if that's correct for chained requests as well!	 */	req->tcon = tcon;	return handle->ntvfs;}void smb2srv_push_handle(uint8_t *base, uint_t offset, struct ntvfs_handle *ntvfs){	struct smbsrv_handle *handle = talloc_get_type(ntvfs->frontend_data.private_data,				       struct smbsrv_handle);	/* 	 * the handle is 128 bit on the wire	 */	SIVAL(base, offset,	handle->hid);	SIVAL(base, offset + 4,	handle->tcon->tid);	SBVAL(base, offset + 8,	handle->session->vuid);}static NTSTATUS smb2srv_handle_create_new(void *private_data, struct ntvfs_request *ntvfs, struct ntvfs_handle **_h){	struct smb2srv_request *req = talloc_get_type(ntvfs->frontend_data.private_data,				      struct smb2srv_request);	struct smbsrv_handle *handle;	struct ntvfs_handle *h;	handle = smbsrv_handle_new(req->session, req->tcon, req, req->request_time);	if (!handle) return NT_STATUS_INSUFFICIENT_RESOURCES;	h = talloc_zero(handle, struct ntvfs_handle);	if (!h) goto nomem;	/* 	 * note: we don't set handle->ntvfs yet,	 *       this will be done by smbsrv_handle_make_valid()	 *       this makes sure the handle is invalid for clients	 *       until the ntvfs subsystem has made it valid	 */	h->ctx		= ntvfs->ctx;	h->session_info	= ntvfs->session_info;	h->smbpid	= ntvfs->smbpid;	h->frontend_data.private_data = handle;	*_h = h;	return NT_STATUS_OK;nomem:	talloc_free(handle);	return NT_STATUS_NO_MEMORY;}static NTSTATUS smb2srv_handle_make_valid(void *private_data, struct ntvfs_handle *h){	struct smbsrv_tcon *tcon = talloc_get_type(private_data, struct smbsrv_tcon);	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,						       struct smbsrv_handle);	/* this tells the frontend that the handle is valid */	handle->ntvfs = h;	/* this moves the smbsrv_request to the smbsrv_tcon memory context */	talloc_steal(tcon, handle);	return NT_STATUS_OK;}static void smb2srv_handle_destroy(void *private_data, struct ntvfs_handle *h){	struct smbsrv_handle *handle = talloc_get_type(h->frontend_data.private_data,						       struct smbsrv_handle);	talloc_free(handle);}static struct ntvfs_handle *smb2srv_handle_search_by_wire_key(void *private_data, struct ntvfs_request *ntvfs, const DATA_BLOB *key){	return NULL;}static DATA_BLOB smb2srv_handle_get_wire_key(void *private_data, struct ntvfs_handle *handle, TALLOC_CTX *mem_ctx){	return data_blob(NULL, 0);}static NTSTATUS smb2srv_tcon_backend(struct smb2srv_request *req, union smb_tcon *io){	struct smbsrv_tcon *tcon;	NTSTATUS status;	enum ntvfs_type type;	const char *service = io->smb2.in.path;	struct share_config *scfg;	const char *sharetype;	uint64_t ntvfs_caps = 0;	if (strncmp(service, "\\\\", 2) == 0) {		const char *p = strchr(service+2, '\\');		if (p) {			service = p + 1;		}	}	status = share_get_config(req, req->smb_conn->share_context, service, &scfg);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0,("smb2srv_tcon_backend: couldn't find service %s\n", service));		return NT_STATUS_BAD_NETWORK_NAME;	}	if (!socket_check_access(req->smb_conn->connection->socket, 				 scfg->name, 				 share_string_list_option(req, scfg, SHARE_HOSTS_ALLOW), 				 share_string_list_option(req, scfg, SHARE_HOSTS_DENY))) {		return NT_STATUS_ACCESS_DENIED;	}	/* work out what sort of connection this is */	sharetype = share_string_option(scfg, SHARE_TYPE, "DISK");	if (sharetype && strcmp(sharetype, "IPC") == 0) {		type = NTVFS_IPC;	} else if (sharetype && strcmp(sharetype, "PRINTER") == 0) {		type = NTVFS_PRINT;	} else {		type = NTVFS_DISK;	}	tcon = smbsrv_smb2_tcon_new(req->session, scfg->name);	if (!tcon) {		DEBUG(0,("smb2srv_tcon_backend: Couldn't find free connection.\n"));		return NT_STATUS_INSUFFICIENT_RESOURCES;	}	req->tcon = tcon;	ntvfs_caps = NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS;	/* init ntvfs function pointers */	status = ntvfs_init_connection(tcon, scfg, type,				       req->smb_conn->negotiate.protocol,				       ntvfs_caps,				       req->smb_conn->connection->event.ctx,				       req->smb_conn->connection->msg_ctx,				       req->smb_conn->lp_ctx,				       req->smb_conn->connection->server_id,				       &tcon->ntvfs);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0, ("smb2srv_tcon_backend: ntvfs_init_connection failed for service %s\n", 			  scfg->name));		goto failed;	}	status = ntvfs_set_oplock_handler(tcon->ntvfs, smb2srv_send_oplock_break, tcon);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the oplock handler!\n"));		goto failed;	}	status = ntvfs_set_addr_callbacks(tcon->ntvfs, smbsrv_get_my_addr, smbsrv_get_peer_addr, req->smb_conn);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the addr callbacks!\n"));		goto failed;	}	status = ntvfs_set_handle_callbacks(tcon->ntvfs,					    smb2srv_handle_create_new,					    smb2srv_handle_make_valid,					    smb2srv_handle_destroy,					    smb2srv_handle_search_by_wire_key,					    smb2srv_handle_get_wire_key,					    tcon);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0,("smb2srv_tcon_backend: NTVFS failed to set the handle callbacks!\n"));		goto failed;	}	req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req,					  req->session->session_info,					  0, /* TODO: fill in PID */					  req->request_time,					  req, NULL, 0);	if (!req->ntvfs) {		status = NT_STATUS_NO_MEMORY;		goto failed;	}	/* Invoke NTVFS connection hook */	status = ntvfs_connect(req->ntvfs, scfg->name);	if (!NT_STATUS_IS_OK(status)) {		DEBUG(0,("smb2srv_tcon_backend: NTVFS ntvfs_connect() failed!\n"));		goto failed;	}	io->smb2.out.share_type	  = (unsigned)type; /* 1 - DISK, 2 - Print, 3 - IPC */	io->smb2.out.reserved	  = 0;	io->smb2.out.flags	  = 0x00000000;	io->smb2.out.capabilities = 0;	io->smb2.out.access_mask  = SEC_RIGHTS_FILE_ALL;	io->smb2.out.tid	= tcon->tid;	return NT_STATUS_OK;failed:	req->tcon = NULL;	talloc_free(tcon);	return status;}static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io){	uint16_t credit;	if (!NT_STATUS_IS_OK(req->status)) {		smb2srv_send_error(req, req->status);		return;	}	if (io->smb2.out.share_type == NTVFS_IPC) {		/* if it's an IPC share vista returns 0x0005 */		credit = 0x0005;	} else {		credit = 0x0001;	}	SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, false, 0));	SIVAL(req->out.hdr,	SMB2_HDR_TID,	io->smb2.out.tid);	SSVAL(req->out.hdr,	SMB2_HDR_CREDIT,credit);	SCVAL(req->out.body,	0x02,		io->smb2.out.share_type);	SCVAL(req->out.body,	0x03,		io->smb2.out.reserved);	SIVAL(req->out.body,	0x04,		io->smb2.out.flags);	SIVAL(req->out.body,	0x08,		io->smb2.out.capabilities);	SIVAL(req->out.body,	0x0C,		io->smb2.out.access_mask);	smb2srv_send_reply(req);}void smb2srv_tcon_recv(struct smb2srv_request *req){	union smb_tcon *io;	SMB2SRV_CHECK_BODY_SIZE(req, 0x08, true);	SMB2SRV_TALLOC_IO_PTR(io, union smb_tcon);	io->smb2.level		= RAW_TCON_SMB2;	io->smb2.in.reserved	= SVAL(req->in.body, 0x02);	SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x04, &io->smb2.in.path));	/* the VFS backend does not yet handle NULL paths */	if (io->smb2.in.path == NULL) {		io->smb2.in.path = "";	}	req->status = smb2srv_tcon_backend(req, io);	if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {		talloc_free(req);		return;	}	smb2srv_tcon_send(req, io);}static NTSTATUS smb2srv_tdis_backend(struct smb2srv_request *req){	/* TODO: call ntvfs backends to close file of this tcon */	talloc_free(req->tcon);	req->tcon = NULL;	return NT_STATUS_OK;}static void smb2srv_tdis_send(struct smb2srv_request *req){	NTSTATUS status;	if (NT_STATUS_IS_ERR(req->status)) {		smb2srv_send_error(req, req->status);		return;	}	status = smb2srv_setup_reply(req, 0x04, false, 0);	if (!NT_STATUS_IS_OK(status)) {		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));		talloc_free(req);		return;	}	SSVAL(req->out.body, 0x02, 0);	smb2srv_send_reply(req);}void smb2srv_tdis_recv(struct smb2srv_request *req){	uint16_t _pad;	SMB2SRV_CHECK_BODY_SIZE(req, 0x04, false);	_pad	= SVAL(req->in.body, 0x02);	req->status = smb2srv_tdis_backend(req);	if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {		talloc_free(req);		return;	}	smb2srv_tdis_send(req);}

⌨️ 快捷键说明

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