const strbuf & strbuf_cat (const strbuf &sb, sfsstat err) { switch (err) { case SFS_REDIRECT: return strbuf_cat (sb, "hostname or public key has changed", false); default: return strbuf_cat (sb, nfsstat3 (err)); } }
bool filesrv::fixres (svccb *sbp, void *res, reqstate *rqsp) { filesys *fsp = &fstab[rqsp->fsno]; if (sbp->proc () == NFSPROC3_READDIR) fixrdres (res, fsp, rqsp->rootfh); else if (sbp->proc () == NFSPROC3_READDIRPLUS) fixrdplusres (res, fsp, rqsp->rootfh); bool subst = false; fh3trans fht (fh3trans::ENCODE, fhkey, rqsp->fsno, wrap (this, &filesrv::fhsubst, &subst, fsp)); fht.fattr_hook = wrap (xor_ino, this); if (!nfs3exp_transres (fht, res, sbp->proc ())) { warn ("nfs3reply: nfs3_transres encode failed (err %d)\n", fht.err); nfs3exp_err (sbp, nfsstat3 (fht.err)); return false; } switch (sbp->proc ()) { case NFSPROC3_LOOKUP: { ex_lookup3res *dor = static_cast<ex_lookup3res *> (res); if (rqsp->rootfh) { if (dor->status) dor->resfail->set_present (false); else dor->resok->dir_attributes.set_present (false); } if (subst && !dor->status) dor->resok->obj_attributes.set_present (false); break; } case NFSPROC3_ACCESS: if (!sbp->getaui () && fsp->options != filesys::ANON_READWRITE) { ex_access3res *ar = static_cast<ex_access3res *> (res); if ((fsp->options & filesys::ANON_READ) != filesys::ANON_READ) { if (ar->status) ar->resfail->set_present (false); else { ar->resok->access = 0; ar->resok->obj_attributes.set_present (false); } } else if (!ar->status) ar->resok->access &= ACCESS3_READ|ACCESS3_LOOKUP|ACCESS3_EXECUTE; } break; } return true; }
bool filesrv::fixarg (svccb *sbp, reqstate *rqsp) { fh3trans fht (fh3trans::DECODE, fhkey); if (!nfs3_transarg (fht, sbp->Xtmpl getarg<void> (), sbp->proc ())) { nfs3exp_err (sbp, nfsstat3 (fht.err)); return false; } if (fht.srvno >= fstab.size ()) { nfs3exp_err (sbp, NFS3ERR_BADHANDLE); return false; } rqsp->fsno = fht.srvno; filesys *fsp = &fstab[rqsp->fsno]; rqsp->rootfh = false; rqsp->c = fsp->c; #if 1 /* We let anonymous users GETATTR any root file handle, not just the * root of all exported files. This is to help client * implementations that want to avoid (st_ino, st_dev) conflicts by * creating multiple mount points for each server. Is this bad? */ if (!sbp->getaui () && !anon_checkperm (sbp, fsp->options, *sbp->Xtmpl getarg<nfs_fh3> () == fsp->fh_root)) return false; #else /* The other option is to disallow this. Then commands like "ls * -al" will return a bunch of permission denied errors. */ if (!sbp->getaui () && !anon_checkperm (sbp, fsp->options, (fsp == fstab.base () && (*sbp->Xtmpl getarg<nfs_fh3> () == fsp->fh_root)))) return false; #endif switch (sbp->proc ()) { case NFSPROC3_LOOKUP: { diropargs3 *doa = sbp->Xtmpl getarg<diropargs3> (); if (doa->name == ".." && doa->dir == fsp->fh_root) { if (!getfsno (fsp)) { nfs3exp_err (sbp, NFS3ERR_ACCES); return false; } doa->dir = fsp->fh_mntpt; rqsp->fsno = getfsno (fsp->parent); fsp = &fstab[rqsp->fsno]; rqsp->rootfh = true; rqsp->c = fsp->c; } break; } case NFSPROC3_READDIR: case NFSPROC3_READDIRPLUS: { nfs_fh3 *rpa = sbp->Xtmpl getarg<nfs_fh3> (); if (*rpa == fsp->fh_root) rqsp->rootfh = true; break; } } return true; }