diff options
Diffstat (limited to 'fs/smb/server/smb2ops.c')
| -rw-r--r-- | fs/smb/server/smb2ops.c | 320 | 
1 files changed, 320 insertions, 0 deletions
diff --git a/fs/smb/server/smb2ops.c b/fs/smb/server/smb2ops.c new file mode 100644 index 000000000000..aed7704a0672 --- /dev/null +++ b/fs/smb/server/smb2ops.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> + *   Copyright (C) 2018 Samsung Electronics Co., Ltd. + */ + +#include <linux/slab.h> +#include "glob.h" + +#include "auth.h" +#include "connection.h" +#include "smb_common.h" +#include "server.h" + +static struct smb_version_values smb21_server_values = { +	.version_string = SMB21_VERSION_STRING, +	.protocol_id = SMB21_PROT_ID, +	.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, +	.max_read_size = SMB21_DEFAULT_IOSIZE, +	.max_write_size = SMB21_DEFAULT_IOSIZE, +	.max_trans_size = SMB21_DEFAULT_IOSIZE, +	.max_credits = SMB2_MAX_CREDITS, +	.large_lock_type = 0, +	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, +	.shared_lock_type = SMB2_LOCKFLAG_SHARED, +	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, +	.header_size = sizeof(struct smb2_hdr), +	.max_header_size = MAX_SMB2_HDR_SIZE, +	.read_rsp_size = sizeof(struct smb2_read_rsp), +	.lock_cmd = SMB2_LOCK, +	.cap_unix = 0, +	.cap_nt_find = SMB2_NT_FIND, +	.cap_large_files = SMB2_LARGE_FILES, +	.create_lease_size = sizeof(struct create_lease), +	.create_durable_size = sizeof(struct create_durable_rsp), +	.create_mxac_size = sizeof(struct create_mxac_rsp), +	.create_disk_id_size = sizeof(struct create_disk_id_rsp), +	.create_posix_size = sizeof(struct create_posix_rsp), +}; + +static struct smb_version_values smb30_server_values = { +	.version_string = SMB30_VERSION_STRING, +	.protocol_id = SMB30_PROT_ID, +	.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, +	.max_read_size = SMB3_DEFAULT_IOSIZE, +	.max_write_size = SMB3_DEFAULT_IOSIZE, +	.max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +	.max_credits = SMB2_MAX_CREDITS, +	.large_lock_type = 0, +	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, +	.shared_lock_type = SMB2_LOCKFLAG_SHARED, +	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, +	.header_size = sizeof(struct smb2_hdr), +	.max_header_size = MAX_SMB2_HDR_SIZE, +	.read_rsp_size = sizeof(struct smb2_read_rsp), +	.lock_cmd = SMB2_LOCK, +	.cap_unix = 0, +	.cap_nt_find = SMB2_NT_FIND, +	.cap_large_files = SMB2_LARGE_FILES, +	.create_lease_size = sizeof(struct create_lease_v2), +	.create_durable_size = sizeof(struct create_durable_rsp), +	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp), +	.create_mxac_size = sizeof(struct create_mxac_rsp), +	.create_disk_id_size = sizeof(struct create_disk_id_rsp), +	.create_posix_size = sizeof(struct create_posix_rsp), +}; + +static struct smb_version_values smb302_server_values = { +	.version_string = SMB302_VERSION_STRING, +	.protocol_id = SMB302_PROT_ID, +	.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, +	.max_read_size = SMB3_DEFAULT_IOSIZE, +	.max_write_size = SMB3_DEFAULT_IOSIZE, +	.max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +	.max_credits = SMB2_MAX_CREDITS, +	.large_lock_type = 0, +	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, +	.shared_lock_type = SMB2_LOCKFLAG_SHARED, +	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, +	.header_size = sizeof(struct smb2_hdr), +	.max_header_size = MAX_SMB2_HDR_SIZE, +	.read_rsp_size = sizeof(struct smb2_read_rsp), +	.lock_cmd = SMB2_LOCK, +	.cap_unix = 0, +	.cap_nt_find = SMB2_NT_FIND, +	.cap_large_files = SMB2_LARGE_FILES, +	.create_lease_size = sizeof(struct create_lease_v2), +	.create_durable_size = sizeof(struct create_durable_rsp), +	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp), +	.create_mxac_size = sizeof(struct create_mxac_rsp), +	.create_disk_id_size = sizeof(struct create_disk_id_rsp), +	.create_posix_size = sizeof(struct create_posix_rsp), +}; + +static struct smb_version_values smb311_server_values = { +	.version_string = SMB311_VERSION_STRING, +	.protocol_id = SMB311_PROT_ID, +	.capabilities = SMB2_GLOBAL_CAP_LARGE_MTU, +	.max_read_size = SMB3_DEFAULT_IOSIZE, +	.max_write_size = SMB3_DEFAULT_IOSIZE, +	.max_trans_size = SMB3_DEFAULT_TRANS_SIZE, +	.max_credits = SMB2_MAX_CREDITS, +	.large_lock_type = 0, +	.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE, +	.shared_lock_type = SMB2_LOCKFLAG_SHARED, +	.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK, +	.header_size = sizeof(struct smb2_hdr), +	.max_header_size = MAX_SMB2_HDR_SIZE, +	.read_rsp_size = sizeof(struct smb2_read_rsp), +	.lock_cmd = SMB2_LOCK, +	.cap_unix = 0, +	.cap_nt_find = SMB2_NT_FIND, +	.cap_large_files = SMB2_LARGE_FILES, +	.create_lease_size = sizeof(struct create_lease_v2), +	.create_durable_size = sizeof(struct create_durable_rsp), +	.create_durable_v2_size = sizeof(struct create_durable_v2_rsp), +	.create_mxac_size = sizeof(struct create_mxac_rsp), +	.create_disk_id_size = sizeof(struct create_disk_id_rsp), +	.create_posix_size = sizeof(struct create_posix_rsp), +}; + +static struct smb_version_ops smb2_0_server_ops = { +	.get_cmd_val		=	get_smb2_cmd_val, +	.init_rsp_hdr		=	init_smb2_rsp_hdr, +	.set_rsp_status		=	set_smb2_rsp_status, +	.allocate_rsp_buf       =       smb2_allocate_rsp_buf, +	.set_rsp_credits	=	smb2_set_rsp_credits, +	.check_user_session	=	smb2_check_user_session, +	.get_ksmbd_tcon		=	smb2_get_ksmbd_tcon, +	.is_sign_req		=	smb2_is_sign_req, +	.check_sign_req		=	smb2_check_sign_req, +	.set_sign_rsp		=	smb2_set_sign_rsp +}; + +static struct smb_version_ops smb3_0_server_ops = { +	.get_cmd_val		=	get_smb2_cmd_val, +	.init_rsp_hdr		=	init_smb2_rsp_hdr, +	.set_rsp_status		=	set_smb2_rsp_status, +	.allocate_rsp_buf       =       smb2_allocate_rsp_buf, +	.set_rsp_credits	=	smb2_set_rsp_credits, +	.check_user_session	=	smb2_check_user_session, +	.get_ksmbd_tcon		=	smb2_get_ksmbd_tcon, +	.is_sign_req		=	smb2_is_sign_req, +	.check_sign_req		=	smb3_check_sign_req, +	.set_sign_rsp		=	smb3_set_sign_rsp, +	.generate_signingkey	=	ksmbd_gen_smb30_signingkey, +	.generate_encryptionkey	=	ksmbd_gen_smb30_encryptionkey, +	.is_transform_hdr	=	smb3_is_transform_hdr, +	.decrypt_req		=	smb3_decrypt_req, +	.encrypt_resp		=	smb3_encrypt_resp +}; + +static struct smb_version_ops smb3_11_server_ops = { +	.get_cmd_val		=	get_smb2_cmd_val, +	.init_rsp_hdr		=	init_smb2_rsp_hdr, +	.set_rsp_status		=	set_smb2_rsp_status, +	.allocate_rsp_buf       =       smb2_allocate_rsp_buf, +	.set_rsp_credits	=	smb2_set_rsp_credits, +	.check_user_session	=	smb2_check_user_session, +	.get_ksmbd_tcon		=	smb2_get_ksmbd_tcon, +	.is_sign_req		=	smb2_is_sign_req, +	.check_sign_req		=	smb3_check_sign_req, +	.set_sign_rsp		=	smb3_set_sign_rsp, +	.generate_signingkey	=	ksmbd_gen_smb311_signingkey, +	.generate_encryptionkey	=	ksmbd_gen_smb311_encryptionkey, +	.is_transform_hdr	=	smb3_is_transform_hdr, +	.decrypt_req		=	smb3_decrypt_req, +	.encrypt_resp		=	smb3_encrypt_resp +}; + +static struct smb_version_cmds smb2_0_server_cmds[NUMBER_OF_SMB2_COMMANDS] = { +	[SMB2_NEGOTIATE_HE]	=	{ .proc = smb2_negotiate_request, }, +	[SMB2_SESSION_SETUP_HE] =	{ .proc = smb2_sess_setup, }, +	[SMB2_TREE_CONNECT_HE]  =	{ .proc = smb2_tree_connect,}, +	[SMB2_TREE_DISCONNECT_HE]  =	{ .proc = smb2_tree_disconnect,}, +	[SMB2_LOGOFF_HE]	=	{ .proc = smb2_session_logoff,}, +	[SMB2_CREATE_HE]	=	{ .proc = smb2_open}, +	[SMB2_QUERY_INFO_HE]	=	{ .proc = smb2_query_info}, +	[SMB2_QUERY_DIRECTORY_HE] =	{ .proc = smb2_query_dir}, +	[SMB2_CLOSE_HE]		=	{ .proc = smb2_close}, +	[SMB2_ECHO_HE]		=	{ .proc = smb2_echo}, +	[SMB2_SET_INFO_HE]      =       { .proc = smb2_set_info}, +	[SMB2_READ_HE]		=	{ .proc = smb2_read}, +	[SMB2_WRITE_HE]		=	{ .proc = smb2_write}, +	[SMB2_FLUSH_HE]		=	{ .proc = smb2_flush}, +	[SMB2_CANCEL_HE]	=	{ .proc = smb2_cancel}, +	[SMB2_LOCK_HE]		=	{ .proc = smb2_lock}, +	[SMB2_IOCTL_HE]		=	{ .proc = smb2_ioctl}, +	[SMB2_OPLOCK_BREAK_HE]	=	{ .proc = smb2_oplock_break}, +	[SMB2_CHANGE_NOTIFY_HE]	=	{ .proc = smb2_notify}, +}; + +/** + * init_smb2_1_server() - initialize a smb server connection with smb2.1 + *			command dispatcher + * @conn:	connection instance + */ +void init_smb2_1_server(struct ksmbd_conn *conn) +{ +	conn->vals = &smb21_server_values; +	conn->ops = &smb2_0_server_ops; +	conn->cmds = smb2_0_server_cmds; +	conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); +	conn->signing_algorithm = SIGNING_ALG_HMAC_SHA256_LE; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; +} + +/** + * init_smb3_0_server() - initialize a smb server connection with smb3.0 + *			command dispatcher + * @conn:	connection instance + */ +void init_smb3_0_server(struct ksmbd_conn *conn) +{ +	conn->vals = &smb30_server_values; +	conn->ops = &smb3_0_server_ops; +	conn->cmds = smb2_0_server_cmds; +	conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); +	conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION && +	    conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; +} + +/** + * init_smb3_02_server() - initialize a smb server connection with smb3.02 + *			command dispatcher + * @conn:	connection instance + */ +void init_smb3_02_server(struct ksmbd_conn *conn) +{ +	conn->vals = &smb302_server_values; +	conn->ops = &smb3_0_server_ops; +	conn->cmds = smb2_0_server_cmds; +	conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); +	conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || +	    (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && +	     conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; +} + +/** + * init_smb3_11_server() - initialize a smb server connection with smb3.11 + *			command dispatcher + * @conn:	connection instance + */ +int init_smb3_11_server(struct ksmbd_conn *conn) +{ +	conn->vals = &smb311_server_values; +	conn->ops = &smb3_11_server_ops; +	conn->cmds = smb2_0_server_cmds; +	conn->max_cmds = ARRAY_SIZE(smb2_0_server_cmds); +	conn->signing_algorithm = SIGNING_ALG_AES_CMAC_LE; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_LEASES) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_LEASING; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION || +	    (!(server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION_OFF) && +	     conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION; + +	if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) +		conn->vals->capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL; + +	INIT_LIST_HEAD(&conn->preauth_sess_table); +	return 0; +} + +void init_smb2_max_read_size(unsigned int sz) +{ +	sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); +	smb21_server_values.max_read_size = sz; +	smb30_server_values.max_read_size = sz; +	smb302_server_values.max_read_size = sz; +	smb311_server_values.max_read_size = sz; +} + +void init_smb2_max_write_size(unsigned int sz) +{ +	sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); +	smb21_server_values.max_write_size = sz; +	smb30_server_values.max_write_size = sz; +	smb302_server_values.max_write_size = sz; +	smb311_server_values.max_write_size = sz; +} + +void init_smb2_max_trans_size(unsigned int sz) +{ +	sz = clamp_val(sz, SMB3_MIN_IOSIZE, SMB3_MAX_IOSIZE); +	smb21_server_values.max_trans_size = sz; +	smb30_server_values.max_trans_size = sz; +	smb302_server_values.max_trans_size = sz; +	smb311_server_values.max_trans_size = sz; +} + +void init_smb2_max_credits(unsigned int sz) +{ +	smb21_server_values.max_credits = sz; +	smb30_server_values.max_credits = sz; +	smb302_server_values.max_credits = sz; +	smb311_server_values.max_credits = sz; +}  | 
