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