shithub: riscv

Download patch

ref: 427e925eea1ea4ca9a5308b7b08af01785389991
parent: 30d4d8984bfc64e971bfbb3b913c37ed8a8da17b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Aug 11 18:36:59 EDT 2014

cwfs: add optional uid argument to allow command, unify permission override code

the allow command now takes an optional uid argument for the user
to be granted temporary god status on the fileserver for maintenance.

this was kenji okomotos idea, so thanks :)

remove wstatallow and writeallow flags. instead, we have global:

int allowed;

that contains the uid of the currently allowed user id or -1
if permission checking is globally disabled for the fileserver.
when zero, normal permission checking takes place.

added int isallowed(File*) function that returns non-zero when the
context is the console, or the allowed user. this is also used internally
by iaccess(), so all the extra code of in the callers of iaccess()
is gone now.

dont conflate allowed user with noauth flag and auto-allow on ream.
the installer already knows about noauth and allow flags so theres no
problem with bootstraping.

--- a/sys/man/8/fs
+++ b/sys/man/8/fs
@@ -9,6 +9,7 @@
 ]
 .PP
 .B allow
+.RI [ uid ]
 .PP
 .B arp
 .I subcommand
@@ -158,7 +159,10 @@
 .PP
 .I Allow
 disables permission checking and allows
-.BR wstat .
+.BR wstat
+for the specified
+.I uid
+or for any user if omited.
 This may help in initializing a file system.
 Use this with caution.
 .PP
--- a/sys/src/cmd/cwfs/9p1.c
+++ b/sys/src/cmd/cwfs/9p1.c
@@ -57,7 +57,7 @@
 	memmove(aip->rchal, in->chal, sizeof(aip->rchal));
 	mkchallenge(aip);
 	memmove(ou->chal, aip->chal, sizeof(ou->chal));
-	if(noauth || wstatallow)
+	if(noauth)
 		memset(ou->authid, 0, sizeof(ou->authid));
 	else
 		memmove(ou->authid, nvr.authid, sizeof(ou->authid));
@@ -78,7 +78,7 @@
 	ulong bit;
 	Authinfo *aip;
 
-	if(noauth || wstatallow)	/* set to allow entry during boot */
+	if(noauth)
 		return 1;
 
 	if(strcmp(in->uname, "none") == 0)
@@ -245,7 +245,7 @@
 		ou->err = Ealloc;
 		goto out;
 	}
-	if (iaccess(f, d, DEXEC) ||
+	if(iaccess(f, d, DEXEC) ||
 	    f->uid == 0 && fs->dev->type == Devro) {
 		/*
 		 * 'none' not allowed on dump
@@ -370,7 +370,7 @@
 	}
 	if(ou->err = mkqidcmp(&f->qid, d))
 		goto out;
-	if(cp != cons.chan && iaccess(f, d, DEXEC)) {
+	if(iaccess(f, d, DEXEC)) {
 		ou->err = Eaccess;
 		goto out;
 	}
@@ -469,7 +469,7 @@
 	File *f;
 	Tlock *t;
 	Qid qid;
-	int ro, fmod, wok;
+	int ro, fmod;
 
 	if(CHAT(cp)) {
 		fprint(2, "c_open %d\n", cp->chan);
@@ -477,10 +477,6 @@
 		fprint(2, "\tmode = %o\n", in->mode);
 	}
 
-	wok = 0;
-	if(cp == cons.chan || writeallow)
-		wok = 1;
-
 	p = 0;
 	f = filep(cp, in->fid, 0);
 	if(!f) {
@@ -528,14 +524,13 @@
 	switch(in->mode & 7) {
 
 	case OREAD:
-		if(iaccess(f, d, DREAD) && !wok)
+		if(iaccess(f, d, DREAD))
 			goto badaccess;
 		fmod = FREAD;
 		break;
 
 	case OWRITE:
-		if((d->mode & DDIR) ||
-		   (iaccess(f, d, DWRITE) && !wok))
+		if((d->mode & DDIR) || iaccess(f, d, DWRITE))
 			goto badaccess;
 		if(ro) {
 			ou->err = Eronly;
@@ -545,9 +540,7 @@
 		break;
 
 	case ORDWR:
-		if((d->mode & DDIR) ||
-		   (iaccess(f, d, DREAD) && !wok) ||
-		   (iaccess(f, d, DWRITE) && !wok))
+		if((d->mode & DDIR) || iaccess(f, d, DREAD) || iaccess(f, d, DWRITE))
 			goto badaccess;
 		if(ro) {
 			ou->err = Eronly;
@@ -557,8 +550,7 @@
 		break;
 
 	case OEXEC:
-		if((d->mode & DDIR) ||
-		   (iaccess(f, d, DEXEC) && !wok))
+		if((d->mode & DDIR) || iaccess(f, d, DEXEC))
 			goto badaccess;
 		fmod = FREAD;
 		break;
@@ -568,8 +560,7 @@
 		goto out;
 	}
 	if(in->mode & OTRUNC) {
-		if((d->mode & DDIR) ||
-		   (iaccess(f, d, DWRITE) && !wok))
+		if((d->mode & DDIR) || iaccess(f, d, DWRITE))
 			goto badaccess;
 		if(ro) {
 			ou->err = Eronly;
@@ -617,7 +608,7 @@
 	Iobuf *p, *p1;
 	Dentry *d, *d1;
 	File *f;
-	int slot, slot1, fmod, wok;
+	int slot, slot1, fmod;
 	Off addr, addr1, path;
 	Qid qid;
 	Tlock *t;
@@ -632,10 +623,6 @@
 		fprint(2, "\tmode = %o\n", in->mode);
 	}
 
-	wok = 0;
-	if(cp == cons.chan || writeallow)
-		wok = 1;
-
 	p = 0;
 	f = filep(cp, in->fid, 0);
 	if(!f) {
@@ -659,7 +646,7 @@
 		ou->err = Edir2;
 		goto out;
 	}
-	if(iaccess(f, d, DWRITE) && !wok) {
+	if(iaccess(f, d, DWRITE)) {
 		ou->err = Eaccess;
 		goto out;
 	}
@@ -1118,7 +1105,7 @@
 }
 
 int
-doremove(File *f, int wok)
+doremove(File *f)
 {
 	Iobuf *p, *p1;
 	Dentry *d, *d1;
@@ -1144,7 +1131,7 @@
 		err = Ephase;
 		goto out;
 	}
-	if(iaccess(f, d1, DWRITE) && !wok) {
+	if(iaccess(f, d1, DWRITE)) {
 		err = Eaccess;
 		goto out;
 	}
@@ -1202,7 +1189,7 @@
 }
 
 static int
-doclunk(File* f, int remove, int wok)
+doclunk(File* f, int remove)
 {
 	Tlock *t;
 	int err;
@@ -1214,7 +1201,7 @@
 		f->tlock = 0;
 	}
 	if(remove)
-		err = doremove(f, wok);
+		err = doremove(f);
 	f->open = 0;
 	freewp(f->wpath);
 	freefp(f);
@@ -1236,7 +1223,7 @@
 	if(!f)
 		ou->err = Efid;
 	else {
-		doclunk(f, f->open & FREMOV, 0);
+		doclunk(f, f->open & FREMOV);
 		qunlock(f);
 	}
 	ou->fid = in->fid;
@@ -1256,7 +1243,7 @@
 	if(!f)
 		ou->err = Efid;
 	else {
-		ou->err = doclunk(f, 1, cp==cons.chan);
+		ou->err = doclunk(f, 1);
 		qunlock(f);
 	}
 	ou->fid = in->fid;
@@ -1371,7 +1358,7 @@
 	 * if chown,
 	 * must be god
 	 */
-	if(xd.uid != d->uid && !wstatallow) { /* set to allow chown during boot */
+	if(xd.uid != d->uid && !isallowed(f)) {
 		ou->err = Ewstatu;
 		goto out;
 	}
@@ -1382,10 +1369,9 @@
 	 *	a) owner and in new group
 	 *	b) leader of both groups
 	 */
-	if (xd.gid != d->gid &&
-	    (!wstatallow && !writeallow &&  /* set to allow chgrp during boot */
+	if (xd.gid != d->gid && !isallowed(f) && 
 	     (d->uid != f->uid || !ingroup(f->uid, xd.gid)) &&
-	     (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid)))) {
+	     (!leadgroup(f->uid, xd.gid) || !leadgroup(f->uid, d->gid))) {
 		ou->err = Ewstatg;
 		goto out;
 	}
@@ -1439,8 +1425,7 @@
 			goto out;
 		}
 
-		if (!wstatallow && !writeallow && /* set to allow rename during boot */
-		    (!d1 || iaccess(f, d1, DWRITE))) {
+		if(iaccess(f, d1, DWRITE)) {
 			ou->err = Eaccess;
 			goto out;
 		}
@@ -1453,8 +1438,7 @@
 	 */
 	if (d->mtime != xd.mtime ||
 	    ((d->mode^xd.mode) & (DAPND|DLOCK|0777)))
-		if (!wstatallow &&	/* set to allow chmod during boot */
-		    d->uid != f->uid &&
+		if (d->uid != f->uid && !isallowed(f) &&
 		    !leadgroup(f->uid, xd.gid) &&
 		    !leadgroup(f->uid, d->gid)) {
 			ou->err = Ewstatu;
--- a/sys/src/cmd/cwfs/9p2.c
+++ b/sys/src/cmd/cwfs/9p2.c
@@ -148,7 +148,7 @@
 	Filsys *fs;
 	int error;
 
-	if(noauth || wstatallow)
+	if(noauth)
 		return Eauthdisabled;
 
 	error = 0;
@@ -201,7 +201,7 @@
 
 	db = cons.flags & authdebugflag;
 
-	if(noauth || wstatallow){
+	if(noauth){
 		uid = strtouid(f->uname);
 		if(db)
 			fprint(2, "permission granted by noauth uid %s = %d\n",
@@ -290,7 +290,7 @@
 		error = Ealloc;
 		goto out;
 	}
-	if (iaccess(file, d, DEXEC) ||
+	if(iaccess(file, d, DEXEC) ||
 	    file->uid == 0 && fs->dev->type == Devro) {
 		/*
 		 * 'none' not allowed on dump
@@ -394,7 +394,7 @@
 	 * For walked elements the implied user must
 	 * have permission to search the directory.
 	 */
-	if(file->cp != cons.chan && iaccess(file, d, DEXEC)){
+	if(iaccess(file, d, DEXEC)){
 		error = Eaccess;
 		goto out;
 	}
@@ -607,14 +607,9 @@
 	File *file;
 	Tlock *t;
 	Qid qid;
-	int error, ro, fmod, wok;
+	int error, ro, fmod;
 
-	wok = 0;
 	p = nil;
-
-	if(chan == cons.chan || writeallow)
-		wok = 1;
-
 	if((file = filep(chan, f->fid, 0)) == nil){
 		error = Efid;
 		goto out;
@@ -672,13 +667,13 @@
 	switch(f->mode & 7){
 
 	case OREAD:
-		if(iaccess(file, d, DREAD) && !wok)
+		if(iaccess(file, d, DREAD))
 			goto badaccess;
 		fmod = FREAD;
 		break;
 
 	case OWRITE:
-		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
+		if((d->mode & DDIR) || iaccess(file, d, DWRITE))
 			goto badaccess;
 		if(ro){
 			error = Eronly;
@@ -689,8 +684,8 @@
 
 	case ORDWR:
 		if((d->mode & DDIR)
-		|| (iaccess(file, d, DREAD) && !wok)
-		|| (iaccess(file, d, DWRITE) && !wok))
+		|| iaccess(file, d, DREAD)
+		|| iaccess(file, d, DWRITE))
 			goto badaccess;
 		if(ro){
 			error = Eronly;
@@ -700,7 +695,7 @@
 		break;
 
 	case OEXEC:
-		if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))
+		if((d->mode & DDIR) || iaccess(file, d, DEXEC))
 			goto badaccess;
 		fmod = FREAD;
 		break;
@@ -710,7 +705,7 @@
 		goto out;
 	}
 	if(f->mode & OTRUNC){
-		if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
+		if((d->mode & DDIR) || iaccess(file, d, DWRITE))
 			goto badaccess;
 		if(ro){
 			error = Eronly;
@@ -759,17 +754,13 @@
 	Iobuf *p, *p1;
 	Dentry *d, *d1;
 	File *file;
-	int error, slot, slot1, fmod, wok;
+	int error, slot, slot1, fmod;
 	Off addr, addr1, path;
 	Tlock *t;
 	Wpath *w;
 
-	wok = 0;
 	p = nil;
 
-	if(chan == cons.chan || writeallow)
-		wok = 1;
-
 	if((file = filep(chan, f->fid, 0)) == nil){
 		error = Efid;
 		goto out;
@@ -799,7 +790,7 @@
 		error = Edir2;
 		goto out;
 	}
-	if(iaccess(file, d, DWRITE) && !wok) {
+	if(iaccess(file, d, DWRITE)) {
 		error = Eaccess;
 		goto out;
 	}
@@ -1273,7 +1264,7 @@
 }
 
 static int
-_clunk(File* file, int remove, int wok)
+_clunk(File* file, int remove)
 {
 	Tlock *t;
 	int error;
@@ -1285,7 +1276,7 @@
 		file->tlock = 0;
 	}
 	if(remove && (file->qid.type & QTAUTH) == 0)
-		error = doremove(file, wok);
+		error = doremove(file);
 	file->open = 0;
 	freewp(file->wpath);
 	authfree(file->auth);
@@ -1304,7 +1295,7 @@
 	if((file = filep(chan, f->fid, 0)) == nil)
 		return Efid;
 
-	_clunk(file, file->open & FREMOV, 0);
+	_clunk(file, file->open & FREMOV);
 	return 0;
 }
 
@@ -1315,8 +1306,7 @@
 
 	if((file = filep(chan, f->fid, 0)) == nil)
 		return Efid;
-
-	return _clunk(file, 1, chan == cons.chan);
+	return _clunk(file, 1);
 }
 
 static int
@@ -1433,13 +1423,10 @@
 	 * .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 (and .muid iff wstatallow).
+	 * possibly be changed (and .muid iff is god).
 	 *
 	 * 'Op' flags there are changed fields, i.e. it's not a no-op.
 	 * 'Tsync' flags all fields are defaulted.
-	 *
-	 * Wstatallow and writeallow are set to allow changes during the
-	 * fileserver bootstrap phase.
 	 */
 	tsync = 1;
 	if(dir.qid.path != ~0){
@@ -1526,7 +1513,7 @@
 	gl = leadgroup(file->uid, gid) != 0;
 	gl += leadgroup(file->uid, d->gid) != 0;
 
-	if(op && !wstatallow && d->uid != file->uid && !gl){
+	if(op && !isallowed(file) && d->uid != file->uid && !gl){
 		error = Ewstato;
 		goto out;
 	}
@@ -1613,7 +1600,7 @@
 		/*
 		 * Check write permission in the parent.
 		 */
-		if(!wstatallow && !writeallow && iaccess(file, d1, DWRITE)){
+		if(iaccess(file, d1, DWRITE)){
 			error = Eaccess;
 			goto out;
 		}
@@ -1625,7 +1612,7 @@
 	if(dir.uid != nil && *dir.uid != '\0'){
 		uid = strtouid(dir.uid);
 		if(uid != d->uid){
-			if(!wstatallow){
+			if(!isallowed(file)){
 				error = Ewstatu;
 				goto out;
 			}
@@ -1637,7 +1624,7 @@
 	if(dir.muid != nil && *dir.muid != '\0'){
 		muid = strtouid(dir.muid);
 		if(muid != d->muid){
-			if(!wstatallow){
+			if(!isallowed(file)){
 				error = Ewstatm;
 				goto out;
 			}
@@ -1652,7 +1639,7 @@
 	 * either owner and in new group or leader of both groups.
 	 */
 	if(gid != d->gid){
-		if(!(wstatallow || writeallow)
+		if(!isallowed(file)
 		&& !(d->uid == file->uid && ingroup(file->uid, gid))
 		&& !(gl == 2)){
 			error = Ewstatg;
--- a/sys/src/cmd/cwfs/all.h
+++ b/sys/src/cmd/cwfs/all.h
@@ -85,12 +85,10 @@
 int	nonone;			/* attach as none disabled */
 int	noatime;		/* atime is disabled */
 int	noatimeset;		/* noatime was changed (reset after dump) */
-int	wstatallow;		/* set to circumvent wstat permissions */
-int	writeallow;		/* set to circumvent write permissions */
+int	allowed;		/* allow wstat and disable permission checks
+				 * for user or anyone when -1 */
 int	duallow;		/* single user to allow du */
 int	readonly;		/* disable writes if true */
-
-
 int	rawreadok;		/* allow reading raw data */
 
 File*	flist[5003];		/* base of file structures */
--- a/sys/src/cmd/cwfs/con.c
+++ b/sys/src/cmd/cwfs/con.c
@@ -461,15 +461,31 @@
 }
 
 static void
-cmd_allow(int, char**)
+cmd_allow(int argc, char *argv[])
 {
-	wstatallow = writeallow = 1;
+	char *name;
+	int uid;
+
+	uid = -1;
+	name = "any user";
+	if(argc > 1){
+		name = argv[1];
+		uid = strtouid(name);
+		if(uid < 0)
+			uid = number(name, -2, 10);
+		if(uid < 0) {
+			print("bad uid %s\n", name);
+			return;
+		}
+	}
+	print("allowed %s\n", name);
+	allowed = uid;
 }
 
 static void
 cmd_disallow(int, char**)
 {
-	wstatallow = writeallow = 0;
+	allowed = 0;
 }
 
 void
@@ -748,7 +764,7 @@
 static void
 installcmds(void)
 {
-	cmd_install("allow", "-- disable permission checking", cmd_allow);
+	cmd_install("allow", "[uid] -- disable permission checking", cmd_allow);
 	cmd_install("cfs", "[file] -- set current filesystem", cmd_cfs);
 	cmd_install("chatty", "n -- set chattiness", cmd_chatty);
 	cmd_install("clean", "file [bno [addr]] -- block print/fix", cmd_clean);
@@ -755,7 +771,7 @@
 	cmd_install("check", "[options]", cmd_check);
 	cmd_install("clri", "[file ...] -- purge files/dirs", cmd_clri);
 	cmd_install("create", "path uid gid perm [lad] -- make a file/dir", cmd_create);
-	cmd_install("disallow", "-- enable permission checking", cmd_disallow);
+	cmd_install("disallow", "-- (re)enable permission checking", cmd_disallow);
 	cmd_install("duallow", "uid -- duallow", cmd_duallow);
 	cmd_install("flag", "-- print set flags", cmd_flag);
 	cmd_install("fstat", "path -- print info on a file/dir", cmd_fstat);
--- a/sys/src/cmd/cwfs/config.c
+++ b/sys/src/cmd/cwfs/config.c
@@ -1105,9 +1105,6 @@
 		}
 		switch(verb) {
 		case FREAM:
-			if(strcmp(fs->name, "main") == 0)
-				wstatallow = 1;	/* only set, never reset */
-			/* fallthrough */
 		case FRECOVER:
 			fs->flags |= verb;
 			break;
--- a/sys/src/cmd/cwfs/portfns.h
+++ b/sys/src/cmd/cwfs/portfns.h
@@ -66,7 +66,7 @@
 int	devwrite(Device*, Off, void*);
 Iobuf*	dnodebuf(Iobuf*, Dentry*, Off, int, int);
 Iobuf*	dnodebuf1(Iobuf*, Dentry*, Off, int, int);
-int	doremove(File*, int);
+int	doremove(File*);
 void	dtrunc(Iobuf*, Dentry*, int);
 int	dtrunclen(Iobuf *p, Dentry *, Off newsize, int uid);
 int	dumpblock(Device*);
@@ -107,6 +107,7 @@
 void*	iobufmap(Iobuf*);
 void	iobufunmap(Iobuf*);
 int	iobufql(QLock*);
+int	isallowed(File*);
 int	jukeread(Device*, Off, void*);
 int	jukewrite(Device*, Off, void*);
 void	jukeinit(Device*);
--- a/sys/src/cmd/cwfs/sub.c
+++ b/sys/src/cmd/cwfs/sub.c
@@ -89,7 +89,7 @@
 				f->tlock = 0;
 			}
 			if(f->open & FREMOV)
-				doremove(f, 0);
+				doremove(f);
 			freewp(f->wpath);
 			f->open = 0;
 			authfree(f->auth);
@@ -237,10 +237,13 @@
 				return 0;
 	}
 
-	/*
-	 * other
-	 */
+	/* other */
 	if(m & d->mode) {
+		/* 
+		 *  walk directories regardless.
+		 *  otherwise its impossible to get
+		 *  from the root to noworld's directories.
+		 */
 		if((d->mode & DDIR) && (m == DEXEC))
 			return 0;
 		if(!ingroup(f->uid, 9999))
@@ -247,16 +250,28 @@
 			return 0;
 	}
 
-	/*
-	 * various forms of superuser
-	 */
-	if(wstatallow)
-		return 0;
+	/* read access for du */
 	if(duallow != 0 && duallow == f->uid)
 		if((d->mode & DDIR) && (m == DREAD || m == DEXEC))
 			return 0;
 
-	return 1;
+	/* allow god */
+	return !isallowed(f);
+}
+
+int
+isallowed(File *f)
+{
+	if(f->cp == cons.chan)
+		return 1;
+	switch(allowed){
+	case 0:
+		return 0;
+	case -1:
+		return 1;
+	default:
+		return f->uid == allowed;
+	}
 }
 
 Tlock*