xref: /plan9-contrib/sys/src/9k/port/devssl.c (revision 406c76facc4b13aa2a55454bf4091aab9f03da22)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  *  devssl - secure sockets layer
39ef1f84bSDavid du Colombier  */
49ef1f84bSDavid du Colombier #include	"u.h"
59ef1f84bSDavid du Colombier #include	"../port/lib.h"
69ef1f84bSDavid du Colombier #include	"mem.h"
79ef1f84bSDavid du Colombier #include	"dat.h"
89ef1f84bSDavid du Colombier #include	"fns.h"
99ef1f84bSDavid du Colombier #include	"../port/error.h"
109ef1f84bSDavid du Colombier 
119ef1f84bSDavid du Colombier #include	<libsec.h>
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier #define NOSPOOKS 1
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier typedef struct OneWay OneWay;
169ef1f84bSDavid du Colombier struct OneWay
179ef1f84bSDavid du Colombier {
189ef1f84bSDavid du Colombier 	QLock	q;
199ef1f84bSDavid du Colombier 	QLock	ctlq;
209ef1f84bSDavid du Colombier 
219ef1f84bSDavid du Colombier 	void	*state;		/* encryption state */
229ef1f84bSDavid du Colombier 	int	slen;		/* hash data length */
239ef1f84bSDavid du Colombier 	uchar	*secret;	/* secret */
249ef1f84bSDavid du Colombier 	ulong	mid;		/* message id */
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier enum
289ef1f84bSDavid du Colombier {
299ef1f84bSDavid du Colombier 	/* connection states */
309ef1f84bSDavid du Colombier 	Sincomplete=	0,
319ef1f84bSDavid du Colombier 	Sclear=		1,
329ef1f84bSDavid du Colombier 	Sencrypting=	2,
339ef1f84bSDavid du Colombier 	Sdigesting=	4,
349ef1f84bSDavid du Colombier 	Sdigenc=	Sencrypting|Sdigesting,
359ef1f84bSDavid du Colombier 
369ef1f84bSDavid du Colombier 	/* encryption algorithms */
379ef1f84bSDavid du Colombier 	Noencryption=	0,
389ef1f84bSDavid du Colombier 	DESCBC=		1,
399ef1f84bSDavid du Colombier 	DESECB=		2,
409ef1f84bSDavid du Colombier 	RC4=		3
419ef1f84bSDavid du Colombier };
429ef1f84bSDavid du Colombier 
439ef1f84bSDavid du Colombier typedef struct Dstate Dstate;
449ef1f84bSDavid du Colombier struct Dstate
459ef1f84bSDavid du Colombier {
469ef1f84bSDavid du Colombier 	Chan	*c;		/* io channel */
479ef1f84bSDavid du Colombier 	uchar	state;		/* state of connection */
489ef1f84bSDavid du Colombier 	int	ref;		/* serialized by dslock for atomic destroy */
499ef1f84bSDavid du Colombier 
509ef1f84bSDavid du Colombier 	uchar	encryptalg;	/* encryption algorithm */
519ef1f84bSDavid du Colombier 	ushort	blocklen;	/* blocking length */
529ef1f84bSDavid du Colombier 
539ef1f84bSDavid du Colombier 	ushort	diglen;		/* length of digest */
549ef1f84bSDavid du Colombier 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */
559ef1f84bSDavid du Colombier 
569ef1f84bSDavid du Colombier 	/* for SSL format */
579ef1f84bSDavid du Colombier 	int	max;		/* maximum unpadded data per msg */
589ef1f84bSDavid du Colombier 	int	maxpad;		/* maximum padded data per msg */
599ef1f84bSDavid du Colombier 
609ef1f84bSDavid du Colombier 	/* input side */
619ef1f84bSDavid du Colombier 	OneWay	in;
629ef1f84bSDavid du Colombier 	Block	*processed;
639ef1f84bSDavid du Colombier 	Block	*unprocessed;
649ef1f84bSDavid du Colombier 
659ef1f84bSDavid du Colombier 	/* output side */
669ef1f84bSDavid du Colombier 	OneWay	out;
679ef1f84bSDavid du Colombier 
689ef1f84bSDavid du Colombier 	/* protections */
699ef1f84bSDavid du Colombier 	char	*user;
709ef1f84bSDavid du Colombier 	int	perm;
719ef1f84bSDavid du Colombier };
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier enum
749ef1f84bSDavid du Colombier {
759ef1f84bSDavid du Colombier 	Maxdmsg=	1<<16,
76*406c76faSDavid du Colombier 	Maxdstate=	512,	/* max. open ssl conn's; must be a power of 2 */
779ef1f84bSDavid du Colombier };
789ef1f84bSDavid du Colombier 
79*406c76faSDavid du Colombier static	Lock	dslock;
80*406c76faSDavid du Colombier static	int	dshiwat;
81*406c76faSDavid du Colombier static	char	*dsname[Maxdstate];
82*406c76faSDavid du Colombier static	Dstate	*dstate[Maxdstate];
83*406c76faSDavid du Colombier static	char	*encalgs;
84*406c76faSDavid du Colombier static	char	*hashalgs;
859ef1f84bSDavid du Colombier 
869ef1f84bSDavid du Colombier enum{
879ef1f84bSDavid du Colombier 	Qtopdir		= 1,	/* top level directory */
889ef1f84bSDavid du Colombier 	Qprotodir,
899ef1f84bSDavid du Colombier 	Qclonus,
909ef1f84bSDavid du Colombier 	Qconvdir,		/* directory for a conversation */
919ef1f84bSDavid du Colombier 	Qdata,
929ef1f84bSDavid du Colombier 	Qctl,
939ef1f84bSDavid du Colombier 	Qsecretin,
949ef1f84bSDavid du Colombier 	Qsecretout,
959ef1f84bSDavid du Colombier 	Qencalgs,
969ef1f84bSDavid du Colombier 	Qhashalgs,
979ef1f84bSDavid du Colombier };
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier #define TYPE(x) 	((x).path & 0xf)
1009ef1f84bSDavid du Colombier #define CONV(x) 	(((x).path >> 5)&(Maxdstate-1))
1019ef1f84bSDavid du Colombier #define QID(c, y) 	(((c)<<5) | (y))
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier static void	ensure(Dstate*, Block**, int);
1049ef1f84bSDavid du Colombier static void	consume(Block**, uchar*, int);
1059ef1f84bSDavid du Colombier static void	setsecret(OneWay*, uchar*, int);
1069ef1f84bSDavid du Colombier static Block*	encryptb(Dstate*, Block*, int);
1079ef1f84bSDavid du Colombier static Block*	decryptb(Dstate*, Block*);
1089ef1f84bSDavid du Colombier static Block*	digestb(Dstate*, Block*, int);
1099ef1f84bSDavid du Colombier static void	checkdigestb(Dstate*, Block*);
1109ef1f84bSDavid du Colombier static Chan*	buftochan(char*);
1119ef1f84bSDavid du Colombier static void	sslhangup(Dstate*);
1129ef1f84bSDavid du Colombier static Dstate*	dsclone(Chan *c);
1139ef1f84bSDavid du Colombier static void	dsnew(Chan *c, Dstate **);
1149ef1f84bSDavid du Colombier static long	sslput(Dstate *s, Block * volatile b);
1159ef1f84bSDavid du Colombier 
1169ef1f84bSDavid du Colombier char *sslnames[] = {
1179ef1f84bSDavid du Colombier [Qclonus]	"clone",
1189ef1f84bSDavid du Colombier [Qdata]		"data",
1199ef1f84bSDavid du Colombier [Qctl]		"ctl",
1209ef1f84bSDavid du Colombier [Qsecretin]	"secretin",
1219ef1f84bSDavid du Colombier [Qsecretout]	"secretout",
1229ef1f84bSDavid du Colombier [Qencalgs]	"encalgs",
1239ef1f84bSDavid du Colombier [Qhashalgs]	"hashalgs",
1249ef1f84bSDavid du Colombier };
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier static int
sslgen(Chan * c,char *,Dirtab * d,int nd,int s,Dir * dp)1279ef1f84bSDavid du Colombier sslgen(Chan *c, char*, Dirtab *d, int nd, int s, Dir *dp)
1289ef1f84bSDavid du Colombier {
1299ef1f84bSDavid du Colombier 	Qid q;
1309ef1f84bSDavid du Colombier 	Dstate *ds;
1319ef1f84bSDavid du Colombier 	char name[16], *p, *nm;
1329ef1f84bSDavid du Colombier 	int ft;
1339ef1f84bSDavid du Colombier 
1349ef1f84bSDavid du Colombier 	USED(nd);
1359ef1f84bSDavid du Colombier 	USED(d);
1369ef1f84bSDavid du Colombier 
1379ef1f84bSDavid du Colombier 	q.type = QTFILE;
1389ef1f84bSDavid du Colombier 	q.vers = 0;
1399ef1f84bSDavid du Colombier 
1409ef1f84bSDavid du Colombier 	ft = TYPE(c->qid);
1419ef1f84bSDavid du Colombier 	switch(ft) {
1429ef1f84bSDavid du Colombier 	case Qtopdir:
1439ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
1449ef1f84bSDavid du Colombier 			q.path = QID(0, Qtopdir);
1459ef1f84bSDavid du Colombier 			q.type = QTDIR;
1469ef1f84bSDavid du Colombier 			devdir(c, q, "#D", 0, eve, 0555, dp);
1479ef1f84bSDavid du Colombier 			return 1;
1489ef1f84bSDavid du Colombier 		}
1499ef1f84bSDavid du Colombier 		if(s > 0)
1509ef1f84bSDavid du Colombier 			return -1;
1519ef1f84bSDavid du Colombier 		q.path = QID(0, Qprotodir);
1529ef1f84bSDavid du Colombier 		q.type = QTDIR;
1539ef1f84bSDavid du Colombier 		devdir(c, q, "ssl", 0, eve, 0555, dp);
1549ef1f84bSDavid du Colombier 		return 1;
1559ef1f84bSDavid du Colombier 	case Qprotodir:
1569ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
1579ef1f84bSDavid du Colombier 			q.path = QID(0, Qtopdir);
1589ef1f84bSDavid du Colombier 			q.type = QTDIR;
1599ef1f84bSDavid du Colombier 			devdir(c, q, ".", 0, eve, 0555, dp);
1609ef1f84bSDavid du Colombier 			return 1;
1619ef1f84bSDavid du Colombier 		}
1629ef1f84bSDavid du Colombier 		if(s < dshiwat) {
1639ef1f84bSDavid du Colombier 			q.path = QID(s, Qconvdir);
1649ef1f84bSDavid du Colombier 			q.type = QTDIR;
1659ef1f84bSDavid du Colombier 			ds = dstate[s];
1669ef1f84bSDavid du Colombier 			if(ds != 0)
1679ef1f84bSDavid du Colombier 				nm = ds->user;
1689ef1f84bSDavid du Colombier 			else
1699ef1f84bSDavid du Colombier 				nm = eve;
1709ef1f84bSDavid du Colombier 			if(dsname[s] == nil){
171*406c76faSDavid du Colombier 				snprint(name, sizeof name, "%d", s);
1729ef1f84bSDavid du Colombier 				kstrdup(&dsname[s], name);
1739ef1f84bSDavid du Colombier 			}
1749ef1f84bSDavid du Colombier 			devdir(c, q, dsname[s], 0, nm, 0555, dp);
1759ef1f84bSDavid du Colombier 			return 1;
1769ef1f84bSDavid du Colombier 		}
1779ef1f84bSDavid du Colombier 		if(s > dshiwat)
1789ef1f84bSDavid du Colombier 			return -1;
1799ef1f84bSDavid du Colombier 		q.path = QID(0, Qclonus);
1809ef1f84bSDavid du Colombier 		devdir(c, q, "clone", 0, eve, 0555, dp);
1819ef1f84bSDavid du Colombier 		return 1;
1829ef1f84bSDavid du Colombier 	case Qconvdir:
1839ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
1849ef1f84bSDavid du Colombier 			q.path = QID(0, Qprotodir);
1859ef1f84bSDavid du Colombier 			q.type = QTDIR;
1869ef1f84bSDavid du Colombier 			devdir(c, q, "ssl", 0, eve, 0555, dp);
1879ef1f84bSDavid du Colombier 			return 1;
1889ef1f84bSDavid du Colombier 		}
1899ef1f84bSDavid du Colombier 		ds = dstate[CONV(c->qid)];
1909ef1f84bSDavid du Colombier 		if(ds != 0)
1919ef1f84bSDavid du Colombier 			nm = ds->user;
1929ef1f84bSDavid du Colombier 		else
1939ef1f84bSDavid du Colombier 			nm = eve;
1949ef1f84bSDavid du Colombier 		switch(s) {
1959ef1f84bSDavid du Colombier 		default:
1969ef1f84bSDavid du Colombier 			return -1;
1979ef1f84bSDavid du Colombier 		case 0:
1989ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qctl);
1999ef1f84bSDavid du Colombier 			p = "ctl";
2009ef1f84bSDavid du Colombier 			break;
2019ef1f84bSDavid du Colombier 		case 1:
2029ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qdata);
2039ef1f84bSDavid du Colombier 			p = "data";
2049ef1f84bSDavid du Colombier 			break;
2059ef1f84bSDavid du Colombier 		case 2:
2069ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qsecretin);
2079ef1f84bSDavid du Colombier 			p = "secretin";
2089ef1f84bSDavid du Colombier 			break;
2099ef1f84bSDavid du Colombier 		case 3:
2109ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qsecretout);
2119ef1f84bSDavid du Colombier 			p = "secretout";
2129ef1f84bSDavid du Colombier 			break;
2139ef1f84bSDavid du Colombier 		case 4:
2149ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qencalgs);
2159ef1f84bSDavid du Colombier 			p = "encalgs";
2169ef1f84bSDavid du Colombier 			break;
2179ef1f84bSDavid du Colombier 		case 5:
2189ef1f84bSDavid du Colombier 			q.path = QID(CONV(c->qid), Qhashalgs);
2199ef1f84bSDavid du Colombier 			p = "hashalgs";
2209ef1f84bSDavid du Colombier 			break;
2219ef1f84bSDavid du Colombier 		}
2229ef1f84bSDavid du Colombier 		devdir(c, q, p, 0, nm, 0660, dp);
2239ef1f84bSDavid du Colombier 		return 1;
2249ef1f84bSDavid du Colombier 	case Qclonus:
2259ef1f84bSDavid du Colombier 		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
2269ef1f84bSDavid du Colombier 		return 1;
2279ef1f84bSDavid du Colombier 	default:
2289ef1f84bSDavid du Colombier 		ds = dstate[CONV(c->qid)];
2299ef1f84bSDavid du Colombier 		if(ds != 0)
2309ef1f84bSDavid du Colombier 			nm = ds->user;
2319ef1f84bSDavid du Colombier 		else
2329ef1f84bSDavid du Colombier 			nm = eve;
2339ef1f84bSDavid du Colombier 		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
2349ef1f84bSDavid du Colombier 		return 1;
2359ef1f84bSDavid du Colombier 	}
2369ef1f84bSDavid du Colombier }
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier static Chan*
sslattach(char * spec)2399ef1f84bSDavid du Colombier sslattach(char *spec)
2409ef1f84bSDavid du Colombier {
2419ef1f84bSDavid du Colombier 	Chan *c;
2429ef1f84bSDavid du Colombier 
2439ef1f84bSDavid du Colombier 	c = devattach('D', spec);
2449ef1f84bSDavid du Colombier 	c->qid.path = QID(0, Qtopdir);
2459ef1f84bSDavid du Colombier 	c->qid.vers = 0;
2469ef1f84bSDavid du Colombier 	c->qid.type = QTDIR;
2479ef1f84bSDavid du Colombier 	return c;
2489ef1f84bSDavid du Colombier }
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)2519ef1f84bSDavid du Colombier sslwalk(Chan *c, Chan *nc, char **name, int nname)
2529ef1f84bSDavid du Colombier {
2539ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, nil, 0, sslgen);
2549ef1f84bSDavid du Colombier }
2559ef1f84bSDavid du Colombier 
2569ef1f84bSDavid du Colombier static long
sslstat(Chan * c,uchar * db,long n)2579ef1f84bSDavid du Colombier sslstat(Chan *c, uchar *db, long n)
2589ef1f84bSDavid du Colombier {
2599ef1f84bSDavid du Colombier 	return devstat(c, db, n, nil, 0, sslgen);
2609ef1f84bSDavid du Colombier }
2619ef1f84bSDavid du Colombier 
2629ef1f84bSDavid du Colombier static Chan*
sslopen(Chan * c,int omode)2639ef1f84bSDavid du Colombier sslopen(Chan *c, int omode)
2649ef1f84bSDavid du Colombier {
2659ef1f84bSDavid du Colombier 	Dstate *s, **pp;
2669ef1f84bSDavid du Colombier 	int perm;
2679ef1f84bSDavid du Colombier 	int ft;
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 	perm = 0;
2709ef1f84bSDavid du Colombier 	omode &= 3;
2719ef1f84bSDavid du Colombier 	switch(omode) {
2729ef1f84bSDavid du Colombier 	case OREAD:
2739ef1f84bSDavid du Colombier 		perm = 4;
2749ef1f84bSDavid du Colombier 		break;
2759ef1f84bSDavid du Colombier 	case OWRITE:
2769ef1f84bSDavid du Colombier 		perm = 2;
2779ef1f84bSDavid du Colombier 		break;
2789ef1f84bSDavid du Colombier 	case ORDWR:
2799ef1f84bSDavid du Colombier 		perm = 6;
2809ef1f84bSDavid du Colombier 		break;
2819ef1f84bSDavid du Colombier 	}
2829ef1f84bSDavid du Colombier 
2839ef1f84bSDavid du Colombier 	ft = TYPE(c->qid);
2849ef1f84bSDavid du Colombier 	switch(ft) {
2859ef1f84bSDavid du Colombier 	default:
2869ef1f84bSDavid du Colombier 		panic("sslopen");
2879ef1f84bSDavid du Colombier 	case Qtopdir:
2889ef1f84bSDavid du Colombier 	case Qprotodir:
2899ef1f84bSDavid du Colombier 	case Qconvdir:
2909ef1f84bSDavid du Colombier 		if(omode != OREAD)
2919ef1f84bSDavid du Colombier 			error(Eperm);
2929ef1f84bSDavid du Colombier 		break;
2939ef1f84bSDavid du Colombier 	case Qclonus:
2949ef1f84bSDavid du Colombier 		s = dsclone(c);
2959ef1f84bSDavid du Colombier 		if(s == 0)
2969ef1f84bSDavid du Colombier 			error(Enodev);
2979ef1f84bSDavid du Colombier 		break;
2989ef1f84bSDavid du Colombier 	case Qctl:
2999ef1f84bSDavid du Colombier 	case Qdata:
3009ef1f84bSDavid du Colombier 	case Qsecretin:
3019ef1f84bSDavid du Colombier 	case Qsecretout:
3029ef1f84bSDavid du Colombier 		if(waserror()) {
3039ef1f84bSDavid du Colombier 			unlock(&dslock);
3049ef1f84bSDavid du Colombier 			nexterror();
3059ef1f84bSDavid du Colombier 		}
3069ef1f84bSDavid du Colombier 		lock(&dslock);
3079ef1f84bSDavid du Colombier 		pp = &dstate[CONV(c->qid)];
3089ef1f84bSDavid du Colombier 		s = *pp;
3099ef1f84bSDavid du Colombier 		if(s == 0)
3109ef1f84bSDavid du Colombier 			dsnew(c, pp);
3119ef1f84bSDavid du Colombier 		else {
3129ef1f84bSDavid du Colombier 			if((perm & (s->perm>>6)) != perm
3139ef1f84bSDavid du Colombier 			   && (strcmp(up->user, s->user) != 0
3149ef1f84bSDavid du Colombier 			     || (perm & s->perm) != perm))
3159ef1f84bSDavid du Colombier 				error(Eperm);
3169ef1f84bSDavid du Colombier 
3179ef1f84bSDavid du Colombier 			s->ref++;
3189ef1f84bSDavid du Colombier 		}
3199ef1f84bSDavid du Colombier 		unlock(&dslock);
3209ef1f84bSDavid du Colombier 		poperror();
3219ef1f84bSDavid du Colombier 		break;
3229ef1f84bSDavid du Colombier 	case Qencalgs:
3239ef1f84bSDavid du Colombier 	case Qhashalgs:
3249ef1f84bSDavid du Colombier 		if(omode != OREAD)
3259ef1f84bSDavid du Colombier 			error(Eperm);
3269ef1f84bSDavid du Colombier 		break;
3279ef1f84bSDavid du Colombier 	}
3289ef1f84bSDavid du Colombier 	c->mode = openmode(omode);
3299ef1f84bSDavid du Colombier 	c->flag |= COPEN;
3309ef1f84bSDavid du Colombier 	c->offset = 0;
3319ef1f84bSDavid du Colombier 	return c;
3329ef1f84bSDavid du Colombier }
3339ef1f84bSDavid du Colombier 
3349ef1f84bSDavid du Colombier static long
sslwstat(Chan * c,uchar * db,long n)3359ef1f84bSDavid du Colombier sslwstat(Chan *c, uchar *db, long n)
3369ef1f84bSDavid du Colombier {
3379ef1f84bSDavid du Colombier 	Dir *dir;
3389ef1f84bSDavid du Colombier 	Dstate *s;
3399ef1f84bSDavid du Colombier 	int l;
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier 	s = dstate[CONV(c->qid)];
3429ef1f84bSDavid du Colombier 	if(s == 0)
3439ef1f84bSDavid du Colombier 		error(Ebadusefd);
3449ef1f84bSDavid du Colombier 	if(strcmp(s->user, up->user) != 0)
3459ef1f84bSDavid du Colombier 		error(Eperm);
3469ef1f84bSDavid du Colombier 
3479ef1f84bSDavid du Colombier 	dir = smalloc(sizeof(Dir)+n);
3489ef1f84bSDavid du Colombier 	l = convM2D(db, n, &dir[0], (char*)&dir[1]);
3499ef1f84bSDavid du Colombier 	if(l == 0){
3509ef1f84bSDavid du Colombier 		free(dir);
3519ef1f84bSDavid du Colombier 		error(Eshortstat);
3529ef1f84bSDavid du Colombier 	}
3539ef1f84bSDavid du Colombier 
3549ef1f84bSDavid du Colombier 	if(!emptystr(dir->uid))
3559ef1f84bSDavid du Colombier 		kstrdup(&s->user, dir->uid);
3569ef1f84bSDavid du Colombier 	if(dir->mode != ~0UL)
3579ef1f84bSDavid du Colombier 		s->perm = dir->mode;
3589ef1f84bSDavid du Colombier 
3599ef1f84bSDavid du Colombier 	free(dir);
3609ef1f84bSDavid du Colombier 	return l;
3619ef1f84bSDavid du Colombier }
3629ef1f84bSDavid du Colombier 
3639ef1f84bSDavid du Colombier static void
sslclose(Chan * c)3649ef1f84bSDavid du Colombier sslclose(Chan *c)
3659ef1f84bSDavid du Colombier {
3669ef1f84bSDavid du Colombier 	Dstate *s;
3679ef1f84bSDavid du Colombier 	int ft;
3689ef1f84bSDavid du Colombier 
3699ef1f84bSDavid du Colombier 	ft = TYPE(c->qid);
3709ef1f84bSDavid du Colombier 	switch(ft) {
3719ef1f84bSDavid du Colombier 	case Qctl:
3729ef1f84bSDavid du Colombier 	case Qdata:
3739ef1f84bSDavid du Colombier 	case Qsecretin:
3749ef1f84bSDavid du Colombier 	case Qsecretout:
3759ef1f84bSDavid du Colombier 		if((c->flag & COPEN) == 0)
3769ef1f84bSDavid du Colombier 			break;
3779ef1f84bSDavid du Colombier 
3789ef1f84bSDavid du Colombier 		s = dstate[CONV(c->qid)];
3799ef1f84bSDavid du Colombier 		if(s == 0)
3809ef1f84bSDavid du Colombier 			break;
3819ef1f84bSDavid du Colombier 
3829ef1f84bSDavid du Colombier 		lock(&dslock);
3839ef1f84bSDavid du Colombier 		if(--s->ref > 0) {
3849ef1f84bSDavid du Colombier 			unlock(&dslock);
3859ef1f84bSDavid du Colombier 			break;
3869ef1f84bSDavid du Colombier 		}
3879ef1f84bSDavid du Colombier 		dstate[CONV(c->qid)] = 0;
3889ef1f84bSDavid du Colombier 		unlock(&dslock);
3899ef1f84bSDavid du Colombier 
3909ef1f84bSDavid du Colombier 		if(s->user != nil)
3919ef1f84bSDavid du Colombier 			free(s->user);
3929ef1f84bSDavid du Colombier 		sslhangup(s);
3939ef1f84bSDavid du Colombier 		if(s->c)
3949ef1f84bSDavid du Colombier 			cclose(s->c);
3959ef1f84bSDavid du Colombier 		if(s->in.secret)
3969ef1f84bSDavid du Colombier 			free(s->in.secret);
3979ef1f84bSDavid du Colombier 		if(s->out.secret)
3989ef1f84bSDavid du Colombier 			free(s->out.secret);
3999ef1f84bSDavid du Colombier 		if(s->in.state)
4009ef1f84bSDavid du Colombier 			free(s->in.state);
4019ef1f84bSDavid du Colombier 		if(s->out.state)
4029ef1f84bSDavid du Colombier 			free(s->out.state);
4039ef1f84bSDavid du Colombier 		free(s);
4049ef1f84bSDavid du Colombier 
4059ef1f84bSDavid du Colombier 	}
4069ef1f84bSDavid du Colombier }
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier /*
4099ef1f84bSDavid du Colombier  *  make sure we have at least 'n' bytes in list 'l'
4109ef1f84bSDavid du Colombier  */
4119ef1f84bSDavid du Colombier static void
ensure(Dstate * s,Block ** l,int n)4129ef1f84bSDavid du Colombier ensure(Dstate *s, Block **l, int n)
4139ef1f84bSDavid du Colombier {
4149ef1f84bSDavid du Colombier 	int sofar, i;
4159ef1f84bSDavid du Colombier 	Block *b, *bl;
4169ef1f84bSDavid du Colombier 
4179ef1f84bSDavid du Colombier 	sofar = 0;
4189ef1f84bSDavid du Colombier 	for(b = *l; b; b = b->next){
4199ef1f84bSDavid du Colombier 		sofar += BLEN(b);
4209ef1f84bSDavid du Colombier 		if(sofar >= n)
4219ef1f84bSDavid du Colombier 			return;
4229ef1f84bSDavid du Colombier 		l = &b->next;
4239ef1f84bSDavid du Colombier 	}
4249ef1f84bSDavid du Colombier 
4259ef1f84bSDavid du Colombier 	while(sofar < n){
4269ef1f84bSDavid du Colombier 		bl = s->c->dev->bread(s->c, Maxdmsg, 0);
4279ef1f84bSDavid du Colombier 		if(bl == 0)
4289ef1f84bSDavid du Colombier 			nexterror();
4299ef1f84bSDavid du Colombier 		*l = bl;
4309ef1f84bSDavid du Colombier 		i = 0;
4319ef1f84bSDavid du Colombier 		for(b = bl; b; b = b->next){
4329ef1f84bSDavid du Colombier 			i += BLEN(b);
4339ef1f84bSDavid du Colombier 			l = &b->next;
4349ef1f84bSDavid du Colombier 		}
4359ef1f84bSDavid du Colombier 		if(i == 0)
4369ef1f84bSDavid du Colombier 			error(Ehungup);
4379ef1f84bSDavid du Colombier 		sofar += i;
4389ef1f84bSDavid du Colombier 	}
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier /*
4429ef1f84bSDavid du Colombier  *  copy 'n' bytes from 'l' into 'p' and free
4439ef1f84bSDavid du Colombier  *  the bytes in 'l'
4449ef1f84bSDavid du Colombier  */
4459ef1f84bSDavid du Colombier static void
consume(Block ** l,uchar * p,int n)4469ef1f84bSDavid du Colombier consume(Block **l, uchar *p, int n)
4479ef1f84bSDavid du Colombier {
4489ef1f84bSDavid du Colombier 	Block *b;
4499ef1f84bSDavid du Colombier 	int i;
4509ef1f84bSDavid du Colombier 
4519ef1f84bSDavid du Colombier 	for(; *l && n > 0; n -= i){
4529ef1f84bSDavid du Colombier 		b = *l;
4539ef1f84bSDavid du Colombier 		i = BLEN(b);
4549ef1f84bSDavid du Colombier 		if(i > n)
4559ef1f84bSDavid du Colombier 			i = n;
4569ef1f84bSDavid du Colombier 		memmove(p, b->rp, i);
4579ef1f84bSDavid du Colombier 		b->rp += i;
4589ef1f84bSDavid du Colombier 		p += i;
4599ef1f84bSDavid du Colombier 		if(BLEN(b) < 0)
4609ef1f84bSDavid du Colombier 			panic("consume");
4619ef1f84bSDavid du Colombier 		if(BLEN(b))
4629ef1f84bSDavid du Colombier 			break;
4639ef1f84bSDavid du Colombier 		*l = b->next;
4649ef1f84bSDavid du Colombier 		freeb(b);
4659ef1f84bSDavid du Colombier 	}
4669ef1f84bSDavid du Colombier }
4679ef1f84bSDavid du Colombier 
4689ef1f84bSDavid du Colombier /*
4699ef1f84bSDavid du Colombier  *  give back n bytes
4709ef1f84bSDavid du Colombier static void
4719ef1f84bSDavid du Colombier regurgitate(Dstate *s, uchar *p, int n)
4729ef1f84bSDavid du Colombier {
4739ef1f84bSDavid du Colombier 	Block *b;
4749ef1f84bSDavid du Colombier 
4759ef1f84bSDavid du Colombier 	if(n <= 0)
4769ef1f84bSDavid du Colombier 		return;
4779ef1f84bSDavid du Colombier 	b = s->unprocessed;
4789ef1f84bSDavid du Colombier 	if(s->unprocessed == nil || b->rp - b->base < n) {
4799ef1f84bSDavid du Colombier 		b = allocb(n);
4809ef1f84bSDavid du Colombier 		memmove(b->wp, p, n);
4819ef1f84bSDavid du Colombier 		b->wp += n;
4829ef1f84bSDavid du Colombier 		b->next = s->unprocessed;
4839ef1f84bSDavid du Colombier 		s->unprocessed = b;
4849ef1f84bSDavid du Colombier 	} else {
4859ef1f84bSDavid du Colombier 		b->rp -= n;
4869ef1f84bSDavid du Colombier 		memmove(b->rp, p, n);
4879ef1f84bSDavid du Colombier 	}
4889ef1f84bSDavid du Colombier }
4899ef1f84bSDavid du Colombier  */
4909ef1f84bSDavid du Colombier 
4919ef1f84bSDavid du Colombier /*
4929ef1f84bSDavid du Colombier  *  remove at most n bytes from the queue, if discard is set
4939ef1f84bSDavid du Colombier  *  dump the remainder
4949ef1f84bSDavid du Colombier  */
4959ef1f84bSDavid du Colombier static Block*
qtake(Block ** l,int n,int discard)4969ef1f84bSDavid du Colombier qtake(Block **l, int n, int discard)
4979ef1f84bSDavid du Colombier {
4989ef1f84bSDavid du Colombier 	Block *nb, *b, *first;
4999ef1f84bSDavid du Colombier 	int i;
5009ef1f84bSDavid du Colombier 
5019ef1f84bSDavid du Colombier 	first = *l;
5029ef1f84bSDavid du Colombier 	for(b = first; b; b = b->next){
5039ef1f84bSDavid du Colombier 		i = BLEN(b);
5049ef1f84bSDavid du Colombier 		if(i == n){
5059ef1f84bSDavid du Colombier 			if(discard){
5069ef1f84bSDavid du Colombier 				freeblist(b->next);
5079ef1f84bSDavid du Colombier 				*l = 0;
5089ef1f84bSDavid du Colombier 			} else
5099ef1f84bSDavid du Colombier 				*l = b->next;
5109ef1f84bSDavid du Colombier 			b->next = 0;
5119ef1f84bSDavid du Colombier 			return first;
5129ef1f84bSDavid du Colombier 		} else if(i > n){
5139ef1f84bSDavid du Colombier 			i -= n;
5149ef1f84bSDavid du Colombier 			if(discard){
5159ef1f84bSDavid du Colombier 				freeblist(b->next);
5169ef1f84bSDavid du Colombier 				b->wp -= i;
5179ef1f84bSDavid du Colombier 				*l = 0;
5189ef1f84bSDavid du Colombier 			} else {
5199ef1f84bSDavid du Colombier 				nb = allocb(i);
5209ef1f84bSDavid du Colombier 				memmove(nb->wp, b->rp+n, i);
5219ef1f84bSDavid du Colombier 				nb->wp += i;
5229ef1f84bSDavid du Colombier 				b->wp -= i;
5239ef1f84bSDavid du Colombier 				nb->next = b->next;
5249ef1f84bSDavid du Colombier 				*l = nb;
5259ef1f84bSDavid du Colombier 			}
5269ef1f84bSDavid du Colombier 			b->next = 0;
5279ef1f84bSDavid du Colombier 			if(BLEN(b) < 0)
5289ef1f84bSDavid du Colombier 				panic("qtake");
5299ef1f84bSDavid du Colombier 			return first;
5309ef1f84bSDavid du Colombier 		} else
5319ef1f84bSDavid du Colombier 			n -= i;
5329ef1f84bSDavid du Colombier 		if(BLEN(b) < 0)
5339ef1f84bSDavid du Colombier 			panic("qtake");
5349ef1f84bSDavid du Colombier 	}
5359ef1f84bSDavid du Colombier 	*l = 0;
5369ef1f84bSDavid du Colombier 	return first;
5379ef1f84bSDavid du Colombier }
5389ef1f84bSDavid du Colombier 
5399ef1f84bSDavid du Colombier /*
5409ef1f84bSDavid du Colombier  *  We can't let Eintr's lose data since the program
5419ef1f84bSDavid du Colombier  *  doing the read may be able to handle it.  The only
5429ef1f84bSDavid du Colombier  *  places Eintr is possible is during the read's in consume.
5439ef1f84bSDavid du Colombier  *  Therefore, we make sure we can always put back the bytes
5449ef1f84bSDavid du Colombier  *  consumed before the last ensure.
5459ef1f84bSDavid du Colombier  */
5469ef1f84bSDavid du Colombier static Block*
sslbread(Chan * c,long n,vlong)5479ef1f84bSDavid du Colombier sslbread(Chan *c, long n, vlong)
5489ef1f84bSDavid du Colombier {
5499ef1f84bSDavid du Colombier 	Dstate * volatile s;
5509ef1f84bSDavid du Colombier 	Block *b;
5519ef1f84bSDavid du Colombier 	uchar consumed[3], *p;
5529ef1f84bSDavid du Colombier 	int toconsume;
5539ef1f84bSDavid du Colombier 	int len, pad;
5549ef1f84bSDavid du Colombier 
5559ef1f84bSDavid du Colombier 	s = dstate[CONV(c->qid)];
5569ef1f84bSDavid du Colombier 	if(s == 0)
5579ef1f84bSDavid du Colombier 		panic("sslbread");
5589ef1f84bSDavid du Colombier 	if(s->state == Sincomplete)
5599ef1f84bSDavid du Colombier 		error(Ebadusefd);
5609ef1f84bSDavid du Colombier 
5619ef1f84bSDavid du Colombier 	qlock(&s->in.q);
5629ef1f84bSDavid du Colombier 	if(waserror()){
5639ef1f84bSDavid du Colombier 		qunlock(&s->in.q);
5649ef1f84bSDavid du Colombier 		nexterror();
5659ef1f84bSDavid du Colombier 	}
5669ef1f84bSDavid du Colombier 
5679ef1f84bSDavid du Colombier 	if(s->processed == 0){
5689ef1f84bSDavid du Colombier 		/*
5699ef1f84bSDavid du Colombier 		 * Read in the whole message.  Until we've got it all,
5709ef1f84bSDavid du Colombier 		 * it stays on s->unprocessed, so that if we get Eintr,
5719ef1f84bSDavid du Colombier 		 * we'll pick up where we left off.
5729ef1f84bSDavid du Colombier 		 */
5739ef1f84bSDavid du Colombier 		ensure(s, &s->unprocessed, 3);
5749ef1f84bSDavid du Colombier 		s->unprocessed = pullupblock(s->unprocessed, 2);
5759ef1f84bSDavid du Colombier 		p = s->unprocessed->rp;
5769ef1f84bSDavid du Colombier 		if(p[0] & 0x80){
5779ef1f84bSDavid du Colombier 			len = ((p[0] & 0x7f)<<8) | p[1];
5789ef1f84bSDavid du Colombier 			ensure(s, &s->unprocessed, len);
5799ef1f84bSDavid du Colombier 			pad = 0;
5809ef1f84bSDavid du Colombier 			toconsume = 2;
5819ef1f84bSDavid du Colombier 		} else {
5829ef1f84bSDavid du Colombier 			s->unprocessed = pullupblock(s->unprocessed, 3);
5839ef1f84bSDavid du Colombier 			len = ((p[0] & 0x3f)<<8) | p[1];
5849ef1f84bSDavid du Colombier 			pad = p[2];
5859ef1f84bSDavid du Colombier 			if(pad > len){
5869ef1f84bSDavid du Colombier 				print("pad %d buf len %d\n", pad, len);
5879ef1f84bSDavid du Colombier 				error("bad pad in ssl message");
5889ef1f84bSDavid du Colombier 			}
5899ef1f84bSDavid du Colombier 			toconsume = 3;
5909ef1f84bSDavid du Colombier 		}
5919ef1f84bSDavid du Colombier 		ensure(s, &s->unprocessed, toconsume+len);
5929ef1f84bSDavid du Colombier 
5939ef1f84bSDavid du Colombier 		/* skip header */
5949ef1f84bSDavid du Colombier 		consume(&s->unprocessed, consumed, toconsume);
5959ef1f84bSDavid du Colombier 
5969ef1f84bSDavid du Colombier 		/* grab the next message and decode/decrypt it */
5979ef1f84bSDavid du Colombier 		b = qtake(&s->unprocessed, len, 0);
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier 		if(blocklen(b) != len)
6009ef1f84bSDavid du Colombier 			print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
6019ef1f84bSDavid du Colombier 
6029ef1f84bSDavid du Colombier 		if(waserror()){
6039ef1f84bSDavid du Colombier 			qunlock(&s->in.ctlq);
6049ef1f84bSDavid du Colombier 			if(b != nil)
6059ef1f84bSDavid du Colombier 				freeb(b);
6069ef1f84bSDavid du Colombier 			nexterror();
6079ef1f84bSDavid du Colombier 		}
6089ef1f84bSDavid du Colombier 		qlock(&s->in.ctlq);
6099ef1f84bSDavid du Colombier 		switch(s->state){
6109ef1f84bSDavid du Colombier 		case Sencrypting:
6119ef1f84bSDavid du Colombier 			if(b == nil)
6129ef1f84bSDavid du Colombier 				error("ssl message too short (encrypting)");
6139ef1f84bSDavid du Colombier 			b = decryptb(s, b);
6149ef1f84bSDavid du Colombier 			break;
6159ef1f84bSDavid du Colombier 		case Sdigesting:
6169ef1f84bSDavid du Colombier 			b = pullupblock(b, s->diglen);
6179ef1f84bSDavid du Colombier 			if(b == nil)
6189ef1f84bSDavid du Colombier 				error("ssl message too short (digesting)");
6199ef1f84bSDavid du Colombier 			checkdigestb(s, b);
6209ef1f84bSDavid du Colombier 			pullblock(&b, s->diglen);
6219ef1f84bSDavid du Colombier 			len -= s->diglen;
6229ef1f84bSDavid du Colombier 			break;
6239ef1f84bSDavid du Colombier 		case Sdigenc:
6249ef1f84bSDavid du Colombier 			b = decryptb(s, b);
6259ef1f84bSDavid du Colombier 			b = pullupblock(b, s->diglen);
6269ef1f84bSDavid du Colombier 			if(b == nil)
6279ef1f84bSDavid du Colombier 				error("ssl message too short (dig+enc)");
6289ef1f84bSDavid du Colombier 			checkdigestb(s, b);
6299ef1f84bSDavid du Colombier 			pullblock(&b, s->diglen);
6309ef1f84bSDavid du Colombier 			len -= s->diglen;
6319ef1f84bSDavid du Colombier 			break;
6329ef1f84bSDavid du Colombier 		}
6339ef1f84bSDavid du Colombier 
6349ef1f84bSDavid du Colombier 		/* remove pad */
6359ef1f84bSDavid du Colombier 		if(pad)
6369ef1f84bSDavid du Colombier 			s->processed = qtake(&b, len - pad, 1);
6379ef1f84bSDavid du Colombier 		else
6389ef1f84bSDavid du Colombier 			s->processed = b;
6399ef1f84bSDavid du Colombier 		b = nil;
6409ef1f84bSDavid du Colombier 		s->in.mid++;
6419ef1f84bSDavid du Colombier 		qunlock(&s->in.ctlq);
6429ef1f84bSDavid du Colombier 		poperror();
6439ef1f84bSDavid du Colombier 	}
6449ef1f84bSDavid du Colombier 
6459ef1f84bSDavid du Colombier 	/* return at most what was asked for */
6469ef1f84bSDavid du Colombier 	b = qtake(&s->processed, n, 0);
6479ef1f84bSDavid du Colombier 
6489ef1f84bSDavid du Colombier 	qunlock(&s->in.q);
6499ef1f84bSDavid du Colombier 	poperror();
6509ef1f84bSDavid du Colombier 
6519ef1f84bSDavid du Colombier 	return b;
6529ef1f84bSDavid du Colombier }
6539ef1f84bSDavid du Colombier 
6549ef1f84bSDavid du Colombier static long
sslread(Chan * c,void * a,long n,vlong off)6559ef1f84bSDavid du Colombier sslread(Chan *c, void *a, long n, vlong off)
6569ef1f84bSDavid du Colombier {
6579ef1f84bSDavid du Colombier 	Block * volatile b;
6589ef1f84bSDavid du Colombier 	Block *nb;
6599ef1f84bSDavid du Colombier 	uchar *va;
6609ef1f84bSDavid du Colombier 	int i;
6619ef1f84bSDavid du Colombier 	char buf[128];
6629ef1f84bSDavid du Colombier 	long offset;
6639ef1f84bSDavid du Colombier 	int ft;
6649ef1f84bSDavid du Colombier 
6659ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
6669ef1f84bSDavid du Colombier 		return devdirread(c, a, n, 0, 0, sslgen);
6679ef1f84bSDavid du Colombier 
6689ef1f84bSDavid du Colombier 	ft = TYPE(c->qid);
6699ef1f84bSDavid du Colombier 	offset = off;
6709ef1f84bSDavid du Colombier 	switch(ft) {
6719ef1f84bSDavid du Colombier 	default:
6729ef1f84bSDavid du Colombier 		error(Ebadusefd);
6739ef1f84bSDavid du Colombier 	case Qctl:
6749ef1f84bSDavid du Colombier 		ft = CONV(c->qid);
675*406c76faSDavid du Colombier 		snprint(buf, sizeof buf, "%d", ft);
6769ef1f84bSDavid du Colombier 		return readstr(offset, a, n, buf);
6779ef1f84bSDavid du Colombier 	case Qdata:
6789ef1f84bSDavid du Colombier 		b = sslbread(c, n, offset);
6799ef1f84bSDavid du Colombier 		break;
6809ef1f84bSDavid du Colombier 	case Qencalgs:
6819ef1f84bSDavid du Colombier 		return readstr(offset, a, n, encalgs);
6829ef1f84bSDavid du Colombier 		break;
6839ef1f84bSDavid du Colombier 	case Qhashalgs:
6849ef1f84bSDavid du Colombier 		return readstr(offset, a, n, hashalgs);
6859ef1f84bSDavid du Colombier 		break;
6869ef1f84bSDavid du Colombier 	}
6879ef1f84bSDavid du Colombier 
6889ef1f84bSDavid du Colombier 	if(waserror()){
6899ef1f84bSDavid du Colombier 		freeblist(b);
6909ef1f84bSDavid du Colombier 		nexterror();
6919ef1f84bSDavid du Colombier 	}
6929ef1f84bSDavid du Colombier 
6939ef1f84bSDavid du Colombier 	n = 0;
6949ef1f84bSDavid du Colombier 	va = a;
6959ef1f84bSDavid du Colombier 	for(nb = b; nb; nb = nb->next){
6969ef1f84bSDavid du Colombier 		i = BLEN(nb);
6979ef1f84bSDavid du Colombier 		memmove(va+n, nb->rp, i);
6989ef1f84bSDavid du Colombier 		n += i;
6999ef1f84bSDavid du Colombier 	}
7009ef1f84bSDavid du Colombier 
7019ef1f84bSDavid du Colombier 	freeblist(b);
7029ef1f84bSDavid du Colombier 	poperror();
7039ef1f84bSDavid du Colombier 
7049ef1f84bSDavid du Colombier 	return n;
7059ef1f84bSDavid du Colombier }
7069ef1f84bSDavid du Colombier 
7079ef1f84bSDavid du Colombier /*
7089ef1f84bSDavid du Colombier  *  this algorithm doesn't have to be great since we're just
7099ef1f84bSDavid du Colombier  *  trying to obscure the block fill
7109ef1f84bSDavid du Colombier  */
7119ef1f84bSDavid du Colombier static void
randfill(uchar * buf,int len)7129ef1f84bSDavid du Colombier randfill(uchar *buf, int len)
7139ef1f84bSDavid du Colombier {
7149ef1f84bSDavid du Colombier 	while(len-- > 0)
7159ef1f84bSDavid du Colombier 		*buf++ = nrand(256);
7169ef1f84bSDavid du Colombier }
7179ef1f84bSDavid du Colombier 
7189ef1f84bSDavid du Colombier static long
sslbwrite(Chan * c,Block * b,vlong)7199ef1f84bSDavid du Colombier sslbwrite(Chan *c, Block *b, vlong)
7209ef1f84bSDavid du Colombier {
7219ef1f84bSDavid du Colombier 	Dstate * volatile s;
7229ef1f84bSDavid du Colombier 	long rv;
7239ef1f84bSDavid du Colombier 
7249ef1f84bSDavid du Colombier 	s = dstate[CONV(c->qid)];
7259ef1f84bSDavid du Colombier 	if(s == nil)
7269ef1f84bSDavid du Colombier 		panic("sslbwrite");
7279ef1f84bSDavid du Colombier 
7289ef1f84bSDavid du Colombier 	if(s->state == Sincomplete){
7299ef1f84bSDavid du Colombier 		freeb(b);
7309ef1f84bSDavid du Colombier 		error(Ebadusefd);
7319ef1f84bSDavid du Colombier 	}
7329ef1f84bSDavid du Colombier 
7339ef1f84bSDavid du Colombier 	/* lock so split writes won't interleave */
7349ef1f84bSDavid du Colombier 	if(waserror()){
7359ef1f84bSDavid du Colombier 		qunlock(&s->out.q);
7369ef1f84bSDavid du Colombier 		nexterror();
7379ef1f84bSDavid du Colombier 	}
7389ef1f84bSDavid du Colombier 	qlock(&s->out.q);
7399ef1f84bSDavid du Colombier 
7409ef1f84bSDavid du Colombier 	rv = sslput(s, b);
7419ef1f84bSDavid du Colombier 
7429ef1f84bSDavid du Colombier 	poperror();
7439ef1f84bSDavid du Colombier 	qunlock(&s->out.q);
7449ef1f84bSDavid du Colombier 
7459ef1f84bSDavid du Colombier 	return rv;
7469ef1f84bSDavid du Colombier }
7479ef1f84bSDavid du Colombier 
7489ef1f84bSDavid du Colombier /*
7499ef1f84bSDavid du Colombier  *  use SSL record format, add in count, digest and/or encrypt.
7509ef1f84bSDavid du Colombier  *  the write is interruptable.  if it is interrupted, we'll
7519ef1f84bSDavid du Colombier  *  get out of sync with the far side.  not much we can do about
7529ef1f84bSDavid du Colombier  *  it since we don't know if any bytes have been written.
7539ef1f84bSDavid du Colombier  */
7549ef1f84bSDavid du Colombier static long
sslput(Dstate * s,Block * volatile b)7559ef1f84bSDavid du Colombier sslput(Dstate *s, Block * volatile b)
7569ef1f84bSDavid du Colombier {
7579ef1f84bSDavid du Colombier 	Block *nb;
7589ef1f84bSDavid du Colombier 	int h, n, l, pad, rv;
7599ef1f84bSDavid du Colombier 	uchar *p;
7609ef1f84bSDavid du Colombier 	int offset;
7619ef1f84bSDavid du Colombier 
7629ef1f84bSDavid du Colombier 	if(waserror()){
7639ef1f84bSDavid du Colombier 		if(b != nil)
764*406c76faSDavid du Colombier 			freeb(b);
7659ef1f84bSDavid du Colombier 		nexterror();
7669ef1f84bSDavid du Colombier 	}
7679ef1f84bSDavid du Colombier 
7689ef1f84bSDavid du Colombier 	rv = 0;
7699ef1f84bSDavid du Colombier 	while(b != nil){
7709ef1f84bSDavid du Colombier 		l = n = BLEN(b);
7719ef1f84bSDavid du Colombier 		h = s->diglen + 2;
7729ef1f84bSDavid du Colombier 
7739ef1f84bSDavid du Colombier 		/* trim to maximum block size */
7749ef1f84bSDavid du Colombier 		pad = 0;
7759ef1f84bSDavid du Colombier 		if(l > s->max){
7769ef1f84bSDavid du Colombier 			l = s->max;
7779ef1f84bSDavid du Colombier 		} else if(s->blocklen != 1){
7789ef1f84bSDavid du Colombier 			pad = (l + s->diglen)%s->blocklen;
7799ef1f84bSDavid du Colombier 			if(pad){
7809ef1f84bSDavid du Colombier 				if(l > s->maxpad){
7819ef1f84bSDavid du Colombier 					pad = 0;
7829ef1f84bSDavid du Colombier 					l = s->maxpad;
7839ef1f84bSDavid du Colombier 				} else {
7849ef1f84bSDavid du Colombier 					pad = s->blocklen - pad;
7859ef1f84bSDavid du Colombier 					h++;
7869ef1f84bSDavid du Colombier 				}
7879ef1f84bSDavid du Colombier 			}
7889ef1f84bSDavid du Colombier 		}
7899ef1f84bSDavid du Colombier 
7909ef1f84bSDavid du Colombier 		rv += l;
7919ef1f84bSDavid du Colombier 		if(l != n){
7929ef1f84bSDavid du Colombier 			nb = allocb(l + h + pad);
7939ef1f84bSDavid du Colombier 			memmove(nb->wp + h, b->rp, l);
7949ef1f84bSDavid du Colombier 			nb->wp += l + h;
7959ef1f84bSDavid du Colombier 			b->rp += l;
7969ef1f84bSDavid du Colombier 		} else {
7979ef1f84bSDavid du Colombier 			/* add header space */
7989ef1f84bSDavid du Colombier 			nb = padblock(b, h);
7999ef1f84bSDavid du Colombier 			b = 0;
8009ef1f84bSDavid du Colombier 		}
8019ef1f84bSDavid du Colombier 		l += s->diglen;
8029ef1f84bSDavid du Colombier 
8039ef1f84bSDavid du Colombier 		/* SSL style count */
8049ef1f84bSDavid du Colombier 		if(pad){
8059ef1f84bSDavid du Colombier 			nb = padblock(nb, -pad);
8069ef1f84bSDavid du Colombier 			randfill(nb->wp, pad);
8079ef1f84bSDavid du Colombier 			nb->wp += pad;
8089ef1f84bSDavid du Colombier 			l += pad;
8099ef1f84bSDavid du Colombier 
8109ef1f84bSDavid du Colombier 			p = nb->rp;
8119ef1f84bSDavid du Colombier 			p[0] = (l>>8);
8129ef1f84bSDavid du Colombier 			p[1] = l;
8139ef1f84bSDavid du Colombier 			p[2] = pad;
8149ef1f84bSDavid du Colombier 			offset = 3;
8159ef1f84bSDavid du Colombier 		} else {
8169ef1f84bSDavid du Colombier 			p = nb->rp;
8179ef1f84bSDavid du Colombier 			p[0] = (l>>8) | 0x80;
8189ef1f84bSDavid du Colombier 			p[1] = l;
8199ef1f84bSDavid du Colombier 			offset = 2;
8209ef1f84bSDavid du Colombier 		}
8219ef1f84bSDavid du Colombier 
8229ef1f84bSDavid du Colombier 		switch(s->state){
8239ef1f84bSDavid du Colombier 		case Sencrypting:
8249ef1f84bSDavid du Colombier 			nb = encryptb(s, nb, offset);
8259ef1f84bSDavid du Colombier 			break;
8269ef1f84bSDavid du Colombier 		case Sdigesting:
8279ef1f84bSDavid du Colombier 			nb = digestb(s, nb, offset);
8289ef1f84bSDavid du Colombier 			break;
8299ef1f84bSDavid du Colombier 		case Sdigenc:
8309ef1f84bSDavid du Colombier 			nb = digestb(s, nb, offset);
8319ef1f84bSDavid du Colombier 			nb = encryptb(s, nb, offset);
8329ef1f84bSDavid du Colombier 			break;
8339ef1f84bSDavid du Colombier 		}
8349ef1f84bSDavid du Colombier 
8359ef1f84bSDavid du Colombier 		s->out.mid++;
8369ef1f84bSDavid du Colombier 
8379ef1f84bSDavid du Colombier 		l = BLEN(nb);
8389ef1f84bSDavid du Colombier 		s->c->dev->bwrite(s->c, nb, s->c->offset);
8399ef1f84bSDavid du Colombier 		s->c->offset += l;
8409ef1f84bSDavid du Colombier 	}
8419ef1f84bSDavid du Colombier 
8429ef1f84bSDavid du Colombier 	poperror();
8439ef1f84bSDavid du Colombier 	return rv;
8449ef1f84bSDavid du Colombier }
8459ef1f84bSDavid du Colombier 
8469ef1f84bSDavid du Colombier static void
setsecret(OneWay * w,uchar * secret,int n)8479ef1f84bSDavid du Colombier setsecret(OneWay *w, uchar *secret, int n)
8489ef1f84bSDavid du Colombier {
8499ef1f84bSDavid du Colombier 	if(w->secret)
8509ef1f84bSDavid du Colombier 		free(w->secret);
8519ef1f84bSDavid du Colombier 
8529ef1f84bSDavid du Colombier 	w->secret = smalloc(n);
8539ef1f84bSDavid du Colombier 	memmove(w->secret, secret, n);
8549ef1f84bSDavid du Colombier 	w->slen = n;
8559ef1f84bSDavid du Colombier }
8569ef1f84bSDavid du Colombier 
8579ef1f84bSDavid du Colombier static void
initDESkey(OneWay * w)8589ef1f84bSDavid du Colombier initDESkey(OneWay *w)
8599ef1f84bSDavid du Colombier {
8609ef1f84bSDavid du Colombier 	if(w->state){
8619ef1f84bSDavid du Colombier 		free(w->state);
8629ef1f84bSDavid du Colombier 		w->state = 0;
8639ef1f84bSDavid du Colombier 	}
8649ef1f84bSDavid du Colombier 
8659ef1f84bSDavid du Colombier 	w->state = smalloc(sizeof(DESstate));
8669ef1f84bSDavid du Colombier 	if(w->slen >= 16)
8679ef1f84bSDavid du Colombier 		setupDESstate(w->state, w->secret, w->secret+8);
8689ef1f84bSDavid du Colombier 	else if(w->slen >= 8)
8699ef1f84bSDavid du Colombier 		setupDESstate(w->state, w->secret, 0);
8709ef1f84bSDavid du Colombier 	else
8719ef1f84bSDavid du Colombier 		error("secret too short");
8729ef1f84bSDavid du Colombier }
8739ef1f84bSDavid du Colombier 
8749ef1f84bSDavid du Colombier /*
8759ef1f84bSDavid du Colombier  *  40 bit DES is the same as 56 bit DES.  However,
8769ef1f84bSDavid du Colombier  *  16 bits of the key are masked to zero.
8779ef1f84bSDavid du Colombier  */
8789ef1f84bSDavid du Colombier static void
initDESkey_40(OneWay * w)8799ef1f84bSDavid du Colombier initDESkey_40(OneWay *w)
8809ef1f84bSDavid du Colombier {
8819ef1f84bSDavid du Colombier 	uchar key[8];
8829ef1f84bSDavid du Colombier 
8839ef1f84bSDavid du Colombier 	if(w->state){
8849ef1f84bSDavid du Colombier 		free(w->state);
8859ef1f84bSDavid du Colombier 		w->state = 0;
8869ef1f84bSDavid du Colombier 	}
8879ef1f84bSDavid du Colombier 
8889ef1f84bSDavid du Colombier 	if(w->slen >= 8){
8899ef1f84bSDavid du Colombier 		memmove(key, w->secret, 8);
8909ef1f84bSDavid du Colombier 		key[0] &= 0x0f;
8919ef1f84bSDavid du Colombier 		key[2] &= 0x0f;
8929ef1f84bSDavid du Colombier 		key[4] &= 0x0f;
8939ef1f84bSDavid du Colombier 		key[6] &= 0x0f;
8949ef1f84bSDavid du Colombier 	}
8959ef1f84bSDavid du Colombier 
8969ef1f84bSDavid du Colombier 	w->state = malloc(sizeof(DESstate));
897*406c76faSDavid du Colombier 	if(w->state == nil)
898*406c76faSDavid du Colombier 		error(Enomem);
8999ef1f84bSDavid du Colombier 	if(w->slen >= 16)
9009ef1f84bSDavid du Colombier 		setupDESstate(w->state, key, w->secret+8);
9019ef1f84bSDavid du Colombier 	else if(w->slen >= 8)
9029ef1f84bSDavid du Colombier 		setupDESstate(w->state, key, 0);
9039ef1f84bSDavid du Colombier 	else
9049ef1f84bSDavid du Colombier 		error("secret too short");
9059ef1f84bSDavid du Colombier }
9069ef1f84bSDavid du Colombier 
9079ef1f84bSDavid du Colombier static void
initRC4key(OneWay * w)9089ef1f84bSDavid du Colombier initRC4key(OneWay *w)
9099ef1f84bSDavid du Colombier {
9109ef1f84bSDavid du Colombier 	if(w->state){
9119ef1f84bSDavid du Colombier 		free(w->state);
9129ef1f84bSDavid du Colombier 		w->state = 0;
9139ef1f84bSDavid du Colombier 	}
9149ef1f84bSDavid du Colombier 
9159ef1f84bSDavid du Colombier 	w->state = smalloc(sizeof(RC4state));
9169ef1f84bSDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9179ef1f84bSDavid du Colombier }
9189ef1f84bSDavid du Colombier 
9199ef1f84bSDavid du Colombier /*
9209ef1f84bSDavid du Colombier  *  40 bit RC4 is the same as n-bit RC4.  However,
9219ef1f84bSDavid du Colombier  *  we ignore all but the first 40 bits of the key.
9229ef1f84bSDavid du Colombier  */
9239ef1f84bSDavid du Colombier static void
initRC4key_40(OneWay * w)9249ef1f84bSDavid du Colombier initRC4key_40(OneWay *w)
9259ef1f84bSDavid du Colombier {
9269ef1f84bSDavid du Colombier 	if(w->state){
9279ef1f84bSDavid du Colombier 		free(w->state);
9289ef1f84bSDavid du Colombier 		w->state = 0;
9299ef1f84bSDavid du Colombier 	}
9309ef1f84bSDavid du Colombier 
9319ef1f84bSDavid du Colombier 	if(w->slen > 5)
9329ef1f84bSDavid du Colombier 		w->slen = 5;
9339ef1f84bSDavid du Colombier 
9349ef1f84bSDavid du Colombier 	w->state = malloc(sizeof(RC4state));
935*406c76faSDavid du Colombier 	if(w->state == nil)
936*406c76faSDavid du Colombier 		error(Enomem);
9379ef1f84bSDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9389ef1f84bSDavid du Colombier }
9399ef1f84bSDavid du Colombier 
9409ef1f84bSDavid du Colombier /*
9419ef1f84bSDavid du Colombier  *  128 bit RC4 is the same as n-bit RC4.  However,
9429ef1f84bSDavid du Colombier  *  we ignore all but the first 128 bits of the key.
9439ef1f84bSDavid du Colombier  */
9449ef1f84bSDavid du Colombier static void
initRC4key_128(OneWay * w)9459ef1f84bSDavid du Colombier initRC4key_128(OneWay *w)
9469ef1f84bSDavid du Colombier {
9479ef1f84bSDavid du Colombier 	if(w->state){
9489ef1f84bSDavid du Colombier 		free(w->state);
9499ef1f84bSDavid du Colombier 		w->state = 0;
9509ef1f84bSDavid du Colombier 	}
9519ef1f84bSDavid du Colombier 
9529ef1f84bSDavid du Colombier 	if(w->slen > 16)
9539ef1f84bSDavid du Colombier 		w->slen = 16;
9549ef1f84bSDavid du Colombier 
9559ef1f84bSDavid du Colombier 	w->state = malloc(sizeof(RC4state));
956*406c76faSDavid du Colombier 	if(w->state == nil)
957*406c76faSDavid du Colombier 		error(Enomem);
9589ef1f84bSDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9599ef1f84bSDavid du Colombier }
9609ef1f84bSDavid du Colombier 
9619ef1f84bSDavid du Colombier 
9629ef1f84bSDavid du Colombier typedef struct Hashalg Hashalg;
9639ef1f84bSDavid du Colombier struct Hashalg
9649ef1f84bSDavid du Colombier {
9659ef1f84bSDavid du Colombier 	char	*name;
9669ef1f84bSDavid du Colombier 	int	diglen;
9679ef1f84bSDavid du Colombier 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
9689ef1f84bSDavid du Colombier };
9699ef1f84bSDavid du Colombier 
9709ef1f84bSDavid du Colombier Hashalg hashtab[] =
9719ef1f84bSDavid du Colombier {
9729ef1f84bSDavid du Colombier 	{ "md4", MD4dlen, md4, },
9739ef1f84bSDavid du Colombier 	{ "md5", MD5dlen, md5, },
9749ef1f84bSDavid du Colombier 	{ "sha1", SHA1dlen, sha1, },
9759ef1f84bSDavid du Colombier 	{ "sha", SHA1dlen, sha1, },
9769ef1f84bSDavid du Colombier 	{ 0 }
9779ef1f84bSDavid du Colombier };
9789ef1f84bSDavid du Colombier 
9799ef1f84bSDavid du Colombier static int
parsehashalg(char * p,Dstate * s)9809ef1f84bSDavid du Colombier parsehashalg(char *p, Dstate *s)
9819ef1f84bSDavid du Colombier {
9829ef1f84bSDavid du Colombier 	Hashalg *ha;
9839ef1f84bSDavid du Colombier 
9849ef1f84bSDavid du Colombier 	for(ha = hashtab; ha->name; ha++){
9859ef1f84bSDavid du Colombier 		if(strcmp(p, ha->name) == 0){
9869ef1f84bSDavid du Colombier 			s->hf = ha->hf;
9879ef1f84bSDavid du Colombier 			s->diglen = ha->diglen;
9889ef1f84bSDavid du Colombier 			s->state &= ~Sclear;
9899ef1f84bSDavid du Colombier 			s->state |= Sdigesting;
9909ef1f84bSDavid du Colombier 			return 0;
9919ef1f84bSDavid du Colombier 		}
9929ef1f84bSDavid du Colombier 	}
9939ef1f84bSDavid du Colombier 	return -1;
9949ef1f84bSDavid du Colombier }
9959ef1f84bSDavid du Colombier 
9969ef1f84bSDavid du Colombier typedef struct Encalg Encalg;
9979ef1f84bSDavid du Colombier struct Encalg
9989ef1f84bSDavid du Colombier {
9999ef1f84bSDavid du Colombier 	char	*name;
10009ef1f84bSDavid du Colombier 	int	blocklen;
10019ef1f84bSDavid du Colombier 	int	alg;
10029ef1f84bSDavid du Colombier 	void	(*keyinit)(OneWay*);
10039ef1f84bSDavid du Colombier };
10049ef1f84bSDavid du Colombier 
10059ef1f84bSDavid du Colombier #ifdef NOSPOOKS
10069ef1f84bSDavid du Colombier Encalg encrypttab[] =
10079ef1f84bSDavid du Colombier {
10089ef1f84bSDavid du Colombier 	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
10099ef1f84bSDavid du Colombier 	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
10109ef1f84bSDavid du Colombier 	{ "des_56_cbc", 8, DESCBC, initDESkey, },
10119ef1f84bSDavid du Colombier 	{ "des_56_ecb", 8, DESECB, initDESkey, },
10129ef1f84bSDavid du Colombier 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
10139ef1f84bSDavid du Colombier 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
10149ef1f84bSDavid du Colombier 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
10159ef1f84bSDavid du Colombier 	{ "rc4_256", 1, RC4, initRC4key, },
10169ef1f84bSDavid du Colombier 	{ "rc4_128", 1, RC4, initRC4key_128, },
10179ef1f84bSDavid du Colombier 	{ "rc4_40", 1, RC4, initRC4key_40, },
10189ef1f84bSDavid du Colombier 	{ 0 }
10199ef1f84bSDavid du Colombier };
10209ef1f84bSDavid du Colombier #else
10219ef1f84bSDavid du Colombier Encalg encrypttab[] =
10229ef1f84bSDavid du Colombier {
10239ef1f84bSDavid du Colombier 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
10249ef1f84bSDavid du Colombier 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
10259ef1f84bSDavid du Colombier 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
10269ef1f84bSDavid du Colombier 	{ "rc4_40", 1, RC4, initRC4key_40, },
10279ef1f84bSDavid du Colombier 	{ 0 }
10289ef1f84bSDavid du Colombier };
10299ef1f84bSDavid du Colombier #endif NOSPOOKS
10309ef1f84bSDavid du Colombier 
10319ef1f84bSDavid du Colombier static int
parseencryptalg(char * p,Dstate * s)10329ef1f84bSDavid du Colombier parseencryptalg(char *p, Dstate *s)
10339ef1f84bSDavid du Colombier {
10349ef1f84bSDavid du Colombier 	Encalg *ea;
10359ef1f84bSDavid du Colombier 
10369ef1f84bSDavid du Colombier 	for(ea = encrypttab; ea->name; ea++){
10379ef1f84bSDavid du Colombier 		if(strcmp(p, ea->name) == 0){
10389ef1f84bSDavid du Colombier 			s->encryptalg = ea->alg;
10399ef1f84bSDavid du Colombier 			s->blocklen = ea->blocklen;
10409ef1f84bSDavid du Colombier 			(*ea->keyinit)(&s->in);
10419ef1f84bSDavid du Colombier 			(*ea->keyinit)(&s->out);
10429ef1f84bSDavid du Colombier 			s->state &= ~Sclear;
10439ef1f84bSDavid du Colombier 			s->state |= Sencrypting;
10449ef1f84bSDavid du Colombier 			return 0;
10459ef1f84bSDavid du Colombier 		}
10469ef1f84bSDavid du Colombier 	}
10479ef1f84bSDavid du Colombier 	return -1;
10489ef1f84bSDavid du Colombier }
10499ef1f84bSDavid du Colombier 
10509ef1f84bSDavid du Colombier static long
sslwrite(Chan * c,void * a,long n,vlong)10519ef1f84bSDavid du Colombier sslwrite(Chan *c, void *a, long n, vlong)
10529ef1f84bSDavid du Colombier {
10539ef1f84bSDavid du Colombier 	Dstate * volatile s;
10549ef1f84bSDavid du Colombier 	Block * volatile b;
10559ef1f84bSDavid du Colombier 	int l, t;
10569ef1f84bSDavid du Colombier 	char *p, *np, *e, buf[128];
10579ef1f84bSDavid du Colombier 	uchar *x;
10589ef1f84bSDavid du Colombier 
1059*406c76faSDavid du Colombier 	x = nil;
10609ef1f84bSDavid du Colombier 	s = dstate[CONV(c->qid)];
10619ef1f84bSDavid du Colombier 	if(s == 0)
10629ef1f84bSDavid du Colombier 		panic("sslwrite");
10639ef1f84bSDavid du Colombier 
10649ef1f84bSDavid du Colombier 	t = TYPE(c->qid);
10659ef1f84bSDavid du Colombier 	if(t == Qdata){
10669ef1f84bSDavid du Colombier 		if(s->state == Sincomplete)
10679ef1f84bSDavid du Colombier 			error(Ebadusefd);
10689ef1f84bSDavid du Colombier 
10699ef1f84bSDavid du Colombier 		/* lock should a write gets split over multiple records */
10709ef1f84bSDavid du Colombier 		if(waserror()){
10719ef1f84bSDavid du Colombier 			qunlock(&s->out.q);
10729ef1f84bSDavid du Colombier 			nexterror();
10739ef1f84bSDavid du Colombier 		}
10749ef1f84bSDavid du Colombier 		qlock(&s->out.q);
10759ef1f84bSDavid du Colombier 
10769ef1f84bSDavid du Colombier 		p = a;
10779ef1f84bSDavid du Colombier 		e = p + n;
10789ef1f84bSDavid du Colombier 		do {
10799ef1f84bSDavid du Colombier 			l = e - p;
10809ef1f84bSDavid du Colombier 			if(l > s->max)
10819ef1f84bSDavid du Colombier 				l = s->max;
10829ef1f84bSDavid du Colombier 
10839ef1f84bSDavid du Colombier 			b = allocb(l);
10849ef1f84bSDavid du Colombier 			if(waserror()){
10859ef1f84bSDavid du Colombier 				freeb(b);
10869ef1f84bSDavid du Colombier 				nexterror();
10879ef1f84bSDavid du Colombier 			}
10889ef1f84bSDavid du Colombier 			memmove(b->wp, p, l);
10899ef1f84bSDavid du Colombier 			poperror();
10909ef1f84bSDavid du Colombier 			b->wp += l;
10919ef1f84bSDavid du Colombier 
10929ef1f84bSDavid du Colombier 			sslput(s, b);
10939ef1f84bSDavid du Colombier 
10949ef1f84bSDavid du Colombier 			p += l;
10959ef1f84bSDavid du Colombier 		} while(p < e);
10969ef1f84bSDavid du Colombier 
10979ef1f84bSDavid du Colombier 		poperror();
10989ef1f84bSDavid du Colombier 		qunlock(&s->out.q);
10999ef1f84bSDavid du Colombier 		return n;
11009ef1f84bSDavid du Colombier 	}
11019ef1f84bSDavid du Colombier 
11029ef1f84bSDavid du Colombier 	/* mutex with operations using what we're about to change */
11039ef1f84bSDavid du Colombier 	if(waserror()){
11049ef1f84bSDavid du Colombier 		qunlock(&s->in.ctlq);
11059ef1f84bSDavid du Colombier 		qunlock(&s->out.q);
11069ef1f84bSDavid du Colombier 		nexterror();
11079ef1f84bSDavid du Colombier 	}
11089ef1f84bSDavid du Colombier 	qlock(&s->in.ctlq);
11099ef1f84bSDavid du Colombier 	qlock(&s->out.q);
11109ef1f84bSDavid du Colombier 
11119ef1f84bSDavid du Colombier 	switch(t){
11129ef1f84bSDavid du Colombier 	default:
11139ef1f84bSDavid du Colombier 		panic("sslwrite");
11149ef1f84bSDavid du Colombier 	case Qsecretin:
11159ef1f84bSDavid du Colombier 		setsecret(&s->in, a, n);
11169ef1f84bSDavid du Colombier 		goto out;
11179ef1f84bSDavid du Colombier 	case Qsecretout:
11189ef1f84bSDavid du Colombier 		setsecret(&s->out, a, n);
11199ef1f84bSDavid du Colombier 		goto out;
11209ef1f84bSDavid du Colombier 	case Qctl:
11219ef1f84bSDavid du Colombier 		break;
11229ef1f84bSDavid du Colombier 	}
11239ef1f84bSDavid du Colombier 
11249ef1f84bSDavid du Colombier 	if(n >= sizeof(buf))
11259ef1f84bSDavid du Colombier 		error("arg too long");
11269ef1f84bSDavid du Colombier 	strncpy(buf, a, n);
11279ef1f84bSDavid du Colombier 	buf[n] = 0;
11289ef1f84bSDavid du Colombier 	p = strchr(buf, '\n');
11299ef1f84bSDavid du Colombier 	if(p)
11309ef1f84bSDavid du Colombier 		*p = 0;
11319ef1f84bSDavid du Colombier 	p = strchr(buf, ' ');
11329ef1f84bSDavid du Colombier 	if(p)
11339ef1f84bSDavid du Colombier 		*p++ = 0;
11349ef1f84bSDavid du Colombier 
1135*406c76faSDavid du Colombier 	if(waserror()){
1136*406c76faSDavid du Colombier 		free(x);
1137*406c76faSDavid du Colombier 		nexterror();
1138*406c76faSDavid du Colombier 	}
11399ef1f84bSDavid du Colombier 	if(strcmp(buf, "fd") == 0){
11409ef1f84bSDavid du Colombier 		s->c = buftochan(p);
11419ef1f84bSDavid du Colombier 
11429ef1f84bSDavid du Colombier 		/* default is clear (msg delimiters only) */
11439ef1f84bSDavid du Colombier 		s->state = Sclear;
11449ef1f84bSDavid du Colombier 		s->blocklen = 1;
11459ef1f84bSDavid du Colombier 		s->diglen = 0;
11469ef1f84bSDavid du Colombier 		s->maxpad = s->max = (1<<15) - s->diglen - 1;
11479ef1f84bSDavid du Colombier 		s->in.mid = 0;
11489ef1f84bSDavid du Colombier 		s->out.mid = 0;
11499ef1f84bSDavid du Colombier 	} else if(strcmp(buf, "alg") == 0 && p != 0){
11509ef1f84bSDavid du Colombier 		s->blocklen = 1;
11519ef1f84bSDavid du Colombier 		s->diglen = 0;
11529ef1f84bSDavid du Colombier 
11539ef1f84bSDavid du Colombier 		if(s->c == 0)
11549ef1f84bSDavid du Colombier 			error("must set fd before algorithm");
11559ef1f84bSDavid du Colombier 
11569ef1f84bSDavid du Colombier 		s->state = Sclear;
11579ef1f84bSDavid du Colombier 		s->maxpad = s->max = (1<<15) - s->diglen - 1;
1158*406c76faSDavid du Colombier 		if(strcmp(p, "clear") == 0)
1159*406c76faSDavid du Colombier 			goto outx;
11609ef1f84bSDavid du Colombier 
11619ef1f84bSDavid du Colombier 		if(s->in.secret && s->out.secret == 0)
11629ef1f84bSDavid du Colombier 			setsecret(&s->out, s->in.secret, s->in.slen);
11639ef1f84bSDavid du Colombier 		if(s->out.secret && s->in.secret == 0)
11649ef1f84bSDavid du Colombier 			setsecret(&s->in, s->out.secret, s->out.slen);
11659ef1f84bSDavid du Colombier 		if(s->in.secret == 0 || s->out.secret == 0)
11669ef1f84bSDavid du Colombier 			error("algorithm but no secret");
11679ef1f84bSDavid du Colombier 
11689ef1f84bSDavid du Colombier 		s->hf = 0;
11699ef1f84bSDavid du Colombier 		s->encryptalg = Noencryption;
11709ef1f84bSDavid du Colombier 		s->blocklen = 1;
11719ef1f84bSDavid du Colombier 
11729ef1f84bSDavid du Colombier 		for(;;){
11739ef1f84bSDavid du Colombier 			np = strchr(p, ' ');
11749ef1f84bSDavid du Colombier 			if(np)
11759ef1f84bSDavid du Colombier 				*np++ = 0;
11769ef1f84bSDavid du Colombier 
11779ef1f84bSDavid du Colombier 			if(parsehashalg(p, s) < 0)
11789ef1f84bSDavid du Colombier 			if(parseencryptalg(p, s) < 0)
11799ef1f84bSDavid du Colombier 				error("bad algorithm");
11809ef1f84bSDavid du Colombier 
11819ef1f84bSDavid du Colombier 			if(np == 0)
11829ef1f84bSDavid du Colombier 				break;
11839ef1f84bSDavid du Colombier 			p = np;
11849ef1f84bSDavid du Colombier 		}
11859ef1f84bSDavid du Colombier 
11869ef1f84bSDavid du Colombier 		if(s->hf == 0 && s->encryptalg == Noencryption)
11879ef1f84bSDavid du Colombier 			error("bad algorithm");
11889ef1f84bSDavid du Colombier 
11899ef1f84bSDavid du Colombier 		if(s->blocklen != 1){
11909ef1f84bSDavid du Colombier 			s->max = (1<<15) - s->diglen - 1;
11919ef1f84bSDavid du Colombier 			s->max -= s->max % s->blocklen;
11929ef1f84bSDavid du Colombier 			s->maxpad = (1<<14) - s->diglen - 1;
11939ef1f84bSDavid du Colombier 			s->maxpad -= s->maxpad % s->blocklen;
11949ef1f84bSDavid du Colombier 		} else
11959ef1f84bSDavid du Colombier 			s->maxpad = s->max = (1<<15) - s->diglen - 1;
11969ef1f84bSDavid du Colombier 	} else if(strcmp(buf, "secretin") == 0 && p != 0) {
11979ef1f84bSDavid du Colombier 		l = (strlen(p)*3)/2;
11989ef1f84bSDavid du Colombier 		x = smalloc(l);
11999ef1f84bSDavid du Colombier 		t = dec64(x, l, p, strlen(p));
1200*406c76faSDavid du Colombier 		if(t <= 0)
1201*406c76faSDavid du Colombier 			error(Ebadarg);
12029ef1f84bSDavid du Colombier 		setsecret(&s->in, x, t);
12039ef1f84bSDavid du Colombier 	} else if(strcmp(buf, "secretout") == 0 && p != 0) {
12049ef1f84bSDavid du Colombier 		l = (strlen(p)*3)/2 + 1;
12059ef1f84bSDavid du Colombier 		x = smalloc(l);
12069ef1f84bSDavid du Colombier 		t = dec64(x, l, p, strlen(p));
1207*406c76faSDavid du Colombier 		if(t <= 0)
1208*406c76faSDavid du Colombier 			error(Ebadarg);
12099ef1f84bSDavid du Colombier 		setsecret(&s->out, x, t);
12109ef1f84bSDavid du Colombier 	} else
12119ef1f84bSDavid du Colombier 		error(Ebadarg);
1212*406c76faSDavid du Colombier outx:
1213*406c76faSDavid du Colombier 	free(x);
1214*406c76faSDavid du Colombier 	poperror();
12159ef1f84bSDavid du Colombier out:
12169ef1f84bSDavid du Colombier 	qunlock(&s->in.ctlq);
12179ef1f84bSDavid du Colombier 	qunlock(&s->out.q);
12189ef1f84bSDavid du Colombier 	poperror();
12199ef1f84bSDavid du Colombier 	return n;
12209ef1f84bSDavid du Colombier }
12219ef1f84bSDavid du Colombier 
12229ef1f84bSDavid du Colombier static void
sslinit(void)12239ef1f84bSDavid du Colombier sslinit(void)
12249ef1f84bSDavid du Colombier {
12259ef1f84bSDavid du Colombier 	struct Encalg *e;
12269ef1f84bSDavid du Colombier 	struct Hashalg *h;
12279ef1f84bSDavid du Colombier 	int n;
12289ef1f84bSDavid du Colombier 	char *cp;
12299ef1f84bSDavid du Colombier 
12309ef1f84bSDavid du Colombier 	n = 1;
12319ef1f84bSDavid du Colombier 	for(e = encrypttab; e->name != nil; e++)
12329ef1f84bSDavid du Colombier 		n += strlen(e->name) + 1;
12339ef1f84bSDavid du Colombier 	cp = encalgs = smalloc(n);
12349ef1f84bSDavid du Colombier 	for(e = encrypttab;;){
12359ef1f84bSDavid du Colombier 		strcpy(cp, e->name);
12369ef1f84bSDavid du Colombier 		cp += strlen(e->name);
12379ef1f84bSDavid du Colombier 		e++;
12389ef1f84bSDavid du Colombier 		if(e->name == nil)
12399ef1f84bSDavid du Colombier 			break;
12409ef1f84bSDavid du Colombier 		*cp++ = ' ';
12419ef1f84bSDavid du Colombier 	}
12429ef1f84bSDavid du Colombier 	*cp = 0;
12439ef1f84bSDavid du Colombier 
12449ef1f84bSDavid du Colombier 	n = 1;
12459ef1f84bSDavid du Colombier 	for(h = hashtab; h->name != nil; h++)
12469ef1f84bSDavid du Colombier 		n += strlen(h->name) + 1;
12479ef1f84bSDavid du Colombier 	cp = hashalgs = smalloc(n);
12489ef1f84bSDavid du Colombier 	for(h = hashtab;;){
12499ef1f84bSDavid du Colombier 		strcpy(cp, h->name);
12509ef1f84bSDavid du Colombier 		cp += strlen(h->name);
12519ef1f84bSDavid du Colombier 		h++;
12529ef1f84bSDavid du Colombier 		if(h->name == nil)
12539ef1f84bSDavid du Colombier 			break;
12549ef1f84bSDavid du Colombier 		*cp++ = ' ';
12559ef1f84bSDavid du Colombier 	}
12569ef1f84bSDavid du Colombier 	*cp = 0;
12579ef1f84bSDavid du Colombier }
12589ef1f84bSDavid du Colombier 
12599ef1f84bSDavid du Colombier Dev ssldevtab = {
12609ef1f84bSDavid du Colombier 	'D',
12619ef1f84bSDavid du Colombier 	"ssl",
12629ef1f84bSDavid du Colombier 
12639ef1f84bSDavid du Colombier 	devreset,
12649ef1f84bSDavid du Colombier 	sslinit,
12659ef1f84bSDavid du Colombier 	devshutdown,
12669ef1f84bSDavid du Colombier 	sslattach,
12679ef1f84bSDavid du Colombier 	sslwalk,
12689ef1f84bSDavid du Colombier 	sslstat,
12699ef1f84bSDavid du Colombier 	sslopen,
12709ef1f84bSDavid du Colombier 	devcreate,
12719ef1f84bSDavid du Colombier 	sslclose,
12729ef1f84bSDavid du Colombier 	sslread,
12739ef1f84bSDavid du Colombier 	sslbread,
12749ef1f84bSDavid du Colombier 	sslwrite,
12759ef1f84bSDavid du Colombier 	sslbwrite,
12769ef1f84bSDavid du Colombier 	devremove,
12779ef1f84bSDavid du Colombier 	sslwstat,
12789ef1f84bSDavid du Colombier };
12799ef1f84bSDavid du Colombier 
12809ef1f84bSDavid du Colombier static Block*
encryptb(Dstate * s,Block * b,int offset)12819ef1f84bSDavid du Colombier encryptb(Dstate *s, Block *b, int offset)
12829ef1f84bSDavid du Colombier {
12839ef1f84bSDavid du Colombier 	uchar *p, *ep, *p2, *ip, *eip;
12849ef1f84bSDavid du Colombier 	DESstate *ds;
12859ef1f84bSDavid du Colombier 
12869ef1f84bSDavid du Colombier 	switch(s->encryptalg){
12879ef1f84bSDavid du Colombier 	case DESECB:
12889ef1f84bSDavid du Colombier 		ds = s->out.state;
12899ef1f84bSDavid du Colombier 		ep = b->rp + BLEN(b);
12909ef1f84bSDavid du Colombier 		for(p = b->rp + offset; p < ep; p += 8)
12919ef1f84bSDavid du Colombier 			block_cipher(ds->expanded, p, 0);
12929ef1f84bSDavid du Colombier 		break;
12939ef1f84bSDavid du Colombier 	case DESCBC:
12949ef1f84bSDavid du Colombier 		ds = s->out.state;
12959ef1f84bSDavid du Colombier 		ep = b->rp + BLEN(b);
12969ef1f84bSDavid du Colombier 		for(p = b->rp + offset; p < ep; p += 8){
12979ef1f84bSDavid du Colombier 			p2 = p;
12989ef1f84bSDavid du Colombier 			ip = ds->ivec;
12999ef1f84bSDavid du Colombier 			for(eip = ip+8; ip < eip; )
13009ef1f84bSDavid du Colombier 				*p2++ ^= *ip++;
13019ef1f84bSDavid du Colombier 			block_cipher(ds->expanded, p, 0);
13029ef1f84bSDavid du Colombier 			memmove(ds->ivec, p, 8);
13039ef1f84bSDavid du Colombier 		}
13049ef1f84bSDavid du Colombier 		break;
13059ef1f84bSDavid du Colombier 	case RC4:
13069ef1f84bSDavid du Colombier 		rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
13079ef1f84bSDavid du Colombier 		break;
13089ef1f84bSDavid du Colombier 	}
13099ef1f84bSDavid du Colombier 	return b;
13109ef1f84bSDavid du Colombier }
13119ef1f84bSDavid du Colombier 
13129ef1f84bSDavid du Colombier static Block*
decryptb(Dstate * s,Block * bin)13139ef1f84bSDavid du Colombier decryptb(Dstate *s, Block *bin)
13149ef1f84bSDavid du Colombier {
13159ef1f84bSDavid du Colombier 	Block *b, **l;
13169ef1f84bSDavid du Colombier 	uchar *p, *ep, *tp, *ip, *eip;
13179ef1f84bSDavid du Colombier 	DESstate *ds;
13189ef1f84bSDavid du Colombier 	uchar tmp[8];
13199ef1f84bSDavid du Colombier 	int i;
13209ef1f84bSDavid du Colombier 
13219ef1f84bSDavid du Colombier 	l = &bin;
13229ef1f84bSDavid du Colombier 	for(b = bin; b; b = b->next){
13239ef1f84bSDavid du Colombier 		/* make sure we have a multiple of s->blocklen */
13249ef1f84bSDavid du Colombier 		if(s->blocklen > 1){
13259ef1f84bSDavid du Colombier 			i = BLEN(b);
13269ef1f84bSDavid du Colombier 			if(i % s->blocklen){
13279ef1f84bSDavid du Colombier 				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
13289ef1f84bSDavid du Colombier 				if(b == 0)
13299ef1f84bSDavid du Colombier 					error("ssl encrypted message too short");
13309ef1f84bSDavid du Colombier 			}
13319ef1f84bSDavid du Colombier 		}
13329ef1f84bSDavid du Colombier 		l = &b->next;
13339ef1f84bSDavid du Colombier 
13349ef1f84bSDavid du Colombier 		/* decrypt */
13359ef1f84bSDavid du Colombier 		switch(s->encryptalg){
13369ef1f84bSDavid du Colombier 		case DESECB:
13379ef1f84bSDavid du Colombier 			ds = s->in.state;
13389ef1f84bSDavid du Colombier 			ep = b->rp + BLEN(b);
13399ef1f84bSDavid du Colombier 			for(p = b->rp; p < ep; p += 8)
13409ef1f84bSDavid du Colombier 				block_cipher(ds->expanded, p, 1);
13419ef1f84bSDavid du Colombier 			break;
13429ef1f84bSDavid du Colombier 		case DESCBC:
13439ef1f84bSDavid du Colombier 			ds = s->in.state;
13449ef1f84bSDavid du Colombier 			ep = b->rp + BLEN(b);
13459ef1f84bSDavid du Colombier 			for(p = b->rp; p < ep;){
13469ef1f84bSDavid du Colombier 				memmove(tmp, p, 8);
13479ef1f84bSDavid du Colombier 				block_cipher(ds->expanded, p, 1);
13489ef1f84bSDavid du Colombier 				tp = tmp;
13499ef1f84bSDavid du Colombier 				ip = ds->ivec;
13509ef1f84bSDavid du Colombier 				for(eip = ip+8; ip < eip; ){
13519ef1f84bSDavid du Colombier 					*p++ ^= *ip;
13529ef1f84bSDavid du Colombier 					*ip++ = *tp++;
13539ef1f84bSDavid du Colombier 				}
13549ef1f84bSDavid du Colombier 			}
13559ef1f84bSDavid du Colombier 			break;
13569ef1f84bSDavid du Colombier 		case RC4:
13579ef1f84bSDavid du Colombier 			rc4(s->in.state, b->rp, BLEN(b));
13589ef1f84bSDavid du Colombier 			break;
13599ef1f84bSDavid du Colombier 		}
13609ef1f84bSDavid du Colombier 	}
13619ef1f84bSDavid du Colombier 	return bin;
13629ef1f84bSDavid du Colombier }
13639ef1f84bSDavid du Colombier 
13649ef1f84bSDavid du Colombier static Block*
digestb(Dstate * s,Block * b,int offset)13659ef1f84bSDavid du Colombier digestb(Dstate *s, Block *b, int offset)
13669ef1f84bSDavid du Colombier {
13679ef1f84bSDavid du Colombier 	uchar *p;
13689ef1f84bSDavid du Colombier 	DigestState ss;
13699ef1f84bSDavid du Colombier 	uchar msgid[4];
13709ef1f84bSDavid du Colombier 	ulong n, h;
13719ef1f84bSDavid du Colombier 	OneWay *w;
13729ef1f84bSDavid du Colombier 
13739ef1f84bSDavid du Colombier 	w = &s->out;
13749ef1f84bSDavid du Colombier 
13759ef1f84bSDavid du Colombier 	memset(&ss, 0, sizeof(ss));
13769ef1f84bSDavid du Colombier 	h = s->diglen + offset;
13779ef1f84bSDavid du Colombier 	n = BLEN(b) - h;
13789ef1f84bSDavid du Colombier 
13799ef1f84bSDavid du Colombier 	/* hash secret + message */
13809ef1f84bSDavid du Colombier 	(*s->hf)(w->secret, w->slen, 0, &ss);
13819ef1f84bSDavid du Colombier 	(*s->hf)(b->rp + h, n, 0, &ss);
13829ef1f84bSDavid du Colombier 
13839ef1f84bSDavid du Colombier 	/* hash message id */
13849ef1f84bSDavid du Colombier 	p = msgid;
13859ef1f84bSDavid du Colombier 	n = w->mid;
13869ef1f84bSDavid du Colombier 	*p++ = n>>24;
13879ef1f84bSDavid du Colombier 	*p++ = n>>16;
13889ef1f84bSDavid du Colombier 	*p++ = n>>8;
13899ef1f84bSDavid du Colombier 	*p = n;
13909ef1f84bSDavid du Colombier 	(*s->hf)(msgid, 4, b->rp + offset, &ss);
13919ef1f84bSDavid du Colombier 
13929ef1f84bSDavid du Colombier 	return b;
13939ef1f84bSDavid du Colombier }
13949ef1f84bSDavid du Colombier 
13959ef1f84bSDavid du Colombier static void
checkdigestb(Dstate * s,Block * bin)13969ef1f84bSDavid du Colombier checkdigestb(Dstate *s, Block *bin)
13979ef1f84bSDavid du Colombier {
13989ef1f84bSDavid du Colombier 	uchar *p;
13999ef1f84bSDavid du Colombier 	DigestState ss;
14009ef1f84bSDavid du Colombier 	uchar msgid[4];
14019ef1f84bSDavid du Colombier 	int n, h;
14029ef1f84bSDavid du Colombier 	OneWay *w;
14039ef1f84bSDavid du Colombier 	uchar digest[128];
14049ef1f84bSDavid du Colombier 	Block *b;
14059ef1f84bSDavid du Colombier 
14069ef1f84bSDavid du Colombier 	w = &s->in;
14079ef1f84bSDavid du Colombier 
14089ef1f84bSDavid du Colombier 	memset(&ss, 0, sizeof(ss));
14099ef1f84bSDavid du Colombier 
14109ef1f84bSDavid du Colombier 	/* hash secret */
14119ef1f84bSDavid du Colombier 	(*s->hf)(w->secret, w->slen, 0, &ss);
14129ef1f84bSDavid du Colombier 
14139ef1f84bSDavid du Colombier 	/* hash message */
14149ef1f84bSDavid du Colombier 	h = s->diglen;
14159ef1f84bSDavid du Colombier 	for(b = bin; b; b = b->next){
14169ef1f84bSDavid du Colombier 		n = BLEN(b) - h;
14179ef1f84bSDavid du Colombier 		if(n < 0)
14189ef1f84bSDavid du Colombier 			panic("checkdigestb");
14199ef1f84bSDavid du Colombier 		(*s->hf)(b->rp + h, n, 0, &ss);
14209ef1f84bSDavid du Colombier 		h = 0;
14219ef1f84bSDavid du Colombier 	}
14229ef1f84bSDavid du Colombier 
14239ef1f84bSDavid du Colombier 	/* hash message id */
14249ef1f84bSDavid du Colombier 	p = msgid;
14259ef1f84bSDavid du Colombier 	n = w->mid;
14269ef1f84bSDavid du Colombier 	*p++ = n>>24;
14279ef1f84bSDavid du Colombier 	*p++ = n>>16;
14289ef1f84bSDavid du Colombier 	*p++ = n>>8;
14299ef1f84bSDavid du Colombier 	*p = n;
14309ef1f84bSDavid du Colombier 	(*s->hf)(msgid, 4, digest, &ss);
14319ef1f84bSDavid du Colombier 
14329ef1f84bSDavid du Colombier 	if(memcmp(digest, bin->rp, s->diglen) != 0)
14339ef1f84bSDavid du Colombier 		error("bad digest");
14349ef1f84bSDavid du Colombier }
14359ef1f84bSDavid du Colombier 
14369ef1f84bSDavid du Colombier /* get channel associated with an fd */
14379ef1f84bSDavid du Colombier static Chan*
buftochan(char * p)14389ef1f84bSDavid du Colombier buftochan(char *p)
14399ef1f84bSDavid du Colombier {
14409ef1f84bSDavid du Colombier 	Chan *c;
14419ef1f84bSDavid du Colombier 	int fd;
14429ef1f84bSDavid du Colombier 
14439ef1f84bSDavid du Colombier 	if(p == 0)
14449ef1f84bSDavid du Colombier 		error(Ebadarg);
14459ef1f84bSDavid du Colombier 	fd = strtoul(p, 0, 0);
14469ef1f84bSDavid du Colombier 	if(fd < 0)
14479ef1f84bSDavid du Colombier 		error(Ebadarg);
14489ef1f84bSDavid du Colombier 	c = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
14499ef1f84bSDavid du Colombier 	if(c->dev == &ssldevtab){
14509ef1f84bSDavid du Colombier 		cclose(c);
14519ef1f84bSDavid du Colombier 		error("cannot ssl encrypt devssl files");
14529ef1f84bSDavid du Colombier 	}
14539ef1f84bSDavid du Colombier 	return c;
14549ef1f84bSDavid du Colombier }
14559ef1f84bSDavid du Colombier 
14569ef1f84bSDavid du Colombier /* hand up a digest connection */
14579ef1f84bSDavid du Colombier static void
sslhangup(Dstate * s)14589ef1f84bSDavid du Colombier sslhangup(Dstate *s)
14599ef1f84bSDavid du Colombier {
14609ef1f84bSDavid du Colombier 	Block *b;
14619ef1f84bSDavid du Colombier 
14629ef1f84bSDavid du Colombier 	qlock(&s->in.q);
14639ef1f84bSDavid du Colombier 	for(b = s->processed; b; b = s->processed){
14649ef1f84bSDavid du Colombier 		s->processed = b->next;
14659ef1f84bSDavid du Colombier 		freeb(b);
14669ef1f84bSDavid du Colombier 	}
14679ef1f84bSDavid du Colombier 	if(s->unprocessed){
14689ef1f84bSDavid du Colombier 		freeb(s->unprocessed);
14699ef1f84bSDavid du Colombier 		s->unprocessed = 0;
14709ef1f84bSDavid du Colombier 	}
14719ef1f84bSDavid du Colombier 	s->state = Sincomplete;
14729ef1f84bSDavid du Colombier 	qunlock(&s->in.q);
14739ef1f84bSDavid du Colombier }
14749ef1f84bSDavid du Colombier 
14759ef1f84bSDavid du Colombier static Dstate*
dsclone(Chan * ch)14769ef1f84bSDavid du Colombier dsclone(Chan *ch)
14779ef1f84bSDavid du Colombier {
14789ef1f84bSDavid du Colombier 	int i;
14799ef1f84bSDavid du Colombier 	Dstate *ret;
14809ef1f84bSDavid du Colombier 
14819ef1f84bSDavid du Colombier 	if(waserror()) {
14829ef1f84bSDavid du Colombier 		unlock(&dslock);
14839ef1f84bSDavid du Colombier 		nexterror();
14849ef1f84bSDavid du Colombier 	}
14859ef1f84bSDavid du Colombier 	lock(&dslock);
14869ef1f84bSDavid du Colombier 	ret = nil;
14879ef1f84bSDavid du Colombier 	for(i=0; i<Maxdstate; i++){
14889ef1f84bSDavid du Colombier 		if(dstate[i] == nil){
14899ef1f84bSDavid du Colombier 			dsnew(ch, &dstate[i]);
14909ef1f84bSDavid du Colombier 			ret = dstate[i];
14919ef1f84bSDavid du Colombier 			break;
14929ef1f84bSDavid du Colombier 		}
14939ef1f84bSDavid du Colombier 	}
14949ef1f84bSDavid du Colombier 	unlock(&dslock);
14959ef1f84bSDavid du Colombier 	poperror();
14969ef1f84bSDavid du Colombier 	return ret;
14979ef1f84bSDavid du Colombier }
14989ef1f84bSDavid du Colombier 
14999ef1f84bSDavid du Colombier static void
dsnew(Chan * ch,Dstate ** pp)15009ef1f84bSDavid du Colombier dsnew(Chan *ch, Dstate **pp)
15019ef1f84bSDavid du Colombier {
15029ef1f84bSDavid du Colombier 	Dstate *s;
15039ef1f84bSDavid du Colombier 	int t;
15049ef1f84bSDavid du Colombier 
15059ef1f84bSDavid du Colombier 	*pp = s = malloc(sizeof(*s));
15069ef1f84bSDavid du Colombier 	if(!s)
15079ef1f84bSDavid du Colombier 		error(Enomem);
15089ef1f84bSDavid du Colombier 	if(pp - dstate >= dshiwat)
15099ef1f84bSDavid du Colombier 		dshiwat++;
15109ef1f84bSDavid du Colombier 	memset(s, 0, sizeof(*s));
15119ef1f84bSDavid du Colombier 	s->state = Sincomplete;
15129ef1f84bSDavid du Colombier 	s->ref = 1;
15139ef1f84bSDavid du Colombier 	kstrdup(&s->user, up->user);
15149ef1f84bSDavid du Colombier 	s->perm = 0660;
15159ef1f84bSDavid du Colombier 	t = TYPE(ch->qid);
15169ef1f84bSDavid du Colombier 	if(t == Qclonus)
15179ef1f84bSDavid du Colombier 		t = Qctl;
15189ef1f84bSDavid du Colombier 	ch->qid.path = QID(pp - dstate, t);
15199ef1f84bSDavid du Colombier 	ch->qid.vers = 0;
15209ef1f84bSDavid du Colombier }
1521