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 2011 Nexenta Systems, Inc. All rights reserved. 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 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 * smb_raw_mode: read_raw and write_raw supported (1) or NOT supported (0). 60 */ 61 int smb_maxbufsize = SMB_NT_MAXBUF; 62 int smb_oplock_levelII = 1; 63 int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 64 int smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT; 65 int smb_flush_required = 1; 66 int smb_dirsymlink_enable = 1; 67 int smb_sign_debug = 0; 68 int smb_raw_mode = 0; 69 int smb_shortnames = 1; 70 uint_t smb_audit_flags = 71 #ifdef DEBUG 72 SMB_AUDIT_NODE; 73 #else 74 0; 75 #endif 76 77 /* 78 * Maximum number of simultaneous authentication, share mapping, pipe open 79 * requests to be processed. 80 */ 81 int smb_ssetup_threshold = 256; 82 int smb_tcon_threshold = 1024; 83 int smb_opipe_threshold = 1024; 84 85 /* 86 * Number of milliseconds that a request will be stalled if it comes in after 87 * the maximum number of inflight operations are being proccessed. 88 */ 89 int smb_ssetup_timeout = (30 * 1000); 90 int smb_tcon_timeout = (30 * 1000); 91 int smb_opipe_timeout = (30 * 1000); 92 93 int smb_threshold_debug = 0; 94 95 96 /* 97 * ***************************************************************************** 98 * ********************** Static Variables / Module Linkage ******************** 99 * ***************************************************************************** 100 */ 101 102 static struct cb_ops cbops = { 103 smb_drv_open, /* cb_open */ 104 smb_drv_close, /* cb_close */ 105 nodev, /* cb_strategy */ 106 nodev, /* cb_print */ 107 nodev, /* cb_dump */ 108 nodev, /* cb_read */ 109 nodev, /* cb_write */ 110 smb_drv_ioctl, /* cb_ioctl */ 111 nodev, /* cb_devmap */ 112 nodev, /* cb_mmap */ 113 nodev, /* cb_segmap */ 114 nochpoll, /* cb_chpoll */ 115 ddi_prop_op, /* cb_prop_op */ 116 NULL, /* cb_streamtab */ 117 D_MP, /* cb_flag */ 118 CB_REV, /* cb_rev */ 119 nodev, /* cb_aread */ 120 nodev, /* cb_awrite */ 121 }; 122 123 static struct dev_ops devops = { 124 DEVO_REV, /* devo_rev */ 125 0, /* devo_refcnt */ 126 smb_drv_getinfo, /* devo_getinfo */ 127 nulldev, /* devo_identify */ 128 nulldev, /* devo_probe */ 129 smb_drv_attach, /* devo_attach */ 130 smb_drv_detach, /* devo_detach */ 131 nodev, /* devo_reset */ 132 &cbops, /* devo_cb_ops */ 133 NULL, /* devo_bus_ops */ 134 NULL, /* devo_power */ 135 ddi_quiesce_not_needed, /* devo_quiesce */ 136 }; 137 138 static struct modldrv modldrv = { 139 &mod_driverops, /* drv_modops */ 140 "CIFS Server Protocol", /* drv_linkinfo */ 141 &devops, 142 }; 143 144 static struct modlinkage modlinkage = { 145 MODREV_1, /* revision of the module, must be: MODREV_1 */ 146 &modldrv, /* ptr to linkage structures */ 147 NULL, 148 }; 149 150 static dev_info_t *smb_drv_dip = NULL; 151 152 /* 153 * **************************************************************************** 154 * Module Interface 155 * **************************************************************************** 156 */ 157 158 int 159 _init(void) 160 { 161 int rc; 162 163 if ((rc = smb_kshare_init()) != 0) 164 return (rc); 165 166 if ((rc = smb_server_svc_init()) != 0) { 167 smb_kshare_fini(); 168 return (rc); 169 } 170 171 if ((rc = mod_install(&modlinkage)) != 0) { 172 smb_kshare_fini(); 173 (void) smb_server_svc_fini(); 174 } 175 176 return (rc); 177 } 178 179 int 180 _info(struct modinfo *modinfop) 181 { 182 return (mod_info(&modlinkage, modinfop)); 183 } 184 185 int 186 _fini(void) 187 { 188 int rc; 189 190 if ((rc = mod_remove(&modlinkage)) == 0) { 191 rc = smb_server_svc_fini(); 192 smb_kshare_fini(); 193 } 194 195 return (rc); 196 } 197 198 /* 199 * **************************************************************************** 200 * Pseudo Device Entry Points 201 * **************************************************************************** 202 */ 203 /* ARGSUSED */ 204 static int 205 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *credp) 206 { 207 /* 208 * Check caller's privileges. 209 */ 210 if (secpolicy_smb(credp) != 0) 211 return (EPERM); 212 213 /* 214 * Start SMB service state machine 215 */ 216 return (smb_server_create()); 217 } 218 219 /* ARGSUSED */ 220 static int 221 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 222 { 223 return (smb_server_delete()); 224 } 225 226 /* ARGSUSED */ 227 static int 228 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 229 int *retval) 230 { 231 smb_ioc_t *ioc; 232 smb_ioc_header_t ioc_hdr; 233 uint32_t crc; 234 boolean_t copyout = B_FALSE; 235 int rc = 0; 236 237 if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t), 238 flags) || (ioc_hdr.version != SMB_IOC_VERSION)) 239 return (EFAULT); 240 241 crc = ioc_hdr.crc; 242 ioc_hdr.crc = 0; 243 if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 244 return (EFAULT); 245 246 ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP); 247 if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) { 248 kmem_free(ioc, ioc_hdr.len); 249 return (EFAULT); 250 } 251 252 switch (cmd) { 253 case SMB_IOC_CONFIG: 254 rc = smb_server_configure(&ioc->ioc_cfg); 255 break; 256 case SMB_IOC_START: 257 rc = smb_server_start(&ioc->ioc_start); 258 break; 259 case SMB_IOC_STOP: 260 rc = smb_server_stop(); 261 break; 262 case SMB_IOC_EVENT: 263 rc = smb_server_notify_event(&ioc->ioc_event); 264 break; 265 case SMB_IOC_GMTOFF: 266 rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 267 break; 268 case SMB_IOC_SHARE: 269 rc = smb_kshare_export_list(&ioc->ioc_share); 270 break; 271 case SMB_IOC_UNSHARE: 272 rc = smb_kshare_unexport_list(&ioc->ioc_share); 273 break; 274 case SMB_IOC_SHAREINFO: 275 rc = smb_kshare_info(&ioc->ioc_shareinfo); 276 copyout = B_TRUE; 277 break; 278 case SMB_IOC_NUMOPEN: 279 rc = smb_server_numopen(&ioc->ioc_opennum); 280 copyout = B_TRUE; 281 break; 282 case SMB_IOC_SVCENUM: 283 rc = smb_server_enum(&ioc->ioc_svcenum); 284 copyout = B_TRUE; 285 break; 286 case SMB_IOC_SESSION_CLOSE: 287 rc = smb_server_session_close(&ioc->ioc_session); 288 break; 289 case SMB_IOC_FILE_CLOSE: 290 rc = smb_server_file_close(&ioc->ioc_fileid); 291 break; 292 case SMB_IOC_SPOOLDOC: 293 rc = smb_server_spooldoc(&ioc->ioc_spooldoc); 294 copyout = B_TRUE; 295 break; 296 default: 297 rc = ENOTTY; 298 break; 299 } 300 if ((rc == 0) && copyout) { 301 if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len, 302 flags)) 303 rc = EFAULT; 304 } 305 kmem_free(ioc, ioc_hdr.len); 306 return (rc); 307 } 308 309 /* 310 * **************************************************************************** 311 * Pseudo Device Operations 312 * **************************************************************************** 313 */ 314 static int 315 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 316 { 317 if (cmd == DDI_ATTACH) { 318 /* we only allow instance 0 to attach */ 319 if (ddi_get_instance(dip) == 0) { 320 /* create the minor node */ 321 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 322 DDI_PSEUDO, 0) == DDI_SUCCESS) { 323 smb_drv_dip = dip; 324 return (DDI_SUCCESS); 325 } else { 326 cmn_err(CE_WARN, "smb_drv_attach:" 327 " failed creating minor node"); 328 } 329 } 330 } 331 return (DDI_FAILURE); 332 } 333 334 static int 335 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 336 { 337 if (cmd == DDI_DETACH) { 338 ASSERT(dip == smb_drv_dip); 339 ddi_remove_minor_node(dip, NULL); 340 smb_drv_dip = NULL; 341 return (DDI_SUCCESS); 342 } 343 return (DDI_FAILURE); 344 } 345 346 /* ARGSUSED */ 347 static int 348 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 349 { 350 ulong_t instance = getminor((dev_t)arg); 351 352 switch (cmd) { 353 case DDI_INFO_DEVT2DEVINFO: 354 *result = smb_drv_dip; 355 return (DDI_SUCCESS); 356 357 case DDI_INFO_DEVT2INSTANCE: 358 *result = (void *)instance; 359 return (DDI_SUCCESS); 360 361 default: 362 break; 363 } 364 365 return (DDI_FAILURE); 366 } 367