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.
|