1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2312b65585SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <sys/types.h> 27b819cea2SGordon Ross #include <sys/conf.h> 28da6c28aaSamw #include <sys/ddi.h> 29da6c28aaSamw #include <sys/modctl.h> 30da6c28aaSamw #include <sys/cred.h> 3108344b29SGordon Ross #include <sys/disp.h> 32da6c28aaSamw #include <sys/ioccom.h> 33da6c28aaSamw #include <sys/policy.h> 3494fff790SAlan Wright #include <sys/cmn_err.h> 35bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 36da6c28aaSamw #include <smbsrv/smb_ioctl.h> 37faa1795aSjb150015 38b819cea2SGordon Ross #ifdef _FAKE_KERNEL 39b819cea2SGordon Ross #error "See libfksmbsrv" 40b819cea2SGordon Ross #endif /* _FAKE_KERNEL */ 41b819cea2SGordon Ross 42faa1795aSjb150015 static int smb_drv_open(dev_t *, int, int, cred_t *); 43faa1795aSjb150015 static int smb_drv_close(dev_t, int, int, cred_t *); 44faa1795aSjb150015 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 45da6c28aaSamw static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 46da6c28aaSamw static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 47da6c28aaSamw static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 48da6c28aaSamw 49da6c28aaSamw /* 50faa1795aSjb150015 * ***************************************************************************** 51faa1795aSjb150015 * ****************************** Global Variables ***************************** 52faa1795aSjb150015 * ***************************************************************************** 53faa1795aSjb150015 * 54faa1795aSjb150015 * These variables can only be changed through the /etc/system file. 55da6c28aaSamw */ 56faa1795aSjb150015 57faa1795aSjb150015 /* 58faa1795aSjb150015 * Maximum buffer size for NT: configurable based on the client environment. 59faa1795aSjb150015 * IR104720 Experiments with Windows 2000 indicate that we achieve better 60faa1795aSjb150015 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 61faa1795aSjb150015 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 62faa1795aSjb150015 * listing problems so this buffer size is configurable based on the end-user 63faa1795aSjb150015 * environment. When in doubt use 37KB. 64faa1795aSjb150015 */ 65faa1795aSjb150015 int smb_maxbufsize = SMB_NT_MAXBUF; 66cb174861Sjoyce mcintosh int smb_oplock_levelII = 1; 672c2961f8Sjose borrego int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 68cb174861Sjoyce mcintosh int smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT; 69faa1795aSjb150015 int smb_flush_required = 1; 70faa1795aSjb150015 int smb_dirsymlink_enable = 1; 71c8ec8eeaSjose borrego int smb_sign_debug = 0; 72cb174861Sjoyce mcintosh int smb_shortnames = 1; 732c2961f8Sjose borrego uint_t smb_audit_flags = 742c2961f8Sjose borrego #ifdef DEBUG 752c2961f8Sjose borrego SMB_AUDIT_NODE; 762c2961f8Sjose borrego #else 772c2961f8Sjose borrego 0; 782c2961f8Sjose borrego #endif 79faa1795aSjb150015 80faa1795aSjb150015 /* 81cb174861Sjoyce mcintosh * Maximum number of simultaneous authentication, share mapping, pipe open 82cb174861Sjoyce mcintosh * requests to be processed. 83cb174861Sjoyce mcintosh */ 8412b65585SGordon Ross int smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD; 85cb174861Sjoyce mcintosh int smb_tcon_threshold = 1024; 86cb174861Sjoyce mcintosh int smb_opipe_threshold = 1024; 87cb174861Sjoyce mcintosh 88cb174861Sjoyce mcintosh /* 89cb174861Sjoyce mcintosh * Number of milliseconds that a request will be stalled if it comes in after 90cb174861Sjoyce mcintosh * the maximum number of inflight operations are being proccessed. 91cb174861Sjoyce mcintosh */ 92cb174861Sjoyce mcintosh int smb_ssetup_timeout = (30 * 1000); 93cb174861Sjoyce mcintosh int smb_tcon_timeout = (30 * 1000); 94cb174861Sjoyce mcintosh int smb_opipe_timeout = (30 * 1000); 95cb174861Sjoyce mcintosh 9608344b29SGordon Ross /* 9708344b29SGordon Ross * Thread priorities used in smbsrv. Our threads spend most of their time 9808344b29SGordon Ross * blocked on various conditions. However, if the system gets heavy load, 9908344b29SGordon Ross * the scheduler has to choose an order to run these. We want the order: 10008344b29SGordon Ross * (a) timers, (b) notifications, (c) workers, (d) receivers (and etc.) 10108344b29SGordon Ross * where notifications are oplock and change notify work. Aside from this 10208344b29SGordon Ross * relative ordering, smbsrv threads should run with a priority close to 10308344b29SGordon Ross * that of normal user-space threads (thus minclsyspri below), just like 10408344b29SGordon Ross * NFS and other "file service" kinds of processing. 10508344b29SGordon Ross */ 10608344b29SGordon Ross int smbsrv_base_pri = MINCLSYSPRI; 10708344b29SGordon Ross int smbsrv_listen_pri = MINCLSYSPRI; 10808344b29SGordon Ross int smbsrv_receive_pri = MINCLSYSPRI; 10908344b29SGordon Ross int smbsrv_worker_pri = MINCLSYSPRI + 1; 11008344b29SGordon Ross int smbsrv_notify_pri = MINCLSYSPRI + 2; 11108344b29SGordon Ross int smbsrv_timer_pri = MINCLSYSPRI + 5; 11208344b29SGordon Ross 113cb174861Sjoyce mcintosh 114cb174861Sjoyce mcintosh /* 115faa1795aSjb150015 * ***************************************************************************** 116faa1795aSjb150015 * ********************** Static Variables / Module Linkage ******************** 117faa1795aSjb150015 * ***************************************************************************** 118faa1795aSjb150015 */ 119faa1795aSjb150015 120da6c28aaSamw static struct cb_ops cbops = { 121da6c28aaSamw smb_drv_open, /* cb_open */ 122da6c28aaSamw smb_drv_close, /* cb_close */ 123da6c28aaSamw nodev, /* cb_strategy */ 124da6c28aaSamw nodev, /* cb_print */ 125da6c28aaSamw nodev, /* cb_dump */ 126da6c28aaSamw nodev, /* cb_read */ 127da6c28aaSamw nodev, /* cb_write */ 128da6c28aaSamw smb_drv_ioctl, /* cb_ioctl */ 129da6c28aaSamw nodev, /* cb_devmap */ 130da6c28aaSamw nodev, /* cb_mmap */ 131da6c28aaSamw nodev, /* cb_segmap */ 132da6c28aaSamw nochpoll, /* cb_chpoll */ 133da6c28aaSamw ddi_prop_op, /* cb_prop_op */ 134da6c28aaSamw NULL, /* cb_streamtab */ 135da6c28aaSamw D_MP, /* cb_flag */ 136da6c28aaSamw CB_REV, /* cb_rev */ 137da6c28aaSamw nodev, /* cb_aread */ 138da6c28aaSamw nodev, /* cb_awrite */ 139da6c28aaSamw }; 140da6c28aaSamw 141da6c28aaSamw static struct dev_ops devops = { 142da6c28aaSamw DEVO_REV, /* devo_rev */ 143da6c28aaSamw 0, /* devo_refcnt */ 144da6c28aaSamw smb_drv_getinfo, /* devo_getinfo */ 145da6c28aaSamw nulldev, /* devo_identify */ 146da6c28aaSamw nulldev, /* devo_probe */ 147da6c28aaSamw smb_drv_attach, /* devo_attach */ 148da6c28aaSamw smb_drv_detach, /* devo_detach */ 149da6c28aaSamw nodev, /* devo_reset */ 150da6c28aaSamw &cbops, /* devo_cb_ops */ 151da6c28aaSamw NULL, /* devo_bus_ops */ 152da6c28aaSamw NULL, /* devo_power */ 15319397407SSherry Moore ddi_quiesce_not_needed, /* devo_quiesce */ 154da6c28aaSamw }; 155da6c28aaSamw 156da6c28aaSamw static struct modldrv modldrv = { 157da6c28aaSamw &mod_driverops, /* drv_modops */ 15819397407SSherry Moore "CIFS Server Protocol", /* drv_linkinfo */ 159da6c28aaSamw &devops, 160da6c28aaSamw }; 161da6c28aaSamw 162da6c28aaSamw static struct modlinkage modlinkage = { 163da6c28aaSamw MODREV_1, /* revision of the module, must be: MODREV_1 */ 164da6c28aaSamw &modldrv, /* ptr to linkage structures */ 165da6c28aaSamw NULL, 166da6c28aaSamw }; 167da6c28aaSamw 168da6c28aaSamw static dev_info_t *smb_drv_dip = NULL; 169da6c28aaSamw 170da6c28aaSamw /* 171faa1795aSjb150015 * **************************************************************************** 172faa1795aSjb150015 * Module Interface 173faa1795aSjb150015 * **************************************************************************** 174da6c28aaSamw */ 175da6c28aaSamw 176da6c28aaSamw int 177da6c28aaSamw _init(void) 178da6c28aaSamw { 179f9a15d2cSjose borrego int rc; 180f9a15d2cSjose borrego 1818622ec45SGordon Ross if ((rc = smb_server_g_init()) != 0) { 182148c5f43SAlan Wright return (rc); 183148c5f43SAlan Wright } 184148c5f43SAlan Wright 185148c5f43SAlan Wright if ((rc = mod_install(&modlinkage)) != 0) { 186*a90cf9f2SGordon Ross smb_server_g_fini(); 187f9a15d2cSjose borrego } 188148c5f43SAlan Wright 189f9a15d2cSjose borrego return (rc); 190da6c28aaSamw } 191da6c28aaSamw 192da6c28aaSamw int 193da6c28aaSamw _info(struct modinfo *modinfop) 194da6c28aaSamw { 195da6c28aaSamw return (mod_info(&modlinkage, modinfop)); 196da6c28aaSamw } 197da6c28aaSamw 198da6c28aaSamw int 199da6c28aaSamw _fini(void) 200da6c28aaSamw { 201f9a15d2cSjose borrego int rc; 202f9a15d2cSjose borrego 203*a90cf9f2SGordon Ross if (smb_server_get_count() != 0) 204*a90cf9f2SGordon Ross return (EBUSY); 205*a90cf9f2SGordon Ross 206148c5f43SAlan Wright if ((rc = mod_remove(&modlinkage)) == 0) { 207*a90cf9f2SGordon Ross smb_server_g_fini(); 208148c5f43SAlan Wright } 209148c5f43SAlan Wright 210f9a15d2cSjose borrego return (rc); 211da6c28aaSamw } 212da6c28aaSamw 213faa1795aSjb150015 /* 214faa1795aSjb150015 * **************************************************************************** 215faa1795aSjb150015 * Pseudo Device Entry Points 216faa1795aSjb150015 * **************************************************************************** 217faa1795aSjb150015 */ 218faa1795aSjb150015 /* ARGSUSED */ 219faa1795aSjb150015 static int 2208622ec45SGordon Ross smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 221faa1795aSjb150015 { 2228622ec45SGordon Ross zoneid_t zid; 2238622ec45SGordon Ross 224faa1795aSjb150015 /* 225faa1795aSjb150015 * Check caller's privileges. 226faa1795aSjb150015 */ 2278622ec45SGordon Ross if (secpolicy_smb(cr) != 0) 228faa1795aSjb150015 return (EPERM); 229faa1795aSjb150015 230faa1795aSjb150015 /* 2318622ec45SGordon Ross * We need a unique minor per zone otherwise an smbd in any other 2328622ec45SGordon Ross * zone will keep this minor open and we won't get a close call. 2338622ec45SGordon Ross * The zone ID is good enough as a minor number. 2348622ec45SGordon Ross */ 2358622ec45SGordon Ross zid = crgetzoneid(cr); 2368622ec45SGordon Ross if (zid < 0) 2378622ec45SGordon Ross return (ENODEV); 2388622ec45SGordon Ross *devp = makedevice(getmajor(*devp), zid); 2398622ec45SGordon Ross 2408622ec45SGordon Ross /* 241faa1795aSjb150015 * Start SMB service state machine 242faa1795aSjb150015 */ 243faa1795aSjb150015 return (smb_server_create()); 244faa1795aSjb150015 } 245faa1795aSjb150015 246faa1795aSjb150015 /* ARGSUSED */ 247faa1795aSjb150015 static int 248faa1795aSjb150015 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 249faa1795aSjb150015 { 250faa1795aSjb150015 return (smb_server_delete()); 251faa1795aSjb150015 } 252faa1795aSjb150015 253faa1795aSjb150015 /* ARGSUSED */ 254faa1795aSjb150015 static int 25529bd2886SAlan Wright smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 256faa1795aSjb150015 int *retval) 257faa1795aSjb150015 { 25829bd2886SAlan Wright smb_ioc_t *ioc; 25929bd2886SAlan Wright smb_ioc_header_t ioc_hdr; 26029bd2886SAlan Wright uint32_t crc; 26129bd2886SAlan Wright boolean_t copyout = B_FALSE; 262faa1795aSjb150015 int rc = 0; 263faa1795aSjb150015 26429bd2886SAlan Wright if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t), 26529bd2886SAlan Wright flags) || (ioc_hdr.version != SMB_IOC_VERSION)) 266faa1795aSjb150015 return (EFAULT); 267faa1795aSjb150015 26829bd2886SAlan Wright crc = ioc_hdr.crc; 26929bd2886SAlan Wright ioc_hdr.crc = 0; 27029bd2886SAlan Wright if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 27194fff790SAlan Wright return (EFAULT); 27294fff790SAlan Wright 27329bd2886SAlan Wright ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP); 27429bd2886SAlan Wright if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) { 27529bd2886SAlan Wright kmem_free(ioc, ioc_hdr.len); 27629bd2886SAlan Wright return (EFAULT); 27729bd2886SAlan Wright } 27829bd2886SAlan Wright 279faa1795aSjb150015 switch (cmd) { 280faa1795aSjb150015 case SMB_IOC_CONFIG: 28129bd2886SAlan Wright rc = smb_server_configure(&ioc->ioc_cfg); 282faa1795aSjb150015 break; 283faa1795aSjb150015 case SMB_IOC_START: 28429bd2886SAlan Wright rc = smb_server_start(&ioc->ioc_start); 285faa1795aSjb150015 break; 2869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States case SMB_IOC_STOP: 2879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_server_stop(); 2889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break; 2899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States case SMB_IOC_EVENT: 2909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rc = smb_server_notify_event(&ioc->ioc_event); 2919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break; 292faa1795aSjb150015 case SMB_IOC_GMTOFF: 29329bd2886SAlan Wright rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 29429bd2886SAlan Wright break; 29529bd2886SAlan Wright case SMB_IOC_SHARE: 296148c5f43SAlan Wright rc = smb_kshare_export_list(&ioc->ioc_share); 29729bd2886SAlan Wright break; 29829bd2886SAlan Wright case SMB_IOC_UNSHARE: 299148c5f43SAlan Wright rc = smb_kshare_unexport_list(&ioc->ioc_share); 30029bd2886SAlan Wright break; 301cb174861Sjoyce mcintosh case SMB_IOC_SHAREINFO: 302cb174861Sjoyce mcintosh rc = smb_kshare_info(&ioc->ioc_shareinfo); 303cb174861Sjoyce mcintosh copyout = B_TRUE; 304cb174861Sjoyce mcintosh break; 3051fcced4cSJordan Brown case SMB_IOC_NUMOPEN: 3061fcced4cSJordan Brown rc = smb_server_numopen(&ioc->ioc_opennum); 30729bd2886SAlan Wright copyout = B_TRUE; 30829bd2886SAlan Wright break; 3091fcced4cSJordan Brown case SMB_IOC_SVCENUM: 3101fcced4cSJordan Brown rc = smb_server_enum(&ioc->ioc_svcenum); 31129bd2886SAlan Wright copyout = B_TRUE; 312faa1795aSjb150015 break; 3131fcced4cSJordan Brown case SMB_IOC_SESSION_CLOSE: 3141fcced4cSJordan Brown rc = smb_server_session_close(&ioc->ioc_session); 3151fcced4cSJordan Brown break; 3161fcced4cSJordan Brown case SMB_IOC_FILE_CLOSE: 3171fcced4cSJordan Brown rc = smb_server_file_close(&ioc->ioc_fileid); 3181fcced4cSJordan Brown break; 319cb174861Sjoyce mcintosh case SMB_IOC_SPOOLDOC: 320cb174861Sjoyce mcintosh rc = smb_server_spooldoc(&ioc->ioc_spooldoc); 321cb174861Sjoyce mcintosh copyout = B_TRUE; 322cb174861Sjoyce mcintosh break; 323faa1795aSjb150015 default: 324faa1795aSjb150015 rc = ENOTTY; 325faa1795aSjb150015 break; 326faa1795aSjb150015 } 32729bd2886SAlan Wright if ((rc == 0) && copyout) { 32829bd2886SAlan Wright if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len, 32929bd2886SAlan Wright flags)) 33029bd2886SAlan Wright rc = EFAULT; 33129bd2886SAlan Wright } 33229bd2886SAlan Wright kmem_free(ioc, ioc_hdr.len); 333da6c28aaSamw return (rc); 334da6c28aaSamw } 335da6c28aaSamw 336da6c28aaSamw /* 337faa1795aSjb150015 * **************************************************************************** 338faa1795aSjb150015 * Pseudo Device Operations 339faa1795aSjb150015 * **************************************************************************** 340da6c28aaSamw */ 341faa1795aSjb150015 static int 342faa1795aSjb150015 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 343faa1795aSjb150015 { 344faa1795aSjb150015 if (cmd == DDI_ATTACH) { 345faa1795aSjb150015 /* we only allow instance 0 to attach */ 346faa1795aSjb150015 if (ddi_get_instance(dip) == 0) { 347faa1795aSjb150015 /* create the minor node */ 348faa1795aSjb150015 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 349faa1795aSjb150015 DDI_PSEUDO, 0) == DDI_SUCCESS) { 350faa1795aSjb150015 smb_drv_dip = dip; 351faa1795aSjb150015 return (DDI_SUCCESS); 352faa1795aSjb150015 } else { 353faa1795aSjb150015 cmn_err(CE_WARN, "smb_drv_attach:" 354faa1795aSjb150015 " failed creating minor node"); 355faa1795aSjb150015 } 356faa1795aSjb150015 } 357faa1795aSjb150015 } 358faa1795aSjb150015 return (DDI_FAILURE); 359faa1795aSjb150015 } 360faa1795aSjb150015 361faa1795aSjb150015 static int 362faa1795aSjb150015 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 363faa1795aSjb150015 { 364faa1795aSjb150015 if (cmd == DDI_DETACH) { 365faa1795aSjb150015 ASSERT(dip == smb_drv_dip); 366faa1795aSjb150015 ddi_remove_minor_node(dip, NULL); 367faa1795aSjb150015 smb_drv_dip = NULL; 368faa1795aSjb150015 return (DDI_SUCCESS); 369faa1795aSjb150015 } 370faa1795aSjb150015 return (DDI_FAILURE); 371faa1795aSjb150015 } 372da6c28aaSamw 373da6c28aaSamw /* ARGSUSED */ 374da6c28aaSamw static int 375da6c28aaSamw smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 376da6c28aaSamw { 377da6c28aaSamw ulong_t instance = getminor((dev_t)arg); 378da6c28aaSamw 379da6c28aaSamw switch (cmd) { 380da6c28aaSamw case DDI_INFO_DEVT2DEVINFO: 381da6c28aaSamw *result = smb_drv_dip; 382da6c28aaSamw return (DDI_SUCCESS); 383da6c28aaSamw 384da6c28aaSamw case DDI_INFO_DEVT2INSTANCE: 385da6c28aaSamw *result = (void *)instance; 386da6c28aaSamw return (DDI_SUCCESS); 387da6c28aaSamw 388da6c28aaSamw default: 389da6c28aaSamw break; 390da6c28aaSamw } 391da6c28aaSamw 392da6c28aaSamw return (DDI_FAILURE); 393da6c28aaSamw } 394