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