git: 9front

Download patch

ref: 7d9677ed9930b8509a4dc6ff3bf40332e4b0e013
parent: bffaa325f1fbbb3edf7048f132303cf4f6c41634
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Sep 21 19:28:37 EDT 2019

devip: fix permission checking

permission checking had the "other" and "owner" bits swapped plus incoming
connections where always owned by "network" instead of the owner of
the listening connection. also, ipwstat() was not effective as the uid
strings where not parsed.

this fixes the permission checks for data/ctl/err file and makes incoming
connections inherit the owner from the listening connection.

we also allow ipwstat() to change ownership to the commonuser() or anyone
if we are eve.

we might have to add additional restrictions for none at a later point...

--- a/sys/src/9/ip/devip.c
+++ b/sys/src/9/ip/devip.c
@@ -355,7 +355,7 @@
 	default:
 		break;
 	case Qndb:
-		if(omode & (OWRITE|OTRUNC) && !iseve())
+		if((omode & (OWRITE|OTRUNC)) != 0 && !iseve())
 			error(Eperm);
 		if((omode & (OWRITE|OTRUNC)) == (OWRITE|OTRUNC))
 			f->ndb[0] = 0;
@@ -412,15 +412,12 @@
 			qunlock(p);
 			nexterror();
 		}
-		if((perm & (cv->perm>>6)) != perm) {
-			if(strcmp(ATTACHER(c), cv->owner) != 0)
-				error(Eperm);
-		 	if((perm & cv->perm) != perm)
-				error(Eperm);
+		if(strcmp(ATTACHER(c), cv->owner) == 0)
+			perm <<= 6;
+		if((perm & cv->perm) != perm && !iseve())
+			error(Eperm);
 
-		}
-		cv->inuse++;
-		if(cv->inuse == 1){
+		if(++cv->inuse == 1){
 			kstrdup(&cv->owner, ATTACHER(c));
 			cv->perm = 0660;
 		}
@@ -430,24 +427,26 @@
 		break;
 	case Qlisten:
 		cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
-		if((perm & (cv->perm>>6)) != perm) {
-			if(strcmp(ATTACHER(c), cv->owner) != 0)
-				error(Eperm);
-		 	if((perm & cv->perm) != perm)
-				error(Eperm);
-
+		qlock(cv);
+		if(waserror()){
+			qunlock(cv);
+			nexterror();
 		}
+		if(strcmp(ATTACHER(c), cv->owner) == 0)
+			perm <<= 6;
+		if((perm & cv->perm) != perm && !iseve())
+			error(Eperm);
 
 		if(cv->state != Announced)
 			error("not announced");
 
+		cv->inuse++;
+		qunlock(cv);
+		poperror();
 		if(waserror()){
 			closeconv(cv);
 			nexterror();
 		}
-		qlock(cv);
-		cv->inuse++;
-		qunlock(cv);
 
 		nc = nil;
 		while(nc == nil) {
@@ -469,7 +468,6 @@
 			if(nc != nil){
 				cv->incall = nc->next;
 				mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
-				kstrdup(&cv->owner, ATTACHER(c));
 			}
 			qunlock(cv);
 
@@ -502,10 +500,9 @@
 static int
 ipwstat(Chan *c, uchar *dp, int n)
 {
-	Dir d;
+	Dir *dir;
 	Conv *cv;
 	Fs *f;
-	Proto *p;
 
 	f = ipfs[c->dev];
 	switch(TYPE(c->qid)) {
@@ -517,16 +514,36 @@
 		break;
 	}
 
-	n = convM2D(dp, n, &d, nil);
-	if(n > 0){
-		p = f->p[PROTO(c->qid)];
-		cv = p->conv[CONV(c->qid)];
-		if(!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
+	dir = smalloc(sizeof(Dir)+n);
+	if(waserror()){
+		free(dir);
+		nexterror();
+	}
+	n = convM2D(dp, n, &dir[0], (char*)&dir[1]);
+	if(n == 0)
+		error(Eshortstat);
+
+	cv = f->p[PROTO(c->qid)]->conv[CONV(c->qid)];
+	qlock(cv);
+	if(waserror()){
+		qunlock(cv);
+		nexterror();
+	}
+	if(strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
+		error(Eperm);
+	if(!emptystr(dir->uid)){
+		if(strcmp(dir->uid, commonuser()) != 0 && !iseve())
 			error(Eperm);
-		if(d.uid[0])
-			kstrdup(&cv->owner, d.uid);
-		cv->perm = d.mode & 0777;
+		kstrdup(&cv->owner, dir->uid);
 	}
+	if(dir->mode != ~0UL)
+		cv->perm = dir->mode & 0666;
+	qunlock(cv);
+	poperror();
+
+	free(dir);
+	poperror();
+
 	return n;
 }
 
@@ -1394,7 +1411,7 @@
 	}
 
 	/* find a free conversation */
-	nc = Fsprotoclone(c->p, network);
+	nc = Fsprotoclone(c->p, c->owner);
 	if(nc == nil) {
 		qunlock(c);
 		return nil;
--