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/id_space.h> 35 #include <sys/ioccom.h> 36 #include <sys/policy.h> 37 #include <sys/cmn_err.h> 38 #include <smbsrv/smb_kproto.h> 39 #include <smbsrv/smb_ioctl.h> 40 41 #ifdef _FAKE_KERNEL 42 #error "See libfksmbsrv" 43 #endif /* _FAKE_KERNEL */ 44 45 static int smb_drv_open(dev_t *, int, int, cred_t *); 46 static int smb_drv_open_ctl(dev_t *, int, int, cred_t *); 47 static int smb_drv_open_lib(dev_t *, int, int, cred_t *); 48 static int smb_drv_close(dev_t, int, int, cred_t *); 49 static int smb_drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 50 static int smb_drv_attach(dev_info_t *, ddi_attach_cmd_t); 51 static int smb_drv_detach(dev_info_t *, ddi_detach_cmd_t); 52 static int smb_drv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 53 54 55 56 /* 57 * ***************************************************************************** 58 * ****************************** Global Variables ***************************** 59 * ***************************************************************************** 60 * 61 * These variables can only be changed through the /etc/system file. 62 */ 63 64 /* 65 * Maximum buffer size for NT: configurable based on the client environment. 66 * IR104720 Experiments with Windows 2000 indicate that we achieve better 67 * SmbWriteX performance with a buffer size of 64KB instead of the 37KB used 68 * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory 69 * listing problems so this buffer size is configurable based on the end-user 70 * environment. When in doubt use 37KB. 71 */ 72 int smb_maxbufsize = SMB_NT_MAXBUF; 73 int smb_flush_required = 1; 74 int smb_dirsymlink_enable = 1; 75 int smb_sign_debug = 0; 76 uint_t smb_audit_flags = 77 #ifdef DEBUG 78 SMB_AUDIT_NODE; 79 #else 80 0; 81 #endif 82 83 int smb_allow_advisory_locks = 0; /* See smb_vops.c */ 84 85 /* 86 * Maximum number of simultaneous authentication, share mapping, pipe open 87 * requests to be processed. 88 */ 89 int smb_ssetup_threshold = SMB_AUTHSVC_MAXTHREAD; 90 int smb_tcon_threshold = 1024; 91 int smb_opipe_threshold = 1024; 92 int smb_logoff_threshold = 1024; 93 94 /* 95 * Number of milliseconds that a request will be stalled if it comes in after 96 * the maximum number of inflight operations are being proccessed. 97 */ 98 int smb_ssetup_timeout = (30 * 1000); 99 int smb_tcon_timeout = (30 * 1000); 100 int smb_opipe_timeout = (30 * 1000); 101 int smb_logoff_timeout = (600 * 1000); 102 103 /* 104 * Thread priorities used in smbsrv. 105 * 106 * The SMB server runs at a priority a little below the maximum for 107 * user-level process threads so it won't monopolize the CPU. 108 * Todo: make this configurable 109 * 110 * Aside from that, we want these relative priorities: (a) timers, 111 * (b) notify + oplock completions, (c) workers, (d) receivers, etc. 112 * The "base" is somewhat arbirary, and what shows up in prstat 113 * because it's used for the main thread in newproc(). 114 */ 115 int smbsrv_timer_pri = MINCLSYSPRI; /* smb_server_timers */ 116 int smbsrv_base_pri = MINCLSYSPRI - 1; /* kshare thread, newproc */ 117 int smbsrv_notify_pri = MINCLSYSPRI - 1; /* oplocks, notify */ 118 /* Gap in which user-level administrative stuff runs. */ 119 int smbsrv_worker_pri = MINCLSYSPRI - 7; 120 int smbsrv_receive_pri = MINCLSYSPRI - 8; 121 int smbsrv_listen_pri = MINCLSYSPRI - 9; 122 123 124 /* 125 * ***************************************************************************** 126 * ********************** Static Variables / Module Linkage ******************** 127 * ***************************************************************************** 128 */ 129 130 static struct cb_ops cbops = { 131 smb_drv_open, /* cb_open */ 132 smb_drv_close, /* cb_close */ 133 nodev, /* cb_strategy */ 134 nodev, /* cb_print */ 135 nodev, /* cb_dump */ 136 nodev, /* cb_read */ 137 nodev, /* cb_write */ 138 smb_drv_ioctl, /* cb_ioctl */ 139 nodev, /* cb_devmap */ 140 nodev, /* cb_mmap */ 141 nodev, /* cb_segmap */ 142 nochpoll, /* cb_chpoll */ 143 ddi_prop_op, /* cb_prop_op */ 144 NULL, /* cb_streamtab */ 145 D_MP, /* cb_flag */ 146 CB_REV, /* cb_rev */ 147 nodev, /* cb_aread */ 148 nodev, /* cb_awrite */ 149 }; 150 151 static struct dev_ops devops = { 152 DEVO_REV, /* devo_rev */ 153 0, /* devo_refcnt */ 154 smb_drv_getinfo, /* devo_getinfo */ 155 nulldev, /* devo_identify */ 156 nulldev, /* devo_probe */ 157 smb_drv_attach, /* devo_attach */ 158 smb_drv_detach, /* devo_detach */ 159 nodev, /* devo_reset */ 160 &cbops, /* devo_cb_ops */ 161 NULL, /* devo_bus_ops */ 162 NULL, /* devo_power */ 163 ddi_quiesce_not_needed, /* devo_quiesce */ 164 }; 165 166 static struct modldrv modldrv = { 167 &mod_driverops, /* drv_modops */ 168 "CIFS Server Protocol", /* drv_linkinfo */ 169 &devops, 170 }; 171 172 static struct modlinkage modlinkage = { 173 MODREV_1, /* revision of the module, must be: MODREV_1 */ 174 &modldrv, /* ptr to linkage structures */ 175 NULL, 176 }; 177 178 static dev_info_t *smb_drv_dip = NULL; 179 static id_space_t *smb_drv_minors = NULL; 180 181 /* 182 * **************************************************************************** 183 * Module Interface 184 * **************************************************************************** 185 */ 186 187 int 188 _init(void) 189 { 190 int rc; 191 192 if ((rc = smb_server_g_init()) != 0) { 193 return (rc); 194 } 195 196 if ((rc = mod_install(&modlinkage)) != 0) { 197 smb_server_g_fini(); 198 } 199 200 return (rc); 201 } 202 203 int 204 _info(struct modinfo *modinfop) 205 { 206 return (mod_info(&modlinkage, modinfop)); 207 } 208 209 int 210 _fini(void) 211 { 212 int rc; 213 214 if (smb_server_get_count() != 0) 215 return (EBUSY); 216 217 if ((rc = mod_remove(&modlinkage)) == 0) { 218 smb_server_g_fini(); 219 } 220 221 return (rc); 222 } 223 224 /* 225 * **************************************************************************** 226 * Pseudo Device Entry Points 227 * **************************************************************************** 228 */ 229 /* ARGSUSED */ 230 static int 231 smb_drv_open(dev_t *devp, int flag, int otyp, cred_t *cr) 232 { 233 int rc; 234 minor_t m = getminor(*devp); 235 236 /* See ddi_create_minor_node below */ 237 switch (m) { 238 case 0: /* smbsrv (smbd only) */ 239 rc = smb_drv_open_ctl(devp, flag, otyp, cr); 240 break; 241 case 1: /* smbsrv1 (lib access) */ 242 rc = smb_drv_open_lib(devp, flag, otyp, cr); 243 break; 244 default: 245 rc = ENXIO; 246 break; 247 } 248 return (rc); 249 } 250 251 /* 252 * The smbsrvctl device is exclusively for smbd. 253 * On open, this creates an smb_server_t instance. 254 * Always exclusive open here. 255 */ 256 static int 257 smb_drv_open_ctl(dev_t *devp, int flag, int otyp, cred_t *cr) 258 { 259 dev_t clone; 260 minor_t mi; 261 int rc; 262 263 /* 264 * Check caller's privileges. 265 */ 266 if (secpolicy_smb(cr) != 0) 267 return (SET_ERROR(EPERM)); 268 269 mi = id_allocff(smb_drv_minors); 270 clone = makedevice(getmajor(*devp), mi); 271 272 /* 273 * Start SMB service state machine 274 * Note: sets sv->sv_dev = clone 275 */ 276 rc = smb_server_create(clone); 277 if (rc == 0) { 278 *devp = clone; 279 } else { 280 /* Open fails, eg EBUSY */ 281 id_free(smb_drv_minors, mi); 282 } 283 284 return (rc); 285 } 286 287 /* 288 * The smbsrv device is for library access to smbsrv state. 289 * Multiple open instances are allowed (clone-open). 290 */ 291 static int 292 smb_drv_open_lib(dev_t *devp, int flag, int otyp, cred_t *cr) 293 { 294 minor_t mi; 295 296 mi = id_allocff(smb_drv_minors); 297 *devp = makedevice(getmajor(*devp), mi); 298 299 return (0); 300 } 301 302 /* 303 * Close on unit zero (detected as: sv->sv_dev == dev) 304 * destroys the smb_server_t instance. 305 */ 306 /* 307 * The smbd process keeps the control device open for the life of 308 * smbd (service process). We know the control device is closing 309 * when the device passed to close matches the server sv_dev. 310 * When the control device closes, destroy the kernel smb_server_t 311 */ 312 /* ARGSUSED */ 313 static int 314 smb_drv_close(dev_t dev, int flag, int otyp, cred_t *credp) 315 { 316 smb_server_t *sv; 317 318 if (smb_server_lookup(&sv) == 0) { 319 if (sv->sv_dev == dev) { 320 /* Note releases the ref on sv. */ 321 (void) smb_server_delete(sv); 322 } else { 323 smb_server_release(sv); 324 } 325 } 326 id_free(smb_drv_minors, getminor(dev)); 327 328 return (0); 329 } 330 331 /* ARGSUSED */ 332 static int 333 smb_drv_ioctl(dev_t dev, int cmd, intptr_t argp, int flags, cred_t *cred, 334 int *retval) 335 { 336 smb_ioc_header_t ioc_hdr; 337 smb_ioc_t *ioc; 338 smb_server_t *sv = NULL; 339 uint32_t crc; 340 boolean_t copyout = B_FALSE; 341 int rc = 0; 342 size_t alloclen; 343 344 if (ddi_copyin((void *)argp, &ioc_hdr, sizeof (ioc_hdr), flags)) 345 return (SET_ERROR(EFAULT)); 346 347 /* 348 * Check version and length. 349 * 350 * Note that some ioctls (i.e. SMB_IOC_SVCENUM) have payload 351 * data after the ioctl struct, in which case they specify a 352 * length much larger than sizeof smb_ioc_t. The theoretical 353 * largest ioctl data is therefore the size of the union plus 354 * the max size of the payload (which is SMB_IOC_DATA_SIZE). 355 */ 356 if (ioc_hdr.version != SMB_IOC_VERSION || 357 ioc_hdr.len < sizeof (ioc_hdr) || 358 ioc_hdr.len > (sizeof (*ioc) + SMB_IOC_DATA_SIZE)) 359 return (SET_ERROR(EINVAL)); 360 361 crc = ioc_hdr.crc; 362 ioc_hdr.crc = 0; 363 if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc) 364 return (SET_ERROR(EINVAL)); 365 366 /* 367 * Note that smb_ioc_t is a union, and callers set ioc_hdr.len 368 * to the size of the actual union arm. If some caller were to 369 * set that size too small, we could end up passing under-sized 370 * memory to one of the type-specific handler functions. Avoid 371 * that problem by allocating at least the size of the union, 372 * (zeroed out) and then copy in the caller specified length. 373 */ 374 alloclen = MAX(ioc_hdr.len, sizeof (*ioc)); 375 ioc = kmem_zalloc(alloclen, KM_SLEEP); 376 if (ddi_copyin((void *)argp, ioc, ioc_hdr.len, flags)) { 377 rc = SET_ERROR(EFAULT); 378 goto out; 379 } 380 381 /* Don't allow the request size to change mid-ioctl */ 382 if (ioc_hdr.len != ioc->ioc_hdr.len) { 383 rc = SET_ERROR(EINVAL); 384 goto out; 385 } 386 387 rc = smb_server_lookup(&sv); 388 if (rc != 0) { 389 sv = NULL; 390 goto out; 391 } 392 393 /* 394 * Access control by category of ioctl codes, based on 395 * which device was opened, and privilege checks. 396 */ 397 switch (cmd) { 398 case SMB_IOC_NUMOPEN: 399 case SMB_IOC_SVCENUM: 400 /* 401 * Non-modifying ops. no special priv. 402 * beyond dev open permissions. 403 */ 404 break; 405 406 case SMB_IOC_FILE_CLOSE: 407 case SMB_IOC_SESSION_CLOSE: 408 /* 409 * Modifying ops. Require privilege 410 * (chose one smbd normally has) 411 */ 412 if ((rc = secpolicy_basic_proc(cred)) != 0) 413 goto out; 414 break; 415 default: 416 /* 417 * The rest are only allowed on the control device. 418 * Note: secpolicy_smb checked in open. 419 */ 420 if (sv->sv_dev != dev) { 421 rc = SET_ERROR(EPERM); 422 goto out; 423 } 424 break; 425 } 426 427 /* 428 * See similar in libfksmbrv fksmbsrv_drv_ioctl() 429 */ 430 switch (cmd) { 431 case SMB_IOC_CONFIG: 432 rc = smb_server_configure(sv, &ioc->ioc_cfg); 433 break; 434 case SMB_IOC_START: 435 rc = smb_server_start(sv, &ioc->ioc_start); 436 break; 437 case SMB_IOC_STOP: 438 rc = smb_server_stop(sv); 439 break; 440 case SMB_IOC_EVENT: 441 rc = smb_server_notify_event(sv, &ioc->ioc_event); 442 break; 443 case SMB_IOC_GMTOFF: 444 rc = smb_server_set_gmtoff(sv, &ioc->ioc_gmt); 445 break; 446 case SMB_IOC_SHARE: 447 rc = smb_kshare_export_list(sv, &ioc->ioc_share); 448 break; 449 case SMB_IOC_UNSHARE: 450 rc = smb_kshare_unexport_list(sv, &ioc->ioc_share); 451 break; 452 case SMB_IOC_SHAREINFO: 453 rc = smb_kshare_info(sv, &ioc->ioc_shareinfo); 454 copyout = B_TRUE; 455 break; 456 case SMB_IOC_SHAREACCESS: 457 rc = smb_kshare_access(sv, &ioc->ioc_shareaccess); 458 break; 459 case SMB_IOC_NUMOPEN: 460 rc = smb_server_numopen(sv, &ioc->ioc_opennum); 461 copyout = B_TRUE; 462 break; 463 case SMB_IOC_SVCENUM: 464 rc = smb_server_enum(sv, &ioc->ioc_svcenum); 465 copyout = B_TRUE; 466 break; 467 case SMB_IOC_SESSION_CLOSE: 468 rc = smb_server_session_close(sv, &ioc->ioc_session); 469 break; 470 case SMB_IOC_FILE_CLOSE: 471 rc = smb_server_file_close(sv, &ioc->ioc_fileid); 472 break; 473 case SMB_IOC_SPOOLDOC: 474 rc = smb_server_spooldoc(sv, &ioc->ioc_spooldoc); 475 copyout = B_TRUE; 476 break; 477 default: 478 rc = SET_ERROR(ENOTTY); 479 break; 480 } 481 if ((rc == 0) && copyout) { 482 if (ddi_copyout(ioc, (void *)argp, ioc_hdr.len, flags)) 483 rc = SET_ERROR(EFAULT); 484 } 485 out: 486 if (sv != NULL) 487 smb_server_release(sv); 488 kmem_free(ioc, alloclen); 489 return (rc); 490 } 491 492 /* 493 * **************************************************************************** 494 * Pseudo Device Operations 495 * **************************************************************************** 496 */ 497 static int 498 smb_drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 499 { 500 if (cmd != DDI_ATTACH) 501 return (DDI_FAILURE); 502 503 /* we only allow instance 0 to attach */ 504 if (ddi_get_instance(dip) != 0) 505 return (DDI_FAILURE); 506 507 /* Create the minor nodes. See smb_drv_open */ 508 if (ddi_create_minor_node(dip, "smbsrv", S_IFCHR, 0, 509 DDI_PSEUDO, 0) != DDI_SUCCESS) { 510 cmn_err(CE_WARN, "smb_drv_attach:" 511 " failed creating minor node 0"); 512 return (DDI_FAILURE); 513 } 514 if (ddi_create_minor_node(dip, "smbsrv1", S_IFCHR, 1, 515 DDI_PSEUDO, 0) != DDI_SUCCESS) { 516 cmn_err(CE_WARN, "smb_drv_attach:" 517 " failed creating minor node 1"); 518 ddi_remove_minor_node(dip, NULL); 519 return (DDI_FAILURE); 520 } 521 522 /* Reserved: control dev = 0, library dev = 1 */ 523 smb_drv_minors = id_space_create("smbsrv drv minors", 2, INT32_MAX); 524 smb_drv_dip = dip; 525 526 return (DDI_SUCCESS); 527 } 528 529 static int 530 smb_drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 531 { 532 if (cmd != DDI_DETACH) 533 return (DDI_FAILURE); 534 535 ASSERT(dip == smb_drv_dip); 536 smb_drv_dip = NULL; 537 538 id_space_destroy(smb_drv_minors); 539 smb_drv_minors = NULL; 540 541 ddi_remove_minor_node(dip, NULL); 542 543 return (DDI_SUCCESS); 544 } 545 546 /* ARGSUSED */ 547 static int 548 smb_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 549 { 550 ulong_t instance = getminor((dev_t)arg); 551 552 switch (cmd) { 553 case DDI_INFO_DEVT2DEVINFO: 554 *result = smb_drv_dip; 555 return (DDI_SUCCESS); 556 557 case DDI_INFO_DEVT2INSTANCE: 558 *result = (void *)instance; 559 return (DDI_SUCCESS); 560 561 default: 562 break; 563 } 564 565 return (DDI_FAILURE); 566 } 567