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 * Copyright 2015-2023 RackTop Systems, Inc. 25 * Copyright 2019 Joyent, Inc. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/conf.h> 30 #include <sys/ddi.h> 31 #include <sys/modctl.h> 32 #include <sys/cred.h> 33 #include <sys/disp.h> 34 #include <sys/ioccom.h> 35 #include <sys/policy.h> 36 #include <sys/cmn_err.h> 37 #include <smbsrv/smb_kproto.h> 38 #include <smbsrv/smb_ioctl.h> 39 40 #ifdef _FAKE_KERNEL 41 #error "See libfksmbsrv" 42 #endif /* _FAKE_KERNEL */ 43 44 static int smb_drv_open(dev_t *, int, int, cred_t *); 45 static int smb_drv_close(dev_t, int, int, cred_t *); 46 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 47 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 48 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 49 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 50 51 /* 52 * ***************************************************************************** 53 * ****************************** Global Variables ***************************** 54 * ***************************************************************************** 55 * 56 * These variables can only be changed through the /etc/system file. 57 */ 58 59 /* 60 * Maximum buffer size for NT: configurable based on the client environment. 61 * IR104720 Experiments with Windows 2000 indicate that we achieve better 62 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 63 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 64 * listing problems so this buffer size is configurable based on the end-user 65 * environment. When in doubt use 37KB. 66 */ 67 int smb_maxbufsize = SMB_NT_MAXBUF; 68 int smb_flush_required = 1; 69 int smb_dirsymlink_enable = 1; 70 int smb_sign_debug = 0; 71 uint_t smb_audit_flags = 72 #ifdef DEBUG 73 SMB_AUDIT_NODE; 74 #else 75 0; 76 #endif 77 78 int smb_allow_advisory_locks = 0; /* See smb_vops.c */ 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 int smb_logoff_threshold = 1024; 88 89 /* 90 * Number of milliseconds that a request will be stalled if it comes in after 91 * the maximum number of inflight operations are being proccessed. 92 */ 93 int smb_ssetup_timeout = (30 * 1000); 94 int smb_tcon_timeout = (30 * 1000); 95 int smb_opipe_timeout = (30 * 1000); 96 int smb_logoff_timeout = (600 * 1000); 97 98 /* 99 * Thread priorities used in smbsrv. 100 * 101 * The SMB server runs at a priority a little below the maximum for 102 * user-level process threads so it won't monopolize the CPU. 103 * Todo: make this configurable 104 * 105 * Aside from that, we want these relative priorities: (a) timers, 106 * (b) notify + oplock completions, (c) workers, (d) receivers, etc. 107 * The "base" is somewhat arbirary, and what shows up in prstat 108 * because it's used for the main thread in newproc(). 109 */ 110 int smbsrv_timer_pri = MINCLSYSPRI; /* smb_server_timers */ 111 int smbsrv_base_pri = MINCLSYSPRI - 1; /* kshare thread, newproc */ 112 int smbsrv_notify_pri = MINCLSYSPRI - 1; /* oplocks, notify */ 113 /* Gap in which user-level administrative stuff runs. */ 114 int smbsrv_worker_pri = MINCLSYSPRI - 7; 115 int smbsrv_receive_pri = MINCLSYSPRI - 8; 116 int smbsrv_listen_pri = MINCLSYSPRI - 9; 117 118 119 /* 120 * ***************************************************************************** 121 * ********************** Static Variables / Module Linkage ******************** 122 * ***************************************************************************** 123 */ 124 125 static struct cb_ops cbops = { 126 smb_drv_open, /* cb_open */ 127 smb_drv_close, /* cb_close */ 128 nodev, /* cb_strategy */ 129 nodev, /* cb_print */ 130 nodev, /* cb_dump */ 131 nodev, /* cb_read */ 132 nodev, /* cb_write */ 133 smb_drv_ioctl, /* cb_ioctl */ 134 nodev, /* cb_devmap */ 135 nodev, /* cb_mmap */ 136 nodev, /* cb_segmap */ 137 nochpoll, /* cb_chpoll */ 138 ddi_prop_op, /* cb_prop_op */ 139 NULL, /* cb_streamtab */ 140 D_MP, /* cb_flag */ 141 CB_REV, /* cb_rev */ 142 nodev, /* cb_aread */ 143 nodev, /* cb_awrite */ 144 }; 145 146 static struct dev_ops devops = { 147 DEVO_REV, /* devo_rev */ 148 0, /* devo_refcnt */ 149 smb_drv_getinfo, /* devo_getinfo */ 150 nulldev, /* devo_identify */ 151 nulldev, /* devo_probe */ 152 smb_drv_attach, /* devo_attach */ 153 smb_drv_detach, /* devo_detach */ 154 nodev, /* devo_reset */ 155 &cbops, /* devo_cb_ops */ 156 NULL, /* devo_bus_ops */ 157 NULL, /* devo_power */ 158 ddi_quiesce_not_needed, /* devo_quiesce */ 159 }; 160 161 static struct modldrv modldrv = { 162 &mod_driverops, /* drv_modops */ 163 "CIFS Server Protocol", /* drv_linkinfo */ 164 &devops, 165 }; 166 167 static struct modlinkage modlinkage = { 168 MODREV_1, /* revision of the module, must be: MODREV_1 */ 169 &modldrv, /* ptr to linkage structures */ 170 NULL, 171 }; 172 173 static dev_info_t *smb_drv_dip = NULL; 174 175 /* 176 * **************************************************************************** 177 * Module Interface 178 * **************************************************************************** 179 */ 180 181 int 182 _init(void) 183 { 184 int rc; 185 186 if ((rc = smb_server_g_init()) != 0) { 187 return (rc); 188 } 189 190 if ((rc = mod_install(&modlinkage)) != 0) { 191 smb_server_g_fini(); 192 } 193 194 return (rc); 195 } 196 197 int 198 _info(struct modinfo *modinfop) 199 { 200 return (mod_info(&modlinkage, modinfop)); 201 } 202 203 int 204 _fini(void) 205 { 206 int rc; 207 208 if (smb_server_get_count() != 0) 209 return (EBUSY); 210 211 if ((rc = mod_remove(&modlinkage)) == 0) { 212 smb_server_g_fini(); 213 } 214 215 return (rc); 216 } 217 218 /* 219 * **************************************************************************** 220 * Pseudo Device Entry Points 221 * **************************************************************************** 222 */ 223 /* ARGSUSED */ 224 static int 225 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 226 { 227 zoneid_t zid; 228 229 /* 230 * Check caller's privileges. 231 */ 232 if (secpolicy_smb(cr) != 0) 233 return (EPERM); 234 235 /* 236 * We need a unique minor per zone otherwise an smbd in any other 237 * zone will keep this minor open and we won't get a close call. 238 * The zone ID is good enough as a minor number. 239 */ 240 zid = crgetzoneid(cr); 241 if (zid < 0) 242 return (ENODEV); 243 *devp = makedevice(getmajor(*devp), zid); 244 245 /* 246 * Start SMB service state machine 247 */ 248 return (smb_server_create()); 249 } 250 251 /* ARGSUSED */ 252 static int 253 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 254 { 255 smb_server_t *sv; 256 int rc; 257 258 rc = smb_server_lookup(&sv); 259 if (rc == 0) 260 rc = smb_server_delete(sv); 261 262 return (rc); 263 } 264 265 /* ARGSUSED */ 266 static int 267 smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred, 268 int *retval) 269 { 270 smb_ioc_t *ioc; 271 smb_ioc_header_t ioc_hdr; 272 uint32_t crc; 273 boolean_t copyout = B_FALSE; 274 int rc = 0; 275 size_t alloclen; 276 277 if (ddi_copyin((void *)argp, &ioc_hdr, sizeof (ioc_hdr), flags)) 278 return (EFAULT); 279 280 /* 281 * Check version and length. 282 * 283 * Note that some ioctls (i.e. SMB_IOC_SVCENUM) have payload 284 * data after the ioctl struct, in which case they specify a 285 * length much larger than sizeof smb_ioc_t. The theoretical 286 * largest ioctl data is therefore the size of the union plus 287 * the max size of the payload (which is SMB_IOC_DATA_SIZE). 288 */ 289 if (ioc_hdr.version != SMB_IOC_VERSION || 290 ioc_hdr.len < sizeof (ioc_hdr) || 291 ioc_hdr.len > (sizeof (*ioc) + SMB_IOC_DATA_SIZE)) 292 return (EINVAL); 293 294 crc = ioc_hdr.crc; 295 ioc_hdr.crc = 0; 296 if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 297 return (EINVAL); 298 299 /* 300 * Note that smb_ioc_t is a union, and callers set ioc_hdr.len 301 * to the size of the actual union arm. If some caller were to 302 * set that size too small, we could end up passing under-sized 303 * memory to one of the type-specific handler functions. Avoid 304 * that problem by allocating at least the size of the union, 305 * (zeroed out) and then copy in the caller specified length. 306 */ 307 alloclen = MAX(ioc_hdr.len, sizeof (*ioc)); 308 ioc = kmem_zalloc(alloclen, KM_SLEEP); 309 if (ddi_copyin((void *)argp, ioc, ioc_hdr.len, flags)) { 310 kmem_free(ioc, alloclen); 311 return (EFAULT); 312 } 313 314 /* Don't allow the request size to change mid-ioctl */ 315 if (ioc_hdr.len != ioc->ioc_hdr.len) { 316 kmem_free(ioc, alloclen); 317 return (EINVAL); 318 } 319 320 switch (cmd) { 321 case SMB_IOC_CONFIG: 322 rc = smb_server_configure(&ioc->ioc_cfg); 323 break; 324 case SMB_IOC_START: 325 rc = smb_server_start(&ioc->ioc_start); 326 break; 327 case SMB_IOC_STOP: 328 rc = smb_server_stop(); 329 break; 330 case SMB_IOC_EVENT: 331 rc = smb_server_notify_event(&ioc->ioc_event); 332 break; 333 case SMB_IOC_GMTOFF: 334 rc = smb_server_set_gmtoff(&ioc->ioc_gmt); 335 break; 336 case SMB_IOC_SHARE: 337 rc = smb_kshare_export_list(&ioc->ioc_share); 338 break; 339 case SMB_IOC_UNSHARE: 340 rc = smb_kshare_unexport_list(&ioc->ioc_share); 341 break; 342 case SMB_IOC_SHAREINFO: 343 rc = smb_kshare_info(&ioc->ioc_shareinfo); 344 copyout = B_TRUE; 345 break; 346 case SMB_IOC_SHAREACCESS: 347 rc = smb_kshare_access(&ioc->ioc_shareaccess); 348 break; 349 case SMB_IOC_NUMOPEN: 350 rc = smb_server_numopen(&ioc->ioc_opennum); 351 copyout = B_TRUE; 352 break; 353 case SMB_IOC_SVCENUM: 354 rc = smb_server_enum(&ioc->ioc_svcenum); 355 copyout = B_TRUE; 356 break; 357 case SMB_IOC_SESSION_CLOSE: 358 rc = smb_server_session_close(&ioc->ioc_session); 359 break; 360 case SMB_IOC_FILE_CLOSE: 361 rc = smb_server_file_close(&ioc->ioc_fileid); 362 break; 363 case SMB_IOC_SPOOLDOC: 364 rc = smb_server_spooldoc(&ioc->ioc_spooldoc); 365 copyout = B_TRUE; 366 break; 367 default: 368 rc = ENOTTY; 369 break; 370 } 371 if ((rc == 0) && copyout) { 372 if (ddi_copyout(ioc, (void *)argp, ioc_hdr.len, flags)) 373 rc = EFAULT; 374 } 375 kmem_free(ioc, alloclen); 376 return (rc); 377 } 378 379 /* 380 * **************************************************************************** 381 * Pseudo Device Operations 382 * **************************************************************************** 383 */ 384 static int 385 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 386 { 387 if (cmd == DDI_ATTACH) { 388 /* we only allow instance 0 to attach */ 389 if (ddi_get_instance(dip) == 0) { 390 /* create the minor node */ 391 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 392 DDI_PSEUDO, 0) == DDI_SUCCESS) { 393 smb_drv_dip = dip; 394 return (DDI_SUCCESS); 395 } else { 396 cmn_err(CE_WARN, "smb_drv_attach:" 397 " failed creating minor node"); 398 } 399 } 400 } 401 return (DDI_FAILURE); 402 } 403 404 static int 405 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 406 { 407 if (cmd == DDI_DETACH) { 408 ASSERT(dip == smb_drv_dip); 409 ddi_remove_minor_node(dip, NULL); 410 smb_drv_dip = NULL; 411 return (DDI_SUCCESS); 412 } 413 return (DDI_FAILURE); 414 } 415 416 /* ARGSUSED */ 417 static int 418 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 419 { 420 ulong_t instance = getminor((dev_t)arg); 421 422 switch (cmd) { 423 case DDI_INFO_DEVT2DEVINFO: 424 *result = smb_drv_dip; 425 return (DDI_SUCCESS); 426 427 case DDI_INFO_DEVT2INSTANCE: 428 *result = (void *)instance; 429 return (DDI_SUCCESS); 430 431 default: 432 break; 433 } 434 435 return (DDI_FAILURE); 436 } 437