1 /* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $ 33 */ 34 35 /* 36 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 37 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 38 * Copyright 2013, Joyent, Inc. All rights reserved. 39 * Copyright (c) 2016 by Delphix. All rights reserved. 40 */ 41 42 #include <sys/systm.h> 43 #include <sys/cred.h> 44 #include <sys/time.h> 45 #include <sys/vfs.h> 46 #include <sys/vnode.h> 47 #include <fs/fs_subr.h> 48 #include <sys/sysmacros.h> 49 #include <sys/kmem.h> 50 #include <sys/mkdev.h> 51 #include <sys/mount.h> 52 #include <sys/statvfs.h> 53 #include <sys/errno.h> 54 #include <sys/debug.h> 55 #include <sys/cmn_err.h> 56 #include <sys/modctl.h> 57 #include <sys/policy.h> 58 #include <sys/atomic.h> 59 #include <sys/zone.h> 60 #include <sys/vfs_opreg.h> 61 #include <sys/mntent.h> 62 #include <sys/priv.h> 63 #include <sys/tsol/label.h> 64 #include <sys/tsol/tndb.h> 65 #include <inet/ip.h> 66 67 #include <netsmb/smb_osdep.h> 68 #include <netsmb/smb.h> 69 #include <netsmb/smb_conn.h> 70 #include <netsmb/smb_subr.h> 71 #include <netsmb/smb_dev.h> 72 73 #include <smbfs/smbfs.h> 74 #include <smbfs/smbfs_node.h> 75 #include <smbfs/smbfs_subr.h> 76 77 /* 78 * Should smbfs mount enable "-o acl" by default? There are good 79 * arguments for both. The most common use case is individual users 80 * accessing files on some SMB server, for which "noacl" is the more 81 * convenient default. A less common use case is data migration, 82 * where the "acl" option might be a desirable default. We'll make 83 * the common use case the default. This default can be changed via 84 * /etc/system, and/or set per-mount via the "acl" mount option. 85 */ 86 int smbfs_default_opt_acl = 0; 87 88 /* 89 * Local functions definitions. 90 */ 91 int smbfsinit(int fstyp, char *name); 92 void smbfsfini(); 93 static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); 94 95 /* 96 * SMBFS Mount options table for MS_OPTIONSTR 97 * Note: These are not all the options. 98 * Some options come in via MS_DATA. 99 * Others are generic (see vfs.c) 100 */ 101 static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; 102 static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; 103 static char *acl_cancel[] = { MNTOPT_NOACL, NULL }; 104 static char *noacl_cancel[] = { MNTOPT_ACL, NULL }; 105 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; 106 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; 107 108 static mntopt_t mntopts[] = { 109 /* 110 * option name cancel option default arg flags 111 * ufs arg flag 112 */ 113 { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, 114 { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, 115 { MNTOPT_ACL, acl_cancel, NULL, 0, 0 }, 116 { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, 117 { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, 118 { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } 119 }; 120 121 static mntopts_t smbfs_mntopts = { 122 sizeof (mntopts) / sizeof (mntopt_t), 123 mntopts 124 }; 125 126 static const char fs_type_name[FSTYPSZ] = "smbfs"; 127 128 static vfsdef_t vfw = { 129 VFSDEF_VERSION, 130 (char *)fs_type_name, 131 smbfsinit, /* init routine */ 132 VSW_HASPROTO|VSW_NOTZONESAFE, /* flags */ 133 &smbfs_mntopts /* mount options table prototype */ 134 }; 135 136 static struct modlfs modlfs = { 137 &mod_fsops, 138 "SMBFS filesystem", 139 &vfw 140 }; 141 142 static struct modlinkage modlinkage = { 143 MODREV_1, (void *)&modlfs, NULL 144 }; 145 146 /* 147 * Mutex to protect the following variables: 148 * smbfs_major 149 * smbfs_minor 150 */ 151 extern kmutex_t smbfs_minor_lock; 152 extern int smbfs_major; 153 extern int smbfs_minor; 154 155 /* 156 * Prevent unloads while we have mounts 157 */ 158 uint32_t smbfs_mountcount; 159 160 /* 161 * smbfs vfs operations. 162 */ 163 static int smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); 164 static int smbfs_unmount(vfs_t *, int, cred_t *); 165 static int smbfs_root(vfs_t *, vnode_t **); 166 static int smbfs_statvfs(vfs_t *, statvfs64_t *); 167 static int smbfs_sync(vfs_t *, short, cred_t *); 168 static void smbfs_freevfs(vfs_t *); 169 170 /* 171 * Module loading 172 */ 173 174 /* 175 * This routine is invoked automatically when the kernel module 176 * containing this routine is loaded. This allows module specific 177 * initialization to be done when the module is loaded. 178 */ 179 int 180 _init(void) 181 { 182 int error; 183 184 /* 185 * Check compiled-in version of "nsmb" 186 * that we're linked with. (paranoid) 187 */ 188 if (nsmb_version != NSMB_VERSION) { 189 cmn_err(CE_WARN, "_init: nsmb version mismatch"); 190 return (ENOTTY); 191 } 192 193 smbfs_mountcount = 0; 194 195 /* 196 * NFS calls these two in _clntinit 197 * Easier to follow this way. 198 */ 199 if ((error = smbfs_subrinit()) != 0) { 200 cmn_err(CE_WARN, "_init: smbfs_subrinit failed"); 201 return (error); 202 } 203 204 if ((error = smbfs_vfsinit()) != 0) { 205 cmn_err(CE_WARN, "_init: smbfs_vfsinit failed"); 206 smbfs_subrfini(); 207 return (error); 208 } 209 210 if ((error = smbfs_clntinit()) != 0) { 211 cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); 212 smbfs_vfsfini(); 213 smbfs_subrfini(); 214 return (error); 215 } 216 217 error = mod_install((struct modlinkage *)&modlinkage); 218 return (error); 219 } 220 221 /* 222 * Free kernel module resources that were allocated in _init 223 * and remove the linkage information into the kernel 224 */ 225 int 226 _fini(void) 227 { 228 int error; 229 230 /* 231 * If a forcedly unmounted instance is still hanging around, 232 * we cannot allow the module to be unloaded because that would 233 * cause panics once the VFS framework decides it's time to call 234 * into VFS_FREEVFS(). 235 */ 236 if (smbfs_mountcount) 237 return (EBUSY); 238 239 error = mod_remove(&modlinkage); 240 if (error) 241 return (error); 242 243 /* 244 * Free the allocated smbnodes, etc. 245 */ 246 smbfs_clntfini(); 247 248 /* NFS calls these two in _clntfini */ 249 smbfs_vfsfini(); 250 smbfs_subrfini(); 251 252 /* 253 * Free the ops vectors 254 */ 255 smbfsfini(); 256 return (0); 257 } 258 259 /* 260 * Return information about the module 261 */ 262 int 263 _info(struct modinfo *modinfop) 264 { 265 return (mod_info((struct modlinkage *)&modlinkage, modinfop)); 266 } 267 268 /* 269 * Initialize the vfs structure 270 */ 271 272 int smbfsfstyp; 273 vfsops_t *smbfs_vfsops = NULL; 274 275 static const fs_operation_def_t smbfs_vfsops_template[] = { 276 { VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } }, 277 { VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } }, 278 { VFSNAME_ROOT, { .vfs_root = smbfs_root } }, 279 { VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } }, 280 { VFSNAME_SYNC, { .vfs_sync = smbfs_sync } }, 281 { VFSNAME_VGET, { .error = fs_nosys } }, 282 { VFSNAME_MOUNTROOT, { .error = fs_nosys } }, 283 { VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } }, 284 { NULL, NULL } 285 }; 286 287 int 288 smbfsinit(int fstyp, char *name) 289 { 290 int error; 291 292 error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops); 293 if (error != 0) { 294 zcmn_err(GLOBAL_ZONEID, CE_WARN, 295 "smbfsinit: bad vfs ops template"); 296 return (error); 297 } 298 299 error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops); 300 if (error != 0) { 301 (void) vfs_freevfsops_by_type(fstyp); 302 zcmn_err(GLOBAL_ZONEID, CE_WARN, 303 "smbfsinit: bad vnode ops template"); 304 return (error); 305 } 306 307 smbfsfstyp = fstyp; 308 309 return (0); 310 } 311 312 void 313 smbfsfini() 314 { 315 if (smbfs_vfsops) { 316 (void) vfs_freevfsops_by_type(smbfsfstyp); 317 smbfs_vfsops = NULL; 318 } 319 if (smbfs_vnodeops) { 320 vn_freevnodeops(smbfs_vnodeops); 321 smbfs_vnodeops = NULL; 322 } 323 } 324 325 void 326 smbfs_free_smi(smbmntinfo_t *smi) 327 { 328 if (smi == NULL) 329 return; 330 331 if (smi->smi_zone_ref.zref_zone != NULL) 332 zone_rele_ref(&smi->smi_zone_ref, ZONE_REF_SMBFS); 333 334 if (smi->smi_share != NULL) 335 smb_share_rele(smi->smi_share); 336 337 avl_destroy(&smi->smi_hash_avl); 338 rw_destroy(&smi->smi_hash_lk); 339 cv_destroy(&smi->smi_statvfs_cv); 340 mutex_destroy(&smi->smi_lock); 341 342 kmem_free(smi, sizeof (smbmntinfo_t)); 343 } 344 345 /* 346 * smbfs mount vfsop 347 * Set up mount info record and attach it to vfs struct. 348 */ 349 static int 350 smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) 351 { 352 char *data = uap->dataptr; 353 int error; 354 smbnode_t *rtnp = NULL; /* root of this fs */ 355 smbmntinfo_t *smi = NULL; 356 dev_t smbfs_dev; 357 int version; 358 int devfd; 359 zone_t *zone = curproc->p_zone; 360 zone_t *mntzone = NULL; 361 smb_share_t *ssp = NULL; 362 smb_cred_t scred; 363 int flags, sec; 364 365 STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ 366 367 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0) 368 return (error); 369 370 if (mvp->v_type != VDIR) 371 return (ENOTDIR); 372 373 /* 374 * get arguments 375 * 376 * uap->datalen might be different from sizeof (args) 377 * in a compatible situation. 378 */ 379 STRUCT_INIT(args, get_udatamodel()); 380 bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); 381 if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen, 382 SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)))) 383 return (EFAULT); 384 385 /* 386 * Check mount program version 387 */ 388 version = STRUCT_FGET(args, version); 389 if (version != SMBFS_VERSION) { 390 cmn_err(CE_WARN, "mount version mismatch:" 391 " kernel=%d, mount=%d\n", 392 SMBFS_VERSION, version); 393 return (EINVAL); 394 } 395 396 /* 397 * Deal with re-mount requests. 398 */ 399 if (uap->flags & MS_REMOUNT) { 400 cmn_err(CE_WARN, "MS_REMOUNT not implemented"); 401 return (ENOTSUP); 402 } 403 404 /* 405 * Check for busy 406 */ 407 mutex_enter(&mvp->v_lock); 408 if (!(uap->flags & MS_OVERLAY) && 409 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) { 410 mutex_exit(&mvp->v_lock); 411 return (EBUSY); 412 } 413 mutex_exit(&mvp->v_lock); 414 415 /* 416 * Get the "share" from the netsmb driver (ssp). 417 * It is returned with a "ref" (hold) for us. 418 * Release this hold: at errout below, or in 419 * smbfs_freevfs(). 420 */ 421 devfd = STRUCT_FGET(args, devfd); 422 error = smb_dev2share(devfd, &ssp); 423 if (error) { 424 cmn_err(CE_WARN, "invalid device handle %d (%d)\n", 425 devfd, error); 426 return (error); 427 } 428 429 /* 430 * Use "goto errout" from here on. 431 * See: ssp, smi, rtnp, mntzone 432 */ 433 434 /* 435 * Determine the zone we're being mounted into. 436 */ 437 zone_hold(mntzone = zone); /* start with this assumption */ 438 if (getzoneid() == GLOBAL_ZONEID) { 439 zone_rele(mntzone); 440 mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); 441 ASSERT(mntzone != NULL); 442 if (mntzone != zone) { 443 error = EBUSY; 444 goto errout; 445 } 446 } 447 448 /* 449 * Stop the mount from going any further if the zone is going away. 450 */ 451 if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) { 452 error = EBUSY; 453 goto errout; 454 } 455 456 /* 457 * On a Trusted Extensions client, we may have to force read-only 458 * for read-down mounts. 459 */ 460 if (is_system_labeled()) { 461 void *addr; 462 int ipvers = 0; 463 struct smb_vc *vcp; 464 465 vcp = SSTOVC(ssp); 466 addr = smb_vc_getipaddr(vcp, &ipvers); 467 error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr); 468 469 if (error > 0) 470 goto errout; 471 472 if (error == -1) { 473 /* change mount to read-only to prevent write-down */ 474 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); 475 } 476 } 477 478 /* Prevent unload. */ 479 atomic_inc_32(&smbfs_mountcount); 480 481 /* 482 * Create a mount record and link it to the vfs struct. 483 * No more possiblities for errors from here on. 484 * Tear-down of this stuff is in smbfs_free_smi() 485 * 486 * Compare with NFS: nfsrootvp() 487 */ 488 smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); 489 490 mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); 491 cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); 492 493 rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); 494 smbfs_init_hash_avl(&smi->smi_hash_avl); 495 496 smi->smi_share = ssp; 497 ssp = NULL; 498 499 /* 500 * Convert the anonymous zone hold acquired via zone_hold() above 501 * into a zone reference. 502 */ 503 zone_init_ref(&smi->smi_zone_ref); 504 zone_hold_ref(mntzone, &smi->smi_zone_ref, ZONE_REF_SMBFS); 505 zone_rele(mntzone); 506 mntzone = NULL; 507 508 /* 509 * Initialize option defaults 510 */ 511 smi->smi_flags = SMI_LLOCK; 512 smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); 513 smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); 514 smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); 515 smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); 516 517 /* 518 * All "generic" mount options have already been 519 * handled in vfs.c:domount() - see mntopts stuff. 520 * Query generic options using vfs_optionisset(). 521 * Give ACL an adjustable system-wide default. 522 */ 523 if (smbfs_default_opt_acl || 524 vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) 525 smi->smi_flags |= SMI_ACL; 526 if (vfs_optionisset(vfsp, MNTOPT_NOACL, NULL)) 527 smi->smi_flags &= ~SMI_ACL; 528 if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) 529 smi->smi_flags |= SMI_INT; 530 531 /* 532 * Get the mount options that come in as smbfs_args, 533 * starting with args.flags (SMBFS_MF_xxx) 534 */ 535 flags = STRUCT_FGET(args, flags); 536 smi->smi_uid = STRUCT_FGET(args, uid); 537 smi->smi_gid = STRUCT_FGET(args, gid); 538 smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; 539 smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; 540 541 /* 542 * Hande the SMBFS_MF_xxx flags. 543 */ 544 if (flags & SMBFS_MF_NOAC) 545 smi->smi_flags |= SMI_NOAC; 546 if (flags & SMBFS_MF_ACREGMIN) { 547 sec = STRUCT_FGET(args, acregmin); 548 if (sec < 0 || sec > SMBFS_ACMINMAX) 549 sec = SMBFS_ACMINMAX; 550 smi->smi_acregmin = SEC2HR(sec); 551 } 552 if (flags & SMBFS_MF_ACREGMAX) { 553 sec = STRUCT_FGET(args, acregmax); 554 if (sec < 0 || sec > SMBFS_ACMAXMAX) 555 sec = SMBFS_ACMAXMAX; 556 smi->smi_acregmax = SEC2HR(sec); 557 } 558 if (flags & SMBFS_MF_ACDIRMIN) { 559 sec = STRUCT_FGET(args, acdirmin); 560 if (sec < 0 || sec > SMBFS_ACMINMAX) 561 sec = SMBFS_ACMINMAX; 562 smi->smi_acdirmin = SEC2HR(sec); 563 } 564 if (flags & SMBFS_MF_ACDIRMAX) { 565 sec = STRUCT_FGET(args, acdirmax); 566 if (sec < 0 || sec > SMBFS_ACMAXMAX) 567 sec = SMBFS_ACMAXMAX; 568 smi->smi_acdirmax = SEC2HR(sec); 569 } 570 571 /* 572 * Get attributes of the remote file system, 573 * i.e. ACL support, named streams, etc. 574 */ 575 smb_credinit(&scred, cr); 576 error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); 577 smb_credrele(&scred); 578 if (error) { 579 SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); 580 } 581 582 /* 583 * We enable XATTR by default (via smbfs_mntopts) 584 * but if the share does not support named streams, 585 * force the NOXATTR option (also clears XATTR). 586 * Caller will set or clear VFS_XATTR after this. 587 */ 588 if ((smi->smi_fsattr & FILE_NAMED_STREAMS) == 0) 589 vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); 590 591 /* 592 * Ditto ACLs (disable if not supported on this share) 593 */ 594 if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { 595 vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); 596 smi->smi_flags &= ~SMI_ACL; 597 } 598 599 /* 600 * Assign a unique device id to the mount 601 */ 602 mutex_enter(&smbfs_minor_lock); 603 do { 604 smbfs_minor = (smbfs_minor + 1) & MAXMIN32; 605 smbfs_dev = makedevice(smbfs_major, smbfs_minor); 606 } while (vfs_devismounted(smbfs_dev)); 607 mutex_exit(&smbfs_minor_lock); 608 609 vfsp->vfs_dev = smbfs_dev; 610 vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp); 611 vfsp->vfs_data = (caddr_t)smi; 612 vfsp->vfs_fstype = smbfsfstyp; 613 vfsp->vfs_bsize = MAXBSIZE; 614 vfsp->vfs_bcount = 0; 615 616 smi->smi_vfsp = vfsp; 617 smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ 618 619 /* PSARC 2007/227 VFS Feature Registration */ 620 vfs_set_feature(vfsp, VFSFT_XVATTR); 621 vfs_set_feature(vfsp, VFSFT_SYSATTR_VIEWS); 622 623 /* 624 * Create the root vnode, which we need in unmount 625 * for the call to smbfs_check_table(), etc. 626 * Release this hold in smbfs_unmount. 627 */ 628 rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, 629 &smbfs_fattr0); 630 ASSERT(rtnp != NULL); 631 rtnp->r_vnode->v_type = VDIR; 632 rtnp->r_vnode->v_flag |= VROOT; 633 smi->smi_root = rtnp; 634 635 /* 636 * NFS does other stuff here too: 637 * async worker threads 638 * init kstats 639 * 640 * End of code from NFS nfsrootvp() 641 */ 642 return (0); 643 644 errout: 645 vfsp->vfs_data = NULL; 646 if (smi != NULL) 647 smbfs_free_smi(smi); 648 649 if (mntzone != NULL) 650 zone_rele(mntzone); 651 652 if (ssp != NULL) 653 smb_share_rele(ssp); 654 655 return (error); 656 } 657 658 /* 659 * vfs operations 660 */ 661 static int 662 smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) 663 { 664 smbmntinfo_t *smi; 665 smbnode_t *rtnp; 666 667 smi = VFTOSMI(vfsp); 668 669 if (secpolicy_fs_unmount(cr, vfsp) != 0) 670 return (EPERM); 671 672 if ((flag & MS_FORCE) == 0) { 673 smbfs_rflush(vfsp, cr); 674 675 /* 676 * If there are any active vnodes on this file system, 677 * (other than the root vnode) then the file system is 678 * busy and can't be umounted. 679 */ 680 if (smbfs_check_table(vfsp, smi->smi_root)) 681 return (EBUSY); 682 683 /* 684 * We normally hold a ref to the root vnode, so 685 * check for references beyond the one we expect: 686 * smbmntinfo_t -> smi_root 687 * Note that NFS does not hold the root vnode. 688 */ 689 if (smi->smi_root && 690 smi->smi_root->r_vnode->v_count > 1) 691 return (EBUSY); 692 } 693 694 /* 695 * common code for both forced and non-forced 696 * 697 * Setting VFS_UNMOUNTED prevents new operations. 698 * Operations already underway may continue, 699 * but not for long. 700 */ 701 vfsp->vfs_flag |= VFS_UNMOUNTED; 702 703 /* 704 * Shutdown any outstanding I/O requests on this share, 705 * and force a tree disconnect. The share object will 706 * continue to hang around until smb_share_rele(). 707 * This should also cause most active nodes to be 708 * released as their operations fail with EIO. 709 */ 710 smb_share_kill(smi->smi_share); 711 712 /* 713 * If we hold the root VP (and we normally do) 714 * then it's safe to release it now. 715 */ 716 if (smi->smi_root) { 717 rtnp = smi->smi_root; 718 smi->smi_root = NULL; 719 VN_RELE(rtnp->r_vnode); /* release root vnode */ 720 } 721 722 /* 723 * Remove all nodes from the node hash tables. 724 * This (indirectly) calls: smbfs_addfree, smbinactive, 725 * which will try to flush dirty pages, etc. so 726 * don't destroy the underlying share just yet. 727 * 728 * Also, with a forced unmount, some nodes may 729 * remain active, and those will get cleaned up 730 * after their last vn_rele. 731 */ 732 smbfs_destroy_table(vfsp); 733 734 /* 735 * Delete our kstats... 736 * 737 * Doing it here, rather than waiting until 738 * smbfs_freevfs so these are not visible 739 * after the unmount. 740 */ 741 if (smi->smi_io_kstats) { 742 kstat_delete(smi->smi_io_kstats); 743 smi->smi_io_kstats = NULL; 744 } 745 if (smi->smi_ro_kstats) { 746 kstat_delete(smi->smi_ro_kstats); 747 smi->smi_ro_kstats = NULL; 748 } 749 750 /* 751 * The rest happens in smbfs_freevfs() 752 */ 753 return (0); 754 } 755 756 757 /* 758 * find root of smbfs 759 */ 760 static int 761 smbfs_root(vfs_t *vfsp, vnode_t **vpp) 762 { 763 smbmntinfo_t *smi; 764 vnode_t *vp; 765 766 smi = VFTOSMI(vfsp); 767 768 if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 769 return (EPERM); 770 771 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 772 return (EIO); 773 774 /* 775 * The root vp is created in mount and held 776 * until unmount, so this is paranoia. 777 */ 778 if (smi->smi_root == NULL) 779 return (EIO); 780 781 /* Just take a reference and return it. */ 782 vp = SMBTOV(smi->smi_root); 783 VN_HOLD(vp); 784 *vpp = vp; 785 786 return (0); 787 } 788 789 /* 790 * Get file system statistics. 791 */ 792 static int 793 smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp) 794 { 795 int error; 796 smbmntinfo_t *smi = VFTOSMI(vfsp); 797 smb_share_t *ssp = smi->smi_share; 798 statvfs64_t stvfs; 799 hrtime_t now; 800 smb_cred_t scred; 801 802 if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 803 return (EPERM); 804 805 if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 806 return (EIO); 807 808 mutex_enter(&smi->smi_lock); 809 810 /* 811 * Use cached result if still valid. 812 */ 813 recheck: 814 now = gethrtime(); 815 if (now < smi->smi_statfstime) { 816 error = 0; 817 goto cache_hit; 818 } 819 820 /* 821 * FS attributes are stale, so someone 822 * needs to do an OTW call to get them. 823 * Serialize here so only one thread 824 * does the OTW call. 825 */ 826 if (smi->smi_status & SM_STATUS_STATFS_BUSY) { 827 smi->smi_status |= SM_STATUS_STATFS_WANT; 828 if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) { 829 mutex_exit(&smi->smi_lock); 830 return (EINTR); 831 } 832 /* Hope status is valid now. */ 833 goto recheck; 834 } 835 smi->smi_status |= SM_STATUS_STATFS_BUSY; 836 mutex_exit(&smi->smi_lock); 837 838 /* 839 * Do the OTW call. Note: lock NOT held. 840 */ 841 smb_credinit(&scred, NULL); 842 bzero(&stvfs, sizeof (stvfs)); 843 error = smbfs_smb_statfs(ssp, &stvfs, &scred); 844 smb_credrele(&scred); 845 if (error) { 846 SMBVDEBUG("statfs error=%d\n", error); 847 } else { 848 849 /* 850 * Set a few things the OTW call didn't get. 851 */ 852 stvfs.f_frsize = stvfs.f_bsize; 853 stvfs.f_favail = stvfs.f_ffree; 854 stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0]; 855 bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ); 856 stvfs.f_flag = vf_to_stf(vfsp->vfs_flag); 857 stvfs.f_namemax = smi->smi_fsa.fsa_maxname; 858 859 /* 860 * Save the result, update lifetime 861 */ 862 now = gethrtime(); 863 smi->smi_statfstime = now + 864 (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC); 865 smi->smi_statvfsbuf = stvfs; /* struct assign! */ 866 } 867 868 mutex_enter(&smi->smi_lock); 869 if (smi->smi_status & SM_STATUS_STATFS_WANT) 870 cv_broadcast(&smi->smi_statvfs_cv); 871 smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT); 872 873 /* 874 * Copy the statvfs data to caller's buf. 875 * Note: struct assignment 876 */ 877 cache_hit: 878 if (error == 0) 879 *sbp = smi->smi_statvfsbuf; 880 mutex_exit(&smi->smi_lock); 881 return (error); 882 } 883 884 static kmutex_t smbfs_syncbusy; 885 886 /* 887 * Flush dirty smbfs files for file system vfsp. 888 * If vfsp == NULL, all smbfs files are flushed. 889 */ 890 /*ARGSUSED*/ 891 static int 892 smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) 893 { 894 /* 895 * Cross-zone calls are OK here, since this translates to a 896 * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. 897 */ 898 if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { 899 smbfs_rflush(vfsp, cr); 900 mutex_exit(&smbfs_syncbusy); 901 } 902 903 return (0); 904 } 905 906 /* 907 * Initialization routine for VFS routines. Should only be called once 908 */ 909 int 910 smbfs_vfsinit(void) 911 { 912 mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL); 913 return (0); 914 } 915 916 /* 917 * Shutdown routine for VFS routines. Should only be called once 918 */ 919 void 920 smbfs_vfsfini(void) 921 { 922 mutex_destroy(&smbfs_syncbusy); 923 } 924 925 void 926 smbfs_freevfs(vfs_t *vfsp) 927 { 928 smbmntinfo_t *smi; 929 930 /* free up the resources */ 931 smi = VFTOSMI(vfsp); 932 933 /* 934 * By this time we should have already deleted the 935 * smi kstats in the unmount code. If they are still around 936 * something is wrong 937 */ 938 ASSERT(smi->smi_io_kstats == NULL); 939 940 smbfs_zonelist_remove(smi); 941 942 smbfs_free_smi(smi); 943 944 /* 945 * Allow _fini() to succeed now, if so desired. 946 */ 947 atomic_dec_32(&smbfs_mountcount); 948 } 949 950 /* 951 * smbfs_mount_label_policy: 952 * Determine whether the mount is allowed according to MAC check, 953 * by comparing (where appropriate) label of the remote server 954 * against the label of the zone being mounted into. 955 * 956 * Returns: 957 * 0 : access allowed 958 * -1 : read-only access allowed (i.e., read-down) 959 * >0 : error code, such as EACCES 960 * 961 * NB: 962 * NFS supports Cipso labels by parsing the vfs_resource 963 * to see what the Solaris server global zone has shared. 964 * We can't support that for CIFS since resource names 965 * contain share names, not paths. 966 */ 967 static int 968 smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr) 969 { 970 bslabel_t *server_sl, *mntlabel; 971 zone_t *mntzone = NULL; 972 ts_label_t *zlabel; 973 tsol_tpc_t *tp; 974 ts_label_t *tsl = NULL; 975 int retv; 976 977 /* 978 * Get the zone's label. Each zone on a labeled system has a label. 979 */ 980 mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE); 981 zlabel = mntzone->zone_slabel; 982 ASSERT(zlabel != NULL); 983 label_hold(zlabel); 984 985 retv = EACCES; /* assume the worst */ 986 987 /* 988 * Next, get the assigned label of the remote server. 989 */ 990 tp = find_tpc(ipaddr, addr_type, B_FALSE); 991 if (tp == NULL) 992 goto out; /* error getting host entry */ 993 994 if (tp->tpc_tp.tp_doi != zlabel->tsl_doi) 995 goto rel_tpc; /* invalid domain */ 996 if ((tp->tpc_tp.host_type != UNLABELED)) 997 goto rel_tpc; /* invalid hosttype */ 998 999 server_sl = &tp->tpc_tp.tp_def_label; 1000 mntlabel = label2bslabel(zlabel); 1001 1002 /* 1003 * Now compare labels to complete the MAC check. If the labels 1004 * are equal or if the requestor is in the global zone and has 1005 * NET_MAC_AWARE, then allow read-write access. (Except for 1006 * mounts into the global zone itself; restrict these to 1007 * read-only.) 1008 * 1009 * If the requestor is in some other zone, but their label 1010 * dominates the server, then allow read-down. 1011 * 1012 * Otherwise, access is denied. 1013 */ 1014 if (blequal(mntlabel, server_sl) || 1015 (crgetzoneid(cr) == GLOBAL_ZONEID && 1016 getpflags(NET_MAC_AWARE, cr) != 0)) { 1017 if ((mntzone == global_zone) || 1018 !blequal(mntlabel, server_sl)) 1019 retv = -1; /* read-only */ 1020 else 1021 retv = 0; /* access OK */ 1022 } else if (bldominates(mntlabel, server_sl)) { 1023 retv = -1; /* read-only */ 1024 } else { 1025 retv = EACCES; 1026 } 1027 1028 if (tsl != NULL) 1029 label_rele(tsl); 1030 1031 rel_tpc: 1032 /*LINTED*/ 1033 TPC_RELE(tp); 1034 out: 1035 if (mntzone) 1036 zone_rele(mntzone); 1037 label_rele(zlabel); 1038 return (retv); 1039 }