169783Smsmith// SPDX-License-Identifier: GPL-2.0-or-later 269783Smsmith/* 369783Smsmith * Copyright (C) 2018 Samsung Electronics Co., Ltd. 469783Smsmith */ 569783Smsmith 669783Smsmith#include <linux/jhash.h> 769783Smsmith#include <linux/slab.h> 869783Smsmith#include <linux/rwsem.h> 969783Smsmith#include <linux/mutex.h> 1069783Smsmith#include <linux/wait.h> 1169783Smsmith#include <linux/hashtable.h> 1269783Smsmith#include <net/net_namespace.h> 1369783Smsmith#include <net/genetlink.h> 1469783Smsmith#include <linux/socket.h> 1569783Smsmith#include <linux/workqueue.h> 1669783Smsmith 1769783Smsmith#include "vfs_cache.h" 1869783Smsmith#include "transport_ipc.h" 1969783Smsmith#include "server.h" 2069783Smsmith#include "smb_common.h" 2169783Smsmith 2269783Smsmith#include "mgmt/user_config.h" 2369783Smsmith#include "mgmt/share_config.h" 2469783Smsmith#include "mgmt/user_session.h" 2569783Smsmith#include "mgmt/tree_connect.h" 2669783Smsmith#include "mgmt/ksmbd_ida.h" 2769783Smsmith#include "connection.h" 2869783Smsmith#include "transport_tcp.h" 2969783Smsmith#include "transport_rdma.h" 3069783Smsmith 31119418Sobrien#define IPC_WAIT_TIMEOUT (2 * HZ) 32119418Sobrien 33119418Sobrien#define IPC_MSG_HASH_BITS 3 3469783Smsmithstatic DEFINE_HASHTABLE(ipc_msg_table, IPC_MSG_HASH_BITS); 3569783Smsmithstatic DECLARE_RWSEM(ipc_msg_table_lock); 3669783Smsmithstatic DEFINE_MUTEX(startup_lock); 3769783Smsmith 3869783Smsmithstatic DEFINE_IDA(ipc_ida); 3969783Smsmith 4069783Smsmithstatic unsigned int ksmbd_tools_pid; 41129876Sphk 4269783Smsmithstatic bool ksmbd_ipc_validate_version(struct genl_info *m) 43107546Simp{ 44107546Simp if (m->genlhdr->version != KSMBD_GENL_VERSION) { 45106844Smdodd pr_err("%s. ksmbd: %d, kernel module: %d. %s.\n", 4669783Smsmith "Daemon and kernel module version mismatch", 4769783Smsmith m->genlhdr->version, 4869783Smsmith KSMBD_GENL_VERSION, 49119285Simp "User-space ksmbd should terminate"); 50119285Simp return false; 51119285Simp } 5269783Smsmith return true; 5369783Smsmith} 5469783Smsmith 55200341Sjkimstruct ksmbd_ipc_msg { 56200341Sjkim unsigned int type; 57200341Sjkim unsigned int sz; 58200341Sjkim unsigned char payload[]; 59200341Sjkim}; 60200341Sjkim 61200341Sjkimstruct ipc_msg_table_entry { 62200341Sjkim unsigned int handle; 63200341Sjkim unsigned int type; 6469783Smsmith wait_queue_head_t wait; 65200341Sjkim struct hlist_node ipc_table_hlist; 66200341Sjkim 6769783Smsmith void *response; 6869783Smsmith unsigned int msg_sz; 6969783Smsmith}; 7069783Smsmith 7169783Smsmithstatic struct delayed_work ipc_timer_work; 72145661Simp 7369783Smsmithstatic int handle_startup_event(struct sk_buff *skb, struct genl_info *info); 74200341Sjkimstatic int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info); 75200341Sjkimstatic int handle_generic_event(struct sk_buff *skb, struct genl_info *info); 7669783Smsmithstatic int ksmbd_ipc_heartbeat_request(void); 7769783Smsmith 7869783Smsmithstatic const struct nla_policy ksmbd_nl_policy[KSMBD_EVENT_MAX + 1] = { 7969783Smsmith [KSMBD_EVENT_UNSPEC] = { 8069783Smsmith .len = 0, 8169783Smsmith }, 8269783Smsmith [KSMBD_EVENT_HEARTBEAT_REQUEST] = { 8369783Smsmith .len = sizeof(struct ksmbd_heartbeat), 8469783Smsmith }, 8569783Smsmith [KSMBD_EVENT_STARTING_UP] = { 8669783Smsmith .len = sizeof(struct ksmbd_startup_request), 8769783Smsmith }, 8869783Smsmith [KSMBD_EVENT_SHUTTING_DOWN] = { 8969783Smsmith .len = sizeof(struct ksmbd_shutdown_request), 9069783Smsmith }, 9169783Smsmith [KSMBD_EVENT_LOGIN_REQUEST] = { 9269783Smsmith .len = sizeof(struct ksmbd_login_request), 93164264Sjhb }, 94164264Sjhb [KSMBD_EVENT_LOGIN_RESPONSE] = { 95164264Sjhb .len = sizeof(struct ksmbd_login_response), 96164264Sjhb }, 97169221Sjhb [KSMBD_EVENT_SHARE_CONFIG_REQUEST] = { 9869783Smsmith .len = sizeof(struct ksmbd_share_config_request), 9969783Smsmith }, 10069783Smsmith [KSMBD_EVENT_SHARE_CONFIG_RESPONSE] = { 10169783Smsmith .len = sizeof(struct ksmbd_share_config_response), 102154079Sjhb }, 10369783Smsmith [KSMBD_EVENT_TREE_CONNECT_REQUEST] = { 104154079Sjhb .len = sizeof(struct ksmbd_tree_connect_request), 10569783Smsmith }, 10669783Smsmith [KSMBD_EVENT_TREE_CONNECT_RESPONSE] = { 10769783Smsmith .len = sizeof(struct ksmbd_tree_connect_response), 108163805Simp }, 109163805Simp [KSMBD_EVENT_TREE_DISCONNECT_REQUEST] = { 110163805Simp .len = sizeof(struct ksmbd_tree_disconnect_request), 111163805Simp }, 112163805Simp [KSMBD_EVENT_LOGOUT_REQUEST] = { 113163805Simp .len = sizeof(struct ksmbd_logout_request), 114163805Simp }, 115163805Simp [KSMBD_EVENT_RPC_REQUEST] = { 116163805Simp }, 117163805Simp [KSMBD_EVENT_RPC_RESPONSE] = { 118163805Simp }, 119163805Simp [KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST] = { 120163805Simp }, 121163805Simp [KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE] = { 122163805Simp }, 123163805Simp}; 124163805Simp 125163805Simpstatic struct genl_ops ksmbd_genl_ops[] = { 126163805Simp { 127163805Simp .cmd = KSMBD_EVENT_UNSPEC, 128163805Simp .doit = handle_unsupported_event, 129163805Simp }, 130163805Simp { 131163805Simp .cmd = KSMBD_EVENT_HEARTBEAT_REQUEST, 132163805Simp .doit = handle_unsupported_event, 133163805Simp }, 134163805Simp { 135200341Sjkim .cmd = KSMBD_EVENT_STARTING_UP, 136200341Sjkim .doit = handle_startup_event, 137200341Sjkim }, 138200341Sjkim { 139200341Sjkim .cmd = KSMBD_EVENT_SHUTTING_DOWN, 140200341Sjkim .doit = handle_unsupported_event, 141200341Sjkim }, 142200341Sjkim { 143200341Sjkim .cmd = KSMBD_EVENT_LOGIN_REQUEST, 144200341Sjkim .doit = handle_unsupported_event, 145200341Sjkim }, 146200341Sjkim { 147200341Sjkim .cmd = KSMBD_EVENT_LOGIN_RESPONSE, 148200341Sjkim .doit = handle_generic_event, 149200341Sjkim }, 150200341Sjkim { 151200341Sjkim .cmd = KSMBD_EVENT_SHARE_CONFIG_REQUEST, 152200341Sjkim .doit = handle_unsupported_event, 153200341Sjkim }, 154200341Sjkim { 155200341Sjkim .cmd = KSMBD_EVENT_SHARE_CONFIG_RESPONSE, 156200341Sjkim .doit = handle_generic_event, 157200341Sjkim }, 158200341Sjkim { 159200341Sjkim .cmd = KSMBD_EVENT_TREE_CONNECT_REQUEST, 160200341Sjkim .doit = handle_unsupported_event, 161200341Sjkim }, 162200341Sjkim { 163200341Sjkim .cmd = KSMBD_EVENT_TREE_CONNECT_RESPONSE, 164200341Sjkim .doit = handle_generic_event, 165200341Sjkim }, 166200341Sjkim { 167200341Sjkim .cmd = KSMBD_EVENT_TREE_DISCONNECT_REQUEST, 168200341Sjkim .doit = handle_unsupported_event, 169200341Sjkim }, 170200341Sjkim { 171200341Sjkim .cmd = KSMBD_EVENT_LOGOUT_REQUEST, 172200341Sjkim .doit = handle_unsupported_event, 173200341Sjkim }, 174200341Sjkim { 175200341Sjkim .cmd = KSMBD_EVENT_RPC_REQUEST, 176200341Sjkim .doit = handle_unsupported_event, 177200341Sjkim }, 178200341Sjkim { 179200341Sjkim .cmd = KSMBD_EVENT_RPC_RESPONSE, 180200341Sjkim .doit = handle_generic_event, 181200341Sjkim }, 182200341Sjkim { 183200341Sjkim .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST, 184200341Sjkim .doit = handle_unsupported_event, 185200341Sjkim }, 186200341Sjkim { 187200341Sjkim .cmd = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE, 188200341Sjkim .doit = handle_generic_event, 189200341Sjkim }, 190200341Sjkim}; 191200341Sjkim 192200341Sjkimstatic struct genl_family ksmbd_genl_family = { 193200341Sjkim .name = KSMBD_GENL_NAME, 194200341Sjkim .version = KSMBD_GENL_VERSION, 195200341Sjkim .hdrsize = 0, 196200341Sjkim .maxattr = KSMBD_EVENT_MAX, 197200341Sjkim .netnsok = true, 198200341Sjkim .module = THIS_MODULE, 199200341Sjkim .ops = ksmbd_genl_ops, 200200341Sjkim .n_ops = ARRAY_SIZE(ksmbd_genl_ops), 201200341Sjkim .resv_start_op = KSMBD_EVENT_SPNEGO_AUTHEN_RESPONSE + 1, 202200341Sjkim}; 203200341Sjkim 204200341Sjkimstatic void ksmbd_nl_init_fixup(void) 205200341Sjkim{ 206200341Sjkim int i; 207200341Sjkim 208200341Sjkim for (i = 0; i < ARRAY_SIZE(ksmbd_genl_ops); i++) 209200341Sjkim ksmbd_genl_ops[i].validate = GENL_DONT_VALIDATE_STRICT | 210200341Sjkim GENL_DONT_VALIDATE_DUMP; 211200341Sjkim 212200341Sjkim ksmbd_genl_family.policy = ksmbd_nl_policy; 213200341Sjkim} 214200341Sjkim 215200341Sjkimstatic int rpc_context_flags(struct ksmbd_session *sess) 216200341Sjkim{ 217200341Sjkim if (user_guest(sess->user)) 218200341Sjkim return KSMBD_RPC_RESTRICTED_CONTEXT; 219200341Sjkim return 0; 220200341Sjkim} 221200341Sjkim 222200341Sjkimstatic void ipc_update_last_active(void) 223200341Sjkim{ 224200341Sjkim if (server_conf.ipc_timeout) 225200341Sjkim server_conf.ipc_last_active = jiffies; 226200341Sjkim} 227200341Sjkim 228200341Sjkimstatic struct ksmbd_ipc_msg *ipc_msg_alloc(size_t sz) 229200341Sjkim{ 230200341Sjkim struct ksmbd_ipc_msg *msg; 231200341Sjkim size_t msg_sz = sz + sizeof(struct ksmbd_ipc_msg); 232200341Sjkim 233200341Sjkim msg = kvzalloc(msg_sz, GFP_KERNEL); 234200341Sjkim if (msg) 235200341Sjkim msg->sz = sz; 236200341Sjkim return msg; 237200341Sjkim} 238200341Sjkim 239200341Sjkimstatic void ipc_msg_free(struct ksmbd_ipc_msg *msg) 240200341Sjkim{ 241200341Sjkim kvfree(msg); 242200341Sjkim} 243200341Sjkim 244200341Sjkimstatic void ipc_msg_handle_free(int handle) 245200341Sjkim{ 246200341Sjkim if (handle >= 0) 247200341Sjkim ksmbd_release_id(&ipc_ida, handle); 248200341Sjkim} 249200341Sjkim 250200341Sjkimstatic int handle_response(int type, void *payload, size_t sz) 251200341Sjkim{ 252200341Sjkim unsigned int handle = *(unsigned int *)payload; 253200341Sjkim struct ipc_msg_table_entry *entry; 254200341Sjkim int ret = 0; 255200341Sjkim 256200341Sjkim ipc_update_last_active(); 257200341Sjkim down_read(&ipc_msg_table_lock); 258200341Sjkim hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) { 259200341Sjkim if (handle != entry->handle) 260200341Sjkim continue; 261200341Sjkim 262200341Sjkim entry->response = NULL; 263200341Sjkim /* 264200341Sjkim * Response message type value should be equal to 265200341Sjkim * request message type + 1. 266200341Sjkim */ 267200341Sjkim if (entry->type + 1 != type) { 268200341Sjkim pr_err("Waiting for IPC type %d, got %d. Ignore.\n", 269200341Sjkim entry->type + 1, type); 270200341Sjkim } 271200341Sjkim 272200341Sjkim entry->response = kvzalloc(sz, GFP_KERNEL); 273200341Sjkim if (!entry->response) { 274200341Sjkim ret = -ENOMEM; 275200341Sjkim break; 276200341Sjkim } 277200341Sjkim 278200341Sjkim memcpy(entry->response, payload, sz); 279200341Sjkim entry->msg_sz = sz; 280200341Sjkim wake_up_interruptible(&entry->wait); 281200341Sjkim ret = 0; 282200341Sjkim break; 28369783Smsmith } 28469783Smsmith up_read(&ipc_msg_table_lock); 28569783Smsmith 28669783Smsmith return ret; 28769783Smsmith} 28869783Smsmith 28969783Smsmithstatic int ipc_server_config_on_startup(struct ksmbd_startup_request *req) 29069783Smsmith{ 29169783Smsmith int ret; 29269783Smsmith 29369783Smsmith ksmbd_set_fd_limit(req->file_max); 29469783Smsmith server_conf.flags = req->flags; 29569783Smsmith server_conf.signing = req->signing; 296102441Sjhb server_conf.tcp_port = req->tcp_port; 297102441Sjhb server_conf.ipc_timeout = req->ipc_timeout * HZ; 29869783Smsmith server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL; 29969783Smsmith server_conf.share_fake_fscaps = req->share_fake_fscaps; 300181789Simp ksmbd_init_domain(req->sub_auth); 301181789Simp 30269783Smsmith if (req->smb2_max_read) 30369783Smsmith init_smb2_max_read_size(req->smb2_max_read); 30469783Smsmith if (req->smb2_max_write) 30569783Smsmith init_smb2_max_write_size(req->smb2_max_write); 30669908Smsmith if (req->smb2_max_trans) 30769908Smsmith init_smb2_max_trans_size(req->smb2_max_trans); 30869908Smsmith if (req->smb2_max_credits) 309200341Sjkim init_smb2_max_credits(req->smb2_max_credits); 310200341Sjkim if (req->smbd_max_io_size) 311200341Sjkim init_smbd_max_io_size(req->smbd_max_io_size); 31269783Smsmith 31369908Smsmith if (req->max_connections) 314181789Simp server_conf.max_connections = req->max_connections; 315181789Simp 316181789Simp ret = ksmbd_set_netbios_name(req->netbios_name); 317181789Simp ret |= ksmbd_set_server_string(req->server_string); 318181789Simp ret |= ksmbd_set_work_group(req->work_group); 319182706Simp ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req), 320181789Simp req->ifc_list_sz); 321182706Simp if (ret) { 322181789Simp pr_err("Server configuration error: %s %s %s\n", 323182706Simp req->netbios_name, req->server_string, 324181789Simp req->work_group); 325182706Simp return ret; 326181789Simp } 327181789Simp 32869908Smsmith if (req->min_prot[0]) { 32969908Smsmith ret = ksmbd_lookup_protocol_idx(req->min_prot); 33069908Smsmith if (ret >= 0) 331124365Simp server_conf.min_protocol = ret; 33269908Smsmith } 333119266Simp if (req->max_prot[0]) { 33469908Smsmith ret = ksmbd_lookup_protocol_idx(req->max_prot); 33569908Smsmith if (ret >= 0) 33669908Smsmith server_conf.max_protocol = ret; 33769908Smsmith } 33869908Smsmith 33969908Smsmith if (server_conf.ipc_timeout) 340124365Simp schedule_delayed_work(&ipc_timer_work, server_conf.ipc_timeout); 34169908Smsmith return 0; 342124365Simp} 343124365Simp 344124365Simpstatic int handle_startup_event(struct sk_buff *skb, struct genl_info *info) 345124365Simp{ 346124365Simp int ret = 0; 347124365Simp 348124365Simp#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN 349124365Simp if (!netlink_capable(skb, CAP_NET_ADMIN)) 350124365Simp return -EPERM; 351124365Simp#endif 352124365Simp 35369908Smsmith if (!ksmbd_ipc_validate_version(info)) 354149521Sjkim return -EINVAL; 355149521Sjkim 356149521Sjkim if (!info->attrs[KSMBD_EVENT_STARTING_UP]) 357149521Sjkim return -EINVAL; 358149521Sjkim 359149521Sjkim mutex_lock(&startup_lock); 360157949Sjkim if (!ksmbd_server_configurable()) { 361149521Sjkim mutex_unlock(&startup_lock); 362157949Sjkim pr_err("Server reset is in progress, can't start daemon\n"); 363157949Sjkim return -EINVAL; 364149521Sjkim } 365157949Sjkim 366157949Sjkim if (ksmbd_tools_pid) { 367157949Sjkim if (ksmbd_ipc_heartbeat_request() == 0) { 368157949Sjkim ret = -EINVAL; 369157949Sjkim goto out; 370157949Sjkim } 371157949Sjkim 372157949Sjkim pr_err("Reconnect to a new user space daemon\n"); 373157949Sjkim } else { 374149521Sjkim struct ksmbd_startup_request *req; 375149521Sjkim 376149521Sjkim req = nla_data(info->attrs[info->genlhdr->cmd]); 377149521Sjkim ret = ipc_server_config_on_startup(req); 378149521Sjkim if (ret) 379149521Sjkim goto out; 38069908Smsmith server_queue_ctrl_init_work(); 38169908Smsmith } 382165995Sjhb 383165995Sjhb ksmbd_tools_pid = info->snd_portid; 384165995Sjhb ipc_update_last_active(); 385124365Simp 386124365Simpout: 387124365Simp mutex_unlock(&startup_lock); 388124365Simp return ret; 389124365Simp} 390124365Simp 391124365Simpstatic int handle_unsupported_event(struct sk_buff *skb, struct genl_info *info) 392124365Simp{ 393124365Simp pr_err("Unknown IPC event: %d, ignore.\n", info->genlhdr->cmd); 394168157Sjhb return -EINVAL; 395124365Simp} 396124365Simp 39769783Smsmithstatic int handle_generic_event(struct sk_buff *skb, struct genl_info *info) 398172394Smarius{ 39969783Smsmith void *payload; 40069783Smsmith int sz; 40169783Smsmith int type = info->genlhdr->cmd; 402163805Simp 403163805Simp#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN 404163805Simp if (!netlink_capable(skb, CAP_NET_ADMIN)) 405163805Simp return -EPERM; 406163805Simp#endif 407163805Simp 408163805Simp if (type > KSMBD_EVENT_MAX) { 409163805Simp WARN_ON(1); 410124365Simp return -EINVAL; 411124365Simp } 41269783Smsmith 41369783Smsmith if (!ksmbd_ipc_validate_version(info)) 41469783Smsmith return -EINVAL; 41569783Smsmith 416181798Simp if (!info->attrs[type]) 417181798Simp return -EINVAL; 418181798Simp 419181798Simp payload = nla_data(info->attrs[info->genlhdr->cmd]); 420181798Simp sz = nla_len(info->attrs[info->genlhdr->cmd]); 421181798Simp return handle_response(type, payload, sz); 42269783Smsmith} 42369783Smsmith 424181798Simpstatic int ipc_msg_send(struct ksmbd_ipc_msg *msg) 425181798Simp{ 42669783Smsmith struct genlmsghdr *nlh; 427102441Sjhb struct sk_buff *skb; 42869783Smsmith int ret = -EINVAL; 429103042Sjhb 430102441Sjhb if (!ksmbd_tools_pid) 431102441Sjhb return ret; 432102441Sjhb 433102441Sjhb skb = genlmsg_new(msg->sz, GFP_KERNEL); 434102441Sjhb if (!skb) 435102441Sjhb return -ENOMEM; 436102441Sjhb 43769783Smsmith nlh = genlmsg_put(skb, 0, 0, &ksmbd_genl_family, 0, msg->type); 438103016Sjhb if (!nlh) 43969783Smsmith goto out; 44069783Smsmith 441181798Simp ret = nla_put(skb, msg->type, msg->sz, msg->payload); 44269783Smsmith if (ret) { 44369783Smsmith genlmsg_cancel(skb, nlh); 44469783Smsmith goto out; 44569783Smsmith } 44669783Smsmith 447102441Sjhb genlmsg_end(skb, nlh); 448200341Sjkim ret = genlmsg_unicast(&init_net, skb, ksmbd_tools_pid); 449200341Sjkim if (!ret) 450200341Sjkim ipc_update_last_active(); 451200341Sjkim return ret; 452200341Sjkim 453200341Sjkimout: 454200341Sjkim nlmsg_free(skb); 455200341Sjkim return ret; 456200341Sjkim} 457200341Sjkim 458200341Sjkimstatic int ipc_validate_msg(struct ipc_msg_table_entry *entry) 459200341Sjkim{ 460200341Sjkim unsigned int msg_sz = entry->msg_sz; 461200341Sjkim 462200341Sjkim if (entry->type == KSMBD_EVENT_RPC_REQUEST) { 463200341Sjkim struct ksmbd_rpc_command *resp = entry->response; 464200341Sjkim 465200341Sjkim msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; 466200341Sjkim } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) { 467200341Sjkim struct ksmbd_spnego_authen_response *resp = entry->response; 468200341Sjkim 469200341Sjkim msg_sz = sizeof(struct ksmbd_spnego_authen_response) + 470200341Sjkim resp->session_key_len + resp->spnego_blob_len; 471200341Sjkim } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) { 472200341Sjkim struct ksmbd_share_config_response *resp = entry->response; 473200341Sjkim 474200341Sjkim if (resp->payload_sz) { 475200341Sjkim if (resp->payload_sz < resp->veto_list_sz) 476200341Sjkim return -EINVAL; 477200341Sjkim 478200341Sjkim msg_sz = sizeof(struct ksmbd_share_config_response) + 479200341Sjkim resp->payload_sz; 480200341Sjkim } 481200341Sjkim } 482200341Sjkim 48369783Smsmith return entry->msg_sz != msg_sz ? -EINVAL : 0; 48469783Smsmith} 48569783Smsmith 48669783Smsmithstatic void *ipc_msg_send_request(struct ksmbd_ipc_msg *msg, unsigned int handle) 48769783Smsmith{ 488172394Smarius struct ipc_msg_table_entry entry; 489172394Smarius int ret; 490172394Smarius 49169783Smsmith if ((int)handle < 0) 49269783Smsmith return NULL; 49369783Smsmith 49469783Smsmith entry.type = msg->type; 49569783Smsmith entry.response = NULL; 49669783Smsmith init_waitqueue_head(&entry.wait); 49769783Smsmith 498102441Sjhb down_write(&ipc_msg_table_lock); 49969783Smsmith entry.handle = handle; 50069783Smsmith hash_add(ipc_msg_table, &entry.ipc_table_hlist, entry.handle); 50169783Smsmith up_write(&ipc_msg_table_lock); 50269783Smsmith 50369783Smsmith ret = ipc_msg_send(msg); 504172394Smarius if (ret) 505172394Smarius goto out; 50669783Smsmith 50769783Smsmith ret = wait_event_interruptible_timeout(entry.wait, 508172394Smarius entry.response != NULL, 50969783Smsmith IPC_WAIT_TIMEOUT); 51069783Smsmith if (entry.response) { 51169783Smsmith ret = ipc_validate_msg(&entry); 51269783Smsmith if (ret) { 51369783Smsmith kvfree(entry.response); 51469783Smsmith entry.response = NULL; 51569783Smsmith } 51669783Smsmith } 517102441Sjhbout: 51869783Smsmith down_write(&ipc_msg_table_lock); 519142051Simp hash_del(&entry.ipc_table_hlist); 52069783Smsmith up_write(&ipc_msg_table_lock); 521124365Simp return entry.response; 522164130Sjhb} 523124365Simp 52469783Smsmithstatic int ksmbd_ipc_heartbeat_request(void) 52569783Smsmith{ 52669783Smsmith struct ksmbd_ipc_msg *msg; 52769783Smsmith int ret; 528164130Sjhb 529164130Sjhb msg = ipc_msg_alloc(sizeof(struct ksmbd_heartbeat)); 530164130Sjhb if (!msg) 531164130Sjhb return -EINVAL; 532164130Sjhb 533164130Sjhb msg->type = KSMBD_EVENT_HEARTBEAT_REQUEST; 53469783Smsmith ret = ipc_msg_send(msg); 53569783Smsmith ipc_msg_free(msg); 536107546Simp return ret; 537124365Simp} 538124365Simp 539124365Simpstruct ksmbd_login_response *ksmbd_ipc_login_request(const char *account) 540145652Smarcel{ 541145652Smarcel struct ksmbd_ipc_msg *msg; 542145652Smarcel struct ksmbd_login_request *req; 543145652Smarcel struct ksmbd_login_response *resp; 544145652Smarcel 545145652Smarcel if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 546145652Smarcel return NULL; 547145652Smarcel 548124365Simp msg = ipc_msg_alloc(sizeof(struct ksmbd_login_request)); 549124365Simp if (!msg) 550124365Simp return NULL; 551124365Simp 552124365Simp msg->type = KSMBD_EVENT_LOGIN_REQUEST; 553124365Simp req = (struct ksmbd_login_request *)msg->payload; 554142051Simp req->handle = ksmbd_acquire_id(&ipc_ida); 555142051Simp strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 556124365Simp 557106844Smdodd resp = ipc_msg_send_request(msg, req->handle); 558124365Simp ipc_msg_handle_free(req->handle); 559189844Simp ipc_msg_free(msg); 560189792Simp return resp; 561189792Simp} 562189792Simp 563189792Simpstruct ksmbd_spnego_authen_response * 564189792Simpksmbd_ipc_spnego_authen_request(const char *spnego_blob, int blob_len) 565189792Simp{ 566189844Simp struct ksmbd_ipc_msg *msg; 567106844Smdodd struct ksmbd_spnego_authen_request *req; 568124365Simp struct ksmbd_spnego_authen_response *resp; 569142051Simp 570142051Simp msg = ipc_msg_alloc(sizeof(struct ksmbd_spnego_authen_request) + 571124365Simp blob_len + 1); 572124365Simp if (!msg) 573124365Simp return NULL; 574124365Simp 575124365Simp msg->type = KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST; 576164130Sjhb req = (struct ksmbd_spnego_authen_request *)msg->payload; 577124365Simp req->handle = ksmbd_acquire_id(&ipc_ida); 578164130Sjhb req->spnego_blob_len = blob_len; 579124365Simp memcpy(req->spnego_blob, spnego_blob, blob_len); 580124365Simp 581124365Simp resp = ipc_msg_send_request(msg, req->handle); 582142051Simp ipc_msg_handle_free(req->handle); 583164130Sjhb ipc_msg_free(msg); 584164130Sjhb return resp; 585124365Simp} 58669783Smsmith 58769783Smsmithstruct ksmbd_tree_connect_response * 588107546Simpksmbd_ipc_tree_connect_request(struct ksmbd_session *sess, 589107546Simp struct ksmbd_share_config *share, 590124365Simp struct ksmbd_tree_connect *tree_conn, 591107546Simp struct sockaddr *peer_addr) 592124365Simp{ 593145652Smarcel struct ksmbd_ipc_msg *msg; 594145652Smarcel struct ksmbd_tree_connect_request *req; 595145652Smarcel struct ksmbd_tree_connect_response *resp; 596145652Smarcel 597145652Smarcel if (strlen(user_name(sess->user)) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 598145652Smarcel return NULL; 599145652Smarcel 600145652Smarcel if (strlen(share->name) >= KSMBD_REQ_MAX_SHARE_NAME) 601124365Simp return NULL; 602124365Simp 603124365Simp msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_connect_request)); 604124365Simp if (!msg) 605124365Simp return NULL; 606124365Simp 607124365Simp msg->type = KSMBD_EVENT_TREE_CONNECT_REQUEST; 608124365Simp req = (struct ksmbd_tree_connect_request *)msg->payload; 609124365Simp 610124365Simp req->handle = ksmbd_acquire_id(&ipc_ida); 611124365Simp req->account_flags = sess->user->flags; 612124365Simp req->session_id = sess->id; 613124365Simp req->connect_id = tree_conn->id; 614124365Simp strscpy(req->account, user_name(sess->user), KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 615124365Simp strscpy(req->share, share->name, KSMBD_REQ_MAX_SHARE_NAME); 616124365Simp snprintf(req->peer_addr, sizeof(req->peer_addr), "%pIS", peer_addr); 617124365Simp 618124365Simp if (peer_addr->sa_family == AF_INET6) 619124365Simp req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_IPV6; 620124365Simp if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2)) 621124365Simp req->flags |= KSMBD_TREE_CONN_FLAG_REQUEST_SMB2; 622124365Simp 623107546Simp resp = ipc_msg_send_request(msg, req->handle); 624107546Simp ipc_msg_handle_free(req->handle); 625124365Simp ipc_msg_free(msg); 626189844Simp return resp; 627124365Simp} 628189792Simp 629189792Simpint ksmbd_ipc_tree_disconnect_request(unsigned long long session_id, 630124365Simp unsigned long long connect_id) 631124365Simp{ 632189792Simp struct ksmbd_ipc_msg *msg; 633189792Simp struct ksmbd_tree_disconnect_request *req; 634124365Simp int ret; 635189844Simp 636106844Smdodd msg = ipc_msg_alloc(sizeof(struct ksmbd_tree_disconnect_request)); 637124365Simp if (!msg) 638142051Simp return -ENOMEM; 639142051Simp 640124365Simp msg->type = KSMBD_EVENT_TREE_DISCONNECT_REQUEST; 641124365Simp req = (struct ksmbd_tree_disconnect_request *)msg->payload; 642124365Simp req->session_id = session_id; 643124365Simp req->connect_id = connect_id; 644124365Simp 645124365Simp ret = ipc_msg_send(msg); 646164130Sjhb ipc_msg_free(msg); 647163805Simp return ret; 648164130Sjhb} 649163805Simp 650163805Simpint ksmbd_ipc_logout_request(const char *account, int flags) 651124365Simp{ 652124365Simp struct ksmbd_ipc_msg *msg; 653124365Simp struct ksmbd_logout_request *req; 654164130Sjhb int ret; 655142051Simp 656164130Sjhb if (strlen(account) >= KSMBD_REQ_MAX_ACCOUNT_NAME_SZ) 657124365Simp return -EINVAL; 65869908Smsmith 65969783Smsmith msg = ipc_msg_alloc(sizeof(struct ksmbd_logout_request)); 660124365Simp if (!msg) 66169783Smsmith return -ENOMEM; 662124365Simp 663124365Simp msg->type = KSMBD_EVENT_LOGOUT_REQUEST; 664124365Simp req = (struct ksmbd_logout_request *)msg->payload; 665142051Simp req->account_flags = flags; 666142051Simp strscpy(req->account, account, KSMBD_REQ_MAX_ACCOUNT_NAME_SZ); 66769783Smsmith 66869783Smsmith ret = ipc_msg_send(msg); 66969783Smsmith ipc_msg_free(msg); 67069783Smsmith return ret; 67169783Smsmith} 672102441Sjhb 67369783Smsmithstruct ksmbd_share_config_response * 67469783Smsmithksmbd_ipc_share_config_request(const char *name) 67569908Smsmith{ 67669783Smsmith struct ksmbd_ipc_msg *msg; 67769783Smsmith struct ksmbd_share_config_request *req; 67869783Smsmith struct ksmbd_share_config_response *resp; 67969783Smsmith 68069783Smsmith if (strlen(name) >= KSMBD_REQ_MAX_SHARE_NAME) 681119266Simp return NULL; 682189792Simp 68369783Smsmith msg = ipc_msg_alloc(sizeof(struct ksmbd_share_config_request)); 68469783Smsmith if (!msg) 68569783Smsmith return NULL; 68669783Smsmith 687102441Sjhb msg->type = KSMBD_EVENT_SHARE_CONFIG_REQUEST; 688189792Simp req = (struct ksmbd_share_config_request *)msg->payload; 68969783Smsmith req->handle = ksmbd_acquire_id(&ipc_ida); 69069783Smsmith strscpy(req->share_name, name, KSMBD_REQ_MAX_SHARE_NAME); 69169783Smsmith 69269783Smsmith resp = ipc_msg_send_request(msg, req->handle); 69369783Smsmith ipc_msg_handle_free(req->handle); 69469783Smsmith ipc_msg_free(msg); 69569783Smsmith return resp; 696109229Sbenno} 69769783Smsmith 69869783Smsmithstruct ksmbd_rpc_command *ksmbd_rpc_open(struct ksmbd_session *sess, int handle) 69969783Smsmith{ 70069783Smsmith struct ksmbd_ipc_msg *msg; 70169783Smsmith struct ksmbd_rpc_command *req; 70269783Smsmith struct ksmbd_rpc_command *resp; 70369783Smsmith 70469783Smsmith msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 70569783Smsmith if (!msg) 70669783Smsmith return NULL; 70769783Smsmith 70869783Smsmith msg->type = KSMBD_EVENT_RPC_REQUEST; 70969783Smsmith req = (struct ksmbd_rpc_command *)msg->payload; 71069783Smsmith req->handle = handle; 71169783Smsmith req->flags = ksmbd_session_rpc_method(sess, handle); 71269783Smsmith req->flags |= KSMBD_RPC_OPEN_METHOD; 71369783Smsmith req->payload_sz = 0; 714115234Sticso 71569783Smsmith resp = ipc_msg_send_request(msg, req->handle); 71669783Smsmith ipc_msg_free(msg); 71769783Smsmith return resp; 71869783Smsmith} 71969783Smsmith 72069783Smsmithstruct ksmbd_rpc_command *ksmbd_rpc_close(struct ksmbd_session *sess, int handle) 72169783Smsmith{ 722131398Sjhb struct ksmbd_ipc_msg *msg; 723102977Sjhb struct ksmbd_rpc_command *req; 724102977Sjhb struct ksmbd_rpc_command *resp; 72590554Smsmith 72669783Smsmith msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 72769783Smsmith if (!msg) 728107172Sjhb return NULL; 729169221Sjhb 730164264Sjhb msg->type = KSMBD_EVENT_RPC_REQUEST; 731164264Sjhb req = (struct ksmbd_rpc_command *)msg->payload; 732164264Sjhb req->handle = handle; 733169902Sgallatin req->flags = ksmbd_session_rpc_method(sess, handle); 734164264Sjhb req->flags |= KSMBD_RPC_CLOSE_METHOD; 735164264Sjhb req->payload_sz = 0; 736165995Sjhb 737165995Sjhb resp = ipc_msg_send_request(msg, req->handle); 738164264Sjhb ipc_msg_free(msg); 739164264Sjhb return resp; 740164264Sjhb} 741164264Sjhb 742164264Sjhbstruct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle, 743169221Sjhb void *payload, size_t payload_sz) 744164264Sjhb{ 745164264Sjhb struct ksmbd_ipc_msg *msg; 746164264Sjhb struct ksmbd_rpc_command *req; 747164264Sjhb struct ksmbd_rpc_command *resp; 748164264Sjhb 749164264Sjhb msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 750164264Sjhb if (!msg) 751164264Sjhb return NULL; 752164264Sjhb 753164264Sjhb msg->type = KSMBD_EVENT_RPC_REQUEST; 754164264Sjhb req = (struct ksmbd_rpc_command *)msg->payload; 755169221Sjhb req->handle = handle; 756164264Sjhb req->flags = ksmbd_session_rpc_method(sess, handle); 757169902Sgallatin req->flags |= rpc_context_flags(sess); 758164264Sjhb req->flags |= KSMBD_RPC_WRITE_METHOD; 759164264Sjhb req->payload_sz = payload_sz; 760165995Sjhb memcpy(req->payload, payload, payload_sz); 761165995Sjhb 762164264Sjhb resp = ipc_msg_send_request(msg, req->handle); 763169221Sjhb ipc_msg_free(msg); 764164264Sjhb return resp; 765164264Sjhb} 766169221Sjhb 767166176Sjhbstruct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle) 768169221Sjhb{ 769166176Sjhb struct ksmbd_ipc_msg *msg; 770166176Sjhb struct ksmbd_rpc_command *req; 771166176Sjhb struct ksmbd_rpc_command *resp; 772166176Sjhb 773169221Sjhb msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command)); 774166176Sjhb if (!msg) 775166176Sjhb return NULL; 776169221Sjhb 777164264Sjhb msg->type = KSMBD_EVENT_RPC_REQUEST; 778169221Sjhb req = (struct ksmbd_rpc_command *)msg->payload; 779169221Sjhb req->handle = handle; 780164264Sjhb req->flags = ksmbd_session_rpc_method(sess, handle); 781164264Sjhb req->flags |= rpc_context_flags(sess); 782180753Sluoqi req->flags |= KSMBD_RPC_READ_METHOD; 783164264Sjhb req->payload_sz = 0; 784164264Sjhb 785180753Sluoqi resp = ipc_msg_send_request(msg, req->handle); 786180753Sluoqi ipc_msg_free(msg); 787180753Sluoqi return resp; 788180753Sluoqi} 789180753Sluoqi 790180753Sluoqistruct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle, 791164264Sjhb void *payload, size_t payload_sz) 792164264Sjhb{ 793107172Sjhb struct ksmbd_ipc_msg *msg; 794107172Sjhb struct ksmbd_rpc_command *req; 795107172Sjhb struct ksmbd_rpc_command *resp; 796107172Sjhb 797107172Sjhb msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 798107172Sjhb if (!msg) 799119266Simp return NULL; 800107172Sjhb 801119266Simp msg->type = KSMBD_EVENT_RPC_REQUEST; 802107172Sjhb req = (struct ksmbd_rpc_command *)msg->payload; 803107172Sjhb req->handle = handle; 804107248Sjhb req->flags = ksmbd_session_rpc_method(sess, handle); 805107172Sjhb req->flags |= rpc_context_flags(sess); 806107172Sjhb req->flags |= KSMBD_RPC_IOCTL_METHOD; 807107172Sjhb req->payload_sz = payload_sz; 808107172Sjhb memcpy(req->payload, payload, payload_sz); 809107172Sjhb 810107172Sjhb resp = ipc_msg_send_request(msg, req->handle); 811107172Sjhb ipc_msg_free(msg); 812107172Sjhb return resp; 813107172Sjhb} 814107172Sjhb 815107172Sjhbstruct ksmbd_rpc_command *ksmbd_rpc_rap(struct ksmbd_session *sess, void *payload, 816107172Sjhb size_t payload_sz) 817107172Sjhb{ 818107172Sjhb struct ksmbd_ipc_msg *msg; 819107172Sjhb struct ksmbd_rpc_command *req; 820107172Sjhb struct ksmbd_rpc_command *resp; 821107172Sjhb 822107172Sjhb msg = ipc_msg_alloc(sizeof(struct ksmbd_rpc_command) + payload_sz + 1); 823107172Sjhb if (!msg) 824107172Sjhb return NULL; 825107172Sjhb 826107172Sjhb msg->type = KSMBD_EVENT_RPC_REQUEST; 827107172Sjhb req = (struct ksmbd_rpc_command *)msg->payload; 828107172Sjhb req->handle = ksmbd_acquire_id(&ipc_ida); 829107172Sjhb req->flags = rpc_context_flags(sess); 830107172Sjhb req->flags |= KSMBD_RPC_RAP_METHOD; 831107172Sjhb req->payload_sz = payload_sz; 832107172Sjhb memcpy(req->payload, payload, payload_sz); 833107172Sjhb 834107172Sjhb resp = ipc_msg_send_request(msg, req->handle); 835107248Sjhb ipc_msg_handle_free(req->handle); 836107172Sjhb ipc_msg_free(msg); 837107172Sjhb return resp; 838107172Sjhb} 839107248Sjhb 840107172Sjhbstatic int __ipc_heartbeat(void) 841107172Sjhb{ 842107172Sjhb unsigned long delta; 843107248Sjhb 844107172Sjhb if (!ksmbd_server_running()) 845107172Sjhb return 0; 846107172Sjhb 847107248Sjhb if (time_after(jiffies, server_conf.ipc_last_active)) { 848107172Sjhb delta = (jiffies - server_conf.ipc_last_active); 849107172Sjhb } else { 850107172Sjhb ipc_update_last_active(); 851107172Sjhb schedule_delayed_work(&ipc_timer_work, 852107172Sjhb server_conf.ipc_timeout); 853107172Sjhb return 0; 854107172Sjhb } 855107172Sjhb 856107172Sjhb if (delta < server_conf.ipc_timeout) { 857107172Sjhb schedule_delayed_work(&ipc_timer_work, 858107172Sjhb server_conf.ipc_timeout - delta); 859107172Sjhb return 0; 860107172Sjhb } 861107172Sjhb 862107172Sjhb if (ksmbd_ipc_heartbeat_request() == 0) { 863107172Sjhb schedule_delayed_work(&ipc_timer_work, 864107172Sjhb server_conf.ipc_timeout); 865107172Sjhb return 0; 866144110Sjhb } 867144110Sjhb 868144110Sjhb mutex_lock(&startup_lock); 869144110Sjhb WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); 870144110Sjhb server_conf.ipc_last_active = 0; 871107172Sjhb ksmbd_tools_pid = 0; 872107172Sjhb pr_err("No IPC daemon response for %lus\n", delta / HZ); 873107172Sjhb mutex_unlock(&startup_lock); 874107172Sjhb return -EINVAL; 875107172Sjhb} 876107172Sjhb 877107172Sjhbstatic void ipc_timer_heartbeat(struct work_struct *w) 878{ 879 if (__ipc_heartbeat()) 880 server_queue_ctrl_reset_work(); 881} 882 883int ksmbd_ipc_id_alloc(void) 884{ 885 return ksmbd_acquire_id(&ipc_ida); 886} 887 888void ksmbd_rpc_id_free(int handle) 889{ 890 ksmbd_release_id(&ipc_ida, handle); 891} 892 893void ksmbd_ipc_release(void) 894{ 895 cancel_delayed_work_sync(&ipc_timer_work); 896 genl_unregister_family(&ksmbd_genl_family); 897} 898 899void ksmbd_ipc_soft_reset(void) 900{ 901 mutex_lock(&startup_lock); 902 ksmbd_tools_pid = 0; 903 cancel_delayed_work_sync(&ipc_timer_work); 904 mutex_unlock(&startup_lock); 905} 906 907int ksmbd_ipc_init(void) 908{ 909 int ret = 0; 910 911 ksmbd_nl_init_fixup(); 912 INIT_DELAYED_WORK(&ipc_timer_work, ipc_timer_heartbeat); 913 914 ret = genl_register_family(&ksmbd_genl_family); 915 if (ret) { 916 pr_err("Failed to register KSMBD netlink interface %d\n", ret); 917 cancel_delayed_work_sync(&ipc_timer_work); 918 } 919 920 return ret; 921} 922