365 /* ARGSUSED */
366 void
367 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
368 struct svc_req *req, cred_t *cr, bool_t ro)
369 {
370 int error;
371 vnode_t *vp;
372 vnode_t *dvp;
373 struct vattr *vap;
374 struct vattr va;
375 struct vattr *dvap;
376 struct vattr dva;
377 nfs_fh3 *fhp;
378 struct sec_ol sec = {0, 0};
379 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
380 struct sockaddr *ca;
381 char *name = NULL;
382
383 dvap = NULL;
384
385 /*
386 * Allow lookups from the root - the default
387 * location of the public filehandle.
388 */
389 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
390 dvp = rootdir;
391 VN_HOLD(dvp);
392
393 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
394 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
395 } else {
396 dvp = nfs3_fhtovp(&args->what.dir, exi);
397
398 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
399 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
400
401 if (dvp == NULL) {
402 error = ESTALE;
403 goto out;
404 }
405 }
406
407 dva.va_mask = AT_ALL;
408 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
409
410 if (args->what.name == nfs3nametoolong) {
411 resp->status = NFS3ERR_NAMETOOLONG;
412 goto out1;
413 }
414
415 if (args->what.name == NULL || *(args->what.name) == '\0') {
416 resp->status = NFS3ERR_ACCES;
417 goto out1;
418 }
419
420 fhp = &args->what.dir;
421 if (strcmp(args->what.name, "..") == 0 &&
422 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
423 resp->status = NFS3ERR_NOENT;
424 goto out1;
425 }
426
427 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
428 name = nfscmd_convname(ca, exi, args->what.name,
429 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
430
431 if (name == NULL) {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435
436 /*
437 * If the public filehandle is used then allow
438 * a multi-component lookup
439 */
440 if (PUBLIC_FH3(&args->what.dir)) {
441 publicfh_flag = TRUE;
442 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
443 &exi, &sec);
444 if (error && exi != NULL)
445 exi_rele(exi); /* See comment below Re: publicfh_flag */
446 /*
447 * Since WebNFS may bypass MOUNT, we need to ensure this
448 * request didn't come from an unlabeled admin_low client.
449 */
450 if (is_system_labeled() && error == 0) {
451 int addr_type;
452 void *ipaddr;
453 tsol_tpc_t *tp;
454
455 if (ca->sa_family == AF_INET) {
456 addr_type = IPV4_VERSION;
457 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
458 } else if (ca->sa_family == AF_INET6) {
459 addr_type = IPV6_VERSION;
460 ipaddr = &((struct sockaddr_in6 *)
461 ca)->sin6_addr;
462 }
463 tp = find_tpc(ipaddr, addr_type, B_FALSE);
464 if (tp == NULL || tp->tpc_tp.tp_doi !=
465 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
466 SUN_CIPSO) {
467 if (exi != NULL)
468 exi_rele(exi);
469 VN_RELE(vp);
470 error = EACCES;
471 }
472 if (tp != NULL)
473 TPC_RELE(tp);
474 }
475 } else {
476 error = VOP_LOOKUP(dvp, name, &vp,
477 NULL, 0, NULL, cr, NULL, NULL, NULL);
478 }
479
480 if (name != args->what.name)
481 kmem_free(name, MAXPATHLEN + 1);
482
483 if (is_system_labeled() && error == 0) {
484 bslabel_t *clabel = req->rq_label;
485
486 ASSERT(clabel != NULL);
487 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
488 "got client label from request(1)", struct svc_req *, req);
489
490 if (!blequal(&l_admin_low->tsl_label, clabel)) {
491 if (!do_rfs_label_check(clabel, dvp,
492 DOMINANCE_CHECK, exi)) {
493 if (publicfh_flag && exi != NULL)
494 exi_rele(exi);
495 VN_RELE(vp);
496 error = EACCES;
497 }
498 }
499 }
500
501 dva.va_mask = AT_ALL;
502 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
503
504 if (error)
505 goto out;
506
507 if (sec.sec_flags & SEC_QUERY) {
508 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
509 } else {
510 error = makefh3(&resp->resok.object, vp, exi);
511 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
512 auth_weak = TRUE;
513 }
514
515 /*
516 * If publicfh_flag is true then we have called rfs_publicfh_mclookup
517 * and have obtained a new exportinfo in exi which needs to be
518 * released. Note that the original exportinfo pointed to by exi
519 * will be released by the caller, common_dispatch.
520 */
521 if (publicfh_flag)
522 exi_rele(exi);
523
524 if (error) {
525 VN_RELE(vp);
526 goto out;
527 }
528
529 va.va_mask = AT_ALL;
530 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
531
532 VN_RELE(vp);
533
534 resp->status = NFS3_OK;
535 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
536 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
537
538 /*
539 * If it's public fh, no 0x81, and client's flavor is
540 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
541 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
542 */
543 if (auth_weak)
544 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
545
546 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
547 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
548 VN_RELE(dvp);
549
550 return;
551
552 out:
553 if (curthread->t_flag & T_WOULDBLOCK) {
554 curthread->t_flag &= ~T_WOULDBLOCK;
555 resp->status = NFS3ERR_JUKEBOX;
556 } else
557 resp->status = puterrno3(error);
558 out1:
559 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
560 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
561
562 if (dvp != NULL)
563 VN_RELE(dvp);
564 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
565
566 }
567
568 void *
569 rfs3_lookup_getfh(LOOKUP3args *args)
570 {
571
572 return (&args->what.dir);
573 }
574
575 /* ARGSUSED */
576 void
577 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
578 struct svc_req *req, cred_t *cr, bool_t ro)
3592 }
3593
3594 infop[i].namelen = namlen[i];
3595
3596 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3597 NULL, NULL, NULL);
3598 if (error) {
3599 infop[i].attr.attributes = FALSE;
3600 infop[i].fh.handle_follows = FALSE;
3601 dp = nextdp(dp);
3602 continue;
3603 }
3604
3605 nva.va_mask = AT_ALL;
3606 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3607
3608 /* Lie about the object type for a referral */
3609 if (vn_is_nfs_reparse(nvp, cr))
3610 nvap->va_type = VLNK;
3611
3612 vattr_to_post_op_attr(nvap, &infop[i].attr);
3613
3614 error = makefh3(&infop[i].fh.handle, nvp, exi);
3615 if (!error)
3616 infop[i].fh.handle_follows = TRUE;
3617 else
3618 infop[i].fh.handle_follows = FALSE;
3619
3620 VN_RELE(nvp);
3621 dp = nextdp(dp);
3622 }
3623
3624 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626 if (ndata == NULL)
3627 ndata = data;
3628
3629 if (ret > 0) {
3630 /*
3631 * We had to drop one or more entries in order to fit
3632 * during the character conversion. We need to patch
3633 * up the size and eof info.
3634 */
3635 if (iseof)
3636 iseof = FALSE;
3637
3638 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
|
365 /* ARGSUSED */
366 void
367 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
368 struct svc_req *req, cred_t *cr, bool_t ro)
369 {
370 int error;
371 vnode_t *vp;
372 vnode_t *dvp;
373 struct vattr *vap;
374 struct vattr va;
375 struct vattr *dvap;
376 struct vattr dva;
377 nfs_fh3 *fhp;
378 struct sec_ol sec = {0, 0};
379 bool_t publicfh_flag = FALSE, auth_weak = FALSE;
380 struct sockaddr *ca;
381 char *name = NULL;
382
383 dvap = NULL;
384
385 if (exi != NULL)
386 exi_hold(exi);
387
388 /*
389 * Allow lookups from the root - the default
390 * location of the public filehandle.
391 */
392 if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
393 dvp = rootdir;
394 VN_HOLD(dvp);
395
396 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
397 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
398 } else {
399 dvp = nfs3_fhtovp(&args->what.dir, exi);
400
401 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
402 cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
403
404 if (dvp == NULL) {
405 error = ESTALE;
406 goto out;
407 }
408 }
409
410 dva.va_mask = AT_ALL;
411 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
412
413 if (args->what.name == nfs3nametoolong) {
414 resp->status = NFS3ERR_NAMETOOLONG;
415 goto out1;
416 }
417
418 if (args->what.name == NULL || *(args->what.name) == '\0') {
419 resp->status = NFS3ERR_ACCES;
420 goto out1;
421 }
422
423 fhp = &args->what.dir;
424 if (strcmp(args->what.name, "..") == 0 &&
425 EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
426 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
427 (dvp->v_flag & VROOT)) {
428 /*
429 * special case for ".." and 'nohide'exported root
430 */
431 if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
432 resp->status = NFS3ERR_ACCES;
433 goto out1;
434 }
435 } else {
436 resp->status = NFS3ERR_NOENT;
437 goto out1;
438 }
439 }
440
441 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
442 name = nfscmd_convname(ca, exi, args->what.name,
443 NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
444
445 if (name == NULL) {
446 resp->status = NFS3ERR_ACCES;
447 goto out1;
448 }
449
450 /*
451 * If the public filehandle is used then allow
452 * a multi-component lookup
453 */
454 if (PUBLIC_FH3(&args->what.dir)) {
455 publicfh_flag = TRUE;
456
457 exi_rele(exi);
458
459 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
460 &exi, &sec);
461
462 /*
463 * Since WebNFS may bypass MOUNT, we need to ensure this
464 * request didn't come from an unlabeled admin_low client.
465 */
466 if (is_system_labeled() && error == 0) {
467 int addr_type;
468 void *ipaddr;
469 tsol_tpc_t *tp;
470
471 if (ca->sa_family == AF_INET) {
472 addr_type = IPV4_VERSION;
473 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
474 } else if (ca->sa_family == AF_INET6) {
475 addr_type = IPV6_VERSION;
476 ipaddr = &((struct sockaddr_in6 *)
477 ca)->sin6_addr;
478 }
479 tp = find_tpc(ipaddr, addr_type, B_FALSE);
480 if (tp == NULL || tp->tpc_tp.tp_doi !=
481 l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
482 SUN_CIPSO) {
483 VN_RELE(vp);
484 error = EACCES;
485 }
486 if (tp != NULL)
487 TPC_RELE(tp);
488 }
489 } else {
490 error = VOP_LOOKUP(dvp, name, &vp,
491 NULL, 0, NULL, cr, NULL, NULL, NULL);
492 }
493
494 if (name != args->what.name)
495 kmem_free(name, MAXPATHLEN + 1);
496
497 if (error == 0 && vn_ismntpt(vp)) {
498 error = rfs_cross_mnt(&vp, &exi);
499 if (error)
500 VN_RELE(vp);
501 }
502
503 if (is_system_labeled() && error == 0) {
504 bslabel_t *clabel = req->rq_label;
505
506 ASSERT(clabel != NULL);
507 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
508 "got client label from request(1)", struct svc_req *, req);
509
510 if (!blequal(&l_admin_low->tsl_label, clabel)) {
511 if (!do_rfs_label_check(clabel, dvp,
512 DOMINANCE_CHECK, exi)) {
513 VN_RELE(vp);
514 error = EACCES;
515 }
516 }
517 }
518
519 dva.va_mask = AT_ALL;
520 dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
521
522 if (error)
523 goto out;
524
525 if (sec.sec_flags & SEC_QUERY) {
526 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
527 } else {
528 error = makefh3(&resp->resok.object, vp, exi);
529 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
530 auth_weak = TRUE;
531 }
532
533 if (error) {
534 VN_RELE(vp);
535 goto out;
536 }
537
538 va.va_mask = AT_ALL;
539 vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
540
541 exi_rele(exi);
542 VN_RELE(vp);
543
544 resp->status = NFS3_OK;
545 vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
546 vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
547
548 /*
549 * If it's public fh, no 0x81, and client's flavor is
550 * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
551 * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
552 */
553 if (auth_weak)
554 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
555
556 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
557 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
558 VN_RELE(dvp);
559
560 return;
561
562 out:
563 if (curthread->t_flag & T_WOULDBLOCK) {
564 curthread->t_flag &= ~T_WOULDBLOCK;
565 resp->status = NFS3ERR_JUKEBOX;
566 } else
567 resp->status = puterrno3(error);
568 out1:
569 if (exi != NULL)
570 exi_rele(exi);
571
572 DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
573 cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
574
575 if (dvp != NULL)
576 VN_RELE(dvp);
577 vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
578
579 }
580
581 void *
582 rfs3_lookup_getfh(LOOKUP3args *args)
583 {
584
585 return (&args->what.dir);
586 }
587
588 /* ARGSUSED */
589 void
590 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
591 struct svc_req *req, cred_t *cr, bool_t ro)
3605 }
3606
3607 infop[i].namelen = namlen[i];
3608
3609 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3610 NULL, NULL, NULL);
3611 if (error) {
3612 infop[i].attr.attributes = FALSE;
3613 infop[i].fh.handle_follows = FALSE;
3614 dp = nextdp(dp);
3615 continue;
3616 }
3617
3618 nva.va_mask = AT_ALL;
3619 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3620
3621 /* Lie about the object type for a referral */
3622 if (vn_is_nfs_reparse(nvp, cr))
3623 nvap->va_type = VLNK;
3624
3625 if (vn_ismntpt(nvp)) {
3626 infop[i].attr.attributes = FALSE;
3627 infop[i].fh.handle_follows = FALSE;
3628 } else {
3629 vattr_to_post_op_attr(nvap, &infop[i].attr);
3630
3631 error = makefh3(&infop[i].fh.handle, nvp, exi);
3632 if (!error)
3633 infop[i].fh.handle_follows = TRUE;
3634 else
3635 infop[i].fh.handle_follows = FALSE;
3636 }
3637
3638 VN_RELE(nvp);
3639 dp = nextdp(dp);
3640 }
3641
3642 ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3643 ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3644 if (ndata == NULL)
3645 ndata = data;
3646
3647 if (ret > 0) {
3648 /*
3649 * We had to drop one or more entries in order to fit
3650 * during the character conversion. We need to patch
3651 * up the size and eof info.
3652 */
3653 if (iseof)
3654 iseof = FALSE;
3655
3656 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
|