1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright 2017 Joyent, Inc.
  25  */
  26 
  27 #include <sys/types.h>
  28 #include <sys/conf.h>
  29 #include <sys/ddi.h>
  30 #include <sys/modctl.h>
  31 #include <sys/cred.h>
  32 #include <sys/disp.h>
  33 #include <sys/ioccom.h>
  34 #include <sys/policy.h>
  35 #include <sys/cmn_err.h>
  36 #include <smbsrv/smb_kproto.h>
  37 #include <smbsrv/smb_ioctl.h>
  38 
  39 #ifdef  _FAKE_KERNEL
  40 #error  "See libfksmbsrv"
  41 #endif  /* _FAKE_KERNEL */
  42 
  43 static int smb_drv_open(dev_t *, int, int, cred_t *);
  44 static int smb_drv_close(dev_t, int, int, cred_t *);
  45 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  46 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
  47 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
  48 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  49 
  50 /*
  51  * *****************************************************************************
  52  * ****************************** Global Variables *****************************
  53  * *****************************************************************************
  54  *
  55  * These variables can only be changed through the /etc/system file.
  56  */
  57 
  58 /*
  59  * Maximum buffer size for NT: configurable based on the client environment.
  60  * IR104720 Experiments with Windows 2000 indicate that we achieve better
  61  * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used
  62  * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory
  63  * listing problems so this buffer size is configurable based on the end-user
  64  * environment. When in doubt use 37KB.
  65  */
  66 int     smb_maxbufsize = SMB_NT_MAXBUF;
  67 int     smb_oplock_levelII = 1;
  68 int     smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
  69 int     smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT;
  70 int     smb_flush_required = 1;
  71 int     smb_dirsymlink_enable = 1;
  72 int     smb_sign_debug = 0;
  73 int     smb_shortnames = 1;
  74 uint_t  smb_audit_flags =
  75 #ifdef  DEBUG
  76     SMB_AUDIT_NODE;
  77 #else
  78     0;
  79 #endif
  80 
  81 /*
  82  * Maximum number of simultaneous authentication, share mapping, pipe open
  83  * requests to be processed.
  84  */
  85 int     smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD;
  86 int     smb_tcon_threshold = 1024;
  87 int     smb_opipe_threshold = 1024;
  88 
  89 /*
  90  * Number of milliseconds that a request will be stalled if it comes in after
  91  * the maximum number of inflight operations are being proccessed.
  92  */
  93 int     smb_ssetup_timeout = (30 * 1000);
  94 int     smb_tcon_timeout = (30 * 1000);
  95 int     smb_opipe_timeout = (30 * 1000);
  96 
  97 /*
  98  * Thread priorities used in smbsrv.  Our threads spend most of their time
  99  * blocked on various conditions.  However, if the system gets heavy load,
 100  * the scheduler has to choose an order to run these.  We want the order:
 101  * (a) timers, (b) notifications, (c) workers, (d) receivers (and etc.)
 102  * where notifications are oplock and change notify work.  Aside from this
 103  * relative ordering, smbsrv threads should run with a priority close to
 104  * that of normal user-space threads (thus minclsyspri below), just like
 105  * NFS and other "file service" kinds of processing.
 106  */
 107 int smbsrv_base_pri     = MINCLSYSPRI;
 108 int smbsrv_listen_pri   = MINCLSYSPRI;
 109 int smbsrv_receive_pri  = MINCLSYSPRI;
 110 int smbsrv_worker_pri   = MINCLSYSPRI + 1;
 111 int smbsrv_notify_pri   = MINCLSYSPRI + 2;
 112 int smbsrv_timer_pri    = MINCLSYSPRI + 5;
 113 
 114 
 115 /*
 116  * *****************************************************************************
 117  * ********************** Static Variables / Module Linkage ********************
 118  * *****************************************************************************
 119  */
 120 
 121 static struct cb_ops cbops = {
 122         smb_drv_open,           /* cb_open */
 123         smb_drv_close,          /* cb_close */
 124         nodev,                  /* cb_strategy */
 125         nodev,                  /* cb_print */
 126         nodev,                  /* cb_dump */
 127         nodev,                  /* cb_read */
 128         nodev,                  /* cb_write */
 129         smb_drv_ioctl,          /* cb_ioctl */
 130         nodev,                  /* cb_devmap */
 131         nodev,                  /* cb_mmap */
 132         nodev,                  /* cb_segmap */
 133         nochpoll,               /* cb_chpoll */
 134         ddi_prop_op,            /* cb_prop_op */
 135         NULL,                   /* cb_streamtab */
 136         D_MP,                   /* cb_flag */
 137         CB_REV,                 /* cb_rev */
 138         nodev,                  /* cb_aread */
 139         nodev,                  /* cb_awrite */
 140 };
 141 
 142 static struct dev_ops devops = {
 143         DEVO_REV,               /* devo_rev */
 144         0,                      /* devo_refcnt */
 145         smb_drv_getinfo,        /* devo_getinfo */
 146         nulldev,                /* devo_identify */
 147         nulldev,                /* devo_probe */
 148         smb_drv_attach,         /* devo_attach */
 149         smb_drv_detach,         /* devo_detach */
 150         nodev,                  /* devo_reset */
 151         &cbops,                     /* devo_cb_ops */
 152         NULL,                   /* devo_bus_ops */
 153         NULL,                   /* devo_power */
 154         ddi_quiesce_not_needed,         /* devo_quiesce */
 155 };
 156 
 157 static struct modldrv modldrv = {
 158         &mod_driverops,                                     /* drv_modops */
 159         "CIFS Server Protocol",                         /* drv_linkinfo */
 160         &devops,
 161 };
 162 
 163 static struct modlinkage modlinkage = {
 164         MODREV_1,       /* revision of the module, must be: MODREV_1    */
 165         &modldrv,   /* ptr to linkage structures                    */
 166         NULL,
 167 };
 168 
 169 static dev_info_t *smb_drv_dip = NULL;
 170 
 171 /*
 172  * ****************************************************************************
 173  *                                  Module Interface
 174  * ****************************************************************************
 175  */
 176 
 177 int
 178 _init(void)
 179 {
 180         int rc;
 181 
 182         if ((rc = smb_server_g_init()) != 0) {
 183                 return (rc);
 184         }
 185 
 186         if ((rc = mod_install(&modlinkage)) != 0) {
 187                 smb_server_g_fini();
 188         }
 189 
 190         return (rc);
 191 }
 192 
 193 int
 194 _info(struct modinfo *modinfop)
 195 {
 196         return (mod_info(&modlinkage, modinfop));
 197 }
 198 
 199 int
 200 _fini(void)
 201 {
 202         int     rc;
 203 
 204         if (smb_server_get_count() != 0)
 205                 return (EBUSY);
 206 
 207         if ((rc = mod_remove(&modlinkage)) == 0) {
 208                 smb_server_g_fini();
 209         }
 210 
 211         return (rc);
 212 }
 213 
 214 /*
 215  * ****************************************************************************
 216  *                              Pseudo Device Entry Points
 217  * ****************************************************************************
 218  */
 219 /* ARGSUSED */
 220 static int
 221 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr)
 222 {
 223         zoneid_t zid;
 224 
 225         /*
 226          * Check caller's privileges.
 227          */
 228         if (secpolicy_smb(cr) != 0)
 229                 return (EPERM);
 230 
 231         /*
 232          * We need a unique minor per zone otherwise an smbd in any other
 233          * zone will keep this minor open and we won't get a close call.
 234          * The zone ID is good enough as a minor number.
 235          */
 236         zid = crgetzoneid(cr);
 237         if (zid < 0)
 238                 return (ENODEV);
 239         *devp = makedevice(getmajor(*devp), zid);
 240 
 241         /*
 242          * Start SMB service state machine
 243          */
 244         return (smb_server_create());
 245 }
 246 
 247 /* ARGSUSED */
 248 static int
 249 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
 250 {
 251         return (smb_server_delete());
 252 }
 253 
 254 /* ARGSUSED */
 255 static int
 256 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
 257     int *retval)
 258 {
 259         smb_ioc_t       *ioc;
 260         smb_ioc_header_t ioc_hdr;
 261         uint32_t        crc;
 262         boolean_t       copyout = B_FALSE;
 263         int             rc = 0;
 264         size_t          alloclen;
 265 
 266         if (ddi_copyin((void *)argp, &ioc_hdr, sizeof (ioc_hdr), flags))
 267                 return (EFAULT);
 268 
 269         /*
 270          * Check version and length.
 271          *
 272          * Note that some ioctls (i.e. SMB_IOC_SVCENUM) have payload
 273          * data after the ioctl struct, in which case they specify a
 274          * length much larger than sizeof smb_ioc_t.  The theoretical
 275          * largest ioctl data is therefore the size of the union plus
 276          * the max size of the payload (which is SMB_IOC_DATA_SIZE).
 277          */
 278         if (ioc_hdr.version != SMB_IOC_VERSION ||
 279             ioc_hdr.len < sizeof (ioc_hdr) ||
 280             ioc_hdr.len > (sizeof (*ioc) + SMB_IOC_DATA_SIZE))
 281                 return (EINVAL);
 282 
 283         crc = ioc_hdr.crc;
 284         ioc_hdr.crc = 0;
 285         if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
 286                 return (EINVAL);
 287 
 288         /*
 289          * Note that smb_ioc_t is a union, and callers set ioc_hdr.len
 290          * to the size of the actual union arm.  If some caller were to
 291          * set that size too small, we could end up passing under-sized
 292          * memory to one of the type-specific handler functions.  Avoid
 293          * that problem by allocating at least the size of the union,
 294          * (zeroed out) and then copy in the caller specified length.
 295          */
 296         alloclen = MAX(ioc_hdr.len, sizeof (*ioc));
 297         ioc = kmem_zalloc(alloclen, KM_SLEEP);
 298         if (ddi_copyin((void *)argp, ioc, ioc_hdr.len, flags)) {
 299                 kmem_free(ioc, alloclen);
 300                 return (EFAULT);
 301         }
 302 
 303         switch (cmd) {
 304         case SMB_IOC_CONFIG:
 305                 rc = smb_server_configure(&ioc->ioc_cfg);
 306                 break;
 307         case SMB_IOC_START:
 308                 rc = smb_server_start(&ioc->ioc_start);
 309                 break;
 310         case SMB_IOC_STOP:
 311                 rc = smb_server_stop();
 312                 break;
 313         case SMB_IOC_EVENT:
 314                 rc = smb_server_notify_event(&ioc->ioc_event);
 315                 break;
 316         case SMB_IOC_GMTOFF:
 317                 rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
 318                 break;
 319         case SMB_IOC_SHARE:
 320                 rc = smb_kshare_export_list(&ioc->ioc_share);
 321                 break;
 322         case SMB_IOC_UNSHARE:
 323                 rc = smb_kshare_unexport_list(&ioc->ioc_share);
 324                 break;
 325         case SMB_IOC_SHAREINFO:
 326                 rc = smb_kshare_info(&ioc->ioc_shareinfo);
 327                 copyout = B_TRUE;
 328                 break;
 329         case SMB_IOC_NUMOPEN:
 330                 rc = smb_server_numopen(&ioc->ioc_opennum);
 331                 copyout = B_TRUE;
 332                 break;
 333         case SMB_IOC_SVCENUM:
 334                 rc = smb_server_enum(&ioc->ioc_svcenum);
 335                 copyout = B_TRUE;
 336                 break;
 337         case SMB_IOC_SESSION_CLOSE:
 338                 rc = smb_server_session_close(&ioc->ioc_session);
 339                 break;
 340         case SMB_IOC_FILE_CLOSE:
 341                 rc = smb_server_file_close(&ioc->ioc_fileid);
 342                 break;
 343         case SMB_IOC_SPOOLDOC:
 344                 rc = smb_server_spooldoc(&ioc->ioc_spooldoc);
 345                 copyout = B_TRUE;
 346                 break;
 347         default:
 348                 rc = ENOTTY;
 349                 break;
 350         }
 351         if ((rc == 0) && copyout) {
 352                 if (ddi_copyout(ioc, (void *)argp, ioc_hdr.len, flags))
 353                         rc = EFAULT;
 354         }
 355         kmem_free(ioc, alloclen);
 356         return (rc);
 357 }
 358 
 359 /*
 360  * ****************************************************************************
 361  *                              Pseudo Device Operations
 362  * ****************************************************************************
 363  */
 364 static int
 365 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 366 {
 367         if (cmd == DDI_ATTACH) {
 368                 /* we only allow instance 0 to attach */
 369                 if (ddi_get_instance(dip) == 0) {
 370                         /* create the minor node */
 371                         if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
 372                             DDI_PSEUDO, 0) == DDI_SUCCESS) {
 373                                 smb_drv_dip = dip;
 374                                 return (DDI_SUCCESS);
 375                         } else {
 376                                 cmn_err(CE_WARN, "smb_drv_attach:"
 377                                     " failed creating minor node");
 378                         }
 379                 }
 380         }
 381         return (DDI_FAILURE);
 382 }
 383 
 384 static int
 385 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 386 {
 387         if (cmd == DDI_DETACH) {
 388                 ASSERT(dip == smb_drv_dip);
 389                 ddi_remove_minor_node(dip, NULL);
 390                 smb_drv_dip = NULL;
 391                 return (DDI_SUCCESS);
 392         }
 393         return (DDI_FAILURE);
 394 }
 395 
 396 /* ARGSUSED */
 397 static int
 398 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 399 {
 400         ulong_t instance = getminor((dev_t)arg);
 401 
 402         switch (cmd) {
 403         case DDI_INFO_DEVT2DEVINFO:
 404                 *result = smb_drv_dip;
 405                 return (DDI_SUCCESS);
 406 
 407         case DDI_INFO_DEVT2INSTANCE:
 408                 *result = (void *)instance;
 409                 return (DDI_SUCCESS);
 410 
 411         default:
 412                 break;
 413         }
 414 
 415         return (DDI_FAILURE);
 416 }