mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 13:41:48 -04:00
This patch introduces a /proc filesystem interface to ksmbd, providing visibility into the internal state of the SMB server. This allows administrators and developers to monitor active connections, user sessions, and opened files in real-time without relying on external tools or heavy debugging. Key changes include: - Connection Monitoring (/proc/fs/ksmbd/clients): Displays a list of active network connections, including client IP addresses, SMB dialects, credits, and last active timestamps. - Session Management (/proc/fs/ksmbd/sessions/): Adds a global sessions file to list all authenticated users and their session IDs. - Creates individual session entries (e.g., /proc/fs/ksmbd/sessions/<id>) detailing capabilities (DFS, Multi-channel, etc.), signing/encryption algorithms, and connected tree shares. - File Tracking (/proc/fs/ksmbd/files): Shows all currently opened files across the server, including tree IDs, process IDs (PID), access modes (daccess/saccess), and oplock/lease states. - Statistics & Counters: Implements internal counters for global server metrics, such as the number of tree connections, total sessions, and processed read/write bytes. Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com> Signed-off-by: Bahubali B Gumaji <bahubali.bg@samsung.com> Signed-off-by: Sang-Soo Lee <constant.lee@samsung.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
334 lines
12 KiB
C
334 lines
12 KiB
C
// 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"
|
|
#include "stats.h"
|
|
|
|
static struct smb_version_values smb21_server_values = {
|
|
.version_string = SMB21_VERSION_STRING,
|
|
.protocol_id = SMB21_PROT_ID,
|
|
.req_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,
|
|
.req_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_rsp_v2),
|
|
.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,
|
|
.req_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_rsp_v2),
|
|
.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,
|
|
.req_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_rsp_v2),
|
|
.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,
|
|
.inc_reqs = ksmbd_counter_inc_reqs,
|
|
.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,
|
|
.inc_reqs = ksmbd_counter_inc_reqs,
|
|
.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,
|
|
.inc_reqs = ksmbd_counter_inc_reqs,
|
|
.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->req_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->req_capabilities |= SMB2_GLOBAL_CAP_LEASING |
|
|
SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB2_ENCRYPTION &&
|
|
conn->cli_cap & SMB2_GLOBAL_CAP_ENCRYPTION)
|
|
conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
|
|
|
|
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->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
|
|
conn->vals->req_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->req_capabilities |= SMB2_GLOBAL_CAP_LEASING |
|
|
SMB2_GLOBAL_CAP_DIRECTORY_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->req_capabilities |= SMB2_GLOBAL_CAP_ENCRYPTION;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
|
|
conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
|
|
conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
|
|
}
|
|
|
|
/**
|
|
* 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->req_capabilities |= SMB2_GLOBAL_CAP_LEASING |
|
|
SMB2_GLOBAL_CAP_DIRECTORY_LEASING;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL)
|
|
conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_MULTI_CHANNEL;
|
|
|
|
if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE)
|
|
conn->vals->req_capabilities |= SMB2_GLOBAL_CAP_PERSISTENT_HANDLES;
|
|
|
|
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;
|
|
}
|