xref: /plan9/sys/src/cmd/ssh1/agent.c (revision 63afb9a5d3f910047231762bcce0ee49fed3d07c)
1*63afb9a5SDavid du Colombier #include "ssh.h"
2*63afb9a5SDavid du Colombier #include <bio.h>
3*63afb9a5SDavid du Colombier 
4*63afb9a5SDavid du Colombier typedef struct Key Key;
5*63afb9a5SDavid du Colombier struct Key
6*63afb9a5SDavid du Colombier {
7*63afb9a5SDavid du Colombier 	mpint *mod;
8*63afb9a5SDavid du Colombier 	mpint *ek;
9*63afb9a5SDavid du Colombier 	char *comment;
10*63afb9a5SDavid du Colombier };
11*63afb9a5SDavid du Colombier 
12*63afb9a5SDavid du Colombier typedef struct Achan Achan;
13*63afb9a5SDavid du Colombier struct Achan
14*63afb9a5SDavid du Colombier {
15*63afb9a5SDavid du Colombier 	int open;
16*63afb9a5SDavid du Colombier 	u32int chan;	/* of remote */
17*63afb9a5SDavid du Colombier 	uchar lbuf[4];
18*63afb9a5SDavid du Colombier 	uint nlbuf;
19*63afb9a5SDavid du Colombier 	uint len;
20*63afb9a5SDavid du Colombier 	uchar *data;
21*63afb9a5SDavid du Colombier 	int ndata;
22*63afb9a5SDavid du Colombier 	int needeof;
23*63afb9a5SDavid du Colombier 	int needclosed;
24*63afb9a5SDavid du Colombier };
25*63afb9a5SDavid du Colombier 
26*63afb9a5SDavid du Colombier Achan achan[16];
27*63afb9a5SDavid du Colombier 
28*63afb9a5SDavid du Colombier static char*
find(char ** f,int nf,char * k)29*63afb9a5SDavid du Colombier find(char **f, int nf, char *k)
30*63afb9a5SDavid du Colombier {
31*63afb9a5SDavid du Colombier 	int i, len;
32*63afb9a5SDavid du Colombier 
33*63afb9a5SDavid du Colombier 	len = strlen(k);
34*63afb9a5SDavid du Colombier 	for(i=1; i<nf; i++)	/* i=1: f[0] is "key" */
35*63afb9a5SDavid du Colombier 		if(strncmp(f[i], k, len) == 0 && f[i][len] == '=')
36*63afb9a5SDavid du Colombier 			return f[i]+len+1;
37*63afb9a5SDavid du Colombier 	return nil;
38*63afb9a5SDavid du Colombier }
39*63afb9a5SDavid du Colombier 
40*63afb9a5SDavid du Colombier static int
listkeys(Key ** kp)41*63afb9a5SDavid du Colombier listkeys(Key **kp)
42*63afb9a5SDavid du Colombier {
43*63afb9a5SDavid du Colombier 	Biobuf *b;
44*63afb9a5SDavid du Colombier 	Key *k;
45*63afb9a5SDavid du Colombier 	int nk;
46*63afb9a5SDavid du Colombier 	char *p, *f[20];
47*63afb9a5SDavid du Colombier 	int nf;
48*63afb9a5SDavid du Colombier 	mpint *mod, *ek;
49*63afb9a5SDavid du Colombier 
50*63afb9a5SDavid du Colombier 	*kp = nil;
51*63afb9a5SDavid du Colombier 	if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
52*63afb9a5SDavid du Colombier 		return -1;
53*63afb9a5SDavid du Colombier 
54*63afb9a5SDavid du Colombier 	k = nil;
55*63afb9a5SDavid du Colombier 	nk = 0;
56*63afb9a5SDavid du Colombier 	while((p = Brdline(b, '\n')) != nil){
57*63afb9a5SDavid du Colombier 		p[Blinelen(b)-1] = '\0';
58*63afb9a5SDavid du Colombier 		nf = tokenize(p, f, nelem(f));
59*63afb9a5SDavid du Colombier 		if(nf == 0 || strcmp(f[0], "key") != 0)
60*63afb9a5SDavid du Colombier 			continue;
61*63afb9a5SDavid du Colombier 		p = find(f, nf, "proto");
62*63afb9a5SDavid du Colombier 		if(p == nil || strcmp(p, "rsa") != 0)
63*63afb9a5SDavid du Colombier 			continue;
64*63afb9a5SDavid du Colombier 		p = find(f, nf, "n");
65*63afb9a5SDavid du Colombier 		if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
66*63afb9a5SDavid du Colombier 			continue;
67*63afb9a5SDavid du Colombier 		p = find(f, nf, "ek");
68*63afb9a5SDavid du Colombier 		if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
69*63afb9a5SDavid du Colombier 			mpfree(mod);
70*63afb9a5SDavid du Colombier 			continue;
71*63afb9a5SDavid du Colombier 		}
72*63afb9a5SDavid du Colombier 		p = find(f, nf, "comment");
73*63afb9a5SDavid du Colombier 		if(p == nil)
74*63afb9a5SDavid du Colombier 			p = "";
75*63afb9a5SDavid du Colombier 		k = erealloc(k, (nk+1)*sizeof(k[0]));
76*63afb9a5SDavid du Colombier 		k[nk].mod = mod;
77*63afb9a5SDavid du Colombier 		k[nk].ek = ek;
78*63afb9a5SDavid du Colombier 		k[nk].comment = emalloc(strlen(p)+1);
79*63afb9a5SDavid du Colombier 		strcpy(k[nk].comment, p);
80*63afb9a5SDavid du Colombier 		nk++;
81*63afb9a5SDavid du Colombier 	}
82*63afb9a5SDavid du Colombier 	Bterm(b);
83*63afb9a5SDavid du Colombier 	*kp = k;
84*63afb9a5SDavid du Colombier 	return nk;
85*63afb9a5SDavid du Colombier }
86*63afb9a5SDavid du Colombier 
87*63afb9a5SDavid du Colombier 
88*63afb9a5SDavid du Colombier static int
dorsa(mpint * mod,mpint * exp,mpint * chal,uchar chalbuf[32])89*63afb9a5SDavid du Colombier dorsa(mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
90*63afb9a5SDavid du Colombier {
91*63afb9a5SDavid du Colombier 	int afd;
92*63afb9a5SDavid du Colombier 	AuthRpc *rpc;
93*63afb9a5SDavid du Colombier 	mpint *m;
94*63afb9a5SDavid du Colombier 	char buf[4096], *p;
95*63afb9a5SDavid du Colombier 	mpint *decr, *unpad;
96*63afb9a5SDavid du Colombier 
97*63afb9a5SDavid du Colombier 	USED(exp);
98*63afb9a5SDavid du Colombier 
99*63afb9a5SDavid du Colombier 	snprint(buf, sizeof buf, "proto=rsa service=ssh role=client");
100*63afb9a5SDavid du Colombier 	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
101*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
102*63afb9a5SDavid du Colombier 		return -1;
103*63afb9a5SDavid du Colombier 	}
104*63afb9a5SDavid du Colombier 	if((rpc = auth_allocrpc(afd)) == nil){
105*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "auth_allocrpc: %r\n");
106*63afb9a5SDavid du Colombier 		close(afd);
107*63afb9a5SDavid du Colombier 		return -1;
108*63afb9a5SDavid du Colombier 	}
109*63afb9a5SDavid du Colombier 	if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
110*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "auth_rpc start failed: %r\n");
111*63afb9a5SDavid du Colombier 	Die:
112*63afb9a5SDavid du Colombier 		auth_freerpc(rpc);
113*63afb9a5SDavid du Colombier 		close(afd);
114*63afb9a5SDavid du Colombier 		return -1;
115*63afb9a5SDavid du Colombier 	}
116*63afb9a5SDavid du Colombier 	m = nil;
117*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "trying factotum rsa keys\n");
118*63afb9a5SDavid du Colombier 	while(auth_rpc(rpc, "read", nil, 0) == ARok){
119*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
120*63afb9a5SDavid du Colombier 		m = strtomp(rpc->arg, nil, 16, nil);
121*63afb9a5SDavid du Colombier 		if(mpcmp(m, mod) == 0)
122*63afb9a5SDavid du Colombier 			break;
123*63afb9a5SDavid du Colombier 		mpfree(m);
124*63afb9a5SDavid du Colombier 		m = nil;
125*63afb9a5SDavid du Colombier 	}
126*63afb9a5SDavid du Colombier 	if(m == nil)
127*63afb9a5SDavid du Colombier 		goto Die;
128*63afb9a5SDavid du Colombier 	mpfree(m);
129*63afb9a5SDavid du Colombier 
130*63afb9a5SDavid du Colombier 	p = mptoa(chal, 16, nil, 0);
131*63afb9a5SDavid du Colombier 	if(p == nil){
132*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tmptoa failed: %r\n");
133*63afb9a5SDavid du Colombier 		goto Die;
134*63afb9a5SDavid du Colombier 	}
135*63afb9a5SDavid du Colombier 	if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
136*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
137*63afb9a5SDavid du Colombier 		free(p);
138*63afb9a5SDavid du Colombier 		goto Die;
139*63afb9a5SDavid du Colombier 	}
140*63afb9a5SDavid du Colombier 	free(p);
141*63afb9a5SDavid du Colombier 	if(auth_rpc(rpc, "read", nil, 0) != ARok){
142*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
143*63afb9a5SDavid du Colombier 		goto Die;
144*63afb9a5SDavid du Colombier 	}
145*63afb9a5SDavid du Colombier 	decr = strtomp(rpc->arg, nil, 16, nil);
146*63afb9a5SDavid du Colombier 	if(decr == nil){
147*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg);
148*63afb9a5SDavid du Colombier 		goto Die;
149*63afb9a5SDavid du Colombier 	}
150*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "\tdecrypted %B\n", decr);
151*63afb9a5SDavid du Colombier 	unpad = rsaunpad(decr);
152*63afb9a5SDavid du Colombier 	if(unpad == nil){
153*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tunpad %B failed\n", decr);
154*63afb9a5SDavid du Colombier 		mpfree(decr);
155*63afb9a5SDavid du Colombier 		goto Die;
156*63afb9a5SDavid du Colombier 	}
157*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "\tunpadded %B\n", unpad);
158*63afb9a5SDavid du Colombier 	mpfree(decr);
159*63afb9a5SDavid du Colombier 	mptoberjust(unpad, chalbuf, 32);
160*63afb9a5SDavid du Colombier 	mpfree(unpad);
161*63afb9a5SDavid du Colombier 	auth_freerpc(rpc);
162*63afb9a5SDavid du Colombier 	close(afd);
163*63afb9a5SDavid du Colombier 	return 0;
164*63afb9a5SDavid du Colombier }
165*63afb9a5SDavid du Colombier 
166*63afb9a5SDavid du Colombier int
startagent(Conn * c)167*63afb9a5SDavid du Colombier startagent(Conn *c)
168*63afb9a5SDavid du Colombier {
169*63afb9a5SDavid du Colombier 	int ret;
170*63afb9a5SDavid du Colombier 	Msg *m;
171*63afb9a5SDavid du Colombier 
172*63afb9a5SDavid du Colombier 	m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0);
173*63afb9a5SDavid du Colombier 	sendmsg(m);
174*63afb9a5SDavid du Colombier 
175*63afb9a5SDavid du Colombier 	m = recvmsg(c, -1);
176*63afb9a5SDavid du Colombier 	switch(m->type){
177*63afb9a5SDavid du Colombier 	case SSH_SMSG_SUCCESS:
178*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "agent allocated\n");
179*63afb9a5SDavid du Colombier 		ret = 0;
180*63afb9a5SDavid du Colombier 		break;
181*63afb9a5SDavid du Colombier 	case SSH_SMSG_FAILURE:
182*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "agent failed to allocate\n");
183*63afb9a5SDavid du Colombier 		ret = -1;
184*63afb9a5SDavid du Colombier 		break;
185*63afb9a5SDavid du Colombier 	default:
186*63afb9a5SDavid du Colombier 		badmsg(m, 0);
187*63afb9a5SDavid du Colombier 		ret = -1;
188*63afb9a5SDavid du Colombier 		break;
189*63afb9a5SDavid du Colombier 	}
190*63afb9a5SDavid du Colombier 	free(m);
191*63afb9a5SDavid du Colombier 	return ret;
192*63afb9a5SDavid du Colombier }
193*63afb9a5SDavid du Colombier 
194*63afb9a5SDavid du Colombier void handlefullmsg(Conn*, Achan*);
195*63afb9a5SDavid du Colombier 
196*63afb9a5SDavid du Colombier void
handleagentmsg(Msg * m)197*63afb9a5SDavid du Colombier handleagentmsg(Msg *m)
198*63afb9a5SDavid du Colombier {
199*63afb9a5SDavid du Colombier 	u32int chan, len;
200*63afb9a5SDavid du Colombier 	int n;
201*63afb9a5SDavid du Colombier 	Achan *a;
202*63afb9a5SDavid du Colombier 
203*63afb9a5SDavid du Colombier 	assert(m->type == SSH_MSG_CHANNEL_DATA);
204*63afb9a5SDavid du Colombier 
205*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "agent data\n");
206*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "\t%.*H\n", (int)(m->ep - m->rp), m->rp);
207*63afb9a5SDavid du Colombier 	chan = getlong(m);
208*63afb9a5SDavid du Colombier 	len = getlong(m);
209*63afb9a5SDavid du Colombier 	if(m->rp+len != m->ep)
210*63afb9a5SDavid du Colombier 		sysfatal("got bad channel data");
211*63afb9a5SDavid du Colombier 
212*63afb9a5SDavid du Colombier 	if(chan >= nelem(achan))
213*63afb9a5SDavid du Colombier 		error("bad channel in agent request");
214*63afb9a5SDavid du Colombier 
215*63afb9a5SDavid du Colombier 	a = &achan[chan];
216*63afb9a5SDavid du Colombier 
217*63afb9a5SDavid du Colombier 	while(m->rp < m->ep){
218*63afb9a5SDavid du Colombier 		if(a->nlbuf < 4){
219*63afb9a5SDavid du Colombier 			a->lbuf[a->nlbuf++] = getbyte(m);
220*63afb9a5SDavid du Colombier 			if(a->nlbuf == 4){
221*63afb9a5SDavid du Colombier 				a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
222*63afb9a5SDavid du Colombier 				a->data = erealloc(a->data, a->len);
223*63afb9a5SDavid du Colombier 				a->ndata = 0;
224*63afb9a5SDavid du Colombier 			}
225*63afb9a5SDavid du Colombier 			continue;
226*63afb9a5SDavid du Colombier 		}
227*63afb9a5SDavid du Colombier 		if(a->ndata < a->len){
228*63afb9a5SDavid du Colombier 			n = a->len - a->ndata;
229*63afb9a5SDavid du Colombier 			if(n > m->ep - m->rp)
230*63afb9a5SDavid du Colombier 				n = m->ep - m->rp;
231*63afb9a5SDavid du Colombier 			memmove(a->data+a->ndata, getbytes(m, n), n);
232*63afb9a5SDavid du Colombier 			a->ndata += n;
233*63afb9a5SDavid du Colombier 		}
234*63afb9a5SDavid du Colombier 		if(a->ndata == a->len){
235*63afb9a5SDavid du Colombier 			handlefullmsg(m->c, a);
236*63afb9a5SDavid du Colombier 			a->nlbuf = 0;
237*63afb9a5SDavid du Colombier 		}
238*63afb9a5SDavid du Colombier 	}
239*63afb9a5SDavid du Colombier }
240*63afb9a5SDavid du Colombier 
241*63afb9a5SDavid du Colombier void
handlefullmsg(Conn * c,Achan * a)242*63afb9a5SDavid du Colombier handlefullmsg(Conn *c, Achan *a)
243*63afb9a5SDavid du Colombier {
244*63afb9a5SDavid du Colombier 	int i;
245*63afb9a5SDavid du Colombier 	u32int chan, len, n, rt;
246*63afb9a5SDavid du Colombier 	uchar type;
247*63afb9a5SDavid du Colombier 	Msg *m, mm;
248*63afb9a5SDavid du Colombier 	Msg *r;
249*63afb9a5SDavid du Colombier 	Key *k;
250*63afb9a5SDavid du Colombier 	int nk;
251*63afb9a5SDavid du Colombier 	mpint *mod, *ek, *chal;
252*63afb9a5SDavid du Colombier 	uchar sessid[16];
253*63afb9a5SDavid du Colombier 	uchar chalbuf[32];
254*63afb9a5SDavid du Colombier 	uchar digest[16];
255*63afb9a5SDavid du Colombier 	DigestState *s;
256*63afb9a5SDavid du Colombier 	static int first;
257*63afb9a5SDavid du Colombier 
258*63afb9a5SDavid du Colombier 	assert(a->len == a->ndata);
259*63afb9a5SDavid du Colombier 
260*63afb9a5SDavid du Colombier 	chan = a->chan;
261*63afb9a5SDavid du Colombier 	mm.rp = a->data;
262*63afb9a5SDavid du Colombier 	mm.ep = a->data+a->ndata;
263*63afb9a5SDavid du Colombier 	mm.c = c;
264*63afb9a5SDavid du Colombier 	m = &mm;
265*63afb9a5SDavid du Colombier 
266*63afb9a5SDavid du Colombier 	type = getbyte(m);
267*63afb9a5SDavid du Colombier 
268*63afb9a5SDavid du Colombier 	if(first == 0){
269*63afb9a5SDavid du Colombier 		first++;
270*63afb9a5SDavid du Colombier 		fmtinstall('H', encodefmt);
271*63afb9a5SDavid du Colombier 	}
272*63afb9a5SDavid du Colombier 
273*63afb9a5SDavid du Colombier 	switch(type){
274*63afb9a5SDavid du Colombier 	default:
275*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "unknown msg type\n");
276*63afb9a5SDavid du Colombier 	Failure:
277*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "agent sending failure\n");
278*63afb9a5SDavid du Colombier 		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
279*63afb9a5SDavid du Colombier 		putlong(r, chan);
280*63afb9a5SDavid du Colombier 		putlong(r, 5);
281*63afb9a5SDavid du Colombier 		putlong(r, 1);
282*63afb9a5SDavid du Colombier 		putbyte(r, SSH_AGENT_FAILURE);
283*63afb9a5SDavid du Colombier 		sendmsg(r);
284*63afb9a5SDavid du Colombier 		return;
285*63afb9a5SDavid du Colombier 
286*63afb9a5SDavid du Colombier 	case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
287*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "agent request identities\n");
288*63afb9a5SDavid du Colombier 		nk = listkeys(&k);
289*63afb9a5SDavid du Colombier 		if(nk < 0)
290*63afb9a5SDavid du Colombier 			goto Failure;
291*63afb9a5SDavid du Colombier 		len = 1+4;	/* type, nk */
292*63afb9a5SDavid du Colombier 		for(i=0; i<nk; i++){
293*63afb9a5SDavid du Colombier 			len += 4;
294*63afb9a5SDavid du Colombier 			len += 2+(mpsignif(k[i].ek)+7)/8;
295*63afb9a5SDavid du Colombier 			len += 2+(mpsignif(k[i].mod)+7)/8;
296*63afb9a5SDavid du Colombier 			len += 4+strlen(k[i].comment);
297*63afb9a5SDavid du Colombier 		}
298*63afb9a5SDavid du Colombier 		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
299*63afb9a5SDavid du Colombier 		putlong(r, chan);
300*63afb9a5SDavid du Colombier 		putlong(r, len+4);
301*63afb9a5SDavid du Colombier 		putlong(r, len);
302*63afb9a5SDavid du Colombier 		putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
303*63afb9a5SDavid du Colombier 		putlong(r, nk);
304*63afb9a5SDavid du Colombier 		for(i=0; i<nk; i++){
305*63afb9a5SDavid du Colombier 			debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
306*63afb9a5SDavid du Colombier 			putlong(r, mpsignif(k[i].mod));
307*63afb9a5SDavid du Colombier 			putmpint(r, k[i].ek);
308*63afb9a5SDavid du Colombier 			putmpint(r, k[i].mod);
309*63afb9a5SDavid du Colombier 			putstring(r, k[i].comment);
310*63afb9a5SDavid du Colombier 			mpfree(k[i].ek);
311*63afb9a5SDavid du Colombier 			mpfree(k[i].mod);
312*63afb9a5SDavid du Colombier 			free(k[i].comment);
313*63afb9a5SDavid du Colombier 		}
314*63afb9a5SDavid du Colombier 		free(k);
315*63afb9a5SDavid du Colombier 		sendmsg(r);
316*63afb9a5SDavid du Colombier 		break;
317*63afb9a5SDavid du Colombier 
318*63afb9a5SDavid du Colombier 	case SSH_AGENTC_RSA_CHALLENGE:
319*63afb9a5SDavid du Colombier 		n = getlong(m);
320*63afb9a5SDavid du Colombier 		USED(n);	/* number of bits in key; who cares? */
321*63afb9a5SDavid du Colombier 		ek = getmpint(m);
322*63afb9a5SDavid du Colombier 		mod = getmpint(m);
323*63afb9a5SDavid du Colombier 		chal = getmpint(m);
324*63afb9a5SDavid du Colombier 		memmove(sessid, getbytes(m, 16), 16);
325*63afb9a5SDavid du Colombier 		rt = getlong(m);
326*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
327*63afb9a5SDavid du Colombier 			ek, mod, chal, rt, m->rp, m->ep);
328*63afb9a5SDavid du Colombier 		if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
329*63afb9a5SDavid du Colombier 			mpfree(ek);
330*63afb9a5SDavid du Colombier 			mpfree(mod);
331*63afb9a5SDavid du Colombier 			mpfree(chal);
332*63afb9a5SDavid du Colombier 			goto Failure;
333*63afb9a5SDavid du Colombier 		}
334*63afb9a5SDavid du Colombier 		s = md5(chalbuf, 32, nil, nil);
335*63afb9a5SDavid du Colombier 		md5(sessid, 16, digest, s);
336*63afb9a5SDavid du Colombier 		r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
337*63afb9a5SDavid du Colombier 		putlong(r, chan);
338*63afb9a5SDavid du Colombier 		putlong(r, 4+16+1);
339*63afb9a5SDavid du Colombier 		putlong(r, 16+1);
340*63afb9a5SDavid du Colombier 		putbyte(r, SSH_AGENT_RSA_RESPONSE);
341*63afb9a5SDavid du Colombier 		putbytes(r, digest, 16);
342*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "digest %.16H\n", digest);
343*63afb9a5SDavid du Colombier 		sendmsg(r);
344*63afb9a5SDavid du Colombier 		mpfree(ek);
345*63afb9a5SDavid du Colombier 		mpfree(mod);
346*63afb9a5SDavid du Colombier 		mpfree(chal);
347*63afb9a5SDavid du Colombier 		return;
348*63afb9a5SDavid du Colombier 
349*63afb9a5SDavid du Colombier 	case SSH_AGENTC_ADD_RSA_IDENTITY:
350*63afb9a5SDavid du Colombier 		goto Failure;
351*63afb9a5SDavid du Colombier /*
352*63afb9a5SDavid du Colombier 		n = getlong(m);
353*63afb9a5SDavid du Colombier 		pubmod = getmpint(m);
354*63afb9a5SDavid du Colombier 		pubexp = getmpint(m);
355*63afb9a5SDavid du Colombier 		privexp = getmpint(m);
356*63afb9a5SDavid du Colombier 		pinversemodq = getmpint(m);
357*63afb9a5SDavid du Colombier 		p = getmpint(m);
358*63afb9a5SDavid du Colombier 		q = getmpint(m);
359*63afb9a5SDavid du Colombier 		comment = getstring(m);
360*63afb9a5SDavid du Colombier 		add to factotum;
361*63afb9a5SDavid du Colombier 		send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
362*63afb9a5SDavid du Colombier */
363*63afb9a5SDavid du Colombier 
364*63afb9a5SDavid du Colombier 	case SSH_AGENTC_REMOVE_RSA_IDENTITY:
365*63afb9a5SDavid du Colombier 		goto Failure;
366*63afb9a5SDavid du Colombier /*
367*63afb9a5SDavid du Colombier 		n = getlong(m);
368*63afb9a5SDavid du Colombier 		pubmod = getmpint(m);
369*63afb9a5SDavid du Colombier 		pubexp = getmpint(m);
370*63afb9a5SDavid du Colombier 		tell factotum to del key
371*63afb9a5SDavid du Colombier 		send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
372*63afb9a5SDavid du Colombier */
373*63afb9a5SDavid du Colombier 	}
374*63afb9a5SDavid du Colombier }
375*63afb9a5SDavid du Colombier 
376*63afb9a5SDavid du Colombier void
handleagentopen(Msg * m)377*63afb9a5SDavid du Colombier handleagentopen(Msg *m)
378*63afb9a5SDavid du Colombier {
379*63afb9a5SDavid du Colombier 	int i;
380*63afb9a5SDavid du Colombier 	u32int remote;
381*63afb9a5SDavid du Colombier 
382*63afb9a5SDavid du Colombier 	assert(m->type == SSH_SMSG_AGENT_OPEN);
383*63afb9a5SDavid du Colombier 	remote = getlong(m);
384*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "agent open %d\n", remote);
385*63afb9a5SDavid du Colombier 
386*63afb9a5SDavid du Colombier 	for(i=0; i<nelem(achan); i++)
387*63afb9a5SDavid du Colombier 		if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
388*63afb9a5SDavid du Colombier 			break;
389*63afb9a5SDavid du Colombier 	if(i == nelem(achan)){
390*63afb9a5SDavid du Colombier 		m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
391*63afb9a5SDavid du Colombier 		putlong(m, remote);
392*63afb9a5SDavid du Colombier 		sendmsg(m);
393*63afb9a5SDavid du Colombier 		return;
394*63afb9a5SDavid du Colombier 	}
395*63afb9a5SDavid du Colombier 
396*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
397*63afb9a5SDavid du Colombier 	achan[i].open = 1;
398*63afb9a5SDavid du Colombier 	achan[i].needeof = 1;
399*63afb9a5SDavid du Colombier 	achan[i].needclosed = 1;
400*63afb9a5SDavid du Colombier 	achan[i].nlbuf = 0;
401*63afb9a5SDavid du Colombier 	achan[i].chan = remote;
402*63afb9a5SDavid du Colombier 	m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
403*63afb9a5SDavid du Colombier 	putlong(m, remote);
404*63afb9a5SDavid du Colombier 	putlong(m, i);
405*63afb9a5SDavid du Colombier 	sendmsg(m);
406*63afb9a5SDavid du Colombier }
407*63afb9a5SDavid du Colombier 
408*63afb9a5SDavid du Colombier void
handleagentieof(Msg * m)409*63afb9a5SDavid du Colombier handleagentieof(Msg *m)
410*63afb9a5SDavid du Colombier {
411*63afb9a5SDavid du Colombier 	u32int local;
412*63afb9a5SDavid du Colombier 
413*63afb9a5SDavid du Colombier 	assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
414*63afb9a5SDavid du Colombier 	local = getlong(m);
415*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "agent close %d\n", local);
416*63afb9a5SDavid du Colombier 	if(local < nelem(achan)){
417*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
418*63afb9a5SDavid du Colombier 		achan[local].open = 0;
419*63afb9a5SDavid du Colombier /*
420*63afb9a5SDavid du Colombier 		m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
421*63afb9a5SDavid du Colombier 		putlong(m, achan[local].chan);
422*63afb9a5SDavid du Colombier 		sendmsg(m);
423*63afb9a5SDavid du Colombier */
424*63afb9a5SDavid du Colombier 		if(achan[local].needeof){
425*63afb9a5SDavid du Colombier 			achan[local].needeof = 0;
426*63afb9a5SDavid du Colombier 			m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
427*63afb9a5SDavid du Colombier 			putlong(m, achan[local].chan);
428*63afb9a5SDavid du Colombier 			sendmsg(m);
429*63afb9a5SDavid du Colombier 		}
430*63afb9a5SDavid du Colombier 	}
431*63afb9a5SDavid du Colombier }
432*63afb9a5SDavid du Colombier 
433*63afb9a5SDavid du Colombier void
handleagentoclose(Msg * m)434*63afb9a5SDavid du Colombier handleagentoclose(Msg *m)
435*63afb9a5SDavid du Colombier {
436*63afb9a5SDavid du Colombier 	u32int local;
437*63afb9a5SDavid du Colombier 
438*63afb9a5SDavid du Colombier 	assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
439*63afb9a5SDavid du Colombier 	local = getlong(m);
440*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "agent close %d\n", local);
441*63afb9a5SDavid du Colombier 	if(local < nelem(achan)){
442*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
443*63afb9a5SDavid du Colombier 		if(achan[local].needclosed){
444*63afb9a5SDavid du Colombier 			achan[local].needclosed = 0;
445*63afb9a5SDavid du Colombier 			m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
446*63afb9a5SDavid du Colombier 			putlong(m, achan[local].chan);
447*63afb9a5SDavid du Colombier 			sendmsg(m);
448*63afb9a5SDavid du Colombier 		}
449*63afb9a5SDavid du Colombier 	}
450*63afb9a5SDavid du Colombier }
451