File:  [Plan 9 NeXT] / lucent / sys / src / 9 / port / net.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:01:03 2018 UTC (8 years, 1 month ago) by root
Branches: lucent, MAIN
CVS tags: plan9, HEAD
Plan 9 NeXT

#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"

enum
{
	Qlisten	= 1,
	Qclone	= 2,
	Q2nd	= 3,
	Q3rd	= 4,
	Qinf	= 5,
};

/*
 *  find protection structure
 */
static Netprot*
findprot(Network *np, int id)
{
	Netprot *p;

	for(p = np->prot; p; p = p->next)
		if(p->id == id)
			break;
	return p;
}

/*
 *  generate a 3 level directory
 */
int
netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
{
	Qid q;
	char buf[32];
	Network *np = vp;
	int t;
	Netprot *p;
	int perm;
	char *o;

	USED(ntab);
	q.vers = 0;

	/* top level directory contains the name of the network */
	if(c->qid.path == CHDIR){
		switch(i){
		case 0:
			q.path = CHDIR | Q2nd;
			strcpy(buf, np->name);
			devdir(c, q, buf, 0, eve, 0555, dp);
			break;
		default:
			return -1;
		}
		return 1;
	}

	/* second level contains clone plus all the conversations */
	t = STREAMTYPE(c->qid.path);
	if(t == Q2nd || t == Qclone){
		if(i == 0){
			q.path = Qclone;
			devdir(c, q, "clone", 0, eve, 0666, dp);
		}else if(i <= np->nconv){
			if(findprot(np, i-1) == 0)
				return 0;
			q.path = CHDIR|STREAMQID(i-1, Q3rd);
			sprint(buf, "%d", i-1);
			devdir(c, q, buf, 0, eve, 0555, dp);
		}else
			return -1;
		return 1;
	}

	/* third level depends on the number of info files */
	p = findprot(np, STREAMID(c->qid.path));
	if(p == 0)
		return 0;
	if(*p->owner){
		o = p->owner;
		perm = p->mode;
	} else {
		o = eve;
		perm = 0666;
	}
	switch(i){
	case 0:
		q.path = STREAMQID(STREAMID(c->qid.path), Sdataqid);
		devdir(c, q, "data", 0, o, perm, dp);
		break;
	case 1:
		q.path = STREAMQID(STREAMID(c->qid.path), Sctlqid);
		devdir(c, q, "ctl", 0, o, perm, dp);
		break;
	case 2:
		if(np->listen == 0)
			return 0;
		q.path = STREAMQID(STREAMID(c->qid.path), Qlisten);
		devdir(c, q, "listen", 0, o, perm, dp);
		break;
	default:
		i -= 3;
		if(i >= np->ninfo)
			return -1;
		q.path = STREAMQID(STREAMID(c->qid.path), Qinf+i);
		devdir(c, q, np->info[i].name, 0, eve, 0444, dp);
		break;
	}
	return 1;
}

int	 
netwalk(Chan *c, char *name, Network *np)
{
	if(strcmp(name, "..") == 0) {
		switch(STREAMTYPE(c->qid.path)){
		case Q2nd:
			c->qid.path = CHDIR;
			break;
		case Q3rd:
			c->qid.path = CHDIR|Q2nd;
			break;
		default:
			panic("netwalk %lux", c->qid.path);
		}
		return 1;
	}

	return devwalk(c, name, (Dirtab*)np, 0, netgen);
}

void
netstat(Chan *c, char *db, Network *np)
{
	devstat(c, db, (Dirtab*)np, 1, netgen);
}

Chan *
netopen(Chan *c, int omode, Network *np)
{
	int id = 0;
	Netprot *p;

	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Eperm);
	} else {
		switch(STREAMTYPE(c->qid.path)){
		case Sdataqid:
		case Sctlqid:
			id = STREAMID(c->qid.path);
			break;
		case Qlisten:
			streamopen(c, np->devp);
			id = (*np->listen)(c);
			streamclose(c);
			c->qid.path = STREAMQID(id, Sctlqid);
			break;
		case Qclone:
			id = (*np->clone)(c);
			c->qid.path = STREAMQID(id, Sctlqid);
			break;
		default:
			if(omode != OREAD)
				error(Ebadarg);
		}
		switch(STREAMTYPE(c->qid.path)){
		case Sdataqid:
		case Sctlqid:
			streamopen(c, np->devp);
			if(np->protop && c->stream->devq->next->info != np->protop)
				pushq(c->stream, np->protop);
			p = findprot(np, id);
			if(netown(p, u->p->user, omode&7) < 0)
				error(Eperm);
			break;
		}
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

long
netread(Chan *c, void *a, long n, ulong offset, Network *np)
{
	int t;
	char buf[256];

	if(c->stream)
		return streamread(c, a, n);

	if(c->qid.path&CHDIR)
		return devdirread(c, a, n, (Dirtab*)np, 0, netgen);

	t = STREAMTYPE(c->qid.path);
	if(t < Qinf || t >= Qinf + np->ninfo)
		error(Ebadusefd);

	(*np->info[t-Qinf].fill)(c, buf, sizeof(buf));
	return readstr(offset, a, n, buf);
}

void
netadd(Network *np, Netprot *p, int id)
{
	Netprot **l, *pp;

	memset(p, 0, sizeof(Netprot));
	p->id = id;

	l = &np->prot;
	for(pp = np->prot; pp; pp = pp->next){
		if(pp->id == id)
			panic("netadd");
		l = &pp->next;
	}
	*l = p;
}

Lock netlock;

int
netown(Netprot *p, char *o, int omode)
{
	static int access[] = { 0400, 0200, 0600, 0100 };
	int mode;
	int t;

	lock(&netlock);
	if(*p->owner){
		if(strncmp(o, p->owner, NAMELEN) == 0)	/* User */
			mode = p->mode;
		else if(strncmp(o, eve, NAMELEN) == 0)	/* Bootes is group */
			mode = p->mode<<3;
		else
			mode = p->mode<<6;		/* Other */

		t = access[omode&3];
		if((t & mode) == t){
			unlock(&netlock);
			return 0;
		} else {
			unlock(&netlock);
			return -1;
		}
	}
	strncpy(p->owner, o, NAMELEN);
	p->mode = 0660;
	unlock(&netlock);
	return 0;
}

void
netdisown(Netprot *p)
{
	p->owner[0] = 0;
}

#undef	CHDIR	/* BUG */
#include "/sys/src/libc/9syscall/sys.h"

void
netwstat(Chan *c, char *db, Network *np)
{
	Dir dir;
	Netprot *p;

	p = findprot(np, STREAMID(c->qid.path));
	if(p == 0)
		error(Enonexist);
	lock(np);

	/*
	 *  A network channel's ownership/permissions can be changed only if the
	 *  wstat is by the owner or (HACK!) if it is performed using an fwstat.
	 *  The latter allows processes started by a network listener to gain
	 *  ownership of the connection.  The open file descriptor is used as
	 *  a capability for the connection.
	 */
	if(strncmp(p->owner, u->p->user, NAMELEN) != 0 && u->scallnr != FWSTAT){
		unlock(np);
		error(Eperm);
	}
	convM2D(db, &dir);
	strncpy(p->owner, dir.uid, NAMELEN);
	p->mode = dir.mode;

	unlock(np);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.