~kris/9p

9hist

7cd991eddcc06c102af939c4ea8a057ad9118530 — David du Colombier 30 years ago 551995d
Plan 9 from Bell Labs 1996-05-31
2 files changed, 105 insertions(+), 422 deletions(-)

M port/devssl.c
D port/net.c
M port/devssl.c => port/devssl.c +105 -102
@@ 1,25 1,25 @@
/*
 *  template for making a new device
 *  devssl - secure sockets layer emulation
 */
#include "u.h"
#include "../port/lib.h"
#include "../port/error.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"

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


typedef struct OneWay OneWay;
struct OneWay
{
	QLock;
	QLock	q;

	void		*state;		/* encryption state */
	int		slen;		/* hash data length */
	uchar		*secret;	/* secret */
	ulong		mid;		/* message id */
	void	*state;		/* encryption state */
	int	slen;		/* hash data length */
	uchar	*secret;	/* secret */
	ulong	mid;		/* message id */
};

enum


@@ 35,7 35,7 @@ enum
	/* encryption algorithms */
	Noencryption=	0,
	DESCBC=		1,
	DESECB=		2,
	DESECB=		2
};

typedef struct Dstate Dstate;


@@ 64,12 64,12 @@ struct Dstate

enum
{
	Maxdmsg=	1<<16,
	Maxdmsg=	1<<16
};

enum{
	Qdir,
	Qclone,
	Qclone
};
Dirtab digesttab[]={
	"ssl",		{Qclone, 0},	0,	0666,


@@ 98,21 98,20 @@ static void	checkdigestb(Dstate*, Block*);
static Chan*	buftochan(char*, long);
static void	dighangup(Dstate*);


void
sslreset(void)
{
	randq.ep = randq.buf + sizeof(randq.buf);
	randq.rp = randq.wp = randq.buf;
}

void
sslinit(void)
{
	randq.ep = randq.buf + sizeof(randq.buf);
	randq.rp = randq.wp = randq.buf;
}

Chan *
sslattach(char *spec)
sslattach(void *spec)
{
	return devattach('D', spec);
}


@@ 142,7 141,7 @@ sslopen(Chan *c, int omode)

	switch(c->qid.path & ~CHDIR){
	case Qclone:
		s = smalloc(sizeof(Dstate));
		s = malloc(sizeof(Dstate));
		memset(s, 0, sizeof(*s));
		s->state = Algwait;
		c->aux = s;


@@ 154,7 153,10 @@ sslopen(Chan *c, int omode)
void
sslcreate(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
	USED(c);
	USED(name);
	USED(omode);
	USED(perm);
	error(Eperm);
}



@@ 168,7 170,8 @@ sslremove(Chan *c)
void
sslwstat(Chan *c, char *dp)
{
	USED(c, dp);
	USED(c);
	USED(dp);
	error(Eperm);
}



@@ 181,7 184,7 @@ sslclose(Chan *c)
		s = c->aux;
		dighangup(s);
		if(s->c)
			close(s->c);
			cclose(s->c);
		if(s->in.secret)
			free(s->in.secret);
		if(s->out.secret)


@@ 193,81 196,81 @@ sslclose(Chan *c)
Block*
sslbread(Chan *c, long n, ulong offset)
{
	Dstate *s;
	volatile struct { Dstate *s; } s;
	Block *b;
	uchar count[2];
	int i, len, pad;

	USED(offset);

	s = c->aux;
	if(s == 0 || s->state != Established)
	s.s = c->aux;
	if(s.s == 0 || s.s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->in);
		dighangup(s);
		qunlock(&s.s->in.q);
		dighangup(s.s);
		nexterror();
	}
	qlock(&s->in);
	qlock(&s.s->in.q);

	b = s->processed;
	b = s.s->processed;
	if(b == 0){
	
		/* read in the whole message */
		s->processed = s->unprocessed;
		s->unprocessed = 0;
		ensure(s, &s->processed, 2);
		consume(&s->processed, count, 2);
		s.s->processed = s.s->unprocessed;
		s.s->unprocessed = 0;
		ensure(s.s, &s.s->processed, 2);
		consume(&s.s->processed, count, 2);
		if(count[0] & 0x80){
			len = ((count[0] & 0x7f)<<8) | count[1];
			ensure(s, &s->processed, len);
			ensure(s.s, &s.s->processed, len);
			pad = 0;
		} else {
			len = ((count[0] & 0x3f)<<8) | count[1];
			ensure(s, &s->processed, len+1);
			consume(&s->processed, count, 1);
			ensure(s.s, &s.s->processed, len+1);
			consume(&s.s->processed, count, 1);
			pad = count[0];
		}

		/* trade memory bandwidth for less processing complexity */
		b = s->processed = pullupblock(s->processed, len);
		b = s.s->processed = pullupblock(s.s->processed, len);

		/* put remainder on unprocessed queue */
		i = BLEN(b);
		if(i > len){
			i -= len;
			s->unprocessed = allocb(i);
			memmove(s->unprocessed->wp, b->rp+len, i);
			s->unprocessed->wp += i;
			s.s->unprocessed = allocb(i);
			memmove(s.s->unprocessed->wp, b->rp+len, i);
			s.s->unprocessed->wp += i;
			b->wp -= i;
		}

		if(s->encryptalg)
			b = decryptb(s, b);
		if(s.s->encryptalg)
			b = decryptb(s.s, b);
		else {
			if(BLEN(b) < s->diglen)
			if(BLEN(b) < s.s->diglen)
				error("baddigest");
			checkdigestb(s, b);
			b->rp += s->diglen;
			checkdigestb(s.s, b);
			b->rp += s.s->diglen;
		}

		/* remove pad */
		if(b->wp - b->rp < pad)
			panic("sslbread");
		b->wp -= pad;
		s->processed = b;
		s.s->processed = b;
	}

	if(BLEN(b) > n){
		b = allocb(n);
		memmove(b->wp, s->processed->rp, n);
		memmove(b->wp, s.s->processed->rp, n);
		b->wp += n;
		s->processed->rp += n;
		s.s->processed->rp += n;
	} else 
		s->processed = b->next;
		s.s->processed = b->next;

	qunlock(&s->in);
	qunlock(&s.s->in.q);
	poperror();

	return b;


@@ 276,23 279,23 @@ sslbread(Chan *c, long n, ulong offset)
long
sslread(Chan *c, void *a, long n, ulong offset)
{
	Block *b;
	volatile struct { Block *b; } b;

	switch(c->qid.path & ~CHDIR){
	case Qdir:
		return devdirread(c, a, n, digesttab, Ndigesttab, devgen);
	}

	b = sslbread(c, n, offset);
	b.b = sslbread(c, n, offset);

	if(waserror()){
		freeb(b);
		freeb(b.b);
		nexterror();
	}

	n = BLEN(b);
	memmove(a, b->rp, n);
	freeb(b);
	n = BLEN(b.b);
	memmove(a, b.b->rp, n);
	freeb(b.b);

	poperror();



@@ 305,41 308,43 @@ sslread(Chan *c, void *a, long n, ulong offset)
long
sslbwrite(Chan *c, Block *b, ulong offset)
{
	Dstate *s;
	volatile struct { Dstate *s; } s;
	volatile struct { Block *b; } bb;
	Block *nb;
	int h, n, m, pad, rv;
	uchar *p;

	s = c->aux;
	if(s == 0 || s->state != Established)
	bb.b = b;
	s.s = c->aux;
	if(s.s == 0 || s.s->state != Established)
		error(Ebadusefd);

	if(waserror()){
		qunlock(&s->out);
		if(b)
			freeb(b);
		dighangup(s);
		qunlock(&s.s->out.q);
		if(bb.b)
			freeb(bb.b);
		dighangup(s.s);
		nexterror();
	}
	qlock(&s->out);
	qlock(&s.s->out.q);

	rv = 0;
	while(b){
		m = n = BLEN(b);
		h = s->diglen + 2;
	while(bb.b){
		m = n = BLEN(bb.b);
		h = s.s->diglen + 2;

		/* trim to maximum block size */
		pad = 0;
		if(m > s->max){
			m = s->max;
		} else if(s->blocklen != 1){
			pad = m%s->blocklen;
		if(m > s.s->max){
			m = s.s->max;
		} else if(s.s->blocklen != 1){
			pad = m%s.s->blocklen;
			if(pad){
				if(m > s->maxpad){
				if(m > s.s->maxpad){
					pad = 0;
					m = s->maxpad;
					m = s.s->maxpad;
				} else {
					pad = s->blocklen - pad;
					pad = s.s->blocklen - pad;
					h++;
				}
			}


@@ 348,16 353,15 @@ sslbwrite(Chan *c, Block *b, ulong offset)
		rv += m;
		if(m != n){
			nb = allocb(m + h + pad);
			memmove(nb->wp + h, b->rp, m);
			memmove(nb->wp + h, bb.b->rp, m);
			nb->wp += m + h;
			b->rp += m;
			bb.b->rp += m;
		} else {
			/* add header space */
			nb = padblock(b, h);
			nb->rp -= h;
			b = 0;
			nb = padblock(bb.b, h);
			bb.b = 0;
		}
		m += s->diglen;
		m += s.s->diglen;

		/* SSL style count */
		if(pad){


@@ 378,15 382,15 @@ sslbwrite(Chan *c, Block *b, ulong offset)
			offset = 2;
		}

		if(s->encryptalg)
			nb = encryptb(s, nb, offset);
		if(s.s->encryptalg)
			nb = encryptb(s.s, nb, offset);
		else
			nb = digestb(s, nb, offset);
			nb = digestb(s.s, nb, offset);

		(*devtab[s->c->type].bwrite)(s->c, nb, offset);
		(*devtab[s.s->c->type].bwrite)(s.s->c, nb, offset);

	}
	qunlock(&s->out);
	qunlock(&s.s->out.q);
	poperror();

	return rv;


@@ 396,7 400,7 @@ long
sslwrite(Chan *c, void *a, long n, ulong offset)
{
	Dstate *s;
	Block *b;
	volatile struct { Block *b; } b;
	int m;
	char *p, *e, buf[32];



@@ 465,16 469,16 @@ sslwrite(Chan *c, void *a, long n, ulong offset)
			if(m > s->max)
				m = s->max;
	
			b = allocb(m);
			b.b = allocb(m);
			if(waserror()){
				freeb(b);
				freeb(b.b);
				nexterror();
			}
			memmove(b->wp, p, m);
			memmove(b.b->wp, p, m);
			poperror();
			b->wp += m;
			b.b->wp += m;
	
			sslbwrite(c, b, offset);
			sslbwrite(c, b.b, offset);
		}
		break;
	default:


@@ 544,7 548,7 @@ consume(Block **l, uchar *p, int n)
static void
setsecret(Dstate *s, OneWay *w, uchar *secret, int n)
{
	w->secret = smalloc(n);
	w->secret = malloc(n);
	memmove(w->secret, secret, n);
	w->slen = n;
	w->mid = 0;


@@ 553,13 557,13 @@ setsecret(Dstate *s, OneWay *w, uchar *secret, int n)
	case DESECB:
		if(n < 8)
			error("secret too small");
		w->state = smalloc(sizeof(DESstate));
		w->state = malloc(sizeof(DESstate));
		setupDESstate(w->state, secret, 0);
		break;
	case DESCBC:
		if(n < 16)
			error("secret too small");
		w->state = smalloc(sizeof(DESstate));
		w->state = malloc(sizeof(DESstate));
		setupDESstate(w->state, secret, secret+8);
		break;
	}


@@ 714,7 718,7 @@ dighangup(Dstate *s)
{
	Block *b;

	qlock(&s->in);
	qlock(&s->in.q);
	for(b = s->processed; b; b = s->processed){
		s->processed = b->next;
		freeb(b);


@@ 724,7 728,7 @@ dighangup(Dstate *s)
		s->unprocessed = 0;
	}
	s->state = Closed;
	qunlock(&s->in);
	qunlock(&s->in.q);
}

/*


@@ 735,9 739,9 @@ void
handle_exception(int type, char *exception)
{
	if(type == CRITICAL)
		panic("kernel ssl: %s", exception);
		panic("crypt library (devssl): %s", exception);
	else
		print("kernel ssl: %s\n", exception);
		print("crypt library (devssl): %s\n", exception);
}

void*


@@ 745,7 749,7 @@ crypt_malloc(int size)
{
	void *x;

	x = smalloc(size);
	x = malloc(size);
	if(x == 0)
		handle_exception(CRITICAL, "out of memory");
	return x;


@@ 758,4 762,3 @@ crypt_free(void *x)
		handle_exception(CRITICAL, "freeing null pointer");
	free(x);
}


D port/net.c => port/net.c +0 -320
@@ 1,320 0,0 @@
#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, int i, Dir *dp)
{
	Qid q;
	char buf[32];
	Network *np = vp;
	int t;
	Netprot *p;
	int perm;
	char *o;

	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 = NETTYPE(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|NETQID(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, NETID(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 = NETQID(NETID(c->qid.path), Ndataqid);
		devdir(c, q, "data", 0, o, perm, dp);
		break;
	case 1:
		q.path = NETQID(NETID(c->qid.path), Nctlqid);
		devdir(c, q, "ctl", 0, o, perm, dp);
		break;
	case 2:
		if(np->listen == 0)
			return 0;
		q.path = NETQID(NETID(c->qid.path), Qlisten);
		devdir(c, q, "listen", 0, o, perm, dp);
		break;
	default:
		i -= 3;
		if(i >= np->ninfo)
			return -1;
		q.path = NETQID(NETID(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(NETTYPE(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)
{
	int i;
	Dir dir;

	for(i=0;; i++)
		switch(netgen(c, (Dirtab*)np, 0, i, &dir)){
		case -1:
		/*
		 * devices with interesting directories usually don't get
		 * here, which is good because we've lost the name by now.
		 */
			if(c->qid.path & CHDIR){
				devdir(c, c->qid, c->path->elem, 0L, eve, CHDIR|0555, &dir);
				convD2M(&dir, db);
				return;
			}
			print("netstat %C %lux\n", devchar[c->type], c->qid.path);
			error(Enonexist);
		case 0:
			break;
		case 1:
			if(eqqid(c->qid, dir.qid)){
				if(c->flag&CMSG)
					dir.mode |= CHMOUNT;
				convD2M(&dir, db);
				return;
			}
			break;
		}
}

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(NETTYPE(c->qid.path)){
		case Ndataqid:
		case Nctlqid:
			id = NETID(c->qid.path);
			id = (*np->open)(c, id);
			break;
		case Qlisten:
			id = (*np->listen)(c);
			c->qid.path = NETQID(id, Nctlqid);
			ptclone(c, 1, id);
			break;
		case Qclone:
			id = (*np->open)(c, -1);
			c->qid.path = NETQID(id, Nctlqid);
			ptclone(c, 0, id);
			break;
		default:
			if(omode != OREAD)
				error(Ebadarg);
		}
		switch(NETTYPE(c->qid.path)){
		case Ndataqid:
		case Nctlqid:
			p = findprot(np, id);
			if(netown(p, up->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->qid.path&CHDIR)
		return devdirread(c, a, n, (Dirtab*)np, 0, netgen);

	t = NETTYPE(c->qid.path);
	if(t == Nctlqid)
		readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);

	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;
	p->net = np;

	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, NETID(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, up->user, NAMELEN) != 0 && up->scallnr != FWSTAT){
		unlock(np);
		error(Eperm);
	}
	convM2D(db, &dir);
	strncpy(p->owner, dir.uid, NAMELEN);
	p->mode = dir.mode;

	unlock(np);
}