xref: /plan9/sys/src/cmd/unix/drawterm/kern/devssl.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
18ccd4a63SDavid du Colombier /*
28ccd4a63SDavid du Colombier  *  devssl - secure sockets layer
38ccd4a63SDavid du Colombier  */
48ccd4a63SDavid du Colombier #include	"u.h"
58ccd4a63SDavid du Colombier #include	"lib.h"
68ccd4a63SDavid du Colombier #include	"dat.h"
78ccd4a63SDavid du Colombier #include	"fns.h"
88ccd4a63SDavid du Colombier #include	"error.h"
98ccd4a63SDavid du Colombier 
108ccd4a63SDavid du Colombier #include	"libsec.h"
118ccd4a63SDavid du Colombier 
128ccd4a63SDavid du Colombier #define NOSPOOKS 1
138ccd4a63SDavid du Colombier 
148ccd4a63SDavid du Colombier typedef struct OneWay OneWay;
158ccd4a63SDavid du Colombier struct OneWay
168ccd4a63SDavid du Colombier {
178ccd4a63SDavid du Colombier 	QLock	q;
188ccd4a63SDavid du Colombier 	QLock	ctlq;
198ccd4a63SDavid du Colombier 
208ccd4a63SDavid du Colombier 	void	*state;		/* encryption state */
218ccd4a63SDavid du Colombier 	int	slen;		/* hash data length */
228ccd4a63SDavid du Colombier 	uchar	*secret;	/* secret */
238ccd4a63SDavid du Colombier 	ulong	mid;		/* message id */
248ccd4a63SDavid du Colombier };
258ccd4a63SDavid du Colombier 
268ccd4a63SDavid du Colombier enum
278ccd4a63SDavid du Colombier {
288ccd4a63SDavid du Colombier 	/* connection states */
298ccd4a63SDavid du Colombier 	Sincomplete=	0,
308ccd4a63SDavid du Colombier 	Sclear=		1,
318ccd4a63SDavid du Colombier 	Sencrypting=	2,
328ccd4a63SDavid du Colombier 	Sdigesting=	4,
338ccd4a63SDavid du Colombier 	Sdigenc=	Sencrypting|Sdigesting,
348ccd4a63SDavid du Colombier 
358ccd4a63SDavid du Colombier 	/* encryption algorithms */
368ccd4a63SDavid du Colombier 	Noencryption=	0,
378ccd4a63SDavid du Colombier 	DESCBC=		1,
388ccd4a63SDavid du Colombier 	DESECB=		2,
398ccd4a63SDavid du Colombier 	RC4=		3
408ccd4a63SDavid du Colombier };
418ccd4a63SDavid du Colombier 
428ccd4a63SDavid du Colombier typedef struct Dstate Dstate;
438ccd4a63SDavid du Colombier struct Dstate
448ccd4a63SDavid du Colombier {
458ccd4a63SDavid du Colombier 	Chan	*c;		/* io channel */
468ccd4a63SDavid du Colombier 	uchar	state;		/* state of connection */
478ccd4a63SDavid du Colombier 	int	ref;		/* serialized by dslock for atomic destroy */
488ccd4a63SDavid du Colombier 
498ccd4a63SDavid du Colombier 	uchar	encryptalg;	/* encryption algorithm */
508ccd4a63SDavid du Colombier 	ushort	blocklen;	/* blocking length */
518ccd4a63SDavid du Colombier 
528ccd4a63SDavid du Colombier 	ushort	diglen;		/* length of digest */
538ccd4a63SDavid du Colombier 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);	/* hash func */
548ccd4a63SDavid du Colombier 
558ccd4a63SDavid du Colombier 	/* for SSL format */
568ccd4a63SDavid du Colombier 	int	max;		/* maximum unpadded data per msg */
578ccd4a63SDavid du Colombier 	int	maxpad;		/* maximum padded data per msg */
588ccd4a63SDavid du Colombier 
598ccd4a63SDavid du Colombier 	/* input side */
608ccd4a63SDavid du Colombier 	OneWay	in;
618ccd4a63SDavid du Colombier 	Block	*processed;
628ccd4a63SDavid du Colombier 	Block	*unprocessed;
638ccd4a63SDavid du Colombier 
648ccd4a63SDavid du Colombier 	/* output side */
658ccd4a63SDavid du Colombier 	OneWay	out;
668ccd4a63SDavid du Colombier 
678ccd4a63SDavid du Colombier 	/* protections */
688ccd4a63SDavid du Colombier 	char	*user;
698ccd4a63SDavid du Colombier 	int	perm;
708ccd4a63SDavid du Colombier };
718ccd4a63SDavid du Colombier 
728ccd4a63SDavid du Colombier enum
738ccd4a63SDavid du Colombier {
748ccd4a63SDavid du Colombier 	Maxdmsg=	1<<16,
758ccd4a63SDavid du Colombier 	Maxdstate=	128,	/* must be a power of 2 */
768ccd4a63SDavid du Colombier };
778ccd4a63SDavid du Colombier 
788ccd4a63SDavid du Colombier Lock	dslock;
798ccd4a63SDavid du Colombier int	dshiwat;
808ccd4a63SDavid du Colombier char	*dsname[Maxdstate];
818ccd4a63SDavid du Colombier Dstate	*dstate[Maxdstate];
828ccd4a63SDavid du Colombier char	*encalgs;
838ccd4a63SDavid du Colombier char	*hashalgs;
848ccd4a63SDavid du Colombier 
858ccd4a63SDavid du Colombier enum{
868ccd4a63SDavid du Colombier 	Qtopdir		= 1,	/* top level directory */
878ccd4a63SDavid du Colombier 	Qprotodir,
888ccd4a63SDavid du Colombier 	Qclonus,
898ccd4a63SDavid du Colombier 	Qconvdir,		/* directory for a conversation */
908ccd4a63SDavid du Colombier 	Qdata,
918ccd4a63SDavid du Colombier 	Qctl,
928ccd4a63SDavid du Colombier 	Qsecretin,
938ccd4a63SDavid du Colombier 	Qsecretout,
948ccd4a63SDavid du Colombier 	Qencalgs,
958ccd4a63SDavid du Colombier 	Qhashalgs,
968ccd4a63SDavid du Colombier };
978ccd4a63SDavid du Colombier 
988ccd4a63SDavid du Colombier #define TYPE(x) 	((x).path & 0xf)
998ccd4a63SDavid du Colombier #define CONV(x) 	(((x).path >> 5)&(Maxdstate-1))
1008ccd4a63SDavid du Colombier #define QID(c, y) 	(((c)<<5) | (y))
1018ccd4a63SDavid du Colombier 
1028ccd4a63SDavid du Colombier static void	ensure(Dstate*, Block**, int);
1038ccd4a63SDavid du Colombier static void	consume(Block**, uchar*, int);
1048ccd4a63SDavid du Colombier static void	setsecret(OneWay*, uchar*, int);
1058ccd4a63SDavid du Colombier static Block*	encryptb(Dstate*, Block*, int);
1068ccd4a63SDavid du Colombier static Block*	decryptb(Dstate*, Block*);
1078ccd4a63SDavid du Colombier static Block*	digestb(Dstate*, Block*, int);
1088ccd4a63SDavid du Colombier static void	checkdigestb(Dstate*, Block*);
1098ccd4a63SDavid du Colombier static Chan*	buftochan(char*);
1108ccd4a63SDavid du Colombier static void	sslhangup(Dstate*);
1118ccd4a63SDavid du Colombier static Dstate*	dsclone(Chan *c);
1128ccd4a63SDavid du Colombier static void	dsnew(Chan *c, Dstate **);
1138ccd4a63SDavid du Colombier static long	sslput(Dstate *s, Block * volatile b);
1148ccd4a63SDavid du Colombier 
1158ccd4a63SDavid du Colombier char *sslnames[] = {
1168ccd4a63SDavid du Colombier 	/* unused */ 0,
1178ccd4a63SDavid du Colombier 	/* topdir */ 0,
1188ccd4a63SDavid du Colombier 	/* protodir */ 0,
1198ccd4a63SDavid du Colombier 	"clone",
1208ccd4a63SDavid du Colombier 	/* convdir */ 0,
1218ccd4a63SDavid du Colombier 	"data",
1228ccd4a63SDavid du Colombier 	"ctl",
1238ccd4a63SDavid du Colombier 	"secretin",
1248ccd4a63SDavid du Colombier 	"secretout",
1258ccd4a63SDavid du Colombier 	"encalgs",
1268ccd4a63SDavid du Colombier 	"hashalgs",
1278ccd4a63SDavid du Colombier };
1288ccd4a63SDavid du Colombier 
1298ccd4a63SDavid du Colombier static int
sslgen(Chan * c,char * n,Dirtab * d,int nd,int s,Dir * dp)1308ccd4a63SDavid du Colombier sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
1318ccd4a63SDavid du Colombier {
1328ccd4a63SDavid du Colombier 	Qid q;
1338ccd4a63SDavid du Colombier 	Dstate *ds;
1348ccd4a63SDavid du Colombier 	char name[16], *p, *nm;
1358ccd4a63SDavid du Colombier 	int ft;
1368ccd4a63SDavid du Colombier 
1378ccd4a63SDavid du Colombier 	USED(n);
1388ccd4a63SDavid du Colombier 	USED(nd);
1398ccd4a63SDavid du Colombier 	USED(d);
1408ccd4a63SDavid du Colombier 
1418ccd4a63SDavid du Colombier 	q.type = QTFILE;
1428ccd4a63SDavid du Colombier 	q.vers = 0;
1438ccd4a63SDavid du Colombier 
1448ccd4a63SDavid du Colombier 	ft = TYPE(c->qid);
1458ccd4a63SDavid du Colombier 	switch(ft) {
1468ccd4a63SDavid du Colombier 	case Qtopdir:
1478ccd4a63SDavid du Colombier 		if(s == DEVDOTDOT){
1488ccd4a63SDavid du Colombier 			q.path = QID(0, Qtopdir);
1498ccd4a63SDavid du Colombier 			q.type = QTDIR;
1508ccd4a63SDavid du Colombier 			devdir(c, q, "#D", 0, eve, 0555, dp);
1518ccd4a63SDavid du Colombier 			return 1;
1528ccd4a63SDavid du Colombier 		}
1538ccd4a63SDavid du Colombier 		if(s > 0)
1548ccd4a63SDavid du Colombier 			return -1;
1558ccd4a63SDavid du Colombier 		q.path = QID(0, Qprotodir);
1568ccd4a63SDavid du Colombier 		q.type = QTDIR;
1578ccd4a63SDavid du Colombier 		devdir(c, q, "ssl", 0, eve, 0555, dp);
1588ccd4a63SDavid du Colombier 		return 1;
1598ccd4a63SDavid du Colombier 	case Qprotodir:
1608ccd4a63SDavid du Colombier 		if(s == DEVDOTDOT){
1618ccd4a63SDavid du Colombier 			q.path = QID(0, Qtopdir);
1628ccd4a63SDavid du Colombier 			q.type = QTDIR;
1638ccd4a63SDavid du Colombier 			devdir(c, q, ".", 0, eve, 0555, dp);
1648ccd4a63SDavid du Colombier 			return 1;
1658ccd4a63SDavid du Colombier 		}
1668ccd4a63SDavid du Colombier 		if(s < dshiwat) {
1678ccd4a63SDavid du Colombier 			q.path = QID(s, Qconvdir);
1688ccd4a63SDavid du Colombier 			q.type = QTDIR;
1698ccd4a63SDavid du Colombier 			ds = dstate[s];
1708ccd4a63SDavid du Colombier 			if(ds != 0)
1718ccd4a63SDavid du Colombier 				nm = ds->user;
1728ccd4a63SDavid du Colombier 			else
1738ccd4a63SDavid du Colombier 				nm = eve;
1748ccd4a63SDavid du Colombier 			if(dsname[s] == nil){
1758ccd4a63SDavid du Colombier 				sprint(name, "%d", s);
1768ccd4a63SDavid du Colombier 				kstrdup(&dsname[s], name);
1778ccd4a63SDavid du Colombier 			}
1788ccd4a63SDavid du Colombier 			devdir(c, q, dsname[s], 0, nm, 0555, dp);
1798ccd4a63SDavid du Colombier 			return 1;
1808ccd4a63SDavid du Colombier 		}
1818ccd4a63SDavid du Colombier 		if(s > dshiwat)
1828ccd4a63SDavid du Colombier 			return -1;
1838ccd4a63SDavid du Colombier 		q.path = QID(0, Qclonus);
1848ccd4a63SDavid du Colombier 		devdir(c, q, "clone", 0, eve, 0555, dp);
1858ccd4a63SDavid du Colombier 		return 1;
1868ccd4a63SDavid du Colombier 	case Qconvdir:
1878ccd4a63SDavid du Colombier 		if(s == DEVDOTDOT){
1888ccd4a63SDavid du Colombier 			q.path = QID(0, Qprotodir);
1898ccd4a63SDavid du Colombier 			q.type = QTDIR;
1908ccd4a63SDavid du Colombier 			devdir(c, q, "ssl", 0, eve, 0555, dp);
1918ccd4a63SDavid du Colombier 			return 1;
1928ccd4a63SDavid du Colombier 		}
1938ccd4a63SDavid du Colombier 		ds = dstate[CONV(c->qid)];
1948ccd4a63SDavid du Colombier 		if(ds != 0)
1958ccd4a63SDavid du Colombier 			nm = ds->user;
1968ccd4a63SDavid du Colombier 		else
1978ccd4a63SDavid du Colombier 			nm = eve;
1988ccd4a63SDavid du Colombier 		switch(s) {
1998ccd4a63SDavid du Colombier 		default:
2008ccd4a63SDavid du Colombier 			return -1;
2018ccd4a63SDavid du Colombier 		case 0:
2028ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qctl);
2038ccd4a63SDavid du Colombier 			p = "ctl";
2048ccd4a63SDavid du Colombier 			break;
2058ccd4a63SDavid du Colombier 		case 1:
2068ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qdata);
2078ccd4a63SDavid du Colombier 			p = "data";
2088ccd4a63SDavid du Colombier 			break;
2098ccd4a63SDavid du Colombier 		case 2:
2108ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qsecretin);
2118ccd4a63SDavid du Colombier 			p = "secretin";
2128ccd4a63SDavid du Colombier 			break;
2138ccd4a63SDavid du Colombier 		case 3:
2148ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qsecretout);
2158ccd4a63SDavid du Colombier 			p = "secretout";
2168ccd4a63SDavid du Colombier 			break;
2178ccd4a63SDavid du Colombier 		case 4:
2188ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qencalgs);
2198ccd4a63SDavid du Colombier 			p = "encalgs";
2208ccd4a63SDavid du Colombier 			break;
2218ccd4a63SDavid du Colombier 		case 5:
2228ccd4a63SDavid du Colombier 			q.path = QID(CONV(c->qid), Qhashalgs);
2238ccd4a63SDavid du Colombier 			p = "hashalgs";
2248ccd4a63SDavid du Colombier 			break;
2258ccd4a63SDavid du Colombier 		}
2268ccd4a63SDavid du Colombier 		devdir(c, q, p, 0, nm, 0660, dp);
2278ccd4a63SDavid du Colombier 		return 1;
2288ccd4a63SDavid du Colombier 	case Qclonus:
2298ccd4a63SDavid du Colombier 		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
2308ccd4a63SDavid du Colombier 		return 1;
2318ccd4a63SDavid du Colombier 	default:
2328ccd4a63SDavid du Colombier 		ds = dstate[CONV(c->qid)];
2338ccd4a63SDavid du Colombier 		if(ds != 0)
2348ccd4a63SDavid du Colombier 			nm = ds->user;
2358ccd4a63SDavid du Colombier 		else
2368ccd4a63SDavid du Colombier 			nm = eve;
2378ccd4a63SDavid du Colombier 		devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
2388ccd4a63SDavid du Colombier 		return 1;
2398ccd4a63SDavid du Colombier 	}
2408ccd4a63SDavid du Colombier 	return -1;
2418ccd4a63SDavid du Colombier }
2428ccd4a63SDavid du Colombier 
2438ccd4a63SDavid du Colombier static Chan*
sslattach(char * spec)2448ccd4a63SDavid du Colombier sslattach(char *spec)
2458ccd4a63SDavid du Colombier {
2468ccd4a63SDavid du Colombier 	Chan *c;
2478ccd4a63SDavid du Colombier 
2488ccd4a63SDavid du Colombier 	c = devattach('D', spec);
2498ccd4a63SDavid du Colombier 	c->qid.path = QID(0, Qtopdir);
2508ccd4a63SDavid du Colombier 	c->qid.vers = 0;
2518ccd4a63SDavid du Colombier 	c->qid.type = QTDIR;
2528ccd4a63SDavid du Colombier 	return c;
2538ccd4a63SDavid du Colombier }
2548ccd4a63SDavid du Colombier 
2558ccd4a63SDavid du Colombier static Walkqid*
sslwalk(Chan * c,Chan * nc,char ** name,int nname)2568ccd4a63SDavid du Colombier sslwalk(Chan *c, Chan *nc, char **name, int nname)
2578ccd4a63SDavid du Colombier {
2588ccd4a63SDavid du Colombier 	return devwalk(c, nc, name, nname, nil, 0, sslgen);
2598ccd4a63SDavid du Colombier }
2608ccd4a63SDavid du Colombier 
2618ccd4a63SDavid du Colombier static int
sslstat(Chan * c,uchar * db,int n)2628ccd4a63SDavid du Colombier sslstat(Chan *c, uchar *db, int n)
2638ccd4a63SDavid du Colombier {
2648ccd4a63SDavid du Colombier 	return devstat(c, db, n, nil, 0, sslgen);
2658ccd4a63SDavid du Colombier }
2668ccd4a63SDavid du Colombier 
2678ccd4a63SDavid du Colombier static Chan*
sslopen(Chan * c,int omode)2688ccd4a63SDavid du Colombier sslopen(Chan *c, int omode)
2698ccd4a63SDavid du Colombier {
2708ccd4a63SDavid du Colombier 	Dstate *s, **pp;
2718ccd4a63SDavid du Colombier 	int perm;
2728ccd4a63SDavid du Colombier 	int ft;
2738ccd4a63SDavid du Colombier 
2748ccd4a63SDavid du Colombier 	perm = 0;
2758ccd4a63SDavid du Colombier 	omode &= 3;
2768ccd4a63SDavid du Colombier 	switch(omode) {
2778ccd4a63SDavid du Colombier 	case OREAD:
2788ccd4a63SDavid du Colombier 		perm = 4;
2798ccd4a63SDavid du Colombier 		break;
2808ccd4a63SDavid du Colombier 	case OWRITE:
2818ccd4a63SDavid du Colombier 		perm = 2;
2828ccd4a63SDavid du Colombier 		break;
2838ccd4a63SDavid du Colombier 	case ORDWR:
2848ccd4a63SDavid du Colombier 		perm = 6;
2858ccd4a63SDavid du Colombier 		break;
2868ccd4a63SDavid du Colombier 	}
2878ccd4a63SDavid du Colombier 
2888ccd4a63SDavid du Colombier 	ft = TYPE(c->qid);
2898ccd4a63SDavid du Colombier 	switch(ft) {
2908ccd4a63SDavid du Colombier 	default:
2918ccd4a63SDavid du Colombier 		panic("sslopen");
2928ccd4a63SDavid du Colombier 	case Qtopdir:
2938ccd4a63SDavid du Colombier 	case Qprotodir:
2948ccd4a63SDavid du Colombier 	case Qconvdir:
2958ccd4a63SDavid du Colombier 		if(omode != OREAD)
2968ccd4a63SDavid du Colombier 			error(Eperm);
2978ccd4a63SDavid du Colombier 		break;
2988ccd4a63SDavid du Colombier 	case Qclonus:
2998ccd4a63SDavid du Colombier 		s = dsclone(c);
3008ccd4a63SDavid du Colombier 		if(s == 0)
3018ccd4a63SDavid du Colombier 			error(Enodev);
3028ccd4a63SDavid du Colombier 		break;
3038ccd4a63SDavid du Colombier 	case Qctl:
3048ccd4a63SDavid du Colombier 	case Qdata:
3058ccd4a63SDavid du Colombier 	case Qsecretin:
3068ccd4a63SDavid du Colombier 	case Qsecretout:
3078ccd4a63SDavid du Colombier 		if(waserror()) {
3088ccd4a63SDavid du Colombier 			unlock(&dslock);
3098ccd4a63SDavid du Colombier 			nexterror();
3108ccd4a63SDavid du Colombier 		}
3118ccd4a63SDavid du Colombier 		lock(&dslock);
3128ccd4a63SDavid du Colombier 		pp = &dstate[CONV(c->qid)];
3138ccd4a63SDavid du Colombier 		s = *pp;
3148ccd4a63SDavid du Colombier 		if(s == 0)
3158ccd4a63SDavid du Colombier 			dsnew(c, pp);
3168ccd4a63SDavid du Colombier 		else {
3178ccd4a63SDavid du Colombier 			if((perm & (s->perm>>6)) != perm
3188ccd4a63SDavid du Colombier 			   && (strcmp(up->user, s->user) != 0
3198ccd4a63SDavid du Colombier 			     || (perm & s->perm) != perm))
3208ccd4a63SDavid du Colombier 				error(Eperm);
3218ccd4a63SDavid du Colombier 
3228ccd4a63SDavid du Colombier 			s->ref++;
3238ccd4a63SDavid du Colombier 		}
3248ccd4a63SDavid du Colombier 		unlock(&dslock);
3258ccd4a63SDavid du Colombier 		poperror();
3268ccd4a63SDavid du Colombier 		break;
3278ccd4a63SDavid du Colombier 	case Qencalgs:
3288ccd4a63SDavid du Colombier 	case Qhashalgs:
3298ccd4a63SDavid du Colombier 		if(omode != OREAD)
3308ccd4a63SDavid du Colombier 			error(Eperm);
3318ccd4a63SDavid du Colombier 		break;
3328ccd4a63SDavid du Colombier 	}
3338ccd4a63SDavid du Colombier 	c->mode = openmode(omode);
3348ccd4a63SDavid du Colombier 	c->flag |= COPEN;
3358ccd4a63SDavid du Colombier 	c->offset = 0;
3368ccd4a63SDavid du Colombier 	return c;
3378ccd4a63SDavid du Colombier }
3388ccd4a63SDavid du Colombier 
3398ccd4a63SDavid du Colombier static int
sslwstat(Chan * c,uchar * db,int n)3408ccd4a63SDavid du Colombier sslwstat(Chan *c, uchar *db, int n)
3418ccd4a63SDavid du Colombier {
3428ccd4a63SDavid du Colombier 	Dir *dir;
3438ccd4a63SDavid du Colombier 	Dstate *s;
3448ccd4a63SDavid du Colombier 	int m;
3458ccd4a63SDavid du Colombier 
3468ccd4a63SDavid du Colombier 	s = dstate[CONV(c->qid)];
3478ccd4a63SDavid du Colombier 	if(s == 0)
3488ccd4a63SDavid du Colombier 		error(Ebadusefd);
3498ccd4a63SDavid du Colombier 	if(strcmp(s->user, up->user) != 0)
3508ccd4a63SDavid du Colombier 		error(Eperm);
3518ccd4a63SDavid du Colombier 
3528ccd4a63SDavid du Colombier 	dir = smalloc(sizeof(Dir)+n);
3538ccd4a63SDavid du Colombier 	m = convM2D(db, n, &dir[0], (char*)&dir[1]);
3548ccd4a63SDavid du Colombier 	if(m == 0){
3558ccd4a63SDavid du Colombier 		free(dir);
3568ccd4a63SDavid du Colombier 		error(Eshortstat);
3578ccd4a63SDavid du Colombier 	}
3588ccd4a63SDavid du Colombier 
3598ccd4a63SDavid du Colombier 	if(!emptystr(dir->uid))
3608ccd4a63SDavid du Colombier 		kstrdup(&s->user, dir->uid);
361*ec59a3ddSDavid du Colombier 	if(dir->mode != ~0)
3628ccd4a63SDavid du Colombier 		s->perm = dir->mode;
3638ccd4a63SDavid du Colombier 
3648ccd4a63SDavid du Colombier 	free(dir);
3658ccd4a63SDavid du Colombier 	return m;
3668ccd4a63SDavid du Colombier }
3678ccd4a63SDavid du Colombier 
3688ccd4a63SDavid du Colombier static void
sslclose(Chan * c)3698ccd4a63SDavid du Colombier sslclose(Chan *c)
3708ccd4a63SDavid du Colombier {
3718ccd4a63SDavid du Colombier 	Dstate *s;
3728ccd4a63SDavid du Colombier 	int ft;
3738ccd4a63SDavid du Colombier 
3748ccd4a63SDavid du Colombier 	ft = TYPE(c->qid);
3758ccd4a63SDavid du Colombier 	switch(ft) {
3768ccd4a63SDavid du Colombier 	case Qctl:
3778ccd4a63SDavid du Colombier 	case Qdata:
3788ccd4a63SDavid du Colombier 	case Qsecretin:
3798ccd4a63SDavid du Colombier 	case Qsecretout:
3808ccd4a63SDavid du Colombier 		if((c->flag & COPEN) == 0)
3818ccd4a63SDavid du Colombier 			break;
3828ccd4a63SDavid du Colombier 
3838ccd4a63SDavid du Colombier 		s = dstate[CONV(c->qid)];
3848ccd4a63SDavid du Colombier 		if(s == 0)
3858ccd4a63SDavid du Colombier 			break;
3868ccd4a63SDavid du Colombier 
3878ccd4a63SDavid du Colombier 		lock(&dslock);
3888ccd4a63SDavid du Colombier 		if(--s->ref > 0) {
3898ccd4a63SDavid du Colombier 			unlock(&dslock);
3908ccd4a63SDavid du Colombier 			break;
3918ccd4a63SDavid du Colombier 		}
3928ccd4a63SDavid du Colombier 		dstate[CONV(c->qid)] = 0;
3938ccd4a63SDavid du Colombier 		unlock(&dslock);
3948ccd4a63SDavid du Colombier 
3958ccd4a63SDavid du Colombier 		if(s->user != nil)
3968ccd4a63SDavid du Colombier 			free(s->user);
3978ccd4a63SDavid du Colombier 		sslhangup(s);
3988ccd4a63SDavid du Colombier 		if(s->c)
3998ccd4a63SDavid du Colombier 			cclose(s->c);
4008ccd4a63SDavid du Colombier 		if(s->in.secret)
4018ccd4a63SDavid du Colombier 			free(s->in.secret);
4028ccd4a63SDavid du Colombier 		if(s->out.secret)
4038ccd4a63SDavid du Colombier 			free(s->out.secret);
4048ccd4a63SDavid du Colombier 		if(s->in.state)
4058ccd4a63SDavid du Colombier 			free(s->in.state);
4068ccd4a63SDavid du Colombier 		if(s->out.state)
4078ccd4a63SDavid du Colombier 			free(s->out.state);
4088ccd4a63SDavid du Colombier 		free(s);
4098ccd4a63SDavid du Colombier 
4108ccd4a63SDavid du Colombier 	}
4118ccd4a63SDavid du Colombier }
4128ccd4a63SDavid du Colombier 
4138ccd4a63SDavid du Colombier /*
4148ccd4a63SDavid du Colombier  *  make sure we have at least 'n' bytes in list 'l'
4158ccd4a63SDavid du Colombier  */
4168ccd4a63SDavid du Colombier static void
ensure(Dstate * s,Block ** l,int n)4178ccd4a63SDavid du Colombier ensure(Dstate *s, Block **l, int n)
4188ccd4a63SDavid du Colombier {
4198ccd4a63SDavid du Colombier 	int sofar, i;
4208ccd4a63SDavid du Colombier 	Block *b, *bl;
4218ccd4a63SDavid du Colombier 
4228ccd4a63SDavid du Colombier 	sofar = 0;
4238ccd4a63SDavid du Colombier 	for(b = *l; b; b = b->next){
4248ccd4a63SDavid du Colombier 		sofar += BLEN(b);
4258ccd4a63SDavid du Colombier 		if(sofar >= n)
4268ccd4a63SDavid du Colombier 			return;
4278ccd4a63SDavid du Colombier 		l = &b->next;
4288ccd4a63SDavid du Colombier 	}
4298ccd4a63SDavid du Colombier 
4308ccd4a63SDavid du Colombier 	while(sofar < n){
4318ccd4a63SDavid du Colombier 		bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
4328ccd4a63SDavid du Colombier 		if(bl == 0)
4338ccd4a63SDavid du Colombier 			nexterror();
4348ccd4a63SDavid du Colombier 		*l = bl;
4358ccd4a63SDavid du Colombier 		i = 0;
4368ccd4a63SDavid du Colombier 		for(b = bl; b; b = b->next){
4378ccd4a63SDavid du Colombier 			i += BLEN(b);
4388ccd4a63SDavid du Colombier 			l = &b->next;
4398ccd4a63SDavid du Colombier 		}
4408ccd4a63SDavid du Colombier 		if(i == 0)
4418ccd4a63SDavid du Colombier 			error(Ehungup);
4428ccd4a63SDavid du Colombier 		sofar += i;
4438ccd4a63SDavid du Colombier 	}
4448ccd4a63SDavid du Colombier }
4458ccd4a63SDavid du Colombier 
4468ccd4a63SDavid du Colombier /*
4478ccd4a63SDavid du Colombier  *  copy 'n' bytes from 'l' into 'p' and free
4488ccd4a63SDavid du Colombier  *  the bytes in 'l'
4498ccd4a63SDavid du Colombier  */
4508ccd4a63SDavid du Colombier static void
consume(Block ** l,uchar * p,int n)4518ccd4a63SDavid du Colombier consume(Block **l, uchar *p, int n)
4528ccd4a63SDavid du Colombier {
4538ccd4a63SDavid du Colombier 	Block *b;
4548ccd4a63SDavid du Colombier 	int i;
4558ccd4a63SDavid du Colombier 
4568ccd4a63SDavid du Colombier 	for(; *l && n > 0; n -= i){
4578ccd4a63SDavid du Colombier 		b = *l;
4588ccd4a63SDavid du Colombier 		i = BLEN(b);
4598ccd4a63SDavid du Colombier 		if(i > n)
4608ccd4a63SDavid du Colombier 			i = n;
4618ccd4a63SDavid du Colombier 		memmove(p, b->rp, i);
4628ccd4a63SDavid du Colombier 		b->rp += i;
4638ccd4a63SDavid du Colombier 		p += i;
4648ccd4a63SDavid du Colombier 		if(BLEN(b) < 0)
4658ccd4a63SDavid du Colombier 			panic("consume");
4668ccd4a63SDavid du Colombier 		if(BLEN(b))
4678ccd4a63SDavid du Colombier 			break;
4688ccd4a63SDavid du Colombier 		*l = b->next;
4698ccd4a63SDavid du Colombier 		freeb(b);
4708ccd4a63SDavid du Colombier 	}
4718ccd4a63SDavid du Colombier }
4728ccd4a63SDavid du Colombier 
4738ccd4a63SDavid du Colombier /*
4748ccd4a63SDavid du Colombier  *  give back n bytes
4758ccd4a63SDavid du Colombier static void
4768ccd4a63SDavid du Colombier regurgitate(Dstate *s, uchar *p, int n)
4778ccd4a63SDavid du Colombier {
4788ccd4a63SDavid du Colombier 	Block *b;
4798ccd4a63SDavid du Colombier 
4808ccd4a63SDavid du Colombier 	if(n <= 0)
4818ccd4a63SDavid du Colombier 		return;
4828ccd4a63SDavid du Colombier 	b = s->unprocessed;
4838ccd4a63SDavid du Colombier 	if(s->unprocessed == nil || b->rp - b->base < n) {
4848ccd4a63SDavid du Colombier 		b = allocb(n);
4858ccd4a63SDavid du Colombier 		memmove(b->wp, p, n);
4868ccd4a63SDavid du Colombier 		b->wp += n;
4878ccd4a63SDavid du Colombier 		b->next = s->unprocessed;
4888ccd4a63SDavid du Colombier 		s->unprocessed = b;
4898ccd4a63SDavid du Colombier 	} else {
4908ccd4a63SDavid du Colombier 		b->rp -= n;
4918ccd4a63SDavid du Colombier 		memmove(b->rp, p, n);
4928ccd4a63SDavid du Colombier 	}
4938ccd4a63SDavid du Colombier }
4948ccd4a63SDavid du Colombier  */
4958ccd4a63SDavid du Colombier 
4968ccd4a63SDavid du Colombier /*
4978ccd4a63SDavid du Colombier  *  remove at most n bytes from the queue, if discard is set
4988ccd4a63SDavid du Colombier  *  dump the remainder
4998ccd4a63SDavid du Colombier  */
5008ccd4a63SDavid du Colombier static Block*
qtake(Block ** l,int n,int discard)5018ccd4a63SDavid du Colombier qtake(Block **l, int n, int discard)
5028ccd4a63SDavid du Colombier {
5038ccd4a63SDavid du Colombier 	Block *nb, *b, *first;
5048ccd4a63SDavid du Colombier 	int i;
5058ccd4a63SDavid du Colombier 
5068ccd4a63SDavid du Colombier 	first = *l;
5078ccd4a63SDavid du Colombier 	for(b = first; b; b = b->next){
5088ccd4a63SDavid du Colombier 		i = BLEN(b);
5098ccd4a63SDavid du Colombier 		if(i == n){
5108ccd4a63SDavid du Colombier 			if(discard){
5118ccd4a63SDavid du Colombier 				freeblist(b->next);
5128ccd4a63SDavid du Colombier 				*l = 0;
5138ccd4a63SDavid du Colombier 			} else
5148ccd4a63SDavid du Colombier 				*l = b->next;
5158ccd4a63SDavid du Colombier 			b->next = 0;
5168ccd4a63SDavid du Colombier 			return first;
5178ccd4a63SDavid du Colombier 		} else if(i > n){
5188ccd4a63SDavid du Colombier 			i -= n;
5198ccd4a63SDavid du Colombier 			if(discard){
5208ccd4a63SDavid du Colombier 				freeblist(b->next);
5218ccd4a63SDavid du Colombier 				b->wp -= i;
5228ccd4a63SDavid du Colombier 				*l = 0;
5238ccd4a63SDavid du Colombier 			} else {
5248ccd4a63SDavid du Colombier 				nb = allocb(i);
5258ccd4a63SDavid du Colombier 				memmove(nb->wp, b->rp+n, i);
5268ccd4a63SDavid du Colombier 				nb->wp += i;
5278ccd4a63SDavid du Colombier 				b->wp -= i;
5288ccd4a63SDavid du Colombier 				nb->next = b->next;
5298ccd4a63SDavid du Colombier 				*l = nb;
5308ccd4a63SDavid du Colombier 			}
5318ccd4a63SDavid du Colombier 			b->next = 0;
5328ccd4a63SDavid du Colombier 			if(BLEN(b) < 0)
5338ccd4a63SDavid du Colombier 				panic("qtake");
5348ccd4a63SDavid du Colombier 			return first;
5358ccd4a63SDavid du Colombier 		} else
5368ccd4a63SDavid du Colombier 			n -= i;
5378ccd4a63SDavid du Colombier 		if(BLEN(b) < 0)
5388ccd4a63SDavid du Colombier 			panic("qtake");
5398ccd4a63SDavid du Colombier 	}
5408ccd4a63SDavid du Colombier 	*l = 0;
5418ccd4a63SDavid du Colombier 	return first;
5428ccd4a63SDavid du Colombier }
5438ccd4a63SDavid du Colombier 
5448ccd4a63SDavid du Colombier /*
5458ccd4a63SDavid du Colombier  *  We can't let Eintr's lose data since the program
5468ccd4a63SDavid du Colombier  *  doing the read may be able to handle it.  The only
5478ccd4a63SDavid du Colombier  *  places Eintr is possible is during the read's in consume.
5488ccd4a63SDavid du Colombier  *  Therefore, we make sure we can always put back the bytes
5498ccd4a63SDavid du Colombier  *  consumed before the last ensure.
5508ccd4a63SDavid du Colombier  */
5518ccd4a63SDavid du Colombier static Block*
sslbread(Chan * c,long n,ulong o)5528ccd4a63SDavid du Colombier sslbread(Chan *c, long n, ulong o)
5538ccd4a63SDavid du Colombier {
5548ccd4a63SDavid du Colombier 	Dstate * volatile s;
5558ccd4a63SDavid du Colombier 	Block *b;
5568ccd4a63SDavid du Colombier 	uchar consumed[3], *p;
5578ccd4a63SDavid du Colombier 	int toconsume;
5588ccd4a63SDavid du Colombier 	int len, pad;
5598ccd4a63SDavid du Colombier 
5608ccd4a63SDavid du Colombier 	USED(o);
5618ccd4a63SDavid du Colombier 	s = dstate[CONV(c->qid)];
5628ccd4a63SDavid du Colombier 	if(s == 0)
5638ccd4a63SDavid du Colombier 		panic("sslbread");
5648ccd4a63SDavid du Colombier 	if(s->state == Sincomplete)
5658ccd4a63SDavid du Colombier 		error(Ebadusefd);
5668ccd4a63SDavid du Colombier 
5678ccd4a63SDavid du Colombier 	qlock(&s->in.q);
5688ccd4a63SDavid du Colombier 	if(waserror()){
5698ccd4a63SDavid du Colombier 		qunlock(&s->in.q);
5708ccd4a63SDavid du Colombier 		nexterror();
5718ccd4a63SDavid du Colombier 	}
5728ccd4a63SDavid du Colombier 
5738ccd4a63SDavid du Colombier 	if(s->processed == 0){
5748ccd4a63SDavid du Colombier 		/*
5758ccd4a63SDavid du Colombier 		 * Read in the whole message.  Until we've got it all,
5768ccd4a63SDavid du Colombier 		 * it stays on s->unprocessed, so that if we get Eintr,
5778ccd4a63SDavid du Colombier 		 * we'll pick up where we left off.
5788ccd4a63SDavid du Colombier 		 */
5798ccd4a63SDavid du Colombier 		ensure(s, &s->unprocessed, 3);
5808ccd4a63SDavid du Colombier 		s->unprocessed = pullupblock(s->unprocessed, 2);
5818ccd4a63SDavid du Colombier 		p = s->unprocessed->rp;
5828ccd4a63SDavid du Colombier 		if(p[0] & 0x80){
5838ccd4a63SDavid du Colombier 			len = ((p[0] & 0x7f)<<8) | p[1];
5848ccd4a63SDavid du Colombier 			ensure(s, &s->unprocessed, len);
5858ccd4a63SDavid du Colombier 			pad = 0;
5868ccd4a63SDavid du Colombier 			toconsume = 2;
5878ccd4a63SDavid du Colombier 		} else {
5888ccd4a63SDavid du Colombier 			s->unprocessed = pullupblock(s->unprocessed, 3);
5898ccd4a63SDavid du Colombier 			len = ((p[0] & 0x3f)<<8) | p[1];
5908ccd4a63SDavid du Colombier 			pad = p[2];
5918ccd4a63SDavid du Colombier 			if(pad > len){
5928ccd4a63SDavid du Colombier 				print("pad %d buf len %d\n", pad, len);
5938ccd4a63SDavid du Colombier 				error("bad pad in ssl message");
5948ccd4a63SDavid du Colombier 			}
5958ccd4a63SDavid du Colombier 			toconsume = 3;
5968ccd4a63SDavid du Colombier 		}
5978ccd4a63SDavid du Colombier 		ensure(s, &s->unprocessed, toconsume+len);
5988ccd4a63SDavid du Colombier 
5998ccd4a63SDavid du Colombier 		/* skip header */
6008ccd4a63SDavid du Colombier 		consume(&s->unprocessed, consumed, toconsume);
6018ccd4a63SDavid du Colombier 
6028ccd4a63SDavid du Colombier 		/* grab the next message and decode/decrypt it */
6038ccd4a63SDavid du Colombier 		b = qtake(&s->unprocessed, len, 0);
6048ccd4a63SDavid du Colombier 
6058ccd4a63SDavid du Colombier 		if(blocklen(b) != len)
6068ccd4a63SDavid du Colombier 			print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
6078ccd4a63SDavid du Colombier 
6088ccd4a63SDavid du Colombier 		if(waserror()){
6098ccd4a63SDavid du Colombier 			qunlock(&s->in.ctlq);
6108ccd4a63SDavid du Colombier 			if(b != nil)
6118ccd4a63SDavid du Colombier 				freeb(b);
6128ccd4a63SDavid du Colombier 			nexterror();
6138ccd4a63SDavid du Colombier 		}
6148ccd4a63SDavid du Colombier 		qlock(&s->in.ctlq);
6158ccd4a63SDavid du Colombier 		switch(s->state){
6168ccd4a63SDavid du Colombier 		case Sencrypting:
6178ccd4a63SDavid du Colombier 			if(b == nil)
6188ccd4a63SDavid du Colombier 				error("ssl message too short (encrypting)");
6198ccd4a63SDavid du Colombier 			b = decryptb(s, b);
6208ccd4a63SDavid du Colombier 			break;
6218ccd4a63SDavid du Colombier 		case Sdigesting:
6228ccd4a63SDavid du Colombier 			b = pullupblock(b, s->diglen);
6238ccd4a63SDavid du Colombier 			if(b == nil)
6248ccd4a63SDavid du Colombier 				error("ssl message too short (digesting)");
6258ccd4a63SDavid du Colombier 			checkdigestb(s, b);
6268ccd4a63SDavid du Colombier 			pullblock(&b, s->diglen);
6278ccd4a63SDavid du Colombier 			len -= s->diglen;
6288ccd4a63SDavid du Colombier 			break;
6298ccd4a63SDavid du Colombier 		case Sdigenc:
6308ccd4a63SDavid du Colombier 			b = decryptb(s, b);
6318ccd4a63SDavid du Colombier 			b = pullupblock(b, s->diglen);
6328ccd4a63SDavid du Colombier 			if(b == nil)
6338ccd4a63SDavid du Colombier 				error("ssl message too short (dig+enc)");
6348ccd4a63SDavid du Colombier 			checkdigestb(s, b);
6358ccd4a63SDavid du Colombier 			pullblock(&b, s->diglen);
6368ccd4a63SDavid du Colombier 			len -= s->diglen;
6378ccd4a63SDavid du Colombier 			break;
6388ccd4a63SDavid du Colombier 		}
6398ccd4a63SDavid du Colombier 
6408ccd4a63SDavid du Colombier 		/* remove pad */
6418ccd4a63SDavid du Colombier 		if(pad)
6428ccd4a63SDavid du Colombier 			s->processed = qtake(&b, len - pad, 1);
6438ccd4a63SDavid du Colombier 		else
6448ccd4a63SDavid du Colombier 			s->processed = b;
6458ccd4a63SDavid du Colombier 		b = nil;
6468ccd4a63SDavid du Colombier 		s->in.mid++;
6478ccd4a63SDavid du Colombier 		qunlock(&s->in.ctlq);
6488ccd4a63SDavid du Colombier 		poperror();
6498ccd4a63SDavid du Colombier 	}
6508ccd4a63SDavid du Colombier 
6518ccd4a63SDavid du Colombier 	/* return at most what was asked for */
6528ccd4a63SDavid du Colombier 	b = qtake(&s->processed, n, 0);
6538ccd4a63SDavid du Colombier 
6548ccd4a63SDavid du Colombier 	qunlock(&s->in.q);
6558ccd4a63SDavid du Colombier 	poperror();
6568ccd4a63SDavid du Colombier 
6578ccd4a63SDavid du Colombier 	return b;
6588ccd4a63SDavid du Colombier }
6598ccd4a63SDavid du Colombier 
6608ccd4a63SDavid du Colombier static long
sslread(Chan * c,void * a,long n,vlong off)6618ccd4a63SDavid du Colombier sslread(Chan *c, void *a, long n, vlong off)
6628ccd4a63SDavid du Colombier {
6638ccd4a63SDavid du Colombier 	Block * volatile b;
6648ccd4a63SDavid du Colombier 	Block *nb;
6658ccd4a63SDavid du Colombier 	uchar *va;
6668ccd4a63SDavid du Colombier 	int i;
6678ccd4a63SDavid du Colombier 	char buf[128];
6688ccd4a63SDavid du Colombier 	ulong offset = off;
6698ccd4a63SDavid du Colombier 	int ft;
6708ccd4a63SDavid du Colombier 
6718ccd4a63SDavid du Colombier 	if(c->qid.type & QTDIR)
6728ccd4a63SDavid du Colombier 		return devdirread(c, a, n, 0, 0, sslgen);
6738ccd4a63SDavid du Colombier 
6748ccd4a63SDavid du Colombier 	ft = TYPE(c->qid);
6758ccd4a63SDavid du Colombier 	switch(ft) {
6768ccd4a63SDavid du Colombier 	default:
6778ccd4a63SDavid du Colombier 		error(Ebadusefd);
6788ccd4a63SDavid du Colombier 	case Qctl:
6798ccd4a63SDavid du Colombier 		ft = CONV(c->qid);
6808ccd4a63SDavid du Colombier 		sprint(buf, "%d", ft);
6818ccd4a63SDavid du Colombier 		return readstr(offset, a, n, buf);
6828ccd4a63SDavid du Colombier 	case Qdata:
6838ccd4a63SDavid du Colombier 		b = sslbread(c, n, offset);
6848ccd4a63SDavid du Colombier 		break;
6858ccd4a63SDavid du Colombier 	case Qencalgs:
6868ccd4a63SDavid du Colombier 		return readstr(offset, a, n, encalgs);
6878ccd4a63SDavid du Colombier 		break;
6888ccd4a63SDavid du Colombier 	case Qhashalgs:
6898ccd4a63SDavid du Colombier 		return readstr(offset, a, n, hashalgs);
6908ccd4a63SDavid du Colombier 		break;
6918ccd4a63SDavid du Colombier 	}
6928ccd4a63SDavid du Colombier 
6938ccd4a63SDavid du Colombier 	if(waserror()){
6948ccd4a63SDavid du Colombier 		freeblist(b);
6958ccd4a63SDavid du Colombier 		nexterror();
6968ccd4a63SDavid du Colombier 	}
6978ccd4a63SDavid du Colombier 
6988ccd4a63SDavid du Colombier 	n = 0;
6998ccd4a63SDavid du Colombier 	va = a;
7008ccd4a63SDavid du Colombier 	for(nb = b; nb; nb = nb->next){
7018ccd4a63SDavid du Colombier 		i = BLEN(nb);
7028ccd4a63SDavid du Colombier 		memmove(va+n, nb->rp, i);
7038ccd4a63SDavid du Colombier 		n += i;
7048ccd4a63SDavid du Colombier 	}
7058ccd4a63SDavid du Colombier 
7068ccd4a63SDavid du Colombier 	freeblist(b);
7078ccd4a63SDavid du Colombier 	poperror();
7088ccd4a63SDavid du Colombier 
7098ccd4a63SDavid du Colombier 	return n;
7108ccd4a63SDavid du Colombier }
7118ccd4a63SDavid du Colombier 
7128ccd4a63SDavid du Colombier /*
7138ccd4a63SDavid du Colombier  *  this algorithm doesn't have to be great since we're just
7148ccd4a63SDavid du Colombier  *  trying to obscure the block fill
7158ccd4a63SDavid du Colombier  */
7168ccd4a63SDavid du Colombier static void
randfill(uchar * buf,int len)7178ccd4a63SDavid du Colombier randfill(uchar *buf, int len)
7188ccd4a63SDavid du Colombier {
7198ccd4a63SDavid du Colombier 	while(len-- > 0)
7208ccd4a63SDavid du Colombier 		*buf++ = fastrand();
7218ccd4a63SDavid du Colombier }
7228ccd4a63SDavid du Colombier 
7238ccd4a63SDavid du Colombier static long
sslbwrite(Chan * c,Block * b,ulong o)7248ccd4a63SDavid du Colombier sslbwrite(Chan *c, Block *b, ulong o)
7258ccd4a63SDavid du Colombier {
7268ccd4a63SDavid du Colombier 	Dstate * volatile s;
7278ccd4a63SDavid du Colombier 	long rv;
7288ccd4a63SDavid du Colombier 
7298ccd4a63SDavid du Colombier 	USED(o);
7308ccd4a63SDavid du Colombier 	s = dstate[CONV(c->qid)];
7318ccd4a63SDavid du Colombier 	if(s == nil)
7328ccd4a63SDavid du Colombier 		panic("sslbwrite");
7338ccd4a63SDavid du Colombier 
7348ccd4a63SDavid du Colombier 	if(s->state == Sincomplete){
7358ccd4a63SDavid du Colombier 		freeb(b);
7368ccd4a63SDavid du Colombier 		error(Ebadusefd);
7378ccd4a63SDavid du Colombier 	}
7388ccd4a63SDavid du Colombier 
7398ccd4a63SDavid du Colombier 	/* lock so split writes won't interleave */
7408ccd4a63SDavid du Colombier 	if(waserror()){
7418ccd4a63SDavid du Colombier 		qunlock(&s->out.q);
7428ccd4a63SDavid du Colombier 		nexterror();
7438ccd4a63SDavid du Colombier 	}
7448ccd4a63SDavid du Colombier 	qlock(&s->out.q);
7458ccd4a63SDavid du Colombier 
7468ccd4a63SDavid du Colombier 	rv = sslput(s, b);
7478ccd4a63SDavid du Colombier 
7488ccd4a63SDavid du Colombier 	poperror();
7498ccd4a63SDavid du Colombier 	qunlock(&s->out.q);
7508ccd4a63SDavid du Colombier 
7518ccd4a63SDavid du Colombier 	return rv;
7528ccd4a63SDavid du Colombier }
7538ccd4a63SDavid du Colombier 
7548ccd4a63SDavid du Colombier /*
7558ccd4a63SDavid du Colombier  *  use SSL record format, add in count, digest and/or encrypt.
7568ccd4a63SDavid du Colombier  *  the write is interruptable.  if it is interrupted, we'll
7578ccd4a63SDavid du Colombier  *  get out of sync with the far side.  not much we can do about
7588ccd4a63SDavid du Colombier  *  it since we don't know if any bytes have been written.
7598ccd4a63SDavid du Colombier  */
7608ccd4a63SDavid du Colombier static long
sslput(Dstate * s,Block * volatile b)7618ccd4a63SDavid du Colombier sslput(Dstate *s, Block * volatile b)
7628ccd4a63SDavid du Colombier {
7638ccd4a63SDavid du Colombier 	Block *nb;
7648ccd4a63SDavid du Colombier 	int h, n, m, pad, rv;
7658ccd4a63SDavid du Colombier 	uchar *p;
7668ccd4a63SDavid du Colombier 	int offset;
7678ccd4a63SDavid du Colombier 
7688ccd4a63SDavid du Colombier 	if(waserror()){
7698ccd4a63SDavid du Colombier iprint("error: %s\n", up->errstr);
7708ccd4a63SDavid du Colombier 		if(b != nil)
7718ccd4a63SDavid du Colombier 			free(b);
7728ccd4a63SDavid du Colombier 		nexterror();
7738ccd4a63SDavid du Colombier 	}
7748ccd4a63SDavid du Colombier 
7758ccd4a63SDavid du Colombier 	rv = 0;
7768ccd4a63SDavid du Colombier 	while(b != nil){
7778ccd4a63SDavid du Colombier 		m = n = BLEN(b);
7788ccd4a63SDavid du Colombier 		h = s->diglen + 2;
7798ccd4a63SDavid du Colombier 
7808ccd4a63SDavid du Colombier 		/* trim to maximum block size */
7818ccd4a63SDavid du Colombier 		pad = 0;
7828ccd4a63SDavid du Colombier 		if(m > s->max){
7838ccd4a63SDavid du Colombier 			m = s->max;
7848ccd4a63SDavid du Colombier 		} else if(s->blocklen != 1){
7858ccd4a63SDavid du Colombier 			pad = (m + s->diglen)%s->blocklen;
7868ccd4a63SDavid du Colombier 			if(pad){
7878ccd4a63SDavid du Colombier 				if(m > s->maxpad){
7888ccd4a63SDavid du Colombier 					pad = 0;
7898ccd4a63SDavid du Colombier 					m = s->maxpad;
7908ccd4a63SDavid du Colombier 				} else {
7918ccd4a63SDavid du Colombier 					pad = s->blocklen - pad;
7928ccd4a63SDavid du Colombier 					h++;
7938ccd4a63SDavid du Colombier 				}
7948ccd4a63SDavid du Colombier 			}
7958ccd4a63SDavid du Colombier 		}
7968ccd4a63SDavid du Colombier 
7978ccd4a63SDavid du Colombier 		rv += m;
7988ccd4a63SDavid du Colombier 		if(m != n){
7998ccd4a63SDavid du Colombier 			nb = allocb(m + h + pad);
8008ccd4a63SDavid du Colombier 			memmove(nb->wp + h, b->rp, m);
8018ccd4a63SDavid du Colombier 			nb->wp += m + h;
8028ccd4a63SDavid du Colombier 			b->rp += m;
8038ccd4a63SDavid du Colombier 		} else {
8048ccd4a63SDavid du Colombier 			/* add header space */
8058ccd4a63SDavid du Colombier 			nb = padblock(b, h);
8068ccd4a63SDavid du Colombier 			b = 0;
8078ccd4a63SDavid du Colombier 		}
8088ccd4a63SDavid du Colombier 		m += s->diglen;
8098ccd4a63SDavid du Colombier 
8108ccd4a63SDavid du Colombier 		/* SSL style count */
8118ccd4a63SDavid du Colombier 		if(pad){
8128ccd4a63SDavid du Colombier 			nb = padblock(nb, -pad);
8138ccd4a63SDavid du Colombier 			randfill(nb->wp, pad);
8148ccd4a63SDavid du Colombier 			nb->wp += pad;
8158ccd4a63SDavid du Colombier 			m += pad;
8168ccd4a63SDavid du Colombier 
8178ccd4a63SDavid du Colombier 			p = nb->rp;
8188ccd4a63SDavid du Colombier 			p[0] = (m>>8);
8198ccd4a63SDavid du Colombier 			p[1] = m;
8208ccd4a63SDavid du Colombier 			p[2] = pad;
8218ccd4a63SDavid du Colombier 			offset = 3;
8228ccd4a63SDavid du Colombier 		} else {
8238ccd4a63SDavid du Colombier 			p = nb->rp;
8248ccd4a63SDavid du Colombier 			p[0] = (m>>8) | 0x80;
8258ccd4a63SDavid du Colombier 			p[1] = m;
8268ccd4a63SDavid du Colombier 			offset = 2;
8278ccd4a63SDavid du Colombier 		}
8288ccd4a63SDavid du Colombier 
8298ccd4a63SDavid du Colombier 		switch(s->state){
8308ccd4a63SDavid du Colombier 		case Sencrypting:
8318ccd4a63SDavid du Colombier 			nb = encryptb(s, nb, offset);
8328ccd4a63SDavid du Colombier 			break;
8338ccd4a63SDavid du Colombier 		case Sdigesting:
8348ccd4a63SDavid du Colombier 			nb = digestb(s, nb, offset);
8358ccd4a63SDavid du Colombier 			break;
8368ccd4a63SDavid du Colombier 		case Sdigenc:
8378ccd4a63SDavid du Colombier 			nb = digestb(s, nb, offset);
8388ccd4a63SDavid du Colombier 			nb = encryptb(s, nb, offset);
8398ccd4a63SDavid du Colombier 			break;
8408ccd4a63SDavid du Colombier 		}
8418ccd4a63SDavid du Colombier 
8428ccd4a63SDavid du Colombier 		s->out.mid++;
8438ccd4a63SDavid du Colombier 
8448ccd4a63SDavid du Colombier 		m = BLEN(nb);
8458ccd4a63SDavid du Colombier 		devtab[s->c->type]->bwrite(s->c, nb, s->c->offset);
8468ccd4a63SDavid du Colombier 		s->c->offset += m;
8478ccd4a63SDavid du Colombier 	}
8488ccd4a63SDavid du Colombier 
8498ccd4a63SDavid du Colombier 	poperror();
8508ccd4a63SDavid du Colombier 	return rv;
8518ccd4a63SDavid du Colombier }
8528ccd4a63SDavid du Colombier 
8538ccd4a63SDavid du Colombier static void
setsecret(OneWay * w,uchar * secret,int n)8548ccd4a63SDavid du Colombier setsecret(OneWay *w, uchar *secret, int n)
8558ccd4a63SDavid du Colombier {
8568ccd4a63SDavid du Colombier 	if(w->secret)
8578ccd4a63SDavid du Colombier 		free(w->secret);
8588ccd4a63SDavid du Colombier 
8598ccd4a63SDavid du Colombier 	w->secret = smalloc(n);
8608ccd4a63SDavid du Colombier 	memmove(w->secret, secret, n);
8618ccd4a63SDavid du Colombier 	w->slen = n;
8628ccd4a63SDavid du Colombier }
8638ccd4a63SDavid du Colombier 
8648ccd4a63SDavid du Colombier static void
initDESkey(OneWay * w)8658ccd4a63SDavid du Colombier initDESkey(OneWay *w)
8668ccd4a63SDavid du Colombier {
8678ccd4a63SDavid du Colombier 	if(w->state){
8688ccd4a63SDavid du Colombier 		free(w->state);
8698ccd4a63SDavid du Colombier 		w->state = 0;
8708ccd4a63SDavid du Colombier 	}
8718ccd4a63SDavid du Colombier 
8728ccd4a63SDavid du Colombier 	w->state = smalloc(sizeof(DESstate));
8738ccd4a63SDavid du Colombier 	if(w->slen >= 16)
8748ccd4a63SDavid du Colombier 		setupDESstate(w->state, w->secret, w->secret+8);
8758ccd4a63SDavid du Colombier 	else if(w->slen >= 8)
8768ccd4a63SDavid du Colombier 		setupDESstate(w->state, w->secret, 0);
8778ccd4a63SDavid du Colombier 	else
8788ccd4a63SDavid du Colombier 		error("secret too short");
8798ccd4a63SDavid du Colombier }
8808ccd4a63SDavid du Colombier 
8818ccd4a63SDavid du Colombier /*
8828ccd4a63SDavid du Colombier  *  40 bit DES is the same as 56 bit DES.  However,
8838ccd4a63SDavid du Colombier  *  16 bits of the key are masked to zero.
8848ccd4a63SDavid du Colombier  */
8858ccd4a63SDavid du Colombier static void
initDESkey_40(OneWay * w)8868ccd4a63SDavid du Colombier initDESkey_40(OneWay *w)
8878ccd4a63SDavid du Colombier {
8888ccd4a63SDavid du Colombier 	uchar key[8];
8898ccd4a63SDavid du Colombier 
8908ccd4a63SDavid du Colombier 	if(w->state){
8918ccd4a63SDavid du Colombier 		free(w->state);
8928ccd4a63SDavid du Colombier 		w->state = 0;
8938ccd4a63SDavid du Colombier 	}
8948ccd4a63SDavid du Colombier 
8958ccd4a63SDavid du Colombier 	if(w->slen >= 8){
8968ccd4a63SDavid du Colombier 		memmove(key, w->secret, 8);
8978ccd4a63SDavid du Colombier 		key[0] &= 0x0f;
8988ccd4a63SDavid du Colombier 		key[2] &= 0x0f;
8998ccd4a63SDavid du Colombier 		key[4] &= 0x0f;
9008ccd4a63SDavid du Colombier 		key[6] &= 0x0f;
9018ccd4a63SDavid du Colombier 	}
9028ccd4a63SDavid du Colombier 
9038ccd4a63SDavid du Colombier 	w->state = malloc(sizeof(DESstate));
9048ccd4a63SDavid du Colombier 	if(w->slen >= 16)
9058ccd4a63SDavid du Colombier 		setupDESstate(w->state, key, w->secret+8);
9068ccd4a63SDavid du Colombier 	else if(w->slen >= 8)
9078ccd4a63SDavid du Colombier 		setupDESstate(w->state, key, 0);
9088ccd4a63SDavid du Colombier 	else
9098ccd4a63SDavid du Colombier 		error("secret too short");
9108ccd4a63SDavid du Colombier }
9118ccd4a63SDavid du Colombier 
9128ccd4a63SDavid du Colombier static void
initRC4key(OneWay * w)9138ccd4a63SDavid du Colombier initRC4key(OneWay *w)
9148ccd4a63SDavid du Colombier {
9158ccd4a63SDavid du Colombier 	if(w->state){
9168ccd4a63SDavid du Colombier 		free(w->state);
9178ccd4a63SDavid du Colombier 		w->state = 0;
9188ccd4a63SDavid du Colombier 	}
9198ccd4a63SDavid du Colombier 
9208ccd4a63SDavid du Colombier 	w->state = smalloc(sizeof(RC4state));
9218ccd4a63SDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9228ccd4a63SDavid du Colombier }
9238ccd4a63SDavid du Colombier 
9248ccd4a63SDavid du Colombier /*
9258ccd4a63SDavid du Colombier  *  40 bit RC4 is the same as n-bit RC4.  However,
9268ccd4a63SDavid du Colombier  *  we ignore all but the first 40 bits of the key.
9278ccd4a63SDavid du Colombier  */
9288ccd4a63SDavid du Colombier static void
initRC4key_40(OneWay * w)9298ccd4a63SDavid du Colombier initRC4key_40(OneWay *w)
9308ccd4a63SDavid du Colombier {
9318ccd4a63SDavid du Colombier 	if(w->state){
9328ccd4a63SDavid du Colombier 		free(w->state);
9338ccd4a63SDavid du Colombier 		w->state = 0;
9348ccd4a63SDavid du Colombier 	}
9358ccd4a63SDavid du Colombier 
9368ccd4a63SDavid du Colombier 	if(w->slen > 5)
9378ccd4a63SDavid du Colombier 		w->slen = 5;
9388ccd4a63SDavid du Colombier 
9398ccd4a63SDavid du Colombier 	w->state = malloc(sizeof(RC4state));
9408ccd4a63SDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9418ccd4a63SDavid du Colombier }
9428ccd4a63SDavid du Colombier 
9438ccd4a63SDavid du Colombier /*
9448ccd4a63SDavid du Colombier  *  128 bit RC4 is the same as n-bit RC4.  However,
9458ccd4a63SDavid du Colombier  *  we ignore all but the first 128 bits of the key.
9468ccd4a63SDavid du Colombier  */
9478ccd4a63SDavid du Colombier static void
initRC4key_128(OneWay * w)9488ccd4a63SDavid du Colombier initRC4key_128(OneWay *w)
9498ccd4a63SDavid du Colombier {
9508ccd4a63SDavid du Colombier 	if(w->state){
9518ccd4a63SDavid du Colombier 		free(w->state);
9528ccd4a63SDavid du Colombier 		w->state = 0;
9538ccd4a63SDavid du Colombier 	}
9548ccd4a63SDavid du Colombier 
9558ccd4a63SDavid du Colombier 	if(w->slen > 16)
9568ccd4a63SDavid du Colombier 		w->slen = 16;
9578ccd4a63SDavid du Colombier 
9588ccd4a63SDavid du Colombier 	w->state = malloc(sizeof(RC4state));
9598ccd4a63SDavid du Colombier 	setupRC4state(w->state, w->secret, w->slen);
9608ccd4a63SDavid du Colombier }
9618ccd4a63SDavid du Colombier 
9628ccd4a63SDavid du Colombier 
9638ccd4a63SDavid du Colombier typedef struct Hashalg Hashalg;
9648ccd4a63SDavid du Colombier struct Hashalg
9658ccd4a63SDavid du Colombier {
9668ccd4a63SDavid du Colombier 	char	*name;
9678ccd4a63SDavid du Colombier 	int	diglen;
9688ccd4a63SDavid du Colombier 	DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*);
9698ccd4a63SDavid du Colombier };
9708ccd4a63SDavid du Colombier 
9718ccd4a63SDavid du Colombier Hashalg hashtab[] =
9728ccd4a63SDavid du Colombier {
9738ccd4a63SDavid du Colombier 	{ "md4", MD4dlen, md4, },
9748ccd4a63SDavid du Colombier 	{ "md5", MD5dlen, md5, },
9758ccd4a63SDavid du Colombier 	{ "sha1", SHA1dlen, sha1, },
9768ccd4a63SDavid du Colombier 	{ "sha", SHA1dlen, sha1, },
9778ccd4a63SDavid du Colombier 	{ 0 }
9788ccd4a63SDavid du Colombier };
9798ccd4a63SDavid du Colombier 
9808ccd4a63SDavid du Colombier static int
parsehashalg(char * p,Dstate * s)9818ccd4a63SDavid du Colombier parsehashalg(char *p, Dstate *s)
9828ccd4a63SDavid du Colombier {
9838ccd4a63SDavid du Colombier 	Hashalg *ha;
9848ccd4a63SDavid du Colombier 
9858ccd4a63SDavid du Colombier 	for(ha = hashtab; ha->name; ha++){
9868ccd4a63SDavid du Colombier 		if(strcmp(p, ha->name) == 0){
9878ccd4a63SDavid du Colombier 			s->hf = ha->hf;
9888ccd4a63SDavid du Colombier 			s->diglen = ha->diglen;
9898ccd4a63SDavid du Colombier 			s->state &= ~Sclear;
9908ccd4a63SDavid du Colombier 			s->state |= Sdigesting;
9918ccd4a63SDavid du Colombier 			return 0;
9928ccd4a63SDavid du Colombier 		}
9938ccd4a63SDavid du Colombier 	}
9948ccd4a63SDavid du Colombier 	return -1;
9958ccd4a63SDavid du Colombier }
9968ccd4a63SDavid du Colombier 
9978ccd4a63SDavid du Colombier typedef struct Encalg Encalg;
9988ccd4a63SDavid du Colombier struct Encalg
9998ccd4a63SDavid du Colombier {
10008ccd4a63SDavid du Colombier 	char	*name;
10018ccd4a63SDavid du Colombier 	int	blocklen;
10028ccd4a63SDavid du Colombier 	int	alg;
10038ccd4a63SDavid du Colombier 	void	(*keyinit)(OneWay*);
10048ccd4a63SDavid du Colombier };
10058ccd4a63SDavid du Colombier 
10068ccd4a63SDavid du Colombier #ifdef NOSPOOKS
10078ccd4a63SDavid du Colombier Encalg encrypttab[] =
10088ccd4a63SDavid du Colombier {
10098ccd4a63SDavid du Colombier 	{ "descbc", 8, DESCBC, initDESkey, },           /* DEPRECATED -- use des_56_cbc */
10108ccd4a63SDavid du Colombier 	{ "desecb", 8, DESECB, initDESkey, },           /* DEPRECATED -- use des_56_ecb */
10118ccd4a63SDavid du Colombier 	{ "des_56_cbc", 8, DESCBC, initDESkey, },
10128ccd4a63SDavid du Colombier 	{ "des_56_ecb", 8, DESECB, initDESkey, },
10138ccd4a63SDavid du Colombier 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
10148ccd4a63SDavid du Colombier 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
10158ccd4a63SDavid du Colombier 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
10168ccd4a63SDavid du Colombier 	{ "rc4_256", 1, RC4, initRC4key, },
10178ccd4a63SDavid du Colombier 	{ "rc4_128", 1, RC4, initRC4key_128, },
10188ccd4a63SDavid du Colombier 	{ "rc4_40", 1, RC4, initRC4key_40, },
10198ccd4a63SDavid du Colombier 	{ 0 }
10208ccd4a63SDavid du Colombier };
10218ccd4a63SDavid du Colombier #else
10228ccd4a63SDavid du Colombier Encalg encrypttab[] =
10238ccd4a63SDavid du Colombier {
10248ccd4a63SDavid du Colombier 	{ "des_40_cbc", 8, DESCBC, initDESkey_40, },
10258ccd4a63SDavid du Colombier 	{ "des_40_ecb", 8, DESECB, initDESkey_40, },
10268ccd4a63SDavid du Colombier 	{ "rc4", 1, RC4, initRC4key_40, },              /* DEPRECATED -- use rc4_X      */
10278ccd4a63SDavid du Colombier 	{ "rc4_40", 1, RC4, initRC4key_40, },
10288ccd4a63SDavid du Colombier 	{ 0 }
10298ccd4a63SDavid du Colombier };
10308ccd4a63SDavid du Colombier #endif /* NOSPOOKS */
10318ccd4a63SDavid du Colombier 
10328ccd4a63SDavid du Colombier static int
parseencryptalg(char * p,Dstate * s)10338ccd4a63SDavid du Colombier parseencryptalg(char *p, Dstate *s)
10348ccd4a63SDavid du Colombier {
10358ccd4a63SDavid du Colombier 	Encalg *ea;
10368ccd4a63SDavid du Colombier 
10378ccd4a63SDavid du Colombier 	for(ea = encrypttab; ea->name; ea++){
10388ccd4a63SDavid du Colombier 		if(strcmp(p, ea->name) == 0){
10398ccd4a63SDavid du Colombier 			s->encryptalg = ea->alg;
10408ccd4a63SDavid du Colombier 			s->blocklen = ea->blocklen;
10418ccd4a63SDavid du Colombier 			(*ea->keyinit)(&s->in);
10428ccd4a63SDavid du Colombier 			(*ea->keyinit)(&s->out);
10438ccd4a63SDavid du Colombier 			s->state &= ~Sclear;
10448ccd4a63SDavid du Colombier 			s->state |= Sencrypting;
10458ccd4a63SDavid du Colombier 			return 0;
10468ccd4a63SDavid du Colombier 		}
10478ccd4a63SDavid du Colombier 	}
10488ccd4a63SDavid du Colombier 	return -1;
10498ccd4a63SDavid du Colombier }
10508ccd4a63SDavid du Colombier 
10518ccd4a63SDavid du Colombier static long
sslwrite(Chan * c,void * a,long n,vlong o)10528ccd4a63SDavid du Colombier sslwrite(Chan *c, void *a, long n, vlong o)
10538ccd4a63SDavid du Colombier {
10548ccd4a63SDavid du Colombier 	Dstate * volatile s;
10558ccd4a63SDavid du Colombier 	Block * volatile b;
10568ccd4a63SDavid du Colombier 	int m, t;
10578ccd4a63SDavid du Colombier 	char *p, *np, *e, buf[128];
10588ccd4a63SDavid du Colombier 	uchar *x;
10598ccd4a63SDavid du Colombier 
10608ccd4a63SDavid du Colombier 	USED(o);
10618ccd4a63SDavid du Colombier 	s = dstate[CONV(c->qid)];
10628ccd4a63SDavid du Colombier 	if(s == 0)
10638ccd4a63SDavid du Colombier 		panic("sslwrite");
10648ccd4a63SDavid du Colombier 
10658ccd4a63SDavid du Colombier 	t = TYPE(c->qid);
10668ccd4a63SDavid du Colombier 	if(t == Qdata){
10678ccd4a63SDavid du Colombier 		if(s->state == Sincomplete)
10688ccd4a63SDavid du Colombier 			error(Ebadusefd);
10698ccd4a63SDavid du Colombier 
10708ccd4a63SDavid du Colombier 		/* lock should a write gets split over multiple records */
10718ccd4a63SDavid du Colombier 		if(waserror()){
10728ccd4a63SDavid du Colombier 			qunlock(&s->out.q);
10738ccd4a63SDavid du Colombier 			nexterror();
10748ccd4a63SDavid du Colombier 		}
10758ccd4a63SDavid du Colombier 		qlock(&s->out.q);
10768ccd4a63SDavid du Colombier 		p = a;
10778ccd4a63SDavid du Colombier if(0) iprint("write %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
10788ccd4a63SDavid du Colombier 	n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
10798ccd4a63SDavid du Colombier 		e = p + n;
10808ccd4a63SDavid du Colombier 		do {
10818ccd4a63SDavid du Colombier 			m = e - p;
10828ccd4a63SDavid du Colombier 			if(m > s->max)
10838ccd4a63SDavid du Colombier 				m = s->max;
10848ccd4a63SDavid du Colombier 
10858ccd4a63SDavid du Colombier 			b = allocb(m);
10868ccd4a63SDavid du Colombier 			if(waserror()){
10878ccd4a63SDavid du Colombier 				freeb(b);
10888ccd4a63SDavid du Colombier 				nexterror();
10898ccd4a63SDavid du Colombier 			}
10908ccd4a63SDavid du Colombier 			memmove(b->wp, p, m);
10918ccd4a63SDavid du Colombier 			poperror();
10928ccd4a63SDavid du Colombier 			b->wp += m;
10938ccd4a63SDavid du Colombier 
10948ccd4a63SDavid du Colombier 			sslput(s, b);
10958ccd4a63SDavid du Colombier 
10968ccd4a63SDavid du Colombier 			p += m;
10978ccd4a63SDavid du Colombier 		} while(p < e);
10988ccd4a63SDavid du Colombier 		p = a;
10998ccd4a63SDavid du Colombier if(0) iprint("wrote %d %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n",
11008ccd4a63SDavid du Colombier 	n, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
11018ccd4a63SDavid du Colombier 		poperror();
11028ccd4a63SDavid du Colombier 		qunlock(&s->out.q);
11038ccd4a63SDavid du Colombier 		return n;
11048ccd4a63SDavid du Colombier 	}
11058ccd4a63SDavid du Colombier 
11068ccd4a63SDavid du Colombier 	/* mutex with operations using what we're about to change */
11078ccd4a63SDavid du Colombier 	if(waserror()){
11088ccd4a63SDavid du Colombier 		qunlock(&s->in.ctlq);
11098ccd4a63SDavid du Colombier 		qunlock(&s->out.q);
11108ccd4a63SDavid du Colombier 		nexterror();
11118ccd4a63SDavid du Colombier 	}
11128ccd4a63SDavid du Colombier 	qlock(&s->in.ctlq);
11138ccd4a63SDavid du Colombier 	qlock(&s->out.q);
11148ccd4a63SDavid du Colombier 
11158ccd4a63SDavid du Colombier 	switch(t){
11168ccd4a63SDavid du Colombier 	default:
11178ccd4a63SDavid du Colombier 		panic("sslwrite");
11188ccd4a63SDavid du Colombier 	case Qsecretin:
11198ccd4a63SDavid du Colombier 		setsecret(&s->in, a, n);
11208ccd4a63SDavid du Colombier 		goto out;
11218ccd4a63SDavid du Colombier 	case Qsecretout:
11228ccd4a63SDavid du Colombier 		setsecret(&s->out, a, n);
11238ccd4a63SDavid du Colombier 		goto out;
11248ccd4a63SDavid du Colombier 	case Qctl:
11258ccd4a63SDavid du Colombier 		break;
11268ccd4a63SDavid du Colombier 	}
11278ccd4a63SDavid du Colombier 
11288ccd4a63SDavid du Colombier 	if(n >= sizeof(buf))
11298ccd4a63SDavid du Colombier 		error("arg too long");
11308ccd4a63SDavid du Colombier 	strncpy(buf, a, n);
11318ccd4a63SDavid du Colombier 	buf[n] = 0;
11328ccd4a63SDavid du Colombier 	p = strchr(buf, '\n');
11338ccd4a63SDavid du Colombier 	if(p)
11348ccd4a63SDavid du Colombier 		*p = 0;
11358ccd4a63SDavid du Colombier 	p = strchr(buf, ' ');
11368ccd4a63SDavid du Colombier 	if(p)
11378ccd4a63SDavid du Colombier 		*p++ = 0;
11388ccd4a63SDavid du Colombier 
11398ccd4a63SDavid du Colombier 	if(strcmp(buf, "fd") == 0){
11408ccd4a63SDavid du Colombier 		s->c = buftochan(p);
11418ccd4a63SDavid du Colombier 
11428ccd4a63SDavid du Colombier 		/* default is clear (msg delimiters only) */
11438ccd4a63SDavid du Colombier 		s->state = Sclear;
11448ccd4a63SDavid du Colombier 		s->blocklen = 1;
11458ccd4a63SDavid du Colombier 		s->diglen = 0;
11468ccd4a63SDavid du Colombier 		s->maxpad = s->max = (1<<15) - s->diglen - 1;
11478ccd4a63SDavid du Colombier 		s->in.mid = 0;
11488ccd4a63SDavid du Colombier 		s->out.mid = 0;
11498ccd4a63SDavid du Colombier 	} else if(strcmp(buf, "alg") == 0 && p != 0){
11508ccd4a63SDavid du Colombier 		s->blocklen = 1;
11518ccd4a63SDavid du Colombier 		s->diglen = 0;
11528ccd4a63SDavid du Colombier 
11538ccd4a63SDavid du Colombier 		if(s->c == 0)
11548ccd4a63SDavid du Colombier 			error("must set fd before algorithm");
11558ccd4a63SDavid du Colombier 
11568ccd4a63SDavid du Colombier 		s->state = Sclear;
11578ccd4a63SDavid du Colombier 		s->maxpad = s->max = (1<<15) - s->diglen - 1;
11588ccd4a63SDavid du Colombier 		if(strcmp(p, "clear") == 0){
11598ccd4a63SDavid du Colombier 			goto out;
11608ccd4a63SDavid du Colombier 		}
11618ccd4a63SDavid du Colombier 
11628ccd4a63SDavid du Colombier 		if(s->in.secret && s->out.secret == 0)
11638ccd4a63SDavid du Colombier 			setsecret(&s->out, s->in.secret, s->in.slen);
11648ccd4a63SDavid du Colombier 		if(s->out.secret && s->in.secret == 0)
11658ccd4a63SDavid du Colombier 			setsecret(&s->in, s->out.secret, s->out.slen);
11668ccd4a63SDavid du Colombier 		if(s->in.secret == 0 || s->out.secret == 0)
11678ccd4a63SDavid du Colombier 			error("algorithm but no secret");
11688ccd4a63SDavid du Colombier 
11698ccd4a63SDavid du Colombier 		s->hf = 0;
11708ccd4a63SDavid du Colombier 		s->encryptalg = Noencryption;
11718ccd4a63SDavid du Colombier 		s->blocklen = 1;
11728ccd4a63SDavid du Colombier 
11738ccd4a63SDavid du Colombier 		for(;;){
11748ccd4a63SDavid du Colombier 			np = strchr(p, ' ');
11758ccd4a63SDavid du Colombier 			if(np)
11768ccd4a63SDavid du Colombier 				*np++ = 0;
11778ccd4a63SDavid du Colombier 
11788ccd4a63SDavid du Colombier 			if(parsehashalg(p, s) < 0)
11798ccd4a63SDavid du Colombier 			if(parseencryptalg(p, s) < 0)
11808ccd4a63SDavid du Colombier 				error("bad algorithm");
11818ccd4a63SDavid du Colombier 
11828ccd4a63SDavid du Colombier 			if(np == 0)
11838ccd4a63SDavid du Colombier 				break;
11848ccd4a63SDavid du Colombier 			p = np;
11858ccd4a63SDavid du Colombier 		}
11868ccd4a63SDavid du Colombier 
11878ccd4a63SDavid du Colombier 		if(s->hf == 0 && s->encryptalg == Noencryption)
11888ccd4a63SDavid du Colombier 			error("bad algorithm");
11898ccd4a63SDavid du Colombier 
11908ccd4a63SDavid du Colombier 		if(s->blocklen != 1){
11918ccd4a63SDavid du Colombier 			s->max = (1<<15) - s->diglen - 1;
11928ccd4a63SDavid du Colombier 			s->max -= s->max % s->blocklen;
11938ccd4a63SDavid du Colombier 			s->maxpad = (1<<14) - s->diglen - 1;
11948ccd4a63SDavid du Colombier 			s->maxpad -= s->maxpad % s->blocklen;
11958ccd4a63SDavid du Colombier 		} else
11968ccd4a63SDavid du Colombier 			s->maxpad = s->max = (1<<15) - s->diglen - 1;
11978ccd4a63SDavid du Colombier 	} else if(strcmp(buf, "secretin") == 0 && p != 0) {
11988ccd4a63SDavid du Colombier 		m = (strlen(p)*3)/2;
11998ccd4a63SDavid du Colombier 		x = smalloc(m);
12008ccd4a63SDavid du Colombier 		t = dec64(x, m, p, strlen(p));
12018ccd4a63SDavid du Colombier 		setsecret(&s->in, x, t);
12028ccd4a63SDavid du Colombier 		free(x);
12038ccd4a63SDavid du Colombier 	} else if(strcmp(buf, "secretout") == 0 && p != 0) {
12048ccd4a63SDavid du Colombier 		m = (strlen(p)*3)/2 + 1;
12058ccd4a63SDavid du Colombier 		x = smalloc(m);
12068ccd4a63SDavid du Colombier 		t = dec64(x, m, p, strlen(p));
12078ccd4a63SDavid du Colombier 		setsecret(&s->out, x, t);
12088ccd4a63SDavid du Colombier 		free(x);
12098ccd4a63SDavid du Colombier 	} else
12108ccd4a63SDavid du Colombier 		error(Ebadarg);
12118ccd4a63SDavid du Colombier 
12128ccd4a63SDavid du Colombier out:
12138ccd4a63SDavid du Colombier 	qunlock(&s->in.ctlq);
12148ccd4a63SDavid du Colombier 	qunlock(&s->out.q);
12158ccd4a63SDavid du Colombier 	poperror();
12168ccd4a63SDavid du Colombier 	return n;
12178ccd4a63SDavid du Colombier }
12188ccd4a63SDavid du Colombier 
12198ccd4a63SDavid du Colombier static void
sslinit(void)12208ccd4a63SDavid du Colombier sslinit(void)
12218ccd4a63SDavid du Colombier {
12228ccd4a63SDavid du Colombier 	struct Encalg *e;
12238ccd4a63SDavid du Colombier 	struct Hashalg *h;
12248ccd4a63SDavid du Colombier 	int n;
12258ccd4a63SDavid du Colombier 	char *cp;
12268ccd4a63SDavid du Colombier 
12278ccd4a63SDavid du Colombier 	n = 1;
12288ccd4a63SDavid du Colombier 	for(e = encrypttab; e->name != nil; e++)
12298ccd4a63SDavid du Colombier 		n += strlen(e->name) + 1;
12308ccd4a63SDavid du Colombier 	cp = encalgs = smalloc(n);
12318ccd4a63SDavid du Colombier 	for(e = encrypttab;;){
12328ccd4a63SDavid du Colombier 		strcpy(cp, e->name);
12338ccd4a63SDavid du Colombier 		cp += strlen(e->name);
12348ccd4a63SDavid du Colombier 		e++;
12358ccd4a63SDavid du Colombier 		if(e->name == nil)
12368ccd4a63SDavid du Colombier 			break;
12378ccd4a63SDavid du Colombier 		*cp++ = ' ';
12388ccd4a63SDavid du Colombier 	}
12398ccd4a63SDavid du Colombier 	*cp = 0;
12408ccd4a63SDavid du Colombier 
12418ccd4a63SDavid du Colombier 	n = 1;
12428ccd4a63SDavid du Colombier 	for(h = hashtab; h->name != nil; h++)
12438ccd4a63SDavid du Colombier 		n += strlen(h->name) + 1;
12448ccd4a63SDavid du Colombier 	cp = hashalgs = smalloc(n);
12458ccd4a63SDavid du Colombier 	for(h = hashtab;;){
12468ccd4a63SDavid du Colombier 		strcpy(cp, h->name);
12478ccd4a63SDavid du Colombier 		cp += strlen(h->name);
12488ccd4a63SDavid du Colombier 		h++;
12498ccd4a63SDavid du Colombier 		if(h->name == nil)
12508ccd4a63SDavid du Colombier 			break;
12518ccd4a63SDavid du Colombier 		*cp++ = ' ';
12528ccd4a63SDavid du Colombier 	}
12538ccd4a63SDavid du Colombier 	*cp = 0;
12548ccd4a63SDavid du Colombier }
12558ccd4a63SDavid du Colombier 
12568ccd4a63SDavid du Colombier Dev ssldevtab = {
12578ccd4a63SDavid du Colombier 	'D',
12588ccd4a63SDavid du Colombier 	"ssl",
12598ccd4a63SDavid du Colombier 
12608ccd4a63SDavid du Colombier 	devreset,
12618ccd4a63SDavid du Colombier 	sslinit,
12628ccd4a63SDavid du Colombier 	devshutdown,
12638ccd4a63SDavid du Colombier 	sslattach,
12648ccd4a63SDavid du Colombier 	sslwalk,
12658ccd4a63SDavid du Colombier 	sslstat,
12668ccd4a63SDavid du Colombier 	sslopen,
12678ccd4a63SDavid du Colombier 	devcreate,
12688ccd4a63SDavid du Colombier 	sslclose,
12698ccd4a63SDavid du Colombier 	sslread,
12708ccd4a63SDavid du Colombier 	sslbread,
12718ccd4a63SDavid du Colombier 	sslwrite,
12728ccd4a63SDavid du Colombier 	sslbwrite,
12738ccd4a63SDavid du Colombier 	devremove,
12748ccd4a63SDavid du Colombier 	sslwstat,
12758ccd4a63SDavid du Colombier };
12768ccd4a63SDavid du Colombier 
12778ccd4a63SDavid du Colombier static Block*
encryptb(Dstate * s,Block * b,int offset)12788ccd4a63SDavid du Colombier encryptb(Dstate *s, Block *b, int offset)
12798ccd4a63SDavid du Colombier {
12808ccd4a63SDavid du Colombier 	uchar *p, *ep, *p2, *ip, *eip;
12818ccd4a63SDavid du Colombier 	DESstate *ds;
12828ccd4a63SDavid du Colombier 
12838ccd4a63SDavid du Colombier 	switch(s->encryptalg){
12848ccd4a63SDavid du Colombier 	case DESECB:
12858ccd4a63SDavid du Colombier 		ds = s->out.state;
12868ccd4a63SDavid du Colombier 		ep = b->rp + BLEN(b);
12878ccd4a63SDavid du Colombier 		for(p = b->rp + offset; p < ep; p += 8)
12888ccd4a63SDavid du Colombier 			block_cipher(ds->expanded, p, 0);
12898ccd4a63SDavid du Colombier 		break;
12908ccd4a63SDavid du Colombier 	case DESCBC:
12918ccd4a63SDavid du Colombier 		ds = s->out.state;
12928ccd4a63SDavid du Colombier 		ep = b->rp + BLEN(b);
12938ccd4a63SDavid du Colombier 		for(p = b->rp + offset; p < ep; p += 8){
12948ccd4a63SDavid du Colombier 			p2 = p;
12958ccd4a63SDavid du Colombier 			ip = ds->ivec;
12968ccd4a63SDavid du Colombier 			for(eip = ip+8; ip < eip; )
12978ccd4a63SDavid du Colombier 				*p2++ ^= *ip++;
12988ccd4a63SDavid du Colombier 			block_cipher(ds->expanded, p, 0);
12998ccd4a63SDavid du Colombier 			memmove(ds->ivec, p, 8);
13008ccd4a63SDavid du Colombier 		}
13018ccd4a63SDavid du Colombier 		break;
13028ccd4a63SDavid du Colombier 	case RC4:
13038ccd4a63SDavid du Colombier 		rc4(s->out.state, b->rp + offset, BLEN(b) - offset);
13048ccd4a63SDavid du Colombier 		break;
13058ccd4a63SDavid du Colombier 	}
13068ccd4a63SDavid du Colombier 	return b;
13078ccd4a63SDavid du Colombier }
13088ccd4a63SDavid du Colombier 
13098ccd4a63SDavid du Colombier static Block*
decryptb(Dstate * s,Block * bin)13108ccd4a63SDavid du Colombier decryptb(Dstate *s, Block *bin)
13118ccd4a63SDavid du Colombier {
13128ccd4a63SDavid du Colombier 	Block *b, **l;
13138ccd4a63SDavid du Colombier 	uchar *p, *ep, *tp, *ip, *eip;
13148ccd4a63SDavid du Colombier 	DESstate *ds;
13158ccd4a63SDavid du Colombier 	uchar tmp[8];
13168ccd4a63SDavid du Colombier 	int i;
13178ccd4a63SDavid du Colombier 
13188ccd4a63SDavid du Colombier 	l = &bin;
13198ccd4a63SDavid du Colombier 	for(b = bin; b; b = b->next){
13208ccd4a63SDavid du Colombier 		/* make sure we have a multiple of s->blocklen */
13218ccd4a63SDavid du Colombier 		if(s->blocklen > 1){
13228ccd4a63SDavid du Colombier 			i = BLEN(b);
13238ccd4a63SDavid du Colombier 			if(i % s->blocklen){
13248ccd4a63SDavid du Colombier 				*l = b = pullupblock(b, i + s->blocklen - (i%s->blocklen));
13258ccd4a63SDavid du Colombier 				if(b == 0)
13268ccd4a63SDavid du Colombier 					error("ssl encrypted message too short");
13278ccd4a63SDavid du Colombier 			}
13288ccd4a63SDavid du Colombier 		}
13298ccd4a63SDavid du Colombier 		l = &b->next;
13308ccd4a63SDavid du Colombier 
13318ccd4a63SDavid du Colombier 		/* decrypt */
13328ccd4a63SDavid du Colombier 		switch(s->encryptalg){
13338ccd4a63SDavid du Colombier 		case DESECB:
13348ccd4a63SDavid du Colombier 			ds = s->in.state;
13358ccd4a63SDavid du Colombier 			ep = b->rp + BLEN(b);
13368ccd4a63SDavid du Colombier 			for(p = b->rp; p < ep; p += 8)
13378ccd4a63SDavid du Colombier 				block_cipher(ds->expanded, p, 1);
13388ccd4a63SDavid du Colombier 			break;
13398ccd4a63SDavid du Colombier 		case DESCBC:
13408ccd4a63SDavid du Colombier 			ds = s->in.state;
13418ccd4a63SDavid du Colombier 			ep = b->rp + BLEN(b);
13428ccd4a63SDavid du Colombier 			for(p = b->rp; p < ep;){
13438ccd4a63SDavid du Colombier 				memmove(tmp, p, 8);
13448ccd4a63SDavid du Colombier 				block_cipher(ds->expanded, p, 1);
13458ccd4a63SDavid du Colombier 				tp = tmp;
13468ccd4a63SDavid du Colombier 				ip = ds->ivec;
13478ccd4a63SDavid du Colombier 				for(eip = ip+8; ip < eip; ){
13488ccd4a63SDavid du Colombier 					*p++ ^= *ip;
13498ccd4a63SDavid du Colombier 					*ip++ = *tp++;
13508ccd4a63SDavid du Colombier 				}
13518ccd4a63SDavid du Colombier 			}
13528ccd4a63SDavid du Colombier 			break;
13538ccd4a63SDavid du Colombier 		case RC4:
13548ccd4a63SDavid du Colombier 			rc4(s->in.state, b->rp, BLEN(b));
13558ccd4a63SDavid du Colombier 			break;
13568ccd4a63SDavid du Colombier 		}
13578ccd4a63SDavid du Colombier 	}
13588ccd4a63SDavid du Colombier 	return bin;
13598ccd4a63SDavid du Colombier }
13608ccd4a63SDavid du Colombier 
13618ccd4a63SDavid du Colombier static Block*
digestb(Dstate * s,Block * b,int offset)13628ccd4a63SDavid du Colombier digestb(Dstate *s, Block *b, int offset)
13638ccd4a63SDavid du Colombier {
13648ccd4a63SDavid du Colombier 	uchar *p;
13658ccd4a63SDavid du Colombier 	DigestState ss;
13668ccd4a63SDavid du Colombier 	uchar msgid[4];
13678ccd4a63SDavid du Colombier 	ulong n, h;
13688ccd4a63SDavid du Colombier 	OneWay *w;
13698ccd4a63SDavid du Colombier 
13708ccd4a63SDavid du Colombier 	w = &s->out;
13718ccd4a63SDavid du Colombier 
13728ccd4a63SDavid du Colombier 	memset(&ss, 0, sizeof(ss));
13738ccd4a63SDavid du Colombier 	h = s->diglen + offset;
13748ccd4a63SDavid du Colombier 	n = BLEN(b) - h;
13758ccd4a63SDavid du Colombier 
13768ccd4a63SDavid du Colombier 	/* hash secret + message */
13778ccd4a63SDavid du Colombier 	(*s->hf)(w->secret, w->slen, 0, &ss);
13788ccd4a63SDavid du Colombier 	(*s->hf)(b->rp + h, n, 0, &ss);
13798ccd4a63SDavid du Colombier 
13808ccd4a63SDavid du Colombier 	/* hash message id */
13818ccd4a63SDavid du Colombier 	p = msgid;
13828ccd4a63SDavid du Colombier 	n = w->mid;
13838ccd4a63SDavid du Colombier 	*p++ = n>>24;
13848ccd4a63SDavid du Colombier 	*p++ = n>>16;
13858ccd4a63SDavid du Colombier 	*p++ = n>>8;
13868ccd4a63SDavid du Colombier 	*p = n;
13878ccd4a63SDavid du Colombier 	(*s->hf)(msgid, 4, b->rp + offset, &ss);
13888ccd4a63SDavid du Colombier 
13898ccd4a63SDavid du Colombier 	return b;
13908ccd4a63SDavid du Colombier }
13918ccd4a63SDavid du Colombier 
13928ccd4a63SDavid du Colombier static void
checkdigestb(Dstate * s,Block * bin)13938ccd4a63SDavid du Colombier checkdigestb(Dstate *s, Block *bin)
13948ccd4a63SDavid du Colombier {
13958ccd4a63SDavid du Colombier 	uchar *p;
13968ccd4a63SDavid du Colombier 	DigestState ss;
13978ccd4a63SDavid du Colombier 	uchar msgid[4];
13988ccd4a63SDavid du Colombier 	int n, h;
13998ccd4a63SDavid du Colombier 	OneWay *w;
14008ccd4a63SDavid du Colombier 	uchar digest[128];
14018ccd4a63SDavid du Colombier 	Block *b;
14028ccd4a63SDavid du Colombier 
14038ccd4a63SDavid du Colombier 	w = &s->in;
14048ccd4a63SDavid du Colombier 
14058ccd4a63SDavid du Colombier 	memset(&ss, 0, sizeof(ss));
14068ccd4a63SDavid du Colombier 
14078ccd4a63SDavid du Colombier 	/* hash secret */
14088ccd4a63SDavid du Colombier 	(*s->hf)(w->secret, w->slen, 0, &ss);
14098ccd4a63SDavid du Colombier 
14108ccd4a63SDavid du Colombier 	/* hash message */
14118ccd4a63SDavid du Colombier 	h = s->diglen;
14128ccd4a63SDavid du Colombier 	for(b = bin; b; b = b->next){
14138ccd4a63SDavid du Colombier 		n = BLEN(b) - h;
14148ccd4a63SDavid du Colombier 		if(n < 0)
14158ccd4a63SDavid du Colombier 			panic("checkdigestb");
14168ccd4a63SDavid du Colombier 		(*s->hf)(b->rp + h, n, 0, &ss);
14178ccd4a63SDavid du Colombier 		h = 0;
14188ccd4a63SDavid du Colombier 	}
14198ccd4a63SDavid du Colombier 
14208ccd4a63SDavid du Colombier 	/* hash message id */
14218ccd4a63SDavid du Colombier 	p = msgid;
14228ccd4a63SDavid du Colombier 	n = w->mid;
14238ccd4a63SDavid du Colombier 	*p++ = n>>24;
14248ccd4a63SDavid du Colombier 	*p++ = n>>16;
14258ccd4a63SDavid du Colombier 	*p++ = n>>8;
14268ccd4a63SDavid du Colombier 	*p = n;
14278ccd4a63SDavid du Colombier 	(*s->hf)(msgid, 4, digest, &ss);
14288ccd4a63SDavid du Colombier 
14298ccd4a63SDavid du Colombier 	if(memcmp(digest, bin->rp, s->diglen) != 0)
14308ccd4a63SDavid du Colombier 		error("bad digest");
14318ccd4a63SDavid du Colombier }
14328ccd4a63SDavid du Colombier 
14338ccd4a63SDavid du Colombier /* get channel associated with an fd */
14348ccd4a63SDavid du Colombier static Chan*
buftochan(char * p)14358ccd4a63SDavid du Colombier buftochan(char *p)
14368ccd4a63SDavid du Colombier {
14378ccd4a63SDavid du Colombier 	Chan *c;
14388ccd4a63SDavid du Colombier 	int fd;
14398ccd4a63SDavid du Colombier 
14408ccd4a63SDavid du Colombier 	if(p == 0)
14418ccd4a63SDavid du Colombier 		error(Ebadarg);
14428ccd4a63SDavid du Colombier 	fd = strtoul(p, 0, 0);
14438ccd4a63SDavid du Colombier 	if(fd < 0)
14448ccd4a63SDavid du Colombier 		error(Ebadarg);
14458ccd4a63SDavid du Colombier 	c = fdtochan(fd, -1, 0, 1);	/* error check and inc ref */
14468ccd4a63SDavid du Colombier 	if(devtab[c->type] == &ssldevtab){
14478ccd4a63SDavid du Colombier 		cclose(c);
14488ccd4a63SDavid du Colombier 		error("cannot ssl encrypt devssl files");
14498ccd4a63SDavid du Colombier 	}
14508ccd4a63SDavid du Colombier 	return c;
14518ccd4a63SDavid du Colombier }
14528ccd4a63SDavid du Colombier 
14538ccd4a63SDavid du Colombier /* hand up a digest connection */
14548ccd4a63SDavid du Colombier static void
sslhangup(Dstate * s)14558ccd4a63SDavid du Colombier sslhangup(Dstate *s)
14568ccd4a63SDavid du Colombier {
14578ccd4a63SDavid du Colombier 	Block *b;
14588ccd4a63SDavid du Colombier 
14598ccd4a63SDavid du Colombier 	qlock(&s->in.q);
14608ccd4a63SDavid du Colombier 	for(b = s->processed; b; b = s->processed){
14618ccd4a63SDavid du Colombier 		s->processed = b->next;
14628ccd4a63SDavid du Colombier 		freeb(b);
14638ccd4a63SDavid du Colombier 	}
14648ccd4a63SDavid du Colombier 	if(s->unprocessed){
14658ccd4a63SDavid du Colombier 		freeb(s->unprocessed);
14668ccd4a63SDavid du Colombier 		s->unprocessed = 0;
14678ccd4a63SDavid du Colombier 	}
14688ccd4a63SDavid du Colombier 	s->state = Sincomplete;
14698ccd4a63SDavid du Colombier 	qunlock(&s->in.q);
14708ccd4a63SDavid du Colombier }
14718ccd4a63SDavid du Colombier 
14728ccd4a63SDavid du Colombier static Dstate*
dsclone(Chan * ch)14738ccd4a63SDavid du Colombier dsclone(Chan *ch)
14748ccd4a63SDavid du Colombier {
14758ccd4a63SDavid du Colombier 	int i;
14768ccd4a63SDavid du Colombier 	Dstate *ret;
14778ccd4a63SDavid du Colombier 
14788ccd4a63SDavid du Colombier 	if(waserror()) {
14798ccd4a63SDavid du Colombier 		unlock(&dslock);
14808ccd4a63SDavid du Colombier 		nexterror();
14818ccd4a63SDavid du Colombier 	}
14828ccd4a63SDavid du Colombier 	lock(&dslock);
14838ccd4a63SDavid du Colombier 	ret = nil;
14848ccd4a63SDavid du Colombier 	for(i=0; i<Maxdstate; i++){
14858ccd4a63SDavid du Colombier 		if(dstate[i] == nil){
14868ccd4a63SDavid du Colombier 			dsnew(ch, &dstate[i]);
14878ccd4a63SDavid du Colombier 			ret = dstate[i];
14888ccd4a63SDavid du Colombier 			break;
14898ccd4a63SDavid du Colombier 		}
14908ccd4a63SDavid du Colombier 	}
14918ccd4a63SDavid du Colombier 	unlock(&dslock);
14928ccd4a63SDavid du Colombier 	poperror();
14938ccd4a63SDavid du Colombier 	return ret;
14948ccd4a63SDavid du Colombier }
14958ccd4a63SDavid du Colombier 
14968ccd4a63SDavid du Colombier static void
dsnew(Chan * ch,Dstate ** pp)14978ccd4a63SDavid du Colombier dsnew(Chan *ch, Dstate **pp)
14988ccd4a63SDavid du Colombier {
14998ccd4a63SDavid du Colombier 	Dstate *s;
15008ccd4a63SDavid du Colombier 	int t;
15018ccd4a63SDavid du Colombier 
15028ccd4a63SDavid du Colombier 	*pp = s = malloc(sizeof(*s));
15038ccd4a63SDavid du Colombier 	if(!s)
15048ccd4a63SDavid du Colombier 		error(Enomem);
15058ccd4a63SDavid du Colombier 	if(pp - dstate >= dshiwat)
15068ccd4a63SDavid du Colombier 		dshiwat++;
15078ccd4a63SDavid du Colombier 	memset(s, 0, sizeof(*s));
15088ccd4a63SDavid du Colombier 	s->state = Sincomplete;
15098ccd4a63SDavid du Colombier 	s->ref = 1;
15108ccd4a63SDavid du Colombier 	kstrdup(&s->user, up->user);
15118ccd4a63SDavid du Colombier 	s->perm = 0660;
15128ccd4a63SDavid du Colombier 	t = TYPE(ch->qid);
15138ccd4a63SDavid du Colombier 	if(t == Qclonus)
15148ccd4a63SDavid du Colombier 		t = Qctl;
15158ccd4a63SDavid du Colombier 	ch->qid.path = QID(pp - dstate, t);
15168ccd4a63SDavid du Colombier 	ch->qid.vers = 0;
15178ccd4a63SDavid du Colombier }
1518