📄 nfs.c
字号:
/* $Id: nfs.C,v 1.17 2001/10/12 21:27:28 dm Exp $ *//* * * Copyright (C) 2001 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */#include "nfs.h"const u_int maxfhiv = 512;AUTH *cryptfs::ao = authopaque_create ();tailq<cryptfs::fhiv, &cryptfs::fhiv::lrulink> cryptfs::ivlruq;u_int cryptfs::fhiv::nfhiv;inline voidxorblock (char *dest, const char *src){ for (u_int i = 0; i < blocksize; i++) dest[i] ^= src[i];}u_int64_tcryptfs::fhiv::attr2iv (const fattr3exp *f){ /* Note: We make the iv a deterministic function of the attributes * in case two clients simultaneously perform UNCHECKED creates of * the same file. We could alternatively hash the file handle, but * in the case of SFS, different clients will have different file * handles (because sfsrwcd encrypts file handles to make it * slightly resistant to forged "loopback" traffic). */ u_char buf[sha1::hashsize]; puthyper (buf, f->fileid); puthyper (buf + 8, f->fsid); sha1_hash (buf, buf, 16); return gethyper (buf);}voidcryptfs::fhiv::init (){ cryptfs::ivlruq.insert_tail (this); cfs->ivtab.insert (this); nfhiv++; while (nfhiv > maxfhiv && cfs->ivlruq.first->stable) delete cfs->ivlruq.first;}voidcryptfs::fhiv::fetchcb (ref<cryptfs> hold, ref<read3res> resp, clnt_stat stat){ if (stat || resp->status || resp->resok->data.size () < blocksize) err = true; else { char *buf = resp->resok->data.base (); cfs->decrypt (-blocksize, 0, buf, buf); if (gethyper (buf)) err = true; else iv = gethyper (buf + 8); } wake ();}voidcryptfs::fhiv::createcb (ref<cryptfs> hold, ref<write3res> resp, clnt_stat stat){ if (stat || resp->status) err = true; wake ();}voidcryptfs::fhiv::wake (){ stable = valid = true; touch (); typedef vec<cbv> ivw_t; if (ivw_t *p = cfs->ivwait[fh]) { ivw_t v; p->swap (v); cfs->ivwait.remove (fh); while (!v.empty ()) (*v.pop_front ()) (); }}cryptfs::fhiv::fhiv (cryptfs *fs, const nfs_fh3 &f, bool isdir) : cfs (fs), fh (f), iv (0), valid (false), stable (false), err (false){ assert (!isdir); init (); read3args arg; arg.file = fh; arg.offset = 0; arg.count = blocksize; ref<read3res> resp = New refcounted<read3res>; cfs->call (NFSPROC3_READ, &arg, resp, wrap (this, &cryptfs::fhiv::fetchcb, mkref (cfs), resp), cfs->ao);}cryptfs::fhiv::fhiv (cryptfs *fs, const nfs_fh3 &f, const fattr3exp *fa) : cfs (fs), fh (f), iv (attr2iv (fa)), valid (true), stable (false), err (false){ init (); write3args arg; arg.file = fh; arg.offset = 0; arg.count = blocksize; arg.stable = DATA_SYNC; arg.data.setsize (blocksize); puthyper (arg.data.base (), 0); puthyper (arg.data.base () + 8, iv); cfs->encrypt (-blocksize, 0, arg.data.base (), arg.data.base ()); ref<write3res> resp = New refcounted<write3res>; cfs->call (NFSPROC3_WRITE, &arg, resp, wrap (this, &cryptfs::fhiv::createcb, mkref (cfs), resp), cfs->ao);}cryptfs::fhiv::~fhiv (){ cryptfs::ivlruq.remove (this); cfs->ivtab.remove (this); nfhiv--;}voidcryptfs::fhiv::touch (){ cryptfs::ivlruq.remove (this); cryptfs::ivlruq.insert_tail (this);}voidcryptfs::encrypt (u_int64_t offset, u_int64_t iv, char *out, const char *in){ assert (!(offset & 15)); char buf[16]; puthyper (buf, iv); puthyper (buf + 8, offset); fskey.encipher_bytes (buf, buf); xorblock (buf, in); fskey.encipher_bytes (out, buf);}voidcryptfs::decrypt (u_int64_t offset, u_int64_t iv, char *out, const char *in){ assert (!(offset & 15)); char buf[16]; puthyper (buf, iv); puthyper (buf + 8, offset); fskey.encipher_bytes (buf, buf); fskey.decipher_bytes (out, in); xorblock (out, buf);}strcryptfs::encodename (u_int64_t diriv, str name){ static str zeros ("\0", 2); assert (name.len ()); if (name == "." || name == "..") return name; name = name << zeros; mstr b (name.len () + blockmask & ~blockmask); memcpy (b, name, name.len ()); bzero (b + name.len (), b.len () - name.len ()); fskey.encipher_bytes (b); for (char *p = b.cstr () + blocksize, *e = b.cstr () + b.len (); p < e; p += blocksize) { xorblock (p, p - blocksize); fskey.encipher_bytes (p); } /* Now encrypt backwards in CBC mode, so all output bits depend on * all input bits. */ for (char *p = b.cstr () + b.len () - 2*blocksize; p >= b; p -= blocksize) { xorblock (p, p + blocksize); fskey.encipher_bytes (p); } return armor64A (b);}strcryptfs::decodename (u_int64_t diriv, str name){ if (name == "." || name == "..") return name; name = dearmor64A (name); if (name.len () & blockmask) return NULL; mstr b (name.len ()); memcpy (b, name, name.len ()); for (char *p = b, *e = b.cstr () + b.len () - blocksize; p < e; p += blocksize) { fskey.decipher_bytes (p); xorblock (p, p + blocksize); } for (char *p = b.cstr () + b.len () - blocksize; p > b; p -= blocksize) { fskey.decipher_bytes (p); xorblock (p, p - blocksize); } fskey.decipher_bytes (b); *(b.cstr () + b.len ()) = '\0'; u_int blen = strlen (b.cstr ()); if (b.len () - blen < 2) return NULL; for (u_int i = blen; i < b.len (); i++) if (b[i]) return NULL; b.setlen (blen); return b;}intcryptfs::getiv (nfs_fh3 &fh, bool stable, const authunix_parms *aup, cbv::ptr cb, u_int64_t *ivp){ fhiv *fp = ivtab[fh]; if (fp && fp->valid && (fp->stable || !stable)) { if (ivp) *ivp = fp->iv; fp->touch (); return fp->err ? -1 : 1; } if (cb) { vec<cbv> *p = ivwait[fh]; if (!p) { ivwait.insert (fh); p = ivwait[fh]; } p->push_back (cb); } if (!fp) { authopaque_set (ao, aup); vNew fhiv (this, fh, false); } return 0;}voidcryptfs::fillpoa (nfscall *nc, const nfs_fh3 *fhp, post_op_attr *poa, aclnt_cb cb){ ref<getattr3res> ares = New refcounted<getattr3res>; call (NFSPROC3_GETATTR, fhp, ares, wrap (mkref (this), &cryptfs::fillpoa_1, nc, poa, ares, cb), ao);}voidcryptfs::fillpoa_1 (nfscall *nc, post_op_attr *poa, ref<getattr3res> ares, aclnt_cb cb, clnt_stat stat){ if (stat) (*cb) (stat); else if (ares->status) nc->error (ares->status); else { poa->set_present (true); *poa->attributes = *ares->attributes; (*cb) (RPC_SUCCESS); }}voidcryptfs::reply (nfscall *nc, clnt_stat stat){ if (stat) { warn << "NFS server: " << stat << "\n"; nc->reject (SYSTEM_ERR); return; } else if (nc->proc () == NFSPROC3_NULL) { nc->reply (NULL); return; } nfs3_exp_enable (nc->proc (), nc->getvoidres ()); xattrvec xv; nfs3_getxattr (&xv, nc->proc (), nc->getvoidarg (), nc->getvoidres ()); for (xattr *x = xv.base (); x < xv.lim (); x++) if (x->fattr) { x->fattr->size = fixsize (x->fattr->type, x->fattr->size); if (x->wattr) x->wattr->size = fixsize (x->fattr->type, x->wattr->size); } else if (x->wattr) // without ftype, don't know how to adjust size, so nuke it x->wdata->before.set_present (false); nfs3_exp_disable (nc->proc (), nc->getvoidres ()); if (nc->proc () != NFSPROC3_NULL && !*nc->template getres<nfsstat3> ()) switch (nc->proc ()) { case NFSPROC3_WRITE: { write3args *arg = nc->template getarg<write3args> (); write3res *res = nc->template getres<write3res> (); res->resok->count -= arg->offset & blockmask; if (res->resok->count > arg->count) res->resok->count = arg->count; break; } case NFSPROC3_READLINK: { readlink3res *res = nc->template getres<readlink3res> (); if (str link = decodename (0, res->resok->data)) res->resok->data = substr (link, 8); else res->resok->data = ""; break; } case NFSPROC3_READDIR: if (!fixreaddir<NFSPROC3_READDIR> (nc)) return; break; case NFSPROC3_READDIRPLUS: if (!fixreaddir<NFSPROC3_READDIRPLUS> (nc)) return; break; case NFSPROC3_ACCESS: if (aid != sfsaid_nobody && aid != aup2aid (nc->getaup ()) && (!nc->getaup () || (nc->getaup ()->aup_uid))) nc->template getres<access3res> ()->resok->access = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -