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