linux/fs/smb/client/smb2pdu.c

// SPDX-License-Identifier: LGPL-2.1
/*
 *
 *   Copyright (C) International Business Machines  Corp., 2009, 2013
 *                 Etersoft, 2012
 *   Author(s): Steve French ([email protected])
 *              Pavel Shilovsky ([email protected]) 2012
 *
 *   Contains the routines for constructing the SMB2 PDUs themselves
 *
 */

 /* SMB2 PDU handling routines here - except for leftovers (eg session setup) */
 /* Note that there are handle based routines which must be		      */
 /* treated slightly differently for reconnection purposes since we never     */
 /* want to reuse a stale file handle and only the caller knows the file info */

#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/vfs.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/uaccess.h>
#include <linux/uuid.h>
#include <linux/pagemap.h>
#include <linux/xattr.h>
#include <linux/netfs.h>
#include <trace/events/netfs.h>
#include "cifsglob.h"
#include "cifsacl.h"
#include "cifsproto.h"
#include "smb2proto.h"
#include "cifs_unicode.h"
#include "cifs_debug.h"
#include "ntlmssp.h"
#include "smb2status.h"
#include "smb2glob.h"
#include "cifspdu.h"
#include "cifs_spnego.h"
#include "smbdirect.h"
#include "trace.h"
#ifdef CONFIG_CIFS_DFS_UPCALL
#include "dfs_cache.h"
#endif
#include "cached_dir.h"

/*
 *  The following table defines the expected "StructureSize" of SMB2 requests
 *  in order by SMB2 command.  This is similar to "wct" in SMB/CIFS requests.
 *
 *  Note that commands are defined in smb2pdu.h in le16 but the array below is
 *  indexed by command in host byte order.
 */
static const int smb2_req_struct_sizes[NUMBER_OF_SMB2_COMMANDS] =;

int smb3_encryption_required(const struct cifs_tcon *tcon)
{}

static void
smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
		  const struct cifs_tcon *tcon,
		  struct TCP_Server_Info *server)
{}

/* helper function for code reuse */
static int
cifs_chan_skip_or_disable(struct cifs_ses *ses,
			  struct TCP_Server_Info *server,
			  bool from_reconnect)
{}

static int
smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
	       struct TCP_Server_Info *server, bool from_reconnect)
{}

static void
fill_small_buf(__le16 smb2_command, struct cifs_tcon *tcon,
	       struct TCP_Server_Info *server,
	       void *buf,
	       unsigned int *total_len)
{}

/*
 * Allocate and return pointer to an SMB request hdr, and set basic
 * SMB information in the SMB header. If the return code is zero, this
 * function must have filled in request_buf pointer.
 */
static int __smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
				 struct TCP_Server_Info *server,
				 void **request_buf, unsigned int *total_len)
{}

static int smb2_plain_req_init(__le16 smb2_command, struct cifs_tcon *tcon,
			       struct TCP_Server_Info *server,
			       void **request_buf, unsigned int *total_len)
{}

static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
			       struct TCP_Server_Info *server,
			       void **request_buf, unsigned int *total_len)
{}

/* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */

static void
build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt)
{}

static void
build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_ctxt)
{}

static unsigned int
build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt)
{}

static void
build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt)
{}

static unsigned int
build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostname)
{}

static void
build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt)
{}

static void
assemble_neg_contexts(struct smb2_negotiate_req *req,
		      struct TCP_Server_Info *server, unsigned int *total_len)
{}

/* If invalid preauth context warn but use what we requested, SHA-512 */
static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt)
{}

static void decode_compress_ctx(struct TCP_Server_Info *server,
			 struct smb2_compression_capabilities_context *ctxt)
{}

static int decode_encrypt_ctx(struct TCP_Server_Info *server,
			      struct smb2_encryption_neg_context *ctxt)
{}

static void decode_signing_ctx(struct TCP_Server_Info *server,
			       struct smb2_signing_capabilities *pctxt)
{}


static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp,
				     struct TCP_Server_Info *server,
				     unsigned int len_of_smb)
{}

static struct create_posix *
create_posix_buf(umode_t mode)
{}

static int
add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
{}


/*
 *
 *	SMB2 Worker functions follow:
 *
 *	The general structure of the worker functions is:
 *	1) Call smb2_init (assembles SMB2 header)
 *	2) Initialize SMB2 command specific fields in fixed length area of SMB
 *	3) Call smb_sendrcv2 (sends request on socket and waits for response)
 *	4) Decode SMB2 command specific fields in the fixed length area
 *	5) Decode variable length data area (if any for this SMB2 command type)
 *	6) Call free smb buffer
 *	7) return
 *
 */

int
SMB2_negotiate(const unsigned int xid,
	       struct cifs_ses *ses,
	       struct TCP_Server_Info *server)
{}

int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
{}

enum securityEnum
smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
{}

struct SMB2_sess_data {};

static int
SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
{}

static void
SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data)
{}

static int
SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
{}

static int
SMB2_sess_establish_session(struct SMB2_sess_data *sess_data)
{}

#ifdef CONFIG_CIFS_UPCALL
static void
SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
{}
#else
static void
SMB2_auth_kerberos(struct SMB2_sess_data *sess_data)
{
	cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
	sess_data->result = -EOPNOTSUPP;
	sess_data->func = NULL;
}
#endif

static void
SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data);

static void
SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data)
{}

static void
SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data)
{}

static int
SMB2_select_sec(struct SMB2_sess_data *sess_data)
{}

int
SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
		struct TCP_Server_Info *server,
		const struct nls_table *nls_cp)
{}

int
SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
{}

static inline void cifs_stats_fail_inc(struct cifs_tcon *tcon, uint16_t code)
{}

#define MAX_SHARENAME_LENGTH

/* These are similar values to what Windows uses */
static inline void init_copy_chunk_defaults(struct cifs_tcon *tcon)
{}

int
SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
	  struct cifs_tcon *tcon, const struct nls_table *cp)
{}

int
SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
{}


static struct create_durable *
create_durable_buf(void)
{}

static struct create_durable *
create_reconnect_durable_buf(struct cifs_fid *fid)
{}

static void
parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
{}

static void
parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info,
		 struct create_posix_rsp *posix)
{}

int smb2_parse_contexts(struct TCP_Server_Info *server,
			struct kvec *rsp_iov,
			unsigned int *epoch,
			char *lease_key, __u8 *oplock,
			struct smb2_file_all_info *buf,
			struct create_posix_rsp *posix)
{}

static int
add_lease_context(struct TCP_Server_Info *server,
		  struct smb2_create_req *req,
		  struct kvec *iov,
		  unsigned int *num_iovec, u8 *lease_key, __u8 *oplock)
{}

static struct create_durable_v2 *
create_durable_v2_buf(struct cifs_open_parms *oparms)
{}

static struct create_durable_handle_reconnect_v2 *
create_reconnect_durable_v2_buf(struct cifs_fid *fid)
{}

static int
add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
		    struct cifs_open_parms *oparms)
{}

static int
add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
		    struct cifs_open_parms *oparms)
{}

static int
add_durable_context(struct kvec *iov, unsigned int *num_iovec,
		    struct cifs_open_parms *oparms, bool use_persistent)
{}

/* See MS-SMB2 2.2.13.2.7 */
static struct crt_twarp_ctxt *
create_twarp_buf(__u64 timewarp)
{}

/* See MS-SMB2 2.2.13.2.7 */
static int
add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
{}

/* See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx */
static void setup_owner_group_sids(char *buf)
{}

/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
static struct crt_sd_ctxt *
create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
{}

static int
add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bool set_owner)
{}

static struct crt_query_id_ctxt *
create_query_id_buf(void)
{}

/* See MS-SMB2 2.2.13.2.9 */
static int
add_query_id_context(struct kvec *iov, unsigned int *num_iovec)
{}

static void add_ea_context(struct cifs_open_parms *oparms,
			   struct kvec *rq_iov, unsigned int *num_iovs)
{}

static int
alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
			    const char *treename, const __le16 *path)
{}

int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
			       umode_t mode, struct cifs_tcon *tcon,
			       const char *full_path,
			       struct cifs_sb_info *cifs_sb)
{}

int
SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
	       struct smb_rqst *rqst, __u8 *oplock,
	       struct cifs_open_parms *oparms, __le16 *path)
{}

/* rq_iov[0] is the request and is released by cifs_small_buf_release().
 * All other vectors are freed by kfree().
 */
void
SMB2_open_free(struct smb_rqst *rqst)
{}

int
SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
	  __u8 *oplock, struct smb2_file_all_info *buf,
	  struct create_posix_rsp *posix,
	  struct kvec *err_iov, int *buftype)
{}

int
SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		struct smb_rqst *rqst,
		u64 persistent_fid, u64 volatile_fid, u32 opcode,
		char *in_data, u32 indatalen,
		__u32 max_response_size)
{}

void
SMB2_ioctl_free(struct smb_rqst *rqst)
{}


/*
 *	SMB2 IOCTL is used for both IOCTLs and FSCTLs
 */
int
SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
	   u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen,
	   u32 max_out_data_len, char **out_data,
	   u32 *plen /* returned data len */)
{}

/*
 *   Individual callers to ioctl worker function follow
 */

int
SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
		     u64 persistent_fid, u64 volatile_fid)
{}

int
SMB2_close_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		struct smb_rqst *rqst,
		u64 persistent_fid, u64 volatile_fid, bool query_attrs)
{}

void
SMB2_close_free(struct smb_rqst *rqst)
{}

int
__SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
	     u64 persistent_fid, u64 volatile_fid,
	     struct smb2_file_network_open_info *pbuf)
{}

int
SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
		u64 persistent_fid, u64 volatile_fid)
{}

int
smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
		  struct kvec *iov, unsigned int min_buf_size)
{}

/*
 * If SMB buffer fields are valid, copy into temporary buffer to hold result.
 * Caller must free buffer.
 */
int
smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
			   struct kvec *iov, unsigned int minbufsize,
			   char *data)
{}

int
SMB2_query_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		     struct smb_rqst *rqst,
		     u64 persistent_fid, u64 volatile_fid,
		     u8 info_class, u8 info_type, u32 additional_info,
		     size_t output_len, size_t input_len, void *input)
{}

void
SMB2_query_info_free(struct smb_rqst *rqst)
{}

static int
query_info(const unsigned int xid, struct cifs_tcon *tcon,
	   u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type,
	   u32 additional_info, size_t output_len, size_t min_len, void **data,
		u32 *dlen)
{}

int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
	u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
{}

#if 0
/* currently unused, as now we are doing compounding instead (see smb311_posix_query_path_info) */
int
SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
		u64 persistent_fid, u64 volatile_fid, struct smb311_posix_qinfo *data, u32 *plen)
{
	size_t output_len = sizeof(struct smb311_posix_qinfo *) +
			(sizeof(struct cifs_sid) * 2) + (PATH_MAX * 2);
	*plen = 0;

	return query_info(xid, tcon, persistent_fid, volatile_fid,
			  SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0,
			  output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen);
	/* Note caller must free "data" (passed in above). It may be allocated in query_info call */
}
#endif

int
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
	       u64 persistent_fid, u64 volatile_fid,
	       void **data, u32 *plen, u32 extra_info)
{}

int
SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
		 u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
{}

/*
 * CHANGE_NOTIFY Request is sent to get notifications on changes to a directory
 * See MS-SMB2 2.2.35 and 2.2.36
 */

static int
SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
		 struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		 u64 persistent_fid, u64 volatile_fid,
		 u32 completion_filter, bool watch_tree)
{}

int
SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
		u64 persistent_fid, u64 volatile_fid, bool watch_tree,
		u32 completion_filter, u32 max_out_data_len, char **out_data,
		u32 *plen /* returned data len */)
{}



/*
 * This is a no-op for now. We're not really interested in the reply, but
 * rather in the fact that the server sent one and that server->lstrp
 * gets updated.
 *
 * FIXME: maybe we should consider checking that the reply matches request?
 */
static void
smb2_echo_callback(struct mid_q_entry *mid)
{}

void smb2_reconnect_server(struct work_struct *work)
{}

int
SMB2_echo(struct TCP_Server_Info *server)
{}

void
SMB2_flush_free(struct smb_rqst *rqst)
{}

int
SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
		struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		u64 persistent_fid, u64 volatile_fid)
{}

int
SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
	   u64 volatile_fid)
{}

#ifdef CONFIG_CIFS_SMB_DIRECT
static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms)
{}
#endif /* CONFIG_CIFS_SMB_DIRECT */

/*
 * To form a chain of read requests, any read requests after the first should
 * have the end_of_chain boolean set to true.
 */
static int
smb2_new_read_req(void **buf, unsigned int *total_len,
	struct cifs_io_parms *io_parms, struct cifs_io_subrequest *rdata,
	unsigned int remaining_bytes, int request_type)
{}

static void smb2_readv_worker(struct work_struct *work)
{}

static void
smb2_readv_callback(struct mid_q_entry *mid)
{}

/* smb2_async_readv - send an async read, and set up mid to handle result */
int
smb2_async_readv(struct cifs_io_subrequest *rdata)
{}

int
SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
	  unsigned int *nbytes, char **buf, int *buf_type)
{}

/*
 * Check the mid_state and signature on received buffer (if any), and queue the
 * workqueue completion task.
 */
static void
smb2_writev_callback(struct mid_q_entry *mid)
{}

/* smb2_async_writev - send an async write, and set up mid to handle result */
void
smb2_async_writev(struct cifs_io_subrequest *wdata)
{}

/*
 * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
 * The length field from io_parms must be at least 1 and indicates a number of
 * elements with data to write that begins with position 1 in iov array. All
 * data length is specified by count.
 */
int
SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
	   unsigned int *nbytes, struct kvec *iov, int n_vec)
{}

int posix_info_sid_size(const void *beg, const void *end)
{}

int posix_info_parse(const void *beg, const void *end,
		     struct smb2_posix_info_parsed *out)

{}

static int posix_info_extra_size(const void *beg, const void *end)
{}

static unsigned int
num_entries(int infotype, char *bufstart, char *end_of_buf, char **lastentry,
	    size_t size)
{}

/*
 * Readdir/FindFirst
 */
int SMB2_query_directory_init(const unsigned int xid,
			      struct cifs_tcon *tcon,
			      struct TCP_Server_Info *server,
			      struct smb_rqst *rqst,
			      u64 persistent_fid, u64 volatile_fid,
			      int index, int info_level)
{}

void SMB2_query_directory_free(struct smb_rqst *rqst)
{}

int
smb2_parse_query_directory(struct cifs_tcon *tcon,
			   struct kvec *rsp_iov,
			   int resp_buftype,
			   struct cifs_search_info *srch_inf)
{}

int
SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
		     u64 persistent_fid, u64 volatile_fid, int index,
		     struct cifs_search_info *srch_inf)
{}

int
SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
		   struct smb_rqst *rqst,
		   u64 persistent_fid, u64 volatile_fid, u32 pid,
		   u8 info_class, u8 info_type, u32 additional_info,
		   void **data, unsigned int *size)
{}

void
SMB2_set_info_free(struct smb_rqst *rqst)
{}

static int
send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
	       u64 persistent_fid, u64 volatile_fid, u32 pid, u8 info_class,
	       u8 info_type, u32 additional_info, unsigned int num,
		void **data, unsigned int *size)
{}

int
SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
	     u64 volatile_fid, u32 pid, loff_t new_eof)
{}

int
SMB2_set_acl(const unsigned int xid, struct cifs_tcon *tcon,
		u64 persistent_fid, u64 volatile_fid,
		struct cifs_ntsd *pnntsd, int pacllen, int aclflag)
{}

int
SMB2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
	    u64 persistent_fid, u64 volatile_fid,
	    struct smb2_file_full_ea_info *buf, int len)
{}

int
SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
		  const u64 persistent_fid, const u64 volatile_fid,
		  __u8 oplock_level)
{}

void
smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
			     struct kstatfs *kst)
{}

static void
copy_posix_fs_info_to_kstatfs(FILE_SYSTEM_POSIX_INFO *response_data,
			struct kstatfs *kst)
{}

static int
build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon,
		   struct TCP_Server_Info *server,
		   int level, int outbuf_len, u64 persistent_fid,
		   u64 volatile_fid)
{}

static inline void free_qfs_info_req(struct kvec *iov)
{}

int
SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon,
	      u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
{}

int
SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
	      u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
{}

int
SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon,
	      u64 persistent_fid, u64 volatile_fid, int level)
{}

int
smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon,
	   const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
	   const __u32 num_lock, struct smb2_lock_element *buf)
{}

int
SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon,
	  const __u64 persist_fid, const __u64 volatile_fid, const __u32 pid,
	  const __u64 length, const __u64 offset, const __u32 lock_flags,
	  const bool wait)
{}

int
SMB2_lease_break(const unsigned int xid, struct cifs_tcon *tcon,
		 __u8 *lease_key, const __le32 lease_state)
{}