plan 9 kernel history: overview | file list | diff list

2002/0109/port/devssl.c (diff list | history)

2002/0109/sys/src/9/port/devssl.c:1,14872002/0306/sys/src/9/port/devssl.c:1,1488 (short | long | prev | next)
1995/1213    
/* 
1996/0531    
 *  devssl - secure sockets layer emulation 
2002/0306    
 *  devssl - secure sockets layer 
1995/1213    
 */ 
1997/0618    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
1995/1213    
 
2000/0112    
#include	<libsec.h> 
1995/1213    
 
1998/0806    
#define NOSPOOKS 1 
 
1995/1213    
typedef struct OneWay OneWay; 
struct OneWay 
{ 
1996/0531    
	QLock	q; 
1996/1029    
	QLock	ctlq; 
1995/1213    
 
1996/0531    
	void	*state;		/* encryption state */ 
	int	slen;		/* hash data length */ 
	uchar	*secret;	/* secret */ 
	ulong	mid;		/* message id */ 
1995/1213    
}; 
 
enum 
{ 
	/* connection states */ 
1996/1029    
	Sincomplete=	0, 
1997/0618    
	Sclear=		1, 
	Sencrypting=	2, 
	Sdigesting=	4, 
	Sdigenc=	Sencrypting|Sdigesting, 
1995/1213    
 
	/* encryption algorithms */ 
1995/1218    
	Noencryption=	0, 
1995/1213    
	DESCBC=		1, 
1996/1029    
	DESECB=		2, 
	RC4=		3 
1995/1213    
}; 
 
typedef struct Dstate Dstate; 
struct Dstate 
{ 
	Chan	*c;		/* io channel */ 
	uchar	state;		/* state of connection */ 
1996/1029    
	int	ref;		/* serialized by dslock for atomic destroy */ 
 
1995/1213    
	uchar	encryptalg;	/* encryption algorithm */ 
1995/1218    
	ushort	blocklen;	/* blocking length */ 
1995/1213    
 
	ushort	diglen;		/* length of digest */ 
	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */ 
 
1995/1218    
	/* for SSL format */ 
1995/1213    
	int	max;		/* maximum unpadded data per msg */ 
1995/1217    
	int	maxpad;		/* maximum padded data per msg */ 
1995/1213    
 
	/* input side */ 
	OneWay	in; 
	Block	*processed; 
	Block	*unprocessed; 
 
	/* output side */ 
	OneWay	out; 
1996/1029    
 
	/* protections */ 
2001/0527    
	char	*user; 
1996/1029    
	int	perm; 
1995/1213    
}; 
 
enum 
{ 
1996/1029    
	Maxdmsg=	1<<16, 
2001/0823    
	Maxdstate=	128,	/* must be a power of 2 */ 
1995/1213    
}; 
 
2001/0823    
Lock	dslock; 
int	dshiwat; 
char	*dsname[Maxdstate]; 
Dstate	*dstate[Maxdstate]; 
char	*encalgs; 
char	*hashalgs; 
 
1995/1213    
enum{ 
1996/1029    
	Qtopdir		= 1,	/* top level directory */ 
1998/0417    
	Qprotodir, 
1996/1029    
	Qclonus, 
	Qconvdir,		/* directory for a conversation */ 
	Qdata, 
	Qctl, 
	Qsecretin, 
1998/0417    
	Qsecretout, 
	Qencalgs, 
	Qhashalgs, 
1995/1213    
}; 
 
1996/1029    
#define TYPE(x) 	((x).path & 0xf) 
2000/0325    
#define CONV(x) 	(((x).path >> 5)&(Maxdstate-1)) 
#define QID(c, y) 	(((c)<<5) | (y)) 
1995/1213    
 
1995/1217    
static void	ensure(Dstate*, Block**, int); 
static void	consume(Block**, uchar*, int); 
1996/1029    
static void	setsecret(OneWay*, uchar*, int); 
1995/1217    
static Block*	encryptb(Dstate*, Block*, int); 
static Block*	decryptb(Dstate*, Block*); 
static Block*	digestb(Dstate*, Block*, int); 
static void	checkdigestb(Dstate*, Block*); 
1996/1029    
static Chan*	buftochan(char*); 
static void	sslhangup(Dstate*); 
static Dstate*	dsclone(Chan *c); 
static void	dsnew(Chan *c, Dstate **); 
1995/1217    
 
2000/0325    
char *sslnames[] = { 
[Qclonus]	"clone", 
[Qdata]		"data", 
[Qctl]		"ctl", 
[Qsecretin]	"secretin", 
[Qsecretout]	"secretout", 
[Qencalgs]	"encalgs", 
[Qhashalgs]	"hashalgs", 
}; 
 
1997/0327    
static int 
2001/0527    
sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp) 
1996/1029    
{ 
	Qid q; 
	Dstate *ds; 
	char name[16], *p, *nm; 
2001/0527    
	int ft; 
1996/1029    
 
	USED(nd); 
	USED(d); 
2001/0527    
 
	q.type = QTFILE; 
1996/1029    
	q.vers = 0; 
2001/0527    
 
	ft = TYPE(c->qid); 
	switch(ft) { 
1996/1029    
	case Qtopdir: 
1999/1230    
		if(s == DEVDOTDOT){ 
2001/0527    
			q.path = QID(0, Qtopdir); 
			q.type = QTDIR; 
			devdir(c, q, "#D", 0, eve, 0555, dp); 
1999/1230    
			return 1; 
		} 
1998/0417    
		if(s > 0) 
			return -1; 
2001/0527    
		q.path = QID(0, Qprotodir); 
		q.type = QTDIR; 
		devdir(c, q, "ssl", 0, eve, 0555, dp); 
1998/0417    
		return 1; 
	case Qprotodir: 
1999/1230    
		if(s == DEVDOTDOT){ 
2001/0527    
			q.path = QID(0, Qtopdir); 
			q.type = QTDIR; 
			devdir(c, q, ".", 0, eve, 0555, dp); 
1999/1230    
			return 1; 
		} 
1996/1029    
		if(s < dshiwat) { 
2001/0527    
			q.path = QID(s, Qconvdir); 
			q.type = QTDIR; 
1996/1029    
			ds = dstate[s]; 
			if(ds != 0) 
				nm = ds->user; 
			else 
				nm = eve; 
2001/0527    
			if(dsname[s] == nil){ 
				sprint(name, "%d", s); 
				kstrdup(&dsname[s], name); 
			} 
			devdir(c, q, dsname[s], 0, nm, 0555, dp); 
1996/1029    
			return 1; 
		} 
		if(s > dshiwat) 
			return -1; 
		q.path = QID(0, Qclonus); 
		devdir(c, q, "clone", 0, eve, 0555, dp); 
		return 1; 
	case Qconvdir: 
1999/1230    
		if(s == DEVDOTDOT){ 
2001/0527    
			q.path = QID(0, Qprotodir); 
			q.type = QTDIR; 
			devdir(c, q, "ssl", 0, eve, 0555, dp); 
1999/1230    
			return 1; 
		} 
1996/1029    
		ds = dstate[CONV(c->qid)]; 
		if(ds != 0) 
			nm = ds->user; 
		else 
			nm = eve; 
		switch(s) { 
		default: 
			return -1; 
		case 0: 
			q.path = QID(CONV(c->qid), Qctl); 
			p = "ctl"; 
			break; 
		case 1: 
			q.path = QID(CONV(c->qid), Qdata); 
			p = "data"; 
			break; 
		case 2: 
			q.path = QID(CONV(c->qid), Qsecretin); 
			p = "secretin"; 
			break; 
		case 3: 
			q.path = QID(CONV(c->qid), Qsecretout); 
			p = "secretout"; 
			break; 
1998/0417    
		case 4: 
			q.path = QID(CONV(c->qid), Qencalgs); 
			p = "encalgs"; 
			break; 
		case 5: 
			q.path = QID(CONV(c->qid), Qhashalgs); 
			p = "hashalgs"; 
			break; 
1996/1029    
		} 
		devdir(c, q, p, 0, nm, 0660, dp); 
2000/0325    
		return 1; 
	case Qclonus: 
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp); 
		return 1; 
	default: 
		ds = dstate[CONV(c->qid)]; 
2001/0527    
		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, ds->user, 0660, dp); 
1996/1029    
		return 1; 
	} 
	return -1; 
} 
 
1997/0327    
static Chan* 
1999/0320    
sslattach(char *spec) 
1995/1213    
{ 
1996/1029    
	Chan *c; 
 
	c = devattach('D', spec); 
2001/0527    
	c->qid.path = QID(0, Qtopdir); 
1996/1029    
	c->qid.vers = 0; 
2001/0527    
	c->qid.type = QTDIR; 
1996/1029    
	return c; 
1995/1213    
} 
 
2001/0527    
static Walkqid* 
sslwalk(Chan *c, Chan *nc, char **name, int nname) 
1995/1213    
{ 
2001/0527    
	return devwalk(c, nc, name, nname, nil, 0, sslgen); 
1995/1213    
} 
 
2001/0527    
static int 
sslstat(Chan *c, uchar *db, int n) 
1995/1213    
{ 
2001/0527    
	return devstat(c, db, n, nil, 0, sslgen); 
1995/1213    
} 
 
1997/0327    
static Chan* 
1995/1213    
sslopen(Chan *c, int omode) 
{ 
1996/1029    
	Dstate *s, **pp; 
	int perm; 
2001/0527    
	int ft; 
1995/1213    
 
1996/1029    
	perm = 0; 
	omode &= 3; 
	switch(omode) { 
	case OREAD: 
		perm = 4; 
1995/1213    
		break; 
1996/1029    
	case OWRITE: 
		perm = 2; 
		break; 
	case ORDWR: 
		perm = 6; 
		break; 
1995/1213    
	} 
1996/1029    
 
2001/0527    
	ft = TYPE(c->qid); 
	switch(ft) { 
1996/1029    
	default: 
		panic("sslopen"); 
	case Qtopdir: 
1998/0417    
	case Qprotodir: 
1996/1029    
	case Qconvdir: 
		if(omode != OREAD) 
			error(Eperm); 
		break; 
	case Qclonus: 
		s = dsclone(c); 
		if(s == 0) 
			error(Enodev); 
		break; 
	case Qctl: 
	case Qdata: 
	case Qsecretin: 
	case Qsecretout: 
		if(waserror()) { 
			unlock(&dslock); 
			nexterror(); 
		} 
		lock(&dslock); 
		pp = &dstate[CONV(c->qid)]; 
		s = *pp; 
		if(s == 0) 
			dsnew(c, pp); 
		else { 
			if((perm & (s->perm>>6)) != perm 
			   && (strcmp(up->user, s->user) != 0 
			     || (perm & s->perm) != perm)) 
				error(Eperm); 
 
			s->ref++; 
		} 
		unlock(&dslock); 
		poperror(); 
		break; 
1998/0417    
	case Qencalgs: 
	case Qhashalgs: 
		if(omode != OREAD) 
			error(Eperm); 
		break; 
1996/1029    
	} 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
1995/1213    
} 
 
2001/0527    
static int 
sslwstat(Chan *c, uchar *db, int n) 
1995/1213    
{ 
2001/0527    
	Dir *dir; 
1996/1029    
	Dstate *s; 
2001/0527    
	int m; 
1996/1029    
 
	s = dstate[CONV(c->qid)]; 
	if(s == 0) 
		error(Ebadusefd); 
	if(strcmp(s->user, up->user) != 0) 
		error(Eperm); 
 
2001/0527    
	dir = smalloc(sizeof(Dir)+n); 
	m = convM2D(db, n, &dir[0], (char*)&dir[1]); 
2001/1106    
	if(m == 0){ 
		free(dir); 
		error(Eshortstat); 
	} 
 
	if(!emptystr(dir->uid)) 
2001/0527    
		kstrdup(&s->user, dir->uid); 
2001/1106    
	if(dir->mode != ~0UL) 
2001/0527    
		s->perm = dir->mode; 
2001/1106    
 
2001/0527    
	free(dir); 
	return m; 
1995/1213    
} 
 
1997/0327    
static void 
1995/1213    
sslclose(Chan *c) 
{ 
	Dstate *s; 
2001/0527    
	int ft; 
1995/1213    
 
2001/0527    
	ft = TYPE(c->qid); 
	switch(ft) { 
1996/1029    
	case Qctl: 
	case Qdata: 
	case Qsecretin: 
	case Qsecretout: 
		if((c->flag & COPEN) == 0) 
			break; 
 
		s = dstate[CONV(c->qid)]; 
		if(s == 0) 
			break; 
 
		lock(&dslock); 
		if(--s->ref > 0) { 
			unlock(&dslock); 
			break; 
		} 
		dstate[CONV(c->qid)] = 0; 
		unlock(&dslock); 
 
2001/0527    
		if(s->user != nil) 
			free(s->user); 
1996/1029    
		sslhangup(s); 
1995/1213    
		if(s->c) 
1997/0327    
			cclose(s->c); 
1995/1213    
		if(s->in.secret) 
			free(s->in.secret); 
		if(s->out.secret) 
			free(s->out.secret); 
1996/1029    
		if(s->in.state) 
			free(s->in.state); 
		if(s->out.state) 
			free(s->out.state); 
1995/1213    
		free(s); 
1996/1029    
 
1995/1213    
	} 
} 
 
1996/1029    
/* 
 *  make sure we have at least 'n' bytes in list 'l' 
 */ 
static void 
ensure(Dstate *s, Block **l, int n) 
{ 
	int sofar, i; 
	Block *b, *bl; 
 
	sofar = 0; 
	for(b = *l; b; b = b->next){ 
		sofar += BLEN(b); 
		if(sofar >= n) 
			return; 
		l = &b->next; 
	} 
 
	while(sofar < n){ 
1997/0327    
		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0); 
1996/1029    
		if(bl == 0) 
2001/0825    
			nexterror(); 
1996/1029    
		*l = bl; 
		i = 0; 
		for(b = bl; b; b = b->next){ 
			i += BLEN(b); 
			l = &b->next; 
		} 
		if(i == 0) 
			error(Ehungup); 
		sofar += i; 
	} 
} 
 
/* 
 *  copy 'n' bytes from 'l' into 'p' and free 
 *  the bytes in 'l' 
 */ 
static void 
consume(Block **l, uchar *p, int n) 
{ 
	Block *b; 
	int i; 
 
	for(; *l && n > 0; n -= i){ 
		b = *l; 
		i = BLEN(b); 
		if(i > n) 
			i = n; 
		memmove(p, b->rp, i); 
		b->rp += i; 
		p += i; 
		if(BLEN(b) < 0) 
			panic("consume"); 
		if(BLEN(b)) 
			break; 
		*l = b->next; 
		freeb(b); 
	} 
} 
 
/* 
2000/0913    
 *  give back n bytes 
static void 
regurgitate(Dstate *s, uchar *p, int n) 
{ 
	Block *b; 
 
	if(n <= 0) 
		return; 
	b = s->unprocessed; 
	if(s->unprocessed == nil || b->rp - b->base < n) { 
		b = allocb(n); 
2000/0914    
		memmove(b->wp, p, n); 
2000/0913    
		b->wp += n; 
		b->next = s->unprocessed; 
		s->unprocessed = b; 
	} else { 
		b->rp -= n; 
2000/0914    
		memmove(b->rp, p, n); 
2000/0913    
	} 
} 
2001/0825    
 */ 
2000/0913    
 
/* 
1996/1029    
 *  remove at most n bytes from the queue, if discard is set 
 *  dump the remainder 
 */ 
static Block* 
2001/0602    
qtake(Block **l, int n, int discard) 
1996/1029    
{ 
	Block *nb, *b, *first; 
	int i; 
 
	first = *l; 
	for(b = first; b; b = b->next){ 
		i = BLEN(b); 
		if(i == n){ 
			if(discard){ 
				freeblist(b->next); 
				*l = 0; 
			} else 
				*l = b->next; 
			b->next = 0; 
1999/0302    
			return first; 
1996/1029    
		} else if(i > n){ 
			i -= n; 
			if(discard){ 
				freeblist(b->next); 
				b->wp -= i; 
				*l = 0; 
			} else { 
				nb = allocb(i); 
				memmove(nb->wp, b->rp+n, i); 
				nb->wp += i; 
				b->wp -= i; 
				nb->next = b->next; 
				*l = nb; 
			} 
			b->next = 0; 
			if(BLEN(b) < 0) 
2001/0602    
				panic("qtake"); 
1996/1029    
			return first; 
		} else 
			n -= i; 
		if(BLEN(b) < 0) 
2001/0602    
			panic("qtake"); 
1996/1029    
	} 
	*l = 0; 
	return first; 
} 
 
2000/0913    
/* 
2001/0527    
 *  We can't let Eintr's lose data since the program 
 *  doing the read may be able to handle it.  The only 
 *  places Eintr is possible is during the read's in consume. 
 *  Therefore, we make sure we can always put back the bytes 
 *  consumed before the last ensure. 
2000/0913    
 */ 
1997/0327    
static Block* 
1998/0327    
sslbread(Chan *c, long n, ulong) 
1995/1213    
{ 
1996/0531    
	volatile struct { Dstate *s; } s; 
1995/1218    
	Block *b; 
2001/0825    
	uchar consumed[3], *p; 
	int toconsume; 
1996/1029    
	int len, pad; 
1995/1217    
 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslbread"); 
	if(s.s->state == Sincomplete) 
1995/1217    
		error(Ebadusefd); 
 
2001/0825    
	qlock(&s.s->in.q); 
1995/1217    
	if(waserror()){ 
1996/0531    
		qunlock(&s.s->in.q); 
1995/1217    
		nexterror(); 
1995/1213    
	} 
1995/1217    
 
1996/1029    
	if(s.s->processed == 0){ 
2001/0825    
		/* 
		 * Read in the whole message.  Until we've got it all, 
		 * it stays on s.s->unprocessed, so that if we get Eintr, 
		 * we'll pick up where we left off. 
		 */ 
		ensure(s.s, &s.s->unprocessed, 3); 
		s.s->unprocessed = pullupblock(s.s->unprocessed, 2); 
		p = s.s->unprocessed->rp; 
		if(p[0] & 0x80){ 
			len = ((p[0] & 0x7f)<<8) | p[1]; 
1996/1029    
			ensure(s.s, &s.s->unprocessed, len); 
1995/1217    
			pad = 0; 
2001/0825    
			toconsume = 2; 
1995/1217    
		} else { 
2002/0306    
			s.s->unprocessed = pullupblock(s.s->unprocessed, 3); 
2001/0825    
			len = ((p[0] & 0x3f)<<8) | p[1]; 
			pad = p[2]; 
1996/1029    
			if(pad > len){ 
				print("pad %d buf len %d\n", pad, len); 
				error("bad pad in ssl message"); 
			} 
2001/0825    
			toconsume = 3; 
1995/1217    
		} 
2001/0825    
		ensure(s.s, &s.s->unprocessed, toconsume+len+pad); 
2002/0306    
		ensure(s.s, &s.s->unprocessed, toconsume+len); 
1995/1217    
 
2001/0825    
		/* 
		 * Now we have a full SSL packet in the unprocessed list. 
		 * Start processing.  We can't get Eintr's here. 
		 * The only cause for errors from here until the end of the 
		 * loop is allocation failures in the block manipulation. 
		 * We'll worry about that when we come across it. 
2000/0913    
		 */ 
1995/1217    
 
2001/0825    
		if(waserror()){ 
			print("devssl: unhandled allocation failure\n"); 
			nexterror(); 
		} 
 
		/* skip header */ 
		consume(&s.s->unprocessed, consumed, toconsume); 
 
2000/0913    
		/* grab the next message and decode/decrypt it */ 
2001/0825    
		b = qtake(&s.s->unprocessed, len+pad, 0); 
2002/0306    
		b = qtake(&s.s->unprocessed, len, 0); 
2000/0913    
 
2001/0825    
		if(blocklen(b) != len+pad) 
2002/0306    
		if(blocklen(b) != len) 
2001/0825    
			print("devssl: sslbread got wrong count %d != %d", blocklen(b), len); 
 
1996/1029    
		if(waserror()){ 
			qunlock(&s.s->in.ctlq); 
2000/0913    
			if(b != nil) 
				freeb(b); 
1996/1029    
			nexterror(); 
1995/1217    
		} 
1996/1029    
		qlock(&s.s->in.ctlq); 
		switch(s.s->state){ 
		case Sencrypting: 
2001/0825    
			if(b == nil) 
				error("ssl message too short (encrypting)"); 
2000/0913    
			b = decryptb(s.s, b); 
1996/1029    
			break; 
		case Sdigesting: 
2000/0913    
			b = pullupblock(b, s.s->diglen); 
			if(b == nil) 
2001/0825    
				error("ssl message too short (digesting)"); 
2000/0913    
			checkdigestb(s.s, b); 
			b->rp += s.s->diglen; 
1996/1029    
			break; 
1997/0618    
		case Sdigenc: 
2000/0913    
			b = decryptb(s.s, b); 
			b = pullupblock(b, s.s->diglen); 
			if(b == nil) 
2001/0825    
				error("ssl message too short (dig+enc)"); 
2000/0913    
			checkdigestb(s.s, b); 
			b->rp += s.s->diglen; 
1998/0501    
			len -= s.s->diglen; 
1997/0618    
			break; 
1995/1218    
		} 
1995/1217    
 
		/* remove pad */ 
1996/1029    
		if(pad) 
2001/0602    
			s.s->processed = qtake(&b, len - pad, 1); 
2000/0913    
		else 
			s.s->processed = b; 
		b = nil; 
		s.s->in.mid++; 
		qunlock(&s.s->in.ctlq); 
		poperror(); 
2001/0825    
		poperror(); 
1995/1217    
	} 
 
1996/1029    
	/* return at most what was asked for */ 
2001/0602    
	b = qtake(&s.s->processed, n, 0); 
1995/1217    
 
1996/0531    
	qunlock(&s.s->in.q); 
1995/1217    
	poperror(); 
 
	return b; 
1995/1213    
} 
 
1997/0327    
static long 
1998/0319    
sslread(Chan *c, void *a, long n, vlong off) 
1995/1213    
{ 
1996/0531    
	volatile struct { Block *b; } b; 
1996/1029    
	Block *nb; 
	uchar *va; 
	int i; 
	char buf[128]; 
1998/0319    
	ulong offset = off; 
2001/0527    
	int ft; 
1995/1213    
 
2001/0527    
	if(c->qid.type & QTDIR) 
1996/1029    
		return devdirread(c, a, n, 0, 0, sslgen); 
 
2001/0527    
	ft = TYPE(c->qid); 
	switch(ft) { 
1996/1029    
	default: 
		error(Ebadusefd); 
	case Qctl: 
2001/0527    
		ft = CONV(c->qid); 
		sprint(buf, "%d", ft); 
1996/1029    
		return readstr(offset, a, n, buf); 
	case Qdata: 
		b.b = sslbread(c, n, offset); 
		break; 
1998/0417    
	case Qencalgs: 
		return readstr(offset, a, n, encalgs); 
2001/0527    
		break; 
1998/0417    
	case Qhashalgs: 
		return readstr(offset, a, n, hashalgs); 
2001/0527    
		break; 
1995/1213    
	} 
 
1996/0223    
	if(waserror()){ 
1996/1029    
		freeblist(b.b); 
1996/0223    
		nexterror(); 
1995/1213    
	} 
 
1996/1029    
	n = 0; 
	va = a; 
	for(nb = b.b; nb; nb = nb->next){ 
		i = BLEN(nb); 
		memmove(va+n, nb->rp, i); 
		n += i; 
	} 
1996/0223    
 
1996/1029    
	freeblist(b.b); 
1996/0223    
	poperror(); 
 
1995/1213    
	return n; 
} 
 
1995/1215    
/* 
1996/1029    
 *  this algorithm doesn't have to be great since we're just 
 *  trying to obscure the block fill 
 */ 
static void 
randfill(uchar *buf, int len) 
{ 
1997/0618    
	while(len-- > 0) 
		*buf++ = nrand(256); 
1996/1029    
} 
 
/* 
2000/0913    
 *  use SSL record format, add in count, digest and/or encrypt. 
 *  the write is interruptable.  if it is interrupted, we'll 
 *  get out of sync with the far side.  not much we can do about 
 *  it since we don't know if any bytes have been written. 
1995/1215    
 */ 
1997/0327    
static long 
1995/1215    
sslbwrite(Chan *c, Block *b, ulong offset) 
1995/1213    
{ 
1996/0531    
	volatile struct { Dstate *s; } s; 
	volatile struct { Block *b; } bb; 
1995/1213    
	Block *nb; 
1995/1215    
	int h, n, m, pad, rv; 
1995/1217    
	uchar *p; 
1995/1215    
 
1996/0531    
	bb.b = b; 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslbwrite"); 
	if(s.s->state == Sincomplete){ 
		freeb(b); 
1995/1215    
		error(Ebadusefd); 
1996/1029    
	} 
1995/1215    
 
	if(waserror()){ 
1996/0531    
		qunlock(&s.s->out.q); 
2000/0913    
		if(bb.b != nil) 
1996/0531    
			freeb(bb.b); 
1995/1215    
		nexterror(); 
	} 
1996/0531    
	qlock(&s.s->out.q); 
1995/1215    
 
	rv = 0; 
1996/0531    
	while(bb.b){ 
		m = n = BLEN(bb.b); 
		h = s.s->diglen + 2; 
1995/1215    
 
1995/1218    
		/* trim to maximum block size */ 
1995/1215    
		pad = 0; 
1996/0531    
		if(m > s.s->max){ 
			m = s.s->max; 
		} else if(s.s->blocklen != 1){ 
1998/0501    
			pad = (m + s.s->diglen)%s.s->blocklen; 
1995/1215    
			if(pad){ 
1996/0531    
				if(m > s.s->maxpad){ 
1995/1215    
					pad = 0; 
1996/0531    
					m = s.s->maxpad; 
1995/1218    
				} else { 
1996/0531    
					pad = s.s->blocklen - pad; 
1995/1218    
					h++; 
1995/1215    
				} 
			} 
		} 
 
		rv += m; 
		if(m != n){ 
			nb = allocb(m + h + pad); 
1996/0531    
			memmove(nb->wp + h, bb.b->rp, m); 
1995/1215    
			nb->wp += m + h; 
1996/0531    
			bb.b->rp += m; 
1995/1215    
		} else { 
1995/1218    
			/* add header space */ 
1996/0531    
			nb = padblock(bb.b, h); 
			bb.b = 0; 
1995/1215    
		} 
1996/0531    
		m += s.s->diglen; 
1995/1215    
 
		/* SSL style count */ 
		if(pad){ 
1995/1218    
			nb = padblock(nb, -pad); 
1996/1029    
			randfill(nb->wp, pad); 
1995/1227    
			nb->wp += pad; 
1995/1215    
			m += pad; 
1995/1218    
 
			p = nb->rp; 
1995/1217    
			p[0] = (m>>8); 
			p[1] = m; 
			p[2] = pad; 
			offset = 3; 
		} else { 
1995/1218    
			p = nb->rp; 
			p[0] = (m>>8) | 0x80; 
1995/1217    
			p[1] = m; 
			offset = 2; 
		} 
1995/1213    
 
1996/1029    
		switch(s.s->state){ 
		case Sencrypting: 
1996/0531    
			nb = encryptb(s.s, nb, offset); 
1996/1029    
			break; 
		case Sdigesting: 
1996/0531    
			nb = digestb(s.s, nb, offset); 
1996/1029    
			break; 
1997/0618    
		case Sdigenc: 
			nb = digestb(s.s, nb, offset); 
			nb = encryptb(s.s, nb, offset); 
			break; 
1996/1029    
		} 
1995/1213    
 
1997/0618    
		s.s->out.mid++; 
 
2001/0527    
		m = BLEN(nb); 
1997/0327    
		devtab[s.s->c->type]->bwrite(s.s->c, nb, s.s->c->offset); 
2001/0527    
		s.s->c->offset += m; 
1995/1215    
	} 
1996/0531    
	qunlock(&s.s->out.q); 
1995/1215    
	poperror(); 
 
	return rv; 
1996/0223    
} 
 
1996/1029    
static void 
setsecret(OneWay *w, uchar *secret, int n) 
{ 
	if(w->secret) 
		free(w->secret); 
 
1997/0618    
	w->secret = smalloc(n); 
1996/1029    
	memmove(w->secret, secret, n); 
	w->slen = n; 
} 
 
static void 
initDESkey(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
1997/0618    
	w->state = smalloc(sizeof(DESstate)); 
1996/1029    
	if(w->slen >= 16) 
		setupDESstate(w->state, w->secret, w->secret+8); 
	else if(w->slen >= 8) 
		setupDESstate(w->state, w->secret, 0); 
	else 
		error("secret too short"); 
} 
 
1998/0806    
/* 
 *  40 bit DES is the same as 56 bit DES.  However, 
 *  16 bits of the key are masked to zero. 
 */ 
1996/1029    
static void 
1998/0806    
initDESkey_40(OneWay *w) 
{ 
1999/0415    
	uchar key[8]; 
 
1998/0806    
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
1999/0415    
	if(w->slen >= 8){ 
		memmove(key, w->secret, 8); 
		key[0] &= 0x0f; 
		key[2] &= 0x0f; 
		key[4] &= 0x0f; 
		key[6] &= 0x0f; 
1998/0806    
	} 
 
	w->state = malloc(sizeof(DESstate)); 
	if(w->slen >= 16) 
1999/0415    
		setupDESstate(w->state, key, w->secret+8); 
1998/0806    
	else if(w->slen >= 8) 
1999/0415    
		setupDESstate(w->state, key, 0); 
1998/0806    
	else 
		error("secret too short"); 
} 
 
static void 
1996/1029    
initRC4key(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
1997/0618    
	w->state = smalloc(sizeof(RC4state)); 
1996/1029    
	setupRC4state(w->state, w->secret, w->slen); 
} 
 
1998/0806    
/* 
 *  40 bit RC4 is the same as n-bit RC4.  However, 
 *  we ignore all but the first 40 bits of the key. 
 */ 
static void 
initRC4key_40(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
	if(w->slen > 5) 
		w->slen = 5; 
 
	w->state = malloc(sizeof(RC4state)); 
	setupRC4state(w->state, w->secret, w->slen); 
} 
 
1998/0910    
/* 
 *  128 bit RC4 is the same as n-bit RC4.  However, 
 *  we ignore all but the first 128 bits of the key. 
 */ 
static void 
initRC4key_128(OneWay *w) 
{ 
	if(w->state){ 
		free(w->state); 
		w->state = 0; 
	} 
 
	if(w->slen > 16) 
		w->slen = 16; 
 
	w->state = malloc(sizeof(RC4state)); 
	setupRC4state(w->state, w->secret, w->slen); 
} 
 
 
1998/0806    
typedef struct Hashalg Hashalg; 
1997/0618    
struct Hashalg 
{ 
	char	*name; 
	int	diglen; 
	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); 
1998/0806    
}; 
 
Hashalg hashtab[] = 
1997/0618    
{ 
	{ "md4", MD4dlen, md4, }, 
	{ "md5", MD5dlen, md5, }, 
2000/0112    
	{ "sha1", SHA1dlen, sha1, }, 
2000/0204    
	{ "sha", SHA1dlen, sha1, }, 
1997/0618    
	{ 0 } 
}; 
 
static int 
parsehashalg(char *p, Dstate *s) 
{ 
1998/0806    
	Hashalg *ha; 
1997/0618    
 
	for(ha = hashtab; ha->name; ha++){ 
		if(strcmp(p, ha->name) == 0){ 
			s->hf = ha->hf; 
			s->diglen = ha->diglen; 
			s->state &= ~Sclear; 
			s->state |= Sdigesting; 
			return 0; 
		} 
	} 
	return -1; 
} 
 
1998/0806    
typedef struct Encalg Encalg; 
1997/0618    
struct Encalg 
{ 
	char	*name; 
	int	blocklen; 
	int	alg; 
	void	(*keyinit)(OneWay*); 
1998/0806    
}; 
 
#ifdef NOSPOOKS 
Encalg encrypttab[] = 
1997/0618    
{ 
1998/0910    
	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */ 
	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */ 
	{ "des_56_cbc", 8, DESCBC, initDESkey, }, 
	{ "des_56_ecb", 8, DESECB, initDESkey, }, 
	{ "des_40_cbc", 8, DESCBC, initDESkey_40, }, 
	{ "des_40_ecb", 8, DESECB, initDESkey_40, }, 
	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */ 
	{ "rc4_256", 1, RC4, initRC4key, }, 
	{ "rc4_128", 1, RC4, initRC4key_128, }, 
1998/0806    
	{ "rc4_40", 1, RC4, initRC4key_40, }, 
1997/0618    
	{ 0 } 
}; 
1998/0806    
#else 
Encalg encrypttab[] = 
{ 
1998/0910    
	{ "des_40_cbc", 8, DESCBC, initDESkey_40, }, 
	{ "des_40_ecb", 8, DESECB, initDESkey_40, }, 
	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */ 
1998/0806    
	{ "rc4_40", 1, RC4, initRC4key_40, }, 
	{ 0 } 
}; 
#endif NOSPOOKS 
1997/0618    
 
static int 
parseencryptalg(char *p, Dstate *s) 
{ 
1998/0806    
	Encalg *ea; 
1997/0618    
 
	for(ea = encrypttab; ea->name; ea++){ 
		if(strcmp(p, ea->name) == 0){ 
			s->encryptalg = ea->alg; 
			s->blocklen = ea->blocklen; 
			(*ea->keyinit)(&s->in); 
			(*ea->keyinit)(&s->out); 
			s->state &= ~Sclear; 
			s->state |= Sencrypting; 
			return 0; 
		} 
	} 
	return -1; 
} 
 
1997/0327    
static long 
1998/0319    
sslwrite(Chan *c, void *a, long n, vlong off) 
1996/0223    
{ 
1996/1029    
	volatile struct { Dstate *s; } s; 
1996/0531    
	volatile struct { Block *b; } b; 
1996/1029    
	int m, t; 
1999/0804    
	char *p, *np, *e, buf[128]; 
	uchar *x; 
1998/0319    
	ulong offset = off; 
1996/0223    
 
1996/1029    
	s.s = dstate[CONV(c->qid)]; 
	if(s.s == 0) 
		panic("sslwrite"); 
1996/0223    
 
1996/1029    
	t = TYPE(c->qid); 
	if(t == Qdata){ 
		if(s.s->state == Sincomplete) 
			error(Ebadusefd); 
1996/0223    
 
		p = a; 
1996/1029    
		e = p + n; 
		do { 
1996/0223    
			m = e - p; 
1996/1029    
			if(m > s.s->max) 
				m = s.s->max; 
1998/0512    
 
1996/0531    
			b.b = allocb(m); 
1996/0223    
			if(waserror()){ 
1996/0531    
				freeb(b.b); 
1996/0223    
				nexterror(); 
			} 
1996/0531    
			memmove(b.b->wp, p, m); 
1996/0223    
			poperror(); 
1996/0531    
			b.b->wp += m; 
1998/0512    
 
1996/0531    
			sslbwrite(c, b.b, offset); 
1996/1029    
 
			p += m; 
		} while(p < e); 
		return n; 
	} 
 
	/* mutex with operations using what we're about to change */ 
	if(waserror()){ 
		qunlock(&s.s->in.ctlq); 
		qunlock(&s.s->out.q); 
		nexterror(); 
	} 
	qlock(&s.s->in.ctlq); 
	qlock(&s.s->out.q); 
 
	switch(t){ 
1996/0223    
	default: 
1996/1029    
		panic("sslwrite"); 
	case Qsecretin: 
		setsecret(&s.s->in, a, n); 
		goto out; 
	case Qsecretout: 
		setsecret(&s.s->out, a, n); 
		goto out; 
	case Qctl: 
		break; 
1996/0223    
	} 
 
1996/1029    
	if(n >= sizeof(buf)) 
1999/0804    
		error("arg too long"); 
1996/1029    
	strncpy(buf, a, n); 
	buf[n] = 0; 
	p = strchr(buf, '\n'); 
	if(p) 
		*p = 0; 
	p = strchr(buf, ' '); 
	if(p) 
		*p++ = 0; 
1995/1213    
 
1996/1029    
	if(strcmp(buf, "fd") == 0){ 
		s.s->c = buftochan(p); 
1995/1213    
 
1996/1029    
		/* default is clear (msg delimiters only) */ 
		s.s->state = Sclear; 
		s.s->blocklen = 1; 
		s.s->diglen = 0; 
		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
1997/0618    
		s.s->in.mid = 0; 
		s.s->out.mid = 0; 
1996/1029    
	} else if(strcmp(buf, "alg") == 0 && p != 0){ 
		s.s->blocklen = 1; 
		s.s->diglen = 0; 
1995/1213    
 
1996/1029    
		if(s.s->c == 0) 
			error("must set fd before algorithm"); 
 
1999/0527    
		s.s->state = Sclear; 
		s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
1996/1029    
		if(strcmp(p, "clear") == 0){ 
			goto out; 
1995/1213    
		} 
 
1996/1029    
		if(s.s->in.secret && s.s->out.secret == 0) 
			setsecret(&s.s->out, s.s->in.secret, s.s->in.slen); 
		if(s.s->out.secret && s.s->in.secret == 0) 
			setsecret(&s.s->in, s.s->out.secret, s.s->out.slen); 
1997/0618    
		if(s.s->in.secret == 0 || s.s->out.secret == 0) 
			error("algorithm but no secret"); 
 
		s.s->hf = 0; 
		s.s->encryptalg = Noencryption; 
		s.s->blocklen = 1; 
 
		for(;;){ 
			np = strchr(p, ' '); 
			if(np) 
				*np++ = 0; 
 
			if(parsehashalg(p, s.s) < 0) 
			if(parseencryptalg(p, s.s) < 0) 
1999/0804    
				error("bad algorithm"); 
1997/0618    
 
			if(np == 0) 
				break; 
			p = np; 
		} 
 
		if(s.s->hf == 0 && s.s->encryptalg == Noencryption) 
1999/0804    
			error("bad algorithm"); 
1995/1213    
 
1996/1029    
		if(s.s->blocklen != 1){ 
			s.s->max = (1<<15) - s.s->diglen - 1; 
			s.s->max -= s.s->max % s.s->blocklen; 
			s.s->maxpad = (1<<14) - s.s->diglen - 1; 
			s.s->maxpad -= s.s->maxpad % s.s->blocklen; 
		} else 
			s.s->maxpad = s.s->max = (1<<15) - s.s->diglen - 1; 
1999/0804    
	} else if(strcmp(buf, "secretin") == 0 && p != 0) { 
		m = (strlen(p)*3)/2; 
		x = smalloc(m); 
		n = dec64(x, m, p, strlen(p)); 
		setsecret(&s.s->in, x, n); 
2002/0306    
		t = dec64(x, m, p, strlen(p)); 
		setsecret(&s.s->in, x, t); 
1999/0804    
		free(x); 
	} else if(strcmp(buf, "secretout") == 0 && p != 0) { 
		m = (strlen(p)*3)/2 + 1; 
		x = smalloc(m); 
		n = dec64(x, m, p, strlen(p)); 
		setsecret(&s.s->out, x, n); 
2002/0306    
		t = dec64(x, m, p, strlen(p)); 
		setsecret(&s.s->out, x, t); 
1999/0804    
		free(x); 
1996/1029    
	} else 
		error(Ebadarg); 
1995/1213    
 
1996/1029    
out: 
	qunlock(&s.s->in.ctlq); 
	qunlock(&s.s->out.q); 
	poperror(); 
	return n; 
1998/0417    
} 
 
static void 
sslinit(void) 
{ 
	struct Encalg *e; 
	struct Hashalg *h; 
	int n; 
	char *cp; 
 
	n = 1; 
	for(e = encrypttab; e->name != nil; e++) 
		n += strlen(e->name) + 1; 
	cp = encalgs = smalloc(n); 
	for(e = encrypttab;;){ 
		strcpy(cp, e->name); 
		cp += strlen(e->name); 
		e++; 
		if(e->name == nil) 
			break; 
		*cp++ = ' '; 
	} 
	*cp = 0; 
 
	n = 1; 
	for(h = hashtab; h->name != nil; h++) 
		n += strlen(h->name) + 1; 
	cp = hashalgs = smalloc(n); 
	for(h = hashtab;;){ 
		strcpy(cp, h->name); 
		cp += strlen(h->name); 
		h++; 
		if(h->name == nil) 
			break; 
		*cp++ = ' '; 
	} 
	*cp = 0; 
1995/1213    
} 
 
1997/0327    
Dev ssldevtab = { 
1997/0408    
	'D', 
	"ssl", 
 
1997/0327    
	devreset, 
	sslinit, 
2002/0109    
	devshutdown, 
1997/0327    
	sslattach, 
	sslwalk, 
	sslstat, 
	sslopen, 
	devcreate, 
	sslclose, 
	sslread, 
	sslbread, 
	sslwrite, 
	sslbwrite, 
	devremove, 
	sslwstat, 
}; 
1995/1213    
 
1995/1217    
static Block* 
encryptb(Dstate *s, Block *b, int offset) 
{ 
1995/1218    
	uchar *p, *ep, *p2, *ip, *eip; 
1995/1217    
	DESstate *ds; 
1995/1213    
 
1995/1217    
	switch(s->encryptalg){ 
1995/1218    
	case DESECB: 
1995/1217    
		ds = s->out.state; 
		ep = b->rp + BLEN(b); 
		for(p = b->rp + offset; p < ep; p += 8) 
			block_cipher(ds->expanded, p, 0); 
		break; 
	case DESCBC: 
		ds = s->out.state; 
		ep = b->rp + BLEN(b); 
1995/1218    
		for(p = b->rp + offset; p < ep; p += 8){ 
			p2 = p; 
			ip = ds->ivec; 
			for(eip = ip+8; ip < eip; ) 
				*p2++ ^= *ip++; 
			block_cipher(ds->expanded, p, 0); 
			memmove(ds->ivec, p, 8); 
		} 
1995/1217    
		break; 
1996/1029    
	case RC4: 
		rc4(s->out.state, b->rp + offset, BLEN(b) - offset); 
		break; 
1995/1213    
	} 
1995/1217    
	return b; 
} 
1995/1213    
 
1995/1217    
static Block* 
1999/0414    
decryptb(Dstate *s, Block *bin) 
1995/1217    
{ 
1996/1029    
	Block *b, **l; 
1995/1218    
	uchar *p, *ep, *tp, *ip, *eip; 
1995/1217    
	DESstate *ds; 
1995/1218    
	uchar tmp[8]; 
1996/1029    
	int i; 
1995/1213    
 
1999/0414    
	l = &bin; 
	for(b = bin; b; b = b->next){ 
1996/1029    
		/* make sure we have a multiple of s->blocklen */ 
		if(s->blocklen > 1){ 
			i = BLEN(b); 
			if(i % s->blocklen){ 
				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen)); 
				if(b == 0) 
					error("ssl encrypted message too short"); 
1995/1218    
			} 
		} 
1996/1029    
		l = &b->next; 
 
		/* decrypt */ 
		switch(s->encryptalg){ 
		case DESECB: 
			ds = s->in.state; 
			ep = b->rp + BLEN(b); 
1998/0501    
			for(p = b->rp; p < ep; p += 8) 
1996/1029    
				block_cipher(ds->expanded, p, 1); 
			break; 
		case DESCBC: 
			ds = s->in.state; 
			ep = b->rp + BLEN(b); 
1998/0501    
			for(p = b->rp; p < ep;){ 
1996/1029    
				memmove(tmp, p, 8); 
				block_cipher(ds->expanded, p, 1); 
				tp = tmp; 
				ip = ds->ivec; 
				for(eip = ip+8; ip < eip; ){ 
					*p++ ^= *ip; 
					*ip++ = *tp++; 
				} 
			} 
			break; 
		case RC4: 
			rc4(s->in.state, b->rp, BLEN(b)); 
			break; 
		} 
1995/1217    
	} 
1999/0414    
	return bin; 
1995/1213    
} 
 
1995/1217    
static Block* 
digestb(Dstate *s, Block *b, int offset) 
1995/1213    
{ 
1995/1215    
	uchar *p; 
	DigestState ss; 
	uchar msgid[4]; 
	ulong n, h; 
	OneWay *w; 
1995/1213    
 
1995/1215    
	w = &s->out; 
1995/1213    
 
1995/1215    
	memset(&ss, 0, sizeof(ss)); 
1995/1217    
	h = s->diglen + offset; 
1995/1215    
	n = BLEN(b) - h; 
1995/1213    
 
1995/1215    
	/* hash secret + message */ 
1997/0618    
	(*s->hf)(w->secret, w->slen, 0, &ss); 
	(*s->hf)(b->rp + h, n, 0, &ss); 
1995/1213    
 
1995/1215    
	/* hash message id */ 
	p = msgid; 
1997/0618    
	n = w->mid; 
1995/1215    
	*p++ = n>>24; 
	*p++ = n>>16; 
	*p++ = n>>8; 
	*p = n; 
1997/0618    
	(*s->hf)(msgid, 4, b->rp + offset, &ss); 
1995/1217    
 
1995/1218    
	return b; 
1995/1215    
} 
1995/1213    
 
1995/1217    
static void 
1999/0414    
checkdigestb(Dstate *s, Block *bin) 
1995/1215    
{ 
1995/1217    
	uchar *p; 
	DigestState ss; 
	uchar msgid[4]; 
1995/1218    
	int n, h; 
1995/1217    
	OneWay *w; 
	uchar digest[128]; 
1996/1029    
	Block *b; 
1995/1213    
 
1995/1217    
	w = &s->in; 
1995/1213    
 
1995/1217    
	memset(&ss, 0, sizeof(ss)); 
 
1996/1029    
	/* hash secret */ 
1997/0618    
	(*s->hf)(w->secret, w->slen, 0, &ss); 
1995/1217    
 
1996/1029    
	/* hash message */ 
	h = s->diglen; 
1999/0414    
	for(b = bin; b; b = b->next){ 
1996/1029    
		n = BLEN(b) - h; 
		if(n < 0) 
			panic("checkdigestb"); 
1997/0618    
		(*s->hf)(b->rp + h, n, 0, &ss); 
1996/1029    
		h = 0; 
	} 
 
1995/1217    
	/* hash message id */ 
	p = msgid; 
1997/0618    
	n = w->mid; 
1995/1217    
	*p++ = n>>24; 
	*p++ = n>>16; 
	*p++ = n>>8; 
	*p = n; 
1997/0618    
	(*s->hf)(msgid, 4, digest, &ss); 
1995/1217    
 
1999/0414    
	if(memcmp(digest, bin->rp, s->diglen) != 0) 
1995/1217    
		error("bad digest"); 
1995/1213    
} 
 
1995/1215    
/* get channel associated with an fd */ 
1995/1213    
static Chan* 
1996/1029    
buftochan(char *p) 
1995/1213    
{ 
	Chan *c; 
	int fd; 
 
1996/1029    
	if(p == 0) 
		error(Ebadarg); 
	fd = strtoul(p, 0, 0); 
	if(fd < 0) 
		error(Ebadarg); 
1995/1213    
	c = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */ 
2001/0823    
	if(devtab[c->type] == &ssldevtab){ 
		cclose(c); 
		error("cannot ssl encrypt devssl files"); 
	} 
1995/1213    
	return c; 
} 
 
1995/1215    
/* hand up a digest connection */ 
static void 
1996/1029    
sslhangup(Dstate *s) 
1995/1213    
{ 
1995/1215    
	Block *b; 
1995/1213    
 
1996/0531    
	qlock(&s->in.q); 
1995/1215    
	for(b = s->processed; b; b = s->processed){ 
		s->processed = b->next; 
		freeb(b); 
1995/1213    
	} 
1995/1215    
	if(s->unprocessed){ 
		freeb(s->unprocessed); 
		s->unprocessed = 0; 
1995/1213    
	} 
1996/1029    
	s->state = Sincomplete; 
1996/0531    
	qunlock(&s->in.q); 
1995/1213    
} 
1996/1029    
 
static Dstate* 
dsclone(Chan *ch) 
{ 
2001/0823    
	int i; 
	Dstate *ret; 
1996/1029    
 
	if(waserror()) { 
		unlock(&dslock); 
		nexterror(); 
	} 
	lock(&dslock); 
2001/0823    
	ret = nil; 
	for(i=0; i<Maxdstate; i++){ 
		if(dstate[i] == nil){ 
			dsnew(ch, &dstate[i]); 
			ret = dstate[i]; 
1996/1029    
			break; 
		} 
	} 
	unlock(&dslock); 
	poperror(); 
2001/0823    
	return ret; 
1996/1029    
} 
 
static void 
dsnew(Chan *ch, Dstate **pp) 
{ 
	Dstate *s; 
	int t; 
 
	*pp = s = malloc(sizeof(*s)); 
	if(!s) 
		error(Enomem); 
	if(pp - dstate >= dshiwat) 
		dshiwat++; 
	memset(s, 0, sizeof(*s)); 
	s->state = Sincomplete; 
	s->ref = 1; 
2001/0527    
	kstrdup(&s->user, up->user); 
1996/1029    
	s->perm = 0660; 
	t = TYPE(ch->qid); 
	if(t == Qclonus) 
		t = Qctl; 
	ch->qid.path = QID(pp - dstate, t); 
	ch->qid.vers = 0; 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)