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, NULL }  /* ptr to linkage structures            */
 165 };
 166 
 167 static dev_info_t *smb_drv_dip = NULL;
 168 
 169 /*
 170  * ****************************************************************************
 171  *                                  Module Interface
 172  * ****************************************************************************
 173  */
 174 
 175 int
 176 _init(void)
 177 {
 178         int rc;
 179 
 180         if ((rc = smb_server_g_init()) != 0) {
 181                 return (rc);
 182         }
 183 
 184         if ((rc = mod_install(&modlinkage)) != 0) {
 185                 smb_server_g_fini();
 186         }
 187 
 188         return (rc);
 189 }
 190 
 191 int
 192 _info(struct modinfo *modinfop)
 193 {
 194         return (mod_info(&modlinkage, modinfop));
 195 }
 196 
 197 int
 198 _fini(void)
 199 {
 200         int     rc;
 201 
 202         if (smb_server_get_count() != 0)
 203                 return (EBUSY);
 204 
 205         if ((rc = mod_remove(&modlinkage)) == 0) {
 206                 smb_server_g_fini();
 207         }
 208 
 209         return (rc);
 210 }
 211 
 212 /*
 213  * ****************************************************************************
 214  *                              Pseudo Device Entry Points
 215  * ****************************************************************************
 216  */
 217 /* ARGSUSED */
 218 static int
 219 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr)
 220 {
 221         zoneid_t zid;
 222 
 223         /*
 224          * Check caller's privileges.
 225          */
 226         if (secpolicy_smb(cr) != 0)
 227                 return (EPERM);
 228 
 229         /*
 230          * We need a unique minor per zone otherwise an smbd in any other
 231          * zone will keep this minor open and we won't get a close call.
 232          * The zone ID is good enough as a minor number.
 233          */
 234         zid = crgetzoneid(cr);
 235         if (zid < 0)
 236                 return (ENODEV);
 237         *devp = makedevice(getmajor(*devp), zid);
 238 
 239         /*
 240          * Start SMB service state machine
 241          */
 242         return (smb_server_create());
 243 }
 244 
 245 /* ARGSUSED */
 246 static int
 247 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
 248 {
 249         return (smb_server_delete());
 250 }
 251 
 252 /* ARGSUSED */
 253 static int
 254 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
 255     int *retval)
 256 {
 257         smb_ioc_t       *ioc;
 258         smb_ioc_header_t ioc_hdr;
 259         uint32_t        crc;
 260         boolean_t       copyout = B_FALSE;
 261         int             rc = 0;
 262 
 263         if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t),
 264             flags) || (ioc_hdr.version != SMB_IOC_VERSION))
 265                 return (EFAULT);
 266 
 267         crc = ioc_hdr.crc;
 268         ioc_hdr.crc = 0;
 269         if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
 270                 return (EFAULT);
 271 
 272         ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP);
 273         if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) {
 274                 kmem_free(ioc, ioc_hdr.len);
 275                 return (EFAULT);
 276         }
 277 
 278         switch (cmd) {
 279         case SMB_IOC_CONFIG:
 280                 rc = smb_server_configure(&ioc->ioc_cfg);
 281                 break;
 282         case SMB_IOC_START:
 283                 rc = smb_server_start(&ioc->ioc_start);
 284                 break;
 285         case SMB_IOC_STOP:
 286                 rc = smb_server_stop();
 287                 break;
 288         case SMB_IOC_EVENT:
 289                 rc = smb_server_notify_event(&ioc->ioc_event);
 290                 break;
 291         case SMB_IOC_GMTOFF:
 292                 rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
 293                 break;
 294         case SMB_IOC_SHARE:
 295                 rc = smb_kshare_export_list(&ioc->ioc_share);
 296                 break;
 297         case SMB_IOC_UNSHARE:
 298                 rc = smb_kshare_unexport_list(&ioc->ioc_share);
 299                 break;
 300         case SMB_IOC_SHAREINFO:
 301                 rc = smb_kshare_info(&ioc->ioc_shareinfo);
 302                 copyout = B_TRUE;
 303                 break;
 304         case SMB_IOC_NUMOPEN:
 305                 rc = smb_server_numopen(&ioc->ioc_opennum);
 306                 copyout = B_TRUE;
 307                 break;
 308         case SMB_IOC_SVCENUM:
 309                 rc = smb_server_enum(&ioc->ioc_svcenum);
 310                 copyout = B_TRUE;
 311                 break;
 312         case SMB_IOC_SESSION_CLOSE:
 313                 rc = smb_server_session_close(&ioc->ioc_session);
 314                 break;
 315         case SMB_IOC_FILE_CLOSE:
 316                 rc = smb_server_file_close(&ioc->ioc_fileid);
 317                 break;
 318         case SMB_IOC_SPOOLDOC:
 319                 rc = smb_server_spooldoc(&ioc->ioc_spooldoc);
 320                 copyout = B_TRUE;
 321                 break;
 322         default:
 323                 rc = ENOTTY;
 324                 break;
 325         }
 326         if ((rc == 0) && copyout) {
 327                 if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len,
 328                     flags))
 329                         rc = EFAULT;
 330         }
 331         kmem_free(ioc, ioc_hdr.len);
 332         return (rc);
 333 }
 334 
 335 /*
 336  * ****************************************************************************
 337  *                              Pseudo Device Operations
 338  * ****************************************************************************
 339  */
 340 static int
 341 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 342 {
 343         if (cmd == DDI_ATTACH) {
 344                 /* we only allow instance 0 to attach */
 345                 if (ddi_get_instance(dip) == 0) {
 346                         /* create the minor node */
 347                         if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
 348                             DDI_PSEUDO, 0) == DDI_SUCCESS) {
 349                                 smb_drv_dip = dip;
 350                                 return (DDI_SUCCESS);
 351                         } else {
 352                                 cmn_err(CE_WARN, "smb_drv_attach:"
 353                                     " failed creating minor node");
 354                         }
 355                 }
 356         }
 357         return (DDI_FAILURE);
 358 }
 359 
 360 static int
 361 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 362 {
 363         if (cmd == DDI_DETACH) {
 364                 ASSERT(dip == smb_drv_dip);
 365                 ddi_remove_minor_node(dip, NULL);
 366                 smb_drv_dip = NULL;
 367                 return (DDI_SUCCESS);
 368         }
 369         return (DDI_FAILURE);
 370 }
 371 
 372 /* ARGSUSED */
 373 static int
 374 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 375 {
 376         ulong_t instance = getminor((dev_t)arg);
 377 
 378         switch (cmd) {
 379         case DDI_INFO_DEVT2DEVINFO:
 380                 *result = smb_drv_dip;
 381                 return (DDI_SUCCESS);
 382 
 383         case DDI_INFO_DEVT2INSTANCE:
 384                 *result = (void *)instance;
 385                 return (DDI_SUCCESS);
 386 
 387         default:
 388                 break;
 389         }
 390 
 391         return (DDI_FAILURE);
 392 }