xref: /plan9/sys/src/cmd/ssh1/cmsg.c (revision 63afb9a5d3f910047231762bcce0ee49fed3d07c)
1*63afb9a5SDavid du Colombier #include "ssh.h"
2*63afb9a5SDavid du Colombier 
3*63afb9a5SDavid du Colombier static void
recv_ssh_smsg_public_key(Conn * c)4*63afb9a5SDavid du Colombier recv_ssh_smsg_public_key(Conn *c)
5*63afb9a5SDavid du Colombier {
6*63afb9a5SDavid du Colombier 	Msg *m;
7*63afb9a5SDavid du Colombier 
8*63afb9a5SDavid du Colombier 	m = recvmsg(c, SSH_SMSG_PUBLIC_KEY);
9*63afb9a5SDavid du Colombier 	memmove(c->cookie, getbytes(m, COOKIELEN), COOKIELEN);
10*63afb9a5SDavid du Colombier 	c->serverkey = getRSApub(m);
11*63afb9a5SDavid du Colombier 	c->hostkey = getRSApub(m);
12*63afb9a5SDavid du Colombier 	c->flags = getlong(m);
13*63afb9a5SDavid du Colombier 	c->ciphermask = getlong(m);
14*63afb9a5SDavid du Colombier 	c->authmask = getlong(m);
15*63afb9a5SDavid du Colombier 	free(m);
16*63afb9a5SDavid du Colombier }
17*63afb9a5SDavid du Colombier 
18*63afb9a5SDavid du Colombier static void
send_ssh_cmsg_session_key(Conn * c)19*63afb9a5SDavid du Colombier send_ssh_cmsg_session_key(Conn *c)
20*63afb9a5SDavid du Colombier {
21*63afb9a5SDavid du Colombier 	int i, n, buflen, serverkeylen, hostkeylen;
22*63afb9a5SDavid du Colombier 	mpint *b;
23*63afb9a5SDavid du Colombier 	uchar *buf;
24*63afb9a5SDavid du Colombier 	Msg *m;
25*63afb9a5SDavid du Colombier 	RSApub *ksmall, *kbig;
26*63afb9a5SDavid du Colombier 
27*63afb9a5SDavid du Colombier 	m = allocmsg(c, SSH_CMSG_SESSION_KEY, 2048);
28*63afb9a5SDavid du Colombier 	putbyte(m, c->cipher->id);
29*63afb9a5SDavid du Colombier 	putbytes(m, c->cookie, COOKIELEN);
30*63afb9a5SDavid du Colombier 
31*63afb9a5SDavid du Colombier 	serverkeylen = mpsignif(c->serverkey->n);
32*63afb9a5SDavid du Colombier 	hostkeylen = mpsignif(c->hostkey->n);
33*63afb9a5SDavid du Colombier 	ksmall = kbig = nil;
34*63afb9a5SDavid du Colombier 	if(serverkeylen+128 <= hostkeylen){
35*63afb9a5SDavid du Colombier 		ksmall = c->serverkey;
36*63afb9a5SDavid du Colombier 		kbig = c->hostkey;
37*63afb9a5SDavid du Colombier 	}else if(hostkeylen+128 <= serverkeylen){
38*63afb9a5SDavid du Colombier 		ksmall = c->hostkey;
39*63afb9a5SDavid du Colombier 		kbig = c->serverkey;
40*63afb9a5SDavid du Colombier 	}else
41*63afb9a5SDavid du Colombier 		error("server session and host keys do not differ by at least 128 bits");
42*63afb9a5SDavid du Colombier 
43*63afb9a5SDavid du Colombier 	buflen = (mpsignif(kbig->n)+7)/8;
44*63afb9a5SDavid du Colombier 	buf = emalloc(buflen);
45*63afb9a5SDavid du Colombier 
46*63afb9a5SDavid du Colombier 	debug(DBG_CRYPTO, "session key is %.*H\n", SESSKEYLEN, c->sesskey);
47*63afb9a5SDavid du Colombier 	memmove(buf, c->sesskey, SESSKEYLEN);
48*63afb9a5SDavid du Colombier 	for(i = 0; i < SESSIDLEN; i++)
49*63afb9a5SDavid du Colombier 		buf[i] ^= c->sessid[i];
50*63afb9a5SDavid du Colombier 	debug(DBG_CRYPTO, "munged session key is %.*H\n", SESSKEYLEN, buf);
51*63afb9a5SDavid du Colombier 
52*63afb9a5SDavid du Colombier 	b = rsaencryptbuf(ksmall, buf, SESSKEYLEN);
53*63afb9a5SDavid du Colombier 	n = (mpsignif(ksmall->n)+7) / 8;
54*63afb9a5SDavid du Colombier 	mptoberjust(b, buf, n);
55*63afb9a5SDavid du Colombier 	mpfree(b);
56*63afb9a5SDavid du Colombier 	debug(DBG_CRYPTO, "encrypted with ksmall is %.*H\n", n, buf);
57*63afb9a5SDavid du Colombier 
58*63afb9a5SDavid du Colombier 	b = rsaencryptbuf(kbig, buf, n);
59*63afb9a5SDavid du Colombier 	putmpint(m, b);
60*63afb9a5SDavid du Colombier 	debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b);
61*63afb9a5SDavid du Colombier 	mpfree(b);
62*63afb9a5SDavid du Colombier 
63*63afb9a5SDavid du Colombier 	memset(buf, 0, buflen);
64*63afb9a5SDavid du Colombier 	free(buf);
65*63afb9a5SDavid du Colombier 
66*63afb9a5SDavid du Colombier 	putlong(m, c->flags);
67*63afb9a5SDavid du Colombier 	sendmsg(m);
68*63afb9a5SDavid du Colombier }
69*63afb9a5SDavid du Colombier 
70*63afb9a5SDavid du Colombier static int
authuser(Conn * c)71*63afb9a5SDavid du Colombier authuser(Conn *c)
72*63afb9a5SDavid du Colombier {
73*63afb9a5SDavid du Colombier 	int i;
74*63afb9a5SDavid du Colombier 	Msg *m;
75*63afb9a5SDavid du Colombier 
76*63afb9a5SDavid du Colombier 	m = allocmsg(c, SSH_CMSG_USER, 4+strlen(c->user));
77*63afb9a5SDavid du Colombier 	putstring(m, c->user);
78*63afb9a5SDavid du Colombier 	sendmsg(m);
79*63afb9a5SDavid du Colombier 
80*63afb9a5SDavid du Colombier 	m = recvmsg(c, -1);
81*63afb9a5SDavid du Colombier 	switch(m->type){
82*63afb9a5SDavid du Colombier 	case SSH_SMSG_SUCCESS:
83*63afb9a5SDavid du Colombier 		free(m);
84*63afb9a5SDavid du Colombier 		return 0;
85*63afb9a5SDavid du Colombier 	case SSH_SMSG_FAILURE:
86*63afb9a5SDavid du Colombier 		free(m);
87*63afb9a5SDavid du Colombier 		break;
88*63afb9a5SDavid du Colombier 	default:
89*63afb9a5SDavid du Colombier 		badmsg(m, 0);
90*63afb9a5SDavid du Colombier 	}
91*63afb9a5SDavid du Colombier 
92*63afb9a5SDavid du Colombier 	for(i=0; i<c->nokauth; i++){
93*63afb9a5SDavid du Colombier 		debug(DBG_AUTH, "authmask %#lux, consider %s (%#x)\n",
94*63afb9a5SDavid du Colombier 			c->authmask, c->okauth[i]->name, 1<<c->okauth[i]->id);
95*63afb9a5SDavid du Colombier 		if(c->authmask & (1<<c->okauth[i]->id))
96*63afb9a5SDavid du Colombier 			if((*c->okauth[i]->fn)(c) == 0)
97*63afb9a5SDavid du Colombier 				return 0;
98*63afb9a5SDavid du Colombier 	}
99*63afb9a5SDavid du Colombier 
100*63afb9a5SDavid du Colombier 	debug(DBG_AUTH, "no auth methods worked; (authmask=%#lux)\n", c->authmask);
101*63afb9a5SDavid du Colombier 	return -1;
102*63afb9a5SDavid du Colombier }
103*63afb9a5SDavid du Colombier 
104*63afb9a5SDavid du Colombier static char
ask(Conn * c,char * answers,char * question)105*63afb9a5SDavid du Colombier ask(Conn *c, char *answers, char *question)
106*63afb9a5SDavid du Colombier {
107*63afb9a5SDavid du Colombier 	int fd;
108*63afb9a5SDavid du Colombier 	char buf[256];
109*63afb9a5SDavid du Colombier 
110*63afb9a5SDavid du Colombier 	if(!c->interactive)
111*63afb9a5SDavid du Colombier 		return answers[0];
112*63afb9a5SDavid du Colombier 
113*63afb9a5SDavid du Colombier 	if((fd = open("/dev/cons", ORDWR)) < 0)
114*63afb9a5SDavid du Colombier 		return answers[0];
115*63afb9a5SDavid du Colombier 
116*63afb9a5SDavid du Colombier 	fprint(fd, "%s", question);
117*63afb9a5SDavid du Colombier 	if(read(fd, buf, 256) <= 0 || buf[0]=='\n'){
118*63afb9a5SDavid du Colombier 		close(fd);
119*63afb9a5SDavid du Colombier 		return answers[0];
120*63afb9a5SDavid du Colombier 	}
121*63afb9a5SDavid du Colombier 	close(fd);
122*63afb9a5SDavid du Colombier 	return buf[0];
123*63afb9a5SDavid du Colombier }
124*63afb9a5SDavid du Colombier static void
checkkey(Conn * c)125*63afb9a5SDavid du Colombier checkkey(Conn *c)
126*63afb9a5SDavid du Colombier {
127*63afb9a5SDavid du Colombier 	char *home, *keyfile;
128*63afb9a5SDavid du Colombier 
129*63afb9a5SDavid du Colombier 	debug(DBG_CRYPTO, "checking key %B %B\n", c->hostkey->n, c->hostkey->ek);
130*63afb9a5SDavid du Colombier 	switch(findkey("/sys/lib/ssh/keyring", c->aliases, c->hostkey)){
131*63afb9a5SDavid du Colombier 	default:
132*63afb9a5SDavid du Colombier 		abort();
133*63afb9a5SDavid du Colombier 	case KeyOk:
134*63afb9a5SDavid du Colombier 		return;
135*63afb9a5SDavid du Colombier 	case KeyWrong:
136*63afb9a5SDavid du Colombier 		fprint(2, "server presented public key different than expected\n");
137*63afb9a5SDavid du Colombier 		fprint(2, "(expected key in /sys/lib/ssh/keyring).  will not continue.\n");
138*63afb9a5SDavid du Colombier 		error("bad server key");
139*63afb9a5SDavid du Colombier 
140*63afb9a5SDavid du Colombier 	case NoKey:
141*63afb9a5SDavid du Colombier 	case NoKeyFile:
142*63afb9a5SDavid du Colombier 		break;
143*63afb9a5SDavid du Colombier 	}
144*63afb9a5SDavid du Colombier 
145*63afb9a5SDavid du Colombier 	home = getenv("home");
146*63afb9a5SDavid du Colombier 	if(home == nil){
147*63afb9a5SDavid du Colombier 		fprint(2, "server %s not on keyring; will not continue.\n", c->host);
148*63afb9a5SDavid du Colombier 		error("bad server key");
149*63afb9a5SDavid du Colombier 	}
150*63afb9a5SDavid du Colombier 
151*63afb9a5SDavid du Colombier 	keyfile = smprint("%s/lib/keyring", home);
152*63afb9a5SDavid du Colombier 	if(keyfile == nil)
153*63afb9a5SDavid du Colombier 		error("out of memory");
154*63afb9a5SDavid du Colombier 
155*63afb9a5SDavid du Colombier 	switch(findkey(keyfile, c->aliases, c->hostkey)){
156*63afb9a5SDavid du Colombier 	default:
157*63afb9a5SDavid du Colombier 		abort();
158*63afb9a5SDavid du Colombier 	case KeyOk:
159*63afb9a5SDavid du Colombier 		return;
160*63afb9a5SDavid du Colombier 	case KeyWrong:
161*63afb9a5SDavid du Colombier 		fprint(2, "server %s presented public key different than expected\n", c->host);
162*63afb9a5SDavid du Colombier 		fprint(2, "(expected key in %s).  will not continue.\n", keyfile);
163*63afb9a5SDavid du Colombier 		fprint(2, "this could be a man-in-the-middle attack.\n");
164*63afb9a5SDavid du Colombier 		switch(ask(c, "eri", "replace key in keyfile (r), continue without replacing key (c), or exit (e) [e]")){
165*63afb9a5SDavid du Colombier 		case 'e':
166*63afb9a5SDavid du Colombier 			error("bad key");
167*63afb9a5SDavid du Colombier 		case 'r':
168*63afb9a5SDavid du Colombier 			if(replacekey(keyfile, c->aliases, c->hostkey) < 0)
169*63afb9a5SDavid du Colombier 				error("replacekey: %r");
170*63afb9a5SDavid du Colombier 			break;
171*63afb9a5SDavid du Colombier 		case 'c':
172*63afb9a5SDavid du Colombier 			break;
173*63afb9a5SDavid du Colombier 		}
174*63afb9a5SDavid du Colombier 		return;
175*63afb9a5SDavid du Colombier 	case NoKey:
176*63afb9a5SDavid du Colombier 	case NoKeyFile:
177*63afb9a5SDavid du Colombier 		fprint(2, "server %s not on keyring.\n", c->host);
178*63afb9a5SDavid du Colombier 		switch(ask(c, "eac", "add key to keyfile (a), continue without adding key (c), or exit (e) [e]")){
179*63afb9a5SDavid du Colombier 		case 'e':
180*63afb9a5SDavid du Colombier 			error("bad key");
181*63afb9a5SDavid du Colombier 		case 'a':
182*63afb9a5SDavid du Colombier 			if(appendkey(keyfile, c->aliases, c->hostkey) < 0)
183*63afb9a5SDavid du Colombier 				error("appendkey: %r");
184*63afb9a5SDavid du Colombier 			break;
185*63afb9a5SDavid du Colombier 		case 'c':
186*63afb9a5SDavid du Colombier 			break;
187*63afb9a5SDavid du Colombier 		}
188*63afb9a5SDavid du Colombier 		return;
189*63afb9a5SDavid du Colombier 	}
190*63afb9a5SDavid du Colombier }
191*63afb9a5SDavid du Colombier 
192*63afb9a5SDavid du Colombier void
sshclienthandshake(Conn * c)193*63afb9a5SDavid du Colombier sshclienthandshake(Conn *c)
194*63afb9a5SDavid du Colombier {
195*63afb9a5SDavid du Colombier 	char buf[128], *p;
196*63afb9a5SDavid du Colombier 	int i;
197*63afb9a5SDavid du Colombier 	Msg *m;
198*63afb9a5SDavid du Colombier 
199*63afb9a5SDavid du Colombier 	/* receive id string */
200*63afb9a5SDavid du Colombier 	if(readstrnl(c->fd[0], buf, sizeof buf) < 0)
201*63afb9a5SDavid du Colombier 		error("reading server version: %r");
202*63afb9a5SDavid du Colombier 
203*63afb9a5SDavid du Colombier 	/* id string is "SSH-m.n-comment".  We need m=1, n>=5. */
204*63afb9a5SDavid du Colombier 	if(strncmp(buf, "SSH-", 4) != 0
205*63afb9a5SDavid du Colombier 	|| strtol(buf+4, &p, 10) != 1
206*63afb9a5SDavid du Colombier 	|| *p != '.'
207*63afb9a5SDavid du Colombier 	|| strtol(p+1, &p, 10) < 5
208*63afb9a5SDavid du Colombier 	|| *p != '-')
209*63afb9a5SDavid du Colombier 		error("protocol mismatch; got %s, need SSH-1.x for x>=5", buf);
210*63afb9a5SDavid du Colombier 
211*63afb9a5SDavid du Colombier 	/* send id string */
212*63afb9a5SDavid du Colombier 	fprint(c->fd[1], "SSH-1.5-Plan 9\n");
213*63afb9a5SDavid du Colombier 
214*63afb9a5SDavid du Colombier 	recv_ssh_smsg_public_key(c);
215*63afb9a5SDavid du Colombier 	checkkey(c);
216*63afb9a5SDavid du Colombier 
217*63afb9a5SDavid du Colombier 	for(i=0; i<SESSKEYLEN; i++)
218*63afb9a5SDavid du Colombier 		c->sesskey[i] = fastrand();
219*63afb9a5SDavid du Colombier 	c->cipher = nil;
220*63afb9a5SDavid du Colombier 	for(i=0; i<c->nokcipher; i++)
221*63afb9a5SDavid du Colombier 		if((1<<c->okcipher[i]->id) & c->ciphermask){
222*63afb9a5SDavid du Colombier 			c->cipher = c->okcipher[i];
223*63afb9a5SDavid du Colombier 			break;
224*63afb9a5SDavid du Colombier 		}
225*63afb9a5SDavid du Colombier 	if(c->cipher == nil)
226*63afb9a5SDavid du Colombier 		error("can't agree on ciphers: remote side supports %#lux", c->ciphermask);
227*63afb9a5SDavid du Colombier 
228*63afb9a5SDavid du Colombier 	calcsessid(c);
229*63afb9a5SDavid du Colombier 
230*63afb9a5SDavid du Colombier 	send_ssh_cmsg_session_key(c);
231*63afb9a5SDavid du Colombier 
232*63afb9a5SDavid du Colombier 	c->cstate = (*c->cipher->init)(c, 0);		/* turns on encryption */
233*63afb9a5SDavid du Colombier 	m = recvmsg(c, SSH_SMSG_SUCCESS);
234*63afb9a5SDavid du Colombier 	free(m);
235*63afb9a5SDavid du Colombier 
236*63afb9a5SDavid du Colombier 	if(authuser(c) < 0)
237*63afb9a5SDavid du Colombier 		error("client authentication failed");
238*63afb9a5SDavid du Colombier }
239*63afb9a5SDavid du Colombier 
240*63afb9a5SDavid du Colombier static int
intgetenv(char * name,int def)241*63afb9a5SDavid du Colombier intgetenv(char *name, int def)
242*63afb9a5SDavid du Colombier {
243*63afb9a5SDavid du Colombier 	char *s;
244*63afb9a5SDavid du Colombier 	int n, val;
245*63afb9a5SDavid du Colombier 
246*63afb9a5SDavid du Colombier 	val = def;
247*63afb9a5SDavid du Colombier 	if((s = getenv(name))!=nil){
248*63afb9a5SDavid du Colombier 		if((n=atoi(s)) > 0)
249*63afb9a5SDavid du Colombier 			val = n;
250*63afb9a5SDavid du Colombier 		free(s);
251*63afb9a5SDavid du Colombier 	}
252*63afb9a5SDavid du Colombier 	return val;
253*63afb9a5SDavid du Colombier }
254*63afb9a5SDavid du Colombier 
255*63afb9a5SDavid du Colombier /*
256*63afb9a5SDavid du Colombier  * assumes that if you care, you're running under vt
257*63afb9a5SDavid du Colombier  * and therefore these are set.
258*63afb9a5SDavid du Colombier  */
259*63afb9a5SDavid du Colombier int
readgeom(int * nrow,int * ncol,int * width,int * height)260*63afb9a5SDavid du Colombier readgeom(int *nrow, int *ncol, int *width, int *height)
261*63afb9a5SDavid du Colombier {
262*63afb9a5SDavid du Colombier 	static int fd = -1;
263*63afb9a5SDavid du Colombier 	char buf[64];
264*63afb9a5SDavid du Colombier 
265*63afb9a5SDavid du Colombier 	if(fd < 0 && (fd = open("/dev/wctl", OREAD)) < 0)
266*63afb9a5SDavid du Colombier 		return -1;
267*63afb9a5SDavid du Colombier 	/* wait for event, but don't care what it says */
268*63afb9a5SDavid du Colombier 	if(read(fd, buf, sizeof buf) < 0)
269*63afb9a5SDavid du Colombier 		return -1;
270*63afb9a5SDavid du Colombier 	*nrow = intgetenv("LINES", 24);
271*63afb9a5SDavid du Colombier 	*ncol = intgetenv("COLS", 80);
272*63afb9a5SDavid du Colombier 	*width = intgetenv("XPIXELS", 640);
273*63afb9a5SDavid du Colombier 	*height = intgetenv("YPIXELS", 480);
274*63afb9a5SDavid du Colombier 	return 0;
275*63afb9a5SDavid du Colombier }
276*63afb9a5SDavid du Colombier 
277*63afb9a5SDavid du Colombier void
sendwindowsize(Conn * c,int nrow,int ncol,int width,int height)278*63afb9a5SDavid du Colombier sendwindowsize(Conn *c, int nrow, int ncol, int width, int height)
279*63afb9a5SDavid du Colombier {
280*63afb9a5SDavid du Colombier 	Msg *m;
281*63afb9a5SDavid du Colombier 
282*63afb9a5SDavid du Colombier 	m = allocmsg(c, SSH_CMSG_WINDOW_SIZE, 4*4);
283*63afb9a5SDavid du Colombier 	putlong(m, nrow);
284*63afb9a5SDavid du Colombier 	putlong(m, ncol);
285*63afb9a5SDavid du Colombier 	putlong(m, width);
286*63afb9a5SDavid du Colombier 	putlong(m, height);
287*63afb9a5SDavid du Colombier 	sendmsg(m);
288*63afb9a5SDavid du Colombier }
289*63afb9a5SDavid du Colombier 
290*63afb9a5SDavid du Colombier /*
291*63afb9a5SDavid du Colombier  * In each option line, the first byte is the option number
292*63afb9a5SDavid du Colombier  * and the second is either a boolean bit or actually an
293*63afb9a5SDavid du Colombier  * ASCII code.
294*63afb9a5SDavid du Colombier  */
295*63afb9a5SDavid du Colombier static uchar ptyopt[] =
296*63afb9a5SDavid du Colombier {
297*63afb9a5SDavid du Colombier 	0x01, 0x7F,	/* interrupt = DEL */
298*63afb9a5SDavid du Colombier 	0x02, 0x11,	/* quit = ^Q */
299*63afb9a5SDavid du Colombier 	0x03, 0x08,	/* backspace = ^H */
300*63afb9a5SDavid du Colombier 	0x04, 0x15,	/* line kill = ^U */
301*63afb9a5SDavid du Colombier 	0x05, 0x04,	/* EOF = ^D */
302*63afb9a5SDavid du Colombier 	0x20, 0x00,	/* don't strip high bit */
303*63afb9a5SDavid du Colombier 	0x48, 0x01,	/* give us CRs */
304*63afb9a5SDavid du Colombier 
305*63afb9a5SDavid du Colombier 	0x00,		/* end options */
306*63afb9a5SDavid du Colombier };
307*63afb9a5SDavid du Colombier 
308*63afb9a5SDavid du Colombier static uchar rawptyopt[] =
309*63afb9a5SDavid du Colombier {
310*63afb9a5SDavid du Colombier 	30,	0,		/* ignpar */
311*63afb9a5SDavid du Colombier 	31,	0,		/* parmrk */
312*63afb9a5SDavid du Colombier 	32,	0,		/* inpck */
313*63afb9a5SDavid du Colombier 	33,	0,		/* istrip */
314*63afb9a5SDavid du Colombier 	34,	0,		/* inlcr */
315*63afb9a5SDavid du Colombier 	35,	0,		/* igncr */
316*63afb9a5SDavid du Colombier 	36,	0,		/* icnrl */
317*63afb9a5SDavid du Colombier 	37,	0,		/* iuclc */
318*63afb9a5SDavid du Colombier 	38,	0,		/* ixon */
319*63afb9a5SDavid du Colombier 	39,	1,		/* ixany */
320*63afb9a5SDavid du Colombier 	40,	0,		/* ixoff */
321*63afb9a5SDavid du Colombier 	41,	0,		/* imaxbel */
322*63afb9a5SDavid du Colombier 
323*63afb9a5SDavid du Colombier 	50,	0,		/* isig: intr, quit, susp processing */
324*63afb9a5SDavid du Colombier 	51,	0,		/* icanon: erase and kill processing */
325*63afb9a5SDavid du Colombier 	52,	0,		/* xcase */
326*63afb9a5SDavid du Colombier 
327*63afb9a5SDavid du Colombier 	53,	0,		/* echo */
328*63afb9a5SDavid du Colombier 
329*63afb9a5SDavid du Colombier 	57,	0,		/* noflsh */
330*63afb9a5SDavid du Colombier 	58,	0,		/* tostop */
331*63afb9a5SDavid du Colombier 	59,	0,		/* iexten: impl defined control chars */
332*63afb9a5SDavid du Colombier 
333*63afb9a5SDavid du Colombier 	70,	0,		/* opost */
334*63afb9a5SDavid du Colombier 
335*63afb9a5SDavid du Colombier 	0x00,
336*63afb9a5SDavid du Colombier };
337*63afb9a5SDavid du Colombier 
338*63afb9a5SDavid du Colombier void
requestpty(Conn * c)339*63afb9a5SDavid du Colombier requestpty(Conn *c)
340*63afb9a5SDavid du Colombier {
341*63afb9a5SDavid du Colombier 	char *term;
342*63afb9a5SDavid du Colombier 	int nrow, ncol, width, height;
343*63afb9a5SDavid du Colombier 	Msg *m;
344*63afb9a5SDavid du Colombier 
345*63afb9a5SDavid du Colombier 	m = allocmsg(c, SSH_CMSG_REQUEST_PTY, 1024);
346*63afb9a5SDavid du Colombier 	if((term = getenv("TERM")) == nil)
347*63afb9a5SDavid du Colombier 		term = "9term";
348*63afb9a5SDavid du Colombier 	putstring(m, term);
349*63afb9a5SDavid du Colombier 
350*63afb9a5SDavid du Colombier 	readgeom(&nrow, &ncol, &width, &height);
351*63afb9a5SDavid du Colombier 	putlong(m, nrow);	/* characters */
352*63afb9a5SDavid du Colombier 	putlong(m, ncol);
353*63afb9a5SDavid du Colombier 	putlong(m, width);	/* pixels */
354*63afb9a5SDavid du Colombier 	putlong(m, height);
355*63afb9a5SDavid du Colombier 
356*63afb9a5SDavid du Colombier 	if(rawhack)
357*63afb9a5SDavid du Colombier 		putbytes(m, rawptyopt, sizeof rawptyopt);
358*63afb9a5SDavid du Colombier 	else
359*63afb9a5SDavid du Colombier 		putbytes(m, ptyopt, sizeof ptyopt);
360*63afb9a5SDavid du Colombier 
361*63afb9a5SDavid du Colombier 	sendmsg(m);
362*63afb9a5SDavid du Colombier 
363*63afb9a5SDavid du Colombier 	m = recvmsg(c, 0);
364*63afb9a5SDavid du Colombier 	switch(m->type){
365*63afb9a5SDavid du Colombier 	case SSH_SMSG_SUCCESS:
366*63afb9a5SDavid du Colombier 		debug(DBG_IO, "PTY allocated\n");
367*63afb9a5SDavid du Colombier 		break;
368*63afb9a5SDavid du Colombier 	case SSH_SMSG_FAILURE:
369*63afb9a5SDavid du Colombier 		debug(DBG_IO, "PTY allocation failed\n");
370*63afb9a5SDavid du Colombier 		break;
371*63afb9a5SDavid du Colombier 	default:
372*63afb9a5SDavid du Colombier 		badmsg(m, 0);
373*63afb9a5SDavid du Colombier 	}
374*63afb9a5SDavid du Colombier 	free(m);
375*63afb9a5SDavid du Colombier }
376*63afb9a5SDavid du Colombier 
377