15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 22*12508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 235331Samw */ 245331Samw 255331Samw #include <sys/types.h> 265331Samw #include <sys/ddi.h> 275331Samw #include <sys/modctl.h> 285331Samw #include <sys/cred.h> 295331Samw #include <sys/ioccom.h> 305331Samw #include <sys/policy.h> 318167Samw@Sun.COM #include <sys/cmn_err.h> 3210966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 335331Samw #include <smbsrv/smb_ioctl.h> 346139Sjb150015 356139Sjb150015 static int smb_drv_open(dev_t *, int, int, cred_t *); 366139Sjb150015 static int smb_drv_close(dev_t, int, int, cred_t *); 376139Sjb150015 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 385331Samw static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 395331Samw static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 405331Samw static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 416139Sjb150015 426139Sjb150015 /* 436139Sjb150015 * ***************************************************************************** 446139Sjb150015 * ****************************** Global Variables ***************************** 456139Sjb150015 * ***************************************************************************** 466139Sjb150015 * 476139Sjb150015 * These variables can only be changed through the /etc/system file. 486139Sjb150015 */ 495331Samw 505331Samw /* 516139Sjb150015 * Maximum buffer size for NT: configurable based on the client environment. 526139Sjb150015 * IR104720 Experiments with Windows 2000 indicate that we achieve better 536139Sjb150015 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 546139Sjb150015 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 556139Sjb150015 * listing problems so this buffer size is configurable based on the end-user 566139Sjb150015 * environment. When in doubt use 37KB. 575331Samw */ 586139Sjb150015 int smb_maxbufsize = SMB_NT_MAXBUF; 598934SJose.Borrego@Sun.COM int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 606139Sjb150015 int smb_flush_required = 1; 616139Sjb150015 int smb_dirsymlink_enable = 1; 627348SJose.Borrego@Sun.COM int smb_sign_debug = 0; 638934SJose.Borrego@Sun.COM uint_t smb_audit_flags = 648934SJose.Borrego@Sun.COM #ifdef DEBUG 658934SJose.Borrego@Sun.COM SMB_AUDIT_NODE; 668934SJose.Borrego@Sun.COM #else 678934SJose.Borrego@Sun.COM 0; 688934SJose.Borrego@Sun.COM #endif 696139Sjb150015 706139Sjb150015 /* 716139Sjb150015 * ***************************************************************************** 726139Sjb150015 * ********************** Static Variables / Module Linkage ******************** 736139Sjb150015 * ***************************************************************************** 746139Sjb150015 */ 756139Sjb150015 765331Samw static struct cb_ops cbops = { 775331Samw smb_drv_open, /* cb_open */ 785331Samw smb_drv_close, /* cb_close */ 795331Samw nodev, /* cb_strategy */ 805331Samw nodev, /* cb_print */ 815331Samw nodev, /* cb_dump */ 825331Samw nodev, /* cb_read */ 835331Samw nodev, /* cb_write */ 845331Samw smb_drv_ioctl, /* cb_ioctl */ 855331Samw nodev, /* cb_devmap */ 865331Samw nodev, /* cb_mmap */ 875331Samw nodev, /* cb_segmap */ 885331Samw nochpoll, /* cb_chpoll */ 895331Samw ddi_prop_op, /* cb_prop_op */ 905331Samw NULL, /* cb_streamtab */ 915331Samw D_MP, /* cb_flag */ 925331Samw CB_REV, /* cb_rev */ 935331Samw nodev, /* cb_aread */ 945331Samw nodev, /* cb_awrite */ 955331Samw }; 965331Samw 975331Samw static struct dev_ops devops = { 985331Samw DEVO_REV, /* devo_rev */ 995331Samw 0, /* devo_refcnt */ 1005331Samw smb_drv_getinfo, /* devo_getinfo */ 1015331Samw nulldev, /* devo_identify */ 1025331Samw nulldev, /* devo_probe */ 1035331Samw smb_drv_attach, /* devo_attach */ 1045331Samw smb_drv_detach, /* devo_detach */ 1055331Samw nodev, /* devo_reset */ 1065331Samw &cbops, /* devo_cb_ops */ 1075331Samw NULL, /* devo_bus_ops */ 1085331Samw NULL, /* devo_power */ 1097656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */ 1105331Samw }; 1115331Samw 1125331Samw static struct modldrv modldrv = { 1135331Samw &mod_driverops, /* drv_modops */ 1147656SSherry.Moore@Sun.COM "CIFS Server Protocol", /* drv_linkinfo */ 1155331Samw &devops, 1165331Samw }; 1175331Samw 1185331Samw static struct modlinkage modlinkage = { 1195331Samw MODREV_1, /* revision of the module, must be: MODREV_1 */ 1205331Samw &modldrv, /* ptr to linkage structures */ 1215331Samw NULL, 1225331Samw }; 1235331Samw 1245331Samw static dev_info_t *smb_drv_dip = NULL; 1255331Samw 1265331Samw /* 1276139Sjb150015 * **************************************************************************** 1286139Sjb150015 * Module Interface 1296139Sjb150015 * **************************************************************************** 1305331Samw */ 1315331Samw 1325331Samw int 1335331Samw _init(void) 1345331Samw { 135*12508Samw@Sun.COM int rc; 136*12508Samw@Sun.COM 137*12508Samw@Sun.COM if ((rc = smb_kshare_init()) != 0) 138*12508Samw@Sun.COM return (rc); 1398473SJose.Borrego@Sun.COM 140*12508Samw@Sun.COM if ((rc = smb_server_svc_init()) != 0) { 141*12508Samw@Sun.COM smb_kshare_fini(); 142*12508Samw@Sun.COM return (rc); 1438473SJose.Borrego@Sun.COM } 144*12508Samw@Sun.COM 145*12508Samw@Sun.COM if ((rc = mod_install(&modlinkage)) != 0) { 146*12508Samw@Sun.COM smb_kshare_fini(); 147*12508Samw@Sun.COM (void) smb_server_svc_fini(); 148*12508Samw@Sun.COM } 149*12508Samw@Sun.COM 1508473SJose.Borrego@Sun.COM return (rc); 1515331Samw } 1525331Samw 1535331Samw int 1545331Samw _info(struct modinfo *modinfop) 1555331Samw { 1565331Samw return (mod_info(&modlinkage, modinfop)); 1575331Samw } 1585331Samw 1595331Samw int 1605331Samw _fini(void) 1615331Samw { 1628473SJose.Borrego@Sun.COM int rc; 1638473SJose.Borrego@Sun.COM 164*12508Samw@Sun.COM if ((rc = mod_remove(&modlinkage)) == 0) { 1658473SJose.Borrego@Sun.COM rc = smb_server_svc_fini(); 166*12508Samw@Sun.COM smb_kshare_fini(); 167*12508Samw@Sun.COM } 168*12508Samw@Sun.COM 1698473SJose.Borrego@Sun.COM return (rc); 1706139Sjb150015 } 1716139Sjb150015 1726139Sjb150015 /* 1736139Sjb150015 * **************************************************************************** 1746139Sjb150015 * Pseudo Device Entry Points 1756139Sjb150015 * **************************************************************************** 1766139Sjb150015 */ 1776139Sjb150015 /* ARGSUSED */ 1786139Sjb150015 static int 1796139Sjb150015 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 1806139Sjb150015 { 1816139Sjb150015 /* 1826139Sjb150015 * Check caller's privileges. 1836139Sjb150015 */ 1846139Sjb150015 if (secpolicy_smb(credp) != 0) 1856139Sjb150015 return (EPERM); 1866139Sjb150015 1876139Sjb150015 /* 1886139Sjb150015 * Start SMB service state machine 1896139Sjb150015 */ 1906139Sjb150015 return (smb_server_create()); 1916139Sjb150015 } 1926139Sjb150015 1936139Sjb150015 /* ARGSUSED */ 1946139Sjb150015 static int 1956139Sjb150015 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 1966139Sjb150015 { 1976139Sjb150015 return (smb_server_delete()); 1986139Sjb150015 } 1995331Samw 2006139Sjb150015 /* ARGSUSED */ 2016139Sjb150015 static int 2029832Samw@Sun.COM smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 2036139Sjb150015 int *retval) 2046139Sjb150015 { 2059832Samw@Sun.COM smb_ioc_t *ioc; 2069832Samw@Sun.COM smb_ioc_header_t ioc_hdr; 2079832Samw@Sun.COM uint32_t crc; 2089832Samw@Sun.COM boolean_t copyout = B_FALSE; 2096139Sjb150015 int rc = 0; 2106139Sjb150015 2119832Samw@Sun.COM if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t), 2129832Samw@Sun.COM flags) || (ioc_hdr.version != SMB_IOC_VERSION)) 2136139Sjb150015 return (EFAULT); 2146139Sjb150015 2159832Samw@Sun.COM crc = ioc_hdr.crc; 2169832Samw@Sun.COM ioc_hdr.crc = 0; 2179832Samw@Sun.COM if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 2189832Samw@Sun.COM return (EFAULT); 2198167Samw@Sun.COM 2209832Samw@Sun.COM ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP); 2219832Samw@Sun.COM if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) { 2229832Samw@Sun.COM kmem_free(ioc, ioc_hdr.len); 2238167Samw@Sun.COM return (EFAULT); 2249832Samw@Sun.COM } 2258167Samw@Sun.COM 2266139Sjb150015 switch (cmd) { 2276139Sjb150015 case SMB_IOC_CONFIG: 2289832Samw@Sun.COM rc = smb_server_configure(&ioc->ioc_cfg); 2296139Sjb150015 break; 2306139Sjb150015 case SMB_IOC_START: 2319832Samw@Sun.COM rc = smb_server_start(&ioc->ioc_start); 2326139Sjb150015 break; 23311963SAfshin.Ardakani@Sun.COM case SMB_IOC_STOP: 23411963SAfshin.Ardakani@Sun.COM rc = smb_server_stop(); 23511963SAfshin.Ardakani@Sun.COM break; 23611963SAfshin.Ardakani@Sun.COM case SMB_IOC_EVENT: 23711963SAfshin.Ardakani@Sun.COM rc = smb_server_notify_event(&ioc->ioc_event); 23811963SAfshin.Ardakani@Sun.COM break; 2396139Sjb150015 case SMB_IOC_NBT_LISTEN: 2409832Samw@Sun.COM rc = smb_server_nbt_listen(&ioc->ioc_listen); 2416139Sjb150015 break; 2426139Sjb150015 case SMB_IOC_TCP_LISTEN: 2439832Samw@Sun.COM rc = smb_server_tcp_listen(&ioc->ioc_listen); 2446139Sjb150015 break; 2456139Sjb150015 case SMB_IOC_NBT_RECEIVE: 2466139Sjb150015 rc = smb_server_nbt_receive(); 2476139Sjb150015 break; 2486139Sjb150015 case SMB_IOC_TCP_RECEIVE: 2496139Sjb150015 rc = smb_server_tcp_receive(); 2506139Sjb150015 break; 2516139Sjb150015 case SMB_IOC_GMTOFF: 2529832Samw@Sun.COM rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 2539832Samw@Sun.COM break; 2549832Samw@Sun.COM case SMB_IOC_SHARE: 255*12508Samw@Sun.COM rc = smb_kshare_export_list(&ioc->ioc_share); 2569832Samw@Sun.COM break; 2579832Samw@Sun.COM case SMB_IOC_UNSHARE: 258*12508Samw@Sun.COM rc = smb_kshare_unexport_list(&ioc->ioc_share); 2599832Samw@Sun.COM break; 26010122SJordan.Brown@Sun.COM case SMB_IOC_NUMOPEN: 26110122SJordan.Brown@Sun.COM rc = smb_server_numopen(&ioc->ioc_opennum); 2629832Samw@Sun.COM copyout = B_TRUE; 2639832Samw@Sun.COM break; 26410122SJordan.Brown@Sun.COM case SMB_IOC_SVCENUM: 26510122SJordan.Brown@Sun.COM rc = smb_server_enum(&ioc->ioc_svcenum); 2669832Samw@Sun.COM copyout = B_TRUE; 2676139Sjb150015 break; 26810122SJordan.Brown@Sun.COM case SMB_IOC_SESSION_CLOSE: 26910122SJordan.Brown@Sun.COM rc = smb_server_session_close(&ioc->ioc_session); 27010122SJordan.Brown@Sun.COM break; 27110122SJordan.Brown@Sun.COM case SMB_IOC_FILE_CLOSE: 27210122SJordan.Brown@Sun.COM rc = smb_server_file_close(&ioc->ioc_fileid); 27310122SJordan.Brown@Sun.COM break; 2746139Sjb150015 default: 2756139Sjb150015 rc = ENOTTY; 2766139Sjb150015 break; 2775331Samw } 2789832Samw@Sun.COM if ((rc == 0) && copyout) { 2799832Samw@Sun.COM if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len, 2809832Samw@Sun.COM flags)) 2819832Samw@Sun.COM rc = EFAULT; 2829832Samw@Sun.COM } 2839832Samw@Sun.COM kmem_free(ioc, ioc_hdr.len); 2845331Samw return (rc); 2855331Samw } 2865331Samw 2875331Samw /* 2886139Sjb150015 * **************************************************************************** 2896139Sjb150015 * Pseudo Device Operations 2906139Sjb150015 * **************************************************************************** 2915331Samw */ 2926139Sjb150015 static int 2936139Sjb150015 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2946139Sjb150015 { 2956139Sjb150015 if (cmd == DDI_ATTACH) { 2966139Sjb150015 /* we only allow instance 0 to attach */ 2976139Sjb150015 if (ddi_get_instance(dip) == 0) { 2986139Sjb150015 /* create the minor node */ 2996139Sjb150015 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 3006139Sjb150015 DDI_PSEUDO, 0) == DDI_SUCCESS) { 3018473SJose.Borrego@Sun.COM smb_drv_dip = dip; 3028473SJose.Borrego@Sun.COM return (DDI_SUCCESS); 3036139Sjb150015 } else { 3046139Sjb150015 cmn_err(CE_WARN, "smb_drv_attach:" 3056139Sjb150015 " failed creating minor node"); 3066139Sjb150015 } 3076139Sjb150015 } 3086139Sjb150015 } 3096139Sjb150015 return (DDI_FAILURE); 3106139Sjb150015 } 3116139Sjb150015 3126139Sjb150015 static int 3136139Sjb150015 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3146139Sjb150015 { 3156139Sjb150015 if (cmd == DDI_DETACH) { 3166139Sjb150015 ASSERT(dip == smb_drv_dip); 3178473SJose.Borrego@Sun.COM ddi_remove_minor_node(dip, NULL); 3188473SJose.Borrego@Sun.COM smb_drv_dip = NULL; 3198473SJose.Borrego@Sun.COM return (DDI_SUCCESS); 3206139Sjb150015 } 3216139Sjb150015 return (DDI_FAILURE); 3226139Sjb150015 } 3235331Samw 3245331Samw /* ARGSUSED */ 3255331Samw static int 3265331Samw smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 3275331Samw { 3285331Samw ulong_t instance = getminor((dev_t)arg); 3295331Samw 3305331Samw switch (cmd) { 3315331Samw case DDI_INFO_DEVT2DEVINFO: 3325331Samw *result = smb_drv_dip; 3335331Samw return (DDI_SUCCESS); 3345331Samw 3355331Samw case DDI_INFO_DEVT2INSTANCE: 3365331Samw *result = (void *)instance; 3375331Samw return (DDI_SUCCESS); 3385331Samw 3395331Samw default: 3405331Samw break; 3415331Samw } 3425331Samw 3435331Samw return (DDI_FAILURE); 3445331Samw } 345