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