Home | History | Annotate | Download | only in smbsrv
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/ddi.h>
     28 #include <sys/modctl.h>
     29 #include <sys/cred.h>
     30 #include <sys/ioccom.h>
     31 #include <sys/policy.h>
     32 #include <sys/cmn_err.h>
     33 #include <smbsrv/smb_kproto.h>
     34 #include <smbsrv/smb_door_svc.h>
     35 #include <smbsrv/smb_ioctl.h>
     36 
     37 static int smb_drv_open(dev_t *, int, int, cred_t *);
     38 static int smb_drv_close(dev_t, int, int, cred_t *);
     39 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
     40 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t);
     41 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t);
     42 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
     43 
     44 /*
     45  * *****************************************************************************
     46  * ****************************** Global Variables *****************************
     47  * *****************************************************************************
     48  *
     49  * These variables can only be changed through the /etc/system file.
     50  */
     51 
     52 /*
     53  * Maximum buffer size for NT: configurable based on the client environment.
     54  * IR104720 Experiments with Windows 2000 indicate that we achieve better
     55  * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used
     56  * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory
     57  * listing problems so this buffer size is configurable based on the end-user
     58  * environment. When in doubt use 37KB.
     59  */
     60 int	smb_maxbufsize = SMB_NT_MAXBUF;
     61 int	smb_oplock_timeout = OPLOCK_STD_TIMEOUT;
     62 int	smb_flush_required = 1;
     63 int	smb_dirsymlink_enable = 1;
     64 int	smb_sign_debug = 0;
     65 uint_t	smb_audit_flags =
     66 #ifdef	DEBUG
     67     SMB_AUDIT_NODE;
     68 #else
     69     0;
     70 #endif
     71 
     72 /*
     73  * *****************************************************************************
     74  * ********************** Static Variables / Module Linkage ********************
     75  * *****************************************************************************
     76  */
     77 
     78 static struct cb_ops cbops = {
     79 	smb_drv_open,		/* cb_open */
     80 	smb_drv_close,		/* cb_close */
     81 	nodev,			/* cb_strategy */
     82 	nodev,			/* cb_print */
     83 	nodev,			/* cb_dump */
     84 	nodev,			/* cb_read */
     85 	nodev,			/* cb_write */
     86 	smb_drv_ioctl,		/* cb_ioctl */
     87 	nodev,			/* cb_devmap */
     88 	nodev,			/* cb_mmap */
     89 	nodev,			/* cb_segmap */
     90 	nochpoll,		/* cb_chpoll */
     91 	ddi_prop_op,		/* cb_prop_op */
     92 	NULL,			/* cb_streamtab */
     93 	D_MP,			/* cb_flag */
     94 	CB_REV,			/* cb_rev */
     95 	nodev,			/* cb_aread */
     96 	nodev,			/* cb_awrite */
     97 };
     98 
     99 static struct dev_ops devops = {
    100 	DEVO_REV,		/* devo_rev */
    101 	0,			/* devo_refcnt */
    102 	smb_drv_getinfo,	/* devo_getinfo */
    103 	nulldev,		/* devo_identify */
    104 	nulldev,		/* devo_probe */
    105 	smb_drv_attach,		/* devo_attach */
    106 	smb_drv_detach,		/* devo_detach */
    107 	nodev,			/* devo_reset */
    108 	&cbops,			/* devo_cb_ops */
    109 	NULL,			/* devo_bus_ops */
    110 	NULL,			/* devo_power */
    111 	ddi_quiesce_not_needed,		/* devo_quiesce */
    112 };
    113 
    114 static struct modldrv modldrv = {
    115 	&mod_driverops,					/* drv_modops */
    116 	"CIFS Server Protocol",				/* drv_linkinfo */
    117 	&devops,
    118 };
    119 
    120 static struct modlinkage modlinkage = {
    121 	MODREV_1,	/* revision of the module, must be: MODREV_1	*/
    122 	&modldrv,	/* ptr to linkage structures			*/
    123 	NULL,
    124 };
    125 
    126 static dev_info_t *smb_drv_dip = NULL;
    127 
    128 /*
    129  * ****************************************************************************
    130  *				    Module Interface
    131  * ****************************************************************************
    132  */
    133 
    134 int
    135 _init(void)
    136 {
    137 	int	rc;
    138 
    139 	rc = smb_server_svc_init();
    140 	if (rc == 0) {
    141 		rc = mod_install(&modlinkage);
    142 		if (rc != 0)
    143 			(void) smb_server_svc_fini();
    144 	}
    145 	return (rc);
    146 }
    147 
    148 int
    149 _info(struct modinfo *modinfop)
    150 {
    151 	return (mod_info(&modlinkage, modinfop));
    152 }
    153 
    154 int
    155 _fini(void)
    156 {
    157 	int	rc;
    158 
    159 	rc = mod_remove(&modlinkage);
    160 	if (rc == 0)
    161 		rc = smb_server_svc_fini();
    162 	return (rc);
    163 }
    164 
    165 /*
    166  * ****************************************************************************
    167  *				Pseudo Device Entry Points
    168  * ****************************************************************************
    169  */
    170 /* ARGSUSED */
    171 static int
    172 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp)
    173 {
    174 	/*
    175 	 * Check caller's privileges.
    176 	 */
    177 	if (secpolicy_smb(credp) != 0)
    178 		return (EPERM);
    179 
    180 	/*
    181 	 * Start SMB service state machine
    182 	 */
    183 	return (smb_server_create());
    184 }
    185 
    186 /* ARGSUSED */
    187 static int
    188 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp)
    189 {
    190 	return (smb_server_delete());
    191 }
    192 
    193 /* ARGSUSED */
    194 static int
    195 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
    196     int *retval)
    197 {
    198 	smb_ioc_t	*ioc;
    199 	smb_ioc_header_t ioc_hdr;
    200 	uint32_t	crc;
    201 	boolean_t	copyout = B_FALSE;
    202 	int		rc = 0;
    203 
    204 	if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t),
    205 	    flags) || (ioc_hdr.version != SMB_IOC_VERSION))
    206 		return (EFAULT);
    207 
    208 	crc = ioc_hdr.crc;
    209 	ioc_hdr.crc = 0;
    210 	if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
    211 		return (EFAULT);
    212 
    213 	ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP);
    214 	if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) {
    215 		kmem_free(ioc, ioc_hdr.len);
    216 		return (EFAULT);
    217 	}
    218 
    219 	switch (cmd) {
    220 	case SMB_IOC_CONFIG:
    221 		rc = smb_server_configure(&ioc->ioc_cfg);
    222 		break;
    223 	case SMB_IOC_START:
    224 		rc = smb_server_start(&ioc->ioc_start);
    225 		break;
    226 	case SMB_IOC_NBT_LISTEN:
    227 		rc = smb_server_nbt_listen(&ioc->ioc_listen);
    228 		break;
    229 	case SMB_IOC_TCP_LISTEN:
    230 		rc = smb_server_tcp_listen(&ioc->ioc_listen);
    231 		break;
    232 	case SMB_IOC_NBT_RECEIVE:
    233 		rc = smb_server_nbt_receive();
    234 		break;
    235 	case SMB_IOC_TCP_RECEIVE:
    236 		rc = smb_server_tcp_receive();
    237 		break;
    238 	case SMB_IOC_GMTOFF:
    239 		rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
    240 		break;
    241 	case SMB_IOC_SHARE:
    242 		rc = smb_server_share_export(&ioc->ioc_share);
    243 		break;
    244 	case SMB_IOC_UNSHARE:
    245 		rc = smb_server_share_unexport(&ioc->ioc_share);
    246 		break;
    247 	case SMB_IOC_NUMOPEN:
    248 		rc = smb_server_numopen(&ioc->ioc_opennum);
    249 		copyout = B_TRUE;
    250 		break;
    251 	case SMB_IOC_SVCENUM:
    252 		rc = smb_server_enum(&ioc->ioc_svcenum);
    253 		copyout = B_TRUE;
    254 		break;
    255 	case SMB_IOC_SESSION_CLOSE:
    256 		rc = smb_server_session_close(&ioc->ioc_session);
    257 		break;
    258 	case SMB_IOC_FILE_CLOSE:
    259 		rc = smb_server_file_close(&ioc->ioc_fileid);
    260 		break;
    261 	default:
    262 		rc = ENOTTY;
    263 		break;
    264 	}
    265 	if ((rc == 0) && copyout) {
    266 		if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len,
    267 		    flags))
    268 			rc = EFAULT;
    269 	}
    270 	kmem_free(ioc, ioc_hdr.len);
    271 	return (rc);
    272 }
    273 
    274 /*
    275  * ****************************************************************************
    276  *				Pseudo Device Operations
    277  * ****************************************************************************
    278  */
    279 static int
    280 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    281 {
    282 	if (cmd == DDI_ATTACH) {
    283 		/* we only allow instance 0 to attach */
    284 		if (ddi_get_instance(dip) == 0) {
    285 			/* create the minor node */
    286 			if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0,
    287 			    DDI_PSEUDO, 0) == DDI_SUCCESS) {
    288 				smb_drv_dip = dip;
    289 				return (DDI_SUCCESS);
    290 			} else {
    291 				cmn_err(CE_WARN, "smb_drv_attach:"
    292 				    " failed creating minor node");
    293 			}
    294 		}
    295 	}
    296 	return (DDI_FAILURE);
    297 }
    298 
    299 static int
    300 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    301 {
    302 	if (cmd == DDI_DETACH) {
    303 		ASSERT(dip == smb_drv_dip);
    304 		ddi_remove_minor_node(dip, NULL);
    305 		smb_drv_dip = NULL;
    306 		return (DDI_SUCCESS);
    307 	}
    308 	return (DDI_FAILURE);
    309 }
    310 
    311 /* ARGSUSED */
    312 static int
    313 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
    314 {
    315 	ulong_t instance = getminor((dev_t)arg);
    316 
    317 	switch (cmd) {
    318 	case DDI_INFO_DEVT2DEVINFO:
    319 		*result = smb_drv_dip;
    320 		return (DDI_SUCCESS);
    321 
    322 	case DDI_INFO_DEVT2INSTANCE:
    323 		*result = (void *)instance;
    324 		return (DDI_SUCCESS);
    325 
    326 	default:
    327 		break;
    328 	}
    329 
    330 	return (DDI_FAILURE);
    331 }
    332