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  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/conf.h>
  28 #include <sys/ddi.h>
  29 #include <sys/modctl.h>
  30 #include <sys/cred.h>
  31 #include <sys/disp.h>
  32 #include <sys/ioccom.h>
  33 #include <sys/policy.h>
  34 #include <sys/cmn_err.h>
  35 #include <smbsrv/smb_kproto.h>
  36 #include <smbsrv/smb_ioctl.h>
  37 
  38 #ifdef  _FAKE_KERNEL
  39 #error  "See libfksmbsrv"
  40 #endif  /* _FAKE_KERNEL */
  41 
  42 static int smb_drv_open(dev_t *, int, int, cred_t *);
  43 static int smb_drv_close(dev_t, int, int, cred_t *);
  44 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
  45 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
  46 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
  47 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
  48 
  49 /*
  50  * *****************************************************************************
  51  * ****************************** Global Variables *****************************
  52  * *****************************************************************************
  53  *
  54  * These variables can only be changed through the /etc/system file.
  55  */
  56 
  57 /*
  58  * Maximum buffer size for NT: configurable based on the client environment.
  59  * IR104720 Experiments with Windows 2000 indicate that we achieve better
  60  * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used
  61  * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory
  62  * listing problems so this buffer size is configurable based on the end-user
  63  * environment. When in doubt use 37KB.
  64  */
  65 int     smb_maxbufsize = SMB_NT_MAXBUF;
  66 int     smb_oplock_levelII = 1;
  67 int     smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
  68 int     smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT;
  69 int     smb_flush_required = 1;
  70 int     smb_dirsymlink_enable = 1;
  71 int     smb_sign_debug = 0;
  72 int     smb_shortnames = 1;
  73 uint_t  smb_audit_flags =
  74 #ifdef  DEBUG
  75     SMB_AUDIT_NODE;
  76 #else
  77     0;
  78 #endif
  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         return (smb_server_delete());
 251 }
 252 
 253 /* ARGSUSED */
 254 static int
 255 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
 256     int *retval)
 257 {
 258         smb_ioc_t       *ioc;
 259         smb_ioc_header_t ioc_hdr;
 260         uint32_t        crc;
 261         boolean_t       copyout = B_FALSE;
 262         int             rc = 0;
 263 
 264         if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t),
 265             flags) || (ioc_hdr.version != SMB_IOC_VERSION))
 266                 return (EFAULT);
 267 
 268         crc = ioc_hdr.crc;
 269         ioc_hdr.crc = 0;
 270         if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
 271                 return (EFAULT);
 272 
 273         ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP);
 274         if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) {
 275                 kmem_free(ioc, ioc_hdr.len);
 276                 return (EFAULT);
 277         }
 278 
 279         switch (cmd) {
 280         case SMB_IOC_CONFIG:
 281                 rc = smb_server_configure(&ioc->ioc_cfg);
 282                 break;
 283         case SMB_IOC_START:
 284                 rc = smb_server_start(&ioc->ioc_start);
 285                 break;
 286         case SMB_IOC_STOP:
 287                 rc = smb_server_stop();
 288                 break;
 289         case SMB_IOC_EVENT:
 290                 rc = smb_server_notify_event(&ioc->ioc_event);
 291                 break;
 292         case SMB_IOC_GMTOFF:
 293                 rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
 294                 break;
 295         case SMB_IOC_SHARE:
 296                 rc = smb_kshare_export_list(&ioc->ioc_share);
 297                 break;
 298         case SMB_IOC_UNSHARE:
 299                 rc = smb_kshare_unexport_list(&ioc->ioc_share);
 300                 break;
 301         case SMB_IOC_SHAREINFO:
 302                 rc = smb_kshare_info(&ioc->ioc_shareinfo);
 303                 copyout = B_TRUE;
 304                 break;
 305         case SMB_IOC_NUMOPEN:
 306                 rc = smb_server_numopen(&ioc->ioc_opennum);
 307                 copyout = B_TRUE;
 308                 break;
 309         case SMB_IOC_SVCENUM:
 310                 rc = smb_server_enum(&ioc->ioc_svcenum);
 311                 copyout = B_TRUE;
 312                 break;
 313         case SMB_IOC_SESSION_CLOSE:
 314                 rc = smb_server_session_close(&ioc->ioc_session);
 315                 break;
 316         case SMB_IOC_FILE_CLOSE:
 317                 rc = smb_server_file_close(&ioc->ioc_fileid);
 318                 break;
 319         case SMB_IOC_SPOOLDOC:
 320                 rc = smb_server_spooldoc(&ioc->ioc_spooldoc);
 321                 copyout = B_TRUE;
 322                 break;
 323         default:
 324                 rc = ENOTTY;
 325                 break;
 326         }
 327         if ((rc == 0) && copyout) {
 328                 if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len,
 329                     flags))
 330                         rc = EFAULT;
 331         }
 332         kmem_free(ioc, ioc_hdr.len);
 333         return (rc);
 334 }
 335 
 336 /*
 337  * ****************************************************************************
 338  *                              Pseudo Device Operations
 339  * ****************************************************************************
 340  */
 341 static int
 342 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 343 {
 344         if (cmd == DDI_ATTACH) {
 345                 /* we only allow instance 0 to attach */
 346                 if (ddi_get_instance(dip) == 0) {
 347                         /* create the minor node */
 348                         if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
 349                             DDI_PSEUDO, 0) == DDI_SUCCESS) {
 350                                 smb_drv_dip = dip;
 351                                 return (DDI_SUCCESS);
 352                         } else {
 353                                 cmn_err(CE_WARN, "smb_drv_attach:"
 354                                     " failed creating minor node");
 355                         }
 356                 }
 357         }
 358         return (DDI_FAILURE);
 359 }
 360 
 361 static int
 362 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 363 {
 364         if (cmd == DDI_DETACH) {
 365                 ASSERT(dip == smb_drv_dip);
 366                 ddi_remove_minor_node(dip, NULL);
 367                 smb_drv_dip = NULL;
 368                 return (DDI_SUCCESS);
 369         }
 370         return (DDI_FAILURE);
 371 }
 372 
 373 /* ARGSUSED */
 374 static int
 375 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 376 {
 377         ulong_t instance = getminor((dev_t)arg);
 378 
 379         switch (cmd) {
 380         case DDI_INFO_DEVT2DEVINFO:
 381                 *result = smb_drv_dip;
 382                 return (DDI_SUCCESS);
 383 
 384         case DDI_INFO_DEVT2INSTANCE:
 385                 *result = (void *)instance;
 386                 return (DDI_SUCCESS);
 387 
 388         default:
 389                 break;
 390         }
 391 
 392         return (DDI_FAILURE);
 393 }