Print this page
2988 nfssrv: need ability to go to submounts for v3 and v2 protocols
Portions contributed by: Marcel Telka <marcel.telka@nexenta.com>
Portions contributed by: Jean McCormack <jean.mccormack@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Change-Id: I6fdf110cc17e789353c4442b83a46cb80643456e
   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) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2016 by Delphix. All rights reserved.
  25  */
  26 
  27 /*
  28  *      Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  29  *      All rights reserved.
  30  */
  31 
  32 #include <sys/param.h>
  33 #include <sys/types.h>
  34 #include <sys/systm.h>
  35 #include <sys/cred.h>
  36 #include <sys/buf.h>
  37 #include <sys/vfs.h>
  38 #include <sys/vnode.h>
  39 #include <sys/uio.h>
  40 #include <sys/stat.h>
  41 #include <sys/errno.h>
  42 #include <sys/sysmacros.h>
  43 #include <sys/statvfs.h>


 312                 }
 313         }
 314 
 315         ct.cc_flags = 0;
 316 
 317         /*
 318          * Force modified metadata out to stable storage.
 319          */
 320         (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 321 
 322         VN_RELE(vp);
 323 
 324         ns->ns_status = puterrno(error);
 325 }
 326 void *
 327 rfs_setattr_getfh(struct nfssaargs *args)
 328 {
 329         return (&args->saa_fh);
 330 }
 331 














































 332 /*




























 333  * Directory lookup.
 334  * Returns an fhandle and file attributes for file name in a directory.
 335  */
 336 /* ARGSUSED */
 337 void
 338 rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 339     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
 340 {
 341         int error;
 342         vnode_t *dvp;
 343         vnode_t *vp;
 344         struct vattr va;
 345         fhandle_t *fhp = da->da_fhandle;
 346         struct sec_ol sec = {0, 0};
 347         bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 348         char *name;
 349         struct sockaddr *ca;
 350 
 351         /*
 352          * Trusted Extension doesn't support NFSv2. MOUNT


 364         if (da->da_name == NULL || *da->da_name == '\0') {
 365                 dr->dr_status = NFSERR_ACCES;
 366                 return;
 367         }
 368 
 369         /*
 370          * Allow lookups from the root - the default
 371          * location of the public filehandle.
 372          */
 373         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 374                 dvp = rootdir;
 375                 VN_HOLD(dvp);
 376         } else {
 377                 dvp = nfs_fhtovp(fhp, exi);
 378                 if (dvp == NULL) {
 379                         dr->dr_status = NFSERR_STALE;
 380                         return;
 381                 }
 382         }
 383 


 384         /*
 385          * Not allow lookup beyond root.
 386          * If the filehandle matches a filehandle of the exi,
 387          * then the ".." refers beyond the root of an exported filesystem.
 388          */
 389         if (strcmp(da->da_name, "..") == 0 &&
 390             EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) {
 391                 VN_RELE(dvp);
 392                 dr->dr_status = NFSERR_NOENT;
 393                 return;





 394         }





 395 
 396         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 397         name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND,
 398             MAXPATHLEN);
 399 
 400         if (name == NULL) {
 401                 dr->dr_status = NFSERR_ACCES;
 402                 return;
 403         }
 404 
 405         /*
 406          * If the public filehandle is used then allow
 407          * a multi-component lookup, i.e. evaluate
 408          * a pathname and follow symbolic links if
 409          * necessary.
 410          *
 411          * This may result in a vnode in another filesystem
 412          * which is OK as long as the filesystem is exported.
 413          */
 414         if (PUBLIC_FH2(fhp)) {
 415                 publicfh_flag = TRUE;



 416                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 417                     &sec);
 418         } else {
 419                 /*
 420                  * Do a normal single component lookup.
 421                  */
 422                 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
 423                     NULL, NULL, NULL);
 424         }
 425 
 426         if (name != da->da_name)
 427                 kmem_free(name, MAXPATHLEN);
 428 





 429 
 430         if (!error) {
 431                 va.va_mask = AT_ALL;    /* we want everything */
 432 
 433                 error = rfs4_delegated_getattr(vp, &va, 0, cr);
 434 
 435                 /* check for overflows */
 436                 if (!error) {
 437                         acl_perm(vp, exi, &va, cr);
 438                         error = vattr_to_nattr(&va, &dr->dr_attr);
 439                         if (!error) {
 440                                 if (sec.sec_flags & SEC_QUERY)
 441                                         error = makefh_ol(&dr->dr_fhandle, exi,
 442                                             sec.sec_index);
 443                                 else {
 444                                         error = makefh(&dr->dr_fhandle, vp,
 445                                             exi);
 446                                         if (!error && publicfh_flag &&
 447                                             !chk_clnt_sec(exi, req))
 448                                                 auth_weak = TRUE;
 449                                 }
 450                         }
 451                 }
 452                 VN_RELE(vp);
 453         }
 454 

 455         VN_RELE(dvp);
 456 
 457         /*
 458          * If publicfh_flag is true then we have called rfs_publicfh_mclookup
 459          * and have obtained a new exportinfo in exi which needs to be
 460          * released. Note the the original exportinfo pointed to by exi
 461          * will be released by the caller, comon_dispatch.
 462          */
 463         if (publicfh_flag && exi != NULL)
 464                 exi_rele(exi);
 465 
 466         /*
 467          * If it's public fh, no 0x81, and client's flavor is
 468          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 469          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 470          */
 471         if (auth_weak)
 472                 dr->dr_status = (enum nfsstat)WNFSERR_CLNT_FLAVOR;
 473         else
 474                 dr->dr_status = puterrno(error);
 475 }
 476 void *
 477 rfs_lookup_getfh(struct nfsdiropargs *da)
 478 {
 479         return (da->da_fhandle);
 480 }
 481 
 482 /*
 483  * Read symbolic link.


   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 /*
  23  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  25  * Copyright (c) 2016 by Delphix. All rights reserved.
  26  */
  27 
  28 /*
  29  *      Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  30  *      All rights reserved.
  31  */
  32 
  33 #include <sys/param.h>
  34 #include <sys/types.h>
  35 #include <sys/systm.h>
  36 #include <sys/cred.h>
  37 #include <sys/buf.h>
  38 #include <sys/vfs.h>
  39 #include <sys/vnode.h>
  40 #include <sys/uio.h>
  41 #include <sys/stat.h>
  42 #include <sys/errno.h>
  43 #include <sys/sysmacros.h>
  44 #include <sys/statvfs.h>


 313                 }
 314         }
 315 
 316         ct.cc_flags = 0;
 317 
 318         /*
 319          * Force modified metadata out to stable storage.
 320          */
 321         (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 322 
 323         VN_RELE(vp);
 324 
 325         ns->ns_status = puterrno(error);
 326 }
 327 void *
 328 rfs_setattr_getfh(struct nfssaargs *args)
 329 {
 330         return (&args->saa_fh);
 331 }
 332 
 333 /* Change and release @exip and @vpp only in success */
 334 int
 335 rfs_cross_mnt(vnode_t **vpp, struct exportinfo **exip)
 336 {
 337         struct exportinfo *exi;
 338         vnode_t *vp = *vpp;
 339         fid_t fid;
 340         int error;
 341 
 342         VN_HOLD(vp);
 343 
 344         if ((error = traverse(&vp)) != 0) {
 345                 VN_RELE(vp);
 346                 return (error);
 347         }
 348 
 349         bzero(&fid, sizeof (fid));
 350         fid.fid_len = MAXFIDSZ;
 351         error = VOP_FID(vp, &fid, NULL);
 352         if (error) {
 353                 VN_RELE(vp);
 354                 return (error);
 355         }
 356 
 357         exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
 358         if (exi == NULL ||
 359             (exi->exi_export.ex_flags & EX_NOHIDE) == 0) {
 360                 /*
 361                  * It is not error, just subdir is not exported
 362                  * or "nohide" is not set
 363                  */
 364                 if (exi != NULL)
 365                         exi_rele(exi);
 366                 VN_RELE(vp);
 367         } else {
 368                 /* go to submount */
 369                 exi_rele(*exip);
 370                 *exip = exi;
 371 
 372                 VN_RELE(*vpp);
 373                 *vpp = vp;
 374         }
 375 
 376         return (0);
 377 }
 378 
 379 /*
 380  * Given mounted "dvp" and "exi", go upper mountpoint
 381  * with dvp/exi correction
 382  * Return 0 in success
 383  */
 384 int
 385 rfs_climb_crossmnt(vnode_t **dvpp, struct exportinfo **exip, cred_t *cr)
 386 {
 387         struct exportinfo *exi;
 388         vnode_t *dvp = *dvpp;
 389 
 390         ASSERT(dvp->v_flag & VROOT);
 391 
 392         VN_HOLD(dvp);
 393         dvp = untraverse(dvp);
 394         exi = nfs_vptoexi(NULL, dvp, cr, NULL, NULL, FALSE);
 395         if (exi == NULL) {
 396                 VN_RELE(dvp);
 397                 return (-1);
 398         }
 399 
 400         exi_rele(*exip);
 401         *exip = exi;
 402         VN_RELE(*dvpp);
 403         *dvpp = dvp;
 404 
 405         return (0);
 406 }
 407 /*
 408  * Directory lookup.
 409  * Returns an fhandle and file attributes for file name in a directory.
 410  */
 411 /* ARGSUSED */
 412 void
 413 rfs_lookup(struct nfsdiropargs *da, struct nfsdiropres *dr,
 414     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
 415 {
 416         int error;
 417         vnode_t *dvp;
 418         vnode_t *vp;
 419         struct vattr va;
 420         fhandle_t *fhp = da->da_fhandle;
 421         struct sec_ol sec = {0, 0};
 422         bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 423         char *name;
 424         struct sockaddr *ca;
 425 
 426         /*
 427          * Trusted Extension doesn't support NFSv2. MOUNT


 439         if (da->da_name == NULL || *da->da_name == '\0') {
 440                 dr->dr_status = NFSERR_ACCES;
 441                 return;
 442         }
 443 
 444         /*
 445          * Allow lookups from the root - the default
 446          * location of the public filehandle.
 447          */
 448         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 449                 dvp = rootdir;
 450                 VN_HOLD(dvp);
 451         } else {
 452                 dvp = nfs_fhtovp(fhp, exi);
 453                 if (dvp == NULL) {
 454                         dr->dr_status = NFSERR_STALE;
 455                         return;
 456                 }
 457         }
 458 
 459         exi_hold(exi);
 460 
 461         /*
 462          * Not allow lookup beyond root.
 463          * If the filehandle matches a filehandle of the exi,
 464          * then the ".." refers beyond the root of an exported filesystem.
 465          */
 466         if (strcmp(da->da_name, "..") == 0 &&
 467             EQFID(&exi->exi_fid, (fid_t *)&fhp->fh_len)) {
 468                 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
 469                     (dvp->v_flag & VROOT)) {
 470                         /*
 471                          * special case for ".." and 'nohide'exported root
 472                          */
 473                         if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
 474                                 error = NFSERR_ACCES;
 475                                 goto out;
 476                         }
 477                 } else  {
 478                         error = NFSERR_NOENT;
 479                         goto out;
 480                 }
 481         }
 482 
 483         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 484         name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND,
 485             MAXPATHLEN);
 486 
 487         if (name == NULL) {
 488                 error = NFSERR_ACCES;
 489                 goto out;
 490         }
 491 
 492         /*
 493          * If the public filehandle is used then allow
 494          * a multi-component lookup, i.e. evaluate
 495          * a pathname and follow symbolic links if
 496          * necessary.
 497          *
 498          * This may result in a vnode in another filesystem
 499          * which is OK as long as the filesystem is exported.
 500          */
 501         if (PUBLIC_FH2(fhp)) {
 502                 publicfh_flag = TRUE;
 503 
 504                 exi_rele(exi);
 505 
 506                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 507                     &sec);
 508         } else {
 509                 /*
 510                  * Do a normal single component lookup.
 511                  */
 512                 error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
 513                     NULL, NULL, NULL);
 514         }
 515 
 516         if (name != da->da_name)
 517                 kmem_free(name, MAXPATHLEN);
 518 
 519         if (error == 0 && vn_ismntpt(vp)) {
 520                 error = rfs_cross_mnt(&vp, &exi);
 521                 if (error)
 522                         VN_RELE(vp);
 523         }
 524 
 525         if (!error) {
 526                 va.va_mask = AT_ALL;    /* we want everything */
 527 
 528                 error = rfs4_delegated_getattr(vp, &va, 0, cr);
 529 
 530                 /* check for overflows */
 531                 if (!error) {
 532                         acl_perm(vp, exi, &va, cr);
 533                         error = vattr_to_nattr(&va, &dr->dr_attr);
 534                         if (!error) {
 535                                 if (sec.sec_flags & SEC_QUERY)
 536                                         error = makefh_ol(&dr->dr_fhandle, exi,
 537                                             sec.sec_index);
 538                                 else {
 539                                         error = makefh(&dr->dr_fhandle, vp,
 540                                             exi);
 541                                         if (!error && publicfh_flag &&
 542                                             !chk_clnt_sec(exi, req))
 543                                                 auth_weak = TRUE;
 544                                 }
 545                         }
 546                 }
 547                 VN_RELE(vp);
 548         }
 549 
 550 out:
 551         VN_RELE(dvp);
 552 
 553         if (exi != NULL)






 554                 exi_rele(exi);
 555 
 556         /*
 557          * If it's public fh, no 0x81, and client's flavor is
 558          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 559          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 560          */
 561         if (auth_weak)
 562                 dr->dr_status = (enum nfsstat)WNFSERR_CLNT_FLAVOR;
 563         else
 564                 dr->dr_status = puterrno(error);
 565 }
 566 void *
 567 rfs_lookup_getfh(struct nfsdiropargs *da)
 568 {
 569         return (da->da_fhandle);
 570 }
 571 
 572 /*
 573  * Read symbolic link.