static void uboxDump(Ubox* box) { User* u; consPrint("nuser %d len = %d\n", box->nuser, box->len); for(u = box->head; u != nil; u = u->next) consPrint("%U\n", u); }
static Source * fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode, int issnapshot) { char *rname, *fname; Source *r; if(!sourceLock(f->source, mode)) return nil; r = sourceOpen(f->source, offset, mode, issnapshot); sourceUnlock(f->source); if(r == nil) return nil; if(r->gen != gen){ vtSetError(ERemoved); goto Err; } if(r->dir != dir && r->mode != -1){ /* this hasn't been as useful as we hoped it would be. */ rname = sourceName(r); fname = fileName(f); consPrint("%s: source %s for file %s: fileOpenSource: " "dir mismatch %d %d\n", f->source->fs->name, rname, fname, r->dir, dir); free(rname); free(fname); vtSetError(EBadMeta); goto Err; } return r; Err: sourceClose(r); return nil; }
static int cmdLstn(int argc, char* argv[]) { int dflag, flags; Lstn *lstn; char *usage = "usage: listen [-dIN] [address]"; dflag = 0; flags = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; case 'I': flags |= ConIPCheck; break; case 'N': flags |= ConNoneAllow; break; }ARGEND switch(argc){ default: return cliError(usage); case 0: vtRLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next) consPrint("\t%s\t%s\n", lstn->address, lstn->dir); vtRUnlock(lbox.lock); break; case 1: if(!dflag){ if(lstnAlloc(argv[0], flags) == nil) return 0; break; } vtLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ if(strcmp(lstn->address, argv[0]) != 0) continue; if(lstn->afd != -1){ close(lstn->afd); lstn->afd = -1; } break; } vtUnlock(lbox.lock); if(lstn == nil){ vtSetError("listen: '%s' not found", argv[0]); return 0; } break; } return 1; }
static int cmdUsers(int argc, char* argv[]) { Ubox *box; int dflag, r, wflag; char *file; char *usage = "usage: users [-d | -r file] [-w]"; dflag = wflag = 0; file = nil; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; case 'r': file = ARGF(); if(file == nil) return cliError(usage); break; case 'w': wflag = 1; break; }ARGEND if(argc) return cliError(usage); if(dflag && file) return cliError("cannot use -d and -r together"); if(dflag) uboxInit(usersDefault, sizeof(usersDefault)); else if(file){ if(usersFileRead(file) == 0) return 0; } vtRLock(ubox.lock); box = ubox.box; consPrint("\tnuser %d len %d\n", box->nuser, box->len); r = 1; if(wflag) r = usersFileWrite(box); vtRUnlock(ubox.lock); return r; }
Source * sourceRoot(Fs *fs, uint32_t addr, int mode) { Source *r; Block *b; b = cacheLocalData(fs->cache, addr, BtDir, RootTag, mode, 0); if(b == nil) return nil; if(mode == OReadWrite && b->l.epoch != fs->ehi) { consPrint("sourceRoot: fs->ehi = %ud, b->l = %L\n", fs->ehi, &b->l); blockPut(b); vtSetError(EBadRoot); return nil; } r = sourceAlloc(fs, b, nil, 0, mode, 0); blockPut(b); return r; }
static int cmdUname(int argc, char* argv[]) { User *u, *up; int d, dflag, i, r; char *p, *uid, *uname; char *createfmt = "fsys main create /active/usr/%s %s %s d775"; char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]"; dflag = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; }ARGEND if(argc < 1){ if(!dflag) return cliError(usage); vtRLock(ubox.lock); uboxDump(ubox.box); vtRUnlock(ubox.lock); return 1; } uname = argv[0]; argc--; argv++; if(argc == 0){ vtRLock(ubox.lock); if((u = _userByUname(ubox.box, uname)) == nil){ vtRUnlock(ubox.lock); return 0; } consPrint("\t%U\n", u); vtRUnlock(ubox.lock); return 1; } vtLock(ubox.lock); u = _userByUname(ubox.box, uname); while(argc--){ if(argv[0][0] == '%'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } p = &argv[0][1]; if((up = _userByUname(ubox.box, p)) != nil){ vtSetError("uname: uname '%s' already exists", up->uname); vtUnlock(ubox.lock); return 0; } for(i = 0; usersMandatory[i] != nil; i++){ if(strcmp(usersMandatory[i], uname) != 0) continue; vtSetError("uname: uname '%s' is mandatory", uname); vtUnlock(ubox.lock); return 0; } d = strlen(p) - strlen(u->uname); for(up = ubox.box->head; up != nil; up = up->next){ if(up->leader != nil){ if(strcmp(up->leader, u->uname) == 0){ vtMemFree(up->leader); up->leader = vtStrDup(p); ubox.box->len += d; } } for(i = 0; i < up->ngroup; i++){ if(strcmp(up->group[i], u->uname) != 0) continue; vtMemFree(up->group[i]); up->group[i] = vtStrDup(p); ubox.box->len += d; break; } } uboxRemUser(ubox.box, u); vtMemFree(u->uname); u->uname = vtStrDup(p); uboxAddUser(ubox.box, u); } else if(argv[0][0] == '='){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ if(argv[0][1] != '\0'){ vtUnlock(ubox.lock); return 0; } } if(u->leader != nil){ ubox.box->len -= strlen(u->leader); vtMemFree(u->leader); u->leader = nil; } if(up != nil){ u->leader = vtStrDup(up->uname); ubox.box->len += strlen(u->leader); } } else if(argv[0][0] == '+'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupAddMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else if(argv[0][0] == '-'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupRemMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else{ if(u != nil){ vtSetError("uname: uname '%s' already exists", u->uname); vtUnlock(ubox.lock); return 0; } uid = argv[0]; if(*uid == ':') uid++; if((u = _userByUid(ubox.box, uid)) != nil){ vtSetError("uname: uid '%s' already exists", u->uid); vtUnlock(ubox.lock); return 0; } u = userAlloc(uid, uname); uboxAddUser(ubox.box, u); if(argv[0][0] != ':'){ // should have an option for the mode and gid p = smprint(createfmt, uname, uname, uname); r = cliExec(p); vtMemFree(p); if(r == 0){ vtUnlock(ubox.lock); return 0; } } } argv++; } if(usersFileWrite(ubox.box) == 0){ vtUnlock(ubox.lock); return 0; } if(dflag) uboxDump(ubox.box); vtUnlock(ubox.lock); return 1; }
static int cmdSrv(int argc, char* argv[]) { Con *con; Srv *srv; char *usage = "usage: srv [-APWdp] [service]"; int conflags, dflag, fd[2], mode, pflag, r; dflag = 0; pflag = 0; conflags = 0; mode = 0666; ARGBEGIN{ default: return cliError(usage); case 'A': conflags |= ConNoAuthCheck; break; case 'I': conflags |= ConIPCheck; break; case 'N': conflags |= ConNoneAllow; break; case 'P': conflags |= ConNoPermCheck; mode = 0600; break; case 'W': conflags |= ConWstatAllow; mode = 0600; break; case 'd': dflag = 1; break; case 'p': pflag = 1; mode = 0600; break; }ARGEND if(pflag && (conflags&ConNoPermCheck)){ vtSetError("srv: cannot use -P with -p"); return 0; } switch(argc){ default: return cliError(usage); case 0: vtRLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next) consPrint("\t%s\t%d\n", srv->service, srv->srvfd); vtRUnlock(sbox.lock); return 1; case 1: if(!dflag) break; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, argv[0]) != 0) continue; srvFree(srv); break; } vtUnlock(sbox.lock); if(srv == nil){ vtSetError("srv: '%s' not found", argv[0]); return 0; } return 1; } if(pipe(fd) < 0){ vtSetError("srv pipe: %r"); return 0; } if((srv = srvAlloc(argv[0], mode, fd[0])) == nil){ close(fd[0]); close(fd[1]); return 0; } if(pflag) r = consOpen(fd[1], srv->srvfd, -1); else{ con = conAlloc(fd[1], srv->mntpnt, conflags); if(con == nil) r = 0; else r = 1; } if(r == 0){ close(fd[1]); vtLock(sbox.lock); srvFree(srv); vtUnlock(sbox.lock); } return r; }
void main(int argc, char* argv[]) { char **cmd, *p; int i, ncmd, tflag; fmtinstall('D', dirfmt); fmtinstall('F', fcallfmt); fmtinstall('M', dirmodefmt); quotefmtinstall(); /* * Insulate from the invoker's environment. */ if(rfork(RFREND|RFNOTEG|RFNAMEG) < 0) sysfatal("rfork: %r"); close(0); open("/dev/null", OREAD); close(1); open("/dev/null", OWRITE); cmd = nil; ncmd = tflag = 0; vtAttach(); ARGBEGIN{ case '?': default: usage(); break; case 'c': p = EARGF(usage()); currfsysname = p; cmd = vtMemRealloc(cmd, (ncmd+1)*sizeof(char*)); cmd[ncmd++] = p; break; case 'D': Dflag ^= 1; break; case 'f': p = EARGF(usage()); currfsysname = foptname = p; readCmdPart(p, &cmd, &ncmd); break; case 'm': mempcnt = atoi(EARGF(usage())); if(mempcnt <= 0 || mempcnt >= 100) usage(); break; case 't': tflag = 1; break; }ARGEND if(argc != 0) usage(); consInit(); cliInit(); msgInit(); conInit(); cmdInit(); fsysInit(); exclInit(); fidInit(); srvInit(); lstnInit(); usersInit(); for(i = 0; i < ncmd; i++) if(cliExec(cmd[i]) == 0) fprint(2, "%s: %R\n", cmd[i]); vtMemFree(cmd); if(tflag && consTTY() == 0) consPrint("%s\n", vtGetError()); vtDetach(); exits(0); }
static void archThread(void *v) { Arch *a = v; Block *b; Param p; Super super; int ret; u32int addr; uchar rbuf[VtRootSize]; VtRoot root; vtThreadSetName("arch"); for(;;){ /* look for work */ vtLock(a->fs->elk); b = superGet(a->c, &super); if(b == nil){ vtUnlock(a->fs->elk); fprint(2, "archThread: superGet: %R\n"); sleep(60*1000); continue; } addr = super.next; if(addr != NilBlock && super.current == NilBlock){ super.current = addr; super.next = NilBlock; superPack(&super, b->data); blockDirty(b); }else addr = super.current; blockPut(b); vtUnlock(a->fs->elk); if(addr == NilBlock){ /* wait for work */ vtLock(a->lk); vtSleep(a->starve); if(a->die != nil) goto Done; vtUnlock(a->lk); continue; } sleep(10*1000); /* window of opportunity to provoke races */ /* do work */ memset(&p, 0, sizeof p); p.blockSize = a->blockSize; p.dsize = 3*VtEntrySize; /* root has three Entries */ p.c = a->c; p.a = a; ret = archWalk(&p, addr, BtDir, RootTag); switch(ret){ default: abort(); case ArchFailure: fprint(2, "archiveBlock %#ux: %R\n", addr); sleep(60*1000); continue; case ArchSuccess: case ArchFaked: break; } if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud" " send %ud nfailsend %ud nvisit %ud" " nreclaim %ud nfake %ud nreal %ud\n", addr, p.maxdepth, p.nfixed, p.nsend, p.nfailsend, p.nvisit, p.nreclaim, p.nfake, p.nreal); if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize); /* tie up vac root */ memset(&root, 0, sizeof root); root.version = VtRootVersion; strecpy(root.type, root.type+sizeof root.type, "vac"); strecpy(root.name, root.name+sizeof root.name, "fossil"); memmove(root.score, p.score, VtScoreSize); memmove(root.prev, super.last, VtScoreSize); root.blockSize = a->blockSize; vtRootPack(&root, rbuf); if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize) || !vtSha1Check(p.score, rbuf, VtRootSize)){ fprint(2, "vtWriteBlock %#ux: %R\n", addr); sleep(60*1000); continue; } /* record success */ vtLock(a->fs->elk); b = superGet(a->c, &super); if(b == nil){ vtUnlock(a->fs->elk); fprint(2, "archThread: superGet: %R\n"); sleep(60*1000); continue; } super.current = NilBlock; memmove(super.last, p.score, VtScoreSize); superPack(&super, b->data); blockDirty(b); blockPut(b); vtUnlock(a->fs->elk); consPrint("archive vac:%V\n", p.score); } Done: a->ref--; vtWakeup(a->die); vtUnlock(a->lk); }
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; }
static Source * sourceAlloc(Fs *fs, Block *b, Source *p, uint32_t offset, int mode, int issnapshot) { int epb; uint32_t epoch; char *pname = nil; Source *r; Entry e; assert(p==nil || sourceIsLocked(p)); if(p == nil) { assert(offset == 0); epb = 1; } else epb = p->dsize / VtEntrySize; if(b->l.type != BtDir) goto Bad; /* * a non-active entry is the only thing that * can legitimately happen here. all the others * get prints. */ if(!entryUnpack(&e, b->data, offset % epb)) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n", fs->name, pname, b->score); goto Bad; } if(!(e.flags & VtEntryActive)) { pname = sourceName(p); if(0) consPrint("%s: %s %V: sourceAlloc: not active\n", fs->name, pname, e.score); goto Bad; } if(e.psize < 256 || e.dsize < 256) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n", fs->name, pname, e.score, e.psize, e.dsize); goto Bad; } if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud " "psize %ud dsize %ud\n", fs->name, pname, e.score, e.depth, e.size, e.psize, e.dsize); goto Bad; } if((e.flags & VtEntryLocal) && e.tag == 0) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n", fs->name, pname, e.score, e.flags, e.tag); goto Bad; } if(e.dsize > fs->blockSize || e.psize > fs->blockSize) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud " "> blocksize %ud\n", fs->name, pname, e.score, e.psize, e.dsize, fs->blockSize); goto Bad; } epoch = b->l.epoch; if(mode == OReadWrite) { if(e.snap != 0) { vtSetError(ESnapRO); return nil; } } else if(e.snap != 0) { if(e.snap < fs->elo) { vtSetError(ESnapOld); return nil; } if(e.snap >= fs->ehi) goto Bad; epoch = e.snap; } r = vtMemAllocZ(sizeof(Source)); r->fs = fs; r->mode = mode; r->issnapshot = issnapshot; r->dsize = e.dsize; r->gen = e.gen; r->dir = (e.flags & VtEntryDir) != 0; r->lk = vtLockAlloc(); r->ref = 1; r->parent = p; if(p) { vtLock(p->lk); assert(mode == OReadOnly || p->mode == OReadWrite); p->ref++; vtUnlock(p->lk); } r->epoch = epoch; // consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score, // b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro"); memmove(r->score, b->score, VtScoreSize); r->scoreEpoch = b->l.epoch; r->offset = offset; r->epb = epb; r->tag = b->l.tag; // consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset); return r; Bad: free(pname); vtSetError(EBadEntry); return nil; }