char* rversion(Fid *unused) { Fid *f; USED(unused); for(f = fids; f; f = f->next) if(f->busy) rclunk(f); if(rhdr.msize < 256) return vtstrdup("version: message size too small"); messagesize = rhdr.msize; if(messagesize > sizeof mdata) messagesize = sizeof mdata; thdr.msize = messagesize; if(strncmp(rhdr.version, "9P2000", 6) != 0) return vtstrdup("unrecognized 9P version"); thdr.version = "9P2000"; if(strncmp(rhdr.version, "9P2000.u", 8) == 0){ dotu = 1; thdr.version = "9P2000.u"; } return nil; }
char* rread(Fid *f) { char *buf; int64_t off; int cnt; VacFile *vf; char err[80]; int n; if(!f->busy) return vtstrdup(Enotexist); vf = f->file; thdr.count = 0; off = rhdr.offset; buf = thdr.data; cnt = rhdr.count; if(f->qid.type & QTDIR) n = vacdirread(f, buf, off, cnt); else if(vacfilegetmode(f->file)&ModeDevice) return vtstrdup("device"); else if(vacfilegetmode(f->file)&ModeLink) return vtstrdup("symbolic link"); else if(vacfilegetmode(f->file)&ModeNamedPipe) return vtstrdup("named pipe"); else n = vacfileread(vf, buf, cnt, off); if(n < 0) { rerrstr(err, sizeof err); return vtstrdup(err); } thdr.count = n; return 0; }
char * rremove(Fid *f) { VacFile *vf, *vfp; char errbuf[80]; char *err = nil; if(!f->busy) return vtstrdup(Enotexist); vf = f->file; vfp = vacfilegetparent(vf); if(!permf(vfp, f->user, Pwrite)) { err = Eperm; goto Exit; } if(!vacfileremove(vf)) { rerrstr(errbuf, sizeof errbuf); err = errbuf; } Exit: vacfiledecref(vfp); rclunk(f); return vtstrdup(err); }
char * rwstat(Fid *f) { if(!f->busy) return vtstrdup(Enotexist); return vtstrdup(Erdonly); }
char* rattach(Fid *f) { /* no authentication for the momment */ VacFile *file; char err[80]; file = vacfsgetroot(fs); if(file == nil) { rerrstr(err, sizeof err); return vtstrdup(err); } f->busy = 1; f->file = file; f->qid.path = vacfilegetid(f->file); f->qid.vers = 0; f->qid.type = QTDIR; thdr.qid = f->qid; if(rhdr.uname[0]) f->user = vtstrdup(rhdr.uname); else f->user = "******"; return 0; }
char* rcreate(Fid* fid) { VacFile *vf; uint32_t mode; if(fid->open) return vtstrdup(Eisopen); if(!fid->busy) return vtstrdup(Enotexist); if(fs->mode & ModeSnapshot) return vtstrdup(Erdonly); vf = fid->file; if(!vacfileisdir(vf)) return vtstrdup(Enotdir); if(!permf(vf, fid->user, Pwrite)) return vtstrdup(Eperm); mode = rhdr.perm & 0777; if(rhdr.perm & DMDIR){ if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND)) return vtstrdup(Emode); switch(rhdr.mode & OPERM){ default: return vtstrdup(Emode); case OEXEC: case OREAD: break; case OWRITE: case ORDWR: return vtstrdup(Eperm); } mode |= ModeDir; } vf = vacfilecreate(vf, rhdr.name, mode); if(vf == nil) { char err[80]; rerrstr(err, sizeof err); return vtstrdup(err); } vacfiledecref(fid->file); fid->file = vf; fid->qid.type = QTFILE; if(vacfileisdir(vf)) fid->qid.type = QTDIR; fid->qid.vers = vacfilegetmcount(vf); fid->qid.path = vacfilegetid(vf); thdr.qid = fid->qid; thdr.iounit = messagesize - IOHDRSZ; return 0; }
int authRead(Fid* afid, void* data, int count) { AuthInfo *ai; AuthRpc *rpc; if((rpc = afid->rpc) == nil){ werrstr("not an auth fid"); return -1; } switch(auth_rpc(rpc, "read", nil, 0)){ default: werrstr("fossil authRead: auth protocol not finished"); return -1; case ARdone: if((ai = auth_getinfo(rpc)) == nil){ werrstr("%r"); break; } if(ai->cuid == nil || *ai->cuid == '\0'){ werrstr("auth with no cuid"); auth_freeAI(ai); break; } assert(afid->cuname == nil); afid->cuname = vtstrdup(ai->cuid); auth_freeAI(ai); if(Dflag) fprint(2, "authRead cuname %s\n", afid->cuname); assert(afid->uid == nil); if((afid->uid = uidByUname(afid->cuname)) == nil){ werrstr("unknown user %#q", afid->cuname); break; } return 0; case ARok: if(count < rpc->narg){ werrstr("not enough data in auth read"); break; } memmove(data, rpc->arg, rpc->narg); return rpc->narg; case ARphase: werrstr("%r"); break; } return -1; }
/* * convert File* to full path name in malloced string. * this hasn't been as useful as we hoped it would be. */ char * fileName(File *f) { char *name, *pname; File *p; static char root[] = "/"; if (f == nil) return vtstrdup("/**GOK**"); p = fileGetParent(f); if (p == f) name = vtstrdup(root); else { pname = fileName(p); if (strcmp(pname, root) == 0) name = smprint("/%s", f->dir.elem); else name = smprint("%s/%s", pname, f->dir.elem); free(pname); } fileDecRef(p); return name; }
char * rstat(Fid *f) { VacDir dir; static uint8_t statbuf[1024]; VacFile *parent; if(!f->busy) return vtstrdup(Enotexist); parent = vacfilegetparent(f->file); vacfilegetdir(f->file, &dir); thdr.stat = statbuf; thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf); vdcleanup(&dir); vacfiledecref(parent); return 0; }
char * ropen(Fid *f) { int mode, trunc; if(f->open) return vtstrdup(Eisopen); if(!f->busy) return vtstrdup(Enotexist); mode = rhdr.mode; thdr.iounit = messagesize - IOHDRSZ; if(f->qid.type & QTDIR){ if(mode != OREAD) return vtstrdup(Eperm); if(!perm(f, Pread)) return vtstrdup(Eperm); thdr.qid = f->qid; f->vde = nil; f->open = 1; return 0; } if(mode & ORCLOSE) return vtstrdup(Erdonly); trunc = mode & OTRUNC; mode &= OPERM; if(mode==OWRITE || mode==ORDWR || trunc) if(!perm(f, Pwrite)) return vtstrdup(Eperm); if(mode==OREAD || mode==ORDWR) if(!perm(f, Pread)) return vtstrdup(Eperm); if(mode==OEXEC) if(!perm(f, Pexec)) return vtstrdup(Eperm); thdr.qid = f->qid; thdr.iounit = messagesize - IOHDRSZ; f->open = 1; return 0; }
/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */ static void fileWAccess(File* f, char *mid) { if(f->mode == OReadOnly) return; fileMetaLock(f); f->dir.atime = f->dir.mtime = time(0L); if(strcmp(f->dir.mid, mid) != 0){ vtfree(f->dir.mid); f->dir.mid = vtstrdup(mid); } f->dir.mcount++; f->dirty = 1; fileMetaUnlock(f); /*RSC: let's try this */ /*presotto - lets not if(f->up) fileWAccess(f->up, mid); */ }
char* rauth(Fid *f) { USED(f); return vtstrdup("vacfs: authentication not required"); }
File * fileCreate(File *f, char *elem, ulong mode, char *uid) { File *ff; DirEntry *dir; Source *pr, *r, *mr; int isdir; if(!fileLock(f)) return nil; r = nil; mr = nil; for(ff = f->down; ff; ff=ff->next){ if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ ff = nil; werrstr(EExists); goto Err1; } } ff = dirLookup(f, elem); if(ff != nil){ werrstr(EExists); goto Err1; } pr = f->source; if(pr->mode != OReadWrite){ werrstr(EReadOnly); goto Err1; } if(!sourceLock2(f->source, f->msource, -1)) goto Err1; ff = fileAlloc(f->fs); isdir = mode & ModeDir; r = sourceCreate(pr, pr->dsize, isdir, 0); if(r == nil) goto Err; if(isdir){ mr = sourceCreate(pr, pr->dsize, 0, r->offset); if(mr == nil) goto Err; } dir = &ff->dir; dir->elem = vtstrdup(elem); dir->entry = r->offset; dir->gen = r->gen; if(isdir){ dir->mentry = mr->offset; dir->mgen = mr->gen; } dir->size = 0; if(!fsNextQid(f->fs, &dir->qid)) goto Err; dir->uid = vtstrdup(uid); dir->gid = vtstrdup(f->dir.gid); dir->mid = vtstrdup(uid); dir->mtime = time(0L); dir->mcount = 0; dir->ctime = dir->mtime; dir->atime = dir->mtime; dir->mode = mode; ff->boff = fileMetaAlloc(f, dir, 0); if(ff->boff == NilBlock) goto Err; sourceUnlock(f->source); sourceUnlock(f->msource); ff->source = r; r->file = ff; /* point back */ ff->msource = mr; if(mode&ModeTemporary){ if(!sourceLock2(r, mr, -1)) goto Err1; fileSetTmp(ff, 1); sourceUnlock(r); if(mr) sourceUnlock(mr); } /* committed */ /* link in and up parent ref count */ ff->next = f->down; f->down = ff; ff->up = f; fileIncRef(f); fileWAccess(f, uid); fileUnlock(f); return ff; Err: sourceUnlock(f->source); sourceUnlock(f->msource); Err1: if(r){ sourceLock(r, -1); sourceRemove(r); } if(mr){ sourceLock(mr, -1); sourceRemove(mr); } if(ff) fileDecRef(ff); fileUnlock(f); return 0; }
char* rwrite(Fid *f) { USED(f); return vtstrdup(Erdonly); }
int fileSetDir(File *f, DirEntry *dir, char *uid) { File *ff; char *oelem; u32int mask; u64int size; /* can not set permissions for the root */ if(fileIsRoot(f)){ werrstr(ERoot); return 0; } if(!fileLock(f)) return 0; if(f->source->mode != OReadWrite){ werrstr(EReadOnly); fileUnlock(f); return 0; } fileMetaLock(f); /* check new name does not already exist */ if(strcmp(f->dir.elem, dir->elem) != 0){ for(ff = f->up->down; ff; ff=ff->next){ if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ werrstr(EExists); goto Err; } } ff = dirLookup(f->up, dir->elem); if(ff != nil){ fileDecRef(ff); werrstr(EExists); goto Err; } } if(!sourceLock2(f->source, f->msource, -1)) goto Err; if(!fileIsDir(f)){ size = sourceGetSize(f->source); if(size != dir->size){ if(!sourceSetSize(f->source, dir->size)){ sourceUnlock(f->source); if(f->msource) sourceUnlock(f->msource); goto Err; } /* commited to changing it now */ } } /* commited to changing it now */ if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary)) fileSetTmp(f, dir->mode&ModeTemporary); sourceUnlock(f->source); if(f->msource) sourceUnlock(f->msource); oelem = nil; if(strcmp(f->dir.elem, dir->elem) != 0){ oelem = f->dir.elem; f->dir.elem = vtstrdup(dir->elem); } if(strcmp(f->dir.uid, dir->uid) != 0){ vtfree(f->dir.uid); f->dir.uid = vtstrdup(dir->uid); } if(strcmp(f->dir.gid, dir->gid) != 0){ vtfree(f->dir.gid); f->dir.gid = vtstrdup(dir->gid); } f->dir.mtime = dir->mtime; f->dir.atime = dir->atime; //fprint(2, "mode %x %x ", f->dir.mode, dir->mode); mask = ~(ModeDir|ModeSnapshot); f->dir.mode &= ~mask; f->dir.mode |= mask & dir->mode; f->dirty = 1; //fprint(2, "->%x\n", f->dir.mode); fileMetaFlush2(f, oelem); vtfree(oelem); fileMetaUnlock(f); fileUnlock(f); fileWAccess(f->up, uid); return 1; Err: fileMetaUnlock(f); fileUnlock(f); return 0; }
int authCheck(Fcall* t, Fid* fid, Fsys* fsys) { Con *con; Fid *afid; uchar buf[1]; /* * Can't lookup with FidWlock here as there may be * protocol to do. Use a separate lock to protect altering * the auth information inside afid. */ con = fid->con; if(t->afid == NOFID){ /* * If no authentication is asked for, allow * "none" provided the connection has already * been authenticatated. * * The console is allowed to attach without * authentication. */ rlock(&con->alock); if(con->isconsole){ /* anything goes */ }else if((con->flags&ConNoneAllow) || con->aok){ static int noneprint; if(noneprint++ < 10) consPrint("attach %s as %s: allowing as none\n", fsysGetName(fsys), fid->uname); vtfree(fid->uname); fid->uname = vtstrdup(unamenone); }else{ runlock(&con->alock); consPrint("attach %s as %s: connection not authenticated, not console\n", fsysGetName(fsys), fid->uname); werrstr("cannot attach as none before authentication"); return 0; } runlock(&con->alock); if((fid->uid = uidByUname(fid->uname)) == nil){ consPrint("attach %s as %s: unknown uname\n", fsysGetName(fsys), fid->uname); werrstr("unknown user"); return 0; } return 1; } if((afid = fidGet(con, t->afid, 0)) == nil){ consPrint("attach %s as %s: bad afid\n", fsysGetName(fsys), fid->uname); werrstr("bad authentication fid"); return 0; } /* * Check valid afid; * check uname and aname match. */ if(!(afid->qid.type & QTAUTH)){ consPrint("attach %s as %s: afid not an auth file\n", fsysGetName(fsys), fid->uname); fidPut(afid); werrstr("bad authentication fid"); return 0; } if(strcmp(afid->uname, fid->uname) != 0 || afid->fsys != fsys){ consPrint("attach %s as %s: afid is for %s as %s\n", fsysGetName(fsys), fid->uname, fsysGetName(afid->fsys), afid->uname); fidPut(afid); werrstr("attach/auth mismatch"); return 0; } qlock(&afid->alock); if(afid->cuname == nil){ if(authRead(afid, buf, 0) != 0 || afid->cuname == nil){ qunlock(&afid->alock); consPrint("attach %s as %s: %r\n", fsysGetName(fsys), fid->uname); fidPut(afid); werrstr("fossil authCheck: auth protocol not finished"); return 0; } } qunlock(&afid->alock); assert(fid->uid == nil); if((fid->uid = uidByUname(afid->cuname)) == nil){ consPrint("attach %s as %s: unknown cuname %s\n", fsysGetName(fsys), fid->uname, afid->cuname); fidPut(afid); werrstr("unknown user"); return 0; } vtfree(fid->uname); fid->uname = vtstrdup(afid->cuname); fidPut(afid); /* * Allow "none" once the connection has been authenticated. */ wlock(&con->alock); con->aok = 1; wunlock(&con->alock); return 1; }
char* rwalk(Fid *f) { VacFile *file, *nfile; Fid *nf; int nqid, nwname; Qid qid; char *err = nil; if(f->busy == 0) return Enotexist; nf = nil; if(rhdr.fid != rhdr.newfid){ if(f->open) return vtstrdup(Eisopen); if(f->busy == 0) return vtstrdup(Enotexist); nf = newfid(rhdr.newfid); if(nf->busy) return vtstrdup(Eisopen); nf->busy = 1; nf->open = 0; nf->qid = f->qid; nf->file = vacfileincref(f->file); nf->user = vtstrdup(f->user); f = nf; } nwname = rhdr.nwname; /* easy case */ if(nwname == 0) { thdr.nwqid = 0; return 0; } file = f->file; vacfileincref(file); qid = f->qid; for(nqid = 0; nqid < nwname; nqid++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(!permf(file, f->user, Pexec)) { err = Eperm; break; } nfile = vacfilewalk(file, rhdr.wname[nqid]); if(nfile == nil) break; vacfiledecref(file); file = nfile; qid.type = QTFILE; if(vacfileisdir(file)) qid.type = QTDIR; qid.vers = vacfilegetmcount(file); qid.path = vacfilegetid(file); thdr.wqid[nqid] = qid; } thdr.nwqid = nqid; if(nqid == nwname){ /* success */ f->qid = thdr.wqid[nqid-1]; vacfiledecref(f->file); f->file = file; return 0; } vacfiledecref(file); if(nf != nil) rclunk(nf); /* only error on the first element */ if(nqid == 0) return vtstrdup(err); return 0; }
int vtversion(VtConn *z) { char buf[VtMaxStringSize], *p, *ep, *prefix, *pp; int i; qlock(&z->lk); if(z->state != VtStateAlloc){ werrstr("bad session state"); qunlock(&z->lk); return -1; } qlock(&z->inlk); qlock(&z->outlk); p = buf; ep = buf + sizeof buf; prefix = "venti-"; p = seprint(p, ep, "%s", prefix); p += strlen(p); for(i=0; okvers[i]; i++) p = seprint(p, ep, "%s%s", i ? ":" : "", okvers[i]); p = seprint(p, ep, "-libventi\n"); assert(p-buf < sizeof buf); if(write(z->outfd, buf, p-buf) != p-buf) goto Err; vtdebug(z, "version string out: %s", buf); if(vtreadversion(z, prefix, buf, sizeof buf) < 0) goto Err; vtdebug(z, "version string in: %s", buf); p = buf+strlen(prefix); for(; *p; p=pp){ if(*p == ':' || *p == '-') p++; pp = strpbrk(p, ":-"); if(pp == nil) pp = p+strlen(p); for(i=0; okvers[i]; i++) if(strlen(okvers[i]) == pp-p && memcmp(okvers[i], p, pp-p) == 0){ *pp = 0; z->version = vtstrdup(p); goto Okay; } } werrstr("unable to negotiate version"); goto Err; Okay: z->state = VtStateConnected; qunlock(&z->inlk); qunlock(&z->outlk); qunlock(&z->lk); return 0; Err: werrstr("vtversion: %r"); if(z->infd >= 0) close(z->infd); if(z->outfd >= 0 && z->outfd != z->infd) close(z->outfd); z->infd = -1; z->outfd = -1; z->state = VtStateClosed; qunlock(&z->inlk); qunlock(&z->outlk); qunlock(&z->lk); return -1; }
int rdconf(char *file, Conf *conf) { char *s, *line, *flds[10]; int i, ok; IFile f; if(readifile(&f, file) < 0) return -1; memset(conf, 0, sizeof *conf); ok = -1; line = nil; for(;;){ s = ifileline(&f); if(s == nil){ ok = 0; break; } line = estrdup(s); i = getfields(s, flds, nelem(flds), 1, " \t\r"); if(i <= 0 || strcmp(flds[0], "mgr") != 0) { /* do nothing */ }else if(i == 4 && strcmp(flds[1], "mirror") == 0) { if(conf->nmirror%64 == 0) conf->mirror = vtrealloc(conf->mirror, (conf->nmirror+64)*sizeof(conf->mirror[0])); conf->mirror[conf->nmirror].src = vtstrdup(flds[2]); conf->mirror[conf->nmirror].dst = vtstrdup(flds[3]); conf->nmirror++; }else if(i == 3 && strcmp(flds[1], "mirrorfreq") == 0) { conf->mirrorfreq = atoi(flds[2]); }else if(i == 3 && strcmp(flds[1], "verify") == 0) { if(conf->nverify%64 == 0) conf->verify = vtrealloc(conf->verify, (conf->nverify+64)*sizeof(conf->verify[0])); conf->verify[conf->nverify++] = vtstrdup(flds[2]); }else if(i == 3 && strcmp(flds[1], "verifyfreq") == 0) { conf->verifyfreq = atoi(flds[2]); }else if(i == 3 && strcmp(flds[1], "httpaddr") == 0){ if(conf->httpaddr){ seterr(EAdmin, "duplicate httpaddr lines in configuration file %s", file); break; } conf->httpaddr = estrdup(flds[2]); }else if(i == 3 && strcmp(flds[1], "webroot") == 0){ if(conf->webroot){ seterr(EAdmin, "duplicate webroot lines in configuration file %s", file); break; } conf->webroot = estrdup(flds[2]); }else if(i == 3 && strcmp(flds[1], "smtp") == 0) { if(conf->smtp){ seterr(EAdmin, "duplicate smtp lines in configuration file %s", file); break; } conf->smtp = estrdup(flds[2]); }else if(i == 3 && strcmp(flds[1], "mailfrom") == 0) { if(conf->mailfrom){ seterr(EAdmin, "duplicate mailfrom lines in configuration file %s", file); break; } conf->mailfrom = estrdup(flds[2]); }else if(i == 3 && strcmp(flds[1], "mailto") == 0) { if(conf->mailto){ seterr(EAdmin, "duplicate mailto lines in configuration file %s", file); break; } conf->mailto = estrdup(flds[2]); }else{ seterr(EAdmin, "illegal line '%s' in configuration file %s", line, file); break; } free(line); line = nil; } free(line); freeifile(&f); return ok; }