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