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_flush_required = 1;
  68 int     smb_dirsymlink_enable = 1;
  69 int     smb_sign_debug = 0;
  70 int     smb_shortnames = 1;
  71 uint_t  smb_audit_flags =
  72 #ifdef  DEBUG
  73     SMB_AUDIT_NODE;
  74 #else
  75     0;
  76 #endif
  77 
  78 int smb_allow_advisory_locks = 0;       /* See smb_vops.c */
  79 
  80 /*
  81  * Maximum number of simultaneous authentication, share mapping, pipe open
  82  * requests to be processed.
  83  */
  84 int     smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD;
  85 int     smb_tcon_threshold = 1024;
  86 int     smb_opipe_threshold = 1024;
  87 
  88 /*
  89  * Number of milliseconds that a request will be stalled if it comes in after
  90  * the maximum number of inflight operations are being proccessed.
  91  */
  92 int     smb_ssetup_timeout = (30 * 1000);
  93 int     smb_tcon_timeout = (30 * 1000);
  94 int     smb_opipe_timeout = (30 * 1000);
  95 
  96 /*
  97  * Thread priorities used in smbsrv.  Our threads spend most of their time
  98  * blocked on various conditions.  However, if the system gets heavy load,
  99  * the scheduler has to choose an order to run these.  We want the order:
 100  * (a) timers, (b) notifications, (c) workers, (d) receivers (and etc.)
 101  * where notifications are oplock and change notify work.  Aside from this
 102  * relative ordering, smbsrv threads should run with a priority close to
 103  * that of normal user-space threads (thus minclsyspri below), just like
 104  * NFS and other "file service" kinds of processing.
 105  */
 106 int smbsrv_base_pri     = MINCLSYSPRI;
 107 int smbsrv_listen_pri   = MINCLSYSPRI;
 108 int smbsrv_receive_pri  = MINCLSYSPRI;
 109 int smbsrv_worker_pri   = MINCLSYSPRI + 1;
 110 int smbsrv_notify_pri   = MINCLSYSPRI + 2;
 111 int smbsrv_timer_pri    = MINCLSYSPRI + 5;
 112 
 113 
 114 /*
 115  * *****************************************************************************
 116  * ********************** Static Variables / Module Linkage ********************
 117  * *****************************************************************************
 118  */
 119 
 120 static struct cb_ops cbops = {
 121         smb_drv_open,           /* cb_open */
 122         smb_drv_close,          /* cb_close */
 123         nodev,                  /* cb_strategy */
 124         nodev,                  /* cb_print */
 125         nodev,                  /* cb_dump */
 126         nodev,                  /* cb_read */
 127         nodev,                  /* cb_write */
 128         smb_drv_ioctl,          /* cb_ioctl */
 129         nodev,                  /* cb_devmap */
 130         nodev,                  /* cb_mmap */
 131         nodev,                  /* cb_segmap */
 132         nochpoll,               /* cb_chpoll */
 133         ddi_prop_op,            /* cb_prop_op */
 134         NULL,                   /* cb_streamtab */
 135         D_MP,                   /* cb_flag */
 136         CB_REV,                 /* cb_rev */
 137         nodev,                  /* cb_aread */
 138         nodev,                  /* cb_awrite */
 139 };
 140 
 141 static struct dev_ops devops = {
 142         DEVO_REV,               /* devo_rev */
 143         0,                      /* devo_refcnt */
 144         smb_drv_getinfo,        /* devo_getinfo */
 145         nulldev,                /* devo_identify */
 146         nulldev,                /* devo_probe */
 147         smb_drv_attach,         /* devo_attach */
 148         smb_drv_detach,         /* devo_detach */
 149         nodev,                  /* devo_reset */
 150         &cbops,                     /* devo_cb_ops */
 151         NULL,                   /* devo_bus_ops */
 152         NULL,                   /* devo_power */
 153         ddi_quiesce_not_needed,         /* devo_quiesce */
 154 };
 155 
 156 static struct modldrv modldrv = {
 157         &mod_driverops,                                     /* drv_modops */
 158         "CIFS Server Protocol",                         /* drv_linkinfo */
 159         &devops,
 160 };
 161 
 162 static struct modlinkage modlinkage = {
 163         MODREV_1,       /* revision of the module, must be: MODREV_1    */
 164         &modldrv,   /* ptr to linkage structures                    */
 165         NULL,
 166 };
 167 
 168 static dev_info_t *smb_drv_dip = NULL;
 169 
 170 /*
 171  * ****************************************************************************
 172  *                                  Module Interface
 173  * ****************************************************************************
 174  */
 175 
 176 int
 177 _init(void)
 178 {
 179         int rc;
 180 
 181         if ((rc = smb_server_g_init()) != 0) {
 182                 return (rc);
 183         }
 184 
 185         if ((rc = mod_install(&modlinkage)) != 0) {
 186                 smb_server_g_fini();
 187         }
 188 
 189         return (rc);
 190 }
 191 
 192 int
 193 _info(struct modinfo *modinfop)
 194 {
 195         return (mod_info(&modlinkage, modinfop));
 196 }
 197 
 198 int
 199 _fini(void)
 200 {
 201         int     rc;
 202 
 203         if (smb_server_get_count() != 0)
 204                 return (EBUSY);
 205 
 206         if ((rc = mod_remove(&modlinkage)) == 0) {
 207                 smb_server_g_fini();
 208         }
 209 
 210         return (rc);
 211 }
 212 
 213 /*
 214  * ****************************************************************************
 215  *                              Pseudo Device Entry Points
 216  * ****************************************************************************
 217  */
 218 /* ARGSUSED */
 219 static int
 220 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr)
 221 {
 222         zoneid_t zid;
 223 
 224         /*
 225          * Check caller's privileges.
 226          */
 227         if (secpolicy_smb(cr) != 0)
 228                 return (EPERM);
 229 
 230         /*
 231          * We need a unique minor per zone otherwise an smbd in any other
 232          * zone will keep this minor open and we won't get a close call.
 233          * The zone ID is good enough as a minor number.
 234          */
 235         zid = crgetzoneid(cr);
 236         if (zid < 0)
 237                 return (ENODEV);
 238         *devp = makedevice(getmajor(*devp), zid);
 239 
 240         /*
 241          * Start SMB service state machine
 242          */
 243         return (smb_server_create());
 244 }
 245 
 246 /* ARGSUSED */
 247 static int
 248 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
 249 {
 250         smb_server_t    *sv;
 251         int             rc;
 252 
 253         rc = smb_server_lookup(&sv);
 254         if (rc == 0)
 255                 rc = smb_server_delete(sv);
 256 
 257         return (rc);
 258 }
 259 
 260 /* ARGSUSED */
 261 static int
 262 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
 263     int *retval)
 264 {
 265         smb_ioc_t       *ioc;
 266         smb_ioc_header_t ioc_hdr;
 267         uint32_t        crc;
 268         boolean_t       copyout = B_FALSE;
 269         int             rc = 0;
 270         size_t          alloclen;
 271 
 272         if (ddi_copyin((void *)argp, &ioc_hdr, sizeof (ioc_hdr), flags))
 273                 return (EFAULT);
 274 
 275         /*
 276          * Check version and length.
 277          *
 278          * Note that some ioctls (i.e. SMB_IOC_SVCENUM) have payload
 279          * data after the ioctl struct, in which case they specify a
 280          * length much larger than sizeof smb_ioc_t.  The theoretical
 281          * largest ioctl data is therefore the size of the union plus
 282          * the max size of the payload (which is SMB_IOC_DATA_SIZE).
 283          */
 284         if (ioc_hdr.version != SMB_IOC_VERSION ||
 285             ioc_hdr.len < sizeof (ioc_hdr) ||
 286             ioc_hdr.len > (sizeof (*ioc) + SMB_IOC_DATA_SIZE))
 287                 return (EINVAL);
 288 
 289         crc = ioc_hdr.crc;
 290         ioc_hdr.crc = 0;
 291         if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
 292                 return (EINVAL);
 293 
 294         /*
 295          * Note that smb_ioc_t is a union, and callers set ioc_hdr.len
 296          * to the size of the actual union arm.  If some caller were to
 297          * set that size too small, we could end up passing under-sized
 298          * memory to one of the type-specific handler functions.  Avoid
 299          * that problem by allocating at least the size of the union,
 300          * (zeroed out) and then copy in the caller specified length.
 301          */
 302         alloclen = MAX(ioc_hdr.len, sizeof (*ioc));
 303         ioc = kmem_zalloc(alloclen, KM_SLEEP);
 304         if (ddi_copyin((void *)argp, ioc, ioc_hdr.len, flags)) {
 305                 kmem_free(ioc, alloclen);
 306                 return (EFAULT);
 307         }
 308 
 309         switch (cmd) {
 310         case SMB_IOC_CONFIG:
 311                 rc = smb_server_configure(&ioc->ioc_cfg);
 312                 break;
 313         case SMB_IOC_START:
 314                 rc = smb_server_start(&ioc->ioc_start);
 315                 break;
 316         case SMB_IOC_STOP:
 317                 rc = smb_server_stop();
 318                 break;
 319         case SMB_IOC_EVENT:
 320                 rc = smb_server_notify_event(&ioc->ioc_event);
 321                 break;
 322         case SMB_IOC_GMTOFF:
 323                 rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
 324                 break;
 325         case SMB_IOC_SHARE:
 326                 rc = smb_kshare_export_list(&ioc->ioc_share);
 327                 break;
 328         case SMB_IOC_UNSHARE:
 329                 rc = smb_kshare_unexport_list(&ioc->ioc_share);
 330                 break;
 331         case SMB_IOC_SHAREINFO:
 332                 rc = smb_kshare_info(&ioc->ioc_shareinfo);
 333                 copyout = B_TRUE;
 334                 break;
 335         case SMB_IOC_NUMOPEN:
 336                 rc = smb_server_numopen(&ioc->ioc_opennum);
 337                 copyout = B_TRUE;
 338                 break;
 339         case SMB_IOC_SVCENUM:
 340                 rc = smb_server_enum(&ioc->ioc_svcenum);
 341                 copyout = B_TRUE;
 342                 break;
 343         case SMB_IOC_SESSION_CLOSE:
 344                 rc = smb_server_session_close(&ioc->ioc_session);
 345                 break;
 346         case SMB_IOC_FILE_CLOSE:
 347                 rc = smb_server_file_close(&ioc->ioc_fileid);
 348                 break;
 349         case SMB_IOC_SPOOLDOC:
 350                 rc = smb_server_spooldoc(&ioc->ioc_spooldoc);
 351                 copyout = B_TRUE;
 352                 break;
 353         default:
 354                 rc = ENOTTY;
 355                 break;
 356         }
 357         if ((rc == 0) && copyout) {
 358                 if (ddi_copyout(ioc, (void *)argp, ioc_hdr.len, flags))
 359                         rc = EFAULT;
 360         }
 361         kmem_free(ioc, alloclen);
 362         return (rc);
 363 }
 364 
 365 /*
 366  * ****************************************************************************
 367  *                              Pseudo Device Operations
 368  * ****************************************************************************
 369  */
 370 static int
 371 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 372 {
 373         if (cmd == DDI_ATTACH) {
 374                 /* we only allow instance 0 to attach */
 375                 if (ddi_get_instance(dip) == 0) {
 376                         /* create the minor node */
 377                         if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
 378                             DDI_PSEUDO, 0) == DDI_SUCCESS) {
 379                                 smb_drv_dip = dip;
 380                                 return (DDI_SUCCESS);
 381                         } else {
 382                                 cmn_err(CE_WARN, "smb_drv_attach:"
 383                                     " failed creating minor node");
 384                         }
 385                 }
 386         }
 387         return (DDI_FAILURE);
 388 }
 389 
 390 static int
 391 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 392 {
 393         if (cmd == DDI_DETACH) {
 394                 ASSERT(dip == smb_drv_dip);
 395                 ddi_remove_minor_node(dip, NULL);
 396                 smb_drv_dip = NULL;
 397                 return (DDI_SUCCESS);
 398         }
 399         return (DDI_FAILURE);
 400 }
 401 
 402 /* ARGSUSED */
 403 static int
 404 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 405 {
 406         ulong_t instance = getminor((dev_t)arg);
 407 
 408         switch (cmd) {
 409         case DDI_INFO_DEVT2DEVINFO:
 410                 *result = smb_drv_dip;
 411                 return (DDI_SUCCESS);
 412 
 413         case DDI_INFO_DEVT2INSTANCE:
 414                 *result = (void *)instance;
 415                 return (DDI_SUCCESS);
 416 
 417         default:
 418                 break;
 419         }
 420 
 421         return (DDI_FAILURE);
 422 }