linux/fs/ksmbd/server.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
   4 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
   5 */
   6
   7#include "glob.h"
   8#include "oplock.h"
   9#include "misc.h"
  10#include <linux/sched/signal.h>
  11#include <linux/workqueue.h>
  12#include <linux/sysfs.h>
  13#include <linux/module.h>
  14#include <linux/moduleparam.h>
  15
  16#include "server.h"
  17#include "smb_common.h"
  18#include "smbstatus.h"
  19#include "connection.h"
  20#include "transport_ipc.h"
  21#include "mgmt/user_session.h"
  22#include "crypto_ctx.h"
  23#include "auth.h"
  24
  25int ksmbd_debug_types;
  26
  27struct ksmbd_server_config server_conf;
  28
  29enum SERVER_CTRL_TYPE {
  30        SERVER_CTRL_TYPE_INIT,
  31        SERVER_CTRL_TYPE_RESET,
  32};
  33
  34struct server_ctrl_struct {
  35        int                     type;
  36        struct work_struct      ctrl_work;
  37};
  38
  39static DEFINE_MUTEX(ctrl_lock);
  40
  41static int ___server_conf_set(int idx, char *val)
  42{
  43        if (idx >= ARRAY_SIZE(server_conf.conf))
  44                return -EINVAL;
  45
  46        if (!val || val[0] == 0x00)
  47                return -EINVAL;
  48
  49        kfree(server_conf.conf[idx]);
  50        server_conf.conf[idx] = kstrdup(val, GFP_KERNEL);
  51        if (!server_conf.conf[idx])
  52                return -ENOMEM;
  53        return 0;
  54}
  55
  56int ksmbd_set_netbios_name(char *v)
  57{
  58        return ___server_conf_set(SERVER_CONF_NETBIOS_NAME, v);
  59}
  60
  61int ksmbd_set_server_string(char *v)
  62{
  63        return ___server_conf_set(SERVER_CONF_SERVER_STRING, v);
  64}
  65
  66int ksmbd_set_work_group(char *v)
  67{
  68        return ___server_conf_set(SERVER_CONF_WORK_GROUP, v);
  69}
  70
  71char *ksmbd_netbios_name(void)
  72{
  73        return server_conf.conf[SERVER_CONF_NETBIOS_NAME];
  74}
  75
  76char *ksmbd_server_string(void)
  77{
  78        return server_conf.conf[SERVER_CONF_SERVER_STRING];
  79}
  80
  81char *ksmbd_work_group(void)
  82{
  83        return server_conf.conf[SERVER_CONF_WORK_GROUP];
  84}
  85
  86/**
  87 * check_conn_state() - check state of server thread connection
  88 * @work:     smb work containing server thread information
  89 *
  90 * Return:      0 on valid connection, otherwise 1 to reconnect
  91 */
  92static inline int check_conn_state(struct ksmbd_work *work)
  93{
  94        struct smb_hdr *rsp_hdr;
  95
  96        if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) {
  97                rsp_hdr = work->response_buf;
  98                rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
  99                return 1;
 100        }
 101        return 0;
 102}
 103
 104#define SERVER_HANDLER_CONTINUE         0
 105#define SERVER_HANDLER_ABORT            1
 106
 107static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
 108                             u16 *cmd)
 109{
 110        struct smb_version_cmds *cmds;
 111        u16 command;
 112        int ret;
 113
 114        if (check_conn_state(work))
 115                return SERVER_HANDLER_CONTINUE;
 116
 117        if (ksmbd_verify_smb_message(work))
 118                return SERVER_HANDLER_ABORT;
 119
 120        command = conn->ops->get_cmd_val(work);
 121        *cmd = command;
 122
 123andx_again:
 124        if (command >= conn->max_cmds) {
 125                conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
 126                return SERVER_HANDLER_CONTINUE;
 127        }
 128
 129        cmds = &conn->cmds[command];
 130        if (!cmds->proc) {
 131                ksmbd_debug(SMB, "*** not implemented yet cmd = %x\n", command);
 132                conn->ops->set_rsp_status(work, STATUS_NOT_IMPLEMENTED);
 133                return SERVER_HANDLER_CONTINUE;
 134        }
 135
 136        if (work->sess && conn->ops->is_sign_req(work, command)) {
 137                ret = conn->ops->check_sign_req(work);
 138                if (!ret) {
 139                        conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED);
 140                        return SERVER_HANDLER_CONTINUE;
 141                }
 142        }
 143
 144        ret = cmds->proc(work);
 145
 146        if (ret < 0)
 147                ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret);
 148        /* AndX commands - chained request can return positive values */
 149        else if (ret > 0) {
 150                command = ret;
 151                *cmd = command;
 152                goto andx_again;
 153        }
 154
 155        if (work->send_no_response)
 156                return SERVER_HANDLER_ABORT;
 157        return SERVER_HANDLER_CONTINUE;
 158}
 159
 160static void __handle_ksmbd_work(struct ksmbd_work *work,
 161                                struct ksmbd_conn *conn)
 162{
 163        u16 command = 0;
 164        int rc;
 165
 166        if (conn->ops->allocate_rsp_buf(work))
 167                return;
 168
 169        if (conn->ops->is_transform_hdr &&
 170            conn->ops->is_transform_hdr(work->request_buf)) {
 171                rc = conn->ops->decrypt_req(work);
 172                if (rc < 0) {
 173                        conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
 174                        goto send;
 175                }
 176
 177                work->encrypted = true;
 178        }
 179
 180        rc = conn->ops->init_rsp_hdr(work);
 181        if (rc) {
 182                /* either uid or tid is not correct */
 183                conn->ops->set_rsp_status(work, STATUS_INVALID_HANDLE);
 184                goto send;
 185        }
 186
 187        if (conn->ops->check_user_session) {
 188                rc = conn->ops->check_user_session(work);
 189                if (rc < 0) {
 190                        command = conn->ops->get_cmd_val(work);
 191                        conn->ops->set_rsp_status(work,
 192                                        STATUS_USER_SESSION_DELETED);
 193                        goto send;
 194                } else if (rc > 0) {
 195                        rc = conn->ops->get_ksmbd_tcon(work);
 196                        if (rc < 0) {
 197                                conn->ops->set_rsp_status(work,
 198                                        STATUS_NETWORK_NAME_DELETED);
 199                                goto send;
 200                        }
 201                }
 202        }
 203
 204        do {
 205                rc = __process_request(work, conn, &command);
 206                if (rc == SERVER_HANDLER_ABORT)
 207                        break;
 208
 209                /*
 210                 * Call smb2_set_rsp_credits() function to set number of credits
 211                 * granted in hdr of smb2 response.
 212                 */
 213                if (conn->ops->set_rsp_credits) {
 214                        spin_lock(&conn->credits_lock);
 215                        rc = conn->ops->set_rsp_credits(work);
 216                        spin_unlock(&conn->credits_lock);
 217                        if (rc < 0) {
 218                                conn->ops->set_rsp_status(work,
 219                                        STATUS_INVALID_PARAMETER);
 220                                goto send;
 221                        }
 222                }
 223
 224                if (work->sess &&
 225                    (work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
 226                     conn->ops->is_sign_req(work, command)))
 227                        conn->ops->set_sign_rsp(work);
 228        } while (is_chained_smb2_message(work));
 229
 230        if (work->send_no_response)
 231                return;
 232
 233send:
 234        smb3_preauth_hash_rsp(work);
 235        if (work->sess && work->sess->enc && work->encrypted &&
 236            conn->ops->encrypt_resp) {
 237                rc = conn->ops->encrypt_resp(work);
 238                if (rc < 0) {
 239                        conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
 240                        goto send;
 241                }
 242        }
 243
 244        ksmbd_conn_write(work);
 245}
 246
 247/**
 248 * handle_ksmbd_work() - process pending smb work requests
 249 * @wk: smb work containing request command buffer
 250 *
 251 * called by kworker threads to processing remaining smb work requests
 252 */
 253static void handle_ksmbd_work(struct work_struct *wk)
 254{
 255        struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
 256        struct ksmbd_conn *conn = work->conn;
 257
 258        atomic64_inc(&conn->stats.request_served);
 259
 260        __handle_ksmbd_work(work, conn);
 261
 262        ksmbd_conn_try_dequeue_request(work);
 263        ksmbd_free_work_struct(work);
 264        atomic_dec(&conn->r_count);
 265}
 266
 267/**
 268 * queue_ksmbd_work() - queue a smb request to worker thread queue
 269 *              for proccessing smb command and sending response
 270 * @conn:       connection instance
 271 *
 272 * read remaining data from socket create and submit work.
 273 */
 274static int queue_ksmbd_work(struct ksmbd_conn *conn)
 275{
 276        struct ksmbd_work *work;
 277
 278        work = ksmbd_alloc_work_struct();
 279        if (!work) {
 280                pr_err("allocation for work failed\n");
 281                return -ENOMEM;
 282        }
 283
 284        work->conn = conn;
 285        work->request_buf = conn->request_buf;
 286        conn->request_buf = NULL;
 287
 288        if (ksmbd_init_smb_server(work)) {
 289                ksmbd_free_work_struct(work);
 290                return -EINVAL;
 291        }
 292
 293        ksmbd_conn_enqueue_request(work);
 294        atomic_inc(&conn->r_count);
 295        /* update activity on connection */
 296        conn->last_active = jiffies;
 297        INIT_WORK(&work->work, handle_ksmbd_work);
 298        ksmbd_queue_work(work);
 299        return 0;
 300}
 301
 302static int ksmbd_server_process_request(struct ksmbd_conn *conn)
 303{
 304        return queue_ksmbd_work(conn);
 305}
 306
 307static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn)
 308{
 309        ksmbd_sessions_deregister(conn);
 310        destroy_lease_table(conn);
 311        return 0;
 312}
 313
 314static void ksmbd_server_tcp_callbacks_init(void)
 315{
 316        struct ksmbd_conn_ops ops;
 317
 318        ops.process_fn = ksmbd_server_process_request;
 319        ops.terminate_fn = ksmbd_server_terminate_conn;
 320
 321        ksmbd_conn_init_server_callbacks(&ops);
 322}
 323
 324static void server_conf_free(void)
 325{
 326        int i;
 327
 328        for (i = 0; i < ARRAY_SIZE(server_conf.conf); i++) {
 329                kfree(server_conf.conf[i]);
 330                server_conf.conf[i] = NULL;
 331        }
 332}
 333
 334static int server_conf_init(void)
 335{
 336        WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
 337        server_conf.enforced_signing = 0;
 338        server_conf.min_protocol = ksmbd_min_protocol();
 339        server_conf.max_protocol = ksmbd_max_protocol();
 340        server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP;
 341#ifdef CONFIG_SMB_SERVER_KERBEROS5
 342        server_conf.auth_mechs |= KSMBD_AUTH_KRB5 |
 343                                KSMBD_AUTH_MSKRB5;
 344#endif
 345        return 0;
 346}
 347
 348static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl)
 349{
 350        int ret;
 351
 352        ret = ksmbd_conn_transport_init();
 353        if (ret) {
 354                server_queue_ctrl_reset_work();
 355                return;
 356        }
 357
 358        WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING);
 359}
 360
 361static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
 362{
 363        ksmbd_ipc_soft_reset();
 364        ksmbd_conn_transport_destroy();
 365        server_conf_free();
 366        server_conf_init();
 367        WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
 368}
 369
 370static void server_ctrl_handle_work(struct work_struct *work)
 371{
 372        struct server_ctrl_struct *ctrl;
 373
 374        ctrl = container_of(work, struct server_ctrl_struct, ctrl_work);
 375
 376        mutex_lock(&ctrl_lock);
 377        switch (ctrl->type) {
 378        case SERVER_CTRL_TYPE_INIT:
 379                server_ctrl_handle_init(ctrl);
 380                break;
 381        case SERVER_CTRL_TYPE_RESET:
 382                server_ctrl_handle_reset(ctrl);
 383                break;
 384        default:
 385                pr_err("Unknown server work type: %d\n", ctrl->type);
 386        }
 387        mutex_unlock(&ctrl_lock);
 388        kfree(ctrl);
 389        module_put(THIS_MODULE);
 390}
 391
 392static int __queue_ctrl_work(int type)
 393{
 394        struct server_ctrl_struct *ctrl;
 395
 396        ctrl = kmalloc(sizeof(struct server_ctrl_struct), GFP_KERNEL);
 397        if (!ctrl)
 398                return -ENOMEM;
 399
 400        __module_get(THIS_MODULE);
 401        ctrl->type = type;
 402        INIT_WORK(&ctrl->ctrl_work, server_ctrl_handle_work);
 403        queue_work(system_long_wq, &ctrl->ctrl_work);
 404        return 0;
 405}
 406
 407int server_queue_ctrl_init_work(void)
 408{
 409        return __queue_ctrl_work(SERVER_CTRL_TYPE_INIT);
 410}
 411
 412int server_queue_ctrl_reset_work(void)
 413{
 414        return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET);
 415}
 416
 417static ssize_t stats_show(struct class *class, struct class_attribute *attr,
 418                          char *buf)
 419{
 420        /*
 421         * Inc this each time you change stats output format,
 422         * so user space will know what to do.
 423         */
 424        static int stats_version = 2;
 425        static const char * const state[] = {
 426                "startup",
 427                "running",
 428                "reset",
 429                "shutdown"
 430        };
 431
 432        ssize_t sz = scnprintf(buf, PAGE_SIZE, "%d %s %d %lu\n", stats_version,
 433                               state[server_conf.state], server_conf.tcp_port,
 434                               server_conf.ipc_last_active / HZ);
 435        return sz;
 436}
 437
 438static ssize_t kill_server_store(struct class *class,
 439                                 struct class_attribute *attr, const char *buf,
 440                                 size_t len)
 441{
 442        if (!sysfs_streq(buf, "hard"))
 443                return len;
 444
 445        pr_info("kill command received\n");
 446        mutex_lock(&ctrl_lock);
 447        WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING);
 448        __module_get(THIS_MODULE);
 449        server_ctrl_handle_reset(NULL);
 450        module_put(THIS_MODULE);
 451        mutex_unlock(&ctrl_lock);
 452        return len;
 453}
 454
 455static const char * const debug_type_strings[] = {"smb", "auth", "vfs",
 456                                                  "oplock", "ipc", "conn",
 457                                                  "rdma"};
 458
 459static ssize_t debug_show(struct class *class, struct class_attribute *attr,
 460                          char *buf)
 461{
 462        ssize_t sz = 0;
 463        int i, pos = 0;
 464
 465        for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
 466                if ((ksmbd_debug_types >> i) & 1) {
 467                        pos = scnprintf(buf + sz,
 468                                        PAGE_SIZE - sz,
 469                                        "[%s] ",
 470                                        debug_type_strings[i]);
 471                } else {
 472                        pos = scnprintf(buf + sz,
 473                                        PAGE_SIZE - sz,
 474                                        "%s ",
 475                                        debug_type_strings[i]);
 476                }
 477                sz += pos;
 478        }
 479        sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
 480        return sz;
 481}
 482
 483static ssize_t debug_store(struct class *class, struct class_attribute *attr,
 484                           const char *buf, size_t len)
 485{
 486        int i;
 487
 488        for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
 489                if (sysfs_streq(buf, "all")) {
 490                        if (ksmbd_debug_types == KSMBD_DEBUG_ALL)
 491                                ksmbd_debug_types = 0;
 492                        else
 493                                ksmbd_debug_types = KSMBD_DEBUG_ALL;
 494                        break;
 495                }
 496
 497                if (sysfs_streq(buf, debug_type_strings[i])) {
 498                        if (ksmbd_debug_types & (1 << i))
 499                                ksmbd_debug_types &= ~(1 << i);
 500                        else
 501                                ksmbd_debug_types |= (1 << i);
 502                        break;
 503                }
 504        }
 505
 506        return len;
 507}
 508
 509static CLASS_ATTR_RO(stats);
 510static CLASS_ATTR_WO(kill_server);
 511static CLASS_ATTR_RW(debug);
 512
 513static struct attribute *ksmbd_control_class_attrs[] = {
 514        &class_attr_stats.attr,
 515        &class_attr_kill_server.attr,
 516        &class_attr_debug.attr,
 517        NULL,
 518};
 519ATTRIBUTE_GROUPS(ksmbd_control_class);
 520
 521static struct class ksmbd_control_class = {
 522        .name           = "ksmbd-control",
 523        .owner          = THIS_MODULE,
 524        .class_groups   = ksmbd_control_class_groups,
 525};
 526
 527static int ksmbd_server_shutdown(void)
 528{
 529        WRITE_ONCE(server_conf.state, SERVER_STATE_SHUTTING_DOWN);
 530
 531        class_unregister(&ksmbd_control_class);
 532        ksmbd_workqueue_destroy();
 533        ksmbd_ipc_release();
 534        ksmbd_conn_transport_destroy();
 535        ksmbd_crypto_destroy();
 536        ksmbd_free_global_file_table();
 537        destroy_lease_table(NULL);
 538        ksmbd_work_pool_destroy();
 539        ksmbd_exit_file_cache();
 540        server_conf_free();
 541        return 0;
 542}
 543
 544static int __init ksmbd_server_init(void)
 545{
 546        int ret;
 547
 548        ret = class_register(&ksmbd_control_class);
 549        if (ret) {
 550                pr_err("Unable to register ksmbd-control class\n");
 551                return ret;
 552        }
 553
 554        ksmbd_server_tcp_callbacks_init();
 555
 556        ret = server_conf_init();
 557        if (ret)
 558                goto err_unregister;
 559
 560        ret = ksmbd_work_pool_init();
 561        if (ret)
 562                goto err_unregister;
 563
 564        ret = ksmbd_init_file_cache();
 565        if (ret)
 566                goto err_destroy_work_pools;
 567
 568        ret = ksmbd_ipc_init();
 569        if (ret)
 570                goto err_exit_file_cache;
 571
 572        ret = ksmbd_init_global_file_table();
 573        if (ret)
 574                goto err_ipc_release;
 575
 576        ret = ksmbd_inode_hash_init();
 577        if (ret)
 578                goto err_destroy_file_table;
 579
 580        ret = ksmbd_crypto_create();
 581        if (ret)
 582                goto err_release_inode_hash;
 583
 584        ret = ksmbd_workqueue_init();
 585        if (ret)
 586                goto err_crypto_destroy;
 587
 588        pr_warn_once("The ksmbd server is experimental, use at your own risk.\n");
 589
 590        return 0;
 591
 592err_crypto_destroy:
 593        ksmbd_crypto_destroy();
 594err_release_inode_hash:
 595        ksmbd_release_inode_hash();
 596err_destroy_file_table:
 597        ksmbd_free_global_file_table();
 598err_ipc_release:
 599        ksmbd_ipc_release();
 600err_exit_file_cache:
 601        ksmbd_exit_file_cache();
 602err_destroy_work_pools:
 603        ksmbd_work_pool_destroy();
 604err_unregister:
 605        class_unregister(&ksmbd_control_class);
 606
 607        return ret;
 608}
 609
 610/**
 611 * ksmbd_server_exit() - shutdown forker thread and free memory at module exit
 612 */
 613static void __exit ksmbd_server_exit(void)
 614{
 615        ksmbd_server_shutdown();
 616        ksmbd_release_inode_hash();
 617}
 618
 619MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>");
 620MODULE_VERSION(KSMBD_VERSION);
 621MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
 622MODULE_LICENSE("GPL");
 623MODULE_SOFTDEP("pre: ecb");
 624MODULE_SOFTDEP("pre: hmac");
 625MODULE_SOFTDEP("pre: md4");
 626MODULE_SOFTDEP("pre: md5");
 627MODULE_SOFTDEP("pre: nls");
 628MODULE_SOFTDEP("pre: aes");
 629MODULE_SOFTDEP("pre: cmac");
 630MODULE_SOFTDEP("pre: sha256");
 631MODULE_SOFTDEP("pre: sha512");
 632MODULE_SOFTDEP("pre: aead2");
 633MODULE_SOFTDEP("pre: ccm");
 634MODULE_SOFTDEP("pre: gcm");
 635module_init(ksmbd_server_init)
 636module_exit(ksmbd_server_exit)
 637