123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110 |
- #include "stdinc.h"
- #include "9.h"
- enum {
- OMODE = 0x7, /* Topen/Tcreate mode */
- };
- enum {
- PermX = 1,
- PermW = 2,
- PermR = 4,
- };
- static char EPermission[] = "permission denied";
- static int
- permFile(File* file, Fid* fid, int perm)
- {
- char *u;
- DirEntry de;
- if(!fileGetDir(file, &de))
- return 0;
- /*
- * User none only gets other permissions.
- */
- if(strcmp(fid->uname, unamenone) != 0){
- /*
- * There is only one uid<->uname mapping
- * and it's already cached in the Fid, but
- * it might have changed during the lifetime
- * if this Fid.
- */
- if((u = unameByUid(de.uid)) != nil){
- if(strcmp(fid->uname, u) == 0 && ((perm<<6) & de.mode)){
- vtMemFree(u);
- deCleanup(&de);
- return 1;
- }
- vtMemFree(u);
- }
- if(groupMember(de.gid, fid->uname) && ((perm<<3) & de.mode)){
- deCleanup(&de);
- return 1;
- }
- }
- if(perm & de.mode){
- if(perm == PermX && (de.mode & ModeDir)){
- deCleanup(&de);
- return 1;
- }
- if(!groupMember(uidnoworld, fid->uname)){
- deCleanup(&de);
- return 1;
- }
- }
- if(fsysNoPermCheck(fid->fsys) || fid->con->noperm){
- deCleanup(&de);
- return 1;
- }
- vtSetError(EPermission);
- deCleanup(&de);
- return 0;
- }
- static int
- permFid(Fid* fid, int p)
- {
- return permFile(fid->file, fid, p);
- }
- static int
- permParent(Fid* fid, int p)
- {
- int r;
- File *parent;
- parent = fileGetParent(fid->file);
- r = permFile(parent, fid, p);
- fileDecRef(parent);
- return r;
- }
- int
- validFileName(char* name)
- {
- char *p;
- if(name == nil || name[0] == '\0'){
- vtSetError("no file name");
- return 0;
- }
- if(name[0] == '.'){
- if(name[1] == '\0' || (name[1] == '.' && name[2] == '\0')){
- vtSetError(". and .. illegal as file name");
- return 0;
- }
- }
- for(p = name; *p != '\0'; p++){
- if((*p & 0xFF) < 040){
- vtSetError("bad character in file name");
- return 0;
- }
- }
- return 1;
- }
- static int
- rTwstat(Msg* m)
- {
- Dir dir;
- Fid *fid;
- ulong mode, oldmode;
- DirEntry de;
- char *gid, *strs, *uid;
- int gl, op, retval, tsync;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
- return 0;
- gid = uid = nil;
- retval = 0;
- if(strcmp(fid->uname, unamenone) == 0 || (fid->qid.type & QTAUTH)){
- vtSetError(EPermission);
- goto error0;
- }
- if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
- vtSetError("read-only filesystem");
- goto error0;
- }
- if(!fileGetDir(fid->file, &de))
- goto error0;
- strs = vtMemAlloc(m->t.nstat);
- if(convM2D(m->t.stat, m->t.nstat, &dir, strs) == 0){
- vtSetError("wstat -- protocol botch");
- goto error;
- }
- /*
- * Run through each of the (sub-)fields in the provided Dir
- * checking for validity and whether it's a default:
- * .type, .dev and .atime are completely ignored and not checked;
- * .qid.path, .qid.vers and .muid are checked for validity but
- * any attempt to change them is an error.
- * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
- * possibly be changed.
- *
- * 'Op' flags there are changed fields, i.e. it's not a no-op.
- * 'Tsync' flags all fields are defaulted.
- */
- tsync = 1;
- if(dir.qid.path != ~0){
- if(dir.qid.path != de.qid){
- vtSetError("wstat -- attempt to change qid.path");
- goto error;
- }
- tsync = 0;
- }
- if(dir.qid.vers != ~0){
- if(dir.qid.vers != de.mcount){
- vtSetError("wstat -- attempt to change qid.vers");
- goto error;
- }
- tsync = 0;
- }
- if(dir.muid != nil && *dir.muid != '\0'){
- if((uid = uidByUname(dir.muid)) == nil){
- vtSetError("wstat -- unknown muid");
- goto error;
- }
- if(strcmp(uid, de.mid) != 0){
- vtSetError("wstat -- attempt to change muid");
- goto error;
- }
- vtMemFree(uid);
- uid = nil;
- tsync = 0;
- }
- /*
- * Check .qid.type and .mode agree if neither is defaulted.
- */
- if(dir.qid.type != (uchar)~0 && dir.mode != ~0){
- if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
- vtSetError("wstat -- qid.type/mode mismatch");
- goto error;
- }
- }
- op = 0;
- oldmode = de.mode;
- if(dir.qid.type != (uchar)~0 || dir.mode != ~0){
- /*
- * .qid.type or .mode isn't defaulted, check for unknown bits.
- */
- if(dir.mode == ~0)
- dir.mode = (dir.qid.type<<24)|(de.mode & 0777);
- if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
- vtSetError("wstat -- unknown bits in qid.type/mode");
- goto error;
- }
- /*
- * Synthesise a mode to check against the current settings.
- */
- mode = dir.mode & 0777;
- if(dir.mode & DMEXCL)
- mode |= ModeExclusive;
- if(dir.mode & DMAPPEND)
- mode |= ModeAppend;
- if(dir.mode & DMDIR)
- mode |= ModeDir;
- if((de.mode^mode) & ModeDir){
- vtSetError("wstat -- attempt to change directory bit");
- goto error;
- }
- if((de.mode & (ModeAppend|ModeExclusive|0777)) != mode){
- de.mode &= ~(ModeAppend|ModeExclusive|0777);
- de.mode |= mode;
- op = 1;
- }
- tsync = 0;
- }
- if(dir.mtime != ~0){
- if(dir.mtime != de.mtime){
- de.mtime = dir.mtime;
- op = 1;
- }
- tsync = 0;
- }
- if(dir.length != ~0){
- /*
- * Cannot change length on append-only files.
- * If we're changing the append bit, it's okay.
- */
- if(de.mode & oldmode & ModeAppend){
- vtSetError("wstat -- attempt to change length of append-only file");
- goto error;
- }
- if(de.mode & ModeDir){
- vtSetError("wstat -- attempt to change length of directory");
- goto error;
- }
- if(dir.length != de.size){
- de.size = dir.length;
- op = 1;
- }
- tsync = 0;
- }
- /*
- * Check for permission to change .mode, .mtime or .length,
- * must be owner or leader of either group, for which test gid
- * is needed; permission checks on gid will be done later.
- */
- if(dir.gid != nil && *dir.gid != '\0'){
- if((gid = uidByUname(dir.gid)) == nil){
- vtSetError("wstat -- unknown gid");
- goto error;
- }
- tsync = 0;
- }
- else
- gid = vtStrDup(de.gid);
- /*
- * 'Gl' counts whether neither, one or both groups are led.
- */
- gl = groupLeader(gid, fid->uname) != 0;
- gl += groupLeader(de.gid, fid->uname) != 0;
- if(op && !fsysWstatAllow(fid->fsys)){
- if(strcmp(fid->uid, de.uid) != 0 && !gl){
- vtSetError("wstat -- not owner or group leader");
- goto error;
- }
- }
- /*
- * Check for permission to change group, must be
- * either owner and in new group or leader of both groups.
- * If gid is nil here then
- */
- if(strcmp(gid, de.gid) != 0){
- if(!fsysWstatAllow(fid->fsys)
- && !(strcmp(fid->uid, de.uid) == 0 && groupMember(gid, fid->uname))
- && !(gl == 2)){
- vtSetError("wstat -- not owner and not group leaders");
- goto error;
- }
- vtMemFree(de.gid);
- de.gid = gid;
- gid = nil;
- op = 1;
- tsync = 0;
- }
- /*
- * Rename.
- * Check .name is valid and different to the current.
- * If so, check write permission in parent.
- */
- if(dir.name != nil && *dir.name != '\0'){
- if(!validFileName(dir.name))
- goto error;
- if(strcmp(dir.name, de.elem) != 0){
- if(!permParent(fid, PermW))
- goto error;
- vtMemFree(de.elem);
- de.elem = vtStrDup(dir.name);
- op = 1;
- }
- tsync = 0;
- }
- /*
- * Check for permission to change owner - must be god.
- */
- if(dir.uid != nil && *dir.uid != '\0'){
- if((uid = uidByUname(dir.uid)) == nil){
- vtSetError("wstat -- unknown uid");
- goto error;
- }
- if(strcmp(uid, de.uid) != 0){
- if(!fsysWstatAllow(fid->fsys)){
- vtSetError("wstat -- not owner");
- goto error;
- }
- if(strcmp(uid, uidnoworld) == 0){
- vtSetError(EPermission);
- goto error;
- }
- vtMemFree(de.uid);
- de.uid = uid;
- uid = nil;
- op = 1;
- }
- tsync = 0;
- }
- if(op)
- retval = fileSetDir(fid->file, &de, fid->uid);
- else
- retval = 1;
- if(tsync){
- /*
- * All values were defaulted,
- * make the state of the file exactly what it
- * claims to be before returning...
- */
- USED(tsync);
- }
- error:
- deCleanup(&de);
- vtMemFree(strs);
- if(gid != nil)
- vtMemFree(gid);
- if(uid != nil)
- vtMemFree(uid);
- error0:
- fidPut(fid);
- return retval;
- };
- static int
- rTstat(Msg* m)
- {
- Dir dir;
- Fid *fid;
- DirEntry de;
- if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
- return 0;
- if(fid->qid.type & QTAUTH){
- memset(&dir, 0, sizeof(Dir));
- dir.qid = fid->qid;
- dir.mode = DMAUTH;
- dir.atime = time(0L);
- dir.mtime = dir.atime;
- dir.length = 0;
- dir.name = "#¿";
- dir.uid = fid->uname;
- dir.gid = fid->uname;
- dir.muid = fid->uname;
- if((m->r.nstat = convD2M(&dir, m->data, m->con->msize)) == 0){
- vtSetError("stat QTAUTH botch");
- fidPut(fid);
- return 0;
- }
- m->r.stat = m->data;
- fidPut(fid);
- return 1;
- }
- if(!fileGetDir(fid->file, &de)){
- fidPut(fid);
- return 0;
- }
- fidPut(fid);
- /*
- * TODO: optimise this copy (in convS2M) away somehow.
- * This pettifoggery with m->data will do for the moment.
- */
- m->r.nstat = dirDe2M(&de, m->data, m->con->msize);
- m->r.stat = m->data;
- deCleanup(&de);
- return 1;
- }
- static int
- _rTclunk(Fid* fid, int remove)
- {
- int rok;
- if(fid->excl)
- exclFree(fid);
- rok = 1;
- if(remove && !(fid->qid.type & QTAUTH)){
- if((rok = permParent(fid, PermW)) != 0)
- rok = fileRemove(fid->file, fid->uid);
- }
- fidClunk(fid);
- return rok;
- }
- static int
- rTremove(Msg* m)
- {
- Fid *fid;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
- return 0;
- return _rTclunk(fid, 1);
- }
- static int
- rTclunk(Msg* m)
- {
- Fid *fid;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
- return 0;
- _rTclunk(fid, (fid->open & FidORclose));
- return 1;
- }
- static int
- rTwrite(Msg* m)
- {
- Fid *fid;
- int count, n;
- if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
- return 0;
- if(!(fid->open & FidOWrite)){
- vtSetError("fid not open for write");
- goto error;
- }
- count = m->t.count;
- if(count < 0 || count > m->con->msize-IOHDRSZ){
- vtSetError("write count too big");
- goto error;
- }
- if(m->t.offset < 0){
- vtSetError("write offset negative");
- goto error;
- }
- if(fid->excl != nil && !exclUpdate(fid))
- goto error;
- if(fid->qid.type & QTDIR){
- vtSetError("is a directory");
- goto error;
- }
- else if(fid->qid.type & QTAUTH)
- n = authWrite(fid, m->t.data, count);
- else
- n = fileWrite(fid->file, m->t.data, count, m->t.offset, fid->uid);
- if(n < 0)
- goto error;
-
- m->r.count = n;
- fidPut(fid);
- return 1;
- error:
- fidPut(fid);
- return 0;
- }
- static int
- rTread(Msg* m)
- {
- Fid *fid;
- uchar *data;
- int count, n;
- if((fid = fidGet(m->con, m->t.fid, 0)) == nil)
- return 0;
- if(!(fid->open & FidORead)){
- vtSetError("fid not open for read");
- goto error;
- }
- count = m->t.count;
- if(count < 0 || count > m->con->msize-IOHDRSZ){
- vtSetError("read count too big");
- goto error;
- }
- if(m->t.offset < 0){
- vtSetError("read offset negative");
- goto error;
- }
- if(fid->excl != nil && !exclUpdate(fid))
- goto error;
- /*
- * TODO: optimise this copy (in convS2M) away somehow.
- * This pettifoggery with m->data will do for the moment.
- */
- data = m->data+IOHDRSZ;
- if(fid->qid.type & QTDIR)
- n = dirRead(fid, data, count, m->t.offset);
- else if(fid->qid.type & QTAUTH)
- n = authRead(fid, data, count);
- else
- n = fileRead(fid->file, data, count, m->t.offset);
- if(n < 0)
- goto error;
- m->r.count = n;
- m->r.data = (char*)data;
- fidPut(fid);
- return 1;
- error:
- fidPut(fid);
- return 0;
- }
- static int
- rTcreate(Msg* m)
- {
- Fid *fid;
- File *file;
- ulong mode;
- int omode, open, perm;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
- return 0;
- if(fid->open){
- vtSetError("fid open for I/O");
- goto error;
- }
- if(fileIsRoFs(fid->file) || !groupWriteMember(fid->uname)){
- vtSetError("read-only filesystem");
- goto error;
- }
- if(!fileIsDir(fid->file)){
- vtSetError("not a directory");
- goto error;
- }
- if(!permFid(fid, PermW))
- goto error;
- if(!validFileName(m->t.name))
- goto error;
- if(strcmp(fid->uid, uidnoworld) == 0){
- vtSetError(EPermission);
- goto error;
- }
- omode = m->t.mode & OMODE;
- open = 0;
- if(omode == OREAD || omode == ORDWR || omode == OEXEC)
- open |= FidORead;
- if(omode == OWRITE || omode == ORDWR)
- open |= FidOWrite;
- if((open & (FidOWrite|FidORead)) == 0){
- vtSetError("unknown mode");
- goto error;
- }
- if(m->t.perm & DMDIR){
- if((m->t.mode & (ORCLOSE|OTRUNC)) || (open & FidOWrite)){
- vtSetError("illegal mode");
- goto error;
- }
- if(m->t.perm & DMAPPEND){
- vtSetError("illegal perm");
- goto error;
- }
- }
- mode = fileGetMode(fid->file);
- perm = m->t.perm;
- if(m->t.perm & DMDIR)
- perm &= ~0777|(mode & 0777);
- else
- perm &= ~0666|(mode & 0666);
- mode = perm & 0777;
- if(m->t.perm & DMDIR)
- mode |= ModeDir;
- if(m->t.perm & DMAPPEND)
- mode |= ModeAppend;
- if(m->t.perm & DMEXCL)
- mode |= ModeExclusive;
- if((file = fileCreate(fid->file, m->t.name, mode, fid->uid)) == nil){
- fidPut(fid);
- return 0;
- }
- fileDecRef(fid->file);
- fid->qid.vers = fileGetMcount(file);
- fid->qid.path = fileGetId(file);
- fid->file = file;
- mode = fileGetMode(fid->file);
- if(mode & ModeDir)
- fid->qid.type = QTDIR;
- else
- fid->qid.type = QTFILE;
- if(mode & ModeAppend)
- fid->qid.type |= QTAPPEND;
- if(mode & ModeExclusive){
- fid->qid.type |= QTEXCL;
- assert(exclAlloc(fid) != 0);
- }
- if(m->t.mode & ORCLOSE)
- open |= FidORclose;
- fid->open = open;
- m->r.qid = fid->qid;
- m->r.iounit = m->con->msize-IOHDRSZ;
- fidPut(fid);
- return 1;
- error:
- fidPut(fid);
- return 0;
- }
- static int
- rTopen(Msg* m)
- {
- Fid *fid;
- int isdir, mode, omode, open, rofs;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock)) == nil)
- return 0;
- if(fid->open){
- vtSetError("fid open for I/O");
- goto error;
- }
- isdir = fileIsDir(fid->file);
- open = 0;
- rofs = fileIsRoFs(fid->file) || !groupWriteMember(fid->uname);
- if(m->t.mode & ORCLOSE){
- if(isdir){
- vtSetError("is a directory");
- goto error;
- }
- if(rofs){
- vtSetError("read-only filesystem");
- goto error;
- }
- if(!permParent(fid, PermW))
- goto error;
- open |= FidORclose;
- }
- omode = m->t.mode & OMODE;
- if(omode == OREAD || omode == ORDWR){
- if(!permFid(fid, PermR))
- goto error;
- open |= FidORead;
- }
- if(omode == OWRITE || omode == ORDWR || (m->t.mode & OTRUNC)){
- if(isdir){
- vtSetError("is a directory");
- goto error;
- }
- if(rofs){
- vtSetError("read-only filesystem");
- goto error;
- }
- if(!permFid(fid, PermW))
- goto error;
- open |= FidOWrite;
- }
- if(omode == OEXEC){
- if(isdir){
- vtSetError("is a directory");
- goto error;
- }
- if(!permFid(fid, PermX))
- goto error;
- open |= FidORead;
- }
- if((open & (FidOWrite|FidORead)) == 0){
- vtSetError("unknown mode");
- goto error;
- }
- mode = fileGetMode(fid->file);
- if((mode & ModeExclusive) && exclAlloc(fid) == 0)
- goto error;
- /*
- * Everything checks out, try to commit any changes.
- */
- if((m->t.mode & OTRUNC) && !(mode & ModeAppend)){
- if(!fileTruncate(fid->file, fid->uid))
- goto error;
- fid->qid.vers = fileGetMcount(fid->file);
- }
- if(isdir && fid->db != nil){
- dirBufFree(fid->db);
- fid->db = nil;
- }
- m->r.qid = fid->qid;
- m->r.iounit = m->con->msize-IOHDRSZ;
- fid->open = open;
- fidPut(fid);
- return 1;
- error:
- if(fid->excl != nil)
- exclFree(fid);
- fidPut(fid);
- return 0;
- }
- static int
- rTwalk(Msg* m)
- {
- Qid qid;
- Fcall *r, *t;
- int nwname, wlock;
- File *file, *nfile;
- Fid *fid, *ofid, *nfid;
- t = &m->t;
- if(t->fid == t->newfid)
- wlock = FidFWlock;
- else
- wlock = 0;
- /*
- * The file identified by t->fid must be valid in the
- * current session and must not have been opened for I/O
- * by an open or create message.
- */
- if((ofid = fidGet(m->con, t->fid, wlock)) == nil)
- return 0;
- if(ofid->open){
- vtSetError("file open for I/O");
- fidPut(ofid);
- return 0;
- }
- /*
- * If newfid is not the same as fid, allocate a new file;
- * a side effect is checking newfid is not already in use (error);
- * if there are no names to walk this will be equivalent to a
- * simple 'clone' operation.
- * It's a no-op if newfid is the same as fid and t->nwname is 0.
- */
- nfid = nil;
- if(t->fid != t->newfid){
- nfid = fidGet(m->con, t->newfid, FidFWlock|FidFCreate);
- if(nfid == nil){
- vtSetError("fid in use");
- fidPut(ofid);
- return 0;
- }
- nfid->open = ofid->open & ~FidORclose;
- nfid->file = fileIncRef(ofid->file);
- nfid->qid = ofid->qid;
- nfid->uid = vtStrDup(ofid->uid);
- nfid->uname = vtStrDup(ofid->uname);
- nfid->fsys = fsysIncRef(ofid->fsys);
- fid = nfid;
- }
- else
- fid = ofid;
- r = &m->r;
- r->nwqid = 0;
- if(t->nwname == 0){
- if(nfid != nil)
- fidPut(nfid);
- fidPut(ofid);
- return 1;
- }
- file = fid->file;
- fileIncRef(file);
- qid = fid->qid;
- for(nwname = 0; nwname < t->nwname; nwname++){
- /*
- * Walked elements must represent a directory and
- * the implied user must have permission to search
- * the directory. Walking .. is always allowed, so that
- * you can't walk into a directory and then not be able
- * to walk out of it.
- */
- if(!(qid.type & QTDIR)){
- vtSetError("not a directory");
- break;
- }
- if(!permFile(file, fid, PermX) && strcmp(t->wname[nwname], "..") != 0)
- break;
- if((nfile = fileWalk(file, t->wname[nwname])) == nil)
- break;
- fileDecRef(file);
- file = nfile;
- qid.type = QTFILE;
- if(fileIsDir(file))
- qid.type = QTDIR;
- qid.vers = fileGetMcount(file);
- qid.path = fileGetId(file);
- r->wqid[r->nwqid++] = qid;
- }
- if(nwname == t->nwname){
- /*
- * Walked all elements. Update the target fid
- * from the temporary qid used during the walk,
- * and tidy up.
- */
- fid->qid = r->wqid[r->nwqid-1];
- fileDecRef(fid->file);
- fid->file = file;
- if(nfid != nil)
- fidPut(nfid);
- fidPut(ofid);
- return 1;
- }
- /*
- * Didn't walk all elements, 'clunk' nfid if it exists
- * and leave fid untouched.
- * It's not an error if some of the elements were walked OK.
- */
- fileDecRef(file);
- if(nfid != nil)
- fidClunk(nfid);
- fidPut(ofid);
- if(nwname == 0)
- return 0;
- return 1;
- }
- static int
- rTflush(Msg* m)
- {
- if(m->t.oldtag != NOTAG)
- msgFlush(m);
- return 1;
- }
- static void
- parseAname(char *aname, char **fsname, char **path)
- {
- char *s;
- if(aname && aname[0])
- s = vtStrDup(aname);
- else
- s = vtStrDup("main/active");
- *fsname = s;
- if((*path = strchr(s, '/')) != nil)
- *(*path)++ = '\0';
- else
- *path = "";
- }
- static int
- rTattach(Msg* m)
- {
- Fid *fid;
- Fsys *fsys;
- char *fsname, *path;
- if((fid = fidGet(m->con, m->t.fid, FidFWlock|FidFCreate)) == nil)
- return 0;
- parseAname(m->t.aname, &fsname, &path);
- if((fsys = fsysGet(fsname)) == nil){
- fidClunk(fid);
- vtMemFree(fsname);
- return 0;
- }
- fid->fsys = fsys;
- if(m->t.uname[0] != '\0')
- fid->uname = vtStrDup(m->t.uname);
- else
- fid->uname = vtStrDup(unamenone);
- if(fsysNoAuthCheck(fsys) || m->con->noauth){
- if((fid->uid = uidByUname(fid->uname)) == nil)
- fid->uid = vtStrDup(unamenone);
- }
- else if(!authCheck(&m->t, fid, fsys)){
- fidClunk(fid);
- vtMemFree(fsname);
- vtSetError("authentication failed");
- return 0;
- }
- fsysFsRlock(fsys);
- if((fid->file = fsysGetRoot(fsys, path)) == nil){
- fsysFsRUnlock(fsys);
- fidClunk(fid);
- vtMemFree(fsname);
- return 0;
- }
- fsysFsRUnlock(fsys);
- vtMemFree(fsname);
- fid->qid = (Qid){fileGetId(fid->file), 0, QTDIR};
- m->r.qid = fid->qid;
- fidPut(fid);
- return 1;
- }
- static int
- rTauth(Msg* m)
- {
- int afd;
- Con *con;
- Fid *afid;
- Fsys *fsys;
- char *fsname, *path;
- parseAname(m->t.aname, &fsname, &path);
- if((fsys = fsysGet(fsname)) == nil){
- vtMemFree(fsname);
- return 0;
- }
- vtMemFree(fsname);
- if(fsysNoAuthCheck(fsys) || m->con->noauth){
- m->con->aok = 1;
- vtSetError("authentication disabled");
- fsysPut(fsys);
- return 0;
- }
- if(strcmp(m->t.uname, unamenone) == 0){
- vtSetError("user 'none' requires no authentication");
- fsysPut(fsys);
- return 0;
- }
- con = m->con;
- if((afid = fidGet(con, m->t.afid, FidFWlock|FidFCreate)) == nil){
- fsysPut(fsys);
- return 0;
- }
- afid->fsys = fsys;
- if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
- vtSetError("can't open \"/mnt/factotum/rpc\"");
- fidClunk(afid);
- return 0;
- }
- if((afid->rpc = auth_allocrpc(afd)) == nil){
- close(afd);
- vtSetError("can't auth_allocrpc");
- fidClunk(afid);
- return 0;
- }
- if(auth_rpc(afid->rpc, "start", "proto=p9any role=server", 23) != ARok){
- vtSetError("can't auth_rpc");
- fidClunk(afid);
- return 0;
- }
- afid->open = FidOWrite|FidORead;
- afid->qid.type = QTAUTH;
- afid->qid.path = m->t.afid;
- afid->uname = vtStrDup(m->t.uname);
- m->r.qid = afid->qid;
- fidPut(afid);
- return 1;
- }
- static int
- rTversion(Msg* m)
- {
- int v;
- Con *con;
- Fcall *r, *t;
- t = &m->t;
- r = &m->r;
- con = m->con;
- vtLock(con->lock);
- if(con->state != ConInit){
- vtUnlock(con->lock);
- vtSetError("Tversion: down");
- return 0;
- }
- con->state = ConNew;
- /*
- * Release the karma of past lives and suffering.
- * Should this be done before or after checking the
- * validity of the Tversion?
- */
- fidClunkAll(con);
- if(t->tag != NOTAG){
- vtUnlock(con->lock);
- vtSetError("Tversion: invalid tag");
- return 0;
- }
- if(t->msize < 256){
- vtUnlock(con->lock);
- vtSetError("Tversion: message size too small");
- return 0;
- }
- if(t->msize < con->msize)
- r->msize = t->msize;
- else
- r->msize = con->msize;
- r->version = "unknown";
- if(t->version[0] == '9' && t->version[1] == 'P'){
- /*
- * Currently, the only defined version
- * is "9P2000"; ignore any later versions.
- */
- v = strtol(&t->version[2], 0, 10);
- if(v >= 2000){
- r->version = VERSION9P;
- con->msize = r->msize;
- con->state = ConUp;
- }
- else if(strcmp(t->version, "9PEoF") == 0){
- r->version = "9PEoF";
- con->msize = r->msize;
- con->state = ConMoribund;
- }
- }
- vtUnlock(con->lock);
- return 1;
- }
- int (*rFcall[Tmax])(Msg*) = {
- [Tversion] = rTversion,
- [Tauth] = rTauth,
- [Tattach] = rTattach,
- [Tflush] = rTflush,
- [Twalk] = rTwalk,
- [Topen] = rTopen,
- [Tcreate] = rTcreate,
- [Tread] = rTread,
- [Twrite] = rTwrite,
- [Tclunk] = rTclunk,
- [Tremove] = rTremove,
- [Tstat] = rTstat,
- [Twstat] = rTwstat,
- };
|