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/disp.h> 31 #include <sys/ioccom.h> 32 #include <sys/policy.h> 33 #include <sys/cmn_err.h> 34 #include <smbsrv/smb_kproto.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_levelII = 1; 62 int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; 63 int smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT; 64 int smb_flush_required = 1; 65 int smb_dirsymlink_enable = 1; 66 int smb_sign_debug = 0; 67 int smb_shortnames = 1; 68 uint_t smb_audit_flags = 69 #ifdef DEBUG 70 SMB_AUDIT_NODE; 71 #else 72 0; 73 #endif 74 75 /* 76 * Maximum number of simultaneous authentication, share mapping, pipe open 77 * requests to be processed. 78 */ 79 int smb_ssetup_threshold = 256; 80 int smb_tcon_threshold = 1024; 81 int smb_opipe_threshold = 1024; 82 83 /* 84 * Number of milliseconds that a request will be stalled if it comes in after 85 * the maximum number of inflight operations are being proccessed. 86 */ 87 int smb_ssetup_timeout = (30 * 1000); 88 int smb_tcon_timeout = (30 * 1000); 89 int smb_opipe_timeout = (30 * 1000); 90 91 /* 92 * Thread priorities used in smbsrv. Our threads spend most of their time 93 * blocked on various conditions. However, if the system gets heavy load, 94 * the scheduler has to choose an order to run these. We want the order: 95 * (a) timers, (b) notifications, (c) workers, (d) receivers (and etc.) 96 * where notifications are oplock and change notify work. Aside from this 97 * relative ordering, smbsrv threads should run with a priority close to 98 * that of normal user-space threads (thus minclsyspri below), just like 99 * NFS and other "file service" kinds of processing. 100 */ 101 int smbsrv_base_pri = MINCLSYSPRI; 102 int smbsrv_listen_pri = MINCLSYSPRI; 103 int smbsrv_receive_pri = MINCLSYSPRI; 104 int smbsrv_worker_pri = MINCLSYSPRI + 1; 105 int smbsrv_notify_pri = MINCLSYSPRI + 2; 106 int smbsrv_timer_pri = MINCLSYSPRI + 5; 107 108 109 /* 110 * ***************************************************************************** 111 * ********************** Static Variables / Module Linkage ******************** 112 * ***************************************************************************** 113 */ 114 115 static struct cb_ops cbops = { 116 smb_drv_open, /* cb_open */ 117 smb_drv_close, /* cb_close */ 118 nodev, /* cb_strategy */ 119 nodev, /* cb_print */ 120 nodev, /* cb_dump */ 121 nodev, /* cb_read */ 122 nodev, /* cb_write */ 123 smb_drv_ioctl, /* cb_ioctl */ 124 nodev, /* cb_devmap */ 125 nodev, /* cb_mmap */ 126 nodev, /* cb_segmap */ 127 nochpoll, /* cb_chpoll */ 128 ddi_prop_op, /* cb_prop_op */ 129 NULL, /* cb_streamtab */ 130 D_MP, /* cb_flag */ 131 CB_REV, /* cb_rev */ 132 nodev, /* cb_aread */ 133 nodev, /* cb_awrite */ 134 }; 135 136 static struct dev_ops devops = { 137 DEVO_REV, /* devo_rev */ 138 0, /* devo_refcnt */ 139 smb_drv_getinfo, /* devo_getinfo */ 140 nulldev, /* devo_identify */ 141 nulldev, /* devo_probe */ 142 smb_drv_attach, /* devo_attach */ 143 smb_drv_detach, /* devo_detach */ 144 nodev, /* devo_reset */ 145 &cbops, /* devo_cb_ops */ 146 NULL, /* devo_bus_ops */ 147 NULL, /* devo_power */ 148 ddi_quiesce_not_needed, /* devo_quiesce */ 149 }; 150 151 static struct modldrv modldrv = { 152 &mod_driverops, /* drv_modops */ 153 "CIFS Server Protocol", /* drv_linkinfo */ 154 &devops, 155 }; 156 157 static struct modlinkage modlinkage = { 158 MODREV_1, /* revision of the module, must be: MODREV_1 */ 159 &modldrv, /* ptr to linkage structures */ 160 NULL, 161 }; 162 163 static dev_info_t *smb_drv_dip = NULL; 164 165 /* 166 * **************************************************************************** 167 * Module Interface 168 * **************************************************************************** 169 */ 170 171 int 172 _init(void) 173 { 174 int rc; 175 176 if ((rc = smb_server_g_init()) != 0) { 177 return (rc); 178 } 179 180 if ((rc = mod_install(&modlinkage)) != 0) { 181 (void) smb_server_g_fini(); 182 } 183 184 return (rc); 185 } 186 187 int 188 _info(struct modinfo *modinfop) 189 { 190 return (mod_info(&modlinkage, modinfop)); 191 } 192 193 int 194 _fini(void) 195 { 196 int rc; 197 198 if ((rc = mod_remove(&modlinkage)) == 0) { 199 rc = smb_server_g_fini(); 200 } 201 202 return (rc); 203 } 204 205 /* 206 * **************************************************************************** 207 * Pseudo Device Entry Points 208 * **************************************************************************** 209 */ 210 /* ARGSUSED */ 211 static int 212 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 213 { 214 zoneid_t zid; 215 216 /* 217 * Check caller's privileges. 218 */ 219 if (secpolicy_smb(cr) != 0) 220 return (EPERM); 221 222 /* 223 * We need a unique minor per zone otherwise an smbd in any other 224 * zone will keep this minor open and we won't get a close call. 225 * The zone ID is good enough as a minor number. 226 */ 227 zid = crgetzoneid(cr); 228 if (zid < 0) 229 return (ENODEV); 230 *devp = makedevice(getmajor(*devp), zid); 231 232 /* 233 * Start SMB service state machine 234 */ 235 return (smb_server_create()); 236 } 237 238 /* ARGSUSED */ 239 static int 240 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 241 { 242 return (smb_server_delete()); 243 } 244 245 /* ARGSUSED */ 246 static int 247 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 248 int *retval) 249 { 250 smb_ioc_t *ioc; 251 smb_ioc_header_t ioc_hdr; 252 uint32_t crc; 253 boolean_t copyout = B_FALSE; 254 int rc = 0; 255 256 if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t), 257 flags) || (ioc_hdr.version != SMB_IOC_VERSION)) 258 return (EFAULT); 259 260 crc = ioc_hdr.crc; 261 ioc_hdr.crc = 0; 262 if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 263 return (EFAULT); 264 265 ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP); 266 if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) { 267 kmem_free(ioc, ioc_hdr.len); 268 return (EFAULT); 269 } 270 271 switch (cmd) { 272 case SMB_IOC_CONFIG: 273 rc = smb_server_configure(&ioc->ioc_cfg); 274 break; 275 case SMB_IOC_START: 276 rc = smb_server_start(&ioc->ioc_start); 277 break; 278 case SMB_IOC_STOP: 279 rc = smb_server_stop(); 280 break; 281 case SMB_IOC_EVENT: 282 rc = smb_server_notify_event(&ioc->ioc_event); 283 break; 284 case SMB_IOC_GMTOFF: 285 rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 286 break; 287 case SMB_IOC_SHARE: 288 rc = smb_kshare_export_list(&ioc->ioc_share); 289 break; 290 case SMB_IOC_UNSHARE: 291 rc = smb_kshare_unexport_list(&ioc->ioc_share); 292 break; 293 case SMB_IOC_SHAREINFO: 294 rc = smb_kshare_info(&ioc->ioc_shareinfo); 295 copyout = B_TRUE; 296 break; 297 case SMB_IOC_NUMOPEN: 298 rc = smb_server_numopen(&ioc->ioc_opennum); 299 copyout = B_TRUE; 300 break; 301 case SMB_IOC_SVCENUM: 302 rc = smb_server_enum(&ioc->ioc_svcenum); 303 copyout = B_TRUE; 304 break; 305 case SMB_IOC_SESSION_CLOSE: 306 rc = smb_server_session_close(&ioc->ioc_session); 307 break; 308 case SMB_IOC_FILE_CLOSE: 309 rc = smb_server_file_close(&ioc->ioc_fileid); 310 break; 311 case SMB_IOC_SPOOLDOC: 312 rc = smb_server_spooldoc(&ioc->ioc_spooldoc); 313 copyout = B_TRUE; 314 break; 315 default: 316 rc = ENOTTY; 317 break; 318 } 319 if ((rc == 0) && copyout) { 320 if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len, 321 flags)) 322 rc = EFAULT; 323 } 324 kmem_free(ioc, ioc_hdr.len); 325 return (rc); 326 } 327 328 /* 329 * **************************************************************************** 330 * Pseudo Device Operations 331 * **************************************************************************** 332 */ 333 static int 334 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 335 { 336 if (cmd == DDI_ATTACH) { 337 /* we only allow instance 0 to attach */ 338 if (ddi_get_instance(dip) == 0) { 339 /* create the minor node */ 340 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 341 DDI_PSEUDO, 0) == DDI_SUCCESS) { 342 smb_drv_dip = dip; 343 return (DDI_SUCCESS); 344 } else { 345 cmn_err(CE_WARN, "smb_drv_attach:" 346 " failed creating minor node"); 347 } 348 } 349 } 350 return (DDI_FAILURE); 351 } 352 353 static int 354 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 355 { 356 if (cmd == DDI_DETACH) { 357 ASSERT(dip == smb_drv_dip); 358 ddi_remove_minor_node(dip, NULL); 359 smb_drv_dip = NULL; 360 return (DDI_SUCCESS); 361 } 362 return (DDI_FAILURE); 363 } 364 365 /* ARGSUSED */ 366 static int 367 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 368 { 369 ulong_t instance = getminor((dev_t)arg); 370 371 switch (cmd) { 372 case DDI_INFO_DEVT2DEVINFO: 373 *result = smb_drv_dip; 374 return (DDI_SUCCESS); 375 376 case DDI_INFO_DEVT2INSTANCE: 377 *result = (void *)instance; 378 return (DDI_SUCCESS); 379 380 default: 381 break; 382 } 383 384 return (DDI_FAILURE); 385 } 386